node/lib/internal/crypto/pbkdf2.js
ZiJian Liu b00bb01db9 lib: refactor to use validateCallback
PR-URL: https://github.com/nodejs/node/pull/36609
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
2020-12-29 15:48:57 +00:00

138 lines
3.2 KiB
JavaScript

'use strict';
const {
FunctionPrototypeCall,
Promise,
} = primordials;
const { Buffer } = require('buffer');
const {
PBKDF2Job,
kCryptoJobAsync,
kCryptoJobSync,
} = internalBinding('crypto');
const {
validateCallback,
validateInteger,
validateUint32,
} = require('internal/validators');
const {
ERR_INVALID_ARG_TYPE,
ERR_MISSING_OPTION,
} = require('internal/errors').codes;
const {
getArrayBufferOrView,
getDefaultEncoding,
lazyDOMException,
normalizeHashName,
kKeyObject,
} = require('internal/crypto/util');
function pbkdf2(password, salt, iterations, keylen, digest, callback) {
if (typeof digest === 'function') {
callback = digest;
digest = undefined;
}
({ password, salt, iterations, keylen, digest } =
check(password, salt, iterations, keylen, digest));
validateCallback(callback);
const job = new PBKDF2Job(
kCryptoJobAsync,
password,
salt,
iterations,
keylen,
digest);
const encoding = getDefaultEncoding();
job.ondone = (err, result) => {
if (err !== undefined)
return FunctionPrototypeCall(callback, job, err);
const buf = Buffer.from(result);
if (encoding === 'buffer')
return FunctionPrototypeCall(callback, job, null, buf);
FunctionPrototypeCall(callback, job, null, buf.toString(encoding));
};
job.run();
}
function pbkdf2Sync(password, salt, iterations, keylen, digest) {
({ password, salt, iterations, keylen, digest } =
check(password, salt, iterations, keylen, digest));
const job = new PBKDF2Job(
kCryptoJobSync,
password,
salt,
iterations,
keylen,
digest);
const [err, result] = job.run();
if (err !== undefined)
throw err;
const buf = Buffer.from(result);
const encoding = getDefaultEncoding();
return encoding === 'buffer' ? buf : buf.toString(encoding);
}
function check(password, salt, iterations, keylen, digest) {
if (typeof digest !== 'string')
throw new ERR_INVALID_ARG_TYPE('digest', 'string', digest);
password = getArrayBufferOrView(password, 'password');
salt = getArrayBufferOrView(salt, 'salt');
validateUint32(iterations, 'iterations', true);
validateUint32(keylen, 'keylen');
return { password, salt, iterations, keylen, digest };
}
async function pbkdf2DeriveBits(algorithm, baseKey, length) {
validateUint32(length, 'length');
const { iterations } = algorithm;
let { hash } = algorithm;
const salt = getArrayBufferOrView(algorithm.salt, 'algorithm.salt');
if (hash === undefined)
throw new ERR_MISSING_OPTION('algorithm.hash');
validateInteger(iterations, 'algorithm.iterations', 1);
hash = normalizeHashName(hash.name);
const raw = baseKey[kKeyObject].export();
let byteLength = 64; // the default
if (length !== undefined) {
if (length === 0)
throw lazyDOMException('length cannot be zero', 'OperationError');
if (length % 8) {
throw lazyDOMException(
'length must be a multiple of 8',
'OperationError');
}
byteLength = length / 8;
}
return new Promise((resolve, reject) => {
pbkdf2(raw, salt, iterations, byteLength, hash, (err, result) => {
if (err) return reject(err);
resolve(result);
});
});
}
module.exports = {
pbkdf2,
pbkdf2Sync,
pbkdf2DeriveBits,
};