1'use strict'; 2 3const common = require('../common'); 4 5if (!common.hasCrypto) 6 common.skip('missing crypto'); 7 8const { kMaxLength } = require('buffer'); 9const assert = require('assert'); 10const { 11 createSecretKey, 12 hkdf, 13 hkdfSync, 14 getHashes 15} = require('crypto'); 16 17{ 18 assert.throws(() => hkdf(), { 19 code: 'ERR_INVALID_ARG_TYPE', 20 message: /The "digest" argument must be of type string/ 21 }); 22 23 [1, {}, [], false, Infinity].forEach((i) => { 24 assert.throws(() => hkdf(i, 'a'), { 25 code: 'ERR_INVALID_ARG_TYPE', 26 message: /^The "digest" argument must be of type string/ 27 }); 28 assert.throws(() => hkdfSync(i, 'a'), { 29 code: 'ERR_INVALID_ARG_TYPE', 30 message: /^The "digest" argument must be of type string/ 31 }); 32 }); 33 34 [1, {}, [], false, Infinity].forEach((i) => { 35 assert.throws(() => hkdf('sha256', i), { 36 code: 'ERR_INVALID_ARG_TYPE', 37 message: /^The "ikm" argument must be / 38 }); 39 assert.throws(() => hkdfSync('sha256', i), { 40 code: 'ERR_INVALID_ARG_TYPE', 41 message: /^The "ikm" argument must be / 42 }); 43 }); 44 45 [1, {}, [], false, Infinity].forEach((i) => { 46 assert.throws(() => hkdf('sha256', 'secret', i), { 47 code: 'ERR_INVALID_ARG_TYPE', 48 message: /^The "salt" argument must be / 49 }); 50 assert.throws(() => hkdfSync('sha256', 'secret', i), { 51 code: 'ERR_INVALID_ARG_TYPE', 52 message: /^The "salt" argument must be / 53 }); 54 }); 55 56 [1, {}, [], false, Infinity].forEach((i) => { 57 assert.throws(() => hkdf('sha256', 'secret', 'salt', i), { 58 code: 'ERR_INVALID_ARG_TYPE', 59 message: /^The "info" argument must be / 60 }); 61 assert.throws(() => hkdfSync('sha256', 'secret', 'salt', i), { 62 code: 'ERR_INVALID_ARG_TYPE', 63 message: /^The "info" argument must be / 64 }); 65 }); 66 67 ['test', {}, [], false].forEach((i) => { 68 assert.throws(() => hkdf('sha256', 'secret', 'salt', 'info', i), { 69 code: 'ERR_INVALID_ARG_TYPE', 70 message: /^The "length" argument must be of type number/ 71 }); 72 assert.throws(() => hkdfSync('sha256', 'secret', 'salt', 'info', i), { 73 code: 'ERR_INVALID_ARG_TYPE', 74 message: /^The "length" argument must be of type number/ 75 }); 76 }); 77 78 assert.throws(() => hkdf('sha256', 'secret', 'salt', 'info', -1), { 79 code: 'ERR_OUT_OF_RANGE' 80 }); 81 assert.throws(() => hkdfSync('sha256', 'secret', 'salt', 'info', -1), { 82 code: 'ERR_OUT_OF_RANGE' 83 }); 84 assert.throws(() => hkdf('sha256', 'secret', 'salt', 'info', 85 kMaxLength + 1), { 86 code: 'ERR_OUT_OF_RANGE' 87 }); 88 assert.throws(() => hkdfSync('sha256', 'secret', 'salt', 'info', 89 kMaxLength + 1), { 90 code: 'ERR_OUT_OF_RANGE' 91 }); 92 93 assert.throws(() => hkdfSync('unknown', 'a', '', '', 10), { 94 code: 'ERR_CRYPTO_INVALID_DIGEST' 95 }); 96 97 assert.throws(() => hkdf('unknown', 'a', '', '', 10, common.mustNotCall()), { 98 code: 'ERR_CRYPTO_INVALID_DIGEST' 99 }); 100 101 assert.throws(() => hkdf('unknown', 'a', '', Buffer.alloc(1025), 10, 102 common.mustNotCall()), { 103 code: 'ERR_OUT_OF_RANGE' 104 }); 105 106 assert.throws(() => hkdfSync('unknown', 'a', '', Buffer.alloc(1025), 10), { 107 code: 'ERR_OUT_OF_RANGE' 108 }); 109 110 assert.throws( 111 () => hkdf('sha512', 'a', '', '', 64 * 255 + 1, common.mustNotCall()), { 112 code: 'ERR_CRYPTO_INVALID_KEYLEN' 113 }); 114 115 assert.throws( 116 () => hkdfSync('sha512', 'a', '', '', 64 * 255 + 1), { 117 code: 'ERR_CRYPTO_INVALID_KEYLEN' 118 }); 119} 120 121const algorithms = [ 122 ['sha256', 'secret', 'salt', 'info', 10], 123 ['sha256', '', '', '', 10], 124 ['sha256', '', 'salt', '', 10], 125 ['sha512', 'secret', 'salt', '', 15], 126]; 127if (!common.hasOpenSSL3) 128 algorithms.push(['whirlpool', 'secret', '', 'info', 20]); 129 130algorithms.forEach(([ hash, secret, salt, info, length ]) => { 131 { 132 const syncResult = hkdfSync(hash, secret, salt, info, length); 133 assert(syncResult instanceof ArrayBuffer); 134 let is_async = false; 135 hkdf(hash, secret, salt, info, length, 136 common.mustSucceed((asyncResult) => { 137 assert(is_async); 138 assert(asyncResult instanceof ArrayBuffer); 139 assert.deepStrictEqual(syncResult, asyncResult); 140 })); 141 // Keep this after the hkdf call above. This verifies 142 // that the callback is invoked asynchronously. 143 is_async = true; 144 } 145 146 { 147 const buf_secret = Buffer.from(secret); 148 const buf_salt = Buffer.from(salt); 149 const buf_info = Buffer.from(info); 150 151 const syncResult = hkdfSync(hash, buf_secret, buf_salt, buf_info, length); 152 hkdf(hash, buf_secret, buf_salt, buf_info, length, 153 common.mustSucceed((asyncResult) => { 154 assert.deepStrictEqual(syncResult, asyncResult); 155 })); 156 } 157 158 { 159 const key_secret = createSecretKey(Buffer.from(secret)); 160 const buf_salt = Buffer.from(salt); 161 const buf_info = Buffer.from(info); 162 163 const syncResult = hkdfSync(hash, key_secret, buf_salt, buf_info, length); 164 hkdf(hash, key_secret, buf_salt, buf_info, length, 165 common.mustSucceed((asyncResult) => { 166 assert.deepStrictEqual(syncResult, asyncResult); 167 })); 168 } 169 170 { 171 const ta_secret = new Uint8Array(Buffer.from(secret)); 172 const ta_salt = new Uint16Array(Buffer.from(salt)); 173 const ta_info = new Uint32Array(Buffer.from(info)); 174 175 const syncResult = hkdfSync(hash, ta_secret, ta_salt, ta_info, length); 176 hkdf(hash, ta_secret, ta_salt, ta_info, length, 177 common.mustSucceed((asyncResult) => { 178 assert.deepStrictEqual(syncResult, asyncResult); 179 })); 180 } 181 182 { 183 const ta_secret = new Uint8Array(Buffer.from(secret)); 184 const ta_salt = new Uint16Array(Buffer.from(salt)); 185 const ta_info = new Uint32Array(Buffer.from(info)); 186 187 const syncResult = hkdfSync( 188 hash, 189 ta_secret.buffer, 190 ta_salt.buffer, 191 ta_info.buffer, 192 length); 193 hkdf(hash, ta_secret, ta_salt, ta_info, length, 194 common.mustSucceed((asyncResult) => { 195 assert.deepStrictEqual(syncResult, asyncResult); 196 })); 197 } 198 199 { 200 const ta_secret = new Uint8Array(Buffer.from(secret)); 201 const sa_salt = new SharedArrayBuffer(0); 202 const sa_info = new SharedArrayBuffer(1); 203 204 const syncResult = hkdfSync( 205 hash, 206 ta_secret.buffer, 207 sa_salt, 208 sa_info, 209 length); 210 hkdf(hash, ta_secret, sa_salt, sa_info, length, 211 common.mustSucceed((asyncResult) => { 212 assert.deepStrictEqual(syncResult, asyncResult); 213 })); 214 } 215}); 216 217 218if (!common.hasOpenSSL3) { 219 const kKnownUnsupported = ['shake128', 'shake256']; 220 getHashes() 221 .filter((hash) => !kKnownUnsupported.includes(hash)) 222 .forEach((hash) => { 223 assert(hkdfSync(hash, 'key', 'salt', 'info', 5)); 224 }); 225} 226