UNPKG

3.83 kBJavaScriptView Raw
1'use strict';
2
3var errors = require('./errors');
4var bitcore = require('bitcore');
5var $ = bitcore.util.preconditions;
6
7// Cipher Block Chaining
8// http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29
9var CBC = function CBC(blockcipher, cipherkeybuf, ivbuf) {
10 if (!(this instanceof CBC)) {
11 return new CBC(blockcipher, cipherkeybuf, ivbuf);
12 }
13
14 this.blockcipher = blockcipher;
15 this.cipherkeybuf = cipherkeybuf;
16 this.ivbuf = ivbuf;
17};
18
19CBC.buf2blockbufs = function(buf, blocksize) {
20 var bytesize = blocksize / 8;
21 var blockbufs = [];
22
23 for (var i = 0; i <= buf.length / bytesize; i++) {
24 var blockbuf = buf.slice(i * bytesize, i * bytesize + bytesize);
25
26 if (blockbuf.length < blocksize) {
27 blockbuf = CBC.pkcs7pad(blockbuf, blocksize);
28 }
29
30 blockbufs.push(blockbuf);
31 }
32
33 return blockbufs;
34};
35
36CBC.blockbufs2buf = function(blockbufs) {
37 var last = blockbufs[blockbufs.length - 1];
38 last = CBC.pkcs7unpad(last);
39 blockbufs[blockbufs.length - 1] = last;
40
41 var buf = Buffer.concat(blockbufs);
42
43 return buf;
44};
45
46CBC.encrypt = function(messagebuf, ivbuf, blockcipher, cipherkeybuf) {
47 var blocksize = ivbuf.length * 8;
48 var blockbufs = CBC.buf2blockbufs(messagebuf, blocksize);
49 var encbufs = CBC.encryptblocks(blockbufs, ivbuf, blockcipher, cipherkeybuf);
50 var encbuf = Buffer.concat(encbufs);
51 return encbuf;
52};
53
54CBC.decrypt = function(encbuf, ivbuf, blockcipher, cipherkeybuf) {
55 var blocksize = ivbuf.length * 8;
56 var bytesize = ivbuf.length;
57 var encbufs = [];
58 for (var i = 0; i < encbuf.length / bytesize; i++) {
59 encbufs.push(encbuf.slice(i * bytesize, i * bytesize + bytesize));
60 }
61 var blockbufs = CBC.decryptblocks(encbufs, ivbuf, blockcipher, cipherkeybuf);
62 var buf = CBC.blockbufs2buf(blockbufs, blocksize);
63 return buf;
64};
65
66CBC.encryptblock = function(blockbuf, ivbuf, blockcipher, cipherkeybuf) {
67 var xorbuf = CBC.xorbufs(blockbuf, ivbuf);
68 var encbuf = blockcipher.encrypt(xorbuf, cipherkeybuf);
69 return encbuf;
70};
71
72CBC.decryptblock = function(encbuf, ivbuf, blockcipher, cipherkeybuf) {
73 var xorbuf = blockcipher.decrypt(encbuf, cipherkeybuf);
74 var blockbuf = CBC.xorbufs(xorbuf, ivbuf);
75 return blockbuf;
76};
77
78CBC.encryptblocks = function(blockbufs, ivbuf, blockcipher, cipherkeybuf) {
79 var encbufs = [];
80
81 for (var i = 0; i < blockbufs.length; i++) {
82 var blockbuf = blockbufs[i];
83 var encbuf = CBC.encryptblock(blockbuf, ivbuf, blockcipher, cipherkeybuf);
84
85 encbufs.push(encbuf);
86
87 ivbuf = encbuf;
88 }
89
90 return encbufs;
91};
92
93CBC.decryptblocks = function(encbufs, ivbuf, blockcipher, cipherkeybuf) {
94 var blockbufs = [];
95
96 for (var i = 0; i < encbufs.length; i++) {
97 var encbuf = encbufs[i];
98 var blockbuf = CBC.decryptblock(encbuf, ivbuf, blockcipher, cipherkeybuf);
99
100 blockbufs.push(blockbuf);
101
102 ivbuf = encbuf;
103 }
104
105 return blockbufs;
106};
107
108CBC.pkcs7pad = function(buf, blocksize) {
109 var bytesize = blocksize / 8;
110 var padbytesize = bytesize - buf.length;
111 var pad = new Buffer(padbytesize);
112 pad.fill(padbytesize);
113 var paddedbuf = Buffer.concat([buf, pad]);
114 return paddedbuf;
115};
116
117CBC.pkcs7unpad = function(paddedbuf) {
118 var padlength = paddedbuf[paddedbuf.length - 1];
119 var padbuf = paddedbuf.slice(paddedbuf.length - padlength, paddedbuf.length);
120 var padbuf2 = new Buffer(padlength);
121 padbuf2.fill(padlength);
122 if (padbuf.toString('hex') !== padbuf2.toString('hex')) {
123 throw new errors.InvalidPadding(padbuf.toString());
124 }
125 return paddedbuf.slice(0, paddedbuf.length - padlength);
126};
127
128CBC.xorbufs = function(buf1, buf2) {
129 $.checkArgument(buf1.length === buf2.length, 'bufs must have the same length');
130
131 var buf = new Buffer(buf1.length);
132
133 for (var i = 0; i < buf1.length; i++) {
134 buf[i] = buf1[i] ^ buf2[i];
135 }
136
137 return buf;
138};
139
140module.exports = CBC;