Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ultraviolet
GitHub Repository: ultraviolet/bitaddress.org
Path: blob/master/src/cryptojs.blockmodes.js
248 views
1
/*!
2
* Crypto-JS 2.5.4 BlockModes.js
3
* contribution from Simon Greatrix
4
*/
5
6
(function (C) {
7
8
// Create pad namespace
9
var C_pad = C.pad = {};
10
11
// Calculate the number of padding bytes required.
12
function _requiredPadding(cipher, message) {
13
var blockSizeInBytes = cipher._blocksize * 4;
14
var reqd = blockSizeInBytes - message.length % blockSizeInBytes;
15
return reqd;
16
}
17
18
// Remove padding when the final byte gives the number of padding bytes.
19
var _unpadLength = function (cipher, message, alg, padding) {
20
var pad = message.pop();
21
if (pad == 0) {
22
throw new Error("Invalid zero-length padding specified for " + alg
23
+ ". Wrong cipher specification or key used?");
24
}
25
var maxPad = cipher._blocksize * 4;
26
if (pad > maxPad) {
27
throw new Error("Invalid padding length of " + pad
28
+ " specified for " + alg
29
+ ". Wrong cipher specification or key used?");
30
}
31
for (var i = 1; i < pad; i++) {
32
var b = message.pop();
33
if (padding != undefined && padding != b) {
34
throw new Error("Invalid padding byte of 0x" + b.toString(16)
35
+ " specified for " + alg
36
+ ". Wrong cipher specification or key used?");
37
}
38
}
39
};
40
41
// No-operation padding, used for stream ciphers
42
C_pad.NoPadding = {
43
pad: function (cipher, message) { },
44
unpad: function (cipher, message) { }
45
};
46
47
// Zero Padding.
48
//
49
// If the message is not an exact number of blocks, the final block is
50
// completed with 0x00 bytes. There is no unpadding.
51
C_pad.ZeroPadding = {
52
pad: function (cipher, message) {
53
var blockSizeInBytes = cipher._blocksize * 4;
54
var reqd = message.length % blockSizeInBytes;
55
if (reqd != 0) {
56
for (reqd = blockSizeInBytes - reqd; reqd > 0; reqd--) {
57
message.push(0x00);
58
}
59
}
60
},
61
62
unpad: function (cipher, message) {
63
while (message[message.length - 1] == 0) {
64
message.pop();
65
}
66
}
67
};
68
69
// ISO/IEC 7816-4 padding.
70
//
71
// Pads the plain text with an 0x80 byte followed by as many 0x00
72
// bytes are required to complete the block.
73
C_pad.iso7816 = {
74
pad: function (cipher, message) {
75
var reqd = _requiredPadding(cipher, message);
76
message.push(0x80);
77
for (; reqd > 1; reqd--) {
78
message.push(0x00);
79
}
80
},
81
82
unpad: function (cipher, message) {
83
var padLength;
84
for (padLength = cipher._blocksize * 4; padLength > 0; padLength--) {
85
var b = message.pop();
86
if (b == 0x80) return;
87
if (b != 0x00) {
88
throw new Error("ISO-7816 padding byte must be 0, not 0x" + b.toString(16) + ". Wrong cipher specification or key used?");
89
}
90
}
91
throw new Error("ISO-7816 padded beyond cipher block size. Wrong cipher specification or key used?");
92
}
93
};
94
95
// ANSI X.923 padding
96
//
97
// The final block is padded with zeros except for the last byte of the
98
// last block which contains the number of padding bytes.
99
C_pad.ansix923 = {
100
pad: function (cipher, message) {
101
var reqd = _requiredPadding(cipher, message);
102
for (var i = 1; i < reqd; i++) {
103
message.push(0x00);
104
}
105
message.push(reqd);
106
},
107
108
unpad: function (cipher, message) {
109
_unpadLength(cipher, message, "ANSI X.923", 0);
110
}
111
};
112
113
// ISO 10126
114
//
115
// The final block is padded with random bytes except for the last
116
// byte of the last block which contains the number of padding bytes.
117
C_pad.iso10126 = {
118
pad: function (cipher, message) {
119
var reqd = _requiredPadding(cipher, message);
120
for (var i = 1; i < reqd; i++) {
121
message.push(Math.floor(Math.random() * 256));
122
}
123
message.push(reqd);
124
},
125
126
unpad: function (cipher, message) {
127
_unpadLength(cipher, message, "ISO 10126", undefined);
128
}
129
};
130
131
// PKCS7 padding
132
//
133
// PKCS7 is described in RFC 5652. Padding is in whole bytes. The
134
// value of each added byte is the number of bytes that are added,
135
// i.e. N bytes, each of value N are added.
136
C_pad.pkcs7 = {
137
pad: function (cipher, message) {
138
var reqd = _requiredPadding(cipher, message);
139
for (var i = 0; i < reqd; i++) {
140
message.push(reqd);
141
}
142
},
143
144
unpad: function (cipher, message) {
145
_unpadLength(cipher, message, "PKCS 7", message[message.length - 1]);
146
}
147
};
148
149
// Create mode namespace
150
var C_mode = C.mode = {};
151
152
/**
153
* Mode base "class".
154
*/
155
var Mode = C_mode.Mode = function (padding) {
156
if (padding) {
157
this._padding = padding;
158
}
159
};
160
161
Mode.prototype = {
162
encrypt: function (cipher, m, iv) {
163
this._padding.pad(cipher, m);
164
this._doEncrypt(cipher, m, iv);
165
},
166
167
decrypt: function (cipher, m, iv) {
168
this._doDecrypt(cipher, m, iv);
169
this._padding.unpad(cipher, m);
170
},
171
172
// Default padding
173
_padding: C_pad.iso7816
174
};
175
176
177
/**
178
* Electronic Code Book mode.
179
*
180
* ECB applies the cipher directly against each block of the input.
181
*
182
* ECB does not require an initialization vector.
183
*/
184
var ECB = C_mode.ECB = function () {
185
// Call parent constructor
186
Mode.apply(this, arguments);
187
};
188
189
// Inherit from Mode
190
var ECB_prototype = ECB.prototype = new Mode;
191
192
// Concrete steps for Mode template
193
ECB_prototype._doEncrypt = function (cipher, m, iv) {
194
var blockSizeInBytes = cipher._blocksize * 4;
195
// Encrypt each block
196
for (var offset = 0; offset < m.length; offset += blockSizeInBytes) {
197
cipher._encryptblock(m, offset);
198
}
199
};
200
ECB_prototype._doDecrypt = function (cipher, c, iv) {
201
var blockSizeInBytes = cipher._blocksize * 4;
202
// Decrypt each block
203
for (var offset = 0; offset < c.length; offset += blockSizeInBytes) {
204
cipher._decryptblock(c, offset);
205
}
206
};
207
208
// ECB never uses an IV
209
ECB_prototype.fixOptions = function (options) {
210
options.iv = [];
211
};
212
213
214
/**
215
* Cipher block chaining
216
*
217
* The first block is XORed with the IV. Subsequent blocks are XOR with the
218
* previous cipher output.
219
*/
220
var CBC = C_mode.CBC = function () {
221
// Call parent constructor
222
Mode.apply(this, arguments);
223
};
224
225
// Inherit from Mode
226
var CBC_prototype = CBC.prototype = new Mode;
227
228
// Concrete steps for Mode template
229
CBC_prototype._doEncrypt = function (cipher, m, iv) {
230
var blockSizeInBytes = cipher._blocksize * 4;
231
232
// Encrypt each block
233
for (var offset = 0; offset < m.length; offset += blockSizeInBytes) {
234
if (offset == 0) {
235
// XOR first block using IV
236
for (var i = 0; i < blockSizeInBytes; i++)
237
m[i] ^= iv[i];
238
} else {
239
// XOR this block using previous crypted block
240
for (var i = 0; i < blockSizeInBytes; i++)
241
m[offset + i] ^= m[offset + i - blockSizeInBytes];
242
}
243
// Encrypt block
244
cipher._encryptblock(m, offset);
245
}
246
};
247
CBC_prototype._doDecrypt = function (cipher, c, iv) {
248
var blockSizeInBytes = cipher._blocksize * 4;
249
250
// At the start, the previously crypted block is the IV
251
var prevCryptedBlock = iv;
252
253
// Decrypt each block
254
for (var offset = 0; offset < c.length; offset += blockSizeInBytes) {
255
// Save this crypted block
256
var thisCryptedBlock = c.slice(offset, offset + blockSizeInBytes);
257
// Decrypt block
258
cipher._decryptblock(c, offset);
259
// XOR decrypted block using previous crypted block
260
for (var i = 0; i < blockSizeInBytes; i++) {
261
c[offset + i] ^= prevCryptedBlock[i];
262
}
263
prevCryptedBlock = thisCryptedBlock;
264
}
265
};
266
267
268
/**
269
* Cipher feed back
270
*
271
* The cipher output is XORed with the plain text to produce the cipher output,
272
* which is then fed back into the cipher to produce a bit pattern to XOR the
273
* next block with.
274
*
275
* This is a stream cipher mode and does not require padding.
276
*/
277
var CFB = C_mode.CFB = function () {
278
// Call parent constructor
279
Mode.apply(this, arguments);
280
};
281
282
// Inherit from Mode
283
var CFB_prototype = CFB.prototype = new Mode;
284
285
// Override padding
286
CFB_prototype._padding = C_pad.NoPadding;
287
288
// Concrete steps for Mode template
289
CFB_prototype._doEncrypt = function (cipher, m, iv) {
290
var blockSizeInBytes = cipher._blocksize * 4,
291
keystream = iv.slice(0);
292
293
// Encrypt each byte
294
for (var i = 0; i < m.length; i++) {
295
296
var j = i % blockSizeInBytes;
297
if (j == 0) cipher._encryptblock(keystream, 0);
298
299
m[i] ^= keystream[j];
300
keystream[j] = m[i];
301
}
302
};
303
CFB_prototype._doDecrypt = function (cipher, c, iv) {
304
var blockSizeInBytes = cipher._blocksize * 4,
305
keystream = iv.slice(0);
306
307
// Encrypt each byte
308
for (var i = 0; i < c.length; i++) {
309
310
var j = i % blockSizeInBytes;
311
if (j == 0) cipher._encryptblock(keystream, 0);
312
313
var b = c[i];
314
c[i] ^= keystream[j];
315
keystream[j] = b;
316
}
317
};
318
319
320
/**
321
* Output feed back
322
*
323
* The cipher repeatedly encrypts its own output. The output is XORed with the
324
* plain text to produce the cipher text.
325
*
326
* This is a stream cipher mode and does not require padding.
327
*/
328
var OFB = C_mode.OFB = function () {
329
// Call parent constructor
330
Mode.apply(this, arguments);
331
};
332
333
// Inherit from Mode
334
var OFB_prototype = OFB.prototype = new Mode;
335
336
// Override padding
337
OFB_prototype._padding = C_pad.NoPadding;
338
339
// Concrete steps for Mode template
340
OFB_prototype._doEncrypt = function (cipher, m, iv) {
341
342
var blockSizeInBytes = cipher._blocksize * 4,
343
keystream = iv.slice(0);
344
345
// Encrypt each byte
346
for (var i = 0; i < m.length; i++) {
347
348
// Generate keystream
349
if (i % blockSizeInBytes == 0)
350
cipher._encryptblock(keystream, 0);
351
352
// Encrypt byte
353
m[i] ^= keystream[i % blockSizeInBytes];
354
355
}
356
};
357
OFB_prototype._doDecrypt = OFB_prototype._doEncrypt;
358
359
/**
360
* Counter
361
* @author Gergely Risko
362
*
363
* After every block the last 4 bytes of the IV is increased by one
364
* with carry and that IV is used for the next block.
365
*
366
* This is a stream cipher mode and does not require padding.
367
*/
368
var CTR = C_mode.CTR = function () {
369
// Call parent constructor
370
Mode.apply(this, arguments);
371
};
372
373
// Inherit from Mode
374
var CTR_prototype = CTR.prototype = new Mode;
375
376
// Override padding
377
CTR_prototype._padding = C_pad.NoPadding;
378
379
CTR_prototype._doEncrypt = function (cipher, m, iv) {
380
var blockSizeInBytes = cipher._blocksize * 4;
381
var counter = iv.slice(0);
382
383
for (var i = 0; i < m.length; ) {
384
// do not lose iv
385
var keystream = counter.slice(0);
386
387
// Generate keystream for next block
388
cipher._encryptblock(keystream, 0);
389
390
// XOR keystream with block
391
for (var j = 0; i < m.length && j < blockSizeInBytes; j++, i++) {
392
m[i] ^= keystream[j];
393
}
394
395
// Increase counter
396
if (++(counter[blockSizeInBytes - 1]) == 256) {
397
counter[blockSizeInBytes - 1] = 0;
398
if (++(counter[blockSizeInBytes - 2]) == 256) {
399
counter[blockSizeInBytes - 2] = 0;
400
if (++(counter[blockSizeInBytes - 3]) == 256) {
401
counter[blockSizeInBytes - 3] = 0;
402
++(counter[blockSizeInBytes - 4]);
403
}
404
}
405
}
406
}
407
};
408
CTR_prototype._doDecrypt = CTR_prototype._doEncrypt;
409
410
})(Crypto);
411