• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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