• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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