1'use strict'; 2 3const { 4 ObjectSetPrototypeOf, 5 Symbol, 6} = primordials; 7 8const { 9 Hash: _Hash, 10 Hmac: _Hmac 11} = internalBinding('crypto'); 12 13const { 14 getDefaultEncoding, 15 kHandle, 16 toBuf 17} = require('internal/crypto/util'); 18 19const { 20 prepareSecretKey 21} = require('internal/crypto/keys'); 22 23const { Buffer } = require('buffer'); 24 25const { 26 ERR_CRYPTO_HASH_FINALIZED, 27 ERR_CRYPTO_HASH_UPDATE_FAILED, 28 ERR_INVALID_ARG_TYPE 29} = require('internal/errors').codes; 30const { 31 validateString, 32 validateUint32 33} = require('internal/validators'); 34const { isArrayBufferView } = require('internal/util/types'); 35const LazyTransform = require('internal/streams/lazy_transform'); 36const kState = Symbol('kState'); 37const kFinalized = Symbol('kFinalized'); 38 39function Hash(algorithm, options) { 40 if (!(this instanceof Hash)) 41 return new Hash(algorithm, options); 42 if (!(algorithm instanceof _Hash)) 43 validateString(algorithm, 'algorithm'); 44 const xofLen = typeof options === 'object' && options !== null ? 45 options.outputLength : undefined; 46 if (xofLen !== undefined) 47 validateUint32(xofLen, 'options.outputLength'); 48 this[kHandle] = new _Hash(algorithm, xofLen); 49 this[kState] = { 50 [kFinalized]: false 51 }; 52 LazyTransform.call(this, options); 53} 54 55ObjectSetPrototypeOf(Hash.prototype, LazyTransform.prototype); 56ObjectSetPrototypeOf(Hash, LazyTransform); 57 58Hash.prototype.copy = function copy(options) { 59 const state = this[kState]; 60 if (state[kFinalized]) 61 throw new ERR_CRYPTO_HASH_FINALIZED(); 62 63 return new Hash(this[kHandle], options); 64}; 65 66Hash.prototype._transform = function _transform(chunk, encoding, callback) { 67 this[kHandle].update(chunk, encoding); 68 callback(); 69}; 70 71Hash.prototype._flush = function _flush(callback) { 72 this.push(this[kHandle].digest()); 73 callback(); 74}; 75 76Hash.prototype.update = function update(data, encoding) { 77 const state = this[kState]; 78 if (state[kFinalized]) 79 throw new ERR_CRYPTO_HASH_FINALIZED(); 80 81 if (typeof data !== 'string' && !isArrayBufferView(data)) { 82 throw new ERR_INVALID_ARG_TYPE('data', 83 ['string', 84 'Buffer', 85 'TypedArray', 86 'DataView'], 87 data); 88 } 89 90 if (!this[kHandle].update(data, encoding || getDefaultEncoding())) 91 throw new ERR_CRYPTO_HASH_UPDATE_FAILED(); 92 return this; 93}; 94 95 96Hash.prototype.digest = function digest(outputEncoding) { 97 const state = this[kState]; 98 if (state[kFinalized]) 99 throw new ERR_CRYPTO_HASH_FINALIZED(); 100 outputEncoding = outputEncoding || getDefaultEncoding(); 101 102 // Explicit conversion for backward compatibility. 103 const ret = this[kHandle].digest(`${outputEncoding}`); 104 state[kFinalized] = true; 105 return ret; 106}; 107 108 109function Hmac(hmac, key, options) { 110 if (!(this instanceof Hmac)) 111 return new Hmac(hmac, key, options); 112 validateString(hmac, 'hmac'); 113 key = prepareSecretKey(key); 114 this[kHandle] = new _Hmac(); 115 this[kHandle].init(hmac, toBuf(key)); 116 this[kState] = { 117 [kFinalized]: false 118 }; 119 LazyTransform.call(this, options); 120} 121 122ObjectSetPrototypeOf(Hmac.prototype, LazyTransform.prototype); 123ObjectSetPrototypeOf(Hmac, LazyTransform); 124 125Hmac.prototype.update = Hash.prototype.update; 126 127Hmac.prototype.digest = function digest(outputEncoding) { 128 const state = this[kState]; 129 outputEncoding = outputEncoding || getDefaultEncoding(); 130 131 if (state[kFinalized]) { 132 const buf = Buffer.from(''); 133 return outputEncoding === 'buffer' ? buf : buf.toString(outputEncoding); 134 } 135 136 // Explicit conversion for backward compatibility. 137 const ret = this[kHandle].digest(`${outputEncoding}`); 138 state[kFinalized] = true; 139 return ret; 140}; 141 142Hmac.prototype._flush = Hash.prototype._flush; 143Hmac.prototype._transform = Hash.prototype._transform; 144 145module.exports = { 146 Hash, 147 Hmac 148}; 149