wallet-core/node_modules/browserify-aes/authCipher.js

118 lines
2.9 KiB
JavaScript
Raw Normal View History

2017-05-03 15:35:00 +02:00
var aes = require('./aes')
2017-12-10 21:51:33 +01:00
var Buffer = require('safe-buffer').Buffer
2017-05-03 15:35:00 +02:00
var Transform = require('cipher-base')
var inherits = require('inherits')
var GHASH = require('./ghash')
var xor = require('buffer-xor')
2017-12-10 21:51:33 +01:00
var incr32 = require('./incr32')
2017-05-03 15:35:00 +02:00
2017-12-10 21:51:33 +01:00
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))
2017-05-03 15:35:00 +02:00
}
2017-12-10 21:51:33 +01:00
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) {
2017-05-03 15:35:00 +02:00
Transform.call(this)
2017-12-10 21:51:33 +01:00
var h = Buffer.alloc(4, 0)
2017-05-03 15:35:00 +02:00
this._cipher = new aes.AES(key)
2017-12-10 21:51:33 +01:00
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)
2017-05-03 15:35:00 +02:00
this._decrypt = decrypt
this._alen = 0
this._len = 0
this._mode = mode
2017-12-10 21:51:33 +01:00
2017-05-03 15:35:00 +02:00
this._authTag = null
this._called = false
}
2017-12-10 21:51:33 +01:00
inherits(StreamCipher, Transform)
2017-05-03 15:35:00 +02:00
StreamCipher.prototype._update = function (chunk) {
if (!this._called && this._alen) {
var rump = 16 - (this._alen % 16)
if (rump < 16) {
2017-12-10 21:51:33 +01:00
rump = Buffer.alloc(rump, 0)
2017-05-03 15:35:00 +02:00
this._ghash.update(rump)
}
}
2017-12-10 21:51:33 +01:00
2017-05-03 15:35:00 +02:00
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
}
2017-12-10 21:51:33 +01:00
2017-05-03 15:35:00 +02:00
StreamCipher.prototype._final = function () {
2017-12-10 21:51:33 +01:00
if (this._decrypt && !this._authTag) throw new Error('Unsupported state or unable to authenticate data')
2017-05-03 15:35:00 +02:00
var tag = xor(this._ghash.final(this._alen * 8, this._len * 8), this._cipher.encryptBlock(this._finID))
2017-12-10 21:51:33 +01:00
if (this._decrypt && xorTest(tag, this._authTag)) throw new Error('Unsupported state or unable to authenticate data')
this._authTag = tag
2017-05-03 15:35:00 +02:00
this._cipher.scrub()
}
2017-12-10 21:51:33 +01:00
2017-05-03 15:35:00 +02:00
StreamCipher.prototype.getAuthTag = function getAuthTag () {
2017-12-10 21:51:33 +01:00
if (this._decrypt || !Buffer.isBuffer(this._authTag)) throw new Error('Attempting to get auth tag in unsupported state')
return this._authTag
2017-05-03 15:35:00 +02:00
}
2017-12-10 21:51:33 +01:00
2017-05-03 15:35:00 +02:00
StreamCipher.prototype.setAuthTag = function setAuthTag (tag) {
2017-12-10 21:51:33 +01:00
if (!this._decrypt) throw new Error('Attempting to set auth tag in unsupported state')
this._authTag = tag
2017-05-03 15:35:00 +02:00
}
2017-12-10 21:51:33 +01:00
2017-05-03 15:35:00 +02:00
StreamCipher.prototype.setAAD = function setAAD (buf) {
2017-12-10 21:51:33 +01:00
if (this._called) throw new Error('Attempting to set AAD in unsupported state')
this._ghash.update(buf)
this._alen += buf.length
2017-05-03 15:35:00 +02:00
}
2017-12-10 21:51:33 +01:00
module.exports = StreamCipher