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 message: 'The "data" argument must be of type string or an instance of ' + 133 'Buffer, TypedArray, or DataView. Received undefined' 134 }); 135 136// Default UTF-8 encoding 137const hutf8 = crypto.createHash('sha512').update('УТФ-8 text').digest('hex'); 138assert.strictEqual( 139 hutf8, 140 '4b21bbd1a68e690a730ddcb5a8bc94ead9879ffe82580767ad7ec6fa8ba2dea6' + 141 '43a821af66afa9a45b6a78c712fecf0e56dc7f43aef4bcfc8eb5b4d8dca6ea5b'); 142 143assert.notStrictEqual( 144 hutf8, 145 crypto.createHash('sha512').update('УТФ-8 text', 'latin1').digest('hex')); 146 147const h3 = crypto.createHash('sha256'); 148h3.digest(); 149 150assert.throws( 151 () => h3.digest(), 152 { 153 code: 'ERR_CRYPTO_HASH_FINALIZED', 154 name: 'Error' 155 }); 156 157assert.throws( 158 () => h3.update('foo'), 159 { 160 code: 'ERR_CRYPTO_HASH_FINALIZED', 161 name: 'Error' 162 }); 163 164assert.strictEqual( 165 crypto.createHash('sha256').update('test').digest('ucs2'), 166 crypto.createHash('sha256').update('test').digest().toString('ucs2')); 167 168assert.throws( 169 () => crypto.createHash(), 170 { 171 code: 'ERR_INVALID_ARG_TYPE', 172 name: 'TypeError', 173 message: 'The "algorithm" argument must be of type string. ' + 174 'Received undefined' 175 } 176); 177 178{ 179 const Hash = crypto.Hash; 180 const instance = crypto.Hash('sha256'); 181 assert(instance instanceof Hash, 'Hash is expected to return a new instance' + 182 ' when called without `new`'); 183} 184 185// Test XOF hash functions and the outputLength option. 186{ 187 // Default outputLengths. 188 assert.strictEqual(crypto.createHash('shake128').digest('hex'), 189 '7f9c2ba4e88f827d616045507605853e'); 190 assert.strictEqual(crypto.createHash('shake128', null).digest('hex'), 191 '7f9c2ba4e88f827d616045507605853e'); 192 assert.strictEqual(crypto.createHash('shake256').digest('hex'), 193 '46b9dd2b0ba88d13233b3feb743eeb24' + 194 '3fcd52ea62b81b82b50c27646ed5762f'); 195 assert.strictEqual(crypto.createHash('shake256', { outputLength: 0 }) 196 .copy() // Default outputLength. 197 .digest('hex'), 198 '46b9dd2b0ba88d13233b3feb743eeb24' + 199 '3fcd52ea62b81b82b50c27646ed5762f'); 200 201 // Short outputLengths. 202 assert.strictEqual(crypto.createHash('shake128', { outputLength: 0 }) 203 .digest('hex'), 204 ''); 205 assert.strictEqual(crypto.createHash('shake128', { outputLength: 5 }) 206 .copy({ outputLength: 0 }) 207 .digest('hex'), 208 ''); 209 assert.strictEqual(crypto.createHash('shake128', { outputLength: 5 }) 210 .digest('hex'), 211 '7f9c2ba4e8'); 212 assert.strictEqual(crypto.createHash('shake128', { outputLength: 0 }) 213 .copy({ outputLength: 5 }) 214 .digest('hex'), 215 '7f9c2ba4e8'); 216 assert.strictEqual(crypto.createHash('shake128', { outputLength: 15 }) 217 .digest('hex'), 218 '7f9c2ba4e88f827d61604550760585'); 219 assert.strictEqual(crypto.createHash('shake256', { outputLength: 16 }) 220 .digest('hex'), 221 '46b9dd2b0ba88d13233b3feb743eeb24'); 222 223 // Large outputLengths. 224 assert.strictEqual(crypto.createHash('shake128', { outputLength: 128 }) 225 .digest('hex'), 226 '7f9c2ba4e88f827d616045507605853e' + 227 'd73b8093f6efbc88eb1a6eacfa66ef26' + 228 '3cb1eea988004b93103cfb0aeefd2a68' + 229 '6e01fa4a58e8a3639ca8a1e3f9ae57e2' + 230 '35b8cc873c23dc62b8d260169afa2f75' + 231 'ab916a58d974918835d25e6a435085b2' + 232 'badfd6dfaac359a5efbb7bcc4b59d538' + 233 'df9a04302e10c8bc1cbf1a0b3a5120ea'); 234 const superLongHash = crypto.createHash('shake256', { 235 outputLength: 1024 * 1024 236 }).update('The message is shorter than the hash!') 237 .digest('hex'); 238 assert.strictEqual(superLongHash.length, 2 * 1024 * 1024); 239 assert.ok(superLongHash.endsWith('193414035ddba77bf7bba97981e656ec')); 240 assert.ok(superLongHash.startsWith('a2a28dbc49cfd6e5d6ceea3d03e77748')); 241 242 // Non-XOF hash functions should accept valid outputLength options as well. 243 assert.strictEqual(crypto.createHash('sha224', { outputLength: 28 }) 244 .digest('hex'), 245 'd14a028c2a3a2bc9476102bb288234c4' + 246 '15a2b01f828ea62ac5b3e42f'); 247 248 // Passing invalid sizes should throw during creation. 249 assert.throws(() => { 250 crypto.createHash('sha256', { outputLength: 28 }); 251 }, { 252 code: 'ERR_OSSL_EVP_NOT_XOF_OR_INVALID_LENGTH' 253 }); 254 255 for (const outputLength of [null, {}, 'foo', false]) { 256 assert.throws(() => crypto.createHash('sha256', { outputLength }), 257 { code: 'ERR_INVALID_ARG_TYPE' }); 258 } 259 260 for (const outputLength of [-1, .5, Infinity, 2 ** 90]) { 261 assert.throws(() => crypto.createHash('sha256', { outputLength }), 262 { code: 'ERR_OUT_OF_RANGE' }); 263 } 264} 265 266{ 267 const h = crypto.createHash('sha512'); 268 h.digest(); 269 assert.throws(() => h.copy(), { code: 'ERR_CRYPTO_HASH_FINALIZED' }); 270 assert.throws(() => h.digest(), { code: 'ERR_CRYPTO_HASH_FINALIZED' }); 271} 272 273{ 274 const a = crypto.createHash('sha512').update('abc'); 275 const b = a.copy(); 276 const c = b.copy().update('def'); 277 const d = crypto.createHash('sha512').update('abcdef'); 278 assert.strictEqual(a.digest('hex'), b.digest('hex')); 279 assert.strictEqual(c.digest('hex'), d.digest('hex')); 280} 281