1 | var aes = require('./aes');
|
2 | var Transform = require('./cipherBase');
|
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 | }
|
22 | Decipher.prototype._transform = function (data, _, next) {
|
23 | this._cache.add(data);
|
24 | var chunk;
|
25 | var thing;
|
26 | while ((chunk = this._cache.get())) {
|
27 | thing = this._mode.decrypt(this, chunk);
|
28 | this.push(thing);
|
29 | }
|
30 | next();
|
31 | };
|
32 | Decipher.prototype._flush = function (next) {
|
33 | var chunk = this._cache.flush();
|
34 | if (!chunk) {
|
35 | return next;
|
36 | }
|
37 |
|
38 | this.push(unpad(this._mode.decrypt(this, chunk)));
|
39 |
|
40 | next();
|
41 | };
|
42 |
|
43 | function Splitter() {
|
44 | if (!(this instanceof Splitter)) {
|
45 | return new Splitter();
|
46 | }
|
47 | this.cache = new Buffer('');
|
48 | }
|
49 | Splitter.prototype.add = function (data) {
|
50 | this.cache = Buffer.concat([this.cache, data]);
|
51 | };
|
52 |
|
53 | Splitter.prototype.get = function () {
|
54 | if (this.cache.length > 16) {
|
55 | var out = this.cache.slice(0, 16);
|
56 | this.cache = this.cache.slice(16);
|
57 | return out;
|
58 | }
|
59 | return null;
|
60 | };
|
61 | Splitter.prototype.flush = function () {
|
62 | if (this.cache.length) {
|
63 | return this.cache;
|
64 | }
|
65 | };
|
66 | function unpad(last) {
|
67 | var padded = last[15];
|
68 | var i = -1;
|
69 | while (++i < padded) {
|
70 | if (last[(i + (16 - padded))] !== padded) {
|
71 | throw new Error('unable to decrypt data');
|
72 | }
|
73 | }
|
74 | if (padded === 16) {
|
75 | return;
|
76 | }
|
77 | return last.slice(0, 16 - padded);
|
78 | }
|
79 |
|
80 | var modelist = {
|
81 | ECB: require('./modes/ecb'),
|
82 | CBC: require('./modes/cbc'),
|
83 | CFB: require('./modes/cfb'),
|
84 | CFB8: require('./modes/cfb8'),
|
85 | CFB1: require('./modes/cfb1'),
|
86 | OFB: require('./modes/ofb'),
|
87 | CTR: require('./modes/ctr'),
|
88 | GCM: require('./modes/ctr')
|
89 | };
|
90 |
|
91 | module.exports = function (crypto) {
|
92 | function createDecipheriv(suite, password, iv) {
|
93 | var config = modes[suite];
|
94 | if (!config) {
|
95 | throw new TypeError('invalid suite type');
|
96 | }
|
97 | if (typeof iv === 'string') {
|
98 | iv = new Buffer(iv);
|
99 | }
|
100 | if (typeof password === 'string') {
|
101 | password = new Buffer(password);
|
102 | }
|
103 | if (password.length !== config.key/8) {
|
104 | throw new TypeError('invalid key length ' + password.length);
|
105 | }
|
106 | if (iv.length !== config.iv) {
|
107 | throw new TypeError('invalid iv length ' + iv.length);
|
108 | }
|
109 | if (config.type === 'stream') {
|
110 | return new StreamCipher(modelist[config.mode], password, iv, true);
|
111 | } else if (config.type === 'auth') {
|
112 | return new AuthCipher(modelist[config.mode], password, iv, true);
|
113 | }
|
114 | return new Decipher(modelist[config.mode], password, iv);
|
115 | }
|
116 |
|
117 | function createDecipher (suite, password) {
|
118 | var config = modes[suite];
|
119 | if (!config) {
|
120 | throw new TypeError('invalid suite type');
|
121 | }
|
122 | var keys = ebtk(crypto, password, config.key, config.iv);
|
123 | return createDecipheriv(suite, keys.key, keys.iv);
|
124 | }
|
125 | return {
|
126 | createDecipher: createDecipher,
|
127 | createDecipheriv: createDecipheriv
|
128 | };
|
129 | };
|