| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 | var aes = require('./aes')var Buffer = require('safe-buffer').Buffervar Transform = require('cipher-base')var inherits = require('inherits')var GHASH = require('./ghash')var xor = require('buffer-xor')var incr32 = require('./incr32')function xorTest (a, b) {  var out = 0  if (a.length !== b.length) out++  var len = Math.min(a.length, b.length)  for (var i = 0; i < len; ++i) {    out += (a[i] ^ b[i])  }  return out}function calcIv (self, iv, ck) {  if (iv.length === 12) {    self._finID = Buffer.concat([iv, Buffer.from([0, 0, 0, 1])])    return Buffer.concat([iv, Buffer.from([0, 0, 0, 2])])  }  var ghash = new GHASH(ck)  var len = iv.length  var toPad = len % 16  ghash.update(iv)  if (toPad) {    toPad = 16 - toPad    ghash.update(Buffer.alloc(toPad, 0))  }  ghash.update(Buffer.alloc(8, 0))  var ivBits = len * 8  var tail = Buffer.alloc(8)  tail.writeUIntBE(ivBits, 0, 8)  ghash.update(tail)  self._finID = ghash.state  var out = Buffer.from(self._finID)  incr32(out)  return out}function StreamCipher (mode, key, iv, decrypt) {  Transform.call(this)  var h = Buffer.alloc(4, 0)  this._cipher = new aes.AES(key)  var ck = this._cipher.encryptBlock(h)  this._ghash = new GHASH(ck)  iv = calcIv(this, iv, ck)  this._prev = Buffer.from(iv)  this._cache = Buffer.allocUnsafe(0)  this._secCache = Buffer.allocUnsafe(0)  this._decrypt = decrypt  this._alen = 0  this._len = 0  this._mode = mode  this._authTag = null  this._called = false}inherits(StreamCipher, Transform)StreamCipher.prototype._update = function (chunk) {  if (!this._called && this._alen) {    var rump = 16 - (this._alen % 16)    if (rump < 16) {      rump = Buffer.alloc(rump, 0)      this._ghash.update(rump)    }  }  this._called = true  var out = this._mode.encrypt(this, chunk)  if (this._decrypt) {    this._ghash.update(chunk)  } else {    this._ghash.update(out)  }  this._len += chunk.length  return out}StreamCipher.prototype._final = function () {  if (this._decrypt && !this._authTag) throw new Error('Unsupported state or unable to authenticate data')  var tag = xor(this._ghash.final(this._alen * 8, this._len * 8), this._cipher.encryptBlock(this._finID))  if (this._decrypt && xorTest(tag, this._authTag)) throw new Error('Unsupported state or unable to authenticate data')  this._authTag = tag  this._cipher.scrub()}StreamCipher.prototype.getAuthTag = function getAuthTag () {  if (this._decrypt || !Buffer.isBuffer(this._authTag)) throw new Error('Attempting to get auth tag in unsupported state')  return this._authTag}StreamCipher.prototype.setAuthTag = function setAuthTag (tag) {  if (!this._decrypt) throw new Error('Attempting to set auth tag in unsupported state')  this._authTag = tag}StreamCipher.prototype.setAAD = function setAAD (buf) {  if (this._called) throw new Error('Attempting to set AAD in unsupported state')  this._ghash.update(buf)  this._alen += buf.length}module.exports = StreamCipher
 |