Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Node.js implementation of System.Security.Cryptography.PasswordDeriveBytes
// Node.js implementation of PasswordDeriveBytes from .NET,
// which itself is a bastardization of PBKDF1.
//
// ONLY USE THIS FUNCTION FOR COMPATIBILITY PURPOSES.
// DO NOT USE THIS IN NEW CODE-- use crypto.pbkdf2 instead.
//
// See:
// * https://crypto.stackexchange.com/questions/22271/what-is-the-algorithm-behind-passwordderivebytes
// * https://referencesource.microsoft.com/#mscorlib/system/security/cryptography/passwordderivebytes.cs
function passwordDeriveBytes(password, salt, iterations, len, hashAlgorithm) {
let baseValue = Buffer.concat([Buffer.from(password, 'utf8'), Buffer.from(salt)]);
// Always compute one base hash, regardless of iterations
// This means that for the case iterations = 1, and len
// is less than or equal to the hash output length,
// the result is equivalent for PBKDF1 for iterations = 2
baseValue = crypto.createHash(hashAlgorithm).update(baseValue).digest();
for(let i = 1; i < iterations - 1; i++) {
baseValue = crypto.createHash(hashAlgorithm).update(baseValue).digest();
}
const key = Buffer.alloc(len);
let keyLength = 0;
let prefixCounter = 0;
while(keyLength < len) {
// Compute a hash prefix to extend the hash's output
// THIS IS NOT SAFE - THE OUTPUT WILL HAVE NO MORE ENTROPY THAN
// THE HASH'S NATIVE OUTPUT LENGTH
if(prefixCounter > 999)
throw new Error('Too many bytes requested');
let hashBase = baseValue;
if(prefixCounter !== 0) {
const prefix = Buffer.from(String(prefixCounter), 'ascii');
hashBase = Buffer.concat([prefix, hashBase]);
}
prefixCounter++;
const hash = crypto.createHash(hashAlgorithm).update(hashBase).digest();
const hashBytes = Math.min(hash.length, len - keyLength);
hash.copy(key, keyLength, 0, hashBytes);
keyLength += hashBytes;
}
return key;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment