You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							117 lines
						
					
					
						
							2.9 KiB
						
					
					
				
			
		
		
	
	
							117 lines
						
					
					
						
							2.9 KiB
						
					
					
				var aes = require('./aes') | 
						|
var Buffer = require('safe-buffer').Buffer | 
						|
var 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
 | 
						|
 |