index.js 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. 'use strict'
  2. var Buffer = require('safe-buffer').Buffer
  3. var Transform = require('readable-stream').Transform
  4. var inherits = require('inherits')
  5. function throwIfNotStringOrBuffer (val, prefix) {
  6. if (!Buffer.isBuffer(val) && typeof val !== 'string') {
  7. throw new TypeError(prefix + ' must be a string or a buffer')
  8. }
  9. }
  10. function HashBase (blockSize) {
  11. Transform.call(this)
  12. this._block = Buffer.allocUnsafe(blockSize)
  13. this._blockSize = blockSize
  14. this._blockOffset = 0
  15. this._length = [0, 0, 0, 0]
  16. this._finalized = false
  17. }
  18. inherits(HashBase, Transform)
  19. HashBase.prototype._transform = function (chunk, encoding, callback) {
  20. var error = null
  21. try {
  22. this.update(chunk, encoding)
  23. } catch (err) {
  24. error = err
  25. }
  26. callback(error)
  27. }
  28. HashBase.prototype._flush = function (callback) {
  29. var error = null
  30. try {
  31. this.push(this.digest())
  32. } catch (err) {
  33. error = err
  34. }
  35. callback(error)
  36. }
  37. HashBase.prototype.update = function (data, encoding) {
  38. throwIfNotStringOrBuffer(data, 'Data')
  39. if (this._finalized) throw new Error('Digest already called')
  40. if (!Buffer.isBuffer(data)) data = Buffer.from(data, encoding)
  41. // consume data
  42. var block = this._block
  43. var offset = 0
  44. while (this._blockOffset + data.length - offset >= this._blockSize) {
  45. for (var i = this._blockOffset; i < this._blockSize;) block[i++] = data[offset++]
  46. this._update()
  47. this._blockOffset = 0
  48. }
  49. while (offset < data.length) block[this._blockOffset++] = data[offset++]
  50. // update length
  51. for (var j = 0, carry = data.length * 8; carry > 0; ++j) {
  52. this._length[j] += carry
  53. carry = (this._length[j] / 0x0100000000) | 0
  54. if (carry > 0) this._length[j] -= 0x0100000000 * carry
  55. }
  56. return this
  57. }
  58. HashBase.prototype._update = function () {
  59. throw new Error('_update is not implemented')
  60. }
  61. HashBase.prototype.digest = function (encoding) {
  62. if (this._finalized) throw new Error('Digest already called')
  63. this._finalized = true
  64. var digest = this._digest()
  65. if (encoding !== undefined) digest = digest.toString(encoding)
  66. // reset state
  67. this._block.fill(0)
  68. this._blockOffset = 0
  69. for (var i = 0; i < 4; ++i) this._length[i] = 0
  70. return digest
  71. }
  72. HashBase.prototype._digest = function () {
  73. throw new Error('_digest is not implemented')
  74. }
  75. module.exports = HashBase