hash.js 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. // prototype class for hash functions
  2. function Hash (blockSize, finalSize) {
  3. this._block = new Buffer(blockSize)
  4. this._finalSize = finalSize
  5. this._blockSize = blockSize
  6. this._len = 0
  7. this._s = 0
  8. }
  9. Hash.prototype.update = function (data, enc) {
  10. if (typeof data === 'string') {
  11. enc = enc || 'utf8'
  12. data = new Buffer(data, enc)
  13. }
  14. var l = this._len += data.length
  15. var s = this._s || 0
  16. var f = 0
  17. var buffer = this._block
  18. while (s < l) {
  19. var t = Math.min(data.length, f + this._blockSize - (s % this._blockSize))
  20. var ch = (t - f)
  21. for (var i = 0; i < ch; i++) {
  22. buffer[(s % this._blockSize) + i] = data[i + f]
  23. }
  24. s += ch
  25. f += ch
  26. if ((s % this._blockSize) === 0) {
  27. this._update(buffer)
  28. }
  29. }
  30. this._s = s
  31. return this
  32. }
  33. Hash.prototype.digest = function (enc) {
  34. // Suppose the length of the message M, in bits, is l
  35. var l = this._len * 8
  36. // Append the bit 1 to the end of the message
  37. this._block[this._len % this._blockSize] = 0x80
  38. // and then k zero bits, where k is the smallest non-negative solution to the equation (l + 1 + k) === finalSize mod blockSize
  39. this._block.fill(0, this._len % this._blockSize + 1)
  40. if (l % (this._blockSize * 8) >= this._finalSize * 8) {
  41. this._update(this._block)
  42. this._block.fill(0)
  43. }
  44. // to this append the block which is equal to the number l written in binary
  45. // TODO: handle case where l is > Math.pow(2, 29)
  46. this._block.writeInt32BE(l, this._blockSize - 4)
  47. var hash = this._update(this._block) || this._hash()
  48. return enc ? hash.toString(enc) : hash
  49. }
  50. Hash.prototype._update = function () {
  51. throw new Error('_update must be implemented by subclass')
  52. }
  53. module.exports = Hash