UNPKG

3.31 kBJavaScriptView Raw
1var aes = require('./aes');
2var Transform = require('./cipherBase');
3var inherits = require('inherits');
4var modes = require('./modes');
5var StreamCipher = require('./streamCipher');
6var AuthCipher = require('./authCipher');
7var ebtk = require('./EVP_BytesToKey');
8
9inherits(Decipher, Transform);
10function 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}
22Decipher.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};
32Decipher.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
43function Splitter() {
44 if (!(this instanceof Splitter)) {
45 return new Splitter();
46 }
47 this.cache = new Buffer('');
48}
49Splitter.prototype.add = function (data) {
50 this.cache = Buffer.concat([this.cache, data]);
51};
52
53Splitter.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};
61Splitter.prototype.flush = function () {
62 if (this.cache.length) {
63 return this.cache;
64 }
65};
66function 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
80var 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
91module.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};