|
| 1 | +'use strict' |
1 | 2 | var Transform = require('stream').Transform
|
2 | 3 | var inherits = require('inherits')
|
3 | 4 | var StringDecoder = require('string_decoder').StringDecoder
|
4 |
| -module.exports = CipherBase |
5 |
| -inherits(CipherBase, Transform) |
6 |
| -function CipherBase (hashMode) { |
| 5 | + |
| 6 | +exports.CipherBase = CipherBase |
| 7 | +exports.CipherivBase = CipherivBase |
| 8 | +exports.DecipherBase = DecipherBase |
| 9 | +exports.DecipherivBase = DecipherivBase |
| 10 | + |
| 11 | +var K_CIPHER = 0 |
| 12 | +var K_DECIPHER = 1 |
| 13 | + |
| 14 | +function throwIfNotStringOrBuffer (val, prefix) { |
| 15 | + if (!Buffer.isBuffer(val) && typeof val !== 'string') throw new TypeError(prefx + ' must be a string or a buffer') |
| 16 | +} |
| 17 | + |
| 18 | +function throwIfNotBuffer (val, prefix) { |
| 19 | + if (!Buffer.isBuffer(val)) throw new TypeError(prefix + ' must be a buffer') |
| 20 | +} |
| 21 | + |
| 22 | +function getDecoder (decoder, encoding) { |
| 23 | + if (encoding === 'utf-8') encoding = 'utf8' |
| 24 | + decoder = decoder || new StringDecoder(encoding) |
| 25 | + if (decoder.encoding !== encoding) throw new Error('Cannot change encoding') |
| 26 | + return decoder |
| 27 | +} |
| 28 | + |
| 29 | +function toBuf (str, prefix) { |
| 30 | + throwIfNotStringOrBuffer(str, prefix) |
| 31 | + if (typeof str === 'string') return new Buffer(str, 'utf8') |
| 32 | + else return str |
| 33 | +} |
| 34 | + |
| 35 | +function CipherBase (cipher, password) { |
7 | 36 | 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 |
| - } |
| 37 | + |
| 38 | + this._kind = K_CIPHER |
| 39 | + this._authTag = null |
14 | 40 | 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) |
27 |
| - } |
28 |
| - return outData |
| 41 | + this._finalized = false |
| 42 | + |
| 43 | + this._init(toBuf(cipher, 'Cipher type'), toBuf(password, 'Password')) |
29 | 44 | }
|
30 | 45 |
|
31 |
| -CipherBase.prototype.setAutoPadding = function () {} |
| 46 | +inherits(CipherBase, Transform) |
32 | 47 |
|
33 |
| -CipherBase.prototype.getAuthTag = function () { |
34 |
| - throw new Error('trying to get auth tag in unsupported state') |
| 48 | +CipherBase.prototype._init = function () { |
| 49 | + throw new Error('_init is not implemented') |
35 | 50 | }
|
36 | 51 |
|
37 |
| -CipherBase.prototype.setAuthTag = function () { |
38 |
| - throw new Error('trying to set auth tag in unsupported state') |
| 52 | +CipherBase.prototype._initiv = function () { |
| 53 | + throw new Error('_initiv is not implemented') |
39 | 54 | }
|
40 | 55 |
|
41 |
| -CipherBase.prototype.setAAD = function () { |
42 |
| - throw new Error('trying to set aad in unsupported state') |
| 56 | +CipherBase.prototype._isAuthenticatedMode = function () { |
| 57 | + throw new Error('_isAuthenticatedMode is not implemented') |
43 | 58 | }
|
44 | 59 |
|
45 |
| -CipherBase.prototype._transform = function (data, _, next) { |
46 |
| - var err |
| 60 | +CipherBase.prototype._transform = function (chunk, encoding, callback) { |
| 61 | + var error = null |
47 | 62 | 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) |
| 63 | + if (encoding !== 'buffer') chunk = new Buffer(chunk, encoding) |
| 64 | + this.push(this.update(chunk)) |
| 65 | + } catch (err) { |
| 66 | + error = err |
57 | 67 | }
|
| 68 | + |
| 69 | + callback(error) |
58 | 70 | }
|
59 |
| -CipherBase.prototype._flush = function (done) { |
60 |
| - var err |
| 71 | + |
| 72 | +CipherBase.prototype._flush = function (callback) { |
| 73 | + var error = null |
61 | 74 | try {
|
62 | 75 | this.push(this._final())
|
63 |
| - } catch (e) { |
64 |
| - err = e |
65 |
| - } finally { |
66 |
| - done(err) |
| 76 | + } catch (err) { |
| 77 | + error = err |
67 | 78 | }
|
| 79 | + |
| 80 | + callback(error) |
68 | 81 | }
|
69 |
| -CipherBase.prototype._finalOrDigest = function (outputEnc) { |
70 |
| - var outData = this._final() || new Buffer('') |
71 |
| - if (outputEnc) { |
72 |
| - outData = this._toString(outData, outputEnc, true) |
| 82 | + |
| 83 | +CipherBase.prototype.update = function (data, inputEncoding, outputEncoding) { |
| 84 | + throwIfNotStringOrBuffer(data, 'Cipher data') |
| 85 | + if (this._finalized) throw new Error('Trying to add data in unsupported state') |
| 86 | + |
| 87 | + if (!Buffer.isBuffer(data)) data = new Buffer(data, inputEncoding || 'binary') |
| 88 | + |
| 89 | + data = this._update(data) |
| 90 | + if (outputEncoding && outputEncoding !== 'buffer') { |
| 91 | + this._decoder = getDecoder(this._decoder, outputEncoding) |
| 92 | + data = this._decoder.write(data) |
73 | 93 | }
|
74 |
| - return outData |
| 94 | + return data |
75 | 95 | }
|
76 | 96 |
|
77 |
| -CipherBase.prototype._toString = function (value, enc, final) { |
78 |
| - if (!this._decoder) { |
79 |
| - this._decoder = new StringDecoder(enc) |
80 |
| - this._encoding = enc |
81 |
| - } |
82 |
| - if (this._encoding !== enc) { |
83 |
| - throw new Error('can\'t switch encodings') |
| 97 | +CipherBase.prototype._update = function (data) { |
| 98 | + throw new Error('_update is not implemented') |
| 99 | +} |
| 100 | + |
| 101 | +CipherBase.prototype.final = function (encoding) { |
| 102 | + if (this._finalized) { |
| 103 | + var msg = this._isAuthenticatedMode() |
| 104 | + ? 'Unsupported state or unable to authenticate data' |
| 105 | + : 'Unsupported state' |
| 106 | + throw new Error(msg) |
84 | 107 | }
|
85 |
| - var out = this._decoder.write(value) |
86 |
| - if (final) { |
87 |
| - out += this._decoder.end() |
| 108 | + this._finalized = true |
| 109 | + |
| 110 | + var data = this._final() |
| 111 | + if (encoding && encoding !== 'buffer') { |
| 112 | + this._decoder = getDecoder(this._decoder, encoding) |
| 113 | + data = this._decoder.end(data) |
88 | 114 | }
|
89 |
| - return out |
| 115 | + return data |
| 116 | +} |
| 117 | + |
| 118 | +CipherBase.prototype._final = function (data) { |
| 119 | + throw new Error('_final is not implemented') |
90 | 120 | }
|
| 121 | + |
| 122 | +CipherBase.prototype.setAAD = function (aadbuf) { |
| 123 | + throwIfNotBuffer(aadbuf, 'AAD') |
| 124 | + if (!this._isAuthenticatedMode() || this._finalized) throw new Error('Attempting to set AAD in unsupported state') |
| 125 | + this._setAAD(aadbuf) |
| 126 | +} |
| 127 | + |
| 128 | +CipherBase.prototype._setAAD = function (aadbuf) { |
| 129 | + throw new Error('_setAAD is not implemented') |
| 130 | +} |
| 131 | + |
| 132 | +CipherBase.prototype.getAuthTag = function () { |
| 133 | + // only after final and if encrypting |
| 134 | + if (this._kind !== K_CIPHER || this._authTag === null) throw new Error('Attempting to get auth tag in unsupported state') |
| 135 | + return new Buffer(this._authTag) |
| 136 | +} |
| 137 | + |
| 138 | +CipherBase.prototype.setAuthTag = function (tagbuf) { |
| 139 | + if (!Buffer.isBuffer(tagbuf)) throw new TypeError('Not a buffer') |
| 140 | + if (!this._isAuthenticatedMode() || this._kind !== K_DECIPHER || this._finalized) throw new Error('Attempting to set auth tag in unsupported state') |
| 141 | + this._authTag = new Buffer(tagbuf) |
| 142 | +} |
| 143 | + |
| 144 | +CipherBase.prototype.setAutoPadding = function (ap) { |
| 145 | + if (this._finalized) throw new Error('Attempting to set auto padding in unsupported state') |
| 146 | + this._setAutoPadding(!!ap) |
| 147 | +} |
| 148 | + |
| 149 | +CipherBase.prototype._setAutoPadding = function (ap) { |
| 150 | + throw new Error('_setAutoPadding is not implemented') |
| 151 | +} |
| 152 | + |
| 153 | +function CipherivBase (cipher, password, iv) { |
| 154 | + Transform.call(this) |
| 155 | + |
| 156 | + this._kind = K_CIPHER |
| 157 | + this._authTag = null |
| 158 | + this._decoder = null |
| 159 | + this._finalized = false |
| 160 | + |
| 161 | + this._initiv(toBuf(cipher, 'Cipher type'), toBuf(password, 'Password'), toBuf(iv, 'IV')) |
| 162 | +} |
| 163 | + |
| 164 | +inherits(CipherivBase, Transform) |
| 165 | + |
| 166 | +function DecipherBase (cipher, password, iv) { |
| 167 | + Transform.call(this) |
| 168 | + |
| 169 | + this._kind = K_DECIPHER |
| 170 | + this._authTag = null |
| 171 | + this._decoder = null |
| 172 | + this._finalized = false |
| 173 | + |
| 174 | + this._init(toBuf(cipher, 'Cipher type'), toBuf(password, 'Password')) |
| 175 | +} |
| 176 | + |
| 177 | +inherits(DecipherBase, Transform) |
| 178 | + |
| 179 | +function DecipherivBase (cipher, password, iv) { |
| 180 | + Transform.call(this) |
| 181 | + |
| 182 | + this._kind = K_DECIPHER |
| 183 | + this._authTag = null |
| 184 | + this._decoder = null |
| 185 | + this._finalized = false |
| 186 | + |
| 187 | + this._initiv(toBuf(cipher, 'Cipher type'), toBuf(password, 'Password'), toBuf(iv, 'IV')) |
| 188 | +} |
| 189 | + |
| 190 | +inherits(DecipherivBase, Transform) |
0 commit comments