Skip to content

Instantly share code, notes, and snippets.

@mhingston
Last active November 25, 2022 07:16
Show Gist options
  • Save mhingston/9bad75edb2b57cb648645dcd5ce96167 to your computer and use it in GitHub Desktop.
Save mhingston/9bad75edb2b57cb648645dcd5ce96167 to your computer and use it in GitHub Desktop.
PBKDF2 for node and C#
using System;
using System.Security.Cryptography;
public class PBKDF2
{
private int hashBytes;
private int saltBytes;
private int iterations;
public PBKDF2(int _hashBytes, int _saltBytes, int _iterations)
{
hashBytes = _hashBytes;
saltBytes = _saltBytes;
iterations = _iterations;
}
public string createHash(string password)
{
byte[] salt = new byte[saltBytes];
Random random = new Random();
random.NextBytes(salt);
Rfc2898DeriveBytes hash = new Rfc2898DeriveBytes(password, salt, iterations);
return "sha1:" + Convert.ToString(iterations) + ":" + Convert.ToString(hashBytes) + ":" + Convert.ToBase64String(salt) + ":" + Convert.ToBase64String(hash.GetBytes(hashBytes));
}
public Boolean verifyHash(string password, string hashString)
{
string[] frames = hashString.Split(':');
string _algorithm = frames[0];
int _iterations = Convert.ToInt32(frames[1]);
int _hashBytes = Convert.ToInt32(frames[2]);
byte[] salt = Convert.FromBase64String(frames[3]);
string hash = frames[4];
string generatedHash = Convert.ToBase64String(new Rfc2898DeriveBytes(password, salt, _iterations).GetBytes(_hashBytes));
return generatedHash.Equals(hash);
}
}
// Example usage
// public class Program
// {
// public static void Main()
// {
// PBKDF2 pkbdf2 = new PBKDF2(18, 24, 64000);
// string hash = pkbdf2.createHash("abc");
// Boolean verify = pkbdf2.verifyHash("abc", hash);
// Console.WriteLine("hash: " + hash);
// Console.WriteLine("Password matches hash: " + verify);
// }
// }
const Promise = require('bluebird');
const crypto = Promise.promisifyAll(require('crypto'));
class PBKDF2
{
constructor(config)
{
config = config || {};
this.hashBytes = config.hashBytes || 18;
this.saltBytes = config.saltBytes || 24;
this.iterations = config.iterations || 64000;
this.algorithm = config.algorithm || 'sha1';
this.encoding = config.encoding || 'base64';
}
async createHash(password)
{
const salt = await crypto.randomBytesAsync(this.saltBytes);
const hash = await crypto.pbkdf2Async(password, salt, this.iterations, this.hashBytes, this.algorithm);
return `${this.algorithm}:${this.iterations}:${hash.length}:${salt.toString(this.encoding)}:${hash.toString(this.encoding)}`;
}
async verifyHash(password, hashString)
{
let [algorithm, iterations, hashBytes, salt, hash] = hashString.split(':');
salt = Buffer.from(salt, this.encoding);
hash = Buffer.from(hash, this.encoding);
const generatedHash = await crypto.pbkdf2Async(password, salt, parseInt(iterations), parseInt(hashBytes), algorithm);
return generatedHash.equals(hash);
}
}
module.exports = PBKDF2;
// Example usage
// const main = async () =>
// {
// const pbkdf2 = new PBKDF2();
// const hash = await pbkdf2.createHash('abc');
// console.log('hash', hash);
// const verify = await pbkdf2.verifyHash('abc', hash);
// console.log('Password matches hash', verify);
// }
// main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment