1'use strict'; 2 3const { AsyncWrap, Providers } = internalBinding('async_wrap'); 4const { Buffer } = require('buffer'); 5const { pbkdf2: _pbkdf2 } = internalBinding('crypto'); 6const { validateUint32 } = require('internal/validators'); 7const { deprecate } = require('internal/util'); 8const { 9 ERR_CRYPTO_INVALID_DIGEST, 10 ERR_CRYPTO_PBKDF2_ERROR, 11 ERR_INVALID_ARG_TYPE, 12 ERR_INVALID_CALLBACK, 13} = require('internal/errors').codes; 14const { 15 getDefaultEncoding, 16 getArrayBufferView, 17} = require('internal/crypto/util'); 18 19function pbkdf2(password, salt, iterations, keylen, digest, callback) { 20 if (typeof digest === 'function') { 21 callback = digest; 22 digest = undefined; 23 } 24 25 ({ password, salt, iterations, keylen, digest } = 26 check(password, salt, iterations, keylen, digest)); 27 28 if (typeof callback !== 'function') 29 throw new ERR_INVALID_CALLBACK(callback); 30 31 const encoding = getDefaultEncoding(); 32 const keybuf = Buffer.alloc(keylen); 33 34 const wrap = new AsyncWrap(Providers.PBKDF2REQUEST); 35 wrap.ondone = (ok) => { // Retains keybuf while request is in flight. 36 if (!ok) return callback.call(wrap, new ERR_CRYPTO_PBKDF2_ERROR()); 37 if (encoding === 'buffer') return callback.call(wrap, null, keybuf); 38 callback.call(wrap, null, keybuf.toString(encoding)); 39 }; 40 41 handleError(_pbkdf2(keybuf, password, salt, iterations, digest, wrap), 42 digest); 43} 44 45function pbkdf2Sync(password, salt, iterations, keylen, digest) { 46 ({ password, salt, iterations, keylen, digest } = 47 check(password, salt, iterations, keylen, digest)); 48 const keybuf = Buffer.alloc(keylen); 49 handleError(_pbkdf2(keybuf, password, salt, iterations, digest), digest); 50 const encoding = getDefaultEncoding(); 51 if (encoding === 'buffer') return keybuf; 52 return keybuf.toString(encoding); 53} 54 55const defaultDigest = deprecate(() => 'sha1', 56 'Calling pbkdf2 or pbkdf2Sync with "digest" ' + 57 'set to null is deprecated.', 58 'DEP0009'); 59 60function check(password, salt, iterations, keylen, digest) { 61 if (typeof digest !== 'string') { 62 if (digest !== null) 63 throw new ERR_INVALID_ARG_TYPE('digest', ['string', 'null'], digest); 64 digest = defaultDigest(); 65 } 66 67 password = getArrayBufferView(password, 'password'); 68 salt = getArrayBufferView(salt, 'salt'); 69 validateUint32(iterations, 'iterations'); 70 validateUint32(keylen, 'keylen'); 71 72 return { password, salt, iterations, keylen, digest }; 73} 74 75function handleError(rc, digest) { 76 if (rc === -1) 77 throw new ERR_CRYPTO_INVALID_DIGEST(digest); 78 79 if (rc === false) 80 throw new ERR_CRYPTO_PBKDF2_ERROR(); 81} 82 83module.exports = { 84 pbkdf2, 85 pbkdf2Sync 86}; 87