source: trip-planner-front/node_modules/node-forge/lib/cipherModes.js

Last change on this file was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 28.2 KB
Line 
1/**
2 * Supported cipher modes.
3 *
4 * @author Dave Longley
5 *
6 * Copyright (c) 2010-2014 Digital Bazaar, Inc.
7 */
8var forge = require('./forge');
9require('./util');
10
11forge.cipher = forge.cipher || {};
12
13// supported cipher modes
14var modes = module.exports = forge.cipher.modes = forge.cipher.modes || {};
15
16/** Electronic codebook (ECB) (Don't use this; it's not secure) **/
17
18modes.ecb = function(options) {
19 options = options || {};
20 this.name = 'ECB';
21 this.cipher = options.cipher;
22 this.blockSize = options.blockSize || 16;
23 this._ints = this.blockSize / 4;
24 this._inBlock = new Array(this._ints);
25 this._outBlock = new Array(this._ints);
26};
27
28modes.ecb.prototype.start = function(options) {};
29
30modes.ecb.prototype.encrypt = function(input, output, finish) {
31 // not enough input to encrypt
32 if(input.length() < this.blockSize && !(finish && input.length() > 0)) {
33 return true;
34 }
35
36 // get next block
37 for(var i = 0; i < this._ints; ++i) {
38 this._inBlock[i] = input.getInt32();
39 }
40
41 // encrypt block
42 this.cipher.encrypt(this._inBlock, this._outBlock);
43
44 // write output
45 for(var i = 0; i < this._ints; ++i) {
46 output.putInt32(this._outBlock[i]);
47 }
48};
49
50modes.ecb.prototype.decrypt = function(input, output, finish) {
51 // not enough input to decrypt
52 if(input.length() < this.blockSize && !(finish && input.length() > 0)) {
53 return true;
54 }
55
56 // get next block
57 for(var i = 0; i < this._ints; ++i) {
58 this._inBlock[i] = input.getInt32();
59 }
60
61 // decrypt block
62 this.cipher.decrypt(this._inBlock, this._outBlock);
63
64 // write output
65 for(var i = 0; i < this._ints; ++i) {
66 output.putInt32(this._outBlock[i]);
67 }
68};
69
70modes.ecb.prototype.pad = function(input, options) {
71 // add PKCS#7 padding to block (each pad byte is the
72 // value of the number of pad bytes)
73 var padding = (input.length() === this.blockSize ?
74 this.blockSize : (this.blockSize - input.length()));
75 input.fillWithByte(padding, padding);
76 return true;
77};
78
79modes.ecb.prototype.unpad = function(output, options) {
80 // check for error: input data not a multiple of blockSize
81 if(options.overflow > 0) {
82 return false;
83 }
84
85 // ensure padding byte count is valid
86 var len = output.length();
87 var count = output.at(len - 1);
88 if(count > (this.blockSize << 2)) {
89 return false;
90 }
91
92 // trim off padding bytes
93 output.truncate(count);
94 return true;
95};
96
97/** Cipher-block Chaining (CBC) **/
98
99modes.cbc = function(options) {
100 options = options || {};
101 this.name = 'CBC';
102 this.cipher = options.cipher;
103 this.blockSize = options.blockSize || 16;
104 this._ints = this.blockSize / 4;
105 this._inBlock = new Array(this._ints);
106 this._outBlock = new Array(this._ints);
107};
108
109modes.cbc.prototype.start = function(options) {
110 // Note: legacy support for using IV residue (has security flaws)
111 // if IV is null, reuse block from previous processing
112 if(options.iv === null) {
113 // must have a previous block
114 if(!this._prev) {
115 throw new Error('Invalid IV parameter.');
116 }
117 this._iv = this._prev.slice(0);
118 } else if(!('iv' in options)) {
119 throw new Error('Invalid IV parameter.');
120 } else {
121 // save IV as "previous" block
122 this._iv = transformIV(options.iv, this.blockSize);
123 this._prev = this._iv.slice(0);
124 }
125};
126
127modes.cbc.prototype.encrypt = function(input, output, finish) {
128 // not enough input to encrypt
129 if(input.length() < this.blockSize && !(finish && input.length() > 0)) {
130 return true;
131 }
132
133 // get next block
134 // CBC XOR's IV (or previous block) with plaintext
135 for(var i = 0; i < this._ints; ++i) {
136 this._inBlock[i] = this._prev[i] ^ input.getInt32();
137 }
138
139 // encrypt block
140 this.cipher.encrypt(this._inBlock, this._outBlock);
141
142 // write output, save previous block
143 for(var i = 0; i < this._ints; ++i) {
144 output.putInt32(this._outBlock[i]);
145 }
146 this._prev = this._outBlock;
147};
148
149modes.cbc.prototype.decrypt = function(input, output, finish) {
150 // not enough input to decrypt
151 if(input.length() < this.blockSize && !(finish && input.length() > 0)) {
152 return true;
153 }
154
155 // get next block
156 for(var i = 0; i < this._ints; ++i) {
157 this._inBlock[i] = input.getInt32();
158 }
159
160 // decrypt block
161 this.cipher.decrypt(this._inBlock, this._outBlock);
162
163 // write output, save previous ciphered block
164 // CBC XOR's IV (or previous block) with ciphertext
165 for(var i = 0; i < this._ints; ++i) {
166 output.putInt32(this._prev[i] ^ this._outBlock[i]);
167 }
168 this._prev = this._inBlock.slice(0);
169};
170
171modes.cbc.prototype.pad = function(input, options) {
172 // add PKCS#7 padding to block (each pad byte is the
173 // value of the number of pad bytes)
174 var padding = (input.length() === this.blockSize ?
175 this.blockSize : (this.blockSize - input.length()));
176 input.fillWithByte(padding, padding);
177 return true;
178};
179
180modes.cbc.prototype.unpad = function(output, options) {
181 // check for error: input data not a multiple of blockSize
182 if(options.overflow > 0) {
183 return false;
184 }
185
186 // ensure padding byte count is valid
187 var len = output.length();
188 var count = output.at(len - 1);
189 if(count > (this.blockSize << 2)) {
190 return false;
191 }
192
193 // trim off padding bytes
194 output.truncate(count);
195 return true;
196};
197
198/** Cipher feedback (CFB) **/
199
200modes.cfb = function(options) {
201 options = options || {};
202 this.name = 'CFB';
203 this.cipher = options.cipher;
204 this.blockSize = options.blockSize || 16;
205 this._ints = this.blockSize / 4;
206 this._inBlock = null;
207 this._outBlock = new Array(this._ints);
208 this._partialBlock = new Array(this._ints);
209 this._partialOutput = forge.util.createBuffer();
210 this._partialBytes = 0;
211};
212
213modes.cfb.prototype.start = function(options) {
214 if(!('iv' in options)) {
215 throw new Error('Invalid IV parameter.');
216 }
217 // use IV as first input
218 this._iv = transformIV(options.iv, this.blockSize);
219 this._inBlock = this._iv.slice(0);
220 this._partialBytes = 0;
221};
222
223modes.cfb.prototype.encrypt = function(input, output, finish) {
224 // not enough input to encrypt
225 var inputLength = input.length();
226 if(inputLength === 0) {
227 return true;
228 }
229
230 // encrypt block
231 this.cipher.encrypt(this._inBlock, this._outBlock);
232
233 // handle full block
234 if(this._partialBytes === 0 && inputLength >= this.blockSize) {
235 // XOR input with output, write input as output
236 for(var i = 0; i < this._ints; ++i) {
237 this._inBlock[i] = input.getInt32() ^ this._outBlock[i];
238 output.putInt32(this._inBlock[i]);
239 }
240 return;
241 }
242
243 // handle partial block
244 var partialBytes = (this.blockSize - inputLength) % this.blockSize;
245 if(partialBytes > 0) {
246 partialBytes = this.blockSize - partialBytes;
247 }
248
249 // XOR input with output, write input as partial output
250 this._partialOutput.clear();
251 for(var i = 0; i < this._ints; ++i) {
252 this._partialBlock[i] = input.getInt32() ^ this._outBlock[i];
253 this._partialOutput.putInt32(this._partialBlock[i]);
254 }
255
256 if(partialBytes > 0) {
257 // block still incomplete, restore input buffer
258 input.read -= this.blockSize;
259 } else {
260 // block complete, update input block
261 for(var i = 0; i < this._ints; ++i) {
262 this._inBlock[i] = this._partialBlock[i];
263 }
264 }
265
266 // skip any previous partial bytes
267 if(this._partialBytes > 0) {
268 this._partialOutput.getBytes(this._partialBytes);
269 }
270
271 if(partialBytes > 0 && !finish) {
272 output.putBytes(this._partialOutput.getBytes(
273 partialBytes - this._partialBytes));
274 this._partialBytes = partialBytes;
275 return true;
276 }
277
278 output.putBytes(this._partialOutput.getBytes(
279 inputLength - this._partialBytes));
280 this._partialBytes = 0;
281};
282
283modes.cfb.prototype.decrypt = function(input, output, finish) {
284 // not enough input to decrypt
285 var inputLength = input.length();
286 if(inputLength === 0) {
287 return true;
288 }
289
290 // encrypt block (CFB always uses encryption mode)
291 this.cipher.encrypt(this._inBlock, this._outBlock);
292
293 // handle full block
294 if(this._partialBytes === 0 && inputLength >= this.blockSize) {
295 // XOR input with output, write input as output
296 for(var i = 0; i < this._ints; ++i) {
297 this._inBlock[i] = input.getInt32();
298 output.putInt32(this._inBlock[i] ^ this._outBlock[i]);
299 }
300 return;
301 }
302
303 // handle partial block
304 var partialBytes = (this.blockSize - inputLength) % this.blockSize;
305 if(partialBytes > 0) {
306 partialBytes = this.blockSize - partialBytes;
307 }
308
309 // XOR input with output, write input as partial output
310 this._partialOutput.clear();
311 for(var i = 0; i < this._ints; ++i) {
312 this._partialBlock[i] = input.getInt32();
313 this._partialOutput.putInt32(this._partialBlock[i] ^ this._outBlock[i]);
314 }
315
316 if(partialBytes > 0) {
317 // block still incomplete, restore input buffer
318 input.read -= this.blockSize;
319 } else {
320 // block complete, update input block
321 for(var i = 0; i < this._ints; ++i) {
322 this._inBlock[i] = this._partialBlock[i];
323 }
324 }
325
326 // skip any previous partial bytes
327 if(this._partialBytes > 0) {
328 this._partialOutput.getBytes(this._partialBytes);
329 }
330
331 if(partialBytes > 0 && !finish) {
332 output.putBytes(this._partialOutput.getBytes(
333 partialBytes - this._partialBytes));
334 this._partialBytes = partialBytes;
335 return true;
336 }
337
338 output.putBytes(this._partialOutput.getBytes(
339 inputLength - this._partialBytes));
340 this._partialBytes = 0;
341};
342
343/** Output feedback (OFB) **/
344
345modes.ofb = function(options) {
346 options = options || {};
347 this.name = 'OFB';
348 this.cipher = options.cipher;
349 this.blockSize = options.blockSize || 16;
350 this._ints = this.blockSize / 4;
351 this._inBlock = null;
352 this._outBlock = new Array(this._ints);
353 this._partialOutput = forge.util.createBuffer();
354 this._partialBytes = 0;
355};
356
357modes.ofb.prototype.start = function(options) {
358 if(!('iv' in options)) {
359 throw new Error('Invalid IV parameter.');
360 }
361 // use IV as first input
362 this._iv = transformIV(options.iv, this.blockSize);
363 this._inBlock = this._iv.slice(0);
364 this._partialBytes = 0;
365};
366
367modes.ofb.prototype.encrypt = function(input, output, finish) {
368 // not enough input to encrypt
369 var inputLength = input.length();
370 if(input.length() === 0) {
371 return true;
372 }
373
374 // encrypt block (OFB always uses encryption mode)
375 this.cipher.encrypt(this._inBlock, this._outBlock);
376
377 // handle full block
378 if(this._partialBytes === 0 && inputLength >= this.blockSize) {
379 // XOR input with output and update next input
380 for(var i = 0; i < this._ints; ++i) {
381 output.putInt32(input.getInt32() ^ this._outBlock[i]);
382 this._inBlock[i] = this._outBlock[i];
383 }
384 return;
385 }
386
387 // handle partial block
388 var partialBytes = (this.blockSize - inputLength) % this.blockSize;
389 if(partialBytes > 0) {
390 partialBytes = this.blockSize - partialBytes;
391 }
392
393 // XOR input with output
394 this._partialOutput.clear();
395 for(var i = 0; i < this._ints; ++i) {
396 this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]);
397 }
398
399 if(partialBytes > 0) {
400 // block still incomplete, restore input buffer
401 input.read -= this.blockSize;
402 } else {
403 // block complete, update input block
404 for(var i = 0; i < this._ints; ++i) {
405 this._inBlock[i] = this._outBlock[i];
406 }
407 }
408
409 // skip any previous partial bytes
410 if(this._partialBytes > 0) {
411 this._partialOutput.getBytes(this._partialBytes);
412 }
413
414 if(partialBytes > 0 && !finish) {
415 output.putBytes(this._partialOutput.getBytes(
416 partialBytes - this._partialBytes));
417 this._partialBytes = partialBytes;
418 return true;
419 }
420
421 output.putBytes(this._partialOutput.getBytes(
422 inputLength - this._partialBytes));
423 this._partialBytes = 0;
424};
425
426modes.ofb.prototype.decrypt = modes.ofb.prototype.encrypt;
427
428/** Counter (CTR) **/
429
430modes.ctr = function(options) {
431 options = options || {};
432 this.name = 'CTR';
433 this.cipher = options.cipher;
434 this.blockSize = options.blockSize || 16;
435 this._ints = this.blockSize / 4;
436 this._inBlock = null;
437 this._outBlock = new Array(this._ints);
438 this._partialOutput = forge.util.createBuffer();
439 this._partialBytes = 0;
440};
441
442modes.ctr.prototype.start = function(options) {
443 if(!('iv' in options)) {
444 throw new Error('Invalid IV parameter.');
445 }
446 // use IV as first input
447 this._iv = transformIV(options.iv, this.blockSize);
448 this._inBlock = this._iv.slice(0);
449 this._partialBytes = 0;
450};
451
452modes.ctr.prototype.encrypt = function(input, output, finish) {
453 // not enough input to encrypt
454 var inputLength = input.length();
455 if(inputLength === 0) {
456 return true;
457 }
458
459 // encrypt block (CTR always uses encryption mode)
460 this.cipher.encrypt(this._inBlock, this._outBlock);
461
462 // handle full block
463 if(this._partialBytes === 0 && inputLength >= this.blockSize) {
464 // XOR input with output
465 for(var i = 0; i < this._ints; ++i) {
466 output.putInt32(input.getInt32() ^ this._outBlock[i]);
467 }
468 } else {
469 // handle partial block
470 var partialBytes = (this.blockSize - inputLength) % this.blockSize;
471 if(partialBytes > 0) {
472 partialBytes = this.blockSize - partialBytes;
473 }
474
475 // XOR input with output
476 this._partialOutput.clear();
477 for(var i = 0; i < this._ints; ++i) {
478 this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]);
479 }
480
481 if(partialBytes > 0) {
482 // block still incomplete, restore input buffer
483 input.read -= this.blockSize;
484 }
485
486 // skip any previous partial bytes
487 if(this._partialBytes > 0) {
488 this._partialOutput.getBytes(this._partialBytes);
489 }
490
491 if(partialBytes > 0 && !finish) {
492 output.putBytes(this._partialOutput.getBytes(
493 partialBytes - this._partialBytes));
494 this._partialBytes = partialBytes;
495 return true;
496 }
497
498 output.putBytes(this._partialOutput.getBytes(
499 inputLength - this._partialBytes));
500 this._partialBytes = 0;
501 }
502
503 // block complete, increment counter (input block)
504 inc32(this._inBlock);
505};
506
507modes.ctr.prototype.decrypt = modes.ctr.prototype.encrypt;
508
509/** Galois/Counter Mode (GCM) **/
510
511modes.gcm = function(options) {
512 options = options || {};
513 this.name = 'GCM';
514 this.cipher = options.cipher;
515 this.blockSize = options.blockSize || 16;
516 this._ints = this.blockSize / 4;
517 this._inBlock = new Array(this._ints);
518 this._outBlock = new Array(this._ints);
519 this._partialOutput = forge.util.createBuffer();
520 this._partialBytes = 0;
521
522 // R is actually this value concatenated with 120 more zero bits, but
523 // we only XOR against R so the other zeros have no effect -- we just
524 // apply this value to the first integer in a block
525 this._R = 0xE1000000;
526};
527
528modes.gcm.prototype.start = function(options) {
529 if(!('iv' in options)) {
530 throw new Error('Invalid IV parameter.');
531 }
532 // ensure IV is a byte buffer
533 var iv = forge.util.createBuffer(options.iv);
534
535 // no ciphered data processed yet
536 this._cipherLength = 0;
537
538 // default additional data is none
539 var additionalData;
540 if('additionalData' in options) {
541 additionalData = forge.util.createBuffer(options.additionalData);
542 } else {
543 additionalData = forge.util.createBuffer();
544 }
545
546 // default tag length is 128 bits
547 if('tagLength' in options) {
548 this._tagLength = options.tagLength;
549 } else {
550 this._tagLength = 128;
551 }
552
553 // if tag is given, ensure tag matches tag length
554 this._tag = null;
555 if(options.decrypt) {
556 // save tag to check later
557 this._tag = forge.util.createBuffer(options.tag).getBytes();
558 if(this._tag.length !== (this._tagLength / 8)) {
559 throw new Error('Authentication tag does not match tag length.');
560 }
561 }
562
563 // create tmp storage for hash calculation
564 this._hashBlock = new Array(this._ints);
565
566 // no tag generated yet
567 this.tag = null;
568
569 // generate hash subkey
570 // (apply block cipher to "zero" block)
571 this._hashSubkey = new Array(this._ints);
572 this.cipher.encrypt([0, 0, 0, 0], this._hashSubkey);
573
574 // generate table M
575 // use 4-bit tables (32 component decomposition of a 16 byte value)
576 // 8-bit tables take more space and are known to have security
577 // vulnerabilities (in native implementations)
578 this.componentBits = 4;
579 this._m = this.generateHashTable(this._hashSubkey, this.componentBits);
580
581 // Note: support IV length different from 96 bits? (only supporting
582 // 96 bits is recommended by NIST SP-800-38D)
583 // generate J_0
584 var ivLength = iv.length();
585 if(ivLength === 12) {
586 // 96-bit IV
587 this._j0 = [iv.getInt32(), iv.getInt32(), iv.getInt32(), 1];
588 } else {
589 // IV is NOT 96-bits
590 this._j0 = [0, 0, 0, 0];
591 while(iv.length() > 0) {
592 this._j0 = this.ghash(
593 this._hashSubkey, this._j0,
594 [iv.getInt32(), iv.getInt32(), iv.getInt32(), iv.getInt32()]);
595 }
596 this._j0 = this.ghash(
597 this._hashSubkey, this._j0, [0, 0].concat(from64To32(ivLength * 8)));
598 }
599
600 // generate ICB (initial counter block)
601 this._inBlock = this._j0.slice(0);
602 inc32(this._inBlock);
603 this._partialBytes = 0;
604
605 // consume authentication data
606 additionalData = forge.util.createBuffer(additionalData);
607 // save additional data length as a BE 64-bit number
608 this._aDataLength = from64To32(additionalData.length() * 8);
609 // pad additional data to 128 bit (16 byte) block size
610 var overflow = additionalData.length() % this.blockSize;
611 if(overflow) {
612 additionalData.fillWithByte(0, this.blockSize - overflow);
613 }
614 this._s = [0, 0, 0, 0];
615 while(additionalData.length() > 0) {
616 this._s = this.ghash(this._hashSubkey, this._s, [
617 additionalData.getInt32(),
618 additionalData.getInt32(),
619 additionalData.getInt32(),
620 additionalData.getInt32()
621 ]);
622 }
623};
624
625modes.gcm.prototype.encrypt = function(input, output, finish) {
626 // not enough input to encrypt
627 var inputLength = input.length();
628 if(inputLength === 0) {
629 return true;
630 }
631
632 // encrypt block
633 this.cipher.encrypt(this._inBlock, this._outBlock);
634
635 // handle full block
636 if(this._partialBytes === 0 && inputLength >= this.blockSize) {
637 // XOR input with output
638 for(var i = 0; i < this._ints; ++i) {
639 output.putInt32(this._outBlock[i] ^= input.getInt32());
640 }
641 this._cipherLength += this.blockSize;
642 } else {
643 // handle partial block
644 var partialBytes = (this.blockSize - inputLength) % this.blockSize;
645 if(partialBytes > 0) {
646 partialBytes = this.blockSize - partialBytes;
647 }
648
649 // XOR input with output
650 this._partialOutput.clear();
651 for(var i = 0; i < this._ints; ++i) {
652 this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]);
653 }
654
655 if(partialBytes <= 0 || finish) {
656 // handle overflow prior to hashing
657 if(finish) {
658 // get block overflow
659 var overflow = inputLength % this.blockSize;
660 this._cipherLength += overflow;
661 // truncate for hash function
662 this._partialOutput.truncate(this.blockSize - overflow);
663 } else {
664 this._cipherLength += this.blockSize;
665 }
666
667 // get output block for hashing
668 for(var i = 0; i < this._ints; ++i) {
669 this._outBlock[i] = this._partialOutput.getInt32();
670 }
671 this._partialOutput.read -= this.blockSize;
672 }
673
674 // skip any previous partial bytes
675 if(this._partialBytes > 0) {
676 this._partialOutput.getBytes(this._partialBytes);
677 }
678
679 if(partialBytes > 0 && !finish) {
680 // block still incomplete, restore input buffer, get partial output,
681 // and return early
682 input.read -= this.blockSize;
683 output.putBytes(this._partialOutput.getBytes(
684 partialBytes - this._partialBytes));
685 this._partialBytes = partialBytes;
686 return true;
687 }
688
689 output.putBytes(this._partialOutput.getBytes(
690 inputLength - this._partialBytes));
691 this._partialBytes = 0;
692 }
693
694 // update hash block S
695 this._s = this.ghash(this._hashSubkey, this._s, this._outBlock);
696
697 // increment counter (input block)
698 inc32(this._inBlock);
699};
700
701modes.gcm.prototype.decrypt = function(input, output, finish) {
702 // not enough input to decrypt
703 var inputLength = input.length();
704 if(inputLength < this.blockSize && !(finish && inputLength > 0)) {
705 return true;
706 }
707
708 // encrypt block (GCM always uses encryption mode)
709 this.cipher.encrypt(this._inBlock, this._outBlock);
710
711 // increment counter (input block)
712 inc32(this._inBlock);
713
714 // update hash block S
715 this._hashBlock[0] = input.getInt32();
716 this._hashBlock[1] = input.getInt32();
717 this._hashBlock[2] = input.getInt32();
718 this._hashBlock[3] = input.getInt32();
719 this._s = this.ghash(this._hashSubkey, this._s, this._hashBlock);
720
721 // XOR hash input with output
722 for(var i = 0; i < this._ints; ++i) {
723 output.putInt32(this._outBlock[i] ^ this._hashBlock[i]);
724 }
725
726 // increment cipher data length
727 if(inputLength < this.blockSize) {
728 this._cipherLength += inputLength % this.blockSize;
729 } else {
730 this._cipherLength += this.blockSize;
731 }
732};
733
734modes.gcm.prototype.afterFinish = function(output, options) {
735 var rval = true;
736
737 // handle overflow
738 if(options.decrypt && options.overflow) {
739 output.truncate(this.blockSize - options.overflow);
740 }
741
742 // handle authentication tag
743 this.tag = forge.util.createBuffer();
744
745 // concatenate additional data length with cipher length
746 var lengths = this._aDataLength.concat(from64To32(this._cipherLength * 8));
747
748 // include lengths in hash
749 this._s = this.ghash(this._hashSubkey, this._s, lengths);
750
751 // do GCTR(J_0, S)
752 var tag = [];
753 this.cipher.encrypt(this._j0, tag);
754 for(var i = 0; i < this._ints; ++i) {
755 this.tag.putInt32(this._s[i] ^ tag[i]);
756 }
757
758 // trim tag to length
759 this.tag.truncate(this.tag.length() % (this._tagLength / 8));
760
761 // check authentication tag
762 if(options.decrypt && this.tag.bytes() !== this._tag) {
763 rval = false;
764 }
765
766 return rval;
767};
768
769/**
770 * See NIST SP-800-38D 6.3 (Algorithm 1). This function performs Galois
771 * field multiplication. The field, GF(2^128), is defined by the polynomial:
772 *
773 * x^128 + x^7 + x^2 + x + 1
774 *
775 * Which is represented in little-endian binary form as: 11100001 (0xe1). When
776 * the value of a coefficient is 1, a bit is set. The value R, is the
777 * concatenation of this value and 120 zero bits, yielding a 128-bit value
778 * which matches the block size.
779 *
780 * This function will multiply two elements (vectors of bytes), X and Y, in
781 * the field GF(2^128). The result is initialized to zero. For each bit of
782 * X (out of 128), x_i, if x_i is set, then the result is multiplied (XOR'd)
783 * by the current value of Y. For each bit, the value of Y will be raised by
784 * a power of x (multiplied by the polynomial x). This can be achieved by
785 * shifting Y once to the right. If the current value of Y, prior to being
786 * multiplied by x, has 0 as its LSB, then it is a 127th degree polynomial.
787 * Otherwise, we must divide by R after shifting to find the remainder.
788 *
789 * @param x the first block to multiply by the second.
790 * @param y the second block to multiply by the first.
791 *
792 * @return the block result of the multiplication.
793 */
794modes.gcm.prototype.multiply = function(x, y) {
795 var z_i = [0, 0, 0, 0];
796 var v_i = y.slice(0);
797
798 // calculate Z_128 (block has 128 bits)
799 for(var i = 0; i < 128; ++i) {
800 // if x_i is 0, Z_{i+1} = Z_i (unchanged)
801 // else Z_{i+1} = Z_i ^ V_i
802 // get x_i by finding 32-bit int position, then left shift 1 by remainder
803 var x_i = x[(i / 32) | 0] & (1 << (31 - i % 32));
804 if(x_i) {
805 z_i[0] ^= v_i[0];
806 z_i[1] ^= v_i[1];
807 z_i[2] ^= v_i[2];
808 z_i[3] ^= v_i[3];
809 }
810
811 // if LSB(V_i) is 1, V_i = V_i >> 1
812 // else V_i = (V_i >> 1) ^ R
813 this.pow(v_i, v_i);
814 }
815
816 return z_i;
817};
818
819modes.gcm.prototype.pow = function(x, out) {
820 // if LSB(x) is 1, x = x >>> 1
821 // else x = (x >>> 1) ^ R
822 var lsb = x[3] & 1;
823
824 // always do x >>> 1:
825 // starting with the rightmost integer, shift each integer to the right
826 // one bit, pulling in the bit from the integer to the left as its top
827 // most bit (do this for the last 3 integers)
828 for(var i = 3; i > 0; --i) {
829 out[i] = (x[i] >>> 1) | ((x[i - 1] & 1) << 31);
830 }
831 // shift the first integer normally
832 out[0] = x[0] >>> 1;
833
834 // if lsb was not set, then polynomial had a degree of 127 and doesn't
835 // need to divided; otherwise, XOR with R to find the remainder; we only
836 // need to XOR the first integer since R technically ends w/120 zero bits
837 if(lsb) {
838 out[0] ^= this._R;
839 }
840};
841
842modes.gcm.prototype.tableMultiply = function(x) {
843 // assumes 4-bit tables are used
844 var z = [0, 0, 0, 0];
845 for(var i = 0; i < 32; ++i) {
846 var idx = (i / 8) | 0;
847 var x_i = (x[idx] >>> ((7 - (i % 8)) * 4)) & 0xF;
848 var ah = this._m[i][x_i];
849 z[0] ^= ah[0];
850 z[1] ^= ah[1];
851 z[2] ^= ah[2];
852 z[3] ^= ah[3];
853 }
854 return z;
855};
856
857/**
858 * A continuing version of the GHASH algorithm that operates on a single
859 * block. The hash block, last hash value (Ym) and the new block to hash
860 * are given.
861 *
862 * @param h the hash block.
863 * @param y the previous value for Ym, use [0, 0, 0, 0] for a new hash.
864 * @param x the block to hash.
865 *
866 * @return the hashed value (Ym).
867 */
868modes.gcm.prototype.ghash = function(h, y, x) {
869 y[0] ^= x[0];
870 y[1] ^= x[1];
871 y[2] ^= x[2];
872 y[3] ^= x[3];
873 return this.tableMultiply(y);
874 //return this.multiply(y, h);
875};
876
877/**
878 * Precomputes a table for multiplying against the hash subkey. This
879 * mechanism provides a substantial speed increase over multiplication
880 * performed without a table. The table-based multiplication this table is
881 * for solves X * H by multiplying each component of X by H and then
882 * composing the results together using XOR.
883 *
884 * This function can be used to generate tables with different bit sizes
885 * for the components, however, this implementation assumes there are
886 * 32 components of X (which is a 16 byte vector), therefore each component
887 * takes 4-bits (so the table is constructed with bits=4).
888 *
889 * @param h the hash subkey.
890 * @param bits the bit size for a component.
891 */
892modes.gcm.prototype.generateHashTable = function(h, bits) {
893 // TODO: There are further optimizations that would use only the
894 // first table M_0 (or some variant) along with a remainder table;
895 // this can be explored in the future
896 var multiplier = 8 / bits;
897 var perInt = 4 * multiplier;
898 var size = 16 * multiplier;
899 var m = new Array(size);
900 for(var i = 0; i < size; ++i) {
901 var tmp = [0, 0, 0, 0];
902 var idx = (i / perInt) | 0;
903 var shft = ((perInt - 1 - (i % perInt)) * bits);
904 tmp[idx] = (1 << (bits - 1)) << shft;
905 m[i] = this.generateSubHashTable(this.multiply(tmp, h), bits);
906 }
907 return m;
908};
909
910/**
911 * Generates a table for multiplying against the hash subkey for one
912 * particular component (out of all possible component values).
913 *
914 * @param mid the pre-multiplied value for the middle key of the table.
915 * @param bits the bit size for a component.
916 */
917modes.gcm.prototype.generateSubHashTable = function(mid, bits) {
918 // compute the table quickly by minimizing the number of
919 // POW operations -- they only need to be performed for powers of 2,
920 // all other entries can be composed from those powers using XOR
921 var size = 1 << bits;
922 var half = size >>> 1;
923 var m = new Array(size);
924 m[half] = mid.slice(0);
925 var i = half >>> 1;
926 while(i > 0) {
927 // raise m0[2 * i] and store in m0[i]
928 this.pow(m[2 * i], m[i] = []);
929 i >>= 1;
930 }
931 i = 2;
932 while(i < half) {
933 for(var j = 1; j < i; ++j) {
934 var m_i = m[i];
935 var m_j = m[j];
936 m[i + j] = [
937 m_i[0] ^ m_j[0],
938 m_i[1] ^ m_j[1],
939 m_i[2] ^ m_j[2],
940 m_i[3] ^ m_j[3]
941 ];
942 }
943 i *= 2;
944 }
945 m[0] = [0, 0, 0, 0];
946 /* Note: We could avoid storing these by doing composition during multiply
947 calculate top half using composition by speed is preferred. */
948 for(i = half + 1; i < size; ++i) {
949 var c = m[i ^ half];
950 m[i] = [mid[0] ^ c[0], mid[1] ^ c[1], mid[2] ^ c[2], mid[3] ^ c[3]];
951 }
952 return m;
953};
954
955/** Utility functions */
956
957function transformIV(iv, blockSize) {
958 if(typeof iv === 'string') {
959 // convert iv string into byte buffer
960 iv = forge.util.createBuffer(iv);
961 }
962
963 if(forge.util.isArray(iv) && iv.length > 4) {
964 // convert iv byte array into byte buffer
965 var tmp = iv;
966 iv = forge.util.createBuffer();
967 for(var i = 0; i < tmp.length; ++i) {
968 iv.putByte(tmp[i]);
969 }
970 }
971
972 if(iv.length() < blockSize) {
973 throw new Error(
974 'Invalid IV length; got ' + iv.length() +
975 ' bytes and expected ' + blockSize + ' bytes.');
976 }
977
978 if(!forge.util.isArray(iv)) {
979 // convert iv byte buffer into 32-bit integer array
980 var ints = [];
981 var blocks = blockSize / 4;
982 for(var i = 0; i < blocks; ++i) {
983 ints.push(iv.getInt32());
984 }
985 iv = ints;
986 }
987
988 return iv;
989}
990
991function inc32(block) {
992 // increment last 32 bits of block only
993 block[block.length - 1] = (block[block.length - 1] + 1) & 0xFFFFFFFF;
994}
995
996function from64To32(num) {
997 // convert 64-bit number to two BE Int32s
998 return [(num / 0x100000000) | 0, num & 0xFFFFFFFF];
999}
Note: See TracBrowser for help on using the repository browser.