forked from browserify/browserify-aes
-
Notifications
You must be signed in to change notification settings - Fork 0
/
decrypter.js
127 lines (106 loc) · 3.27 KB
/
decrypter.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
var GCM = require('./gcm')
var CCM = require('./ccm')
var Buffer = require('safe-buffer').Buffer
var MODES = require('./modes')
var StreamCipher = require('./streamCipher')
var Transform = require('cipher-base')
var aes = require('./aes')
var ebtk = require('evp_bytestokey')
var inherits = require('inherits')
function Decipher (mode, key, iv) {
Transform.call(this)
this._cache = new Splitter()
this._last = void 0
this._cipher = new aes.AES(key)
this._prev = Buffer.from(iv)
this._mode = mode
this._autopadding = true
}
inherits(Decipher, Transform)
Decipher.prototype._update = function (data) {
this._cache.add(data)
var chunk
var thing
var out = []
while ((chunk = this._cache.get(this._autopadding))) {
thing = this._mode.decrypt(this, chunk)
out.push(thing)
}
return Buffer.concat(out)
}
Decipher.prototype._final = function () {
var chunk = this._cache.flush()
if (this._autopadding) {
return unpad(this._mode.decrypt(this, chunk))
} else if (chunk) {
throw new Error('data not multiple of block length')
}
}
Decipher.prototype.setAutoPadding = function (setTo) {
this._autopadding = !!setTo
return this
}
function Splitter () {
this.cache = Buffer.allocUnsafe(0)
}
Splitter.prototype.add = function (data) {
this.cache = Buffer.concat([this.cache, data])
}
Splitter.prototype.get = function (autoPadding) {
var out
if (autoPadding) {
if (this.cache.length > 16) {
out = this.cache.slice(0, 16)
this.cache = this.cache.slice(16)
return out
}
} else {
if (this.cache.length >= 16) {
out = this.cache.slice(0, 16)
this.cache = this.cache.slice(16)
return out
}
}
return null
}
Splitter.prototype.flush = function () {
if (this.cache.length) return this.cache
}
function unpad (last) {
var padded = last[15]
if (padded < 1 || padded > 16) {
throw new Error('unable to decrypt data')
}
var i = -1
while (++i < padded) {
if (last[(i + (16 - padded))] !== padded) {
throw new Error('unable to decrypt data')
}
}
if (padded === 16) return
return last.slice(0, 16 - padded)
}
function createDecipheriv (suite, password, iv, options) {
var config = MODES[suite.toLowerCase()]
if (!config) throw new TypeError('invalid suite type')
if (typeof iv === 'string') iv = Buffer.from(iv)
if (config.type !== 'auth' && iv.length !== config.iv) throw new TypeError('invalid iv length ' + iv.length)
if (typeof password === 'string') password = Buffer.from(password)
if (password.length !== config.key / 8) throw new TypeError('invalid key length ' + password.length)
if (config.type === 'stream') {
return new StreamCipher(config.module, password, iv, true)
} else if (config.mode === 'GCM') {
return new GCM(config.module, password, iv, true)
} else if (config.mode === 'CCM') {
return new CCM(config.module, password, iv, true, options)
}
return new Decipher(config.module, password, iv)
}
function createDecipher (suite, password, options) {
var config = MODES[suite.toLowerCase()]
if (!config) throw new TypeError('invalid suite type')
var keys = ebtk(password, false, config.key, config.iv)
return createDecipheriv(suite, keys.key, keys.iv, options)
}
exports.createDecipher = createDecipher
exports.createDecipheriv = createDecipheriv