Skip to content

Instantly share code, notes, and snippets.

@fenying
Created March 5, 2023 10:33
Show Gist options
  • Save fenying/bd02ef33e5a2903304cefc11257c5805 to your computer and use it in GitHub Desktop.
Save fenying/bd02ef33e5a2903304cefc11257c5805 to your computer and use it in GitHub Desktop.
PBKDF2 implementation in JS
// A JS implementation of PBKDF2.
// For study only, don't use this.
// Use NodeJS native implementation `crypto.pbkdf2` instead.
const Crypto = require('node:crypto');
function hmac(hmacAlgo, key, data) {
return Crypto.createHmac(hmacAlgo, key).update(data).digest();
}
const BUF_INT32_BE = Buffer.alloc(4);
function f(hmacAlgo, password, salt, i, c) {
BUF_INT32_BE.writeUInt32BE(i, 0);
const f = hmac(hmacAlgo, password, Buffer.concat([salt, BUF_INT32_BE]));
let u = f;
for (let i = 1; i < c; i++) {
u = hmac(hmacAlgo, password, u);
for (let j = 0; j < f.length; j++) {
f[j] ^= u[j];
}
}
return f;
}
/**
* @param {string} hmacAlgo The digest algo to be used with HMAC.
* @param {Buffer} password The password/passphrase
* @param {Buffer} salt The cryptography salt
* @param {number} iterations The count of iterations
* @param {number} keylen The byte-length of final key output
*
* @example pbkdf2('sha256', Buffer.from('password'), Buffer.from('salt'), 100000, 64);
*/
exports.pbkdf2 = function(hmacAlgo, password, salt, iterations, keylen) {
let dk = Buffer.allocUnsafe(0);
let i = 1;
while (dk.length < keylen) {
const u = f(hmacAlgo, password, salt, i++, iterations);
dk = Buffer.concat([dk, u]);
}
return dk.subarray(0, keylen);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment