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