UNPKG

3.04 kBJavaScriptView Raw
1var aes = require('./aes');
2var Transform = require('./cipherBase');
3var inherits = require('inherits');
4var modes = require('./modes');
5var ebtk = require('./EVP_BytesToKey');
6var StreamCipher = require('./streamCipher');
7var AuthCipher = require('./authCipher');
8inherits(Cipher, Transform);
9function Cipher(mode, key, iv) {
10 if (!(this instanceof Cipher)) {
11 return new Cipher(mode, key, iv);
12 }
13 Transform.call(this);
14 this._cache = new Splitter();
15 this._cipher = new aes.AES(key);
16 this._prev = new Buffer(iv.length);
17 iv.copy(this._prev);
18 this._mode = mode;
19}
20Cipher.prototype._transform = function (data, _, next) {
21 this._cache.add(data);
22 var chunk;
23 var thing;
24 while ((chunk = this._cache.get())) {
25 thing = this._mode.encrypt(this, chunk);
26 this.push(thing);
27 }
28 next();
29};
30Cipher.prototype._flush = function (next) {
31 var chunk = this._cache.flush();
32 this.push(this._mode.encrypt(this, chunk));
33 this._cipher.scrub();
34 next();
35};
36
37
38function Splitter() {
39 if (!(this instanceof Splitter)) {
40 return new Splitter();
41 }
42 this.cache = new Buffer('');
43}
44Splitter.prototype.add = function (data) {
45 this.cache = Buffer.concat([this.cache, data]);
46};
47
48Splitter.prototype.get = function () {
49 if (this.cache.length > 15) {
50 var out = this.cache.slice(0, 16);
51 this.cache = this.cache.slice(16);
52 return out;
53 }
54 return null;
55};
56Splitter.prototype.flush = function () {
57 var len = 16 - this.cache.length;
58 var padBuff = new Buffer(len);
59
60 var i = -1;
61 while (++i < len) {
62 padBuff.writeUInt8(len, i);
63 }
64 var out = Buffer.concat([this.cache, padBuff]);
65 return out;
66};
67var modelist = {
68 ECB: require('./modes/ecb'),
69 CBC: require('./modes/cbc'),
70 CFB: require('./modes/cfb'),
71 OFB: require('./modes/ofb'),
72 CTR: require('./modes/ctr'),
73 GCM: require('./modes/ctr')
74};
75module.exports = function (crypto) {
76 function createCipheriv(suite, password, iv) {
77 var config = modes[suite];
78 if (!config) {
79 throw new TypeError('invalid suite type');
80 }
81 if (typeof iv === 'string') {
82 iv = new Buffer(iv);
83 }
84 if (typeof password === 'string') {
85 password = new Buffer(password);
86 }
87 if (password.length !== config.key/8) {
88 throw new TypeError('invalid key length ' + password.length);
89 }
90 if (iv.length !== config.iv) {
91 throw new TypeError('invalid iv length ' + iv.length);
92 }
93 if (config.type === 'stream') {
94 return new StreamCipher(modelist[config.mode], password, iv);
95 } else if (config.type === 'auth') {
96 return new AuthCipher(modelist[config.mode], password, iv);
97 }
98 return new Cipher(modelist[config.mode], password, iv);
99 }
100 function createCipher (suite, password) {
101 var config = modes[suite];
102 if (!config) {
103 throw new TypeError('invalid suite type');
104 }
105 var keys = ebtk(crypto, password, config.key, config.iv);
106 return createCipheriv(suite, keys.key, keys.iv);
107 }
108 return {
109 createCipher: createCipher,
110 createCipheriv: createCipheriv
111 };
112};