crypto: refactor pbkdf2() and pbkdf2Sync() methods · nodejs/node@6262fa4
11'use strict';
223+const { AsyncWrap, Providers } = process.binding('async_wrap');
4+const { Buffer } = require('buffer');
5+const { pbkdf2: _pbkdf2 } = process.binding('crypto');
36const {
7+ERR_CRYPTO_INVALID_DIGEST,
8+ERR_CRYPTO_PBKDF2_ERROR,
49ERR_INVALID_ARG_TYPE,
510ERR_INVALID_CALLBACK,
6-ERR_CRYPTO_INVALID_DIGEST,
711} = require('internal/errors').codes;
812const {
913 checkIsArrayBufferView,
1014 checkIsUint,
1115 getDefaultEncoding,
1216} = require('internal/crypto/util');
13-const {
14-PBKDF2
15-} = process.binding('crypto');
16171718function pbkdf2(password, salt, iterations, keylen, digest, callback) {
1819if (typeof digest === 'function') {
1920callback = digest;
2021digest = undefined;
2122}
222324+({ password, salt, iterations, keylen, digest } =
25+check(password, salt, iterations, keylen, digest, callback));
26+2327if (typeof callback !== 'function')
2428throw new ERR_INVALID_CALLBACK();
252926-return _pbkdf2(password, salt, iterations, keylen, digest, callback);
30+const encoding = getDefaultEncoding();
31+const keybuf = Buffer.alloc(keylen);
32+33+const wrap = new AsyncWrap(Providers.PBKDF2REQUEST);
34+wrap.ondone = (ok) => { // Retains keybuf while request is in flight.
35+if (!ok) return callback.call(wrap, new ERR_CRYPTO_PBKDF2_ERROR());
36+if (encoding === 'buffer') return callback.call(wrap, null, keybuf);
37+callback.call(wrap, null, keybuf.toString(encoding));
38+};
39+40+handleError(keybuf, password, salt, iterations, digest, wrap);
2741}
28422943function pbkdf2Sync(password, salt, iterations, keylen, digest) {
30-return _pbkdf2(password, salt, iterations, keylen, digest);
44+({ password, salt, iterations, keylen, digest } =
45+check(password, salt, iterations, keylen, digest, pbkdf2Sync));
46+const keybuf = Buffer.alloc(keylen);
47+handleError(keybuf, password, salt, iterations, digest);
48+const encoding = getDefaultEncoding();
49+if (encoding === 'buffer') return keybuf;
50+return keybuf.toString(encoding);
3151}
325233-function _pbkdf2(password, salt, iterations, keylen, digest, callback) {
34-35-if (digest !== null && typeof digest !== 'string')
36-throw new ERR_INVALID_ARG_TYPE('digest', ['string', 'null'], digest);
53+function check(password, salt, iterations, keylen, digest, callback) {
54+if (typeof digest !== 'string') {
55+if (digest !== null)
56+throw new ERR_INVALID_ARG_TYPE('digest', ['string', 'null'], digest);
57+digest = 'sha1';
58+}
37593860password = checkIsArrayBufferView('password', password);
3961salt = checkIsArrayBufferView('salt', salt);
@@ -42,30 +64,17 @@ function _pbkdf2(password, salt, iterations, keylen, digest, callback) {
4264iterations = checkIsUint('iterations', iterations, 'a non-negative number');
4365keylen = checkIsUint('keylen', keylen);
446645-const encoding = getDefaultEncoding();
67+return { password, salt, iterations, keylen, digest };
68+}
466947-if (encoding === 'buffer') {
48-const ret = PBKDF2(password, salt, iterations, keylen, digest, callback);
49-if (ret === -1)
50-throw new ERR_CRYPTO_INVALID_DIGEST(digest);
51-return ret;
52-}
70+function handleError(keybuf, password, salt, iterations, digest, wrap) {
71+const rc = _pbkdf2(keybuf, password, salt, iterations, digest, wrap);
537254-// at this point, we need to handle encodings.
55-if (callback) {
56-function next(er, ret) {
57-if (ret)
58-ret = ret.toString(encoding);
59-callback(er, ret);
60-}
61-if (PBKDF2(password, salt, iterations, keylen, digest, next) === -1)
62-throw new ERR_CRYPTO_INVALID_DIGEST(digest);
63-} else {
64-const ret = PBKDF2(password, salt, iterations, keylen, digest);
65-if (ret === -1)
66-throw new ERR_CRYPTO_INVALID_DIGEST(digest);
67-return ret.toString(encoding);
68-}
73+if (rc === -1)
74+throw new ERR_CRYPTO_INVALID_DIGEST(digest);
75+76+if (rc === false)
77+throw new ERR_CRYPTO_PBKDF2_ERROR();
6978}
70797180module.exports = {