| 'use strict' |
| var Buffer = require('safe-buffer').Buffer |
| var Transform = require('stream').Transform |
| var inherits = require('inherits') |
| |
| function throwIfNotStringOrBuffer (val, prefix) { |
| if (!Buffer.isBuffer(val) && typeof val !== 'string') { |
| throw new TypeError(prefix + ' must be a string or a buffer') |
| } |
| } |
| |
| function HashBase (blockSize) { |
| Transform.call(this) |
| |
| this._block = Buffer.allocUnsafe(blockSize) |
| this._blockSize = blockSize |
| this._blockOffset = 0 |
| this._length = [0, 0, 0, 0] |
| |
| this._finalized = false |
| } |
| |
| inherits(HashBase, Transform) |
| |
| HashBase.prototype._transform = function (chunk, encoding, callback) { |
| var error = null |
| try { |
| this.update(chunk, encoding) |
| } catch (err) { |
| error = err |
| } |
| |
| callback(error) |
| } |
| |
| HashBase.prototype._flush = function (callback) { |
| var error = null |
| try { |
| this.push(this.digest()) |
| } catch (err) { |
| error = err |
| } |
| |
| callback(error) |
| } |
| |
| HashBase.prototype.update = function (data, encoding) { |
| throwIfNotStringOrBuffer(data, 'Data') |
| if (this._finalized) throw new Error('Digest already called') |
| if (!Buffer.isBuffer(data)) data = Buffer.from(data, encoding) |
| |
| // consume data |
| var block = this._block |
| var offset = 0 |
| while (this._blockOffset + data.length - offset >= this._blockSize) { |
| for (var i = this._blockOffset; i < this._blockSize;) block[i++] = data[offset++] |
| this._update() |
| this._blockOffset = 0 |
| } |
| while (offset < data.length) block[this._blockOffset++] = data[offset++] |
| |
| // update length |
| for (var j = 0, carry = data.length * 8; carry > 0; ++j) { |
| this._length[j] += carry |
| carry = (this._length[j] / 0x0100000000) | 0 |
| if (carry > 0) this._length[j] -= 0x0100000000 * carry |
| } |
| |
| return this |
| } |
| |
| HashBase.prototype._update = function () { |
| throw new Error('_update is not implemented') |
| } |
| |
| HashBase.prototype.digest = function (encoding) { |
| if (this._finalized) throw new Error('Digest already called') |
| this._finalized = true |
| |
| var digest = this._digest() |
| if (encoding !== undefined) digest = digest.toString(encoding) |
| |
| // reset state |
| this._block.fill(0) |
| this._blockOffset = 0 |
| for (var i = 0; i < 4; ++i) this._length[i] = 0 |
| |
| return digest |
| } |
| |
| HashBase.prototype._digest = function () { |
| throw new Error('_digest is not implemented') |
| } |
| |
| module.exports = HashBase |