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 { 8 ERR_CRYPTO_INVALID_DIGEST, 9 ERR_CRYPTO_PBKDF2_ERROR, 10 ERR_INVALID_ARG_TYPE, 11 ERR_INVALID_CALLBACK, 12} = require('internal/errors').codes; 13const { 14 getDefaultEncoding, 15 getArrayBufferView, 16} = require('internal/crypto/util'); 17 18function pbkdf2(password, salt, iterations, keylen, digest, callback) { 19 if (typeof digest === 'function') { 20 callback = digest; 21 digest = undefined; 22 } 23 24 ({ password, salt, iterations, keylen, digest } = 25 check(password, salt, iterations, keylen, digest)); 26 27 if (typeof callback !== 'function') 28 throw new ERR_INVALID_CALLBACK(callback); 29 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(_pbkdf2(keybuf, password, salt, iterations, digest, wrap), 41 digest); 42} 43 44function pbkdf2Sync(password, salt, iterations, keylen, digest) { 45 ({ password, salt, iterations, keylen, digest } = 46 check(password, salt, iterations, keylen, digest)); 47 const keybuf = Buffer.alloc(keylen); 48 handleError(_pbkdf2(keybuf, password, salt, iterations, digest), digest); 49 const encoding = getDefaultEncoding(); 50 if (encoding === 'buffer') return keybuf; 51 return keybuf.toString(encoding); 52} 53 54function check(password, salt, iterations, keylen, digest) { 55 if (typeof digest !== 'string') 56 throw new ERR_INVALID_ARG_TYPE('digest', 'string', digest); 57 58 password = getArrayBufferView(password, 'password'); 59 salt = getArrayBufferView(salt, 'salt'); 60 validateUint32(iterations, 'iterations', true); 61 validateUint32(keylen, 'keylen'); 62 63 return { password, salt, iterations, keylen, digest }; 64} 65 66function handleError(rc, digest) { 67 if (rc === -1) 68 throw new ERR_CRYPTO_INVALID_DIGEST(digest); 69 70 if (rc === false) 71 throw new ERR_CRYPTO_PBKDF2_ERROR(); 72} 73 74module.exports = { 75 pbkdf2, 76 pbkdf2Sync 77}; 78