Skip to content

Commit f1862e8

Browse files
committed
Update CipherBase
1 parent c25cbc8 commit f1862e8

File tree

1 file changed

+126
-64
lines changed

1 file changed

+126
-64
lines changed

index.js

Lines changed: 126 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,152 @@
1+
'use strict'
12
var Transform = require('stream').Transform
23
var inherits = require('inherits')
34
var StringDecoder = require('string_decoder').StringDecoder
4-
module.exports = CipherBase
5-
inherits(CipherBase, Transform)
6-
function CipherBase (hashMode) {
7-
Transform.call(this)
8-
this.hashMode = typeof hashMode === 'string'
9-
if (this.hashMode) {
10-
this[hashMode] = this._finalOrDigest
11-
} else {
12-
this.final = this._finalOrDigest
13-
}
14-
this._decoder = null
15-
this._encoding = null
16-
}
17-
CipherBase.prototype.update = function (data, inputEnc, outputEnc) {
18-
if (typeof data === 'string') {
19-
data = new Buffer(data, inputEnc)
20-
}
21-
var outData = this._update(data)
22-
if (this.hashMode) {
23-
return this
24-
}
25-
if (outputEnc) {
26-
outData = this._toString(outData, outputEnc)
5+
6+
var K_CIPHER = 0
7+
var K_DECIPHER = 1
8+
9+
function throwIfNotStringOrBuffer (val, prefix) {
10+
if (!Buffer.isBuffer(val) && typeof val !== 'string') {
11+
throw new TypeError(prefix + ' must be a string or a buffer')
2712
}
28-
return outData
2913
}
3014

31-
CipherBase.prototype.setAutoPadding = function () {}
15+
function throwIfNotBuffer (val, prefix) {
16+
if (!Buffer.isBuffer(val)) throw new TypeError(prefix + ' must be a buffer')
17+
}
3218

33-
CipherBase.prototype.getAuthTag = function () {
34-
throw new Error('trying to get auth tag in unsupported state')
19+
function getDecoder (decoder, encoding) {
20+
decoder = decoder || new StringDecoder(encoding)
21+
if (decoder.encoding !== encoding) throw new Error('Cannot change encoding')
22+
return decoder
3523
}
3624

37-
CipherBase.prototype.setAuthTag = function () {
38-
throw new Error('trying to set auth tag in unsupported state')
25+
function CipherBase (chipher) {
26+
Transform.call(this)
27+
28+
this._kind = chipher ? K_CIPHER : K_DECIPHER
29+
this._authTag = null
30+
this._decoder = null
31+
this._finalized = false
3932
}
4033

41-
CipherBase.prototype.setAAD = function () {
42-
throw new Error('trying to set aad in unsupported state')
34+
inherits(CipherBase, Transform)
35+
36+
CipherBase.prototype._isAuthenticatedMode = function () {
37+
throw new Error('_isAuthenticatedMode is not implemented')
4338
}
4439

45-
CipherBase.prototype._transform = function (data, _, next) {
46-
var err
40+
CipherBase.prototype._transform = function (chunk, encoding, callback) {
41+
var error = null
4742
try {
48-
if (this.hashMode) {
49-
this._update(data)
50-
} else {
51-
this.push(this._update(data))
52-
}
53-
} catch (e) {
54-
err = e
55-
} finally {
56-
next(err)
43+
this.update(chunk, encoding)
44+
} catch (err) {
45+
error = err
5746
}
47+
48+
callback(error)
5849
}
59-
CipherBase.prototype._flush = function (done) {
60-
var err
50+
51+
CipherBase.prototype._flush = function (callback) {
52+
var error = null
6153
try {
62-
this.push(this._final())
63-
} catch (e) {
64-
err = e
65-
} finally {
66-
done(err)
54+
this.push(this.final())
55+
} catch (err) {
56+
error = err
6757
}
58+
59+
callback(error)
6860
}
69-
CipherBase.prototype._finalOrDigest = function (outputEnc) {
70-
var outData = this._final() || new Buffer('')
71-
if (outputEnc) {
72-
outData = this._toString(outData, outputEnc, true)
61+
62+
CipherBase.prototype.update = function (data, inputEncoding, outputEncoding) {
63+
throwIfNotStringOrBuffer(data, 'Cipher data')
64+
if (this._finalized) throw new Error('Trying to add data in unsupported state')
65+
66+
if (!Buffer.isBuffer(data)) data = Buffer.from(data, inputEncoding)
67+
68+
data = this._update(data)
69+
if (outputEncoding && outputEncoding !== 'buffer') {
70+
this._decoder = getDecoder(this._decoder, outputEncoding)
71+
data = this._decoder.write(data)
7372
}
74-
return outData
73+
return data
74+
}
75+
76+
CipherBase.prototype._update = function () {
77+
throw new Error('_update is not implemented')
7578
}
7679

77-
CipherBase.prototype._toString = function (value, enc, fin) {
78-
if (!this._decoder) {
79-
this._decoder = new StringDecoder(enc)
80-
this._encoding = enc
80+
CipherBase.prototype.final = function (outputEncoding) {
81+
if (this._finalized) {
82+
var msg = this._isAuthenticatedMode()
83+
? 'Unsupported state or unable to authenticate data'
84+
: 'Unsupported state'
85+
throw new Error(msg)
8186
}
82-
if (this._encoding !== enc) {
83-
throw new Error('can\'t switch encodings')
87+
this._finalized = true
88+
89+
var data = this._final()
90+
if (outputEncoding && outputEncoding !== 'buffer') {
91+
this._decoder = getDecoder(this._decoder, outputEncoding)
92+
data = this._decoder.end(data)
8493
}
85-
var out = this._decoder.write(value)
86-
if (fin) {
87-
out += this._decoder.end()
94+
95+
if (this._kind === K_DECIPHER && this._isAuthenticatedMode() && this._authTag !== null) {
96+
this._authTag.fill(0)
97+
this._authTag = null
8898
}
89-
return out
99+
100+
return data
101+
}
102+
103+
CipherBase.prototype._final = function (outputEncoding) {
104+
throw new Error('_final is not implemented')
105+
}
106+
107+
CipherBase.prototype.setAutoPadding = function (ap) {
108+
if (this._finalized) {
109+
throw new Error('Attempting to set auto padding in unsupported state')
110+
}
111+
112+
this._setAutoPadding(ap)
113+
return this
114+
}
115+
116+
CipherBase.prototype._setAutoPadding = function (ap) {
117+
throw new Error('_setAutoPadding is not implemented')
118+
}
119+
120+
CipherBase.prototype.getAuthTag = function () {
121+
if (this._kind !== K_CIPHER || this._authTag === null || !this._finalized) {
122+
throw new Error('Attempting to get auth tag in unsupported state')
123+
}
124+
125+
return Buffer.from(this._authTag)
90126
}
127+
128+
CipherBase.prototype.setAuthTag = function (tagbuf) {
129+
throwIfNotBuffer(tagbuf, 'Auth tag')
130+
if (!this._isAuthenticatedMode() || this._kind !== K_DECIPHER || this._finalized) {
131+
throw new Error('Attempting to set auth tag in unsupported state')
132+
}
133+
134+
this._authTag = Buffer.from(tagbuf)
135+
return this
136+
}
137+
138+
CipherBase.prototype.setAAD = function (aadbuf) {
139+
throwIfNotBuffer(aadbuf, 'AAD')
140+
if (!this._isAuthenticatedMode() || this._finalized) {
141+
throw new Error('Attempting to set AAD in unsupported state')
142+
}
143+
144+
this._setAAD(aadbuf)
145+
return this
146+
}
147+
148+
CipherBase.prototype._setAAD = function (aadbuf) {
149+
throw new Error('_setAAD is not implemented')
150+
}
151+
152+
module.exports = CipherBase

0 commit comments

Comments
 (0)