browserSha256.js
  1  var Buffer = require('buffer/').Buffer;
  2  var hashUtils = require('./browserHashUtils');
  3  
  4  var BLOCK_SIZE = 64;
  5  
  6  var DIGEST_LENGTH = 32;
  7  
  8  var KEY = new Uint32Array([
  9      0x428a2f98,
 10      0x71374491,
 11      0xb5c0fbcf,
 12      0xe9b5dba5,
 13      0x3956c25b,
 14      0x59f111f1,
 15      0x923f82a4,
 16      0xab1c5ed5,
 17      0xd807aa98,
 18      0x12835b01,
 19      0x243185be,
 20      0x550c7dc3,
 21      0x72be5d74,
 22      0x80deb1fe,
 23      0x9bdc06a7,
 24      0xc19bf174,
 25      0xe49b69c1,
 26      0xefbe4786,
 27      0x0fc19dc6,
 28      0x240ca1cc,
 29      0x2de92c6f,
 30      0x4a7484aa,
 31      0x5cb0a9dc,
 32      0x76f988da,
 33      0x983e5152,
 34      0xa831c66d,
 35      0xb00327c8,
 36      0xbf597fc7,
 37      0xc6e00bf3,
 38      0xd5a79147,
 39      0x06ca6351,
 40      0x14292967,
 41      0x27b70a85,
 42      0x2e1b2138,
 43      0x4d2c6dfc,
 44      0x53380d13,
 45      0x650a7354,
 46      0x766a0abb,
 47      0x81c2c92e,
 48      0x92722c85,
 49      0xa2bfe8a1,
 50      0xa81a664b,
 51      0xc24b8b70,
 52      0xc76c51a3,
 53      0xd192e819,
 54      0xd6990624,
 55      0xf40e3585,
 56      0x106aa070,
 57      0x19a4c116,
 58      0x1e376c08,
 59      0x2748774c,
 60      0x34b0bcb5,
 61      0x391c0cb3,
 62      0x4ed8aa4a,
 63      0x5b9cca4f,
 64      0x682e6ff3,
 65      0x748f82ee,
 66      0x78a5636f,
 67      0x84c87814,
 68      0x8cc70208,
 69      0x90befffa,
 70      0xa4506ceb,
 71      0xbef9a3f7,
 72      0xc67178f2
 73  ]);
 74  
 75  var INIT = [
 76      0x6a09e667,
 77      0xbb67ae85,
 78      0x3c6ef372,
 79      0xa54ff53a,
 80      0x510e527f,
 81      0x9b05688c,
 82      0x1f83d9ab,
 83      0x5be0cd19,
 84  ];
 85  
 86  var MAX_HASHABLE_LENGTH = Math.pow(2, 53) - 1;
 87  
 88  /**
 89   * @private
 90   */
 91  function Sha256() {
 92      this.state = [
 93          0x6a09e667,
 94          0xbb67ae85,
 95          0x3c6ef372,
 96          0xa54ff53a,
 97          0x510e527f,
 98          0x9b05688c,
 99          0x1f83d9ab,
100          0x5be0cd19,
101      ];
102      this.temp = new Int32Array(64);
103      this.buffer = new Uint8Array(64);
104      this.bufferLength = 0;
105      this.bytesHashed = 0;
106      /**
107       * @private
108       */
109      this.finished = false;
110  }
111  
112  /**
113   * @api private
114   */
115  module.exports = exports = Sha256;
116  
117  Sha256.BLOCK_SIZE = BLOCK_SIZE;
118  
119  Sha256.prototype.update = function (data) {
120      if (this.finished) {
121          throw new Error('Attempted to update an already finished hash.');
122      }
123  
124      if (hashUtils.isEmptyData(data)) {
125          return this;
126      }
127  
128      data = hashUtils.convertToBuffer(data);
129  
130      var position = 0;
131      var byteLength = data.byteLength;
132      this.bytesHashed += byteLength;
133      if (this.bytesHashed * 8 > MAX_HASHABLE_LENGTH) {
134          throw new Error('Cannot hash more than 2^53 - 1 bits');
135      }
136  
137      while (byteLength > 0) {
138          this.buffer[this.bufferLength++] = data[position++];
139          byteLength--;
140          if (this.bufferLength === BLOCK_SIZE) {
141              this.hashBuffer();
142              this.bufferLength = 0;
143          }
144      }
145  
146      return this;
147  };
148  
149  Sha256.prototype.digest = function (encoding) {
150      if (!this.finished) {
151          var bitsHashed = this.bytesHashed * 8;
152          var bufferView = new DataView(this.buffer.buffer, this.buffer.byteOffset, this.buffer.byteLength);
153          var undecoratedLength = this.bufferLength;
154          bufferView.setUint8(this.bufferLength++, 0x80);
155          // Ensure the final block has enough room for the hashed length
156          if (undecoratedLength % BLOCK_SIZE >= BLOCK_SIZE - 8) {
157              for (var i = this.bufferLength; i < BLOCK_SIZE; i++) {
158                  bufferView.setUint8(i, 0);
159              }
160              this.hashBuffer();
161              this.bufferLength = 0;
162          }
163          for (var i = this.bufferLength; i < BLOCK_SIZE - 8; i++) {
164              bufferView.setUint8(i, 0);
165          }
166          bufferView.setUint32(BLOCK_SIZE - 8, Math.floor(bitsHashed / 0x100000000), true);
167          bufferView.setUint32(BLOCK_SIZE - 4, bitsHashed);
168          this.hashBuffer();
169          this.finished = true;
170      }
171      // The value in state is little-endian rather than big-endian, so flip
172      // each word into a new Uint8Array
173      var out = new Buffer(DIGEST_LENGTH);
174      for (var i = 0; i < 8; i++) {
175          out[i * 4] = (this.state[i] >>> 24) & 0xff;
176          out[i * 4 + 1] = (this.state[i] >>> 16) & 0xff;
177          out[i * 4 + 2] = (this.state[i] >>> 8) & 0xff;
178          out[i * 4 + 3] = (this.state[i] >>> 0) & 0xff;
179      }
180      return encoding ? out.toString(encoding) : out;
181  };
182  
183  Sha256.prototype.hashBuffer = function () {
184      var _a = this,
185          buffer = _a.buffer,
186          state = _a.state;
187      var state0 = state[0],
188          state1 = state[1],
189          state2 = state[2],
190          state3 = state[3],
191          state4 = state[4],
192          state5 = state[5],
193          state6 = state[6],
194          state7 = state[7];
195      for (var i = 0; i < BLOCK_SIZE; i++) {
196          if (i < 16) {
197              this.temp[i] = (((buffer[i * 4] & 0xff) << 24) |
198                  ((buffer[(i * 4) + 1] & 0xff) << 16) |
199                  ((buffer[(i * 4) + 2] & 0xff) << 8) |
200                  (buffer[(i * 4) + 3] & 0xff));
201          }
202          else {
203              var u = this.temp[i - 2];
204              var t1_1 = (u >>> 17 | u << 15) ^
205                  (u >>> 19 | u << 13) ^
206                  (u >>> 10);
207              u = this.temp[i - 15];
208              var t2_1 = (u >>> 7 | u << 25) ^
209                  (u >>> 18 | u << 14) ^
210                  (u >>> 3);
211              this.temp[i] = (t1_1 + this.temp[i - 7] | 0) +
212                  (t2_1 + this.temp[i - 16] | 0);
213          }
214          var t1 = (((((state4 >>> 6 | state4 << 26) ^
215              (state4 >>> 11 | state4 << 21) ^
216              (state4 >>> 25 | state4 << 7))
217              + ((state4 & state5) ^ (~state4 & state6))) | 0)
218              + ((state7 + ((KEY[i] + this.temp[i]) | 0)) | 0)) | 0;
219          var t2 = (((state0 >>> 2 | state0 << 30) ^
220              (state0 >>> 13 | state0 << 19) ^
221              (state0 >>> 22 | state0 << 10)) + ((state0 & state1) ^ (state0 & state2) ^ (state1 & state2))) | 0;
222          state7 = state6;
223          state6 = state5;
224          state5 = state4;
225          state4 = (state3 + t1) | 0;
226          state3 = state2;
227          state2 = state1;
228          state1 = state0;
229          state0 = (t1 + t2) | 0;
230      }
231      state[0] += state0;
232      state[1] += state1;
233      state[2] += state2;
234      state[3] += state3;
235      state[4] += state4;
236      state[5] += state5;
237      state[6] += state6;
238      state[7] += state7;
239  };