• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2const common = require('../common');
3if (!common.hasCrypto)
4  common.skip('missing crypto');
5
6const assert = require('assert');
7const crypto = require('crypto');
8
9common.expectWarning(
10  'DeprecationWarning',
11  'Calling pbkdf2 or pbkdf2Sync with "digest" set to null is deprecated.',
12  'DEP0009');
13
14//
15// Test PBKDF2 with RFC 6070 test vectors (except #4)
16//
17function testPBKDF2(password, salt, iterations, keylen, expected) {
18  const actual =
19    crypto.pbkdf2Sync(password, salt, iterations, keylen, 'sha256');
20  assert.strictEqual(actual.toString('latin1'), expected);
21
22  crypto.pbkdf2(password, salt, iterations, keylen, 'sha256', (err, actual) => {
23    assert.strictEqual(actual.toString('latin1'), expected);
24  });
25}
26
27
28testPBKDF2('password', 'salt', 1, 20,
29           '\x12\x0f\xb6\xcf\xfc\xf8\xb3\x2c\x43\xe7\x22\x52' +
30           '\x56\xc4\xf8\x37\xa8\x65\x48\xc9');
31
32testPBKDF2('password', 'salt', 2, 20,
33           '\xae\x4d\x0c\x95\xaf\x6b\x46\xd3\x2d\x0a\xdf\xf9' +
34           '\x28\xf0\x6d\xd0\x2a\x30\x3f\x8e');
35
36testPBKDF2('password', 'salt', 4096, 20,
37           '\xc5\xe4\x78\xd5\x92\x88\xc8\x41\xaa\x53\x0d\xb6' +
38           '\x84\x5c\x4c\x8d\x96\x28\x93\xa0');
39
40testPBKDF2('passwordPASSWORDpassword',
41           'saltSALTsaltSALTsaltSALTsaltSALTsalt',
42           4096,
43           25,
44           '\x34\x8c\x89\xdb\xcb\xd3\x2b\x2f\x32\xd8\x14\xb8\x11' +
45           '\x6e\x84\xcf\x2b\x17\x34\x7e\xbc\x18\x00\x18\x1c');
46
47testPBKDF2('pass\0word', 'sa\0lt', 4096, 16,
48           '\x89\xb6\x9d\x05\x16\xf8\x29\x89\x3c\x69\x62\x26\x65' +
49           '\x0a\x86\x87');
50
51const expected =
52    '64c486c55d30d4c5a079b8823b7d7cb37ff0556f537da8410233bcec330ed956';
53const key = crypto.pbkdf2Sync('password', 'salt', 32, 32, 'sha256');
54assert.strictEqual(key.toString('hex'), expected);
55
56crypto.pbkdf2('password', 'salt', 32, 32, 'sha256', common.mustCall(ondone));
57function ondone(err, key) {
58  assert.ifError(err);
59  assert.strictEqual(key.toString('hex'), expected);
60}
61
62// Error path should not leak memory (check with valgrind).
63assert.throws(
64  () => crypto.pbkdf2('password', 'salt', 1, 20, null),
65  {
66    code: 'ERR_INVALID_CALLBACK',
67    name: 'TypeError'
68  }
69);
70
71assert.throws(
72  () => crypto.pbkdf2Sync('password', 'salt', -1, 20, 'sha1'),
73  {
74    code: 'ERR_OUT_OF_RANGE',
75    name: 'RangeError',
76    message: 'The value of "iterations" is out of range. ' +
77             'It must be >= 0 && < 4294967296. Received -1'
78  }
79);
80
81['str', null, undefined, [], {}].forEach((notNumber) => {
82  assert.throws(
83    () => {
84      crypto.pbkdf2Sync('password', 'salt', 1, notNumber, 'sha256');
85    }, {
86      code: 'ERR_INVALID_ARG_TYPE',
87      name: 'TypeError',
88      message: 'The "keylen" argument must be of type number.' +
89               `${common.invalidArgTypeHelper(notNumber)}`
90    });
91});
92
93[Infinity, -Infinity, NaN].forEach((input) => {
94  assert.throws(
95    () => {
96      crypto.pbkdf2('password', 'salt', 1, input, 'sha256',
97                    common.mustNotCall());
98    }, {
99      code: 'ERR_OUT_OF_RANGE',
100      name: 'RangeError',
101      message: 'The value of "keylen" is out of range. It ' +
102               `must be an integer. Received ${input}`
103    });
104});
105
106[-1, 4294967297].forEach((input) => {
107  assert.throws(
108    () => {
109      crypto.pbkdf2('password', 'salt', 1, input, 'sha256',
110                    common.mustNotCall());
111    }, {
112      code: 'ERR_OUT_OF_RANGE',
113      name: 'RangeError',
114      message: 'The value of "keylen" is out of range. It must be >= 0 && < ' +
115               `4294967296. Received ${input === -1 ? '-1' : '4_294_967_297'}`
116    });
117});
118
119// Should not get FATAL ERROR with empty password and salt
120// https://github.com/nodejs/node/issues/8571
121crypto.pbkdf2('', '', 1, 32, 'sha256', common.mustCall(assert.ifError));
122
123assert.throws(
124  () => crypto.pbkdf2('password', 'salt', 8, 8, common.mustNotCall()),
125  {
126    code: 'ERR_INVALID_ARG_TYPE',
127    name: 'TypeError',
128    message: 'The "digest" argument must be of type string or null. ' +
129             'Received undefined'
130  });
131
132assert.throws(
133  () => crypto.pbkdf2Sync('password', 'salt', 8, 8),
134  {
135    code: 'ERR_INVALID_ARG_TYPE',
136    name: 'TypeError',
137    message: 'The "digest" argument must be of type string or null. ' +
138             'Received undefined'
139  });
140
141[1, {}, [], true, undefined, null].forEach((input) => {
142  const msgPart2 = 'an instance of Buffer, TypedArray, or DataView.' +
143                   common.invalidArgTypeHelper(input);
144  assert.throws(
145    () => crypto.pbkdf2(input, 'salt', 8, 8, 'sha256', common.mustNotCall()),
146    {
147      code: 'ERR_INVALID_ARG_TYPE',
148      name: 'TypeError',
149      message: `The "password" argument must be of type string or ${msgPart2}`
150    }
151  );
152
153  assert.throws(
154    () => crypto.pbkdf2('pass', input, 8, 8, 'sha256', common.mustNotCall()),
155    {
156      code: 'ERR_INVALID_ARG_TYPE',
157      name: 'TypeError',
158      message: `The "salt" argument must be of type string or ${msgPart2}`
159    }
160  );
161
162  assert.throws(
163    () => crypto.pbkdf2Sync(input, 'salt', 8, 8, 'sha256'),
164    {
165      code: 'ERR_INVALID_ARG_TYPE',
166      name: 'TypeError',
167      message: `The "password" argument must be of type string or ${msgPart2}`
168    }
169  );
170
171  assert.throws(
172    () => crypto.pbkdf2Sync('pass', input, 8, 8, 'sha256'),
173    {
174      code: 'ERR_INVALID_ARG_TYPE',
175      name: 'TypeError',
176      message: `The "salt" argument must be of type string or ${msgPart2}`
177    }
178  );
179});
180
181['test', {}, [], true, undefined, null].forEach((i) => {
182  const received = common.invalidArgTypeHelper(i);
183  assert.throws(
184    () => crypto.pbkdf2('pass', 'salt', i, 8, 'sha256', common.mustNotCall()),
185    {
186      code: 'ERR_INVALID_ARG_TYPE',
187      name: 'TypeError',
188      message: `The "iterations" argument must be of type number.${received}`
189    }
190  );
191
192  assert.throws(
193    () => crypto.pbkdf2Sync('pass', 'salt', i, 8, 'sha256'),
194    {
195      code: 'ERR_INVALID_ARG_TYPE',
196      name: 'TypeError',
197      message: `The "iterations" argument must be of type number.${received}`
198    }
199  );
200});
201
202// Any TypedArray should work for password and salt
203crypto.pbkdf2(new Uint8Array(10), 'salt', 8, 8, 'sha256', common.mustCall());
204crypto.pbkdf2('pass', new Uint8Array(10), 8, 8, 'sha256', common.mustCall());
205crypto.pbkdf2(new Uint16Array(10), 'salt', 8, 8, 'sha256', common.mustCall());
206crypto.pbkdf2('pass', new Uint16Array(10), 8, 8, 'sha256', common.mustCall());
207crypto.pbkdf2(new Uint32Array(10), 'salt', 8, 8, 'sha256', common.mustCall());
208crypto.pbkdf2('pass', new Uint32Array(10), 8, 8, 'sha256', common.mustCall());
209crypto.pbkdf2(new Float32Array(10), 'salt', 8, 8, 'sha256', common.mustCall());
210crypto.pbkdf2('pass', new Float32Array(10), 8, 8, 'sha256', common.mustCall());
211crypto.pbkdf2(new Float64Array(10), 'salt', 8, 8, 'sha256', common.mustCall());
212crypto.pbkdf2('pass', new Float64Array(10), 8, 8, 'sha256', common.mustCall());
213
214crypto.pbkdf2Sync(new Uint8Array(10), 'salt', 8, 8, 'sha256');
215crypto.pbkdf2Sync('pass', new Uint8Array(10), 8, 8, 'sha256');
216crypto.pbkdf2Sync(new Uint16Array(10), 'salt', 8, 8, 'sha256');
217crypto.pbkdf2Sync('pass', new Uint16Array(10), 8, 8, 'sha256');
218crypto.pbkdf2Sync(new Uint32Array(10), 'salt', 8, 8, 'sha256');
219crypto.pbkdf2Sync('pass', new Uint32Array(10), 8, 8, 'sha256');
220crypto.pbkdf2Sync(new Float32Array(10), 'salt', 8, 8, 'sha256');
221crypto.pbkdf2Sync('pass', new Float32Array(10), 8, 8, 'sha256');
222crypto.pbkdf2Sync(new Float64Array(10), 'salt', 8, 8, 'sha256');
223crypto.pbkdf2Sync('pass', new Float64Array(10), 8, 8, 'sha256');
224
225assert.throws(
226  () => crypto.pbkdf2('pass', 'salt', 8, 8, 'md55', common.mustNotCall()),
227  {
228    code: 'ERR_CRYPTO_INVALID_DIGEST',
229    name: 'TypeError',
230    message: 'Invalid digest: md55'
231  }
232);
233
234assert.throws(
235  () => crypto.pbkdf2Sync('pass', 'salt', 8, 8, 'md55'),
236  {
237    code: 'ERR_CRYPTO_INVALID_DIGEST',
238    name: 'TypeError',
239    message: 'Invalid digest: md55'
240  }
241);
242