• 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 { 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