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