1 | var aes = require('./aes')
|
2 | var Transform = require('cipher-base')
|
3 | var inherits = require('inherits')
|
4 | var modes = require('./modes')
|
5 | var StreamCipher = require('./streamCipher')
|
6 | var AuthCipher = require('./authCipher')
|
7 | var ebtk = require('evp_bytestokey')
|
8 |
|
9 | inherits(Decipher, Transform)
|
10 | function Decipher (mode, key, iv) {
|
11 | if (!(this instanceof Decipher)) {
|
12 | return new Decipher(mode, key, iv)
|
13 | }
|
14 | Transform.call(this)
|
15 | this._cache = new Splitter()
|
16 | this._last = void 0
|
17 | this._cipher = new aes.AES(key)
|
18 | this._prev = new Buffer(iv.length)
|
19 | iv.copy(this._prev)
|
20 | this._mode = mode
|
21 | this._autopadding = true
|
22 | }
|
23 | Decipher.prototype._update = function (data) {
|
24 | this._cache.add(data)
|
25 | var chunk
|
26 | var thing
|
27 | var out = []
|
28 | while ((chunk = this._cache.get(this._autopadding))) {
|
29 | thing = this._mode.decrypt(this, chunk)
|
30 | out.push(thing)
|
31 | }
|
32 | return Buffer.concat(out)
|
33 | }
|
34 | Decipher.prototype._final = function () {
|
35 | var chunk = this._cache.flush()
|
36 | if (this._autopadding) {
|
37 | return unpad(this._mode.decrypt(this, chunk))
|
38 | } else if (chunk) {
|
39 | throw new Error('data not multiple of block length')
|
40 | }
|
41 | }
|
42 | Decipher.prototype.setAutoPadding = function (setTo) {
|
43 | this._autopadding = !!setTo
|
44 | return this
|
45 | }
|
46 | function Splitter () {
|
47 | if (!(this instanceof Splitter)) {
|
48 | return new Splitter()
|
49 | }
|
50 | this.cache = new Buffer('')
|
51 | }
|
52 | Splitter.prototype.add = function (data) {
|
53 | this.cache = Buffer.concat([this.cache, data])
|
54 | }
|
55 |
|
56 | Splitter.prototype.get = function (autoPadding) {
|
57 | var out
|
58 | if (autoPadding) {
|
59 | if (this.cache.length > 16) {
|
60 | out = this.cache.slice(0, 16)
|
61 | this.cache = this.cache.slice(16)
|
62 | return out
|
63 | }
|
64 | } else {
|
65 | if (this.cache.length >= 16) {
|
66 | out = this.cache.slice(0, 16)
|
67 | this.cache = this.cache.slice(16)
|
68 | return out
|
69 | }
|
70 | }
|
71 | return null
|
72 | }
|
73 | Splitter.prototype.flush = function () {
|
74 | if (this.cache.length) {
|
75 | return this.cache
|
76 | }
|
77 | }
|
78 | function unpad (last) {
|
79 | var padded = last[15]
|
80 | var i = -1
|
81 | while (++i < padded) {
|
82 | if (last[(i + (16 - padded))] !== padded) {
|
83 | throw new Error('unable to decrypt data')
|
84 | }
|
85 | }
|
86 | if (padded === 16) {
|
87 | return
|
88 | }
|
89 | return last.slice(0, 16 - padded)
|
90 | }
|
91 |
|
92 | var modelist = {
|
93 | ECB: require('./modes/ecb'),
|
94 | CBC: require('./modes/cbc'),
|
95 | CFB: require('./modes/cfb'),
|
96 | CFB8: require('./modes/cfb8'),
|
97 | CFB1: require('./modes/cfb1'),
|
98 | OFB: require('./modes/ofb'),
|
99 | CTR: require('./modes/ctr'),
|
100 | GCM: require('./modes/ctr')
|
101 | }
|
102 |
|
103 | function createDecipheriv (suite, password, iv) {
|
104 | var config = modes[suite.toLowerCase()]
|
105 | if (!config) {
|
106 | throw new TypeError('invalid suite type')
|
107 | }
|
108 | if (typeof iv === 'string') {
|
109 | iv = new Buffer(iv)
|
110 | }
|
111 | if (typeof password === 'string') {
|
112 | password = new Buffer(password)
|
113 | }
|
114 | if (password.length !== config.key / 8) {
|
115 | throw new TypeError('invalid key length ' + password.length)
|
116 | }
|
117 | if (iv.length !== config.iv) {
|
118 | throw new TypeError('invalid iv length ' + iv.length)
|
119 | }
|
120 | if (config.type === 'stream') {
|
121 | return new StreamCipher(modelist[config.mode], password, iv, true)
|
122 | } else if (config.type === 'auth') {
|
123 | return new AuthCipher(modelist[config.mode], password, iv, true)
|
124 | }
|
125 | return new Decipher(modelist[config.mode], password, iv)
|
126 | }
|
127 |
|
128 | function createDecipher (suite, password) {
|
129 | var config = modes[suite.toLowerCase()]
|
130 | if (!config) {
|
131 | throw new TypeError('invalid suite type')
|
132 | }
|
133 | var keys = ebtk(password, false, config.key, config.iv)
|
134 | return createDecipheriv(suite, keys.key, keys.iv)
|
135 | }
|
136 | exports.createDecipher = createDecipher
|
137 | exports.createDecipheriv = createDecipheriv
|