1'use strict'; 2const common = require('../common'); 3if (!common.hasCrypto) 4 common.skip('missing crypto'); 5 6const assert = require('assert'); 7const crypto = require('crypto'); 8const fs = require('fs'); 9 10const fixtures = require('../common/fixtures'); 11 12let cryptoType; 13let digest; 14 15// Test hashing 16const a1 = crypto.createHash('sha1').update('Test123').digest('hex'); 17const a2 = crypto.createHash('sha256').update('Test123').digest('base64'); 18const a3 = crypto.createHash('sha512').update('Test123').digest(); // buffer 19const a4 = crypto.createHash('sha1').update('Test123').digest('buffer'); 20 21// stream interface 22let a5 = crypto.createHash('sha512'); 23a5.end('Test123'); 24a5 = a5.read(); 25 26let a6 = crypto.createHash('sha512'); 27a6.write('Te'); 28a6.write('st'); 29a6.write('123'); 30a6.end(); 31a6 = a6.read(); 32 33let a7 = crypto.createHash('sha512'); 34a7.end(); 35a7 = a7.read(); 36 37let a8 = crypto.createHash('sha512'); 38a8.write(''); 39a8.end(); 40a8 = a8.read(); 41 42if (!common.hasFipsCrypto) { 43 cryptoType = 'md5'; 44 digest = 'latin1'; 45 const a0 = crypto.createHash(cryptoType).update('Test123').digest(digest); 46 assert.strictEqual( 47 a0, 48 'h\u00ea\u00cb\u0097\u00d8o\fF!\u00fa+\u000e\u0017\u00ca\u00bd\u008c', 49 `${cryptoType} with ${digest} digest failed to evaluate to expected hash` 50 ); 51} 52cryptoType = 'md5'; 53digest = 'hex'; 54assert.strictEqual( 55 a1, 56 '8308651804facb7b9af8ffc53a33a22d6a1c8ac2', 57 `${cryptoType} with ${digest} digest failed to evaluate to expected hash`); 58cryptoType = 'sha256'; 59digest = 'base64'; 60assert.strictEqual( 61 a2, 62 '2bX1jws4GYKTlxhloUB09Z66PoJZW+y+hq5R8dnx9l4=', 63 `${cryptoType} with ${digest} digest failed to evaluate to expected hash`); 64cryptoType = 'sha512'; 65digest = 'latin1'; 66assert.deepStrictEqual( 67 a3, 68 Buffer.from( 69 '\u00c1(4\u00f1\u0003\u001fd\u0097!O\'\u00d4C/&Qz\u00d4' + 70 '\u0094\u0015l\u00b8\u008dQ+\u00db\u001d\u00c4\u00b5}\u00b2' + 71 '\u00d6\u0092\u00a3\u00df\u00a2i\u00a1\u009b\n\n*\u000f' + 72 '\u00d7\u00d6\u00a2\u00a8\u0085\u00e3<\u0083\u009c\u0093' + 73 '\u00c2\u0006\u00da0\u00a1\u00879(G\u00ed\'', 74 'latin1'), 75 `${cryptoType} with ${digest} digest failed to evaluate to expected hash`); 76cryptoType = 'sha1'; 77digest = 'hex'; 78assert.deepStrictEqual( 79 a4, 80 Buffer.from('8308651804facb7b9af8ffc53a33a22d6a1c8ac2', 'hex'), 81 `${cryptoType} with ${digest} digest failed to evaluate to expected hash` 82); 83 84// Stream interface should produce the same result. 85assert.deepStrictEqual(a5, a3); 86assert.deepStrictEqual(a6, a3); 87assert.notStrictEqual(a7, undefined); 88assert.notStrictEqual(a8, undefined); 89 90// Test multiple updates to same hash 91const h1 = crypto.createHash('sha1').update('Test123').digest('hex'); 92const h2 = crypto.createHash('sha1').update('Test').update('123').digest('hex'); 93assert.strictEqual(h1, h2); 94 95// Test hashing for binary files 96const fn = fixtures.path('sample.png'); 97const sha1Hash = crypto.createHash('sha1'); 98const fileStream = fs.createReadStream(fn); 99fileStream.on('data', function(data) { 100 sha1Hash.update(data); 101}); 102fileStream.on('close', common.mustCall(function() { 103 // Test SHA1 of sample.png 104 assert.strictEqual(sha1Hash.digest('hex'), 105 '22723e553129a336ad96e10f6aecdf0f45e4149e'); 106})); 107 108// Issue https://github.com/nodejs/node-v0.x-archive/issues/2227: unknown digest 109// method should throw an error. 110assert.throws(function() { 111 crypto.createHash('xyzzy'); 112}, /Digest method not supported/); 113 114// Issue https://github.com/nodejs/node/issues/9819: throwing encoding used to 115// segfault. 116assert.throws( 117 () => crypto.createHash('sha256').digest({ 118 toString: () => { throw new Error('boom'); }, 119 }), 120 { 121 name: 'Error', 122 message: 'boom' 123 }); 124 125// Issue https://github.com/nodejs/node/issues/25487: error message for invalid 126// arg type to update method should include all possible types 127assert.throws( 128 () => crypto.createHash('sha256').update(), 129 { 130 code: 'ERR_INVALID_ARG_TYPE', 131 name: 'TypeError', 132 }); 133 134// Default UTF-8 encoding 135const hutf8 = crypto.createHash('sha512').update('УТФ-8 text').digest('hex'); 136assert.strictEqual( 137 hutf8, 138 '4b21bbd1a68e690a730ddcb5a8bc94ead9879ffe82580767ad7ec6fa8ba2dea6' + 139 '43a821af66afa9a45b6a78c712fecf0e56dc7f43aef4bcfc8eb5b4d8dca6ea5b'); 140 141assert.notStrictEqual( 142 hutf8, 143 crypto.createHash('sha512').update('УТФ-8 text', 'latin1').digest('hex')); 144 145const h3 = crypto.createHash('sha256'); 146h3.digest(); 147 148assert.throws( 149 () => h3.digest(), 150 { 151 code: 'ERR_CRYPTO_HASH_FINALIZED', 152 name: 'Error' 153 }); 154 155assert.throws( 156 () => h3.update('foo'), 157 { 158 code: 'ERR_CRYPTO_HASH_FINALIZED', 159 name: 'Error' 160 }); 161 162assert.strictEqual( 163 crypto.createHash('sha256').update('test').digest('ucs2'), 164 crypto.createHash('sha256').update('test').digest().toString('ucs2')); 165 166assert.throws( 167 () => crypto.createHash(), 168 { 169 code: 'ERR_INVALID_ARG_TYPE', 170 name: 'TypeError', 171 message: 'The "algorithm" argument must be of type string. ' + 172 'Received undefined' 173 } 174); 175 176{ 177 const Hash = crypto.Hash; 178 const instance = crypto.Hash('sha256'); 179 assert(instance instanceof Hash, 'Hash is expected to return a new instance' + 180 ' when called without `new`'); 181} 182 183// Test XOF hash functions and the outputLength option. 184{ 185 // Default outputLengths. 186 assert.strictEqual(crypto.createHash('shake128').digest('hex'), 187 '7f9c2ba4e88f827d616045507605853e'); 188 assert.strictEqual(crypto.createHash('shake128', null).digest('hex'), 189 '7f9c2ba4e88f827d616045507605853e'); 190 assert.strictEqual(crypto.createHash('shake256').digest('hex'), 191 '46b9dd2b0ba88d13233b3feb743eeb24' + 192 '3fcd52ea62b81b82b50c27646ed5762f'); 193 assert.strictEqual(crypto.createHash('shake256', { outputLength: 0 }) 194 .copy() // Default outputLength. 195 .digest('hex'), 196 '46b9dd2b0ba88d13233b3feb743eeb24' + 197 '3fcd52ea62b81b82b50c27646ed5762f'); 198 199 // Short outputLengths. 200 assert.strictEqual(crypto.createHash('shake128', { outputLength: 0 }) 201 .digest('hex'), 202 ''); 203 assert.strictEqual(crypto.createHash('shake128', { outputLength: 5 }) 204 .copy({ outputLength: 0 }) 205 .digest('hex'), 206 ''); 207 assert.strictEqual(crypto.createHash('shake128', { outputLength: 5 }) 208 .digest('hex'), 209 '7f9c2ba4e8'); 210 assert.strictEqual(crypto.createHash('shake128', { outputLength: 0 }) 211 .copy({ outputLength: 5 }) 212 .digest('hex'), 213 '7f9c2ba4e8'); 214 assert.strictEqual(crypto.createHash('shake128', { outputLength: 15 }) 215 .digest('hex'), 216 '7f9c2ba4e88f827d61604550760585'); 217 assert.strictEqual(crypto.createHash('shake256', { outputLength: 16 }) 218 .digest('hex'), 219 '46b9dd2b0ba88d13233b3feb743eeb24'); 220 221 // Large outputLengths. 222 assert.strictEqual(crypto.createHash('shake128', { outputLength: 128 }) 223 .digest('hex'), 224 '7f9c2ba4e88f827d616045507605853e' + 225 'd73b8093f6efbc88eb1a6eacfa66ef26' + 226 '3cb1eea988004b93103cfb0aeefd2a68' + 227 '6e01fa4a58e8a3639ca8a1e3f9ae57e2' + 228 '35b8cc873c23dc62b8d260169afa2f75' + 229 'ab916a58d974918835d25e6a435085b2' + 230 'badfd6dfaac359a5efbb7bcc4b59d538' + 231 'df9a04302e10c8bc1cbf1a0b3a5120ea'); 232 const superLongHash = crypto.createHash('shake256', { 233 outputLength: 1024 * 1024 234 }).update('The message is shorter than the hash!') 235 .digest('hex'); 236 assert.strictEqual(superLongHash.length, 2 * 1024 * 1024); 237 assert.ok(superLongHash.endsWith('193414035ddba77bf7bba97981e656ec')); 238 assert.ok(superLongHash.startsWith('a2a28dbc49cfd6e5d6ceea3d03e77748')); 239 240 // Non-XOF hash functions should accept valid outputLength options as well. 241 assert.strictEqual(crypto.createHash('sha224', { outputLength: 28 }) 242 .digest('hex'), 243 'd14a028c2a3a2bc9476102bb288234c4' + 244 '15a2b01f828ea62ac5b3e42f'); 245 246 // Passing invalid sizes should throw during creation. 247 assert.throws(() => { 248 crypto.createHash('sha256', { outputLength: 28 }); 249 }, { 250 code: 'ERR_OSSL_EVP_NOT_XOF_OR_INVALID_LENGTH' 251 }); 252 253 for (const outputLength of [null, {}, 'foo', false]) { 254 assert.throws(() => crypto.createHash('sha256', { outputLength }), 255 { code: 'ERR_INVALID_ARG_TYPE' }); 256 } 257 258 for (const outputLength of [-1, .5, Infinity, 2 ** 90]) { 259 assert.throws(() => crypto.createHash('sha256', { outputLength }), 260 { code: 'ERR_OUT_OF_RANGE' }); 261 } 262} 263 264{ 265 const h = crypto.createHash('sha512'); 266 h.digest(); 267 assert.throws(() => h.copy(), { code: 'ERR_CRYPTO_HASH_FINALIZED' }); 268 assert.throws(() => h.digest(), { code: 'ERR_CRYPTO_HASH_FINALIZED' }); 269} 270 271{ 272 const a = crypto.createHash('sha512').update('abc'); 273 const b = a.copy(); 274 const c = b.copy().update('def'); 275 const d = crypto.createHash('sha512').update('abcdef'); 276 assert.strictEqual(a.digest('hex'), b.digest('hex')); 277 assert.strictEqual(c.digest('hex'), d.digest('hex')); 278} 279