Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80542 views
1
var aes = require('./aes')
2
var Transform = require('./cipherBase')
3
var inherits = require('inherits')
4
var GHASH = require('./ghash')
5
var xor = require('./xor')
6
inherits(StreamCipher, Transform)
7
module.exports = StreamCipher
8
9
function StreamCipher (mode, key, iv, decrypt) {
10
if (!(this instanceof StreamCipher)) {
11
return new StreamCipher(mode, key, iv)
12
}
13
Transform.call(this)
14
this._finID = Buffer.concat([iv, new Buffer([0, 0, 0, 1])])
15
iv = Buffer.concat([iv, new Buffer([0, 0, 0, 2])])
16
this._cipher = new aes.AES(key)
17
this._prev = new Buffer(iv.length)
18
this._cache = new Buffer('')
19
this._secCache = new Buffer('')
20
this._decrypt = decrypt
21
this._alen = 0
22
this._len = 0
23
iv.copy(this._prev)
24
this._mode = mode
25
var h = new Buffer(4)
26
h.fill(0)
27
this._ghash = new GHASH(this._cipher.encryptBlock(h))
28
this._authTag = null
29
this._called = false
30
}
31
StreamCipher.prototype._update = function (chunk) {
32
if (!this._called && this._alen) {
33
var rump = 16 - (this._alen % 16)
34
if (rump < 16) {
35
rump = new Buffer(rump)
36
rump.fill(0)
37
this._ghash.update(rump)
38
}
39
}
40
this._called = true
41
var out = this._mode.encrypt(this, chunk)
42
if (this._decrypt) {
43
this._ghash.update(chunk)
44
} else {
45
this._ghash.update(out)
46
}
47
this._len += chunk.length
48
return out
49
}
50
StreamCipher.prototype._final = function () {
51
if (this._decrypt && !this._authTag) {
52
throw new Error('Unsupported state or unable to authenticate data')
53
}
54
var tag = xor(this._ghash.final(this._alen * 8, this._len * 8), this._cipher.encryptBlock(this._finID))
55
if (this._decrypt) {
56
if (xorTest(tag, this._authTag)) {
57
throw new Error('Unsupported state or unable to authenticate data')
58
}
59
} else {
60
this._authTag = tag
61
}
62
this._cipher.scrub()
63
}
64
StreamCipher.prototype.getAuthTag = function getAuthTag () {
65
if (!this._decrypt && Buffer.isBuffer(this._authTag)) {
66
return this._authTag
67
} else {
68
throw new Error('Attempting to get auth tag in unsupported state')
69
}
70
}
71
StreamCipher.prototype.setAuthTag = function setAuthTag (tag) {
72
if (this._decrypt) {
73
this._authTag = tag
74
} else {
75
throw new Error('Attempting to set auth tag in unsupported state')
76
}
77
}
78
StreamCipher.prototype.setAAD = function setAAD (buf) {
79
if (!this._called) {
80
this._ghash.update(buf)
81
this._alen += buf.length
82
} else {
83
throw new Error('Attempting to set AAD in unsupported state')
84
}
85
}
86
function xorTest (a, b) {
87
var out = 0
88
if (a.length !== b.length) {
89
out++
90
}
91
var len = Math.min(a.length, b.length)
92
var i = -1
93
while (++i < len) {
94
out += (a[i] ^ b[i])
95
}
96
return out
97
}
98
99