Created
May 8, 2021 19:05
-
-
Save fluggo/151fb5785c5866d16d1af68af824e3f3 to your computer and use it in GitHub Desktop.
Node.js implementation of System.Security.Cryptography.PasswordDeriveBytes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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