hash.js 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. 'use strict';
  2. var Buffer = require('safe-buffer').Buffer;
  3. var toBuffer = require('to-buffer');
  4. // prototype class for hash functions
  5. function Hash(blockSize, finalSize) {
  6. this._block = Buffer.alloc(blockSize);
  7. this._finalSize = finalSize;
  8. this._blockSize = blockSize;
  9. this._len = 0;
  10. }
  11. Hash.prototype.update = function (data, enc) {
  12. /* eslint no-param-reassign: 0 */
  13. data = toBuffer(data, enc || 'utf8');
  14. var block = this._block;
  15. var blockSize = this._blockSize;
  16. var length = data.length;
  17. var accum = this._len;
  18. for (var offset = 0; offset < length;) {
  19. var assigned = accum % blockSize;
  20. var remainder = Math.min(length - offset, blockSize - assigned);
  21. for (var i = 0; i < remainder; i++) {
  22. block[assigned + i] = data[offset + i];
  23. }
  24. accum += remainder;
  25. offset += remainder;
  26. if ((accum % blockSize) === 0) {
  27. this._update(block);
  28. }
  29. }
  30. this._len += length;
  31. return this;
  32. };
  33. Hash.prototype.digest = function (enc) {
  34. var rem = this._len % this._blockSize;
  35. this._block[rem] = 0x80;
  36. /*
  37. * zero (rem + 1) trailing bits, where (rem + 1) is the smallest
  38. * non-negative solution to the equation (length + 1 + (rem + 1)) === finalSize mod blockSize
  39. */
  40. this._block.fill(0, rem + 1);
  41. if (rem >= this._finalSize) {
  42. this._update(this._block);
  43. this._block.fill(0);
  44. }
  45. var bits = this._len * 8;
  46. // uint32
  47. if (bits <= 0xffffffff) {
  48. this._block.writeUInt32BE(bits, this._blockSize - 4);
  49. // uint64
  50. } else {
  51. var lowBits = (bits & 0xffffffff) >>> 0;
  52. var highBits = (bits - lowBits) / 0x100000000;
  53. this._block.writeUInt32BE(highBits, this._blockSize - 8);
  54. this._block.writeUInt32BE(lowBits, this._blockSize - 4);
  55. }
  56. this._update(this._block);
  57. var hash = this._hash();
  58. return enc ? hash.toString(enc) : hash;
  59. };
  60. Hash.prototype._update = function () {
  61. throw new Error('_update must be implemented by subclass');
  62. };
  63. module.exports = Hash;