· 6 years ago · Oct 25, 2019, 08:16 PM
1/**
2 * Utility functions for web applications.
3 *
4 * @author Dave Longley
5 *
6 * Copyright (c) 2010-2014 Digital Bazaar, Inc.
7 */
8(function() {
9/* ########## Begin module implementation ########## */
10function initModule(forge) {
11
12/* Utilities API */
13var util = forge.util = forge.util || {};
14
15// define setImmediate and nextTick
16(function() {
17 // use native nextTick
18 if(typeof process !== 'undefined' && process.nextTick) {
19 util.nextTick = process.nextTick;
20 if(typeof setImmediate === 'function') {
21 util.setImmediate = setImmediate;
22 } else {
23 // polyfill setImmediate with nextTick, older versions of node
24 // (those w/o setImmediate) won't totally starve IO
25 util.setImmediate = util.nextTick;
26 }
27 return;
28 }
29
30 // polyfill nextTick with native setImmediate
31 if(typeof setImmediate === 'function') {
32 util.setImmediate = function() { return setImmediate.apply(undefined, arguments); };
33 util.nextTick = function(callback) {
34 return setImmediate(callback);
35 };
36 return;
37 }
38
39 /* Note: A polyfill upgrade pattern is used here to allow combining
40 polyfills. For example, MutationObserver is fast, but blocks UI updates,
41 so it needs to allow UI updates periodically, so it falls back on
42 postMessage or setTimeout. */
43
44 // polyfill with setTimeout
45 util.setImmediate = function(callback) {
46 setTimeout(callback, 0);
47 };
48
49 // upgrade polyfill to use postMessage
50 if(typeof window !== 'undefined' &&
51 typeof window.postMessage === 'function') {
52 var msg = 'forge.setImmediate';
53 var callbacks = [];
54 util.setImmediate = function(callback) {
55 callbacks.push(callback);
56 // only send message when one hasn't been sent in
57 // the current turn of the event loop
58 if(callbacks.length === 1) {
59 window.postMessage(msg, '*');
60 }
61 };
62 function handler(event) {
63 if(event.source === window && event.data === msg) {
64 event.stopPropagation();
65 var copy = callbacks.slice();
66 callbacks.length = 0;
67 copy.forEach(function(callback) {
68 callback();
69 });
70 }
71 }
72 window.addEventListener('message', handler, true);
73 }
74
75 // upgrade polyfill to use MutationObserver
76 if(typeof MutationObserver !== 'undefined') {
77 // polyfill with MutationObserver
78 var now = Date.now();
79 var attr = true;
80 var div = document.createElement('div');
81 var callbacks = [];
82 new MutationObserver(function() {
83 var copy = callbacks.slice();
84 callbacks.length = 0;
85 copy.forEach(function(callback) {
86 callback();
87 });
88 }).observe(div, {attributes: true});
89 var oldSetImmediate = util.setImmediate;
90 util.setImmediate = function(callback) {
91 if(Date.now() - now > 15) {
92 now = Date.now();
93 oldSetImmediate(callback);
94 } else {
95 callbacks.push(callback);
96 // only trigger observer when it hasn't been triggered in
97 // the current turn of the event loop
98 if(callbacks.length === 1) {
99 div.setAttribute('a', attr = !attr);
100 }
101 }
102 };
103 }
104
105 util.nextTick = util.setImmediate;
106})();
107
108// define isArray
109util.isArray = Array.isArray || function(x) {
110 return Object.prototype.toString.call(x) === '[object Array]';
111};
112
113// define isArrayBuffer
114util.isArrayBuffer = function(x) {
115 return typeof ArrayBuffer !== 'undefined' && x instanceof ArrayBuffer;
116};
117
118// define isArrayBufferView
119util.isArrayBufferView = function(x) {
120 return x && util.isArrayBuffer(x.buffer) && x.byteLength !== undefined;
121};
122
123/**
124 * Ensure a bits param is 8, 16, 24, or 32. Used to validate input for
125 * algorithms where bit manipulation, JavaScript limitations, and/or algorithm
126 * design only allow for byte operations of a limited size.
127 *
128 * @param n number of bits.
129 *
130 * Throw Error if n invalid.
131 */
132function _checkBitsParam(n) {
133 if(!(n === 8 || n === 16 || n === 24 || n === 32)) {
134 throw new Error('Only 8, 16, 24, or 32 bits supported: ' + n);
135 }
136}
137
138// TODO: set ByteBuffer to best available backing
139util.ByteBuffer = ByteStringBuffer;
140
141/** Buffer w/BinaryString backing */
142
143/**
144 * Constructor for a binary string backed byte buffer.
145 *
146 * @param [b] the bytes to wrap (either encoded as string, one byte per
147 * character, or as an ArrayBuffer or Typed Array).
148 */
149function ByteStringBuffer(b) {
150 // TODO: update to match DataBuffer API
151
152 // the data in this buffer
153 this.data = '';
154 // the pointer for reading from this buffer
155 this.read = 0;
156
157 if(typeof b === 'string') {
158 this.data = b;
159 } else if(util.isArrayBuffer(b) || util.isArrayBufferView(b)) {
160 // convert native buffer to forge buffer
161 // FIXME: support native buffers internally instead
162 var arr = new Uint8Array(b);
163 try {
164 this.data = String.fromCharCode.apply(null, arr);
165 } catch(e) {
166 for(var i = 0; i < arr.length; ++i) {
167 this.putByte(arr[i]);
168 }
169 }
170 } else if(b instanceof ByteStringBuffer ||
171 (typeof b === 'object' && typeof b.data === 'string' &&
172 typeof b.read === 'number')) {
173 // copy existing buffer
174 this.data = b.data;
175 this.read = b.read;
176 }
177
178 // used for v8 optimization
179 this._constructedStringLength = 0;
180}
181util.ByteStringBuffer = ByteStringBuffer;
182
183/* Note: This is an optimization for V8-based browsers. When V8 concatenates
184 a string, the strings are only joined logically using a "cons string" or
185 "constructed/concatenated string". These containers keep references to one
186 another and can result in very large memory usage. For example, if a 2MB
187 string is constructed by concatenating 4 bytes together at a time, the
188 memory usage will be ~44MB; so ~22x increase. The strings are only joined
189 together when an operation requiring their joining takes place, such as
190 substr(). This function is called when adding data to this buffer to ensure
191 these types of strings are periodically joined to reduce the memory
192 footprint. */
193var _MAX_CONSTRUCTED_STRING_LENGTH = 4096;
194util.ByteStringBuffer.prototype._optimizeConstructedString = function(x) {
195 this._constructedStringLength += x;
196 if(this._constructedStringLength > _MAX_CONSTRUCTED_STRING_LENGTH) {
197 // this substr() should cause the constructed string to join
198 this.data.substr(0, 1);
199 this._constructedStringLength = 0;
200 }
201};
202
203/**
204 * Gets the number of bytes in this buffer.
205 *
206 * @return the number of bytes in this buffer.
207 */
208util.ByteStringBuffer.prototype.length = function() {
209 return this.data.length - this.read;
210};
211
212/**
213 * Gets whether or not this buffer is empty.
214 *
215 * @return true if this buffer is empty, false if not.
216 */
217util.ByteStringBuffer.prototype.isEmpty = function() {
218 return this.length() <= 0;
219};
220
221/**
222 * Puts a byte in this buffer.
223 *
224 * @param b the byte to put.
225 *
226 * @return this buffer.
227 */
228util.ByteStringBuffer.prototype.putByte = function(b) {
229 return this.putBytes(String.fromCharCode(b));
230};
231
232/**
233 * Puts a byte in this buffer N times.
234 *
235 * @param b the byte to put.
236 * @param n the number of bytes of value b to put.
237 *
238 * @return this buffer.
239 */
240util.ByteStringBuffer.prototype.fillWithByte = function(b, n) {
241 b = String.fromCharCode(b);
242 var d = this.data;
243 while(n > 0) {
244 if(n & 1) {
245 d += b;
246 }
247 n >>>= 1;
248 if(n > 0) {
249 b += b;
250 }
251 }
252 this.data = d;
253 this._optimizeConstructedString(n);
254 return this;
255};
256
257/**
258 * Puts bytes in this buffer.
259 *
260 * @param bytes the bytes (as a UTF-8 encoded string) to put.
261 *
262 * @return this buffer.
263 */
264util.ByteStringBuffer.prototype.putBytes = function(bytes) {
265 this.data += bytes;
266 this._optimizeConstructedString(bytes.length);
267 return this;
268};
269
270/**
271 * Puts a UTF-16 encoded string into this buffer.
272 *
273 * @param str the string to put.
274 *
275 * @return this buffer.
276 */
277util.ByteStringBuffer.prototype.putString = function(str) {
278 return this.putBytes(util.encodeUtf8(str));
279};
280
281/**
282 * Puts a 16-bit integer in this buffer in big-endian order.
283 *
284 * @param i the 16-bit integer.
285 *
286 * @return this buffer.
287 */
288util.ByteStringBuffer.prototype.putInt16 = function(i) {
289 return this.putBytes(
290 String.fromCharCode(i >> 8 & 0xFF) +
291 String.fromCharCode(i & 0xFF));
292};
293
294/**
295 * Puts a 24-bit integer in this buffer in big-endian order.
296 *
297 * @param i the 24-bit integer.
298 *
299 * @return this buffer.
300 */
301util.ByteStringBuffer.prototype.putInt24 = function(i) {
302 return this.putBytes(
303 String.fromCharCode(i >> 16 & 0xFF) +
304 String.fromCharCode(i >> 8 & 0xFF) +
305 String.fromCharCode(i & 0xFF));
306};
307
308/**
309 * Puts a 32-bit integer in this buffer in big-endian order.
310 *
311 * @param i the 32-bit integer.
312 *
313 * @return this buffer.
314 */
315util.ByteStringBuffer.prototype.putInt32 = function(i) {
316 return this.putBytes(
317 String.fromCharCode(i >> 24 & 0xFF) +
318 String.fromCharCode(i >> 16 & 0xFF) +
319 String.fromCharCode(i >> 8 & 0xFF) +
320 String.fromCharCode(i & 0xFF));
321};
322
323/**
324 * Puts a 16-bit integer in this buffer in little-endian order.
325 *
326 * @param i the 16-bit integer.
327 *
328 * @return this buffer.
329 */
330util.ByteStringBuffer.prototype.putInt16Le = function(i) {
331 return this.putBytes(
332 String.fromCharCode(i & 0xFF) +
333 String.fromCharCode(i >> 8 & 0xFF));
334};
335
336/**
337 * Puts a 24-bit integer in this buffer in little-endian order.
338 *
339 * @param i the 24-bit integer.
340 *
341 * @return this buffer.
342 */
343util.ByteStringBuffer.prototype.putInt24Le = function(i) {
344 return this.putBytes(
345 String.fromCharCode(i & 0xFF) +
346 String.fromCharCode(i >> 8 & 0xFF) +
347 String.fromCharCode(i >> 16 & 0xFF));
348};
349
350/**
351 * Puts a 32-bit integer in this buffer in little-endian order.
352 *
353 * @param i the 32-bit integer.
354 *
355 * @return this buffer.
356 */
357util.ByteStringBuffer.prototype.putInt32Le = function(i) {
358 return this.putBytes(
359 String.fromCharCode(i & 0xFF) +
360 String.fromCharCode(i >> 8 & 0xFF) +
361 String.fromCharCode(i >> 16 & 0xFF) +
362 String.fromCharCode(i >> 24 & 0xFF));
363};
364
365/**
366 * Puts an n-bit integer in this buffer in big-endian order.
367 *
368 * @param i the n-bit integer.
369 * @param n the number of bits in the integer (8, 16, 24, or 32).
370 *
371 * @return this buffer.
372 */
373util.ByteStringBuffer.prototype.putInt = function(i, n) {
374 _checkBitsParam(n);
375 var bytes = '';
376 do {
377 n -= 8;
378 bytes += String.fromCharCode((i >> n) & 0xFF);
379 } while(n > 0);
380 return this.putBytes(bytes);
381};
382
383/**
384 * Puts a signed n-bit integer in this buffer in big-endian order. Two's
385 * complement representation is used.
386 *
387 * @param i the n-bit integer.
388 * @param n the number of bits in the integer (8, 16, 24, or 32).
389 *
390 * @return this buffer.
391 */
392util.ByteStringBuffer.prototype.putSignedInt = function(i, n) {
393 // putInt checks n
394 if(i < 0) {
395 i += 2 << (n - 1);
396 }
397 return this.putInt(i, n);
398};
399
400/**
401 * Puts the given buffer into this buffer.
402 *
403 * @param buffer the buffer to put into this one.
404 *
405 * @return this buffer.
406 */
407util.ByteStringBuffer.prototype.putBuffer = function(buffer) {
408 return this.putBytes(buffer.getBytes());
409};
410
411/**
412 * Gets a byte from this buffer and advances the read pointer by 1.
413 *
414 * @return the byte.
415 */
416util.ByteStringBuffer.prototype.getByte = function() {
417 return this.data.charCodeAt(this.read++);
418};
419
420/**
421 * Gets a uint16 from this buffer in big-endian order and advances the read
422 * pointer by 2.
423 *
424 * @return the uint16.
425 */
426util.ByteStringBuffer.prototype.getInt16 = function() {
427 var rval = (
428 this.data.charCodeAt(this.read) << 8 ^
429 this.data.charCodeAt(this.read + 1));
430 this.read += 2;
431 return rval;
432};
433
434/**
435 * Gets a uint24 from this buffer in big-endian order and advances the read
436 * pointer by 3.
437 *
438 * @return the uint24.
439 */
440util.ByteStringBuffer.prototype.getInt24 = function() {
441 var rval = (
442 this.data.charCodeAt(this.read) << 16 ^
443 this.data.charCodeAt(this.read + 1) << 8 ^
444 this.data.charCodeAt(this.read + 2));
445 this.read += 3;
446 return rval;
447};
448
449/**
450 * Gets a uint32 from this buffer in big-endian order and advances the read
451 * pointer by 4.
452 *
453 * @return the word.
454 */
455util.ByteStringBuffer.prototype.getInt32 = function() {
456 var rval = (
457 this.data.charCodeAt(this.read) << 24 ^
458 this.data.charCodeAt(this.read + 1) << 16 ^
459 this.data.charCodeAt(this.read + 2) << 8 ^
460 this.data.charCodeAt(this.read + 3));
461 this.read += 4;
462 return rval;
463};
464
465/**
466 * Gets a uint16 from this buffer in little-endian order and advances the read
467 * pointer by 2.
468 *
469 * @return the uint16.
470 */
471util.ByteStringBuffer.prototype.getInt16Le = function() {
472 var rval = (
473 this.data.charCodeAt(this.read) ^
474 this.data.charCodeAt(this.read + 1) << 8);
475 this.read += 2;
476 return rval;
477};
478
479/**
480 * Gets a uint24 from this buffer in little-endian order and advances the read
481 * pointer by 3.
482 *
483 * @return the uint24.
484 */
485util.ByteStringBuffer.prototype.getInt24Le = function() {
486 var rval = (
487 this.data.charCodeAt(this.read) ^
488 this.data.charCodeAt(this.read + 1) << 8 ^
489 this.data.charCodeAt(this.read + 2) << 16);
490 this.read += 3;
491 return rval;
492};
493
494/**
495 * Gets a uint32 from this buffer in little-endian order and advances the read
496 * pointer by 4.
497 *
498 * @return the word.
499 */
500util.ByteStringBuffer.prototype.getInt32Le = function() {
501 var rval = (
502 this.data.charCodeAt(this.read) ^
503 this.data.charCodeAt(this.read + 1) << 8 ^
504 this.data.charCodeAt(this.read + 2) << 16 ^
505 this.data.charCodeAt(this.read + 3) << 24);
506 this.read += 4;
507 return rval;
508};
509
510/**
511 * Gets an n-bit integer from this buffer in big-endian order and advances the
512 * read pointer by ceil(n/8).
513 *
514 * @param n the number of bits in the integer (8, 16, 24, or 32).
515 *
516 * @return the integer.
517 */
518util.ByteStringBuffer.prototype.getInt = function(n) {
519 _checkBitsParam(n);
520 var rval = 0;
521 do {
522 // TODO: Use (rval * 0x100) if adding support for 33 to 53 bits.
523 rval = (rval << 8) + this.data.charCodeAt(this.read++);
524 n -= 8;
525 } while(n > 0);
526 return rval;
527};
528
529/**
530 * Gets a signed n-bit integer from this buffer in big-endian order, using
531 * two's complement, and advances the read pointer by n/8.
532 *
533 * @param n the number of bits in the integer (8, 16, 24, or 32).
534 *
535 * @return the integer.
536 */
537util.ByteStringBuffer.prototype.getSignedInt = function(n) {
538 // getInt checks n
539 var x = this.getInt(n);
540 var max = 2 << (n - 2);
541 if(x >= max) {
542 x -= max << 1;
543 }
544 return x;
545};
546
547/**
548 * Reads bytes out into a UTF-8 string and clears them from the buffer.
549 *
550 * @param count the number of bytes to read, undefined or null for all.
551 *
552 * @return a UTF-8 string of bytes.
553 */
554util.ByteStringBuffer.prototype.getBytes = function(count) {
555 var rval;
556 if(count) {
557 // read count bytes
558 count = Math.min(this.length(), count);
559 rval = this.data.slice(this.read, this.read + count);
560 this.read += count;
561 } else if(count === 0) {
562 rval = '';
563 } else {
564 // read all bytes, optimize to only copy when needed
565 rval = (this.read === 0) ? this.data : this.data.slice(this.read);
566 this.clear();
567 }
568 return rval;
569};
570
571/**
572 * Gets a UTF-8 encoded string of the bytes from this buffer without modifying
573 * the read pointer.
574 *
575 * @param count the number of bytes to get, omit to get all.
576 *
577 * @return a string full of UTF-8 encoded characters.
578 */
579util.ByteStringBuffer.prototype.bytes = function(count) {
580 return (typeof(count) === 'undefined' ?
581 this.data.slice(this.read) :
582 this.data.slice(this.read, this.read + count));
583};
584
585/**
586 * Gets a byte at the given index without modifying the read pointer.
587 *
588 * @param i the byte index.
589 *
590 * @return the byte.
591 */
592util.ByteStringBuffer.prototype.at = function(i) {
593 return this.data.charCodeAt(this.read + i);
594};
595
596/**
597 * Puts a byte at the given index without modifying the read pointer.
598 *
599 * @param i the byte index.
600 * @param b the byte to put.
601 *
602 * @return this buffer.
603 */
604util.ByteStringBuffer.prototype.setAt = function(i, b) {
605 this.data = this.data.substr(0, this.read + i) +
606 String.fromCharCode(b) +
607 this.data.substr(this.read + i + 1);
608 return this;
609};
610
611/**
612 * Gets the last byte without modifying the read pointer.
613 *
614 * @return the last byte.
615 */
616util.ByteStringBuffer.prototype.last = function() {
617 return this.data.charCodeAt(this.data.length - 1);
618};
619
620/**
621 * Creates a copy of this buffer.
622 *
623 * @return the copy.
624 */
625util.ByteStringBuffer.prototype.copy = function() {
626 var c = util.createBuffer(this.data);
627 c.read = this.read;
628 return c;
629};
630
631/**
632 * Compacts this buffer.
633 *
634 * @return this buffer.
635 */
636util.ByteStringBuffer.prototype.compact = function() {
637 if(this.read > 0) {
638 this.data = this.data.slice(this.read);
639 this.read = 0;
640 }
641 return this;
642};
643
644/**
645 * Clears this buffer.
646 *
647 * @return this buffer.
648 */
649util.ByteStringBuffer.prototype.clear = function() {
650 this.data = '';
651 this.read = 0;
652 return this;
653};
654
655/**
656 * Shortens this buffer by triming bytes off of the end of this buffer.
657 *
658 * @param count the number of bytes to trim off.
659 *
660 * @return this buffer.
661 */
662util.ByteStringBuffer.prototype.truncate = function(count) {
663 var len = Math.max(0, this.length() - count);
664 this.data = this.data.substr(this.read, len);
665 this.read = 0;
666 return this;
667};
668
669/**
670 * Converts this buffer to a hexadecimal string.
671 *
672 * @return a hexadecimal string.
673 */
674util.ByteStringBuffer.prototype.toHex = function() {
675 var rval = '';
676 for(var i = this.read; i < this.data.length; ++i) {
677 var b = this.data.charCodeAt(i);
678 if(b < 16) {
679 rval += '0';
680 }
681 rval += b.toString(16);
682 }
683 return rval;
684};
685
686/**
687 * Converts this buffer to a UTF-16 string (standard JavaScript string).
688 *
689 * @return a UTF-16 string.
690 */
691util.ByteStringBuffer.prototype.toString = function() {
692 return util.decodeUtf8(this.bytes());
693};
694
695/** End Buffer w/BinaryString backing */
696
697
698/** Buffer w/UInt8Array backing */
699
700/**
701 * FIXME: Experimental. Do not use yet.
702 *
703 * Constructor for an ArrayBuffer-backed byte buffer.
704 *
705 * The buffer may be constructed from a string, an ArrayBuffer, DataView, or a
706 * TypedArray.
707 *
708 * If a string is given, its encoding should be provided as an option,
709 * otherwise it will default to 'binary'. A 'binary' string is encoded such
710 * that each character is one byte in length and size.
711 *
712 * If an ArrayBuffer, DataView, or TypedArray is given, it will be used
713 * *directly* without any copying. Note that, if a write to the buffer requires
714 * more space, the buffer will allocate a new backing ArrayBuffer to
715 * accommodate. The starting read and write offsets for the buffer may be
716 * given as options.
717 *
718 * @param [b] the initial bytes for this buffer.
719 * @param options the options to use:
720 * [readOffset] the starting read offset to use (default: 0).
721 * [writeOffset] the starting write offset to use (default: the
722 * length of the first parameter).
723 * [growSize] the minimum amount, in bytes, to grow the buffer by to
724 * accommodate writes (default: 1024).
725 * [encoding] the encoding ('binary', 'utf8', 'utf16', 'hex') for the
726 * first parameter, if it is a string (default: 'binary').
727 */
728function DataBuffer(b, options) {
729 // default options
730 options = options || {};
731
732 // pointers for read from/write to buffer
733 this.read = options.readOffset || 0;
734 this.growSize = options.growSize || 1024;
735
736 var isArrayBuffer = util.isArrayBuffer(b);
737 var isArrayBufferView = util.isArrayBufferView(b);
738 if(isArrayBuffer || isArrayBufferView) {
739 // use ArrayBuffer directly
740 if(isArrayBuffer) {
741 this.data = new DataView(b);
742 } else {
743 // TODO: adjust read/write offset based on the type of view
744 // or specify that this must be done in the options ... that the
745 // offsets are byte-based
746 this.data = new DataView(b.buffer, b.byteOffset, b.byteLength);
747 }
748 this.write = ('writeOffset' in options ?
749 options.writeOffset : this.data.byteLength);
750 return;
751 }
752
753 // initialize to empty array buffer and add any given bytes using putBytes
754 this.data = new DataView(new ArrayBuffer(0));
755 this.write = 0;
756
757 if(b !== null && b !== undefined) {
758 this.putBytes(b);
759 }
760
761 if('writeOffset' in options) {
762 this.write = options.writeOffset;
763 }
764}
765util.DataBuffer = DataBuffer;
766
767/**
768 * Gets the number of bytes in this buffer.
769 *
770 * @return the number of bytes in this buffer.
771 */
772util.DataBuffer.prototype.length = function() {
773 return this.write - this.read;
774};
775
776/**
777 * Gets whether or not this buffer is empty.
778 *
779 * @return true if this buffer is empty, false if not.
780 */
781util.DataBuffer.prototype.isEmpty = function() {
782 return this.length() <= 0;
783};
784
785/**
786 * Ensures this buffer has enough empty space to accommodate the given number
787 * of bytes. An optional parameter may be given that indicates a minimum
788 * amount to grow the buffer if necessary. If the parameter is not given,
789 * the buffer will be grown by some previously-specified default amount
790 * or heuristic.
791 *
792 * @param amount the number of bytes to accommodate.
793 * @param [growSize] the minimum amount, in bytes, to grow the buffer by if
794 * necessary.
795 */
796util.DataBuffer.prototype.accommodate = function(amount, growSize) {
797 if(this.length() >= amount) {
798 return this;
799 }
800 growSize = Math.max(growSize || this.growSize, amount);
801
802 // grow buffer
803 var src = new Uint8Array(
804 this.data.buffer, this.data.byteOffset, this.data.byteLength);
805 var dst = new Uint8Array(this.length() + growSize);
806 dst.set(src);
807 this.data = new DataView(dst.buffer);
808
809 return this;
810};
811
812/**
813 * Puts a byte in this buffer.
814 *
815 * @param b the byte to put.
816 *
817 * @return this buffer.
818 */
819util.DataBuffer.prototype.putByte = function(b) {
820 this.accommodate(1);
821 this.data.setUint8(this.write++, b);
822 return this;
823};
824
825/**
826 * Puts a byte in this buffer N times.
827 *
828 * @param b the byte to put.
829 * @param n the number of bytes of value b to put.
830 *
831 * @return this buffer.
832 */
833util.DataBuffer.prototype.fillWithByte = function(b, n) {
834 this.accommodate(n);
835 for(var i = 0; i < n; ++i) {
836 this.data.setUint8(b);
837 }
838 return this;
839};
840
841/**
842 * Puts bytes in this buffer. The bytes may be given as a string, an
843 * ArrayBuffer, a DataView, or a TypedArray.
844 *
845 * @param bytes the bytes to put.
846 * @param [encoding] the encoding for the first parameter ('binary', 'utf8',
847 * 'utf16', 'hex'), if it is a string (default: 'binary').
848 *
849 * @return this buffer.
850 */
851util.DataBuffer.prototype.putBytes = function(bytes, encoding) {
852 if(util.isArrayBufferView(bytes)) {
853 var src = new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength);
854 var len = src.byteLength - src.byteOffset;
855 this.accommodate(len);
856 var dst = new Uint8Array(this.data.buffer, this.write);
857 dst.set(src);
858 this.write += len;
859 return this;
860 }
861
862 if(util.isArrayBuffer(bytes)) {
863 var src = new Uint8Array(bytes);
864 this.accommodate(src.byteLength);
865 var dst = new Uint8Array(this.data.buffer);
866 dst.set(src, this.write);
867 this.write += src.byteLength;
868 return this;
869 }
870
871 // bytes is a util.DataBuffer or equivalent
872 if(bytes instanceof util.DataBuffer ||
873 (typeof bytes === 'object' &&
874 typeof bytes.read === 'number' && typeof bytes.write === 'number' &&
875 util.isArrayBufferView(bytes.data))) {
876 var src = new Uint8Array(bytes.data.byteLength, bytes.read, bytes.length());
877 this.accommodate(src.byteLength);
878 var dst = new Uint8Array(bytes.data.byteLength, this.write);
879 dst.set(src);
880 this.write += src.byteLength;
881 return this;
882 }
883
884 if(bytes instanceof util.ByteStringBuffer) {
885 // copy binary string and process as the same as a string parameter below
886 bytes = bytes.data;
887 encoding = 'binary';
888 }
889
890 // string conversion
891 encoding = encoding || 'binary';
892 if(typeof bytes === 'string') {
893 var view;
894
895 // decode from string
896 if(encoding === 'hex') {
897 this.accommodate(Math.ceil(bytes.length / 2));
898 view = new Uint8Array(this.data.buffer, this.write);
899 this.write += util.binary.hex.decode(bytes, view, this.write);
900 return this;
901 }
902 if(encoding === 'base64') {
903 this.accommodate(Math.ceil(bytes.length / 4) * 3);
904 view = new Uint8Array(this.data.buffer, this.write);
905 this.write += util.binary.base64.decode(bytes, view, this.write);
906 return this;
907 }
908
909 // encode text as UTF-8 bytes
910 if(encoding === 'utf8') {
911 // encode as UTF-8 then decode string as raw binary
912 bytes = util.encodeUtf8(bytes);
913 encoding = 'binary';
914 }
915
916 // decode string as raw binary
917 if(encoding === 'binary' || encoding === 'raw') {
918 // one byte per character
919 this.accommodate(bytes.length);
920 view = new Uint8Array(this.data.buffer, this.write);
921 this.write += util.binary.raw.decode(view);
922 return this;
923 }
924
925 // encode text as UTF-16 bytes
926 if(encoding === 'utf16') {
927 // two bytes per character
928 this.accommodate(bytes.length * 2);
929 view = new Uint16Array(this.data.buffer, this.write);
930 this.write += util.text.utf16.encode(view);
931 return this;
932 }
933
934 throw new Error('Invalid encoding: ' + encoding);
935 }
936
937 throw Error('Invalid parameter: ' + bytes);
938};
939
940/**
941 * Puts the given buffer into this buffer.
942 *
943 * @param buffer the buffer to put into this one.
944 *
945 * @return this buffer.
946 */
947util.DataBuffer.prototype.putBuffer = function(buffer) {
948 this.putBytes(buffer);
949 buffer.clear();
950 return this;
951};
952
953/**
954 * Puts a string into this buffer.
955 *
956 * @param str the string to put.
957 * @param [encoding] the encoding for the string (default: 'utf16').
958 *
959 * @return this buffer.
960 */
961util.DataBuffer.prototype.putString = function(str) {
962 return this.putBytes(str, 'utf16');
963};
964
965/**
966 * Puts a 16-bit integer in this buffer in big-endian order.
967 *
968 * @param i the 16-bit integer.
969 *
970 * @return this buffer.
971 */
972util.DataBuffer.prototype.putInt16 = function(i) {
973 this.accommodate(2);
974 this.data.setInt16(this.write, i);
975 this.write += 2;
976 return this;
977};
978
979/**
980 * Puts a 24-bit integer in this buffer in big-endian order.
981 *
982 * @param i the 24-bit integer.
983 *
984 * @return this buffer.
985 */
986util.DataBuffer.prototype.putInt24 = function(i) {
987 this.accommodate(3);
988 this.data.setInt16(this.write, i >> 8 & 0xFFFF);
989 this.data.setInt8(this.write, i >> 16 & 0xFF);
990 this.write += 3;
991 return this;
992};
993
994/**
995 * Puts a 32-bit integer in this buffer in big-endian order.
996 *
997 * @param i the 32-bit integer.
998 *
999 * @return this buffer.
1000 */
1001util.DataBuffer.prototype.putInt32 = function(i) {
1002 this.accommodate(4);
1003 this.data.setInt32(this.write, i);
1004 this.write += 4;
1005 return this;
1006};
1007
1008/**
1009 * Puts a 16-bit integer in this buffer in little-endian order.
1010 *
1011 * @param i the 16-bit integer.
1012 *
1013 * @return this buffer.
1014 */
1015util.DataBuffer.prototype.putInt16Le = function(i) {
1016 this.accommodate(2);
1017 this.data.setInt16(this.write, i, true);
1018 this.write += 2;
1019 return this;
1020};
1021
1022/**
1023 * Puts a 24-bit integer in this buffer in little-endian order.
1024 *
1025 * @param i the 24-bit integer.
1026 *
1027 * @return this buffer.
1028 */
1029util.DataBuffer.prototype.putInt24Le = function(i) {
1030 this.accommodate(3);
1031 this.data.setInt8(this.write, i >> 16 & 0xFF);
1032 this.data.setInt16(this.write, i >> 8 & 0xFFFF, true);
1033 this.write += 3;
1034 return this;
1035};
1036
1037/**
1038 * Puts a 32-bit integer in this buffer in little-endian order.
1039 *
1040 * @param i the 32-bit integer.
1041 *
1042 * @return this buffer.
1043 */
1044util.DataBuffer.prototype.putInt32Le = function(i) {
1045 this.accommodate(4);
1046 this.data.setInt32(this.write, i, true);
1047 this.write += 4;
1048 return this;
1049};
1050
1051/**
1052 * Puts an n-bit integer in this buffer in big-endian order.
1053 *
1054 * @param i the n-bit integer.
1055 * @param n the number of bits in the integer (8, 16, 24, or 32).
1056 *
1057 * @return this buffer.
1058 */
1059util.DataBuffer.prototype.putInt = function(i, n) {
1060 _checkBitsParam(n);
1061 this.accommodate(n / 8);
1062 do {
1063 n -= 8;
1064 this.data.setInt8(this.write++, (i >> n) & 0xFF);
1065 } while(n > 0);
1066 return this;
1067};
1068
1069/**
1070 * Puts a signed n-bit integer in this buffer in big-endian order. Two's
1071 * complement representation is used.
1072 *
1073 * @param i the n-bit integer.
1074 * @param n the number of bits in the integer.
1075 *
1076 * @return this buffer.
1077 */
1078util.DataBuffer.prototype.putSignedInt = function(i, n) {
1079 _checkBitsParam(n);
1080 this.accommodate(n / 8);
1081 if(i < 0) {
1082 i += 2 << (n - 1);
1083 }
1084 return this.putInt(i, n);
1085};
1086
1087/**
1088 * Gets a byte from this buffer and advances the read pointer by 1.
1089 *
1090 * @return the byte.
1091 */
1092util.DataBuffer.prototype.getByte = function() {
1093 return this.data.getInt8(this.read++);
1094};
1095
1096/**
1097 * Gets a uint16 from this buffer in big-endian order and advances the read
1098 * pointer by 2.
1099 *
1100 * @return the uint16.
1101 */
1102util.DataBuffer.prototype.getInt16 = function() {
1103 var rval = this.data.getInt16(this.read);
1104 this.read += 2;
1105 return rval;
1106};
1107
1108/**
1109 * Gets a uint24 from this buffer in big-endian order and advances the read
1110 * pointer by 3.
1111 *
1112 * @return the uint24.
1113 */
1114util.DataBuffer.prototype.getInt24 = function() {
1115 var rval = (
1116 this.data.getInt16(this.read) << 8 ^
1117 this.data.getInt8(this.read + 2));
1118 this.read += 3;
1119 return rval;
1120};
1121
1122/**
1123 * Gets a uint32 from this buffer in big-endian order and advances the read
1124 * pointer by 4.
1125 *
1126 * @return the word.
1127 */
1128util.DataBuffer.prototype.getInt32 = function() {
1129 var rval = this.data.getInt32(this.read);
1130 this.read += 4;
1131 return rval;
1132};
1133
1134/**
1135 * Gets a uint16 from this buffer in little-endian order and advances the read
1136 * pointer by 2.
1137 *
1138 * @return the uint16.
1139 */
1140util.DataBuffer.prototype.getInt16Le = function() {
1141 var rval = this.data.getInt16(this.read, true);
1142 this.read += 2;
1143 return rval;
1144};
1145
1146/**
1147 * Gets a uint24 from this buffer in little-endian order and advances the read
1148 * pointer by 3.
1149 *
1150 * @return the uint24.
1151 */
1152util.DataBuffer.prototype.getInt24Le = function() {
1153 var rval = (
1154 this.data.getInt8(this.read) ^
1155 this.data.getInt16(this.read + 1, true) << 8);
1156 this.read += 3;
1157 return rval;
1158};
1159
1160/**
1161 * Gets a uint32 from this buffer in little-endian order and advances the read
1162 * pointer by 4.
1163 *
1164 * @return the word.
1165 */
1166util.DataBuffer.prototype.getInt32Le = function() {
1167 var rval = this.data.getInt32(this.read, true);
1168 this.read += 4;
1169 return rval;
1170};
1171
1172/**
1173 * Gets an n-bit integer from this buffer in big-endian order and advances the
1174 * read pointer by n/8.
1175 *
1176 * @param n the number of bits in the integer (8, 16, 24, or 32).
1177 *
1178 * @return the integer.
1179 */
1180util.DataBuffer.prototype.getInt = function(n) {
1181 _checkBitsParam(n);
1182 var rval = 0;
1183 do {
1184 // TODO: Use (rval * 0x100) if adding support for 33 to 53 bits.
1185 rval = (rval << 8) + this.data.getInt8(this.read++);
1186 n -= 8;
1187 } while(n > 0);
1188 return rval;
1189};
1190
1191/**
1192 * Gets a signed n-bit integer from this buffer in big-endian order, using
1193 * two's complement, and advances the read pointer by n/8.
1194 *
1195 * @param n the number of bits in the integer (8, 16, 24, or 32).
1196 *
1197 * @return the integer.
1198 */
1199util.DataBuffer.prototype.getSignedInt = function(n) {
1200 // getInt checks n
1201 var x = this.getInt(n);
1202 var max = 2 << (n - 2);
1203 if(x >= max) {
1204 x -= max << 1;
1205 }
1206 return x;
1207};
1208
1209/**
1210 * Reads bytes out into a UTF-8 string and clears them from the buffer.
1211 *
1212 * @param count the number of bytes to read, undefined or null for all.
1213 *
1214 * @return a UTF-8 string of bytes.
1215 */
1216util.DataBuffer.prototype.getBytes = function(count) {
1217 // TODO: deprecate this method, it is poorly named and
1218 // this.toString('binary') replaces it
1219 // add a toTypedArray()/toArrayBuffer() function
1220 var rval;
1221 if(count) {
1222 // read count bytes
1223 count = Math.min(this.length(), count);
1224 rval = this.data.slice(this.read, this.read + count);
1225 this.read += count;
1226 } else if(count === 0) {
1227 rval = '';
1228 } else {
1229 // read all bytes, optimize to only copy when needed
1230 rval = (this.read === 0) ? this.data : this.data.slice(this.read);
1231 this.clear();
1232 }
1233 return rval;
1234};
1235
1236/**
1237 * Gets a UTF-8 encoded string of the bytes from this buffer without modifying
1238 * the read pointer.
1239 *
1240 * @param count the number of bytes to get, omit to get all.
1241 *
1242 * @return a string full of UTF-8 encoded characters.
1243 */
1244util.DataBuffer.prototype.bytes = function(count) {
1245 // TODO: deprecate this method, it is poorly named, add "getString()"
1246 return (typeof(count) === 'undefined' ?
1247 this.data.slice(this.read) :
1248 this.data.slice(this.read, this.read + count));
1249};
1250
1251/**
1252 * Gets a byte at the given index without modifying the read pointer.
1253 *
1254 * @param i the byte index.
1255 *
1256 * @return the byte.
1257 */
1258util.DataBuffer.prototype.at = function(i) {
1259 return this.data.getUint8(this.read + i);
1260};
1261
1262/**
1263 * Puts a byte at the given index without modifying the read pointer.
1264 *
1265 * @param i the byte index.
1266 * @param b the byte to put.
1267 *
1268 * @return this buffer.
1269 */
1270util.DataBuffer.prototype.setAt = function(i, b) {
1271 this.data.setUint8(i, b);
1272 return this;
1273};
1274
1275/**
1276 * Gets the last byte without modifying the read pointer.
1277 *
1278 * @return the last byte.
1279 */
1280util.DataBuffer.prototype.last = function() {
1281 return this.data.getUint8(this.write - 1);
1282};
1283
1284/**
1285 * Creates a copy of this buffer.
1286 *
1287 * @return the copy.
1288 */
1289util.DataBuffer.prototype.copy = function() {
1290 return new util.DataBuffer(this);
1291};
1292
1293/**
1294 * Compacts this buffer.
1295 *
1296 * @return this buffer.
1297 */
1298util.DataBuffer.prototype.compact = function() {
1299 if(this.read > 0) {
1300 var src = new Uint8Array(this.data.buffer, this.read);
1301 var dst = new Uint8Array(src.byteLength);
1302 dst.set(src);
1303 this.data = new DataView(dst);
1304 this.write -= this.read;
1305 this.read = 0;
1306 }
1307 return this;
1308};
1309
1310/**
1311 * Clears this buffer.
1312 *
1313 * @return this buffer.
1314 */
1315util.DataBuffer.prototype.clear = function() {
1316 this.data = new DataView(new ArrayBuffer(0));
1317 this.read = this.write = 0;
1318 return this;
1319};
1320
1321/**
1322 * Shortens this buffer by triming bytes off of the end of this buffer.
1323 *
1324 * @param count the number of bytes to trim off.
1325 *
1326 * @return this buffer.
1327 */
1328util.DataBuffer.prototype.truncate = function(count) {
1329 this.write = Math.max(0, this.length() - count);
1330 this.read = Math.min(this.read, this.write);
1331 return this;
1332};
1333
1334/**
1335 * Converts this buffer to a hexadecimal string.
1336 *
1337 * @return a hexadecimal string.
1338 */
1339util.DataBuffer.prototype.toHex = function() {
1340 var rval = '';
1341 for(var i = this.read; i < this.data.byteLength; ++i) {
1342 var b = this.data.getUint8(i);
1343 if(b < 16) {
1344 rval += '0';
1345 }
1346 rval += b.toString(16);
1347 }
1348 return rval;
1349};
1350
1351/**
1352 * Converts this buffer to a string, using the given encoding. If no
1353 * encoding is given, 'utf8' (UTF-8) is used.
1354 *
1355 * @param [encoding] the encoding to use: 'binary', 'utf8', 'utf16', 'hex',
1356 * 'base64' (default: 'utf8').
1357 *
1358 * @return a string representation of the bytes in this buffer.
1359 */
1360util.DataBuffer.prototype.toString = function(encoding) {
1361 var view = new Uint8Array(this.data, this.read, this.length());
1362 encoding = encoding || 'utf8';
1363
1364 // encode to string
1365 if(encoding === 'binary' || encoding === 'raw') {
1366 return util.binary.raw.encode(view);
1367 }
1368 if(encoding === 'hex') {
1369 return util.binary.hex.encode(view);
1370 }
1371 if(encoding === 'base64') {
1372 return util.binary.base64.encode(view);
1373 }
1374
1375 // decode to text
1376 if(encoding === 'utf8') {
1377 return util.text.utf8.decode(view);
1378 }
1379 if(encoding === 'utf16') {
1380 return util.text.utf16.decode(view);
1381 }
1382
1383 throw new Error('Invalid encoding: ' + encoding);
1384};
1385
1386/** End Buffer w/UInt8Array backing */
1387
1388
1389/**
1390 * Creates a buffer that stores bytes. A value may be given to put into the
1391 * buffer that is either a string of bytes or a UTF-16 string that will
1392 * be encoded using UTF-8 (to do the latter, specify 'utf8' as the encoding).
1393 *
1394 * @param [input] the bytes to wrap (as a string) or a UTF-16 string to encode
1395 * as UTF-8.
1396 * @param [encoding] (default: 'raw', other: 'utf8').
1397 */
1398util.createBuffer = function(input, encoding) {
1399 // TODO: deprecate, use new ByteBuffer() instead
1400 encoding = encoding || 'raw';
1401 if(input !== undefined && encoding === 'utf8') {
1402 input = util.encodeUtf8(input);
1403 }
1404 return new util.ByteBuffer(input);
1405};
1406
1407/**
1408 * Fills a string with a particular value. If you want the string to be a byte
1409 * string, pass in String.fromCharCode(theByte).
1410 *
1411 * @param c the character to fill the string with, use String.fromCharCode
1412 * to fill the string with a byte value.
1413 * @param n the number of characters of value c to fill with.
1414 *
1415 * @return the filled string.
1416 */
1417util.fillString = function(c, n) {
1418 var s = '';
1419 while(n > 0) {
1420 if(n & 1) {
1421 s += c;
1422 }
1423 n >>>= 1;
1424 if(n > 0) {
1425 c += c;
1426 }
1427 }
1428 return s;
1429};
1430
1431/**
1432 * Performs a per byte XOR between two byte strings and returns the result as a
1433 * string of bytes.
1434 *
1435 * @param s1 first string of bytes.
1436 * @param s2 second string of bytes.
1437 * @param n the number of bytes to XOR.
1438 *
1439 * @return the XOR'd result.
1440 */
1441util.xorBytes = function(s1, s2, n) {
1442 var s3 = '';
1443 var b = '';
1444 var t = '';
1445 var i = 0;
1446 var c = 0;
1447 for(; n > 0; --n, ++i) {
1448 b = s1.charCodeAt(i) ^ s2.charCodeAt(i);
1449 if(c >= 10) {
1450 s3 += t;
1451 t = '';
1452 c = 0;
1453 }
1454 t += String.fromCharCode(b);
1455 ++c;
1456 }
1457 s3 += t;
1458 return s3;
1459};
1460
1461/**
1462 * Converts a hex string into a 'binary' encoded string of bytes.
1463 *
1464 * @param hex the hexadecimal string to convert.
1465 *
1466 * @return the binary-encoded string of bytes.
1467 */
1468util.hexToBytes = function(hex) {
1469 // TODO: deprecate: "Deprecated. Use util.binary.hex.decode instead."
1470 var rval = '';
1471 var i = 0;
1472 if(hex.length & 1 == 1) {
1473 // odd number of characters, convert first character alone
1474 i = 1;
1475 rval += String.fromCharCode(parseInt(hex[0], 16));
1476 }
1477 // convert 2 characters (1 byte) at a time
1478 for(; i < hex.length; i += 2) {
1479 rval += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
1480 }
1481 return rval;
1482};
1483
1484/**
1485 * Converts a 'binary' encoded string of bytes to hex.
1486 *
1487 * @param bytes the byte string to convert.
1488 *
1489 * @return the string of hexadecimal characters.
1490 */
1491util.bytesToHex = function(bytes) {
1492 // TODO: deprecate: "Deprecated. Use util.binary.hex.encode instead."
1493 return util.createBuffer(bytes).toHex();
1494};
1495
1496/**
1497 * Converts an 32-bit integer to 4-big-endian byte string.
1498 *
1499 * @param i the integer.
1500 *
1501 * @return the byte string.
1502 */
1503util.int32ToBytes = function(i) {
1504 return (
1505 String.fromCharCode(i >> 24 & 0xFF) +
1506 String.fromCharCode(i >> 16 & 0xFF) +
1507 String.fromCharCode(i >> 8 & 0xFF) +
1508 String.fromCharCode(i & 0xFF));
1509};
1510
1511// base64 characters, reverse mapping
1512var _base64 =
1513 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
1514var _base64Idx = [
1515/*43 -43 = 0*/
1516/*'+', 1, 2, 3,'/' */
1517 62, -1, -1, -1, 63,
1518
1519/*'0','1','2','3','4','5','6','7','8','9' */
1520 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
1521
1522/*15, 16, 17,'=', 19, 20, 21 */
1523 -1, -1, -1, 64, -1, -1, -1,
1524
1525/*65 - 43 = 22*/
1526/*'A','B','C','D','E','F','G','H','I','J','K','L','M', */
1527 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
1528
1529/*'N','O','P','Q','R','S','T','U','V','W','X','Y','Z' */
1530 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
1531
1532/*91 - 43 = 48 */
1533/*48, 49, 50, 51, 52, 53 */
1534 -1, -1, -1, -1, -1, -1,
1535
1536/*97 - 43 = 54*/
1537/*'a','b','c','d','e','f','g','h','i','j','k','l','m' */
1538 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
1539
1540/*'n','o','p','q','r','s','t','u','v','w','x','y','z' */
1541 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
1542];
1543
1544/**
1545 * Base64 encodes a 'binary' encoded string of bytes.
1546 *
1547 * @param input the binary encoded string of bytes to base64-encode.
1548 * @param maxline the maximum number of encoded characters per line to use,
1549 * defaults to none.
1550 *
1551 * @return the base64-encoded output.
1552 */
1553util.encode64 = function(input, maxline) {
1554 // TODO: deprecate: "Deprecated. Use util.binary.base64.encode instead."
1555 var line = '';
1556 var output = '';
1557 var chr1, chr2, chr3;
1558 var i = 0;
1559 while(i < input.length) {
1560 chr1 = input.charCodeAt(i++);
1561 chr2 = input.charCodeAt(i++);
1562 chr3 = input.charCodeAt(i++);
1563
1564 // encode 4 character group
1565 line += _base64.charAt(chr1 >> 2);
1566 line += _base64.charAt(((chr1 & 3) << 4) | (chr2 >> 4));
1567 if(isNaN(chr2)) {
1568 line += '==';
1569 } else {
1570 line += _base64.charAt(((chr2 & 15) << 2) | (chr3 >> 6));
1571 line += isNaN(chr3) ? '=' : _base64.charAt(chr3 & 63);
1572 }
1573
1574 if(maxline && line.length > maxline) {
1575 output += line.substr(0, maxline) + '\r\n';
1576 line = line.substr(maxline);
1577 }
1578 }
1579 output += line;
1580 return output;
1581};
1582
1583/**
1584 * Base64 decodes a string into a 'binary' encoded string of bytes.
1585 *
1586 * @param input the base64-encoded input.
1587 *
1588 * @return the binary encoded string.
1589 */
1590util.decode64 = function(input) {
1591 // TODO: deprecate: "Deprecated. Use util.binary.base64.decode instead."
1592
1593 // remove all non-base64 characters
1594 input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '');
1595
1596 var output = '';
1597 var enc1, enc2, enc3, enc4;
1598 var i = 0;
1599
1600 while(i < input.length) {
1601 enc1 = _base64Idx[input.charCodeAt(i++) - 43];
1602 enc2 = _base64Idx[input.charCodeAt(i++) - 43];
1603 enc3 = _base64Idx[input.charCodeAt(i++) - 43];
1604 enc4 = _base64Idx[input.charCodeAt(i++) - 43];
1605
1606 output += String.fromCharCode((enc1 << 2) | (enc2 >> 4));
1607 if(enc3 !== 64) {
1608 // decoded at least 2 bytes
1609 output += String.fromCharCode(((enc2 & 15) << 4) | (enc3 >> 2));
1610 if(enc4 !== 64) {
1611 // decoded 3 bytes
1612 output += String.fromCharCode(((enc3 & 3) << 6) | enc4);
1613 }
1614 }
1615 }
1616
1617 return output;
1618};
1619
1620/**
1621 * UTF-8 encodes the given UTF-16 encoded string (a standard JavaScript
1622 * string). Non-ASCII characters will be encoded as multiple bytes according
1623 * to UTF-8.
1624 *
1625 * @param str the string to encode.
1626 *
1627 * @return the UTF-8 encoded string.
1628 */
1629util.encodeUtf8 = function(str) {
1630 return unescape(encodeURIComponent(str));
1631};
1632
1633/**
1634 * Decodes a UTF-8 encoded string into a UTF-16 string.
1635 *
1636 * @param str the string to decode.
1637 *
1638 * @return the UTF-16 encoded string (standard JavaScript string).
1639 */
1640util.decodeUtf8 = function(str) {
1641 return decodeURIComponent(escape(str));
1642};
1643
1644// binary encoding/decoding tools
1645// FIXME: Experimental. Do not use yet.
1646util.binary = {
1647 raw: {},
1648 hex: {},
1649 base64: {}
1650};
1651
1652/**
1653 * Encodes a Uint8Array as a binary-encoded string. This encoding uses
1654 * a value between 0 and 255 for each character.
1655 *
1656 * @param bytes the Uint8Array to encode.
1657 *
1658 * @return the binary-encoded string.
1659 */
1660util.binary.raw.encode = function(bytes) {
1661 return String.fromCharCode.apply(null, bytes);
1662};
1663
1664/**
1665 * Decodes a binary-encoded string to a Uint8Array. This encoding uses
1666 * a value between 0 and 255 for each character.
1667 *
1668 * @param str the binary-encoded string to decode.
1669 * @param [output] an optional Uint8Array to write the output to; if it
1670 * is too small, an exception will be thrown.
1671 * @param [offset] the start offset for writing to the output (default: 0).
1672 *
1673 * @return the Uint8Array or the number of bytes written if output was given.
1674 */
1675util.binary.raw.decode = function(str, output, offset) {
1676 var out = output;
1677 if(!out) {
1678 out = new Uint8Array(str.length);
1679 }
1680 offset = offset || 0;
1681 var j = offset;
1682 for(var i = 0; i < str.length; ++i) {
1683 out[j++] = str.charCodeAt(i);
1684 }
1685 return output ? (j - offset) : out;
1686};
1687
1688/**
1689 * Encodes a 'binary' string, ArrayBuffer, DataView, TypedArray, or
1690 * ByteBuffer as a string of hexadecimal characters.
1691 *
1692 * @param bytes the bytes to convert.
1693 *
1694 * @return the string of hexadecimal characters.
1695 */
1696util.binary.hex.encode = util.bytesToHex;
1697
1698/**
1699 * Decodes a hex-encoded string to a Uint8Array.
1700 *
1701 * @param hex the hexadecimal string to convert.
1702 * @param [output] an optional Uint8Array to write the output to; if it
1703 * is too small, an exception will be thrown.
1704 * @param [offset] the start offset for writing to the output (default: 0).
1705 *
1706 * @return the Uint8Array or the number of bytes written if output was given.
1707 */
1708util.binary.hex.decode = function(hex, output, offset) {
1709 var out = output;
1710 if(!out) {
1711 out = new Uint8Array(Math.ceil(hex.length / 2));
1712 }
1713 offset = offset || 0;
1714 var i = 0, j = offset;
1715 if(hex.length & 1) {
1716 // odd number of characters, convert first character alone
1717 i = 1;
1718 out[j++] = parseInt(hex[0], 16);
1719 }
1720 // convert 2 characters (1 byte) at a time
1721 for(; i < hex.length; i += 2) {
1722 out[j++] = parseInt(hex.substr(i, 2), 16);
1723 }
1724 return output ? (j - offset) : out;
1725};
1726
1727/**
1728 * Base64-encodes a Uint8Array.
1729 *
1730 * @param input the Uint8Array to encode.
1731 * @param maxline the maximum number of encoded characters per line to use,
1732 * defaults to none.
1733 *
1734 * @return the base64-encoded output string.
1735 */
1736util.binary.base64.encode = function(input, maxline) {
1737 var line = '';
1738 var output = '';
1739 var chr1, chr2, chr3;
1740 var i = 0;
1741 while(i < input.byteLength) {
1742 chr1 = input[i++];
1743 chr2 = input[i++];
1744 chr3 = input[i++];
1745
1746 // encode 4 character group
1747 line += _base64.charAt(chr1 >> 2);
1748 line += _base64.charAt(((chr1 & 3) << 4) | (chr2 >> 4));
1749 if(isNaN(chr2)) {
1750 line += '==';
1751 } else {
1752 line += _base64.charAt(((chr2 & 15) << 2) | (chr3 >> 6));
1753 line += isNaN(chr3) ? '=' : _base64.charAt(chr3 & 63);
1754 }
1755
1756 if(maxline && line.length > maxline) {
1757 output += line.substr(0, maxline) + '\r\n';
1758 line = line.substr(maxline);
1759 }
1760 }
1761 output += line;
1762 return output;
1763};
1764
1765/**
1766 * Decodes a base64-encoded string to a Uint8Array.
1767 *
1768 * @param input the base64-encoded input string.
1769 * @param [output] an optional Uint8Array to write the output to; if it
1770 * is too small, an exception will be thrown.
1771 * @param [offset] the start offset for writing to the output (default: 0).
1772 *
1773 * @return the Uint8Array or the number of bytes written if output was given.
1774 */
1775util.binary.base64.decode = function(input, output, offset) {
1776 var out = output;
1777 if(!out) {
1778 out = new Uint8Array(Math.ceil(input.length / 4) * 3);
1779 }
1780
1781 // remove all non-base64 characters
1782 input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '');
1783
1784 offset = offset || 0;
1785 var enc1, enc2, enc3, enc4;
1786 var i = 0, j = offset;
1787
1788 while(i < input.length) {
1789 enc1 = _base64Idx[input.charCodeAt(i++) - 43];
1790 enc2 = _base64Idx[input.charCodeAt(i++) - 43];
1791 enc3 = _base64Idx[input.charCodeAt(i++) - 43];
1792 enc4 = _base64Idx[input.charCodeAt(i++) - 43];
1793
1794 out[j++] = (enc1 << 2) | (enc2 >> 4);
1795 if(enc3 !== 64) {
1796 // decoded at least 2 bytes
1797 out[j++] = ((enc2 & 15) << 4) | (enc3 >> 2);
1798 if(enc4 !== 64) {
1799 // decoded 3 bytes
1800 out[j++] = ((enc3 & 3) << 6) | enc4;
1801 }
1802 }
1803 }
1804
1805 // make sure result is the exact decoded length
1806 return output ?
1807 (j - offset) :
1808 out.subarray(0, j);
1809};
1810
1811// text encoding/decoding tools
1812// FIXME: Experimental. Do not use yet.
1813util.text = {
1814 utf8: {},
1815 utf16: {}
1816};
1817
1818/**
1819 * Encodes the given string as UTF-8 in a Uint8Array.
1820 *
1821 * @param str the string to encode.
1822 * @param [output] an optional Uint8Array to write the output to; if it
1823 * is too small, an exception will be thrown.
1824 * @param [offset] the start offset for writing to the output (default: 0).
1825 *
1826 * @return the Uint8Array or the number of bytes written if output was given.
1827 */
1828util.text.utf8.encode = function(str, output, offset) {
1829 str = util.encodeUtf8(str);
1830 var out = output;
1831 if(!out) {
1832 out = new Uint8Array(str.length);
1833 }
1834 offset = offset || 0;
1835 var j = offset;
1836 for(var i = 0; i < str.length; ++i) {
1837 out[j++] = str.charCodeAt(i);
1838 }
1839 return output ? (j - offset) : out;
1840};
1841
1842/**
1843 * Decodes the UTF-8 contents from a Uint8Array.
1844 *
1845 * @param bytes the Uint8Array to decode.
1846 *
1847 * @return the resulting string.
1848 */
1849util.text.utf8.decode = function(bytes) {
1850 return util.decodeUtf8(String.fromCharCode.apply(null, bytes));
1851};
1852
1853/**
1854 * Encodes the given string as UTF-16 in a Uint8Array.
1855 *
1856 * @param str the string to encode.
1857 * @param [output] an optional Uint8Array to write the output to; if it
1858 * is too small, an exception will be thrown.
1859 * @param [offset] the start offset for writing to the output (default: 0).
1860 *
1861 * @return the Uint8Array or the number of bytes written if output was given.
1862 */
1863util.text.utf16.encode = function(str, output, offset) {
1864 var out = output;
1865 if(!out) {
1866 out = new Uint8Array(str.length * 2);
1867 }
1868 var view = new Uint16Array(out.buffer);
1869 offset = offset || 0;
1870 var j = offset;
1871 var k = offset;
1872 for(var i = 0; i < str.length; ++i) {
1873 view[k++] = str.charCodeAt(i);
1874 j += 2;
1875 }
1876 return output ? (j - offset) : out;
1877};
1878
1879/**
1880 * Decodes the UTF-16 contents from a Uint8Array.
1881 *
1882 * @param bytes the Uint8Array to decode.
1883 *
1884 * @return the resulting string.
1885 */
1886util.text.utf16.decode = function(bytes) {
1887 return String.fromCharCode.apply(null, new Uint16Array(bytes.buffer));
1888};
1889
1890/**
1891 * Deflates the given data using a flash interface.
1892 *
1893 * @param api the flash interface.
1894 * @param bytes the data.
1895 * @param raw true to return only raw deflate data, false to include zlib
1896 * header and trailer.
1897 *
1898 * @return the deflated data as a string.
1899 */
1900util.deflate = function(api, bytes, raw) {
1901 bytes = util.decode64(api.deflate(util.encode64(bytes)).rval);
1902
1903 // strip zlib header and trailer if necessary
1904 if(raw) {
1905 // zlib header is 2 bytes (CMF,FLG) where FLG indicates that
1906 // there is a 4-byte DICT (alder-32) block before the data if
1907 // its 5th bit is set
1908 var start = 2;
1909 var flg = bytes.charCodeAt(1);
1910 if(flg & 0x20) {
1911 start = 6;
1912 }
1913 // zlib trailer is 4 bytes of adler-32
1914 bytes = bytes.substring(start, bytes.length - 4);
1915 }
1916
1917 return bytes;
1918};
1919
1920/**
1921 * Inflates the given data using a flash interface.
1922 *
1923 * @param api the flash interface.
1924 * @param bytes the data.
1925 * @param raw true if the incoming data has no zlib header or trailer and is
1926 * raw DEFLATE data.
1927 *
1928 * @return the inflated data as a string, null on error.
1929 */
1930util.inflate = function(api, bytes, raw) {
1931 // TODO: add zlib header and trailer if necessary/possible
1932 var rval = api.inflate(util.encode64(bytes)).rval;
1933 return (rval === null) ? null : util.decode64(rval);
1934};
1935
1936/**
1937 * Sets a storage object.
1938 *
1939 * @param api the storage interface.
1940 * @param id the storage ID to use.
1941 * @param obj the storage object, null to remove.
1942 */
1943var _setStorageObject = function(api, id, obj) {
1944 if(!api) {
1945 throw new Error('WebStorage not available.');
1946 }
1947
1948 var rval;
1949 if(obj === null) {
1950 rval = api.removeItem(id);
1951 } else {
1952 // json-encode and base64-encode object
1953 obj = util.encode64(JSON.stringify(obj));
1954 rval = api.setItem(id, obj);
1955 }
1956
1957 // handle potential flash error
1958 if(typeof(rval) !== 'undefined' && rval.rval !== true) {
1959 var error = new Error(rval.error.message);
1960 error.id = rval.error.id;
1961 error.name = rval.error.name;
1962 throw error;
1963 }
1964};
1965
1966/**
1967 * Gets a storage object.
1968 *
1969 * @param api the storage interface.
1970 * @param id the storage ID to use.
1971 *
1972 * @return the storage object entry or null if none exists.
1973 */
1974var _getStorageObject = function(api, id) {
1975 if(!api) {
1976 throw new Error('WebStorage not available.');
1977 }
1978
1979 // get the existing entry
1980 var rval = api.getItem(id);
1981
1982 /* Note: We check api.init because we can't do (api == localStorage)
1983 on IE because of "Class doesn't support Automation" exception. Only
1984 the flash api has an init method so this works too, but we need a
1985 better solution in the future. */
1986
1987 // flash returns item wrapped in an object, handle special case
1988 if(api.init) {
1989 if(rval.rval === null) {
1990 if(rval.error) {
1991 var error = new Error(rval.error.message);
1992 error.id = rval.error.id;
1993 error.name = rval.error.name;
1994 throw error;
1995 }
1996 // no error, but also no item
1997 rval = null;
1998 } else {
1999 rval = rval.rval;
2000 }
2001 }
2002
2003 // handle decoding
2004 if(rval !== null) {
2005 // base64-decode and json-decode data
2006 rval = JSON.parse(util.decode64(rval));
2007 }
2008
2009 return rval;
2010};
2011
2012/**
2013 * Stores an item in local storage.
2014 *
2015 * @param api the storage interface.
2016 * @param id the storage ID to use.
2017 * @param key the key for the item.
2018 * @param data the data for the item (any javascript object/primitive).
2019 */
2020var _setItem = function(api, id, key, data) {
2021 // get storage object
2022 var obj = _getStorageObject(api, id);
2023 if(obj === null) {
2024 // create a new storage object
2025 obj = {};
2026 }
2027 // update key
2028 obj[key] = data;
2029
2030 // set storage object
2031 _setStorageObject(api, id, obj);
2032};
2033
2034/**
2035 * Gets an item from local storage.
2036 *
2037 * @param api the storage interface.
2038 * @param id the storage ID to use.
2039 * @param key the key for the item.
2040 *
2041 * @return the item.
2042 */
2043var _getItem = function(api, id, key) {
2044 // get storage object
2045 var rval = _getStorageObject(api, id);
2046 if(rval !== null) {
2047 // return data at key
2048 rval = (key in rval) ? rval[key] : null;
2049 }
2050
2051 return rval;
2052};
2053
2054/**
2055 * Removes an item from local storage.
2056 *
2057 * @param api the storage interface.
2058 * @param id the storage ID to use.
2059 * @param key the key for the item.
2060 */
2061var _removeItem = function(api, id, key) {
2062 // get storage object
2063 var obj = _getStorageObject(api, id);
2064 if(obj !== null && key in obj) {
2065 // remove key
2066 delete obj[key];
2067
2068 // see if entry has no keys remaining
2069 var empty = true;
2070 for(var prop in obj) {
2071 empty = false;
2072 break;
2073 }
2074 if(empty) {
2075 // remove entry entirely if no keys are left
2076 obj = null;
2077 }
2078
2079 // set storage object
2080 _setStorageObject(api, id, obj);
2081 }
2082};
2083
2084/**
2085 * Clears the local disk storage identified by the given ID.
2086 *
2087 * @param api the storage interface.
2088 * @param id the storage ID to use.
2089 */
2090var _clearItems = function(api, id) {
2091 _setStorageObject(api, id, null);
2092};
2093
2094/**
2095 * Calls a storage function.
2096 *
2097 * @param func the function to call.
2098 * @param args the arguments for the function.
2099 * @param location the location argument.
2100 *
2101 * @return the return value from the function.
2102 */
2103var _callStorageFunction = function(func, args, location) {
2104 var rval = null;
2105
2106 // default storage types
2107 if(typeof(location) === 'undefined') {
2108 location = ['web', 'flash'];
2109 }
2110
2111 // apply storage types in order of preference
2112 var type;
2113 var done = false;
2114 var exception = null;
2115 for(var idx in location) {
2116 type = location[idx];
2117 try {
2118 if(type === 'flash' || type === 'both') {
2119 if(args[0] === null) {
2120 throw new Error('Flash local storage not available.');
2121 }
2122 rval = func.apply(this, args);
2123 done = (type === 'flash');
2124 }
2125 if(type === 'web' || type === 'both') {
2126 args[0] = localStorage;
2127 rval = func.apply(this, args);
2128 done = true;
2129 }
2130 } catch(ex) {
2131 exception = ex;
2132 }
2133 if(done) {
2134 break;
2135 }
2136 }
2137
2138 if(!done) {
2139 throw exception;
2140 }
2141
2142 return rval;
2143};
2144
2145/**
2146 * Stores an item on local disk.
2147 *
2148 * The available types of local storage include 'flash', 'web', and 'both'.
2149 *
2150 * The type 'flash' refers to flash local storage (SharedObject). In order
2151 * to use flash local storage, the 'api' parameter must be valid. The type
2152 * 'web' refers to WebStorage, if supported by the browser. The type 'both'
2153 * refers to storing using both 'flash' and 'web', not just one or the
2154 * other.
2155 *
2156 * The location array should list the storage types to use in order of
2157 * preference:
2158 *
2159 * ['flash']: flash only storage
2160 * ['web']: web only storage
2161 * ['both']: try to store in both
2162 * ['flash','web']: store in flash first, but if not available, 'web'
2163 * ['web','flash']: store in web first, but if not available, 'flash'
2164 *
2165 * The location array defaults to: ['web', 'flash']
2166 *
2167 * @param api the flash interface, null to use only WebStorage.
2168 * @param id the storage ID to use.
2169 * @param key the key for the item.
2170 * @param data the data for the item (any javascript object/primitive).
2171 * @param location an array with the preferred types of storage to use.
2172 */
2173util.setItem = function(api, id, key, data, location) {
2174 _callStorageFunction(_setItem, arguments, location);
2175};
2176
2177/**
2178 * Gets an item on local disk.
2179 *
2180 * Set setItem() for details on storage types.
2181 *
2182 * @param api the flash interface, null to use only WebStorage.
2183 * @param id the storage ID to use.
2184 * @param key the key for the item.
2185 * @param location an array with the preferred types of storage to use.
2186 *
2187 * @return the item.
2188 */
2189util.getItem = function(api, id, key, location) {
2190 return _callStorageFunction(_getItem, arguments, location);
2191};
2192
2193/**
2194 * Removes an item on local disk.
2195 *
2196 * Set setItem() for details on storage types.
2197 *
2198 * @param api the flash interface.
2199 * @param id the storage ID to use.
2200 * @param key the key for the item.
2201 * @param location an array with the preferred types of storage to use.
2202 */
2203util.removeItem = function(api, id, key, location) {
2204 _callStorageFunction(_removeItem, arguments, location);
2205};
2206
2207/**
2208 * Clears the local disk storage identified by the given ID.
2209 *
2210 * Set setItem() for details on storage types.
2211 *
2212 * @param api the flash interface if flash is available.
2213 * @param id the storage ID to use.
2214 * @param location an array with the preferred types of storage to use.
2215 */
2216util.clearItems = function(api, id, location) {
2217 _callStorageFunction(_clearItems, arguments, location);
2218};
2219
2220/**
2221 * Parses the scheme, host, and port from an http(s) url.
2222 *
2223 * @param str the url string.
2224 *
2225 * @return the parsed url object or null if the url is invalid.
2226 */
2227util.parseUrl = function(str) {
2228 // FIXME: this regex looks a bit broken
2229 var regex = /^(https?):\/\/([^:&^\/]*):?(\d*)(.*)$/g;
2230 regex.lastIndex = 0;
2231 var m = regex.exec(str);
2232 var url = (m === null) ? null : {
2233 full: str,
2234 scheme: m[1],
2235 host: m[2],
2236 port: m[3],
2237 path: m[4]
2238 };
2239 if(url) {
2240 url.fullHost = url.host;
2241 if(url.port) {
2242 if(url.port !== 80 && url.scheme === 'http') {
2243 url.fullHost += ':' + url.port;
2244 } else if(url.port !== 443 && url.scheme === 'https') {
2245 url.fullHost += ':' + url.port;
2246 }
2247 } else if(url.scheme === 'http') {
2248 url.port = 80;
2249 } else if(url.scheme === 'https') {
2250 url.port = 443;
2251 }
2252 url.full = url.scheme + '://' + url.fullHost;
2253 }
2254 return url;
2255};
2256
2257/* Storage for query variables */
2258var _queryVariables = null;
2259
2260/**
2261 * Returns the window location query variables. Query is parsed on the first
2262 * call and the same object is returned on subsequent calls. The mapping
2263 * is from keys to an array of values. Parameters without values will have
2264 * an object key set but no value added to the value array. Values are
2265 * unescaped.
2266 *
2267 * ...?k1=v1&k2=v2:
2268 * {
2269 * "k1": ["v1"],
2270 * "k2": ["v2"]
2271 * }
2272 *
2273 * ...?k1=v1&k1=v2:
2274 * {
2275 * "k1": ["v1", "v2"]
2276 * }
2277 *
2278 * ...?k1=v1&k2:
2279 * {
2280 * "k1": ["v1"],
2281 * "k2": []
2282 * }
2283 *
2284 * ...?k1=v1&k1:
2285 * {
2286 * "k1": ["v1"]
2287 * }
2288 *
2289 * ...?k1&k1:
2290 * {
2291 * "k1": []
2292 * }
2293 *
2294 * @param query the query string to parse (optional, default to cached
2295 * results from parsing window location search query).
2296 *
2297 * @return object mapping keys to variables.
2298 */
2299util.getQueryVariables = function(query) {
2300 var parse = function(q) {
2301 var rval = {};
2302 var kvpairs = q.split('&');
2303 for(var i = 0; i < kvpairs.length; i++) {
2304 var pos = kvpairs[i].indexOf('=');
2305 var key;
2306 var val;
2307 if(pos > 0) {
2308 key = kvpairs[i].substring(0, pos);
2309 val = kvpairs[i].substring(pos + 1);
2310 } else {
2311 key = kvpairs[i];
2312 val = null;
2313 }
2314 if(!(key in rval)) {
2315 rval[key] = [];
2316 }
2317 // disallow overriding object prototype keys
2318 if(!(key in Object.prototype) && val !== null) {
2319 rval[key].push(unescape(val));
2320 }
2321 }
2322 return rval;
2323 };
2324
2325 var rval;
2326 if(typeof(query) === 'undefined') {
2327 // set cached variables if needed
2328 if(_queryVariables === null) {
2329 if(typeof(window) !== 'undefined' && window.location && window.location.search) {
2330 // parse window search query
2331 _queryVariables = parse(window.location.search.substring(1));
2332 } else {
2333 // no query variables available
2334 _queryVariables = {};
2335 }
2336 }
2337 rval = _queryVariables;
2338 } else {
2339 // parse given query
2340 rval = parse(query);
2341 }
2342 return rval;
2343};
2344
2345/**
2346 * Parses a fragment into a path and query. This method will take a URI
2347 * fragment and break it up as if it were the main URI. For example:
2348 * /bar/baz?a=1&b=2
2349 * results in:
2350 * {
2351 * path: ["bar", "baz"],
2352 * query: {"k1": ["v1"], "k2": ["v2"]}
2353 * }
2354 *
2355 * @return object with a path array and query object.
2356 */
2357util.parseFragment = function(fragment) {
2358 // default to whole fragment
2359 var fp = fragment;
2360 var fq = '';
2361 // split into path and query if possible at the first '?'
2362 var pos = fragment.indexOf('?');
2363 if(pos > 0) {
2364 fp = fragment.substring(0, pos);
2365 fq = fragment.substring(pos + 1);
2366 }
2367 // split path based on '/' and ignore first element if empty
2368 var path = fp.split('/');
2369 if(path.length > 0 && path[0] === '') {
2370 path.shift();
2371 }
2372 // convert query into object
2373 var query = (fq === '') ? {} : util.getQueryVariables(fq);
2374
2375 return {
2376 pathString: fp,
2377 queryString: fq,
2378 path: path,
2379 query: query
2380 };
2381};
2382
2383/**
2384 * Makes a request out of a URI-like request string. This is intended to
2385 * be used where a fragment id (after a URI '#') is parsed as a URI with
2386 * path and query parts. The string should have a path beginning and
2387 * delimited by '/' and optional query parameters following a '?'. The
2388 * query should be a standard URL set of key value pairs delimited by
2389 * '&'. For backwards compatibility the initial '/' on the path is not
2390 * required. The request object has the following API, (fully described
2391 * in the method code):
2392 * {
2393 * path: <the path string part>.
2394 * query: <the query string part>,
2395 * getPath(i): get part or all of the split path array,
2396 * getQuery(k, i): get part or all of a query key array,
2397 * getQueryLast(k, _default): get last element of a query key array.
2398 * }
2399 *
2400 * @return object with request parameters.
2401 */
2402util.makeRequest = function(reqString) {
2403 var frag = util.parseFragment(reqString);
2404 var req = {
2405 // full path string
2406 path: frag.pathString,
2407 // full query string
2408 query: frag.queryString,
2409 /**
2410 * Get path or element in path.
2411 *
2412 * @param i optional path index.
2413 *
2414 * @return path or part of path if i provided.
2415 */
2416 getPath: function(i) {
2417 return (typeof(i) === 'undefined') ? frag.path : frag.path[i];
2418 },
2419 /**
2420 * Get query, values for a key, or value for a key index.
2421 *
2422 * @param k optional query key.
2423 * @param i optional query key index.
2424 *
2425 * @return query, values for a key, or value for a key index.
2426 */
2427 getQuery: function(k, i) {
2428 var rval;
2429 if(typeof(k) === 'undefined') {
2430 rval = frag.query;
2431 } else {
2432 rval = frag.query[k];
2433 if(rval && typeof(i) !== 'undefined') {
2434 rval = rval[i];
2435 }
2436 }
2437 return rval;
2438 },
2439 getQueryLast: function(k, _default) {
2440 var rval;
2441 var vals = req.getQuery(k);
2442 if(vals) {
2443 rval = vals[vals.length - 1];
2444 } else {
2445 rval = _default;
2446 }
2447 return rval;
2448 }
2449 };
2450 return req;
2451};
2452
2453/**
2454 * Makes a URI out of a path, an object with query parameters, and a
2455 * fragment. Uses jQuery.param() internally for query string creation.
2456 * If the path is an array, it will be joined with '/'.
2457 *
2458 * @param path string path or array of strings.
2459 * @param query object with query parameters. (optional)
2460 * @param fragment fragment string. (optional)
2461 *
2462 * @return string object with request parameters.
2463 */
2464util.makeLink = function(path, query, fragment) {
2465 // join path parts if needed
2466 path = jQuery.isArray(path) ? path.join('/') : path;
2467
2468 var qstr = jQuery.param(query || {});
2469 fragment = fragment || '';
2470 return path +
2471 ((qstr.length > 0) ? ('?' + qstr) : '') +
2472 ((fragment.length > 0) ? ('#' + fragment) : '');
2473};
2474
2475/**
2476 * Follows a path of keys deep into an object hierarchy and set a value.
2477 * If a key does not exist or it's value is not an object, create an
2478 * object in it's place. This can be destructive to a object tree if
2479 * leaf nodes are given as non-final path keys.
2480 * Used to avoid exceptions from missing parts of the path.
2481 *
2482 * @param object the starting object.
2483 * @param keys an array of string keys.
2484 * @param value the value to set.
2485 */
2486util.setPath = function(object, keys, value) {
2487 // need to start at an object
2488 if(typeof(object) === 'object' && object !== null) {
2489 var i = 0;
2490 var len = keys.length;
2491 while(i < len) {
2492 var next = keys[i++];
2493 if(i == len) {
2494 // last
2495 object[next] = value;
2496 } else {
2497 // more
2498 var hasNext = (next in object);
2499 if(!hasNext ||
2500 (hasNext && typeof(object[next]) !== 'object') ||
2501 (hasNext && object[next] === null)) {
2502 object[next] = {};
2503 }
2504 object = object[next];
2505 }
2506 }
2507 }
2508};
2509
2510/**
2511 * Follows a path of keys deep into an object hierarchy and return a value.
2512 * If a key does not exist, create an object in it's place.
2513 * Used to avoid exceptions from missing parts of the path.
2514 *
2515 * @param object the starting object.
2516 * @param keys an array of string keys.
2517 * @param _default value to return if path not found.
2518 *
2519 * @return the value at the path if found, else default if given, else
2520 * undefined.
2521 */
2522util.getPath = function(object, keys, _default) {
2523 var i = 0;
2524 var len = keys.length;
2525 var hasNext = true;
2526 while(hasNext && i < len &&
2527 typeof(object) === 'object' && object !== null) {
2528 var next = keys[i++];
2529 hasNext = next in object;
2530 if(hasNext) {
2531 object = object[next];
2532 }
2533 }
2534 return (hasNext ? object : _default);
2535};
2536
2537/**
2538 * Follow a path of keys deep into an object hierarchy and delete the
2539 * last one. If a key does not exist, do nothing.
2540 * Used to avoid exceptions from missing parts of the path.
2541 *
2542 * @param object the starting object.
2543 * @param keys an array of string keys.
2544 */
2545util.deletePath = function(object, keys) {
2546 // need to start at an object
2547 if(typeof(object) === 'object' && object !== null) {
2548 var i = 0;
2549 var len = keys.length;
2550 while(i < len) {
2551 var next = keys[i++];
2552 if(i == len) {
2553 // last
2554 delete object[next];
2555 } else {
2556 // more
2557 if(!(next in object) ||
2558 (typeof(object[next]) !== 'object') ||
2559 (object[next] === null)) {
2560 break;
2561 }
2562 object = object[next];
2563 }
2564 }
2565 }
2566};
2567
2568/**
2569 * Check if an object is empty.
2570 *
2571 * Taken from:
2572 * http://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object-from-json/679937#679937
2573 *
2574 * @param object the object to check.
2575 */
2576util.isEmpty = function(obj) {
2577 for(var prop in obj) {
2578 if(obj.hasOwnProperty(prop)) {
2579 return false;
2580 }
2581 }
2582 return true;
2583};
2584
2585/**
2586 * Format with simple printf-style interpolation.
2587 *
2588 * %%: literal '%'
2589 * %s,%o: convert next argument into a string.
2590 *
2591 * @param format the string to format.
2592 * @param ... arguments to interpolate into the format string.
2593 */
2594util.format = function(format) {
2595 var re = /%./g;
2596 // current match
2597 var match;
2598 // current part
2599 var part;
2600 // current arg index
2601 var argi = 0;
2602 // collected parts to recombine later
2603 var parts = [];
2604 // last index found
2605 var last = 0;
2606 // loop while matches remain
2607 while((match = re.exec(format))) {
2608 part = format.substring(last, re.lastIndex - 2);
2609 // don't add empty strings (ie, parts between %s%s)
2610 if(part.length > 0) {
2611 parts.push(part);
2612 }
2613 last = re.lastIndex;
2614 // switch on % code
2615 var code = match[0][1];
2616 switch(code) {
2617 case 's':
2618 case 'o':
2619 // check if enough arguments were given
2620 if(argi < arguments.length) {
2621 parts.push(arguments[argi++ + 1]);
2622 } else {
2623 parts.push('<?>');
2624 }
2625 break;
2626 // FIXME: do proper formating for numbers, etc
2627 //case 'f':
2628 //case 'd':
2629 case '%':
2630 parts.push('%');
2631 break;
2632 default:
2633 parts.push('<%' + code + '?>');
2634 }
2635 }
2636 // add trailing part of format string
2637 parts.push(format.substring(last));
2638 return parts.join('');
2639};
2640
2641/**
2642 * Formats a number.
2643 *
2644 * http://snipplr.com/view/5945/javascript-numberformat--ported-from-php/
2645 */
2646util.formatNumber = function(number, decimals, dec_point, thousands_sep) {
2647 // http://kevin.vanzonneveld.net
2648 // + original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
2649 // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
2650 // + bugfix by: Michael White (http://crestidg.com)
2651 // + bugfix by: Benjamin Lupton
2652 // + bugfix by: Allan Jensen (http://www.winternet.no)
2653 // + revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
2654 // * example 1: number_format(1234.5678, 2, '.', '');
2655 // * returns 1: 1234.57
2656
2657 var n = number, c = isNaN(decimals = Math.abs(decimals)) ? 2 : decimals;
2658 var d = dec_point === undefined ? ',' : dec_point;
2659 var t = thousands_sep === undefined ?
2660 '.' : thousands_sep, s = n < 0 ? '-' : '';
2661 var i = parseInt((n = Math.abs(+n || 0).toFixed(c)), 10) + '';
2662 var j = (i.length > 3) ? i.length % 3 : 0;
2663 return s + (j ? i.substr(0, j) + t : '') +
2664 i.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + t) +
2665 (c ? d + Math.abs(n - i).toFixed(c).slice(2) : '');
2666};
2667
2668/**
2669 * Formats a byte size.
2670 *
2671 * http://snipplr.com/view/5949/format-humanize-file-byte-size-presentation-in-javascript/
2672 */
2673util.formatSize = function(size) {
2674 if(size >= 1073741824) {
2675 size = util.formatNumber(size / 1073741824, 2, '.', '') + ' GiB';
2676 } else if(size >= 1048576) {
2677 size = util.formatNumber(size / 1048576, 2, '.', '') + ' MiB';
2678 } else if(size >= 1024) {
2679 size = util.formatNumber(size / 1024, 0) + ' KiB';
2680 } else {
2681 size = util.formatNumber(size, 0) + ' bytes';
2682 }
2683 return size;
2684};
2685
2686/**
2687 * Converts an IPv4 or IPv6 string representation into bytes (in network order).
2688 *
2689 * @param ip the IPv4 or IPv6 address to convert.
2690 *
2691 * @return the 4-byte IPv6 or 16-byte IPv6 address or null if the address can't
2692 * be parsed.
2693 */
2694util.bytesFromIP = function(ip) {
2695 if(ip.indexOf('.') !== -1) {
2696 return util.bytesFromIPv4(ip);
2697 }
2698 if(ip.indexOf(':') !== -1) {
2699 return util.bytesFromIPv6(ip);
2700 }
2701 return null;
2702};
2703
2704/**
2705 * Converts an IPv4 string representation into bytes (in network order).
2706 *
2707 * @param ip the IPv4 address to convert.
2708 *
2709 * @return the 4-byte address or null if the address can't be parsed.
2710 */
2711util.bytesFromIPv4 = function(ip) {
2712 ip = ip.split('.');
2713 if(ip.length !== 4) {
2714 return null;
2715 }
2716 var b = util.createBuffer();
2717 for(var i = 0; i < ip.length; ++i) {
2718 var num = parseInt(ip[i], 10);
2719 if(isNaN(num)) {
2720 return null;
2721 }
2722 b.putByte(num);
2723 }
2724 return b.getBytes();
2725};
2726
2727/**
2728 * Converts an IPv6 string representation into bytes (in network order).
2729 *
2730 * @param ip the IPv6 address to convert.
2731 *
2732 * @return the 16-byte address or null if the address can't be parsed.
2733 */
2734util.bytesFromIPv6 = function(ip) {
2735 var blanks = 0;
2736 ip = ip.split(':').filter(function(e) {
2737 if(e.length === 0) ++blanks;
2738 return true;
2739 });
2740 var zeros = (8 - ip.length + blanks) * 2;
2741 var b = util.createBuffer();
2742 for(var i = 0; i < 8; ++i) {
2743 if(!ip[i] || ip[i].length === 0) {
2744 b.fillWithByte(0, zeros);
2745 zeros = 0;
2746 continue;
2747 }
2748 var bytes = util.hexToBytes(ip[i]);
2749 if(bytes.length < 2) {
2750 b.putByte(0);
2751 }
2752 b.putBytes(bytes);
2753 }
2754 return b.getBytes();
2755};
2756
2757/**
2758 * Converts 4-bytes into an IPv4 string representation or 16-bytes into
2759 * an IPv6 string representation. The bytes must be in network order.
2760 *
2761 * @param bytes the bytes to convert.
2762 *
2763 * @return the IPv4 or IPv6 string representation if 4 or 16 bytes,
2764 * respectively, are given, otherwise null.
2765 */
2766util.bytesToIP = function(bytes) {
2767 if(bytes.length === 4) {
2768 return util.bytesToIPv4(bytes);
2769 }
2770 if(bytes.length === 16) {
2771 return util.bytesToIPv6(bytes);
2772 }
2773 return null;
2774};
2775
2776/**
2777 * Converts 4-bytes into an IPv4 string representation. The bytes must be
2778 * in network order.
2779 *
2780 * @param bytes the bytes to convert.
2781 *
2782 * @return the IPv4 string representation or null for an invalid # of bytes.
2783 */
2784util.bytesToIPv4 = function(bytes) {
2785 if(bytes.length !== 4) {
2786 return null;
2787 }
2788 var ip = [];
2789 for(var i = 0; i < bytes.length; ++i) {
2790 ip.push(bytes.charCodeAt(i));
2791 }
2792 return ip.join('.');
2793};
2794
2795/**
2796 * Converts 16-bytes into an IPv16 string representation. The bytes must be
2797 * in network order.
2798 *
2799 * @param bytes the bytes to convert.
2800 *
2801 * @return the IPv16 string representation or null for an invalid # of bytes.
2802 */
2803util.bytesToIPv6 = function(bytes) {
2804 if(bytes.length !== 16) {
2805 return null;
2806 }
2807 var ip = [];
2808 var zeroGroups = [];
2809 var zeroMaxGroup = 0;
2810 for(var i = 0; i < bytes.length; i += 2) {
2811 var hex = util.bytesToHex(bytes[i] + bytes[i + 1]);
2812 // canonicalize zero representation
2813 while(hex[0] === '0' && hex !== '0') {
2814 hex = hex.substr(1);
2815 }
2816 if(hex === '0') {
2817 var last = zeroGroups[zeroGroups.length - 1];
2818 var idx = ip.length;
2819 if(!last || idx !== last.end + 1) {
2820 zeroGroups.push({start: idx, end: idx});
2821 } else {
2822 last.end = idx;
2823 if((last.end - last.start) >
2824 (zeroGroups[zeroMaxGroup].end - zeroGroups[zeroMaxGroup].start)) {
2825 zeroMaxGroup = zeroGroups.length - 1;
2826 }
2827 }
2828 }
2829 ip.push(hex);
2830 }
2831 if(zeroGroups.length > 0) {
2832 var group = zeroGroups[zeroMaxGroup];
2833 // only shorten group of length > 0
2834 if(group.end - group.start > 0) {
2835 ip.splice(group.start, group.end - group.start + 1, '');
2836 if(group.start === 0) {
2837 ip.unshift('');
2838 }
2839 if(group.end === 7) {
2840 ip.push('');
2841 }
2842 }
2843 }
2844 return ip.join(':');
2845};
2846
2847/**
2848 * Estimates the number of processes that can be run concurrently. If
2849 * creating Web Workers, keep in mind that the main JavaScript process needs
2850 * its own core.
2851 *
2852 * @param options the options to use:
2853 * update true to force an update (not use the cached value).
2854 * @param callback(err, max) called once the operation completes.
2855 */
2856util.estimateCores = function(options, callback) {
2857 if(typeof options === 'function') {
2858 callback = options;
2859 options = {};
2860 }
2861 options = options || {};
2862 if('cores' in util && !options.update) {
2863 return callback(null, util.cores);
2864 }
2865 if(typeof navigator !== 'undefined' &&
2866 'hardwareConcurrency' in navigator &&
2867 navigator.hardwareConcurrency > 0) {
2868 util.cores = navigator.hardwareConcurrency;
2869 return callback(null, util.cores);
2870 }
2871 if(typeof Worker === 'undefined') {
2872 // workers not available
2873 util.cores = 1;
2874 return callback(null, util.cores);
2875 }
2876 if(typeof Blob === 'undefined') {
2877 // can't estimate, default to 2
2878 util.cores = 2;
2879 return callback(null, util.cores);
2880 }
2881
2882 // create worker concurrency estimation code as blob
2883 var blobUrl = URL.createObjectURL(new Blob(['(',
2884 function() {
2885 self.addEventListener('message', function(e) {
2886 // run worker for 4 ms
2887 var st = Date.now();
2888 var et = st + 4;
2889 while(Date.now() < et);
2890 self.postMessage({st: st, et: et});
2891 });
2892 }.toString(),
2893 ')()'], {type: 'application/javascript'}));
2894
2895 // take 5 samples using 16 workers
2896 sample([], 5, 16);
2897
2898 function sample(max, samples, numWorkers) {
2899 if(samples === 0) {
2900 // get overlap average
2901 var avg = Math.floor(max.reduce(function(avg, x) {
2902 return avg + x;
2903 }, 0) / max.length);
2904 util.cores = Math.max(1, avg);
2905 URL.revokeObjectURL(blobUrl);
2906 return callback(null, util.cores);
2907 }
2908 map(numWorkers, function(err, results) {
2909 max.push(reduce(numWorkers, results));
2910 sample(max, samples - 1, numWorkers);
2911 });
2912 }
2913
2914 function map(numWorkers, callback) {
2915 var workers = [];
2916 var results = [];
2917 for(var i = 0; i < numWorkers; ++i) {
2918 var worker = new Worker(blobUrl);
2919 worker.addEventListener('message', function(e) {
2920 results.push(e.data);
2921 if(results.length === numWorkers) {
2922 for(var i = 0; i < numWorkers; ++i) {
2923 workers[i].terminate();
2924 }
2925 callback(null, results);
2926 }
2927 });
2928 workers.push(worker);
2929 }
2930 for(var i = 0; i < numWorkers; ++i) {
2931 workers[i].postMessage(i);
2932 }
2933 }
2934
2935 function reduce(numWorkers, results) {
2936 // find overlapping time windows
2937 var overlaps = [];
2938 for(var n = 0; n < numWorkers; ++n) {
2939 var r1 = results[n];
2940 var overlap = overlaps[n] = [];
2941 for(var i = 0; i < numWorkers; ++i) {
2942 if(n === i) {
2943 continue;
2944 }
2945 var r2 = results[i];
2946 if((r1.st > r2.st && r1.st < r2.et) ||
2947 (r2.st > r1.st && r2.st < r1.et)) {
2948 overlap.push(i);
2949 }
2950 }
2951 }
2952 // get maximum overlaps ... don't include overlapping worker itself
2953 // as the main JS process was also being scheduled during the work and
2954 // would have to be subtracted from the estimate anyway
2955 return overlaps.reduce(function(max, overlap) {
2956 return Math.max(max, overlap.length);
2957 }, 0);
2958 }
2959};
2960
2961} // end module implementation
2962
2963/* ########## Begin module wrapper ########## */
2964var name = 'util';
2965if(typeof define !== 'function') {
2966 // NodeJS -> AMD
2967 if(typeof module === 'object' && module.exports) {
2968 var nodeJS = true;
2969 define = function(ids, factory) {
2970 factory(require, module);
2971 };
2972 } else {
2973 // <script>
2974 if(typeof forge === 'undefined') {
2975 forge = {};
2976 }
2977 return initModule(forge);
2978 }
2979}
2980// AMD
2981var deps;
2982var defineFunc = function(require, module) {
2983 module.exports = function(forge) {
2984 var mods = deps.map(function(dep) {
2985 return require(dep);
2986 }).concat(initModule);
2987 // handle circular dependencies
2988 forge = forge || {};
2989 forge.defined = forge.defined || {};
2990 if(forge.defined[name]) {
2991 return forge[name];
2992 }
2993 forge.defined[name] = true;
2994 for(var i = 0; i < mods.length; ++i) {
2995 mods[i](forge);
2996 }
2997 return forge[name];
2998 };
2999};
3000var tmpDefine = define;
3001define = function(ids, factory) {
3002 deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
3003 if(nodeJS) {
3004 delete define;
3005 return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
3006 }
3007 define = tmpDefine;
3008 return define.apply(null, Array.prototype.slice.call(arguments, 0));
3009};
3010define(['require', 'module'], function() {
3011 defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
3012});
3013})();
3014
3015/**
3016 * Cipher base API.
3017 *
3018 * @author Dave Longley
3019 *
3020 * Copyright (c) 2010-2014 Digital Bazaar, Inc.
3021 */
3022(function() {
3023/* ########## Begin module implementation ########## */
3024function initModule(forge) {
3025
3026forge.cipher = forge.cipher || {};
3027
3028// registered algorithms
3029forge.cipher.algorithms = forge.cipher.algorithms || {};
3030
3031/**
3032 * Creates a cipher object that can be used to encrypt data using the given
3033 * algorithm and key. The algorithm may be provided as a string value for a
3034 * previously registered algorithm or it may be given as a cipher algorithm
3035 * API object.
3036 *
3037 * @param algorithm the algorithm to use, either a string or an algorithm API
3038 * object.
3039 * @param key the key to use, as a binary-encoded string of bytes or a
3040 * byte buffer.
3041 *
3042 * @return the cipher.
3043 */
3044forge.cipher.createCipher = function(algorithm, key) {
3045 var api = algorithm;
3046 if(typeof api === 'string') {
3047 api = forge.cipher.getAlgorithm(api);
3048 if(api) {
3049 api = api();
3050 }
3051 }
3052 if(!api) {
3053 throw new Error('Unsupported algorithm: ' + algorithm);
3054 }
3055
3056 // assume block cipher
3057 return new forge.cipher.BlockCipher({
3058 algorithm: api,
3059 key: key,
3060 decrypt: false
3061 });
3062};
3063
3064/**
3065 * Creates a decipher object that can be used to decrypt data using the given
3066 * algorithm and key. The algorithm may be provided as a string value for a
3067 * previously registered algorithm or it may be given as a cipher algorithm
3068 * API object.
3069 *
3070 * @param algorithm the algorithm to use, either a string or an algorithm API
3071 * object.
3072 * @param key the key to use, as a binary-encoded string of bytes or a
3073 * byte buffer.
3074 *
3075 * @return the cipher.
3076 */
3077forge.cipher.createDecipher = function(algorithm, key) {
3078 var api = algorithm;
3079 if(typeof api === 'string') {
3080 api = forge.cipher.getAlgorithm(api);
3081 if(api) {
3082 api = api();
3083 }
3084 }
3085 if(!api) {
3086 throw new Error('Unsupported algorithm: ' + algorithm);
3087 }
3088
3089 // assume block cipher
3090 return new forge.cipher.BlockCipher({
3091 algorithm: api,
3092 key: key,
3093 decrypt: true
3094 });
3095};
3096
3097/**
3098 * Registers an algorithm by name. If the name was already registered, the
3099 * algorithm API object will be overwritten.
3100 *
3101 * @param name the name of the algorithm.
3102 * @param algorithm the algorithm API object.
3103 */
3104forge.cipher.registerAlgorithm = function(name, algorithm) {
3105 name = name.toUpperCase();
3106 forge.cipher.algorithms[name] = algorithm;
3107};
3108
3109/**
3110 * Gets a registered algorithm by name.
3111 *
3112 * @param name the name of the algorithm.
3113 *
3114 * @return the algorithm, if found, null if not.
3115 */
3116forge.cipher.getAlgorithm = function(name) {
3117 name = name.toUpperCase();
3118 if(name in forge.cipher.algorithms) {
3119 return forge.cipher.algorithms[name];
3120 }
3121 return null;
3122};
3123
3124var BlockCipher = forge.cipher.BlockCipher = function(options) {
3125 this.algorithm = options.algorithm;
3126 this.mode = this.algorithm.mode;
3127 this.blockSize = this.mode.blockSize;
3128 this._finish = false;
3129 this._input = null;
3130 this.output = null;
3131 this._op = options.decrypt ? this.mode.decrypt : this.mode.encrypt;
3132 this._decrypt = options.decrypt;
3133 this.algorithm.initialize(options);
3134};
3135
3136/**
3137 * Starts or restarts the encryption or decryption process, whichever
3138 * was previously configured.
3139 *
3140 * For non-GCM mode, the IV may be a binary-encoded string of bytes, an array
3141 * of bytes, a byte buffer, or an array of 32-bit integers. If the IV is in
3142 * bytes, then it must be Nb (16) bytes in length. If the IV is given in as
3143 * 32-bit integers, then it must be 4 integers long.
3144 *
3145 * Note: an IV is not required or used in ECB mode.
3146 *
3147 * For GCM-mode, the IV must be given as a binary-encoded string of bytes or
3148 * a byte buffer. The number of bytes should be 12 (96 bits) as recommended
3149 * by NIST SP-800-38D but another length may be given.
3150 *
3151 * @param options the options to use:
3152 * iv the initialization vector to use as a binary-encoded string of
3153 * bytes, null to reuse the last ciphered block from a previous
3154 * update() (this "residue" method is for legacy support only).
3155 * additionalData additional authentication data as a binary-encoded
3156 * string of bytes, for 'GCM' mode, (default: none).
3157 * tagLength desired length of authentication tag, in bits, for
3158 * 'GCM' mode (0-128, default: 128).
3159 * tag the authentication tag to check if decrypting, as a
3160 * binary-encoded string of bytes.
3161 * output the output the buffer to write to, null to create one.
3162 */
3163BlockCipher.prototype.start = function(options) {
3164 options = options || {};
3165 var opts = {};
3166 for(var key in options) {
3167 opts[key] = options[key];
3168 }
3169 opts.decrypt = this._decrypt;
3170 this._finish = false;
3171 this._input = forge.util.createBuffer();
3172 this.output = options.output || forge.util.createBuffer();
3173 this.mode.start(opts);
3174};
3175
3176/**
3177 * Updates the next block according to the cipher mode.
3178 *
3179 * @param input the buffer to read from.
3180 */
3181BlockCipher.prototype.update = function(input) {
3182 if(input) {
3183 // input given, so empty it into the input buffer
3184 this._input.putBuffer(input);
3185 }
3186
3187 // do cipher operation until it needs more input and not finished
3188 while(!this._op.call(this.mode, this._input, this.output, this._finish) &&
3189 !this._finish) {}
3190
3191 // free consumed memory from input buffer
3192 this._input.compact();
3193};
3194
3195/**
3196 * Finishes encrypting or decrypting.
3197 *
3198 * @param pad a padding function to use in CBC mode, null for default,
3199 * signature(blockSize, buffer, decrypt).
3200 *
3201 * @return true if successful, false on error.
3202 */
3203BlockCipher.prototype.finish = function(pad) {
3204 // backwards-compatibility w/deprecated padding API
3205 // Note: will overwrite padding functions even after another start() call
3206 if(pad && (this.mode.name === 'ECB' || this.mode.name === 'CBC')) {
3207 this.mode.pad = function(input) {
3208 return pad(this.blockSize, input, false);
3209 };
3210 this.mode.unpad = function(output) {
3211 return pad(this.blockSize, output, true);
3212 };
3213 }
3214
3215 // build options for padding and afterFinish functions
3216 var options = {};
3217 options.decrypt = this._decrypt;
3218
3219 // get # of bytes that won't fill a block
3220 options.overflow = this._input.length() % this.blockSize;
3221
3222 if(!this._decrypt && this.mode.pad) {
3223 if(!this.mode.pad(this._input, options)) {
3224 return false;
3225 }
3226 }
3227
3228 // do final update
3229 this._finish = true;
3230 this.update();
3231
3232 if(this._decrypt && this.mode.unpad) {
3233 if(!this.mode.unpad(this.output, options)) {
3234 return false;
3235 }
3236 }
3237
3238 if(this.mode.afterFinish) {
3239 if(!this.mode.afterFinish(this.output, options)) {
3240 return false;
3241 }
3242 }
3243
3244 return true;
3245};
3246
3247
3248} // end module implementation
3249
3250/* ########## Begin module wrapper ########## */
3251var name = 'cipher';
3252if(typeof define !== 'function') {
3253 // NodeJS -> AMD
3254 if(typeof module === 'object' && module.exports) {
3255 var nodeJS = true;
3256 define = function(ids, factory) {
3257 factory(require, module);
3258 };
3259 } else {
3260 // <script>
3261 if(typeof forge === 'undefined') {
3262 forge = {};
3263 }
3264 return initModule(forge);
3265 }
3266}
3267// AMD
3268var deps;
3269var defineFunc = function(require, module) {
3270 module.exports = function(forge) {
3271 var mods = deps.map(function(dep) {
3272 return require(dep);
3273 }).concat(initModule);
3274 // handle circular dependencies
3275 forge = forge || {};
3276 forge.defined = forge.defined || {};
3277 if(forge.defined[name]) {
3278 return forge[name];
3279 }
3280 forge.defined[name] = true;
3281 for(var i = 0; i < mods.length; ++i) {
3282 mods[i](forge);
3283 }
3284 return forge[name];
3285 };
3286};
3287var tmpDefine = define;
3288define = function(ids, factory) {
3289 deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
3290 if(nodeJS) {
3291 delete define;
3292 return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
3293 }
3294 define = tmpDefine;
3295 return define.apply(null, Array.prototype.slice.call(arguments, 0));
3296};
3297define(['require', 'module', './util'], function() {
3298 defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
3299});
3300})();
3301
3302/**
3303 * Supported cipher modes.
3304 *
3305 * @author Dave Longley
3306 *
3307 * Copyright (c) 2010-2014 Digital Bazaar, Inc.
3308 */
3309(function() {
3310/* ########## Begin module implementation ########## */
3311function initModule(forge) {
3312
3313forge.cipher = forge.cipher || {};
3314
3315// supported cipher modes
3316var modes = forge.cipher.modes = forge.cipher.modes || {};
3317
3318
3319/** Electronic codebook (ECB) (Don't use this; it's not secure) **/
3320
3321modes.ecb = function(options) {
3322 options = options || {};
3323 this.name = 'ECB';
3324 this.cipher = options.cipher;
3325 this.blockSize = options.blockSize || 16;
3326 this._ints = this.blockSize / 4;
3327 this._inBlock = new Array(this._ints);
3328 this._outBlock = new Array(this._ints);
3329};
3330
3331modes.ecb.prototype.start = function(options) {};
3332
3333modes.ecb.prototype.encrypt = function(input, output, finish) {
3334 // not enough input to encrypt
3335 if(input.length() < this.blockSize && !(finish && input.length() > 0)) {
3336 return true;
3337 }
3338
3339 // get next block
3340 for(var i = 0; i < this._ints; ++i) {
3341 this._inBlock[i] = input.getInt32();
3342 }
3343
3344 // encrypt block
3345 this.cipher.encrypt(this._inBlock, this._outBlock);
3346
3347 // write output
3348 for(var i = 0; i < this._ints; ++i) {
3349 output.putInt32(this._outBlock[i]);
3350 }
3351};
3352
3353modes.ecb.prototype.decrypt = function(input, output, finish) {
3354 // not enough input to decrypt
3355 if(input.length() < this.blockSize && !(finish && input.length() > 0)) {
3356 return true;
3357 }
3358
3359 // get next block
3360 for(var i = 0; i < this._ints; ++i) {
3361 this._inBlock[i] = input.getInt32();
3362 }
3363
3364 // decrypt block
3365 this.cipher.decrypt(this._inBlock, this._outBlock);
3366
3367 // write output
3368 for(var i = 0; i < this._ints; ++i) {
3369 output.putInt32(this._outBlock[i]);
3370 }
3371};
3372
3373modes.ecb.prototype.pad = function(input, options) {
3374 // add PKCS#7 padding to block (each pad byte is the
3375 // value of the number of pad bytes)
3376 var padding = (input.length() === this.blockSize ?
3377 this.blockSize : (this.blockSize - input.length()));
3378 input.fillWithByte(padding, padding);
3379 return true;
3380};
3381
3382modes.ecb.prototype.unpad = function(output, options) {
3383 // check for error: input data not a multiple of blockSize
3384 if(options.overflow > 0) {
3385 return false;
3386 }
3387
3388 // ensure padding byte count is valid
3389 var len = output.length();
3390 var count = output.at(len - 1);
3391 if(count > (this.blockSize << 2)) {
3392 return false;
3393 }
3394
3395 // trim off padding bytes
3396 output.truncate(count);
3397 return true;
3398};
3399
3400
3401/** Cipher-block Chaining (CBC) **/
3402
3403modes.cbc = function(options) {
3404 options = options || {};
3405 this.name = 'CBC';
3406 this.cipher = options.cipher;
3407 this.blockSize = options.blockSize || 16;
3408 this._ints = this.blockSize / 4;
3409 this._inBlock = new Array(this._ints);
3410 this._outBlock = new Array(this._ints);
3411};
3412
3413modes.cbc.prototype.start = function(options) {
3414 // Note: legacy support for using IV residue (has security flaws)
3415 // if IV is null, reuse block from previous processing
3416 if(options.iv === null) {
3417 // must have a previous block
3418 if(!this._prev) {
3419 throw new Error('Invalid IV parameter.');
3420 }
3421 this._iv = this._prev.slice(0);
3422 } else if(!('iv' in options)) {
3423 throw new Error('Invalid IV parameter.');
3424 } else {
3425 // save IV as "previous" block
3426 this._iv = transformIV(options.iv);
3427 this._prev = this._iv.slice(0);
3428 }
3429};
3430
3431modes.cbc.prototype.encrypt = function(input, output, finish) {
3432 // not enough input to encrypt
3433 if(input.length() < this.blockSize && !(finish && input.length() > 0)) {
3434 return true;
3435 }
3436
3437 // get next block
3438 // CBC XOR's IV (or previous block) with plaintext
3439 for(var i = 0; i < this._ints; ++i) {
3440 this._inBlock[i] = this._prev[i] ^ input.getInt32();
3441 }
3442
3443 // encrypt block
3444 this.cipher.encrypt(this._inBlock, this._outBlock);
3445
3446 // write output, save previous block
3447 for(var i = 0; i < this._ints; ++i) {
3448 output.putInt32(this._outBlock[i]);
3449 }
3450 this._prev = this._outBlock;
3451};
3452
3453modes.cbc.prototype.decrypt = function(input, output, finish) {
3454 // not enough input to decrypt
3455 if(input.length() < this.blockSize && !(finish && input.length() > 0)) {
3456 return true;
3457 }
3458
3459 // get next block
3460 for(var i = 0; i < this._ints; ++i) {
3461 this._inBlock[i] = input.getInt32();
3462 }
3463
3464 // decrypt block
3465 this.cipher.decrypt(this._inBlock, this._outBlock);
3466
3467 // write output, save previous ciphered block
3468 // CBC XOR's IV (or previous block) with ciphertext
3469 for(var i = 0; i < this._ints; ++i) {
3470 output.putInt32(this._prev[i] ^ this._outBlock[i]);
3471 }
3472 this._prev = this._inBlock.slice(0);
3473};
3474
3475modes.cbc.prototype.pad = function(input, options) {
3476 // add PKCS#7 padding to block (each pad byte is the
3477 // value of the number of pad bytes)
3478 var padding = (input.length() === this.blockSize ?
3479 this.blockSize : (this.blockSize - input.length()));
3480 input.fillWithByte(padding, padding);
3481 return true;
3482};
3483
3484modes.cbc.prototype.unpad = function(output, options) {
3485 // check for error: input data not a multiple of blockSize
3486 if(options.overflow > 0) {
3487 return false;
3488 }
3489
3490 // ensure padding byte count is valid
3491 var len = output.length();
3492 var count = output.at(len - 1);
3493 if(count > (this.blockSize << 2)) {
3494 return false;
3495 }
3496
3497 // trim off padding bytes
3498 output.truncate(count);
3499 return true;
3500};
3501
3502
3503/** Cipher feedback (CFB) **/
3504
3505modes.cfb = function(options) {
3506 options = options || {};
3507 this.name = 'CFB';
3508 this.cipher = options.cipher;
3509 this.blockSize = options.blockSize || 16;
3510 this._ints = this.blockSize / 4;
3511 this._inBlock = null;
3512 this._outBlock = new Array(this._ints);
3513 this._partialBlock = new Array(this._ints);
3514 this._partialOutput = forge.util.createBuffer();
3515 this._partialBytes = 0;
3516};
3517
3518modes.cfb.prototype.start = function(options) {
3519 if(!('iv' in options)) {
3520 throw new Error('Invalid IV parameter.');
3521 }
3522 // use IV as first input
3523 this._iv = transformIV(options.iv);
3524 this._inBlock = this._iv.slice(0);
3525 this._partialBytes = 0;
3526};
3527
3528modes.cfb.prototype.encrypt = function(input, output, finish) {
3529 // not enough input to encrypt
3530 var inputLength = input.length();
3531 if(inputLength === 0) {
3532 return true;
3533 }
3534
3535 // encrypt block
3536 this.cipher.encrypt(this._inBlock, this._outBlock);
3537
3538 // handle full block
3539 if(this._partialBytes === 0 && inputLength >= this.blockSize) {
3540 // XOR input with output, write input as output
3541 for(var i = 0; i < this._ints; ++i) {
3542 this._inBlock[i] = input.getInt32() ^ this._outBlock[i];
3543 output.putInt32(this._inBlock[i]);
3544 }
3545 return;
3546 }
3547
3548 // handle partial block
3549 var partialBytes = (this.blockSize - inputLength) % this.blockSize;
3550 if(partialBytes > 0) {
3551 partialBytes = this.blockSize - partialBytes;
3552 }
3553
3554 // XOR input with output, write input as partial output
3555 this._partialOutput.clear();
3556 for(var i = 0; i < this._ints; ++i) {
3557 this._partialBlock[i] = input.getInt32() ^ this._outBlock[i];
3558 this._partialOutput.putInt32(this._partialBlock[i]);
3559 }
3560
3561 if(partialBytes > 0) {
3562 // block still incomplete, restore input buffer
3563 input.read -= this.blockSize;
3564 } else {
3565 // block complete, update input block
3566 for(var i = 0; i < this._ints; ++i) {
3567 this._inBlock[i] = this._partialBlock[i];
3568 }
3569 }
3570
3571 // skip any previous partial bytes
3572 if(this._partialBytes > 0) {
3573 this._partialOutput.getBytes(this._partialBytes);
3574 }
3575
3576 if(partialBytes > 0 && !finish) {
3577 output.putBytes(this._partialOutput.getBytes(
3578 partialBytes - this._partialBytes));
3579 this._partialBytes = partialBytes;
3580 return true;
3581 }
3582
3583 output.putBytes(this._partialOutput.getBytes(
3584 inputLength - this._partialBytes));
3585 this._partialBytes = 0;
3586};
3587
3588modes.cfb.prototype.decrypt = function(input, output, finish) {
3589 // not enough input to decrypt
3590 var inputLength = input.length();
3591 if(inputLength === 0) {
3592 return true;
3593 }
3594
3595 // encrypt block (CFB always uses encryption mode)
3596 this.cipher.encrypt(this._inBlock, this._outBlock);
3597
3598 // handle full block
3599 if(this._partialBytes === 0 && inputLength >= this.blockSize) {
3600 // XOR input with output, write input as output
3601 for(var i = 0; i < this._ints; ++i) {
3602 this._inBlock[i] = input.getInt32();
3603 output.putInt32(this._inBlock[i] ^ this._outBlock[i]);
3604 }
3605 return;
3606 }
3607
3608 // handle partial block
3609 var partialBytes = (this.blockSize - inputLength) % this.blockSize;
3610 if(partialBytes > 0) {
3611 partialBytes = this.blockSize - partialBytes;
3612 }
3613
3614 // XOR input with output, write input as partial output
3615 this._partialOutput.clear();
3616 for(var i = 0; i < this._ints; ++i) {
3617 this._partialBlock[i] = input.getInt32();
3618 this._partialOutput.putInt32(this._partialBlock[i] ^ this._outBlock[i]);
3619 }
3620
3621 if(partialBytes > 0) {
3622 // block still incomplete, restore input buffer
3623 input.read -= this.blockSize;
3624 } else {
3625 // block complete, update input block
3626 for(var i = 0; i < this._ints; ++i) {
3627 this._inBlock[i] = this._partialBlock[i];
3628 }
3629 }
3630
3631 // skip any previous partial bytes
3632 if(this._partialBytes > 0) {
3633 this._partialOutput.getBytes(this._partialBytes);
3634 }
3635
3636 if(partialBytes > 0 && !finish) {
3637 output.putBytes(this._partialOutput.getBytes(
3638 partialBytes - this._partialBytes));
3639 this._partialBytes = partialBytes;
3640 return true;
3641 }
3642
3643 output.putBytes(this._partialOutput.getBytes(
3644 inputLength - this._partialBytes));
3645 this._partialBytes = 0;
3646};
3647
3648/** Output feedback (OFB) **/
3649
3650modes.ofb = function(options) {
3651 options = options || {};
3652 this.name = 'OFB';
3653 this.cipher = options.cipher;
3654 this.blockSize = options.blockSize || 16;
3655 this._ints = this.blockSize / 4;
3656 this._inBlock = null;
3657 this._outBlock = new Array(this._ints);
3658 this._partialOutput = forge.util.createBuffer();
3659 this._partialBytes = 0;
3660};
3661
3662modes.ofb.prototype.start = function(options) {
3663 if(!('iv' in options)) {
3664 throw new Error('Invalid IV parameter.');
3665 }
3666 // use IV as first input
3667 this._iv = transformIV(options.iv);
3668 this._inBlock = this._iv.slice(0);
3669 this._partialBytes = 0;
3670};
3671
3672modes.ofb.prototype.encrypt = function(input, output, finish) {
3673 // not enough input to encrypt
3674 var inputLength = input.length();
3675 if(input.length() === 0) {
3676 return true;
3677 }
3678
3679 // encrypt block (OFB always uses encryption mode)
3680 this.cipher.encrypt(this._inBlock, this._outBlock);
3681
3682 // handle full block
3683 if(this._partialBytes === 0 && inputLength >= this.blockSize) {
3684 // XOR input with output and update next input
3685 for(var i = 0; i < this._ints; ++i) {
3686 output.putInt32(input.getInt32() ^ this._outBlock[i]);
3687 this._inBlock[i] = this._outBlock[i];
3688 }
3689 return;
3690 }
3691
3692 // handle partial block
3693 var partialBytes = (this.blockSize - inputLength) % this.blockSize;
3694 if(partialBytes > 0) {
3695 partialBytes = this.blockSize - partialBytes;
3696 }
3697
3698 // XOR input with output
3699 this._partialOutput.clear();
3700 for(var i = 0; i < this._ints; ++i) {
3701 this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]);
3702 }
3703
3704 if(partialBytes > 0) {
3705 // block still incomplete, restore input buffer
3706 input.read -= this.blockSize;
3707 } else {
3708 // block complete, update input block
3709 for(var i = 0; i < this._ints; ++i) {
3710 this._inBlock[i] = this._outBlock[i];
3711 }
3712 }
3713
3714 // skip any previous partial bytes
3715 if(this._partialBytes > 0) {
3716 this._partialOutput.getBytes(this._partialBytes);
3717 }
3718
3719 if(partialBytes > 0 && !finish) {
3720 output.putBytes(this._partialOutput.getBytes(
3721 partialBytes - this._partialBytes));
3722 this._partialBytes = partialBytes;
3723 return true;
3724 }
3725
3726 output.putBytes(this._partialOutput.getBytes(
3727 inputLength - this._partialBytes));
3728 this._partialBytes = 0;
3729};
3730
3731modes.ofb.prototype.decrypt = modes.ofb.prototype.encrypt;
3732
3733
3734/** Counter (CTR) **/
3735
3736modes.ctr = function(options) {
3737 options = options || {};
3738 this.name = 'CTR';
3739 this.cipher = options.cipher;
3740 this.blockSize = options.blockSize || 16;
3741 this._ints = this.blockSize / 4;
3742 this._inBlock = null;
3743 this._outBlock = new Array(this._ints);
3744 this._partialOutput = forge.util.createBuffer();
3745 this._partialBytes = 0;
3746};
3747
3748modes.ctr.prototype.start = function(options) {
3749 if(!('iv' in options)) {
3750 throw new Error('Invalid IV parameter.');
3751 }
3752 // use IV as first input
3753 this._iv = transformIV(options.iv);
3754 this._inBlock = this._iv.slice(0);
3755 this._partialBytes = 0;
3756};
3757
3758modes.ctr.prototype.encrypt = function(input, output, finish) {
3759 // not enough input to encrypt
3760 var inputLength = input.length();
3761 if(inputLength === 0) {
3762 return true;
3763 }
3764
3765 // encrypt block (CTR always uses encryption mode)
3766 this.cipher.encrypt(this._inBlock, this._outBlock);
3767
3768 // handle full block
3769 if(this._partialBytes === 0 && inputLength >= this.blockSize) {
3770 // XOR input with output
3771 for(var i = 0; i < this._ints; ++i) {
3772 output.putInt32(input.getInt32() ^ this._outBlock[i]);
3773 }
3774 } else {
3775 // handle partial block
3776 var partialBytes = (this.blockSize - inputLength) % this.blockSize;
3777 if(partialBytes > 0) {
3778 partialBytes = this.blockSize - partialBytes;
3779 }
3780
3781 // XOR input with output
3782 this._partialOutput.clear();
3783 for(var i = 0; i < this._ints; ++i) {
3784 this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]);
3785 }
3786
3787 if(partialBytes > 0) {
3788 // block still incomplete, restore input buffer
3789 input.read -= this.blockSize;
3790 }
3791
3792 // skip any previous partial bytes
3793 if(this._partialBytes > 0) {
3794 this._partialOutput.getBytes(this._partialBytes);
3795 }
3796
3797 if(partialBytes > 0 && !finish) {
3798 output.putBytes(this._partialOutput.getBytes(
3799 partialBytes - this._partialBytes));
3800 this._partialBytes = partialBytes;
3801 return true;
3802 }
3803
3804 output.putBytes(this._partialOutput.getBytes(
3805 inputLength - this._partialBytes));
3806 this._partialBytes = 0;
3807 }
3808
3809 // block complete, increment counter (input block)
3810 inc32(this._inBlock);
3811};
3812
3813modes.ctr.prototype.decrypt = modes.ctr.prototype.encrypt;
3814
3815
3816/** Galois/Counter Mode (GCM) **/
3817
3818modes.gcm = function(options) {
3819 options = options || {};
3820 this.name = 'GCM';
3821 this.cipher = options.cipher;
3822 this.blockSize = options.blockSize || 16;
3823 this._ints = this.blockSize / 4;
3824 this._inBlock = new Array(this._ints);
3825 this._outBlock = new Array(this._ints);
3826 this._partialOutput = forge.util.createBuffer();
3827 this._partialBytes = 0;
3828
3829 // R is actually this value concatenated with 120 more zero bits, but
3830 // we only XOR against R so the other zeros have no effect -- we just
3831 // apply this value to the first integer in a block
3832 this._R = 0xE1000000;
3833};
3834
3835modes.gcm.prototype.start = function(options) {
3836 if(!('iv' in options)) {
3837 throw new Error('Invalid IV parameter.');
3838 }
3839 // ensure IV is a byte buffer
3840 var iv = forge.util.createBuffer(options.iv);
3841
3842 // no ciphered data processed yet
3843 this._cipherLength = 0;
3844
3845 // default additional data is none
3846 var additionalData;
3847 if('additionalData' in options) {
3848 additionalData = forge.util.createBuffer(options.additionalData);
3849 } else {
3850 additionalData = forge.util.createBuffer();
3851 }
3852
3853 // default tag length is 128 bits
3854 if('tagLength' in options) {
3855 this._tagLength = options.tagLength;
3856 } else {
3857 this._tagLength = 128;
3858 }
3859
3860 // if tag is given, ensure tag matches tag length
3861 this._tag = null;
3862 if(options.decrypt) {
3863 // save tag to check later
3864 this._tag = forge.util.createBuffer(options.tag).getBytes();
3865 if(this._tag.length !== (this._tagLength / 8)) {
3866 throw new Error('Authentication tag does not match tag length.');
3867 }
3868 }
3869
3870 // create tmp storage for hash calculation
3871 this._hashBlock = new Array(this._ints);
3872
3873 // no tag generated yet
3874 this.tag = null;
3875
3876 // generate hash subkey
3877 // (apply block cipher to "zero" block)
3878 this._hashSubkey = new Array(this._ints);
3879 this.cipher.encrypt([0, 0, 0, 0], this._hashSubkey);
3880
3881 // generate table M
3882 // use 4-bit tables (32 component decomposition of a 16 byte value)
3883 // 8-bit tables take more space and are known to have security
3884 // vulnerabilities (in native implementations)
3885 this.componentBits = 4;
3886 this._m = this.generateHashTable(this._hashSubkey, this.componentBits);
3887
3888 // Note: support IV length different from 96 bits? (only supporting
3889 // 96 bits is recommended by NIST SP-800-38D)
3890 // generate J_0
3891 var ivLength = iv.length();
3892 if(ivLength === 12) {
3893 // 96-bit IV
3894 this._j0 = [iv.getInt32(), iv.getInt32(), iv.getInt32(), 1];
3895 } else {
3896 // IV is NOT 96-bits
3897 this._j0 = [0, 0, 0, 0];
3898 while(iv.length() > 0) {
3899 this._j0 = this.ghash(
3900 this._hashSubkey, this._j0,
3901 [iv.getInt32(), iv.getInt32(), iv.getInt32(), iv.getInt32()]);
3902 }
3903 this._j0 = this.ghash(
3904 this._hashSubkey, this._j0, [0, 0].concat(from64To32(ivLength * 8)));
3905 }
3906
3907 // generate ICB (initial counter block)
3908 this._inBlock = this._j0.slice(0);
3909 inc32(this._inBlock);
3910 this._partialBytes = 0;
3911
3912 // consume authentication data
3913 additionalData = forge.util.createBuffer(additionalData);
3914 // save additional data length as a BE 64-bit number
3915 this._aDataLength = from64To32(additionalData.length() * 8);
3916 // pad additional data to 128 bit (16 byte) block size
3917 var overflow = additionalData.length() % this.blockSize;
3918 if(overflow) {
3919 additionalData.fillWithByte(0, this.blockSize - overflow);
3920 }
3921 this._s = [0, 0, 0, 0];
3922 while(additionalData.length() > 0) {
3923 this._s = this.ghash(this._hashSubkey, this._s, [
3924 additionalData.getInt32(),
3925 additionalData.getInt32(),
3926 additionalData.getInt32(),
3927 additionalData.getInt32()
3928 ]);
3929 }
3930};
3931
3932modes.gcm.prototype.encrypt = function(input, output, finish) {
3933 // not enough input to encrypt
3934 var inputLength = input.length();
3935 if(inputLength === 0) {
3936 return true;
3937 }
3938
3939 // encrypt block
3940 this.cipher.encrypt(this._inBlock, this._outBlock);
3941
3942 // handle full block
3943 if(this._partialBytes === 0 && inputLength >= this.blockSize) {
3944 // XOR input with output
3945 for(var i = 0; i < this._ints; ++i) {
3946 output.putInt32(this._outBlock[i] ^= input.getInt32());
3947 }
3948 this._cipherLength += this.blockSize;
3949 } else {
3950 // handle partial block
3951 var partialBytes = (this.blockSize - inputLength) % this.blockSize;
3952 if(partialBytes > 0) {
3953 partialBytes = this.blockSize - partialBytes;
3954 }
3955
3956 // XOR input with output
3957 this._partialOutput.clear();
3958 for(var i = 0; i < this._ints; ++i) {
3959 this._partialOutput.putInt32(input.getInt32() ^ this._outBlock[i]);
3960 }
3961
3962 if(partialBytes === 0 || finish) {
3963 // handle overflow prior to hashing
3964 if(finish) {
3965 // get block overflow
3966 var overflow = inputLength % this.blockSize;
3967 this._cipherLength += overflow;
3968 // truncate for hash function
3969 this._partialOutput.truncate(this.blockSize - overflow);
3970 } else {
3971 this._cipherLength += this.blockSize;
3972 }
3973
3974 // get output block for hashing
3975 for(var i = 0; i < this._ints; ++i) {
3976 this._outBlock[i] = this._partialOutput.getInt32();
3977 }
3978 this._partialOutput.read -= this.blockSize;
3979 }
3980
3981 // skip any previous partial bytes
3982 if(this._partialBytes > 0) {
3983 this._partialOutput.getBytes(this._partialBytes);
3984 }
3985
3986 if(partialBytes > 0 && !finish) {
3987 // block still incomplete, restore input buffer, get partial output,
3988 // and return early
3989 input.read -= this.blockSize;
3990 output.putBytes(this._partialOutput.getBytes(
3991 partialBytes - this._partialBytes));
3992 this._partialBytes = partialBytes;
3993 return true;
3994 }
3995
3996 output.putBytes(this._partialOutput.getBytes(
3997 inputLength - this._partialBytes));
3998 this._partialBytes = 0;
3999 }
4000
4001 // update hash block S
4002 this._s = this.ghash(this._hashSubkey, this._s, this._outBlock);
4003
4004 // increment counter (input block)
4005 inc32(this._inBlock);
4006};
4007
4008modes.gcm.prototype.decrypt = function(input, output, finish) {
4009 // not enough input to decrypt
4010 var inputLength = input.length();
4011 if(inputLength < this.blockSize && !(finish && inputLength > 0)) {
4012 return true;
4013 }
4014
4015 // encrypt block (GCM always uses encryption mode)
4016 this.cipher.encrypt(this._inBlock, this._outBlock);
4017
4018 // increment counter (input block)
4019 inc32(this._inBlock);
4020
4021 // update hash block S
4022 this._hashBlock[0] = input.getInt32();
4023 this._hashBlock[1] = input.getInt32();
4024 this._hashBlock[2] = input.getInt32();
4025 this._hashBlock[3] = input.getInt32();
4026 this._s = this.ghash(this._hashSubkey, this._s, this._hashBlock);
4027
4028 // XOR hash input with output
4029 for(var i = 0; i < this._ints; ++i) {
4030 output.putInt32(this._outBlock[i] ^ this._hashBlock[i]);
4031 }
4032
4033 // increment cipher data length
4034 if(inputLength < this.blockSize) {
4035 this._cipherLength += inputLength % this.blockSize;
4036 } else {
4037 this._cipherLength += this.blockSize;
4038 }
4039};
4040
4041modes.gcm.prototype.afterFinish = function(output, options) {
4042 var rval = true;
4043
4044 // handle overflow
4045 if(options.decrypt && options.overflow) {
4046 output.truncate(this.blockSize - options.overflow);
4047 }
4048
4049 // handle authentication tag
4050 this.tag = forge.util.createBuffer();
4051
4052 // concatenate additional data length with cipher length
4053 var lengths = this._aDataLength.concat(from64To32(this._cipherLength * 8));
4054
4055 // include lengths in hash
4056 this._s = this.ghash(this._hashSubkey, this._s, lengths);
4057
4058 // do GCTR(J_0, S)
4059 var tag = [];
4060 this.cipher.encrypt(this._j0, tag);
4061 for(var i = 0; i < this._ints; ++i) {
4062 this.tag.putInt32(this._s[i] ^ tag[i]);
4063 }
4064
4065 // trim tag to length
4066 this.tag.truncate(this.tag.length() % (this._tagLength / 8));
4067
4068 // check authentication tag
4069 if(options.decrypt && this.tag.bytes() !== this._tag) {
4070 rval = false;
4071 }
4072
4073 return rval;
4074};
4075
4076/**
4077 * See NIST SP-800-38D 6.3 (Algorithm 1). This function performs Galois
4078 * field multiplication. The field, GF(2^128), is defined by the polynomial:
4079 *
4080 * x^128 + x^7 + x^2 + x + 1
4081 *
4082 * Which is represented in little-endian binary form as: 11100001 (0xe1). When
4083 * the value of a coefficient is 1, a bit is set. The value R, is the
4084 * concatenation of this value and 120 zero bits, yielding a 128-bit value
4085 * which matches the block size.
4086 *
4087 * This function will multiply two elements (vectors of bytes), X and Y, in
4088 * the field GF(2^128). The result is initialized to zero. For each bit of
4089 * X (out of 128), x_i, if x_i is set, then the result is multiplied (XOR'd)
4090 * by the current value of Y. For each bit, the value of Y will be raised by
4091 * a power of x (multiplied by the polynomial x). This can be achieved by
4092 * shifting Y once to the right. If the current value of Y, prior to being
4093 * multiplied by x, has 0 as its LSB, then it is a 127th degree polynomial.
4094 * Otherwise, we must divide by R after shifting to find the remainder.
4095 *
4096 * @param x the first block to multiply by the second.
4097 * @param y the second block to multiply by the first.
4098 *
4099 * @return the block result of the multiplication.
4100 */
4101modes.gcm.prototype.multiply = function(x, y) {
4102 var z_i = [0, 0, 0, 0];
4103 var v_i = y.slice(0);
4104
4105 // calculate Z_128 (block has 128 bits)
4106 for(var i = 0; i < 128; ++i) {
4107 // if x_i is 0, Z_{i+1} = Z_i (unchanged)
4108 // else Z_{i+1} = Z_i ^ V_i
4109 // get x_i by finding 32-bit int position, then left shift 1 by remainder
4110 var x_i = x[(i / 32) | 0] & (1 << (31 - i % 32));
4111 if(x_i) {
4112 z_i[0] ^= v_i[0];
4113 z_i[1] ^= v_i[1];
4114 z_i[2] ^= v_i[2];
4115 z_i[3] ^= v_i[3];
4116 }
4117
4118 // if LSB(V_i) is 1, V_i = V_i >> 1
4119 // else V_i = (V_i >> 1) ^ R
4120 this.pow(v_i, v_i);
4121 }
4122
4123 return z_i;
4124};
4125
4126modes.gcm.prototype.pow = function(x, out) {
4127 // if LSB(x) is 1, x = x >>> 1
4128 // else x = (x >>> 1) ^ R
4129 var lsb = x[3] & 1;
4130
4131 // always do x >>> 1:
4132 // starting with the rightmost integer, shift each integer to the right
4133 // one bit, pulling in the bit from the integer to the left as its top
4134 // most bit (do this for the last 3 integers)
4135 for(var i = 3; i > 0; --i) {
4136 out[i] = (x[i] >>> 1) | ((x[i - 1] & 1) << 31);
4137 }
4138 // shift the first integer normally
4139 out[0] = x[0] >>> 1;
4140
4141 // if lsb was not set, then polynomial had a degree of 127 and doesn't
4142 // need to divided; otherwise, XOR with R to find the remainder; we only
4143 // need to XOR the first integer since R technically ends w/120 zero bits
4144 if(lsb) {
4145 out[0] ^= this._R;
4146 }
4147};
4148
4149modes.gcm.prototype.tableMultiply = function(x) {
4150 // assumes 4-bit tables are used
4151 var z = [0, 0, 0, 0];
4152 for(var i = 0; i < 32; ++i) {
4153 var idx = (i / 8) | 0;
4154 var x_i = (x[idx] >>> ((7 - (i % 8)) * 4)) & 0xF;
4155 var ah = this._m[i][x_i];
4156 z[0] ^= ah[0];
4157 z[1] ^= ah[1];
4158 z[2] ^= ah[2];
4159 z[3] ^= ah[3];
4160 }
4161 return z;
4162};
4163
4164/**
4165 * A continuing version of the GHASH algorithm that operates on a single
4166 * block. The hash block, last hash value (Ym) and the new block to hash
4167 * are given.
4168 *
4169 * @param h the hash block.
4170 * @param y the previous value for Ym, use [0, 0, 0, 0] for a new hash.
4171 * @param x the block to hash.
4172 *
4173 * @return the hashed value (Ym).
4174 */
4175modes.gcm.prototype.ghash = function(h, y, x) {
4176 y[0] ^= x[0];
4177 y[1] ^= x[1];
4178 y[2] ^= x[2];
4179 y[3] ^= x[3];
4180 return this.tableMultiply(y);
4181 //return this.multiply(y, h);
4182};
4183
4184/**
4185 * Precomputes a table for multiplying against the hash subkey. This
4186 * mechanism provides a substantial speed increase over multiplication
4187 * performed without a table. The table-based multiplication this table is
4188 * for solves X * H by multiplying each component of X by H and then
4189 * composing the results together using XOR.
4190 *
4191 * This function can be used to generate tables with different bit sizes
4192 * for the components, however, this implementation assumes there are
4193 * 32 components of X (which is a 16 byte vector), therefore each component
4194 * takes 4-bits (so the table is constructed with bits=4).
4195 *
4196 * @param h the hash subkey.
4197 * @param bits the bit size for a component.
4198 */
4199modes.gcm.prototype.generateHashTable = function(h, bits) {
4200 // TODO: There are further optimizations that would use only the
4201 // first table M_0 (or some variant) along with a remainder table;
4202 // this can be explored in the future
4203 var multiplier = 8 / bits;
4204 var perInt = 4 * multiplier;
4205 var size = 16 * multiplier;
4206 var m = new Array(size);
4207 for(var i = 0; i < size; ++i) {
4208 var tmp = [0, 0, 0, 0];
4209 var idx = (i / perInt) | 0;
4210 var shft = ((perInt - 1 - (i % perInt)) * bits);
4211 tmp[idx] = (1 << (bits - 1)) << shft;
4212 m[i] = this.generateSubHashTable(this.multiply(tmp, h), bits);
4213 }
4214 return m;
4215};
4216
4217/**
4218 * Generates a table for multiplying against the hash subkey for one
4219 * particular component (out of all possible component values).
4220 *
4221 * @param mid the pre-multiplied value for the middle key of the table.
4222 * @param bits the bit size for a component.
4223 */
4224modes.gcm.prototype.generateSubHashTable = function(mid, bits) {
4225 // compute the table quickly by minimizing the number of
4226 // POW operations -- they only need to be performed for powers of 2,
4227 // all other entries can be composed from those powers using XOR
4228 var size = 1 << bits;
4229 var half = size >>> 1;
4230 var m = new Array(size);
4231 m[half] = mid.slice(0);
4232 var i = half >>> 1;
4233 while(i > 0) {
4234 // raise m0[2 * i] and store in m0[i]
4235 this.pow(m[2 * i], m[i] = []);
4236 i >>= 1;
4237 }
4238 i = 2;
4239 while(i < half) {
4240 for(var j = 1; j < i; ++j) {
4241 var m_i = m[i];
4242 var m_j = m[j];
4243 m[i + j] = [
4244 m_i[0] ^ m_j[0],
4245 m_i[1] ^ m_j[1],
4246 m_i[2] ^ m_j[2],
4247 m_i[3] ^ m_j[3]
4248 ];
4249 }
4250 i *= 2;
4251 }
4252 m[0] = [0, 0, 0, 0];
4253 /* Note: We could avoid storing these by doing composition during multiply
4254 calculate top half using composition by speed is preferred. */
4255 for(i = half + 1; i < size; ++i) {
4256 var c = m[i ^ half];
4257 m[i] = [mid[0] ^ c[0], mid[1] ^ c[1], mid[2] ^ c[2], mid[3] ^ c[3]];
4258 }
4259 return m;
4260};
4261
4262
4263/** Utility functions */
4264
4265function transformIV(iv) {
4266 if(typeof iv === 'string') {
4267 // convert iv string into byte buffer
4268 iv = forge.util.createBuffer(iv);
4269 }
4270
4271 if(forge.util.isArray(iv) && iv.length > 4) {
4272 // convert iv byte array into byte buffer
4273 var tmp = iv;
4274 iv = forge.util.createBuffer();
4275 for(var i = 0; i < tmp.length; ++i) {
4276 iv.putByte(tmp[i]);
4277 }
4278 }
4279 if(!forge.util.isArray(iv)) {
4280 // convert iv byte buffer into 32-bit integer array
4281 iv = [iv.getInt32(), iv.getInt32(), iv.getInt32(), iv.getInt32()];
4282 }
4283
4284 return iv;
4285}
4286
4287function inc32(block) {
4288 // increment last 32 bits of block only
4289 block[block.length - 1] = (block[block.length - 1] + 1) & 0xFFFFFFFF;
4290}
4291
4292function from64To32(num) {
4293 // convert 64-bit number to two BE Int32s
4294 return [(num / 0x100000000) | 0, num & 0xFFFFFFFF];
4295}
4296
4297
4298} // end module implementation
4299
4300/* ########## Begin module wrapper ########## */
4301var name = 'cipherModes';
4302if(typeof define !== 'function') {
4303 // NodeJS -> AMD
4304 if(typeof module === 'object' && module.exports) {
4305 var nodeJS = true;
4306 define = function(ids, factory) {
4307 factory(require, module);
4308 };
4309 } else {
4310 // <script>
4311 if(typeof forge === 'undefined') {
4312 forge = {};
4313 }
4314 return initModule(forge);
4315 }
4316}
4317// AMD
4318var deps;
4319var defineFunc = function(require, module) {
4320 module.exports = function(forge) {
4321 var mods = deps.map(function(dep) {
4322 return require(dep);
4323 }).concat(initModule);
4324 // handle circular dependencies
4325 forge = forge || {};
4326 forge.defined = forge.defined || {};
4327 if(forge.defined[name]) {
4328 return forge[name];
4329 }
4330 forge.defined[name] = true;
4331 for(var i = 0; i < mods.length; ++i) {
4332 mods[i](forge);
4333 }
4334 return forge[name];
4335 };
4336};
4337var tmpDefine = define;
4338define = function(ids, factory) {
4339 deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
4340 if(nodeJS) {
4341 delete define;
4342 return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
4343 }
4344 define = tmpDefine;
4345 return define.apply(null, Array.prototype.slice.call(arguments, 0));
4346};
4347define(['require', 'module', './util'], function() {
4348 defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
4349});
4350})();
4351
4352/**
4353 * Advanced Encryption Standard (AES) implementation.
4354 *
4355 * This implementation is based on the public domain library 'jscrypto' which
4356 * was written by:
4357 *
4358 * Emily Stark (estark@stanford.edu)
4359 * Mike Hamburg (mhamburg@stanford.edu)
4360 * Dan Boneh (dabo@cs.stanford.edu)
4361 *
4362 * Parts of this code are based on the OpenSSL implementation of AES:
4363 * http://www.openssl.org
4364 *
4365 * @author Dave Longley
4366 *
4367 * Copyright (c) 2010-2014 Digital Bazaar, Inc.
4368 */
4369(function() {
4370/* ########## Begin module implementation ########## */
4371function initModule(forge) {
4372
4373/* AES API */
4374forge.aes = forge.aes || {};
4375
4376/**
4377 * Deprecated. Instead, use:
4378 *
4379 * var cipher = forge.cipher.createCipher('AES-<mode>', key);
4380 * cipher.start({iv: iv});
4381 *
4382 * Creates an AES cipher object to encrypt data using the given symmetric key.
4383 * The output will be stored in the 'output' member of the returned cipher.
4384 *
4385 * The key and iv may be given as a string of bytes, an array of bytes,
4386 * a byte buffer, or an array of 32-bit words.
4387 *
4388 * @param key the symmetric key to use.
4389 * @param iv the initialization vector to use.
4390 * @param output the buffer to write to, null to create one.
4391 * @param mode the cipher mode to use (default: 'CBC').
4392 *
4393 * @return the cipher.
4394 */
4395forge.aes.startEncrypting = function(key, iv, output, mode) {
4396 var cipher = _createCipher({
4397 key: key,
4398 output: output,
4399 decrypt: false,
4400 mode: mode
4401 });
4402 cipher.start(iv);
4403 return cipher;
4404};
4405
4406/**
4407 * Deprecated. Instead, use:
4408 *
4409 * var cipher = forge.cipher.createCipher('AES-<mode>', key);
4410 *
4411 * Creates an AES cipher object to encrypt data using the given symmetric key.
4412 *
4413 * The key may be given as a string of bytes, an array of bytes, a
4414 * byte buffer, or an array of 32-bit words.
4415 *
4416 * @param key the symmetric key to use.
4417 * @param mode the cipher mode to use (default: 'CBC').
4418 *
4419 * @return the cipher.
4420 */
4421forge.aes.createEncryptionCipher = function(key, mode) {
4422 return _createCipher({
4423 key: key,
4424 output: null,
4425 decrypt: false,
4426 mode: mode
4427 });
4428};
4429
4430/**
4431 * Deprecated. Instead, use:
4432 *
4433 * var decipher = forge.cipher.createDecipher('AES-<mode>', key);
4434 * decipher.start({iv: iv});
4435 *
4436 * Creates an AES cipher object to decrypt data using the given symmetric key.
4437 * The output will be stored in the 'output' member of the returned cipher.
4438 *
4439 * The key and iv may be given as a string of bytes, an array of bytes,
4440 * a byte buffer, or an array of 32-bit words.
4441 *
4442 * @param key the symmetric key to use.
4443 * @param iv the initialization vector to use.
4444 * @param output the buffer to write to, null to create one.
4445 * @param mode the cipher mode to use (default: 'CBC').
4446 *
4447 * @return the cipher.
4448 */
4449forge.aes.startDecrypting = function(key, iv, output, mode) {
4450 var cipher = _createCipher({
4451 key: key,
4452 output: output,
4453 decrypt: true,
4454 mode: mode
4455 });
4456 cipher.start(iv);
4457 return cipher;
4458};
4459
4460/**
4461 * Deprecated. Instead, use:
4462 *
4463 * var decipher = forge.cipher.createDecipher('AES-<mode>', key);
4464 *
4465 * Creates an AES cipher object to decrypt data using the given symmetric key.
4466 *
4467 * The key may be given as a string of bytes, an array of bytes, a
4468 * byte buffer, or an array of 32-bit words.
4469 *
4470 * @param key the symmetric key to use.
4471 * @param mode the cipher mode to use (default: 'CBC').
4472 *
4473 * @return the cipher.
4474 */
4475forge.aes.createDecryptionCipher = function(key, mode) {
4476 return _createCipher({
4477 key: key,
4478 output: null,
4479 decrypt: true,
4480 mode: mode
4481 });
4482};
4483
4484/**
4485 * Creates a new AES cipher algorithm object.
4486 *
4487 * @param name the name of the algorithm.
4488 * @param mode the mode factory function.
4489 *
4490 * @return the AES algorithm object.
4491 */
4492forge.aes.Algorithm = function(name, mode) {
4493 if(!init) {
4494 initialize();
4495 }
4496 var self = this;
4497 self.name = name;
4498 self.mode = new mode({
4499 blockSize: 16,
4500 cipher: {
4501 encrypt: function(inBlock, outBlock) {
4502 return _updateBlock(self._w, inBlock, outBlock, false);
4503 },
4504 decrypt: function(inBlock, outBlock) {
4505 return _updateBlock(self._w, inBlock, outBlock, true);
4506 }
4507 }
4508 });
4509 self._init = false;
4510};
4511
4512/**
4513 * Initializes this AES algorithm by expanding its key.
4514 *
4515 * @param options the options to use.
4516 * key the key to use with this algorithm.
4517 * decrypt true if the algorithm should be initialized for decryption,
4518 * false for encryption.
4519 */
4520forge.aes.Algorithm.prototype.initialize = function(options) {
4521 if(this._init) {
4522 return;
4523 }
4524
4525 var key = options.key;
4526 var tmp;
4527
4528 /* Note: The key may be a string of bytes, an array of bytes, a byte
4529 buffer, or an array of 32-bit integers. If the key is in bytes, then
4530 it must be 16, 24, or 32 bytes in length. If it is in 32-bit
4531 integers, it must be 4, 6, or 8 integers long. */
4532
4533 if(typeof key === 'string' &&
4534 (key.length === 16 || key.length === 24 || key.length === 32)) {
4535 // convert key string into byte buffer
4536 key = forge.util.createBuffer(key);
4537 } else if(forge.util.isArray(key) &&
4538 (key.length === 16 || key.length === 24 || key.length === 32)) {
4539 // convert key integer array into byte buffer
4540 tmp = key;
4541 key = forge.util.createBuffer();
4542 for(var i = 0; i < tmp.length; ++i) {
4543 key.putByte(tmp[i]);
4544 }
4545 }
4546
4547 // convert key byte buffer into 32-bit integer array
4548 if(!forge.util.isArray(key)) {
4549 tmp = key;
4550 key = [];
4551
4552 // key lengths of 16, 24, 32 bytes allowed
4553 var len = tmp.length();
4554 if(len === 16 || len === 24 || len === 32) {
4555 len = len >>> 2;
4556 for(var i = 0; i < len; ++i) {
4557 key.push(tmp.getInt32());
4558 }
4559 }
4560 }
4561
4562 // key must be an array of 32-bit integers by now
4563 if(!forge.util.isArray(key) ||
4564 !(key.length === 4 || key.length === 6 || key.length === 8)) {
4565 throw new Error('Invalid key parameter.');
4566 }
4567
4568 // encryption operation is always used for these modes
4569 var mode = this.mode.name;
4570 var encryptOp = (['CFB', 'OFB', 'CTR', 'GCM'].indexOf(mode) !== -1);
4571
4572 // do key expansion
4573 this._w = _expandKey(key, options.decrypt && !encryptOp);
4574 this._init = true;
4575};
4576
4577/**
4578 * Expands a key. Typically only used for testing.
4579 *
4580 * @param key the symmetric key to expand, as an array of 32-bit words.
4581 * @param decrypt true to expand for decryption, false for encryption.
4582 *
4583 * @return the expanded key.
4584 */
4585forge.aes._expandKey = function(key, decrypt) {
4586 if(!init) {
4587 initialize();
4588 }
4589 return _expandKey(key, decrypt);
4590};
4591
4592/**
4593 * Updates a single block. Typically only used for testing.
4594 *
4595 * @param w the expanded key to use.
4596 * @param input an array of block-size 32-bit words.
4597 * @param output an array of block-size 32-bit words.
4598 * @param decrypt true to decrypt, false to encrypt.
4599 */
4600forge.aes._updateBlock = _updateBlock;
4601
4602
4603/** Register AES algorithms **/
4604
4605registerAlgorithm('AES-ECB', forge.cipher.modes.ecb);
4606registerAlgorithm('AES-CBC', forge.cipher.modes.cbc);
4607registerAlgorithm('AES-CFB', forge.cipher.modes.cfb);
4608registerAlgorithm('AES-OFB', forge.cipher.modes.ofb);
4609registerAlgorithm('AES-CTR', forge.cipher.modes.ctr);
4610registerAlgorithm('AES-GCM', forge.cipher.modes.gcm);
4611
4612function registerAlgorithm(name, mode) {
4613 var factory = function() {
4614 return new forge.aes.Algorithm(name, mode);
4615 };
4616 forge.cipher.registerAlgorithm(name, factory);
4617}
4618
4619
4620/** AES implementation **/
4621
4622var init = false; // not yet initialized
4623var Nb = 4; // number of words comprising the state (AES = 4)
4624var sbox; // non-linear substitution table used in key expansion
4625var isbox; // inversion of sbox
4626var rcon; // round constant word array
4627var mix; // mix-columns table
4628var imix; // inverse mix-columns table
4629
4630/**
4631 * Performs initialization, ie: precomputes tables to optimize for speed.
4632 *
4633 * One way to understand how AES works is to imagine that 'addition' and
4634 * 'multiplication' are interfaces that require certain mathematical
4635 * properties to hold true (ie: they are associative) but they might have
4636 * different implementations and produce different kinds of results ...
4637 * provided that their mathematical properties remain true. AES defines
4638 * its own methods of addition and multiplication but keeps some important
4639 * properties the same, ie: associativity and distributivity. The
4640 * explanation below tries to shed some light on how AES defines addition
4641 * and multiplication of bytes and 32-bit words in order to perform its
4642 * encryption and decryption algorithms.
4643 *
4644 * The basics:
4645 *
4646 * The AES algorithm views bytes as binary representations of polynomials
4647 * that have either 1 or 0 as the coefficients. It defines the addition
4648 * or subtraction of two bytes as the XOR operation. It also defines the
4649 * multiplication of two bytes as a finite field referred to as GF(2^8)
4650 * (Note: 'GF' means "Galois Field" which is a field that contains a finite
4651 * number of elements so GF(2^8) has 256 elements).
4652 *
4653 * This means that any two bytes can be represented as binary polynomials;
4654 * when they multiplied together and modularly reduced by an irreducible
4655 * polynomial of the 8th degree, the results are the field GF(2^8). The
4656 * specific irreducible polynomial that AES uses in hexadecimal is 0x11b.
4657 * This multiplication is associative with 0x01 as the identity:
4658 *
4659 * (b * 0x01 = GF(b, 0x01) = b).
4660 *
4661 * The operation GF(b, 0x02) can be performed at the byte level by left
4662 * shifting b once and then XOR'ing it (to perform the modular reduction)
4663 * with 0x11b if b is >= 128. Repeated application of the multiplication
4664 * of 0x02 can be used to implement the multiplication of any two bytes.
4665 *
4666 * For instance, multiplying 0x57 and 0x13, denoted as GF(0x57, 0x13), can
4667 * be performed by factoring 0x13 into 0x01, 0x02, and 0x10. Then these
4668 * factors can each be multiplied by 0x57 and then added together. To do
4669 * the multiplication, values for 0x57 multiplied by each of these 3 factors
4670 * can be precomputed and stored in a table. To add them, the values from
4671 * the table are XOR'd together.
4672 *
4673 * AES also defines addition and multiplication of words, that is 4-byte
4674 * numbers represented as polynomials of 3 degrees where the coefficients
4675 * are the values of the bytes.
4676 *
4677 * The word [a0, a1, a2, a3] is a polynomial a3x^3 + a2x^2 + a1x + a0.
4678 *
4679 * Addition is performed by XOR'ing like powers of x. Multiplication
4680 * is performed in two steps, the first is an algebriac expansion as
4681 * you would do normally (where addition is XOR). But the result is
4682 * a polynomial larger than 3 degrees and thus it cannot fit in a word. So
4683 * next the result is modularly reduced by an AES-specific polynomial of
4684 * degree 4 which will always produce a polynomial of less than 4 degrees
4685 * such that it will fit in a word. In AES, this polynomial is x^4 + 1.
4686 *
4687 * The modular product of two polynomials 'a' and 'b' is thus:
4688 *
4689 * d(x) = d3x^3 + d2x^2 + d1x + d0
4690 * with
4691 * d0 = GF(a0, b0) ^ GF(a3, b1) ^ GF(a2, b2) ^ GF(a1, b3)
4692 * d1 = GF(a1, b0) ^ GF(a0, b1) ^ GF(a3, b2) ^ GF(a2, b3)
4693 * d2 = GF(a2, b0) ^ GF(a1, b1) ^ GF(a0, b2) ^ GF(a3, b3)
4694 * d3 = GF(a3, b0) ^ GF(a2, b1) ^ GF(a1, b2) ^ GF(a0, b3)
4695 *
4696 * As a matrix:
4697 *
4698 * [d0] = [a0 a3 a2 a1][b0]
4699 * [d1] [a1 a0 a3 a2][b1]
4700 * [d2] [a2 a1 a0 a3][b2]
4701 * [d3] [a3 a2 a1 a0][b3]
4702 *
4703 * Special polynomials defined by AES (0x02 == {02}):
4704 * a(x) = {03}x^3 + {01}x^2 + {01}x + {02}
4705 * a^-1(x) = {0b}x^3 + {0d}x^2 + {09}x + {0e}.
4706 *
4707 * These polynomials are used in the MixColumns() and InverseMixColumns()
4708 * operations, respectively, to cause each element in the state to affect
4709 * the output (referred to as diffusing).
4710 *
4711 * RotWord() uses: a0 = a1 = a2 = {00} and a3 = {01}, which is the
4712 * polynomial x3.
4713 *
4714 * The ShiftRows() method modifies the last 3 rows in the state (where
4715 * the state is 4 words with 4 bytes per word) by shifting bytes cyclically.
4716 * The 1st byte in the second row is moved to the end of the row. The 1st
4717 * and 2nd bytes in the third row are moved to the end of the row. The 1st,
4718 * 2nd, and 3rd bytes are moved in the fourth row.
4719 *
4720 * More details on how AES arithmetic works:
4721 *
4722 * In the polynomial representation of binary numbers, XOR performs addition
4723 * and subtraction and multiplication in GF(2^8) denoted as GF(a, b)
4724 * corresponds with the multiplication of polynomials modulo an irreducible
4725 * polynomial of degree 8. In other words, for AES, GF(a, b) will multiply
4726 * polynomial 'a' with polynomial 'b' and then do a modular reduction by
4727 * an AES-specific irreducible polynomial of degree 8.
4728 *
4729 * A polynomial is irreducible if its only divisors are one and itself. For
4730 * the AES algorithm, this irreducible polynomial is:
4731 *
4732 * m(x) = x^8 + x^4 + x^3 + x + 1,
4733 *
4734 * or {01}{1b} in hexadecimal notation, where each coefficient is a bit:
4735 * 100011011 = 283 = 0x11b.
4736 *
4737 * For example, GF(0x57, 0x83) = 0xc1 because
4738 *
4739 * 0x57 = 87 = 01010111 = x^6 + x^4 + x^2 + x + 1
4740 * 0x85 = 131 = 10000101 = x^7 + x + 1
4741 *
4742 * (x^6 + x^4 + x^2 + x + 1) * (x^7 + x + 1)
4743 * = x^13 + x^11 + x^9 + x^8 + x^7 +
4744 * x^7 + x^5 + x^3 + x^2 + x +
4745 * x^6 + x^4 + x^2 + x + 1
4746 * = x^13 + x^11 + x^9 + x^8 + x^6 + x^5 + x^4 + x^3 + 1 = y
4747 * y modulo (x^8 + x^4 + x^3 + x + 1)
4748 * = x^7 + x^6 + 1.
4749 *
4750 * The modular reduction by m(x) guarantees the result will be a binary
4751 * polynomial of less than degree 8, so that it can fit in a byte.
4752 *
4753 * The operation to multiply a binary polynomial b with x (the polynomial
4754 * x in binary representation is 00000010) is:
4755 *
4756 * b_7x^8 + b_6x^7 + b_5x^6 + b_4x^5 + b_3x^4 + b_2x^3 + b_1x^2 + b_0x^1
4757 *
4758 * To get GF(b, x) we must reduce that by m(x). If b_7 is 0 (that is the
4759 * most significant bit is 0 in b) then the result is already reduced. If
4760 * it is 1, then we can reduce it by subtracting m(x) via an XOR.
4761 *
4762 * It follows that multiplication by x (00000010 or 0x02) can be implemented
4763 * by performing a left shift followed by a conditional bitwise XOR with
4764 * 0x1b. This operation on bytes is denoted by xtime(). Multiplication by
4765 * higher powers of x can be implemented by repeated application of xtime().
4766 *
4767 * By adding intermediate results, multiplication by any constant can be
4768 * implemented. For instance:
4769 *
4770 * GF(0x57, 0x13) = 0xfe because:
4771 *
4772 * xtime(b) = (b & 128) ? (b << 1 ^ 0x11b) : (b << 1)
4773 *
4774 * Note: We XOR with 0x11b instead of 0x1b because in javascript our
4775 * datatype for b can be larger than 1 byte, so a left shift will not
4776 * automatically eliminate bits that overflow a byte ... by XOR'ing the
4777 * overflow bit with 1 (the extra one from 0x11b) we zero it out.
4778 *
4779 * GF(0x57, 0x02) = xtime(0x57) = 0xae
4780 * GF(0x57, 0x04) = xtime(0xae) = 0x47
4781 * GF(0x57, 0x08) = xtime(0x47) = 0x8e
4782 * GF(0x57, 0x10) = xtime(0x8e) = 0x07
4783 *
4784 * GF(0x57, 0x13) = GF(0x57, (0x01 ^ 0x02 ^ 0x10))
4785 *
4786 * And by the distributive property (since XOR is addition and GF() is
4787 * multiplication):
4788 *
4789 * = GF(0x57, 0x01) ^ GF(0x57, 0x02) ^ GF(0x57, 0x10)
4790 * = 0x57 ^ 0xae ^ 0x07
4791 * = 0xfe.
4792 */
4793function initialize() {
4794 init = true;
4795
4796 /* Populate the Rcon table. These are the values given by
4797 [x^(i-1),{00},{00},{00}] where x^(i-1) are powers of x (and x = 0x02)
4798 in the field of GF(2^8), where i starts at 1.
4799
4800 rcon[0] = [0x00, 0x00, 0x00, 0x00]
4801 rcon[1] = [0x01, 0x00, 0x00, 0x00] 2^(1-1) = 2^0 = 1
4802 rcon[2] = [0x02, 0x00, 0x00, 0x00] 2^(2-1) = 2^1 = 2
4803 ...
4804 rcon[9] = [0x1B, 0x00, 0x00, 0x00] 2^(9-1) = 2^8 = 0x1B
4805 rcon[10] = [0x36, 0x00, 0x00, 0x00] 2^(10-1) = 2^9 = 0x36
4806
4807 We only store the first byte because it is the only one used.
4808 */
4809 rcon = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36];
4810
4811 // compute xtime table which maps i onto GF(i, 0x02)
4812 var xtime = new Array(256);
4813 for(var i = 0; i < 128; ++i) {
4814 xtime[i] = i << 1;
4815 xtime[i + 128] = (i + 128) << 1 ^ 0x11B;
4816 }
4817
4818 // compute all other tables
4819 sbox = new Array(256);
4820 isbox = new Array(256);
4821 mix = new Array(4);
4822 imix = new Array(4);
4823 for(var i = 0; i < 4; ++i) {
4824 mix[i] = new Array(256);
4825 imix[i] = new Array(256);
4826 }
4827 var e = 0, ei = 0, e2, e4, e8, sx, sx2, me, ime;
4828 for(var i = 0; i < 256; ++i) {
4829 /* We need to generate the SubBytes() sbox and isbox tables so that
4830 we can perform byte substitutions. This requires us to traverse
4831 all of the elements in GF, find their multiplicative inverses,
4832 and apply to each the following affine transformation:
4833
4834 bi' = bi ^ b(i + 4) mod 8 ^ b(i + 5) mod 8 ^ b(i + 6) mod 8 ^
4835 b(i + 7) mod 8 ^ ci
4836 for 0 <= i < 8, where bi is the ith bit of the byte, and ci is the
4837 ith bit of a byte c with the value {63} or {01100011}.
4838
4839 It is possible to traverse every possible value in a Galois field
4840 using what is referred to as a 'generator'. There are many
4841 generators (128 out of 256): 3,5,6,9,11,82 to name a few. To fully
4842 traverse GF we iterate 255 times, multiplying by our generator
4843 each time.
4844
4845 On each iteration we can determine the multiplicative inverse for
4846 the current element.
4847
4848 Suppose there is an element in GF 'e'. For a given generator 'g',
4849 e = g^x. The multiplicative inverse of e is g^(255 - x). It turns
4850 out that if use the inverse of a generator as another generator
4851 it will produce all of the corresponding multiplicative inverses
4852 at the same time. For this reason, we choose 5 as our inverse
4853 generator because it only requires 2 multiplies and 1 add and its
4854 inverse, 82, requires relatively few operations as well.
4855
4856 In order to apply the affine transformation, the multiplicative
4857 inverse 'ei' of 'e' can be repeatedly XOR'd (4 times) with a
4858 bit-cycling of 'ei'. To do this 'ei' is first stored in 's' and
4859 'x'. Then 's' is left shifted and the high bit of 's' is made the
4860 low bit. The resulting value is stored in 's'. Then 'x' is XOR'd
4861 with 's' and stored in 'x'. On each subsequent iteration the same
4862 operation is performed. When 4 iterations are complete, 'x' is
4863 XOR'd with 'c' (0x63) and the transformed value is stored in 'x'.
4864 For example:
4865
4866 s = 01000001
4867 x = 01000001
4868
4869 iteration 1: s = 10000010, x ^= s
4870 iteration 2: s = 00000101, x ^= s
4871 iteration 3: s = 00001010, x ^= s
4872 iteration 4: s = 00010100, x ^= s
4873 x ^= 0x63
4874
4875 This can be done with a loop where s = (s << 1) | (s >> 7). However,
4876 it can also be done by using a single 16-bit (in this case 32-bit)
4877 number 'sx'. Since XOR is an associative operation, we can set 'sx'
4878 to 'ei' and then XOR it with 'sx' left-shifted 1,2,3, and 4 times.
4879 The most significant bits will flow into the high 8 bit positions
4880 and be correctly XOR'd with one another. All that remains will be
4881 to cycle the high 8 bits by XOR'ing them all with the lower 8 bits
4882 afterwards.
4883
4884 At the same time we're populating sbox and isbox we can precompute
4885 the multiplication we'll need to do to do MixColumns() later.
4886 */
4887
4888 // apply affine transformation
4889 sx = ei ^ (ei << 1) ^ (ei << 2) ^ (ei << 3) ^ (ei << 4);
4890 sx = (sx >> 8) ^ (sx & 255) ^ 0x63;
4891
4892 // update tables
4893 sbox[e] = sx;
4894 isbox[sx] = e;
4895
4896 /* Mixing columns is done using matrix multiplication. The columns
4897 that are to be mixed are each a single word in the current state.
4898 The state has Nb columns (4 columns). Therefore each column is a
4899 4 byte word. So to mix the columns in a single column 'c' where
4900 its rows are r0, r1, r2, and r3, we use the following matrix
4901 multiplication:
4902
4903 [2 3 1 1]*[r0,c]=[r'0,c]
4904 [1 2 3 1] [r1,c] [r'1,c]
4905 [1 1 2 3] [r2,c] [r'2,c]
4906 [3 1 1 2] [r3,c] [r'3,c]
4907
4908 r0, r1, r2, and r3 are each 1 byte of one of the words in the
4909 state (a column). To do matrix multiplication for each mixed
4910 column c' we multiply the corresponding row from the left matrix
4911 with the corresponding column from the right matrix. In total, we
4912 get 4 equations:
4913
4914 r0,c' = 2*r0,c + 3*r1,c + 1*r2,c + 1*r3,c
4915 r1,c' = 1*r0,c + 2*r1,c + 3*r2,c + 1*r3,c
4916 r2,c' = 1*r0,c + 1*r1,c + 2*r2,c + 3*r3,c
4917 r3,c' = 3*r0,c + 1*r1,c + 1*r2,c + 2*r3,c
4918
4919 As usual, the multiplication is as previously defined and the
4920 addition is XOR. In order to optimize mixing columns we can store
4921 the multiplication results in tables. If you think of the whole
4922 column as a word (it might help to visualize by mentally rotating
4923 the equations above by counterclockwise 90 degrees) then you can
4924 see that it would be useful to map the multiplications performed on
4925 each byte (r0, r1, r2, r3) onto a word as well. For instance, we
4926 could map 2*r0,1*r0,1*r0,3*r0 onto a word by storing 2*r0 in the
4927 highest 8 bits and 3*r0 in the lowest 8 bits (with the other two
4928 respectively in the middle). This means that a table can be
4929 constructed that uses r0 as an index to the word. We can do the
4930 same with r1, r2, and r3, creating a total of 4 tables.
4931
4932 To construct a full c', we can just look up each byte of c in
4933 their respective tables and XOR the results together.
4934
4935 Also, to build each table we only have to calculate the word
4936 for 2,1,1,3 for every byte ... which we can do on each iteration
4937 of this loop since we will iterate over every byte. After we have
4938 calculated 2,1,1,3 we can get the results for the other tables
4939 by cycling the byte at the end to the beginning. For instance
4940 we can take the result of table 2,1,1,3 and produce table 3,2,1,1
4941 by moving the right most byte to the left most position just like
4942 how you can imagine the 3 moved out of 2,1,1,3 and to the front
4943 to produce 3,2,1,1.
4944
4945 There is another optimization in that the same multiples of
4946 the current element we need in order to advance our generator
4947 to the next iteration can be reused in performing the 2,1,1,3
4948 calculation. We also calculate the inverse mix column tables,
4949 with e,9,d,b being the inverse of 2,1,1,3.
4950
4951 When we're done, and we need to actually mix columns, the first
4952 byte of each state word should be put through mix[0] (2,1,1,3),
4953 the second through mix[1] (3,2,1,1) and so forth. Then they should
4954 be XOR'd together to produce the fully mixed column.
4955 */
4956
4957 // calculate mix and imix table values
4958 sx2 = xtime[sx];
4959 e2 = xtime[e];
4960 e4 = xtime[e2];
4961 e8 = xtime[e4];
4962 me =
4963 (sx2 << 24) ^ // 2
4964 (sx << 16) ^ // 1
4965 (sx << 8) ^ // 1
4966 (sx ^ sx2); // 3
4967 ime =
4968 (e2 ^ e4 ^ e8) << 24 ^ // E (14)
4969 (e ^ e8) << 16 ^ // 9
4970 (e ^ e4 ^ e8) << 8 ^ // D (13)
4971 (e ^ e2 ^ e8); // B (11)
4972 // produce each of the mix tables by rotating the 2,1,1,3 value
4973 for(var n = 0; n < 4; ++n) {
4974 mix[n][e] = me;
4975 imix[n][sx] = ime;
4976 // cycle the right most byte to the left most position
4977 // ie: 2,1,1,3 becomes 3,2,1,1
4978 me = me << 24 | me >>> 8;
4979 ime = ime << 24 | ime >>> 8;
4980 }
4981
4982 // get next element and inverse
4983 if(e === 0) {
4984 // 1 is the inverse of 1
4985 e = ei = 1;
4986 } else {
4987 // e = 2e + 2*2*2*(10e)) = multiply e by 82 (chosen generator)
4988 // ei = ei + 2*2*ei = multiply ei by 5 (inverse generator)
4989 e = e2 ^ xtime[xtime[xtime[e2 ^ e8]]];
4990 ei ^= xtime[xtime[ei]];
4991 }
4992 }
4993}
4994
4995/**
4996 * Generates a key schedule using the AES key expansion algorithm.
4997 *
4998 * The AES algorithm takes the Cipher Key, K, and performs a Key Expansion
4999 * routine to generate a key schedule. The Key Expansion generates a total
5000 * of Nb*(Nr + 1) words: the algorithm requires an initial set of Nb words,
5001 * and each of the Nr rounds requires Nb words of key data. The resulting
5002 * key schedule consists of a linear array of 4-byte words, denoted [wi ],
5003 * with i in the range 0 ≤ i < Nb(Nr + 1).
5004 *
5005 * KeyExpansion(byte key[4*Nk], word w[Nb*(Nr+1)], Nk)
5006 * AES-128 (Nb=4, Nk=4, Nr=10)
5007 * AES-192 (Nb=4, Nk=6, Nr=12)
5008 * AES-256 (Nb=4, Nk=8, Nr=14)
5009 * Note: Nr=Nk+6.
5010 *
5011 * Nb is the number of columns (32-bit words) comprising the State (or
5012 * number of bytes in a block). For AES, Nb=4.
5013 *
5014 * @param key the key to schedule (as an array of 32-bit words).
5015 * @param decrypt true to modify the key schedule to decrypt, false not to.
5016 *
5017 * @return the generated key schedule.
5018 */
5019function _expandKey(key, decrypt) {
5020 // copy the key's words to initialize the key schedule
5021 var w = key.slice(0);
5022
5023 /* RotWord() will rotate a word, moving the first byte to the last
5024 byte's position (shifting the other bytes left).
5025
5026 We will be getting the value of Rcon at i / Nk. 'i' will iterate
5027 from Nk to (Nb * Nr+1). Nk = 4 (4 byte key), Nb = 4 (4 words in
5028 a block), Nr = Nk + 6 (10). Therefore 'i' will iterate from
5029 4 to 44 (exclusive). Each time we iterate 4 times, i / Nk will
5030 increase by 1. We use a counter iNk to keep track of this.
5031 */
5032
5033 // go through the rounds expanding the key
5034 var temp, iNk = 1;
5035 var Nk = w.length;
5036 var Nr1 = Nk + 6 + 1;
5037 var end = Nb * Nr1;
5038 for(var i = Nk; i < end; ++i) {
5039 temp = w[i - 1];
5040 if(i % Nk === 0) {
5041 // temp = SubWord(RotWord(temp)) ^ Rcon[i / Nk]
5042 temp =
5043 sbox[temp >>> 16 & 255] << 24 ^
5044 sbox[temp >>> 8 & 255] << 16 ^
5045 sbox[temp & 255] << 8 ^
5046 sbox[temp >>> 24] ^ (rcon[iNk] << 24);
5047 iNk++;
5048 } else if(Nk > 6 && (i % Nk === 4)) {
5049 // temp = SubWord(temp)
5050 temp =
5051 sbox[temp >>> 24] << 24 ^
5052 sbox[temp >>> 16 & 255] << 16 ^
5053 sbox[temp >>> 8 & 255] << 8 ^
5054 sbox[temp & 255];
5055 }
5056 w[i] = w[i - Nk] ^ temp;
5057 }
5058
5059 /* When we are updating a cipher block we always use the code path for
5060 encryption whether we are decrypting or not (to shorten code and
5061 simplify the generation of look up tables). However, because there
5062 are differences in the decryption algorithm, other than just swapping
5063 in different look up tables, we must transform our key schedule to
5064 account for these changes:
5065
5066 1. The decryption algorithm gets its key rounds in reverse order.
5067 2. The decryption algorithm adds the round key before mixing columns
5068 instead of afterwards.
5069
5070 We don't need to modify our key schedule to handle the first case,
5071 we can just traverse the key schedule in reverse order when decrypting.
5072
5073 The second case requires a little work.
5074
5075 The tables we built for performing rounds will take an input and then
5076 perform SubBytes() and MixColumns() or, for the decrypt version,
5077 InvSubBytes() and InvMixColumns(). But the decrypt algorithm requires
5078 us to AddRoundKey() before InvMixColumns(). This means we'll need to
5079 apply some transformations to the round key to inverse-mix its columns
5080 so they'll be correct for moving AddRoundKey() to after the state has
5081 had its columns inverse-mixed.
5082
5083 To inverse-mix the columns of the state when we're decrypting we use a
5084 lookup table that will apply InvSubBytes() and InvMixColumns() at the
5085 same time. However, the round key's bytes are not inverse-substituted
5086 in the decryption algorithm. To get around this problem, we can first
5087 substitute the bytes in the round key so that when we apply the
5088 transformation via the InvSubBytes()+InvMixColumns() table, it will
5089 undo our substitution leaving us with the original value that we
5090 want -- and then inverse-mix that value.
5091
5092 This change will correctly alter our key schedule so that we can XOR
5093 each round key with our already transformed decryption state. This
5094 allows us to use the same code path as the encryption algorithm.
5095
5096 We make one more change to the decryption key. Since the decryption
5097 algorithm runs in reverse from the encryption algorithm, we reverse
5098 the order of the round keys to avoid having to iterate over the key
5099 schedule backwards when running the encryption algorithm later in
5100 decryption mode. In addition to reversing the order of the round keys,
5101 we also swap each round key's 2nd and 4th rows. See the comments
5102 section where rounds are performed for more details about why this is
5103 done. These changes are done inline with the other substitution
5104 described above.
5105 */
5106 if(decrypt) {
5107 var tmp;
5108 var m0 = imix[0];
5109 var m1 = imix[1];
5110 var m2 = imix[2];
5111 var m3 = imix[3];
5112 var wnew = w.slice(0);
5113 end = w.length;
5114 for(var i = 0, wi = end - Nb; i < end; i += Nb, wi -= Nb) {
5115 // do not sub the first or last round key (round keys are Nb
5116 // words) as no column mixing is performed before they are added,
5117 // but do change the key order
5118 if(i === 0 || i === (end - Nb)) {
5119 wnew[i] = w[wi];
5120 wnew[i + 1] = w[wi + 3];
5121 wnew[i + 2] = w[wi + 2];
5122 wnew[i + 3] = w[wi + 1];
5123 } else {
5124 // substitute each round key byte because the inverse-mix
5125 // table will inverse-substitute it (effectively cancel the
5126 // substitution because round key bytes aren't sub'd in
5127 // decryption mode) and swap indexes 3 and 1
5128 for(var n = 0; n < Nb; ++n) {
5129 tmp = w[wi + n];
5130 wnew[i + (3&-n)] =
5131 m0[sbox[tmp >>> 24]] ^
5132 m1[sbox[tmp >>> 16 & 255]] ^
5133 m2[sbox[tmp >>> 8 & 255]] ^
5134 m3[sbox[tmp & 255]];
5135 }
5136 }
5137 }
5138 w = wnew;
5139 }
5140
5141 return w;
5142}
5143
5144/**
5145 * Updates a single block (16 bytes) using AES. The update will either
5146 * encrypt or decrypt the block.
5147 *
5148 * @param w the key schedule.
5149 * @param input the input block (an array of 32-bit words).
5150 * @param output the updated output block.
5151 * @param decrypt true to decrypt the block, false to encrypt it.
5152 */
5153function _updateBlock(w, input, output, decrypt) {
5154 /*
5155 Cipher(byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)])
5156 begin
5157 byte state[4,Nb]
5158 state = in
5159 AddRoundKey(state, w[0, Nb-1])
5160 for round = 1 step 1 to Nr–1
5161 SubBytes(state)
5162 ShiftRows(state)
5163 MixColumns(state)
5164 AddRoundKey(state, w[round*Nb, (round+1)*Nb-1])
5165 end for
5166 SubBytes(state)
5167 ShiftRows(state)
5168 AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1])
5169 out = state
5170 end
5171
5172 InvCipher(byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)])
5173 begin
5174 byte state[4,Nb]
5175 state = in
5176 AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1])
5177 for round = Nr-1 step -1 downto 1
5178 InvShiftRows(state)
5179 InvSubBytes(state)
5180 AddRoundKey(state, w[round*Nb, (round+1)*Nb-1])
5181 InvMixColumns(state)
5182 end for
5183 InvShiftRows(state)
5184 InvSubBytes(state)
5185 AddRoundKey(state, w[0, Nb-1])
5186 out = state
5187 end
5188 */
5189
5190 // Encrypt: AddRoundKey(state, w[0, Nb-1])
5191 // Decrypt: AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1])
5192 var Nr = w.length / 4 - 1;
5193 var m0, m1, m2, m3, sub;
5194 if(decrypt) {
5195 m0 = imix[0];
5196 m1 = imix[1];
5197 m2 = imix[2];
5198 m3 = imix[3];
5199 sub = isbox;
5200 } else {
5201 m0 = mix[0];
5202 m1 = mix[1];
5203 m2 = mix[2];
5204 m3 = mix[3];
5205 sub = sbox;
5206 }
5207 var a, b, c, d, a2, b2, c2;
5208 a = input[0] ^ w[0];
5209 b = input[decrypt ? 3 : 1] ^ w[1];
5210 c = input[2] ^ w[2];
5211 d = input[decrypt ? 1 : 3] ^ w[3];
5212 var i = 3;
5213
5214 /* In order to share code we follow the encryption algorithm when both
5215 encrypting and decrypting. To account for the changes required in the
5216 decryption algorithm, we use different lookup tables when decrypting
5217 and use a modified key schedule to account for the difference in the
5218 order of transformations applied when performing rounds. We also get
5219 key rounds in reverse order (relative to encryption). */
5220 for(var round = 1; round < Nr; ++round) {
5221 /* As described above, we'll be using table lookups to perform the
5222 column mixing. Each column is stored as a word in the state (the
5223 array 'input' has one column as a word at each index). In order to
5224 mix a column, we perform these transformations on each row in c,
5225 which is 1 byte in each word. The new column for c0 is c'0:
5226
5227 m0 m1 m2 m3
5228 r0,c'0 = 2*r0,c0 + 3*r1,c0 + 1*r2,c0 + 1*r3,c0
5229 r1,c'0 = 1*r0,c0 + 2*r1,c0 + 3*r2,c0 + 1*r3,c0
5230 r2,c'0 = 1*r0,c0 + 1*r1,c0 + 2*r2,c0 + 3*r3,c0
5231 r3,c'0 = 3*r0,c0 + 1*r1,c0 + 1*r2,c0 + 2*r3,c0
5232
5233 So using mix tables where c0 is a word with r0 being its upper
5234 8 bits and r3 being its lower 8 bits:
5235
5236 m0[c0 >> 24] will yield this word: [2*r0,1*r0,1*r0,3*r0]
5237 ...
5238 m3[c0 & 255] will yield this word: [1*r3,1*r3,3*r3,2*r3]
5239
5240 Therefore to mix the columns in each word in the state we
5241 do the following (& 255 omitted for brevity):
5242 c'0,r0 = m0[c0 >> 24] ^ m1[c1 >> 16] ^ m2[c2 >> 8] ^ m3[c3]
5243 c'0,r1 = m0[c0 >> 24] ^ m1[c1 >> 16] ^ m2[c2 >> 8] ^ m3[c3]
5244 c'0,r2 = m0[c0 >> 24] ^ m1[c1 >> 16] ^ m2[c2 >> 8] ^ m3[c3]
5245 c'0,r3 = m0[c0 >> 24] ^ m1[c1 >> 16] ^ m2[c2 >> 8] ^ m3[c3]
5246
5247 However, before mixing, the algorithm requires us to perform
5248 ShiftRows(). The ShiftRows() transformation cyclically shifts the
5249 last 3 rows of the state over different offsets. The first row
5250 (r = 0) is not shifted.
5251
5252 s'_r,c = s_r,(c + shift(r, Nb) mod Nb
5253 for 0 < r < 4 and 0 <= c < Nb and
5254 shift(1, 4) = 1
5255 shift(2, 4) = 2
5256 shift(3, 4) = 3.
5257
5258 This causes the first byte in r = 1 to be moved to the end of
5259 the row, the first 2 bytes in r = 2 to be moved to the end of
5260 the row, the first 3 bytes in r = 3 to be moved to the end of
5261 the row:
5262
5263 r1: [c0 c1 c2 c3] => [c1 c2 c3 c0]
5264 r2: [c0 c1 c2 c3] [c2 c3 c0 c1]
5265 r3: [c0 c1 c2 c3] [c3 c0 c1 c2]
5266
5267 We can make these substitutions inline with our column mixing to
5268 generate an updated set of equations to produce each word in the
5269 state (note the columns have changed positions):
5270
5271 c0 c1 c2 c3 => c0 c1 c2 c3
5272 c0 c1 c2 c3 c1 c2 c3 c0 (cycled 1 byte)
5273 c0 c1 c2 c3 c2 c3 c0 c1 (cycled 2 bytes)
5274 c0 c1 c2 c3 c3 c0 c1 c2 (cycled 3 bytes)
5275
5276 Therefore:
5277
5278 c'0 = 2*r0,c0 + 3*r1,c1 + 1*r2,c2 + 1*r3,c3
5279 c'0 = 1*r0,c0 + 2*r1,c1 + 3*r2,c2 + 1*r3,c3
5280 c'0 = 1*r0,c0 + 1*r1,c1 + 2*r2,c2 + 3*r3,c3
5281 c'0 = 3*r0,c0 + 1*r1,c1 + 1*r2,c2 + 2*r3,c3
5282
5283 c'1 = 2*r0,c1 + 3*r1,c2 + 1*r2,c3 + 1*r3,c0
5284 c'1 = 1*r0,c1 + 2*r1,c2 + 3*r2,c3 + 1*r3,c0
5285 c'1 = 1*r0,c1 + 1*r1,c2 + 2*r2,c3 + 3*r3,c0
5286 c'1 = 3*r0,c1 + 1*r1,c2 + 1*r2,c3 + 2*r3,c0
5287
5288 ... and so forth for c'2 and c'3. The important distinction is
5289 that the columns are cycling, with c0 being used with the m0
5290 map when calculating c0, but c1 being used with the m0 map when
5291 calculating c1 ... and so forth.
5292
5293 When performing the inverse we transform the mirror image and
5294 skip the bottom row, instead of the top one, and move upwards:
5295
5296 c3 c2 c1 c0 => c0 c3 c2 c1 (cycled 3 bytes) *same as encryption
5297 c3 c2 c1 c0 c1 c0 c3 c2 (cycled 2 bytes)
5298 c3 c2 c1 c0 c2 c1 c0 c3 (cycled 1 byte) *same as encryption
5299 c3 c2 c1 c0 c3 c2 c1 c0
5300
5301 If you compare the resulting matrices for ShiftRows()+MixColumns()
5302 and for InvShiftRows()+InvMixColumns() the 2nd and 4th columns are
5303 different (in encrypt mode vs. decrypt mode). So in order to use
5304 the same code to handle both encryption and decryption, we will
5305 need to do some mapping.
5306
5307 If in encryption mode we let a=c0, b=c1, c=c2, d=c3, and r<N> be
5308 a row number in the state, then the resulting matrix in encryption
5309 mode for applying the above transformations would be:
5310
5311 r1: a b c d
5312 r2: b c d a
5313 r3: c d a b
5314 r4: d a b c
5315
5316 If we did the same in decryption mode we would get:
5317
5318 r1: a d c b
5319 r2: b a d c
5320 r3: c b a d
5321 r4: d c b a
5322
5323 If instead we swap d and b (set b=c3 and d=c1), then we get:
5324
5325 r1: a b c d
5326 r2: d a b c
5327 r3: c d a b
5328 r4: b c d a
5329
5330 Now the 1st and 3rd rows are the same as the encryption matrix. All
5331 we need to do then to make the mapping exactly the same is to swap
5332 the 2nd and 4th rows when in decryption mode. To do this without
5333 having to do it on each iteration, we swapped the 2nd and 4th rows
5334 in the decryption key schedule. We also have to do the swap above
5335 when we first pull in the input and when we set the final output. */
5336 a2 =
5337 m0[a >>> 24] ^
5338 m1[b >>> 16 & 255] ^
5339 m2[c >>> 8 & 255] ^
5340 m3[d & 255] ^ w[++i];
5341 b2 =
5342 m0[b >>> 24] ^
5343 m1[c >>> 16 & 255] ^
5344 m2[d >>> 8 & 255] ^
5345 m3[a & 255] ^ w[++i];
5346 c2 =
5347 m0[c >>> 24] ^
5348 m1[d >>> 16 & 255] ^
5349 m2[a >>> 8 & 255] ^
5350 m3[b & 255] ^ w[++i];
5351 d =
5352 m0[d >>> 24] ^
5353 m1[a >>> 16 & 255] ^
5354 m2[b >>> 8 & 255] ^
5355 m3[c & 255] ^ w[++i];
5356 a = a2;
5357 b = b2;
5358 c = c2;
5359 }
5360
5361 /*
5362 Encrypt:
5363 SubBytes(state)
5364 ShiftRows(state)
5365 AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1])
5366
5367 Decrypt:
5368 InvShiftRows(state)
5369 InvSubBytes(state)
5370 AddRoundKey(state, w[0, Nb-1])
5371 */
5372 // Note: rows are shifted inline
5373 output[0] =
5374 (sub[a >>> 24] << 24) ^
5375 (sub[b >>> 16 & 255] << 16) ^
5376 (sub[c >>> 8 & 255] << 8) ^
5377 (sub[d & 255]) ^ w[++i];
5378 output[decrypt ? 3 : 1] =
5379 (sub[b >>> 24] << 24) ^
5380 (sub[c >>> 16 & 255] << 16) ^
5381 (sub[d >>> 8 & 255] << 8) ^
5382 (sub[a & 255]) ^ w[++i];
5383 output[2] =
5384 (sub[c >>> 24] << 24) ^
5385 (sub[d >>> 16 & 255] << 16) ^
5386 (sub[a >>> 8 & 255] << 8) ^
5387 (sub[b & 255]) ^ w[++i];
5388 output[decrypt ? 1 : 3] =
5389 (sub[d >>> 24] << 24) ^
5390 (sub[a >>> 16 & 255] << 16) ^
5391 (sub[b >>> 8 & 255] << 8) ^
5392 (sub[c & 255]) ^ w[++i];
5393}
5394
5395/**
5396 * Deprecated. Instead, use:
5397 *
5398 * forge.cipher.createCipher('AES-<mode>', key);
5399 * forge.cipher.createDecipher('AES-<mode>', key);
5400 *
5401 * Creates a deprecated AES cipher object. This object's mode will default to
5402 * CBC (cipher-block-chaining).
5403 *
5404 * The key and iv may be given as a string of bytes, an array of bytes, a
5405 * byte buffer, or an array of 32-bit words.
5406 *
5407 * @param options the options to use.
5408 * key the symmetric key to use.
5409 * output the buffer to write to.
5410 * decrypt true for decryption, false for encryption.
5411 * mode the cipher mode to use (default: 'CBC').
5412 *
5413 * @return the cipher.
5414 */
5415function _createCipher(options) {
5416 options = options || {};
5417 var mode = (options.mode || 'CBC').toUpperCase();
5418 var algorithm = 'AES-' + mode;
5419
5420 var cipher;
5421 if(options.decrypt) {
5422 cipher = forge.cipher.createDecipher(algorithm, options.key);
5423 } else {
5424 cipher = forge.cipher.createCipher(algorithm, options.key);
5425 }
5426
5427 // backwards compatible start API
5428 var start = cipher.start;
5429 cipher.start = function(iv, options) {
5430 // backwards compatibility: support second arg as output buffer
5431 var output = null;
5432 if(options instanceof forge.util.ByteBuffer) {
5433 output = options;
5434 options = {};
5435 }
5436 options = options || {};
5437 options.output = output;
5438 options.iv = iv;
5439 start.call(cipher, options);
5440 };
5441
5442 return cipher;
5443}
5444
5445} // end module implementation
5446
5447/* ########## Begin module wrapper ########## */
5448var name = 'aes';
5449if(typeof define !== 'function') {
5450 // NodeJS -> AMD
5451 if(typeof module === 'object' && module.exports) {
5452 var nodeJS = true;
5453 define = function(ids, factory) {
5454 factory(require, module);
5455 };
5456 } else {
5457 // <script>
5458 if(typeof forge === 'undefined') {
5459 forge = {};
5460 }
5461 return initModule(forge);
5462 }
5463}
5464// AMD
5465var deps;
5466var defineFunc = function(require, module) {
5467 module.exports = function(forge) {
5468 var mods = deps.map(function(dep) {
5469 return require(dep);
5470 }).concat(initModule);
5471 // handle circular dependencies
5472 forge = forge || {};
5473 forge.defined = forge.defined || {};
5474 if(forge.defined[name]) {
5475 return forge[name];
5476 }
5477 forge.defined[name] = true;
5478 for(var i = 0; i < mods.length; ++i) {
5479 mods[i](forge);
5480 }
5481 return forge[name];
5482 };
5483};
5484var tmpDefine = define;
5485define = function(ids, factory) {
5486 deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
5487 if(nodeJS) {
5488 delete define;
5489 return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
5490 }
5491 define = tmpDefine;
5492 return define.apply(null, Array.prototype.slice.call(arguments, 0));
5493};
5494define(
5495 ['require', 'module', './cipher', './cipherModes', './util'], function() {
5496 defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
5497});
5498})();
5499
5500/**
5501 * Object IDs for ASN.1.
5502 *
5503 * @author Dave Longley
5504 *
5505 * Copyright (c) 2010-2013 Digital Bazaar, Inc.
5506 */
5507(function() {
5508/* ########## Begin module implementation ########## */
5509function initModule(forge) {
5510
5511forge.pki = forge.pki || {};
5512var oids = forge.pki.oids = forge.oids = forge.oids || {};
5513
5514// algorithm OIDs
5515oids['1.2.840.113549.1.1.1'] = 'rsaEncryption';
5516oids['rsaEncryption'] = '1.2.840.113549.1.1.1';
5517// Note: md2 & md4 not implemented
5518//oids['1.2.840.113549.1.1.2'] = 'md2WithRSAEncryption';
5519//oids['md2WithRSAEncryption'] = '1.2.840.113549.1.1.2';
5520//oids['1.2.840.113549.1.1.3'] = 'md4WithRSAEncryption';
5521//oids['md4WithRSAEncryption'] = '1.2.840.113549.1.1.3';
5522oids['1.2.840.113549.1.1.4'] = 'md5WithRSAEncryption';
5523oids['md5WithRSAEncryption'] = '1.2.840.113549.1.1.4';
5524oids['1.2.840.113549.1.1.5'] = 'sha1WithRSAEncryption';
5525oids['sha1WithRSAEncryption'] = '1.2.840.113549.1.1.5';
5526oids['1.2.840.113549.1.1.7'] = 'RSAES-OAEP';
5527oids['RSAES-OAEP'] = '1.2.840.113549.1.1.7';
5528oids['1.2.840.113549.1.1.8'] = 'mgf1';
5529oids['mgf1'] = '1.2.840.113549.1.1.8';
5530oids['1.2.840.113549.1.1.9'] = 'pSpecified';
5531oids['pSpecified'] = '1.2.840.113549.1.1.9';
5532oids['1.2.840.113549.1.1.10'] = 'RSASSA-PSS';
5533oids['RSASSA-PSS'] = '1.2.840.113549.1.1.10';
5534oids['1.2.840.113549.1.1.11'] = 'sha256WithRSAEncryption';
5535oids['sha256WithRSAEncryption'] = '1.2.840.113549.1.1.11';
5536oids['1.2.840.113549.1.1.12'] = 'sha384WithRSAEncryption';
5537oids['sha384WithRSAEncryption'] = '1.2.840.113549.1.1.12';
5538oids['1.2.840.113549.1.1.13'] = 'sha512WithRSAEncryption';
5539oids['sha512WithRSAEncryption'] = '1.2.840.113549.1.1.13';
5540
5541oids['1.3.14.3.2.7'] = 'desCBC';
5542oids['desCBC'] = '1.3.14.3.2.7';
5543
5544oids['1.3.14.3.2.26'] = 'sha1';
5545oids['sha1'] = '1.3.14.3.2.26';
5546oids['2.16.840.1.101.3.4.2.1'] = 'sha256';
5547oids['sha256'] = '2.16.840.1.101.3.4.2.1';
5548oids['2.16.840.1.101.3.4.2.2'] = 'sha384';
5549oids['sha384'] = '2.16.840.1.101.3.4.2.2';
5550oids['2.16.840.1.101.3.4.2.3'] = 'sha512';
5551oids['sha512'] = '2.16.840.1.101.3.4.2.3';
5552oids['1.2.840.113549.2.5'] = 'md5';
5553oids['md5'] = '1.2.840.113549.2.5';
5554
5555// pkcs#7 content types
5556oids['1.2.840.113549.1.7.1'] = 'data';
5557oids['data'] = '1.2.840.113549.1.7.1';
5558oids['1.2.840.113549.1.7.2'] = 'signedData';
5559oids['signedData'] = '1.2.840.113549.1.7.2';
5560oids['1.2.840.113549.1.7.3'] = 'envelopedData';
5561oids['envelopedData'] = '1.2.840.113549.1.7.3';
5562oids['1.2.840.113549.1.7.4'] = 'signedAndEnvelopedData';
5563oids['signedAndEnvelopedData'] = '1.2.840.113549.1.7.4';
5564oids['1.2.840.113549.1.7.5'] = 'digestedData';
5565oids['digestedData'] = '1.2.840.113549.1.7.5';
5566oids['1.2.840.113549.1.7.6'] = 'encryptedData';
5567oids['encryptedData'] = '1.2.840.113549.1.7.6';
5568
5569// pkcs#9 oids
5570oids['1.2.840.113549.1.9.1'] = 'emailAddress';
5571oids['emailAddress'] = '1.2.840.113549.1.9.1';
5572oids['1.2.840.113549.1.9.2'] = 'unstructuredName';
5573oids['unstructuredName'] = '1.2.840.113549.1.9.2';
5574oids['1.2.840.113549.1.9.3'] = 'contentType';
5575oids['contentType'] = '1.2.840.113549.1.9.3';
5576oids['1.2.840.113549.1.9.4'] = 'messageDigest';
5577oids['messageDigest'] = '1.2.840.113549.1.9.4';
5578oids['1.2.840.113549.1.9.5'] = 'signingTime';
5579oids['signingTime'] = '1.2.840.113549.1.9.5';
5580oids['1.2.840.113549.1.9.6'] = 'counterSignature';
5581oids['counterSignature'] = '1.2.840.113549.1.9.6';
5582oids['1.2.840.113549.1.9.7'] = 'challengePassword';
5583oids['challengePassword'] = '1.2.840.113549.1.9.7';
5584oids['1.2.840.113549.1.9.8'] = 'unstructuredAddress';
5585oids['unstructuredAddress'] = '1.2.840.113549.1.9.8';
5586oids['1.2.840.113549.1.9.14'] = 'extensionRequest';
5587oids['extensionRequest'] = '1.2.840.113549.1.9.14';
5588
5589oids['1.2.840.113549.1.9.20'] = 'friendlyName';
5590oids['friendlyName'] = '1.2.840.113549.1.9.20';
5591oids['1.2.840.113549.1.9.21'] = 'localKeyId';
5592oids['localKeyId'] = '1.2.840.113549.1.9.21';
5593oids['1.2.840.113549.1.9.22.1'] = 'x509Certificate';
5594oids['x509Certificate'] = '1.2.840.113549.1.9.22.1';
5595
5596// pkcs#12 safe bags
5597oids['1.2.840.113549.1.12.10.1.1'] = 'keyBag';
5598oids['keyBag'] = '1.2.840.113549.1.12.10.1.1';
5599oids['1.2.840.113549.1.12.10.1.2'] = 'pkcs8ShroudedKeyBag';
5600oids['pkcs8ShroudedKeyBag'] = '1.2.840.113549.1.12.10.1.2';
5601oids['1.2.840.113549.1.12.10.1.3'] = 'certBag';
5602oids['certBag'] = '1.2.840.113549.1.12.10.1.3';
5603oids['1.2.840.113549.1.12.10.1.4'] = 'crlBag';
5604oids['crlBag'] = '1.2.840.113549.1.12.10.1.4';
5605oids['1.2.840.113549.1.12.10.1.5'] = 'secretBag';
5606oids['secretBag'] = '1.2.840.113549.1.12.10.1.5';
5607oids['1.2.840.113549.1.12.10.1.6'] = 'safeContentsBag';
5608oids['safeContentsBag'] = '1.2.840.113549.1.12.10.1.6';
5609
5610// password-based-encryption for pkcs#12
5611oids['1.2.840.113549.1.5.13'] = 'pkcs5PBES2';
5612oids['pkcs5PBES2'] = '1.2.840.113549.1.5.13';
5613oids['1.2.840.113549.1.5.12'] = 'pkcs5PBKDF2';
5614oids['pkcs5PBKDF2'] = '1.2.840.113549.1.5.12';
5615
5616oids['1.2.840.113549.1.12.1.1'] = 'pbeWithSHAAnd128BitRC4';
5617oids['pbeWithSHAAnd128BitRC4'] = '1.2.840.113549.1.12.1.1';
5618oids['1.2.840.113549.1.12.1.2'] = 'pbeWithSHAAnd40BitRC4';
5619oids['pbeWithSHAAnd40BitRC4'] = '1.2.840.113549.1.12.1.2';
5620oids['1.2.840.113549.1.12.1.3'] = 'pbeWithSHAAnd3-KeyTripleDES-CBC';
5621oids['pbeWithSHAAnd3-KeyTripleDES-CBC'] = '1.2.840.113549.1.12.1.3';
5622oids['1.2.840.113549.1.12.1.4'] = 'pbeWithSHAAnd2-KeyTripleDES-CBC';
5623oids['pbeWithSHAAnd2-KeyTripleDES-CBC'] = '1.2.840.113549.1.12.1.4';
5624oids['1.2.840.113549.1.12.1.5'] = 'pbeWithSHAAnd128BitRC2-CBC';
5625oids['pbeWithSHAAnd128BitRC2-CBC'] = '1.2.840.113549.1.12.1.5';
5626oids['1.2.840.113549.1.12.1.6'] = 'pbewithSHAAnd40BitRC2-CBC';
5627oids['pbewithSHAAnd40BitRC2-CBC'] = '1.2.840.113549.1.12.1.6';
5628
5629// hmac OIDs
5630oids['1.2.840.113549.2.7'] = 'hmacWithSHA1';
5631oids['hmacWithSHA1'] = '1.2.840.113549.2.7';
5632oids['1.2.840.113549.2.8'] = 'hmacWithSHA224';
5633oids['hmacWithSHA224'] = '1.2.840.113549.2.8';
5634oids['1.2.840.113549.2.9'] = 'hmacWithSHA256';
5635oids['hmacWithSHA256'] = '1.2.840.113549.2.9';
5636oids['1.2.840.113549.2.10'] = 'hmacWithSHA384';
5637oids['hmacWithSHA384'] = '1.2.840.113549.2.10';
5638oids['1.2.840.113549.2.11'] = 'hmacWithSHA512';
5639oids['hmacWithSHA512'] = '1.2.840.113549.2.11';
5640
5641// symmetric key algorithm oids
5642oids['1.2.840.113549.3.7'] = 'des-EDE3-CBC';
5643oids['des-EDE3-CBC'] = '1.2.840.113549.3.7';
5644oids['2.16.840.1.101.3.4.1.2'] = 'aes128-CBC';
5645oids['aes128-CBC'] = '2.16.840.1.101.3.4.1.2';
5646oids['2.16.840.1.101.3.4.1.22'] = 'aes192-CBC';
5647oids['aes192-CBC'] = '2.16.840.1.101.3.4.1.22';
5648oids['2.16.840.1.101.3.4.1.42'] = 'aes256-CBC';
5649oids['aes256-CBC'] = '2.16.840.1.101.3.4.1.42';
5650
5651// certificate issuer/subject OIDs
5652oids['2.5.4.3'] = 'commonName';
5653oids['commonName'] = '2.5.4.3';
5654oids['2.5.4.5'] = 'serialName';
5655oids['serialName'] = '2.5.4.5';
5656oids['2.5.4.6'] = 'countryName';
5657oids['countryName'] = '2.5.4.6';
5658oids['2.5.4.7'] = 'localityName';
5659oids['localityName'] = '2.5.4.7';
5660oids['2.5.4.8'] = 'stateOrProvinceName';
5661oids['stateOrProvinceName'] = '2.5.4.8';
5662oids['2.5.4.10'] = 'organizationName';
5663oids['organizationName'] = '2.5.4.10';
5664oids['2.5.4.11'] = 'organizationalUnitName';
5665oids['organizationalUnitName'] = '2.5.4.11';
5666
5667// X.509 extension OIDs
5668oids['2.16.840.1.113730.1.1'] = 'nsCertType';
5669oids['nsCertType'] = '2.16.840.1.113730.1.1';
5670oids['2.5.29.1'] = 'authorityKeyIdentifier'; // deprecated, use .35
5671oids['2.5.29.2'] = 'keyAttributes'; // obsolete use .37 or .15
5672oids['2.5.29.3'] = 'certificatePolicies'; // deprecated, use .32
5673oids['2.5.29.4'] = 'keyUsageRestriction'; // obsolete use .37 or .15
5674oids['2.5.29.5'] = 'policyMapping'; // deprecated use .33
5675oids['2.5.29.6'] = 'subtreesConstraint'; // obsolete use .30
5676oids['2.5.29.7'] = 'subjectAltName'; // deprecated use .17
5677oids['2.5.29.8'] = 'issuerAltName'; // deprecated use .18
5678oids['2.5.29.9'] = 'subjectDirectoryAttributes';
5679oids['2.5.29.10'] = 'basicConstraints'; // deprecated use .19
5680oids['2.5.29.11'] = 'nameConstraints'; // deprecated use .30
5681oids['2.5.29.12'] = 'policyConstraints'; // deprecated use .36
5682oids['2.5.29.13'] = 'basicConstraints'; // deprecated use .19
5683oids['2.5.29.14'] = 'subjectKeyIdentifier';
5684oids['subjectKeyIdentifier'] = '2.5.29.14';
5685oids['2.5.29.15'] = 'keyUsage';
5686oids['keyUsage'] = '2.5.29.15';
5687oids['2.5.29.16'] = 'privateKeyUsagePeriod';
5688oids['2.5.29.17'] = 'subjectAltName';
5689oids['subjectAltName'] = '2.5.29.17';
5690oids['2.5.29.18'] = 'issuerAltName';
5691oids['issuerAltName'] = '2.5.29.18';
5692oids['2.5.29.19'] = 'basicConstraints';
5693oids['basicConstraints'] = '2.5.29.19';
5694oids['2.5.29.20'] = 'cRLNumber';
5695oids['2.5.29.21'] = 'cRLReason';
5696oids['2.5.29.22'] = 'expirationDate';
5697oids['2.5.29.23'] = 'instructionCode';
5698oids['2.5.29.24'] = 'invalidityDate';
5699oids['2.5.29.25'] = 'cRLDistributionPoints'; // deprecated use .31
5700oids['2.5.29.26'] = 'issuingDistributionPoint'; // deprecated use .28
5701oids['2.5.29.27'] = 'deltaCRLIndicator';
5702oids['2.5.29.28'] = 'issuingDistributionPoint';
5703oids['2.5.29.29'] = 'certificateIssuer';
5704oids['2.5.29.30'] = 'nameConstraints';
5705oids['2.5.29.31'] = 'cRLDistributionPoints';
5706oids['cRLDistributionPoints'] = '2.5.29.31';
5707oids['2.5.29.32'] = 'certificatePolicies';
5708oids['certificatePolicies'] = '2.5.29.32';
5709oids['2.5.29.33'] = 'policyMappings';
5710oids['2.5.29.34'] = 'policyConstraints'; // deprecated use .36
5711oids['2.5.29.35'] = 'authorityKeyIdentifier';
5712oids['authorityKeyIdentifier'] = '2.5.29.35';
5713oids['2.5.29.36'] = 'policyConstraints';
5714oids['2.5.29.37'] = 'extKeyUsage';
5715oids['extKeyUsage'] = '2.5.29.37';
5716oids['2.5.29.46'] = 'freshestCRL';
5717oids['2.5.29.54'] = 'inhibitAnyPolicy';
5718
5719// extKeyUsage purposes
5720oids['1.3.6.1.4.1.11129.2.4.2'] = 'timestampList';
5721oids['timestampList'] = '1.3.6.1.4.1.11129.2.4.2';
5722oids['1.3.6.1.5.5.7.1.1'] = 'authorityInfoAccess';
5723oids['authorityInfoAccess'] = '1.3.6.1.5.5.7.1.1';
5724oids['1.3.6.1.5.5.7.3.1'] = 'serverAuth';
5725oids['serverAuth'] = '1.3.6.1.5.5.7.3.1';
5726oids['1.3.6.1.5.5.7.3.2'] = 'clientAuth';
5727oids['clientAuth'] = '1.3.6.1.5.5.7.3.2';
5728oids['1.3.6.1.5.5.7.3.3'] = 'codeSigning';
5729oids['codeSigning'] = '1.3.6.1.5.5.7.3.3';
5730oids['1.3.6.1.5.5.7.3.4'] = 'emailProtection';
5731oids['emailProtection'] = '1.3.6.1.5.5.7.3.4';
5732oids['1.3.6.1.5.5.7.3.8'] = 'timeStamping';
5733oids['timeStamping'] = '1.3.6.1.5.5.7.3.8';
5734
5735} // end module implementation
5736
5737/* ########## Begin module wrapper ########## */
5738var name = 'oids';
5739if(typeof define !== 'function') {
5740 // NodeJS -> AMD
5741 if(typeof module === 'object' && module.exports) {
5742 var nodeJS = true;
5743 define = function(ids, factory) {
5744 factory(require, module);
5745 };
5746 } else {
5747 // <script>
5748 if(typeof forge === 'undefined') {
5749 forge = {};
5750 }
5751 return initModule(forge);
5752 }
5753}
5754// AMD
5755var deps;
5756var defineFunc = function(require, module) {
5757 module.exports = function(forge) {
5758 var mods = deps.map(function(dep) {
5759 return require(dep);
5760 }).concat(initModule);
5761 // handle circular dependencies
5762 forge = forge || {};
5763 forge.defined = forge.defined || {};
5764 if(forge.defined[name]) {
5765 return forge[name];
5766 }
5767 forge.defined[name] = true;
5768 for(var i = 0; i < mods.length; ++i) {
5769 mods[i](forge);
5770 }
5771 return forge[name];
5772 };
5773};
5774var tmpDefine = define;
5775define = function(ids, factory) {
5776 deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
5777 if(nodeJS) {
5778 delete define;
5779 return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
5780 }
5781 define = tmpDefine;
5782 return define.apply(null, Array.prototype.slice.call(arguments, 0));
5783};
5784define(['require', 'module'], function() {
5785 defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
5786});
5787})();
5788
5789/**
5790 * Javascript implementation of Abstract Syntax Notation Number One.
5791 *
5792 * @author Dave Longley
5793 *
5794 * Copyright (c) 2010-2015 Digital Bazaar, Inc.
5795 *
5796 * An API for storing data using the Abstract Syntax Notation Number One
5797 * format using DER (Distinguished Encoding Rules) encoding. This encoding is
5798 * commonly used to store data for PKI, i.e. X.509 Certificates, and this
5799 * implementation exists for that purpose.
5800 *
5801 * Abstract Syntax Notation Number One (ASN.1) is used to define the abstract
5802 * syntax of information without restricting the way the information is encoded
5803 * for transmission. It provides a standard that allows for open systems
5804 * communication. ASN.1 defines the syntax of information data and a number of
5805 * simple data types as well as a notation for describing them and specifying
5806 * values for them.
5807 *
5808 * The RSA algorithm creates public and private keys that are often stored in
5809 * X.509 or PKCS#X formats -- which use ASN.1 (encoded in DER format). This
5810 * class provides the most basic functionality required to store and load DSA
5811 * keys that are encoded according to ASN.1.
5812 *
5813 * The most common binary encodings for ASN.1 are BER (Basic Encoding Rules)
5814 * and DER (Distinguished Encoding Rules). DER is just a subset of BER that
5815 * has stricter requirements for how data must be encoded.
5816 *
5817 * Each ASN.1 structure has a tag (a byte identifying the ASN.1 structure type)
5818 * and a byte array for the value of this ASN1 structure which may be data or a
5819 * list of ASN.1 structures.
5820 *
5821 * Each ASN.1 structure using BER is (Tag-Length-Value):
5822 *
5823 * | byte 0 | bytes X | bytes Y |
5824 * |--------|---------|----------
5825 * | tag | length | value |
5826 *
5827 * ASN.1 allows for tags to be of "High-tag-number form" which allows a tag to
5828 * be two or more octets, but that is not supported by this class. A tag is
5829 * only 1 byte. Bits 1-5 give the tag number (ie the data type within a
5830 * particular 'class'), 6 indicates whether or not the ASN.1 value is
5831 * constructed from other ASN.1 values, and bits 7 and 8 give the 'class'. If
5832 * bits 7 and 8 are both zero, the class is UNIVERSAL. If only bit 7 is set,
5833 * then the class is APPLICATION. If only bit 8 is set, then the class is
5834 * CONTEXT_SPECIFIC. If both bits 7 and 8 are set, then the class is PRIVATE.
5835 * The tag numbers for the data types for the class UNIVERSAL are listed below:
5836 *
5837 * UNIVERSAL 0 Reserved for use by the encoding rules
5838 * UNIVERSAL 1 Boolean type
5839 * UNIVERSAL 2 Integer type
5840 * UNIVERSAL 3 Bitstring type
5841 * UNIVERSAL 4 Octetstring type
5842 * UNIVERSAL 5 Null type
5843 * UNIVERSAL 6 Object identifier type
5844 * UNIVERSAL 7 Object descriptor type
5845 * UNIVERSAL 8 External type and Instance-of type
5846 * UNIVERSAL 9 Real type
5847 * UNIVERSAL 10 Enumerated type
5848 * UNIVERSAL 11 Embedded-pdv type
5849 * UNIVERSAL 12 UTF8String type
5850 * UNIVERSAL 13 Relative object identifier type
5851 * UNIVERSAL 14-15 Reserved for future editions
5852 * UNIVERSAL 16 Sequence and Sequence-of types
5853 * UNIVERSAL 17 Set and Set-of types
5854 * UNIVERSAL 18-22, 25-30 Character string types
5855 * UNIVERSAL 23-24 Time types
5856 *
5857 * The length of an ASN.1 structure is specified after the tag identifier.
5858 * There is a definite form and an indefinite form. The indefinite form may
5859 * be used if the encoding is constructed and not all immediately available.
5860 * The indefinite form is encoded using a length byte with only the 8th bit
5861 * set. The end of the constructed object is marked using end-of-contents
5862 * octets (two zero bytes).
5863 *
5864 * The definite form looks like this:
5865 *
5866 * The length may take up 1 or more bytes, it depends on the length of the
5867 * value of the ASN.1 structure. DER encoding requires that if the ASN.1
5868 * structure has a value that has a length greater than 127, more than 1 byte
5869 * will be used to store its length, otherwise just one byte will be used.
5870 * This is strict.
5871 *
5872 * In the case that the length of the ASN.1 value is less than 127, 1 octet
5873 * (byte) is used to store the "short form" length. The 8th bit has a value of
5874 * 0 indicating the length is "short form" and not "long form" and bits 7-1
5875 * give the length of the data. (The 8th bit is the left-most, most significant
5876 * bit: also known as big endian or network format).
5877 *
5878 * In the case that the length of the ASN.1 value is greater than 127, 2 to
5879 * 127 octets (bytes) are used to store the "long form" length. The first
5880 * byte's 8th bit is set to 1 to indicate the length is "long form." Bits 7-1
5881 * give the number of additional octets. All following octets are in base 256
5882 * with the most significant digit first (typical big-endian binary unsigned
5883 * integer storage). So, for instance, if the length of a value was 257, the
5884 * first byte would be set to:
5885 *
5886 * 10000010 = 130 = 0x82.
5887 *
5888 * This indicates there are 2 octets (base 256) for the length. The second and
5889 * third bytes (the octets just mentioned) would store the length in base 256:
5890 *
5891 * octet 2: 00000001 = 1 * 256^1 = 256
5892 * octet 3: 00000001 = 1 * 256^0 = 1
5893 * total = 257
5894 *
5895 * The algorithm for converting a js integer value of 257 to base-256 is:
5896 *
5897 * var value = 257;
5898 * var bytes = [];
5899 * bytes[0] = (value >>> 8) & 0xFF; // most significant byte first
5900 * bytes[1] = value & 0xFF; // least significant byte last
5901 *
5902 * On the ASN.1 UNIVERSAL Object Identifier (OID) type:
5903 *
5904 * An OID can be written like: "value1.value2.value3...valueN"
5905 *
5906 * The DER encoding rules:
5907 *
5908 * The first byte has the value 40 * value1 + value2.
5909 * The following bytes, if any, encode the remaining values. Each value is
5910 * encoded in base 128, most significant digit first (big endian), with as
5911 * few digits as possible, and the most significant bit of each byte set
5912 * to 1 except the last in each value's encoding. For example: Given the
5913 * OID "1.2.840.113549", its DER encoding is (remember each byte except the
5914 * last one in each encoding is OR'd with 0x80):
5915 *
5916 * byte 1: 40 * 1 + 2 = 42 = 0x2A.
5917 * bytes 2-3: 128 * 6 + 72 = 840 = 6 72 = 6 72 = 0x0648 = 0x8648
5918 * bytes 4-6: 16384 * 6 + 128 * 119 + 13 = 6 119 13 = 0x06770D = 0x86F70D
5919 *
5920 * The final value is: 0x2A864886F70D.
5921 * The full OID (including ASN.1 tag and length of 6 bytes) is:
5922 * 0x06062A864886F70D
5923 */
5924(function() {
5925/* ########## Begin module implementation ########## */
5926function initModule(forge) {
5927
5928/* ASN.1 API */
5929var asn1 = forge.asn1 = forge.asn1 || {};
5930
5931/**
5932 * ASN.1 classes.
5933 */
5934asn1.Class = {
5935 UNIVERSAL: 0x00,
5936 APPLICATION: 0x40,
5937 CONTEXT_SPECIFIC: 0x80,
5938 PRIVATE: 0xC0
5939};
5940
5941/**
5942 * ASN.1 types. Not all types are supported by this implementation, only
5943 * those necessary to implement a simple PKI are implemented.
5944 */
5945asn1.Type = {
5946 NONE: 0,
5947 BOOLEAN: 1,
5948 INTEGER: 2,
5949 BITSTRING: 3,
5950 OCTETSTRING: 4,
5951 NULL: 5,
5952 OID: 6,
5953 ODESC: 7,
5954 EXTERNAL: 8,
5955 REAL: 9,
5956 ENUMERATED: 10,
5957 EMBEDDED: 11,
5958 UTF8: 12,
5959 ROID: 13,
5960 SEQUENCE: 16,
5961 SET: 17,
5962 PRINTABLESTRING: 19,
5963 IA5STRING: 22,
5964 UTCTIME: 23,
5965 GENERALIZEDTIME: 24,
5966 BMPSTRING: 30
5967};
5968
5969/**
5970 * Creates a new asn1 object.
5971 *
5972 * @param tagClass the tag class for the object.
5973 * @param type the data type (tag number) for the object.
5974 * @param constructed true if the asn1 object is in constructed form.
5975 * @param value the value for the object, if it is not constructed.
5976 * @param [options] the options to use:
5977 * [bitStringContents] the plain BIT STRING content including padding
5978 * byte.
5979 *
5980 * @return the asn1 object.
5981 */
5982asn1.create = function(tagClass, type, constructed, value, options) {
5983 /* An asn1 object has a tagClass, a type, a constructed flag, and a
5984 value. The value's type depends on the constructed flag. If
5985 constructed, it will contain a list of other asn1 objects. If not,
5986 it will contain the ASN.1 value as an array of bytes formatted
5987 according to the ASN.1 data type. */
5988
5989 // remove undefined values
5990 if(forge.util.isArray(value)) {
5991 var tmp = [];
5992 for(var i = 0; i < value.length; ++i) {
5993 if(value[i] !== undefined) {
5994 tmp.push(value[i]);
5995 }
5996 }
5997 value = tmp;
5998 }
5999
6000 var obj = {
6001 tagClass: tagClass,
6002 type: type,
6003 constructed: constructed,
6004 composed: constructed || forge.util.isArray(value),
6005 value: value
6006 };
6007 if(options && 'bitStringContents' in options) {
6008 // TODO: copy byte buffer if it's a buffer not a string
6009 obj.bitStringContents = options.bitStringContents;
6010 // TODO: add readonly flag to avoid this overhead
6011 // save copy to detect changes
6012 obj.original = asn1.copy(obj);
6013 }
6014 return obj;
6015};
6016
6017/**
6018 * Copies an asn1 object.
6019 *
6020 * @param obj the asn1 object.
6021 * @param [options] copy options:
6022 * [excludeBitStringContents] true to not copy bitStringContents
6023 *
6024 * @return the a copy of the asn1 object.
6025 */
6026asn1.copy = function(obj, options) {
6027 var copy;
6028
6029 if(forge.util.isArray(obj)) {
6030 copy = [];
6031 for(var i = 0; i < obj.length; ++i) {
6032 copy.push(asn1.copy(obj[i], options));
6033 }
6034 return copy;
6035 }
6036
6037 if(typeof obj === 'string') {
6038 // TODO: copy byte buffer if it's a buffer not a string
6039 return obj;
6040 }
6041
6042 copy = {
6043 tagClass: obj.tagClass,
6044 type: obj.type,
6045 constructed: obj.constructed,
6046 composed: obj.composed,
6047 value: asn1.copy(obj.value, options)
6048 };
6049 if(options && !options.excludeBitStringContents) {
6050 // TODO: copy byte buffer if it's a buffer not a string
6051 copy.bitStringContents = obj.bitStringContents;
6052 }
6053 return copy;
6054};
6055
6056/**
6057 * Compares asn1 objects for equality.
6058 *
6059 * Note this function does not run in constant time.
6060 *
6061 * @param obj1 the first asn1 object.
6062 * @param obj2 the second asn1 object.
6063 * @param [options] compare options:
6064 * [includeBitStringContents] true to compare bitStringContents
6065 *
6066 * @return true if the asn1 objects are equal.
6067 */
6068asn1.equals = function(obj1, obj2, options) {
6069 if(forge.util.isArray(obj1)) {
6070 if(!forge.util.isArray(obj2)) {
6071 return false;
6072 }
6073 if(obj1.length !== obj2.length) {
6074 return false;
6075 }
6076 for(var i = 0; i < obj1.length; ++i) {
6077 if(!asn1.equals(obj1[i], obj2[i])) {
6078 return false;
6079 }
6080 return true;
6081 }
6082 }
6083
6084 if(typeof obj1 !== typeof obj2) {
6085 return false;
6086 }
6087
6088 if(typeof obj1 === 'string') {
6089 return obj1 === obj2;
6090 }
6091
6092 var equal = obj1.tagClass === obj2.tagClass &&
6093 obj1.type === obj2.type &&
6094 obj1.constructed === obj2.constructed &&
6095 obj1.composed === obj2.composed &&
6096 asn1.equals(obj1.value, obj2.value);
6097 if(options && options.includeBitStringContents) {
6098 equal = equal && (obj1.bitStringContents === obj2.bitStringContents);
6099 }
6100
6101 return equal;
6102};
6103
6104/**
6105 * Gets the length of a BER-encoded ASN.1 value.
6106 *
6107 * In case the length is not specified, undefined is returned.
6108 *
6109 * @param b the BER-encoded ASN.1 byte buffer, starting with the first
6110 * length byte.
6111 *
6112 * @return the length of the BER-encoded ASN.1 value or undefined.
6113 */
6114asn1.getBerValueLength = function(b) {
6115 // TODO: move this function and related DER/BER functions to a der.js
6116 // file; better abstract ASN.1 away from der/ber.
6117 var b2 = b.getByte();
6118 if(b2 === 0x80) {
6119 return undefined;
6120 }
6121
6122 // see if the length is "short form" or "long form" (bit 8 set)
6123 var length;
6124 var longForm = b2 & 0x80;
6125 if(!longForm) {
6126 // length is just the first byte
6127 length = b2;
6128 } else {
6129 // the number of bytes the length is specified in bits 7 through 1
6130 // and each length byte is in big-endian base-256
6131 length = b.getInt((b2 & 0x7F) << 3);
6132 }
6133 return length;
6134};
6135
6136/**
6137 * Check if the byte buffer has enough bytes. Throws an Error if not.
6138 *
6139 * @param bytes the byte buffer to parse from.
6140 * @param remaining the bytes remaining in the current parsing state.
6141 * @param n the number of bytes the buffer must have.
6142 */
6143function _checkBufferLength(bytes, remaining, n) {
6144 if(n > remaining) {
6145 var error = new Error('Too few bytes to parse DER.');
6146 error.available = bytes.length();
6147 error.remaining = remaining;
6148 error.requested = n;
6149 throw error;
6150 }
6151}
6152
6153/**
6154 * Gets the length of a BER-encoded ASN.1 value.
6155 *
6156 * In case the length is not specified, undefined is returned.
6157 *
6158 * @param bytes the byte buffer to parse from.
6159 * @param remaining the bytes remaining in the current parsing state.
6160 *
6161 * @return the length of the BER-encoded ASN.1 value or undefined.
6162 */
6163var _getValueLength = function(bytes, remaining) {
6164 // TODO: move this function and related DER/BER functions to a der.js
6165 // file; better abstract ASN.1 away from der/ber.
6166 // fromDer already checked that this byte exists
6167 var b2 = bytes.getByte();
6168 remaining--;
6169 if(b2 === 0x80) {
6170 return undefined;
6171 }
6172
6173 // see if the length is "short form" or "long form" (bit 8 set)
6174 var length;
6175 var longForm = b2 & 0x80;
6176 if(!longForm) {
6177 // length is just the first byte
6178 length = b2;
6179 } else {
6180 // the number of bytes the length is specified in bits 7 through 1
6181 // and each length byte is in big-endian base-256
6182 var longFormBytes = b2 & 0x7F;
6183 _checkBufferLength(bytes, remaining, longFormBytes);
6184 length = bytes.getInt(longFormBytes << 3);
6185 }
6186 // FIXME: this will only happen for 32 bit getInt with high bit set
6187 if(length < 0) {
6188 throw new Error('Negative length: ' + length);
6189 }
6190 return length;
6191};
6192
6193/**
6194 * Parses an asn1 object from a byte buffer in DER format.
6195 *
6196 * @param bytes the byte buffer to parse from.
6197 * @param [strict] true to be strict when checking value lengths, false to
6198 * allow truncated values (default: true).
6199 * @param [options] object with options or boolean strict flag
6200 * [strict] true to be strict when checking value lengths, false to
6201 * allow truncated values (default: true).
6202 * [decodeBitStrings] true to attempt to decode the content of
6203 * BIT STRINGs (not OCTET STRINGs) using strict mode. Note that
6204 * without schema support to understand the data context this can
6205 * erroneously decode values that happen to be valid ASN.1. This
6206 * flag will be deprecated or removed as soon as schema support is
6207 * available. (default: true)
6208 *
6209 * @return the parsed asn1 object.
6210 */
6211asn1.fromDer = function(bytes, options) {
6212 if(options === undefined) {
6213 options = {
6214 strict: true,
6215 decodeBitStrings: true
6216 };
6217 }
6218 if(typeof options === 'boolean') {
6219 options = {
6220 strict: options,
6221 decodeBitStrings: true
6222 };
6223 }
6224 if(!('strict' in options)) {
6225 options.strict = true;
6226 }
6227 if(!('decodeBitStrings' in options)) {
6228 options.decodeBitStrings = true;
6229 }
6230
6231 // wrap in buffer if needed
6232 if(typeof bytes === 'string') {
6233 bytes = forge.util.createBuffer(bytes);
6234 }
6235
6236 return _fromDer(bytes, bytes.length(), 0, options);
6237}
6238
6239/**
6240 * Internal function to parse an asn1 object from a byte buffer in DER format.
6241 *
6242 * @param bytes the byte buffer to parse from.
6243 * @param remaining the number of bytes remaining for this chunk.
6244 * @param depth the current parsing depth.
6245 * @param options object with same options as fromDer().
6246 *
6247 * @return the parsed asn1 object.
6248 */
6249function _fromDer(bytes, remaining, depth, options) {
6250 // temporary storage for consumption calculations
6251 var start;
6252
6253 // minimum length for ASN.1 DER structure is 2
6254 _checkBufferLength(bytes, remaining, 2);
6255
6256 // get the first byte
6257 var b1 = bytes.getByte();
6258 // consumed one byte
6259 remaining--;
6260
6261 // get the tag class
6262 var tagClass = (b1 & 0xC0);
6263
6264 // get the type (bits 1-5)
6265 var type = b1 & 0x1F;
6266
6267 // get the variable value length and adjust remaining bytes
6268 start = bytes.length();
6269 var length = _getValueLength(bytes, remaining);
6270 remaining -= start - bytes.length();
6271
6272 // ensure there are enough bytes to get the value
6273 if(length !== undefined && length > remaining) {
6274 if(options.strict) {
6275 var error = new Error('Too few bytes to read ASN.1 value.');
6276 error.available = bytes.length();
6277 error.remaining = remaining;
6278 error.requested = length;
6279 throw error;
6280 }
6281 // Note: be lenient with truncated values and use remaining state bytes
6282 length = remaining;
6283 }
6284
6285 // value storage
6286 var value;
6287 // possible BIT STRING contents storage
6288 var bitStringContents;
6289
6290 // constructed flag is bit 6 (32 = 0x20) of the first byte
6291 var constructed = ((b1 & 0x20) === 0x20);
6292 if(constructed) {
6293 // parse child asn1 objects from the value
6294 value = [];
6295 if(length === undefined) {
6296 // asn1 object of indefinite length, read until end tag
6297 for(;;) {
6298 _checkBufferLength(bytes, remaining, 2);
6299 if(bytes.bytes(2) === String.fromCharCode(0, 0)) {
6300 bytes.getBytes(2);
6301 remaining -= 2;
6302 break;
6303 }
6304 start = bytes.length();
6305 value.push(_fromDer(bytes, remaining, depth + 1, options));
6306 remaining -= start - bytes.length();
6307 }
6308 } else {
6309 // parsing asn1 object of definite length
6310 while(length > 0) {
6311 start = bytes.length();
6312 value.push(_fromDer(bytes, length, depth + 1, options));
6313 remaining -= start - bytes.length();
6314 length -= start - bytes.length();
6315 }
6316 }
6317 }
6318
6319 // if a BIT STRING, save the contents including padding
6320 if(value === undefined && tagClass === asn1.Class.UNIVERSAL &&
6321 type === asn1.Type.BITSTRING) {
6322 bitStringContents = bytes.bytes(length);
6323 }
6324
6325 // determine if a non-constructed value should be decoded as a composed
6326 // value that contains other ASN.1 objects. BIT STRINGs (and OCTET STRINGs)
6327 // can be used this way.
6328 if(value === undefined && options.decodeBitStrings &&
6329 tagClass === asn1.Class.UNIVERSAL &&
6330 // FIXME: OCTET STRINGs not yet supported here
6331 // .. other parts of forge expect to decode OCTET STRINGs manually
6332 (type === asn1.Type.BITSTRING /*|| type === asn1.Type.OCTETSTRING*/) &&
6333 length > 1) {
6334 // save read position
6335 var savedRead = bytes.read;
6336 var savedRemaining = remaining;
6337 var unused = 0;
6338 if(type === asn1.Type.BITSTRING) {
6339 /* The first octet gives the number of bits by which the length of the
6340 bit string is less than the next multiple of eight (this is called
6341 the "number of unused bits").
6342
6343 The second and following octets give the value of the bit string
6344 converted to an octet string. */
6345 _checkBufferLength(bytes, remaining, 1);
6346 unused = bytes.getByte();
6347 remaining--;
6348 }
6349 // if all bits are used, maybe the BIT/OCTET STRING holds ASN.1 objs
6350 if(unused === 0) {
6351 try {
6352 // attempt to parse child asn1 object from the value
6353 // (stored in array to signal composed value)
6354 start = bytes.length();
6355 var subOptions = {
6356 // enforce strict mode to avoid parsing ASN.1 from plain data
6357 verbose: options.verbose,
6358 strict: true,
6359 decodeBitStrings: true
6360 };
6361 var composed = _fromDer(bytes, remaining, depth + 1, subOptions);
6362 var used = start - bytes.length();
6363 remaining -= used;
6364 if(type == asn1.Type.BITSTRING) {
6365 used++;
6366 }
6367
6368 // if the data all decoded and the class indicates UNIVERSAL or
6369 // CONTEXT_SPECIFIC then assume we've got an encapsulated ASN.1 object
6370 var tc = composed.tagClass;
6371 if(used === length &&
6372 (tc === asn1.Class.UNIVERSAL || tc === asn1.Class.CONTEXT_SPECIFIC)) {
6373 value = [composed];
6374 }
6375 } catch(ex) {
6376 }
6377 }
6378 if(value === undefined) {
6379 // restore read position
6380 bytes.read = savedRead;
6381 remaining = savedRemaining;
6382 }
6383 }
6384
6385 if(value === undefined) {
6386 // asn1 not constructed or composed, get raw value
6387 // TODO: do DER to OID conversion and vice-versa in .toDer?
6388
6389 if(length === undefined) {
6390 if(options.strict) {
6391 throw new Error('Non-constructed ASN.1 object of indefinite length.');
6392 }
6393 // be lenient and use remaining state bytes
6394 length = remaining;
6395 }
6396
6397 if(type === asn1.Type.BMPSTRING) {
6398 value = '';
6399 for(; length > 0; length -= 2) {
6400 _checkBufferLength(bytes, remaining, 2);
6401 value += String.fromCharCode(bytes.getInt16());
6402 remaining -= 2;
6403 }
6404 } else {
6405 value = bytes.getBytes(length);
6406 }
6407 }
6408
6409 // add BIT STRING contents if available
6410 var asn1Options = bitStringContents === undefined ? null : {
6411 bitStringContents: bitStringContents
6412 };
6413
6414 // create and return asn1 object
6415 return asn1.create(tagClass, type, constructed, value, asn1Options);
6416}
6417
6418/**
6419 * Converts the given asn1 object to a buffer of bytes in DER format.
6420 *
6421 * @param asn1 the asn1 object to convert to bytes.
6422 *
6423 * @return the buffer of bytes.
6424 */
6425asn1.toDer = function(obj) {
6426 var bytes = forge.util.createBuffer();
6427
6428 // build the first byte
6429 var b1 = obj.tagClass | obj.type;
6430
6431 // for storing the ASN.1 value
6432 var value = forge.util.createBuffer();
6433
6434 // use BIT STRING contents if available and data not changed
6435 var useBitStringContents = false;
6436 if('bitStringContents' in obj) {
6437 useBitStringContents = true;
6438 if(obj.original) {
6439 useBitStringContents = asn1.equals(obj, obj.original);
6440 }
6441 }
6442
6443 if(useBitStringContents) {
6444 value.putBytes(obj.bitStringContents);
6445 } else if(obj.composed) {
6446 // if composed, use each child asn1 object's DER bytes as value
6447 // turn on 6th bit (0x20 = 32) to indicate asn1 is constructed
6448 // from other asn1 objects
6449 if(obj.constructed) {
6450 b1 |= 0x20;
6451 } else {
6452 // type is a bit string, add unused bits of 0x00
6453 value.putByte(0x00);
6454 }
6455
6456 // add all of the child DER bytes together
6457 for(var i = 0; i < obj.value.length; ++i) {
6458 if(obj.value[i] !== undefined) {
6459 value.putBuffer(asn1.toDer(obj.value[i]));
6460 }
6461 }
6462 } else {
6463 // use asn1.value directly
6464 if(obj.type === asn1.Type.BMPSTRING) {
6465 for(var i = 0; i < obj.value.length; ++i) {
6466 value.putInt16(obj.value.charCodeAt(i));
6467 }
6468 } else {
6469 // ensure integer is minimally-encoded
6470 // TODO: should all leading bytes be stripped vs just one?
6471 // .. ex '00 00 01' => '01'?
6472 if(obj.type === asn1.Type.INTEGER &&
6473 obj.value.length > 1 &&
6474 // leading 0x00 for positive integer
6475 ((obj.value.charCodeAt(0) === 0 &&
6476 (obj.value.charCodeAt(1) & 0x80) === 0) ||
6477 // leading 0xFF for negative integer
6478 (obj.value.charCodeAt(0) === 0xFF &&
6479 (obj.value.charCodeAt(1) & 0x80) === 0x80))) {
6480 value.putBytes(obj.value.substr(1));
6481 } else {
6482 value.putBytes(obj.value);
6483 }
6484 }
6485 }
6486
6487 // add tag byte
6488 bytes.putByte(b1);
6489
6490 // use "short form" encoding
6491 if(value.length() <= 127) {
6492 // one byte describes the length
6493 // bit 8 = 0 and bits 7-1 = length
6494 bytes.putByte(value.length() & 0x7F);
6495 } else {
6496 // use "long form" encoding
6497 // 2 to 127 bytes describe the length
6498 // first byte: bit 8 = 1 and bits 7-1 = # of additional bytes
6499 // other bytes: length in base 256, big-endian
6500 var len = value.length();
6501 var lenBytes = '';
6502 do {
6503 lenBytes += String.fromCharCode(len & 0xFF);
6504 len = len >>> 8;
6505 } while(len > 0);
6506
6507 // set first byte to # bytes used to store the length and turn on
6508 // bit 8 to indicate long-form length is used
6509 bytes.putByte(lenBytes.length | 0x80);
6510
6511 // concatenate length bytes in reverse since they were generated
6512 // little endian and we need big endian
6513 for(var i = lenBytes.length - 1; i >= 0; --i) {
6514 bytes.putByte(lenBytes.charCodeAt(i));
6515 }
6516 }
6517
6518 // concatenate value bytes
6519 bytes.putBuffer(value);
6520 return bytes;
6521};
6522
6523/**
6524 * Converts an OID dot-separated string to a byte buffer. The byte buffer
6525 * contains only the DER-encoded value, not any tag or length bytes.
6526 *
6527 * @param oid the OID dot-separated string.
6528 *
6529 * @return the byte buffer.
6530 */
6531asn1.oidToDer = function(oid) {
6532 // split OID into individual values
6533 var values = oid.split('.');
6534 var bytes = forge.util.createBuffer();
6535
6536 // first byte is 40 * value1 + value2
6537 bytes.putByte(40 * parseInt(values[0], 10) + parseInt(values[1], 10));
6538 // other bytes are each value in base 128 with 8th bit set except for
6539 // the last byte for each value
6540 var last, valueBytes, value, b;
6541 for(var i = 2; i < values.length; ++i) {
6542 // produce value bytes in reverse because we don't know how many
6543 // bytes it will take to store the value
6544 last = true;
6545 valueBytes = [];
6546 value = parseInt(values[i], 10);
6547 do {
6548 b = value & 0x7F;
6549 value = value >>> 7;
6550 // if value is not last, then turn on 8th bit
6551 if(!last) {
6552 b |= 0x80;
6553 }
6554 valueBytes.push(b);
6555 last = false;
6556 } while(value > 0);
6557
6558 // add value bytes in reverse (needs to be in big endian)
6559 for(var n = valueBytes.length - 1; n >= 0; --n) {
6560 bytes.putByte(valueBytes[n]);
6561 }
6562 }
6563
6564 return bytes;
6565};
6566
6567/**
6568 * Converts a DER-encoded byte buffer to an OID dot-separated string. The
6569 * byte buffer should contain only the DER-encoded value, not any tag or
6570 * length bytes.
6571 *
6572 * @param bytes the byte buffer.
6573 *
6574 * @return the OID dot-separated string.
6575 */
6576asn1.derToOid = function(bytes) {
6577 var oid;
6578
6579 // wrap in buffer if needed
6580 if(typeof bytes === 'string') {
6581 bytes = forge.util.createBuffer(bytes);
6582 }
6583
6584 // first byte is 40 * value1 + value2
6585 var b = bytes.getByte();
6586 oid = Math.floor(b / 40) + '.' + (b % 40);
6587
6588 // other bytes are each value in base 128 with 8th bit set except for
6589 // the last byte for each value
6590 var value = 0;
6591 while(bytes.length() > 0) {
6592 b = bytes.getByte();
6593 value = value << 7;
6594 // not the last byte for the value
6595 if(b & 0x80) {
6596 value += b & 0x7F;
6597 } else {
6598 // last byte
6599 oid += '.' + (value + b);
6600 value = 0;
6601 }
6602 }
6603
6604 return oid;
6605};
6606
6607/**
6608 * Converts a UTCTime value to a date.
6609 *
6610 * Note: GeneralizedTime has 4 digits for the year and is used for X.509
6611 * dates passed 2049. Parsing that structure hasn't been implemented yet.
6612 *
6613 * @param utc the UTCTime value to convert.
6614 *
6615 * @return the date.
6616 */
6617asn1.utcTimeToDate = function(utc) {
6618 /* The following formats can be used:
6619
6620 YYMMDDhhmmZ
6621 YYMMDDhhmm+hh'mm'
6622 YYMMDDhhmm-hh'mm'
6623 YYMMDDhhmmssZ
6624 YYMMDDhhmmss+hh'mm'
6625 YYMMDDhhmmss-hh'mm'
6626
6627 Where:
6628
6629 YY is the least significant two digits of the year
6630 MM is the month (01 to 12)
6631 DD is the day (01 to 31)
6632 hh is the hour (00 to 23)
6633 mm are the minutes (00 to 59)
6634 ss are the seconds (00 to 59)
6635 Z indicates that local time is GMT, + indicates that local time is
6636 later than GMT, and - indicates that local time is earlier than GMT
6637 hh' is the absolute value of the offset from GMT in hours
6638 mm' is the absolute value of the offset from GMT in minutes */
6639 var date = new Date();
6640
6641 // if YY >= 50 use 19xx, if YY < 50 use 20xx
6642 var year = parseInt(utc.substr(0, 2), 10);
6643 year = (year >= 50) ? 1900 + year : 2000 + year;
6644 var MM = parseInt(utc.substr(2, 2), 10) - 1; // use 0-11 for month
6645 var DD = parseInt(utc.substr(4, 2), 10);
6646 var hh = parseInt(utc.substr(6, 2), 10);
6647 var mm = parseInt(utc.substr(8, 2), 10);
6648 var ss = 0;
6649
6650 // not just YYMMDDhhmmZ
6651 if(utc.length > 11) {
6652 // get character after minutes
6653 var c = utc.charAt(10);
6654 var end = 10;
6655
6656 // see if seconds are present
6657 if(c !== '+' && c !== '-') {
6658 // get seconds
6659 ss = parseInt(utc.substr(10, 2), 10);
6660 end += 2;
6661 }
6662 }
6663
6664 // update date
6665 date.setUTCFullYear(year, MM, DD);
6666 date.setUTCHours(hh, mm, ss, 0);
6667
6668 if(end) {
6669 // get +/- after end of time
6670 c = utc.charAt(end);
6671 if(c === '+' || c === '-') {
6672 // get hours+minutes offset
6673 var hhoffset = parseInt(utc.substr(end + 1, 2), 10);
6674 var mmoffset = parseInt(utc.substr(end + 4, 2), 10);
6675
6676 // calculate offset in milliseconds
6677 var offset = hhoffset * 60 + mmoffset;
6678 offset *= 60000;
6679
6680 // apply offset
6681 if(c === '+') {
6682 date.setTime(+date - offset);
6683 } else {
6684 date.setTime(+date + offset);
6685 }
6686 }
6687 }
6688
6689 return date;
6690};
6691
6692/**
6693 * Converts a GeneralizedTime value to a date.
6694 *
6695 * @param gentime the GeneralizedTime value to convert.
6696 *
6697 * @return the date.
6698 */
6699asn1.generalizedTimeToDate = function(gentime) {
6700 /* The following formats can be used:
6701
6702 YYYYMMDDHHMMSS
6703 YYYYMMDDHHMMSS.fff
6704 YYYYMMDDHHMMSSZ
6705 YYYYMMDDHHMMSS.fffZ
6706 YYYYMMDDHHMMSS+hh'mm'
6707 YYYYMMDDHHMMSS.fff+hh'mm'
6708 YYYYMMDDHHMMSS-hh'mm'
6709 YYYYMMDDHHMMSS.fff-hh'mm'
6710
6711 Where:
6712
6713 YYYY is the year
6714 MM is the month (01 to 12)
6715 DD is the day (01 to 31)
6716 hh is the hour (00 to 23)
6717 mm are the minutes (00 to 59)
6718 ss are the seconds (00 to 59)
6719 .fff is the second fraction, accurate to three decimal places
6720 Z indicates that local time is GMT, + indicates that local time is
6721 later than GMT, and - indicates that local time is earlier than GMT
6722 hh' is the absolute value of the offset from GMT in hours
6723 mm' is the absolute value of the offset from GMT in minutes */
6724 var date = new Date();
6725
6726 var YYYY = parseInt(gentime.substr(0, 4), 10);
6727 var MM = parseInt(gentime.substr(4, 2), 10) - 1; // use 0-11 for month
6728 var DD = parseInt(gentime.substr(6, 2), 10);
6729 var hh = parseInt(gentime.substr(8, 2), 10);
6730 var mm = parseInt(gentime.substr(10, 2), 10);
6731 var ss = parseInt(gentime.substr(12, 2), 10);
6732 var fff = 0;
6733 var offset = 0;
6734 var isUTC = false;
6735
6736 if(gentime.charAt(gentime.length - 1) === 'Z') {
6737 isUTC = true;
6738 }
6739
6740 var end = gentime.length - 5, c = gentime.charAt(end);
6741 if(c === '+' || c === '-') {
6742 // get hours+minutes offset
6743 var hhoffset = parseInt(gentime.substr(end + 1, 2), 10);
6744 var mmoffset = parseInt(gentime.substr(end + 4, 2), 10);
6745
6746 // calculate offset in milliseconds
6747 offset = hhoffset * 60 + mmoffset;
6748 offset *= 60000;
6749
6750 // apply offset
6751 if(c === '+') {
6752 offset *= -1;
6753 }
6754
6755 isUTC = true;
6756 }
6757
6758 // check for second fraction
6759 if(gentime.charAt(14) === '.') {
6760 fff = parseFloat(gentime.substr(14), 10) * 1000;
6761 }
6762
6763 if(isUTC) {
6764 date.setUTCFullYear(YYYY, MM, DD);
6765 date.setUTCHours(hh, mm, ss, fff);
6766
6767 // apply offset
6768 date.setTime(+date + offset);
6769 } else {
6770 date.setFullYear(YYYY, MM, DD);
6771 date.setHours(hh, mm, ss, fff);
6772 }
6773
6774 return date;
6775};
6776
6777/**
6778 * Converts a date to a UTCTime value.
6779 *
6780 * Note: GeneralizedTime has 4 digits for the year and is used for X.509
6781 * dates passed 2049. Converting to a GeneralizedTime hasn't been
6782 * implemented yet.
6783 *
6784 * @param date the date to convert.
6785 *
6786 * @return the UTCTime value.
6787 */
6788asn1.dateToUtcTime = function(date) {
6789 // TODO: validate; currently assumes proper format
6790 if(typeof date === 'string') {
6791 return date;
6792 }
6793
6794 var rval = '';
6795
6796 // create format YYMMDDhhmmssZ
6797 var format = [];
6798 format.push(('' + date.getUTCFullYear()).substr(2));
6799 format.push('' + (date.getUTCMonth() + 1));
6800 format.push('' + date.getUTCDate());
6801 format.push('' + date.getUTCHours());
6802 format.push('' + date.getUTCMinutes());
6803 format.push('' + date.getUTCSeconds());
6804
6805 // ensure 2 digits are used for each format entry
6806 for(var i = 0; i < format.length; ++i) {
6807 if(format[i].length < 2) {
6808 rval += '0';
6809 }
6810 rval += format[i];
6811 }
6812 rval += 'Z';
6813
6814 return rval;
6815};
6816
6817/**
6818 * Converts a date to a GeneralizedTime value.
6819 *
6820 * @param date the date to convert.
6821 *
6822 * @return the GeneralizedTime value as a string.
6823 */
6824asn1.dateToGeneralizedTime = function(date) {
6825 // TODO: validate; currently assumes proper format
6826 if(typeof date === 'string') {
6827 return date;
6828 }
6829
6830 var rval = '';
6831
6832 // create format YYYYMMDDHHMMSSZ
6833 var format = [];
6834 format.push('' + date.getUTCFullYear());
6835 format.push('' + (date.getUTCMonth() + 1));
6836 format.push('' + date.getUTCDate());
6837 format.push('' + date.getUTCHours());
6838 format.push('' + date.getUTCMinutes());
6839 format.push('' + date.getUTCSeconds());
6840
6841 // ensure 2 digits are used for each format entry
6842 for(var i = 0; i < format.length; ++i) {
6843 if(format[i].length < 2) {
6844 rval += '0';
6845 }
6846 rval += format[i];
6847 }
6848 rval += 'Z';
6849
6850 return rval;
6851};
6852
6853/**
6854 * Converts a javascript integer to a DER-encoded byte buffer to be used
6855 * as the value for an INTEGER type.
6856 *
6857 * @param x the integer.
6858 *
6859 * @return the byte buffer.
6860 */
6861asn1.integerToDer = function(x) {
6862 var rval = forge.util.createBuffer();
6863 if(x >= -0x80 && x < 0x80) {
6864 return rval.putSignedInt(x, 8);
6865 }
6866 if(x >= -0x8000 && x < 0x8000) {
6867 return rval.putSignedInt(x, 16);
6868 }
6869 if(x >= -0x800000 && x < 0x800000) {
6870 return rval.putSignedInt(x, 24);
6871 }
6872 if(x >= -0x80000000 && x < 0x80000000) {
6873 return rval.putSignedInt(x, 32);
6874 }
6875 var error = new Error('Integer too large; max is 32-bits.');
6876 error.integer = x;
6877 throw error;
6878};
6879
6880/**
6881 * Converts a DER-encoded byte buffer to a javascript integer. This is
6882 * typically used to decode the value of an INTEGER type.
6883 *
6884 * @param bytes the byte buffer.
6885 *
6886 * @return the integer.
6887 */
6888asn1.derToInteger = function(bytes) {
6889 // wrap in buffer if needed
6890 if(typeof bytes === 'string') {
6891 bytes = forge.util.createBuffer(bytes);
6892 }
6893
6894 var n = bytes.length() * 8;
6895 if(n > 32) {
6896 throw new Error('Integer too large; max is 32-bits.');
6897 }
6898 return bytes.getSignedInt(n);
6899};
6900
6901/**
6902 * Validates the that given ASN.1 object is at least a super set of the
6903 * given ASN.1 structure. Only tag classes and types are checked. An
6904 * optional map may also be provided to capture ASN.1 values while the
6905 * structure is checked.
6906 *
6907 * To capture an ASN.1 value, set an object in the validator's 'capture'
6908 * parameter to the key to use in the capture map. To capture the full
6909 * ASN.1 object, specify 'captureAsn1'. To capture BIT STRING bytes, including
6910 * the leading unused bits counter byte, specify 'captureBitStringContents'.
6911 * To capture BIT STRING bytes, without the leading unused bits counter byte,
6912 * specify 'captureBitStringValue'.
6913 *
6914 * Objects in the validator may set a field 'optional' to true to indicate
6915 * that it isn't necessary to pass validation.
6916 *
6917 * @param obj the ASN.1 object to validate.
6918 * @param v the ASN.1 structure validator.
6919 * @param capture an optional map to capture values in.
6920 * @param errors an optional array for storing validation errors.
6921 *
6922 * @return true on success, false on failure.
6923 */
6924asn1.validate = function(obj, v, capture, errors) {
6925 var rval = false;
6926
6927 // ensure tag class and type are the same if specified
6928 if((obj.tagClass === v.tagClass || typeof(v.tagClass) === 'undefined') &&
6929 (obj.type === v.type || typeof(v.type) === 'undefined')) {
6930 // ensure constructed flag is the same if specified
6931 if(obj.constructed === v.constructed ||
6932 typeof(v.constructed) === 'undefined') {
6933 rval = true;
6934
6935 // handle sub values
6936 if(v.value && forge.util.isArray(v.value)) {
6937 var j = 0;
6938 for(var i = 0; rval && i < v.value.length; ++i) {
6939 rval = v.value[i].optional || false;
6940 if(obj.value[j]) {
6941 rval = asn1.validate(obj.value[j], v.value[i], capture, errors);
6942 if(rval) {
6943 ++j;
6944 } else if(v.value[i].optional) {
6945 rval = true;
6946 }
6947 }
6948 if(!rval && errors) {
6949 errors.push(
6950 '[' + v.name + '] ' +
6951 'Tag class "' + v.tagClass + '", type "' +
6952 v.type + '" expected value length "' +
6953 v.value.length + '", got "' +
6954 obj.value.length + '"');
6955 }
6956 }
6957 }
6958
6959 if(rval && capture) {
6960 if(v.capture) {
6961 capture[v.capture] = obj.value;
6962 }
6963 if(v.captureAsn1) {
6964 capture[v.captureAsn1] = obj;
6965 }
6966 if(v.captureBitStringContents && 'bitStringContents' in obj) {
6967 capture[v.captureBitStringContents] = obj.bitStringContents;
6968 }
6969 if(v.captureBitStringValue && 'bitStringContents' in obj) {
6970 var value;
6971 if(obj.bitStringContents.length < 2) {
6972 capture[v.captureBitStringValue] = '';
6973 } else {
6974 // FIXME: support unused bits with data shifting
6975 var unused = obj.bitStringContents.charCodeAt(0);
6976 if(unused !== 0) {
6977 throw new Error(
6978 'captureBitStringValue only supported for zero unused bits');
6979 }
6980 capture[v.captureBitStringValue] = obj.bitStringContents.slice(1);
6981 }
6982 }
6983 }
6984 } else if(errors) {
6985 errors.push(
6986 '[' + v.name + '] ' +
6987 'Expected constructed "' + v.constructed + '", got "' +
6988 obj.constructed + '"');
6989 }
6990 } else if(errors) {
6991 if(obj.tagClass !== v.tagClass) {
6992 errors.push(
6993 '[' + v.name + '] ' +
6994 'Expected tag class "' + v.tagClass + '", got "' +
6995 obj.tagClass + '"');
6996 }
6997 if(obj.type !== v.type) {
6998 errors.push(
6999 '[' + v.name + '] ' +
7000 'Expected type "' + v.type + '", got "' + obj.type + '"');
7001 }
7002 }
7003 return rval;
7004};
7005
7006// regex for testing for non-latin characters
7007var _nonLatinRegex = /[^\\u0000-\\u00ff]/;
7008
7009/**
7010 * Pretty prints an ASN.1 object to a string.
7011 *
7012 * @param obj the object to write out.
7013 * @param level the level in the tree.
7014 * @param indentation the indentation to use.
7015 *
7016 * @return the string.
7017 */
7018asn1.prettyPrint = function(obj, level, indentation) {
7019 var rval = '';
7020
7021 // set default level and indentation
7022 level = level || 0;
7023 indentation = indentation || 2;
7024
7025 // start new line for deep levels
7026 if(level > 0) {
7027 rval += '\n';
7028 }
7029
7030 // create indent
7031 var indent = '';
7032 for(var i = 0; i < level * indentation; ++i) {
7033 indent += ' ';
7034 }
7035
7036 // print class:type
7037 rval += indent + 'Tag: ';
7038 switch(obj.tagClass) {
7039 case asn1.Class.UNIVERSAL:
7040 rval += 'Universal:';
7041 break;
7042 case asn1.Class.APPLICATION:
7043 rval += 'Application:';
7044 break;
7045 case asn1.Class.CONTEXT_SPECIFIC:
7046 rval += 'Context-Specific:';
7047 break;
7048 case asn1.Class.PRIVATE:
7049 rval += 'Private:';
7050 break;
7051 }
7052
7053 if(obj.tagClass === asn1.Class.UNIVERSAL) {
7054 rval += obj.type;
7055
7056 // known types
7057 switch(obj.type) {
7058 case asn1.Type.NONE:
7059 rval += ' (None)';
7060 break;
7061 case asn1.Type.BOOLEAN:
7062 rval += ' (Boolean)';
7063 break;
7064 case asn1.Type.INTEGER:
7065 rval += ' (Integer)';
7066 break;
7067 case asn1.Type.BITSTRING:
7068 rval += ' (Bit string)';
7069 break;
7070 case asn1.Type.OCTETSTRING:
7071 rval += ' (Octet string)';
7072 break;
7073 case asn1.Type.NULL:
7074 rval += ' (Null)';
7075 break;
7076 case asn1.Type.OID:
7077 rval += ' (Object Identifier)';
7078 break;
7079 case asn1.Type.ODESC:
7080 rval += ' (Object Descriptor)';
7081 break;
7082 case asn1.Type.EXTERNAL:
7083 rval += ' (External or Instance of)';
7084 break;
7085 case asn1.Type.REAL:
7086 rval += ' (Real)';
7087 break;
7088 case asn1.Type.ENUMERATED:
7089 rval += ' (Enumerated)';
7090 break;
7091 case asn1.Type.EMBEDDED:
7092 rval += ' (Embedded PDV)';
7093 break;
7094 case asn1.Type.UTF8:
7095 rval += ' (UTF8)';
7096 break;
7097 case asn1.Type.ROID:
7098 rval += ' (Relative Object Identifier)';
7099 break;
7100 case asn1.Type.SEQUENCE:
7101 rval += ' (Sequence)';
7102 break;
7103 case asn1.Type.SET:
7104 rval += ' (Set)';
7105 break;
7106 case asn1.Type.PRINTABLESTRING:
7107 rval += ' (Printable String)';
7108 break;
7109 case asn1.Type.IA5String:
7110 rval += ' (IA5String (ASCII))';
7111 break;
7112 case asn1.Type.UTCTIME:
7113 rval += ' (UTC time)';
7114 break;
7115 case asn1.Type.GENERALIZEDTIME:
7116 rval += ' (Generalized time)';
7117 break;
7118 case asn1.Type.BMPSTRING:
7119 rval += ' (BMP String)';
7120 break;
7121 }
7122 } else {
7123 rval += obj.type;
7124 }
7125
7126 rval += '\n';
7127 rval += indent + 'Constructed: ' + obj.constructed + '\n';
7128
7129 if(obj.composed) {
7130 var subvalues = 0;
7131 var sub = '';
7132 for(var i = 0; i < obj.value.length; ++i) {
7133 if(obj.value[i] !== undefined) {
7134 subvalues += 1;
7135 sub += asn1.prettyPrint(obj.value[i], level + 1, indentation);
7136 if((i + 1) < obj.value.length) {
7137 sub += ',';
7138 }
7139 }
7140 }
7141 rval += indent + 'Sub values: ' + subvalues + sub;
7142 } else {
7143 rval += indent + 'Value: ';
7144 if(obj.type === asn1.Type.OID) {
7145 var oid = asn1.derToOid(obj.value);
7146 rval += oid;
7147 if(forge.pki && forge.pki.oids) {
7148 if(oid in forge.pki.oids) {
7149 rval += ' (' + forge.pki.oids[oid] + ') ';
7150 }
7151 }
7152 }
7153 if(obj.type === asn1.Type.INTEGER) {
7154 try {
7155 rval += asn1.derToInteger(obj.value);
7156 } catch(ex) {
7157 rval += '0x' + forge.util.bytesToHex(obj.value);
7158 }
7159 } else if(obj.type === asn1.Type.BITSTRING) {
7160 // TODO: shift bits as needed to display without padding
7161 if(obj.value.length > 1) {
7162 // remove unused bits field
7163 rval += '0x' + forge.util.bytesToHex(obj.value.slice(1));
7164 } else {
7165 rval += '(none)';
7166 }
7167 // show unused bit count
7168 if(obj.value.length > 0) {
7169 var unused = obj.value.charCodeAt(0);
7170 if(unused == 1) {
7171 rval += ' (1 unused bit shown)';
7172 } else if(unused > 1) {
7173 rval += ' (' + unused + ' unused bits shown)';
7174 }
7175 }
7176 } else if(obj.type === asn1.Type.OCTETSTRING) {
7177 if(!_nonLatinRegex.test(obj.value)) {
7178 rval += '(' + obj.value + ') ';
7179 }
7180 rval += '0x' + forge.util.bytesToHex(obj.value);
7181 } else if(obj.type === asn1.Type.UTF8) {
7182 rval += forge.util.decodeUtf8(obj.value);
7183 } else if(obj.type === asn1.Type.PRINTABLESTRING ||
7184 obj.type === asn1.Type.IA5String) {
7185 rval += obj.value;
7186 } else if(_nonLatinRegex.test(obj.value)) {
7187 rval += '0x' + forge.util.bytesToHex(obj.value);
7188 } else if(obj.value.length === 0) {
7189 rval += '[null]';
7190 } else {
7191 rval += obj.value;
7192 }
7193 }
7194
7195 return rval;
7196};
7197
7198} // end module implementation
7199
7200/* ########## Begin module wrapper ########## */
7201var name = 'asn1';
7202if(typeof define !== 'function') {
7203 // NodeJS -> AMD
7204 if(typeof module === 'object' && module.exports) {
7205 var nodeJS = true;
7206 define = function(ids, factory) {
7207 factory(require, module);
7208 };
7209 } else {
7210 // <script>
7211 if(typeof forge === 'undefined') {
7212 forge = {};
7213 }
7214 return initModule(forge);
7215 }
7216}
7217// AMD
7218var deps;
7219var defineFunc = function(require, module) {
7220 module.exports = function(forge) {
7221 var mods = deps.map(function(dep) {
7222 return require(dep);
7223 }).concat(initModule);
7224 // handle circular dependencies
7225 forge = forge || {};
7226 forge.defined = forge.defined || {};
7227 if(forge.defined[name]) {
7228 return forge[name];
7229 }
7230 forge.defined[name] = true;
7231 for(var i = 0; i < mods.length; ++i) {
7232 mods[i](forge);
7233 }
7234 return forge[name];
7235 };
7236};
7237var tmpDefine = define;
7238define = function(ids, factory) {
7239 deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
7240 if(nodeJS) {
7241 delete define;
7242 return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
7243 }
7244 define = tmpDefine;
7245 return define.apply(null, Array.prototype.slice.call(arguments, 0));
7246};
7247define(['require', 'module', './util', './oids'], function() {
7248 defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
7249});
7250})();
7251
7252/**
7253 * Secure Hash Algorithm with 160-bit digest (SHA-1) implementation.
7254 *
7255 * @author Dave Longley
7256 *
7257 * Copyright (c) 2010-2015 Digital Bazaar, Inc.
7258 */
7259(function() {
7260/* ########## Begin module implementation ########## */
7261function initModule(forge) {
7262
7263var sha1 = forge.sha1 = forge.sha1 || {};
7264forge.md = forge.md || {};
7265forge.md.algorithms = forge.md.algorithms || {};
7266forge.md.sha1 = forge.md.algorithms.sha1 = sha1;
7267
7268/**
7269 * Creates a SHA-1 message digest object.
7270 *
7271 * @return a message digest object.
7272 */
7273sha1.create = function() {
7274 // do initialization as necessary
7275 if(!_initialized) {
7276 _init();
7277 }
7278
7279 // SHA-1 state contains five 32-bit integers
7280 var _state = null;
7281
7282 // input buffer
7283 var _input = forge.util.createBuffer();
7284
7285 // used for word storage
7286 var _w = new Array(80);
7287
7288 // message digest object
7289 var md = {
7290 algorithm: 'sha1',
7291 blockLength: 64,
7292 digestLength: 20,
7293 // 56-bit length of message so far (does not including padding)
7294 messageLength: 0,
7295 // true message length
7296 fullMessageLength: null,
7297 // size of message length in bytes
7298 messageLengthSize: 8
7299 };
7300
7301 /**
7302 * Starts the digest.
7303 *
7304 * @return this digest object.
7305 */
7306 md.start = function() {
7307 // up to 56-bit message length for convenience
7308 md.messageLength = 0;
7309
7310 // full message length (set md.messageLength64 for backwards-compatibility)
7311 md.fullMessageLength = md.messageLength64 = [];
7312 var int32s = md.messageLengthSize / 4;
7313 for(var i = 0; i < int32s; ++i) {
7314 md.fullMessageLength.push(0);
7315 }
7316 _input = forge.util.createBuffer();
7317 _state = {
7318 h0: 0x67452301,
7319 h1: 0xEFCDAB89,
7320 h2: 0x98BADCFE,
7321 h3: 0x10325476,
7322 h4: 0xC3D2E1F0
7323 };
7324 return md;
7325 };
7326 // start digest automatically for first time
7327 md.start();
7328
7329 /**
7330 * Updates the digest with the given message input. The given input can
7331 * treated as raw input (no encoding will be applied) or an encoding of
7332 * 'utf8' maybe given to encode the input using UTF-8.
7333 *
7334 * @param msg the message input to update with.
7335 * @param encoding the encoding to use (default: 'raw', other: 'utf8').
7336 *
7337 * @return this digest object.
7338 */
7339 md.update = function(msg, encoding) {
7340 if(encoding === 'utf8') {
7341 msg = forge.util.encodeUtf8(msg);
7342 }
7343
7344 // update message length
7345 var len = msg.length;
7346 md.messageLength += len;
7347 len = [(len / 0x100000000) >>> 0, len >>> 0];
7348 for(var i = md.fullMessageLength.length - 1; i >= 0; --i) {
7349 md.fullMessageLength[i] += len[1];
7350 len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0);
7351 md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0;
7352 len[0] = ((len[1] / 0x100000000) >>> 0);
7353 }
7354
7355 // add bytes to input buffer
7356 _input.putBytes(msg);
7357
7358 // process bytes
7359 _update(_state, _w, _input);
7360
7361 // compact input buffer every 2K or if empty
7362 if(_input.read > 2048 || _input.length() === 0) {
7363 _input.compact();
7364 }
7365
7366 return md;
7367 };
7368
7369 /**
7370 * Produces the digest.
7371 *
7372 * @return a byte buffer containing the digest value.
7373 */
7374 md.digest = function() {
7375 /* Note: Here we copy the remaining bytes in the input buffer and
7376 add the appropriate SHA-1 padding. Then we do the final update
7377 on a copy of the state so that if the user wants to get
7378 intermediate digests they can do so. */
7379
7380 /* Determine the number of bytes that must be added to the message
7381 to ensure its length is congruent to 448 mod 512. In other words,
7382 the data to be digested must be a multiple of 512 bits (or 128 bytes).
7383 This data includes the message, some padding, and the length of the
7384 message. Since the length of the message will be encoded as 8 bytes (64
7385 bits), that means that the last segment of the data must have 56 bytes
7386 (448 bits) of message and padding. Therefore, the length of the message
7387 plus the padding must be congruent to 448 mod 512 because
7388 512 - 128 = 448.
7389
7390 In order to fill up the message length it must be filled with
7391 padding that begins with 1 bit followed by all 0 bits. Padding
7392 must *always* be present, so if the message length is already
7393 congruent to 448 mod 512, then 512 padding bits must be added. */
7394
7395 var finalBlock = forge.util.createBuffer();
7396 finalBlock.putBytes(_input.bytes());
7397
7398 // compute remaining size to be digested (include message length size)
7399 var remaining = (
7400 md.fullMessageLength[md.fullMessageLength.length - 1] +
7401 md.messageLengthSize);
7402
7403 // add padding for overflow blockSize - overflow
7404 // _padding starts with 1 byte with first bit is set (byte value 128), then
7405 // there may be up to (blockSize - 1) other pad bytes
7406 var overflow = remaining & (md.blockLength - 1);
7407 finalBlock.putBytes(_padding.substr(0, md.blockLength - overflow));
7408
7409 // serialize message length in bits in big-endian order; since length
7410 // is stored in bytes we multiply by 8 and add carry from next int
7411 var next, carry;
7412 var bits = md.fullMessageLength[0] * 8;
7413 for(var i = 0; i < md.fullMessageLength.length - 1; ++i) {
7414 next = md.fullMessageLength[i + 1] * 8;
7415 carry = (next / 0x100000000) >>> 0;
7416 bits += carry;
7417 finalBlock.putInt32(bits >>> 0);
7418 bits = next >>> 0;
7419 }
7420 finalBlock.putInt32(bits);
7421
7422 var s2 = {
7423 h0: _state.h0,
7424 h1: _state.h1,
7425 h2: _state.h2,
7426 h3: _state.h3,
7427 h4: _state.h4
7428 };
7429 _update(s2, _w, finalBlock);
7430 var rval = forge.util.createBuffer();
7431 rval.putInt32(s2.h0);
7432 rval.putInt32(s2.h1);
7433 rval.putInt32(s2.h2);
7434 rval.putInt32(s2.h3);
7435 rval.putInt32(s2.h4);
7436 return rval;
7437 };
7438
7439 return md;
7440};
7441
7442// sha-1 padding bytes not initialized yet
7443var _padding = null;
7444var _initialized = false;
7445
7446/**
7447 * Initializes the constant tables.
7448 */
7449function _init() {
7450 // create padding
7451 _padding = String.fromCharCode(128);
7452 _padding += forge.util.fillString(String.fromCharCode(0x00), 64);
7453
7454 // now initialized
7455 _initialized = true;
7456}
7457
7458/**
7459 * Updates a SHA-1 state with the given byte buffer.
7460 *
7461 * @param s the SHA-1 state to update.
7462 * @param w the array to use to store words.
7463 * @param bytes the byte buffer to update with.
7464 */
7465function _update(s, w, bytes) {
7466 // consume 512 bit (64 byte) chunks
7467 var t, a, b, c, d, e, f, i;
7468 var len = bytes.length();
7469 while(len >= 64) {
7470 // the w array will be populated with sixteen 32-bit big-endian words
7471 // and then extended into 80 32-bit words according to SHA-1 algorithm
7472 // and for 32-79 using Max Locktyukhin's optimization
7473
7474 // initialize hash value for this chunk
7475 a = s.h0;
7476 b = s.h1;
7477 c = s.h2;
7478 d = s.h3;
7479 e = s.h4;
7480
7481 // round 1
7482 for(i = 0; i < 16; ++i) {
7483 t = bytes.getInt32();
7484 w[i] = t;
7485 f = d ^ (b & (c ^ d));
7486 t = ((a << 5) | (a >>> 27)) + f + e + 0x5A827999 + t;
7487 e = d;
7488 d = c;
7489 // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug
7490 c = ((b << 30) | (b >>> 2)) >>> 0;
7491 b = a;
7492 a = t;
7493 }
7494 for(; i < 20; ++i) {
7495 t = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]);
7496 t = (t << 1) | (t >>> 31);
7497 w[i] = t;
7498 f = d ^ (b & (c ^ d));
7499 t = ((a << 5) | (a >>> 27)) + f + e + 0x5A827999 + t;
7500 e = d;
7501 d = c;
7502 // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug
7503 c = ((b << 30) | (b >>> 2)) >>> 0;
7504 b = a;
7505 a = t;
7506 }
7507 // round 2
7508 for(; i < 32; ++i) {
7509 t = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]);
7510 t = (t << 1) | (t >>> 31);
7511 w[i] = t;
7512 f = b ^ c ^ d;
7513 t = ((a << 5) | (a >>> 27)) + f + e + 0x6ED9EBA1 + t;
7514 e = d;
7515 d = c;
7516 // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug
7517 c = ((b << 30) | (b >>> 2)) >>> 0;
7518 b = a;
7519 a = t;
7520 }
7521 for(; i < 40; ++i) {
7522 t = (w[i - 6] ^ w[i - 16] ^ w[i - 28] ^ w[i - 32]);
7523 t = (t << 2) | (t >>> 30);
7524 w[i] = t;
7525 f = b ^ c ^ d;
7526 t = ((a << 5) | (a >>> 27)) + f + e + 0x6ED9EBA1 + t;
7527 e = d;
7528 d = c;
7529 // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug
7530 c = ((b << 30) | (b >>> 2)) >>> 0;
7531 b = a;
7532 a = t;
7533 }
7534 // round 3
7535 for(; i < 60; ++i) {
7536 t = (w[i - 6] ^ w[i - 16] ^ w[i - 28] ^ w[i - 32]);
7537 t = (t << 2) | (t >>> 30);
7538 w[i] = t;
7539 f = (b & c) | (d & (b ^ c));
7540 t = ((a << 5) | (a >>> 27)) + f + e + 0x8F1BBCDC + t;
7541 e = d;
7542 d = c;
7543 // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug
7544 c = ((b << 30) | (b >>> 2)) >>> 0;
7545 b = a;
7546 a = t;
7547 }
7548 // round 4
7549 for(; i < 80; ++i) {
7550 t = (w[i - 6] ^ w[i - 16] ^ w[i - 28] ^ w[i - 32]);
7551 t = (t << 2) | (t >>> 30);
7552 w[i] = t;
7553 f = b ^ c ^ d;
7554 t = ((a << 5) | (a >>> 27)) + f + e + 0xCA62C1D6 + t;
7555 e = d;
7556 d = c;
7557 // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug
7558 c = ((b << 30) | (b >>> 2)) >>> 0;
7559 b = a;
7560 a = t;
7561 }
7562
7563 // update hash state
7564 s.h0 = (s.h0 + a) | 0;
7565 s.h1 = (s.h1 + b) | 0;
7566 s.h2 = (s.h2 + c) | 0;
7567 s.h3 = (s.h3 + d) | 0;
7568 s.h4 = (s.h4 + e) | 0;
7569
7570 len -= 64;
7571 }
7572}
7573
7574} // end module implementation
7575
7576/* ########## Begin module wrapper ########## */
7577var name = 'sha1';
7578if(typeof define !== 'function') {
7579 // NodeJS -> AMD
7580 if(typeof module === 'object' && module.exports) {
7581 var nodeJS = true;
7582 define = function(ids, factory) {
7583 factory(require, module);
7584 };
7585 } else {
7586 // <script>
7587 if(typeof forge === 'undefined') {
7588 forge = {};
7589 }
7590 return initModule(forge);
7591 }
7592}
7593// AMD
7594var deps;
7595var defineFunc = function(require, module) {
7596 module.exports = function(forge) {
7597 var mods = deps.map(function(dep) {
7598 return require(dep);
7599 }).concat(initModule);
7600 // handle circular dependencies
7601 forge = forge || {};
7602 forge.defined = forge.defined || {};
7603 if(forge.defined[name]) {
7604 return forge[name];
7605 }
7606 forge.defined[name] = true;
7607 for(var i = 0; i < mods.length; ++i) {
7608 mods[i](forge);
7609 }
7610 return forge[name];
7611 };
7612};
7613var tmpDefine = define;
7614define = function(ids, factory) {
7615 deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
7616 if(nodeJS) {
7617 delete define;
7618 return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
7619 }
7620 define = tmpDefine;
7621 return define.apply(null, Array.prototype.slice.call(arguments, 0));
7622};
7623define(['require', 'module', './util'], function() {
7624 defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
7625});
7626})();
7627
7628/**
7629 * Secure Hash Algorithm with 256-bit digest (SHA-256) implementation.
7630 *
7631 * See FIPS 180-2 for details.
7632 *
7633 * @author Dave Longley
7634 *
7635 * Copyright (c) 2010-2015 Digital Bazaar, Inc.
7636 */
7637(function() {
7638/* ########## Begin module implementation ########## */
7639function initModule(forge) {
7640
7641var sha256 = forge.sha256 = forge.sha256 || {};
7642forge.md = forge.md || {};
7643forge.md.algorithms = forge.md.algorithms || {};
7644forge.md.sha256 = forge.md.algorithms.sha256 = sha256;
7645
7646/**
7647 * Creates a SHA-256 message digest object.
7648 *
7649 * @return a message digest object.
7650 */
7651sha256.create = function() {
7652 // do initialization as necessary
7653 if(!_initialized) {
7654 _init();
7655 }
7656
7657 // SHA-256 state contains eight 32-bit integers
7658 var _state = null;
7659
7660 // input buffer
7661 var _input = forge.util.createBuffer();
7662
7663 // used for word storage
7664 var _w = new Array(64);
7665
7666 // message digest object
7667 var md = {
7668 algorithm: 'sha256',
7669 blockLength: 64,
7670 digestLength: 32,
7671 // 56-bit length of message so far (does not including padding)
7672 messageLength: 0,
7673 // true message length
7674 fullMessageLength: null,
7675 // size of message length in bytes
7676 messageLengthSize: 8
7677 };
7678
7679 /**
7680 * Starts the digest.
7681 *
7682 * @return this digest object.
7683 */
7684 md.start = function() {
7685 // up to 56-bit message length for convenience
7686 md.messageLength = 0;
7687
7688 // full message length (set md.messageLength64 for backwards-compatibility)
7689 md.fullMessageLength = md.messageLength64 = [];
7690 var int32s = md.messageLengthSize / 4;
7691 for(var i = 0; i < int32s; ++i) {
7692 md.fullMessageLength.push(0);
7693 }
7694 _input = forge.util.createBuffer();
7695 _state = {
7696 h0: 0x6A09E667,
7697 h1: 0xBB67AE85,
7698 h2: 0x3C6EF372,
7699 h3: 0xA54FF53A,
7700 h4: 0x510E527F,
7701 h5: 0x9B05688C,
7702 h6: 0x1F83D9AB,
7703 h7: 0x5BE0CD19
7704 };
7705 return md;
7706 };
7707 // start digest automatically for first time
7708 md.start();
7709
7710 /**
7711 * Updates the digest with the given message input. The given input can
7712 * treated as raw input (no encoding will be applied) or an encoding of
7713 * 'utf8' maybe given to encode the input using UTF-8.
7714 *
7715 * @param msg the message input to update with.
7716 * @param encoding the encoding to use (default: 'raw', other: 'utf8').
7717 *
7718 * @return this digest object.
7719 */
7720 md.update = function(msg, encoding) {
7721 if(encoding === 'utf8') {
7722 msg = forge.util.encodeUtf8(msg);
7723 }
7724
7725 // update message length
7726 var len = msg.length;
7727 md.messageLength += len;
7728 len = [(len / 0x100000000) >>> 0, len >>> 0];
7729 for(var i = md.fullMessageLength.length - 1; i >= 0; --i) {
7730 md.fullMessageLength[i] += len[1];
7731 len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0);
7732 md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0;
7733 len[0] = ((len[1] / 0x100000000) >>> 0);
7734 }
7735
7736 // add bytes to input buffer
7737 _input.putBytes(msg);
7738
7739 // process bytes
7740 _update(_state, _w, _input);
7741
7742 // compact input buffer every 2K or if empty
7743 if(_input.read > 2048 || _input.length() === 0) {
7744 _input.compact();
7745 }
7746
7747 return md;
7748 };
7749
7750 /**
7751 * Produces the digest.
7752 *
7753 * @return a byte buffer containing the digest value.
7754 */
7755 md.digest = function() {
7756 /* Note: Here we copy the remaining bytes in the input buffer and
7757 add the appropriate SHA-256 padding. Then we do the final update
7758 on a copy of the state so that if the user wants to get
7759 intermediate digests they can do so. */
7760
7761 /* Determine the number of bytes that must be added to the message
7762 to ensure its length is congruent to 448 mod 512. In other words,
7763 the data to be digested must be a multiple of 512 bits (or 128 bytes).
7764 This data includes the message, some padding, and the length of the
7765 message. Since the length of the message will be encoded as 8 bytes (64
7766 bits), that means that the last segment of the data must have 56 bytes
7767 (448 bits) of message and padding. Therefore, the length of the message
7768 plus the padding must be congruent to 448 mod 512 because
7769 512 - 128 = 448.
7770
7771 In order to fill up the message length it must be filled with
7772 padding that begins with 1 bit followed by all 0 bits. Padding
7773 must *always* be present, so if the message length is already
7774 congruent to 448 mod 512, then 512 padding bits must be added. */
7775
7776 var finalBlock = forge.util.createBuffer();
7777 finalBlock.putBytes(_input.bytes());
7778
7779 // compute remaining size to be digested (include message length size)
7780 var remaining = (
7781 md.fullMessageLength[md.fullMessageLength.length - 1] +
7782 md.messageLengthSize);
7783
7784 // add padding for overflow blockSize - overflow
7785 // _padding starts with 1 byte with first bit is set (byte value 128), then
7786 // there may be up to (blockSize - 1) other pad bytes
7787 var overflow = remaining & (md.blockLength - 1);
7788 finalBlock.putBytes(_padding.substr(0, md.blockLength - overflow));
7789
7790 // serialize message length in bits in big-endian order; since length
7791 // is stored in bytes we multiply by 8 and add carry from next int
7792 var next, carry;
7793 var bits = md.fullMessageLength[0] * 8;
7794 for(var i = 0; i < md.fullMessageLength.length - 1; ++i) {
7795 next = md.fullMessageLength[i + 1] * 8;
7796 carry = (next / 0x100000000) >>> 0;
7797 bits += carry;
7798 finalBlock.putInt32(bits >>> 0);
7799 bits = next >>> 0;
7800 }
7801 finalBlock.putInt32(bits);
7802
7803 var s2 = {
7804 h0: _state.h0,
7805 h1: _state.h1,
7806 h2: _state.h2,
7807 h3: _state.h3,
7808 h4: _state.h4,
7809 h5: _state.h5,
7810 h6: _state.h6,
7811 h7: _state.h7
7812 };
7813 _update(s2, _w, finalBlock);
7814 var rval = forge.util.createBuffer();
7815 rval.putInt32(s2.h0);
7816 rval.putInt32(s2.h1);
7817 rval.putInt32(s2.h2);
7818 rval.putInt32(s2.h3);
7819 rval.putInt32(s2.h4);
7820 rval.putInt32(s2.h5);
7821 rval.putInt32(s2.h6);
7822 rval.putInt32(s2.h7);
7823 return rval;
7824 };
7825
7826 return md;
7827};
7828
7829// sha-256 padding bytes not initialized yet
7830var _padding = null;
7831var _initialized = false;
7832
7833// table of constants
7834var _k = null;
7835
7836/**
7837 * Initializes the constant tables.
7838 */
7839function _init() {
7840 // create padding
7841 _padding = String.fromCharCode(128);
7842 _padding += forge.util.fillString(String.fromCharCode(0x00), 64);
7843
7844 // create K table for SHA-256
7845 _k = [
7846 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
7847 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
7848 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
7849 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
7850 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
7851 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
7852 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
7853 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
7854 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
7855 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
7856 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
7857 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
7858 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
7859 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
7860 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
7861 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];
7862
7863 // now initialized
7864 _initialized = true;
7865}
7866
7867/**
7868 * Updates a SHA-256 state with the given byte buffer.
7869 *
7870 * @param s the SHA-256 state to update.
7871 * @param w the array to use to store words.
7872 * @param bytes the byte buffer to update with.
7873 */
7874function _update(s, w, bytes) {
7875 // consume 512 bit (64 byte) chunks
7876 var t1, t2, s0, s1, ch, maj, i, a, b, c, d, e, f, g, h;
7877 var len = bytes.length();
7878 while(len >= 64) {
7879 // the w array will be populated with sixteen 32-bit big-endian words
7880 // and then extended into 64 32-bit words according to SHA-256
7881 for(i = 0; i < 16; ++i) {
7882 w[i] = bytes.getInt32();
7883 }
7884 for(; i < 64; ++i) {
7885 // XOR word 2 words ago rot right 17, rot right 19, shft right 10
7886 t1 = w[i - 2];
7887 t1 =
7888 ((t1 >>> 17) | (t1 << 15)) ^
7889 ((t1 >>> 19) | (t1 << 13)) ^
7890 (t1 >>> 10);
7891 // XOR word 15 words ago rot right 7, rot right 18, shft right 3
7892 t2 = w[i - 15];
7893 t2 =
7894 ((t2 >>> 7) | (t2 << 25)) ^
7895 ((t2 >>> 18) | (t2 << 14)) ^
7896 (t2 >>> 3);
7897 // sum(t1, word 7 ago, t2, word 16 ago) modulo 2^32
7898 w[i] = (t1 + w[i - 7] + t2 + w[i - 16]) | 0;
7899 }
7900
7901 // initialize hash value for this chunk
7902 a = s.h0;
7903 b = s.h1;
7904 c = s.h2;
7905 d = s.h3;
7906 e = s.h4;
7907 f = s.h5;
7908 g = s.h6;
7909 h = s.h7;
7910
7911 // round function
7912 for(i = 0; i < 64; ++i) {
7913 // Sum1(e)
7914 s1 =
7915 ((e >>> 6) | (e << 26)) ^
7916 ((e >>> 11) | (e << 21)) ^
7917 ((e >>> 25) | (e << 7));
7918 // Ch(e, f, g) (optimized the same way as SHA-1)
7919 ch = g ^ (e & (f ^ g));
7920 // Sum0(a)
7921 s0 =
7922 ((a >>> 2) | (a << 30)) ^
7923 ((a >>> 13) | (a << 19)) ^
7924 ((a >>> 22) | (a << 10));
7925 // Maj(a, b, c) (optimized the same way as SHA-1)
7926 maj = (a & b) | (c & (a ^ b));
7927
7928 // main algorithm
7929 t1 = h + s1 + ch + _k[i] + w[i];
7930 t2 = s0 + maj;
7931 h = g;
7932 g = f;
7933 f = e;
7934 // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug
7935 // can't truncate with `| 0`
7936 e = (d + t1) >>> 0;
7937 d = c;
7938 c = b;
7939 b = a;
7940 // `>>> 0` necessary to avoid iOS/Safari 10 optimization bug
7941 // can't truncate with `| 0`
7942 a = (t1 + t2) >>> 0;
7943 }
7944
7945 // update hash state
7946 s.h0 = (s.h0 + a) | 0;
7947 s.h1 = (s.h1 + b) | 0;
7948 s.h2 = (s.h2 + c) | 0;
7949 s.h3 = (s.h3 + d) | 0;
7950 s.h4 = (s.h4 + e) | 0;
7951 s.h5 = (s.h5 + f) | 0;
7952 s.h6 = (s.h6 + g) | 0;
7953 s.h7 = (s.h7 + h) | 0;
7954 len -= 64;
7955 }
7956}
7957
7958} // end module implementation
7959
7960/* ########## Begin module wrapper ########## */
7961var name = 'sha256';
7962if(typeof define !== 'function') {
7963 // NodeJS -> AMD
7964 if(typeof module === 'object' && module.exports) {
7965 var nodeJS = true;
7966 define = function(ids, factory) {
7967 factory(require, module);
7968 };
7969 } else {
7970 // <script>
7971 if(typeof forge === 'undefined') {
7972 forge = {};
7973 }
7974 return initModule(forge);
7975 }
7976}
7977// AMD
7978var deps;
7979var defineFunc = function(require, module) {
7980 module.exports = function(forge) {
7981 var mods = deps.map(function(dep) {
7982 return require(dep);
7983 }).concat(initModule);
7984 // handle circular dependencies
7985 forge = forge || {};
7986 forge.defined = forge.defined || {};
7987 if(forge.defined[name]) {
7988 return forge[name];
7989 }
7990 forge.defined[name] = true;
7991 for(var i = 0; i < mods.length; ++i) {
7992 mods[i](forge);
7993 }
7994 return forge[name];
7995 };
7996};
7997var tmpDefine = define;
7998define = function(ids, factory) {
7999 deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
8000 if(nodeJS) {
8001 delete define;
8002 return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
8003 }
8004 define = tmpDefine;
8005 return define.apply(null, Array.prototype.slice.call(arguments, 0));
8006};
8007define(['require', 'module', './util'], function() {
8008 defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
8009});
8010})();
8011
8012/**
8013 * Secure Hash Algorithm with a 1024-bit block size implementation.
8014 *
8015 * This includes: SHA-512, SHA-384, SHA-512/224, and SHA-512/256. For
8016 * SHA-256 (block size 512 bits), see sha256.js.
8017 *
8018 * See FIPS 180-4 for details.
8019 *
8020 * @author Dave Longley
8021 *
8022 * Copyright (c) 2014-2015 Digital Bazaar, Inc.
8023 */
8024(function() {
8025/* ########## Begin module implementation ########## */
8026function initModule(forge) {
8027
8028var sha512 = forge.sha512 = forge.sha512 || {};
8029forge.md = forge.md || {};
8030forge.md.algorithms = forge.md.algorithms || {};
8031
8032// SHA-512
8033forge.md.sha512 = forge.md.algorithms.sha512 = sha512;
8034
8035// SHA-384
8036var sha384 = forge.sha384 = forge.sha512.sha384 = forge.sha512.sha384 || {};
8037sha384.create = function() {
8038 return sha512.create('SHA-384');
8039};
8040forge.md.sha384 = forge.md.algorithms.sha384 = sha384;
8041
8042// SHA-512/256
8043forge.sha512.sha256 = forge.sha512.sha256 || {
8044 create: function() {
8045 return sha512.create('SHA-512/256');
8046 }
8047};
8048forge.md['sha512/256'] = forge.md.algorithms['sha512/256'] =
8049 forge.sha512.sha256;
8050
8051// SHA-512/224
8052forge.sha512.sha224 = forge.sha512.sha224 || {
8053 create: function() {
8054 return sha512.create('SHA-512/224');
8055 }
8056};
8057forge.md['sha512/224'] = forge.md.algorithms['sha512/224'] =
8058 forge.sha512.sha224;
8059
8060/**
8061 * Creates a SHA-2 message digest object.
8062 *
8063 * @param algorithm the algorithm to use (SHA-512, SHA-384, SHA-512/224,
8064 * SHA-512/256).
8065 *
8066 * @return a message digest object.
8067 */
8068sha512.create = function(algorithm) {
8069 // do initialization as necessary
8070 if(!_initialized) {
8071 _init();
8072 }
8073
8074 if(typeof algorithm === 'undefined') {
8075 algorithm = 'SHA-512';
8076 }
8077
8078 if(!(algorithm in _states)) {
8079 throw new Error('Invalid SHA-512 algorithm: ' + algorithm);
8080 }
8081
8082 // SHA-512 state contains eight 64-bit integers (each as two 32-bit ints)
8083 var _state = _states[algorithm];
8084 var _h = null;
8085
8086 // input buffer
8087 var _input = forge.util.createBuffer();
8088
8089 // used for 64-bit word storage
8090 var _w = new Array(80);
8091 for(var wi = 0; wi < 80; ++wi) {
8092 _w[wi] = new Array(2);
8093 }
8094
8095 // message digest object
8096 var md = {
8097 // SHA-512 => sha512
8098 algorithm: algorithm.replace('-', '').toLowerCase(),
8099 blockLength: 128,
8100 digestLength: 64,
8101 // 56-bit length of message so far (does not including padding)
8102 messageLength: 0,
8103 // true message length
8104 fullMessageLength: null,
8105 // size of message length in bytes
8106 messageLengthSize: 16
8107 };
8108
8109 /**
8110 * Starts the digest.
8111 *
8112 * @return this digest object.
8113 */
8114 md.start = function() {
8115 // up to 56-bit message length for convenience
8116 md.messageLength = 0;
8117
8118 // full message length (set md.messageLength128 for backwards-compatibility)
8119 md.fullMessageLength = md.messageLength128 = [];
8120 var int32s = md.messageLengthSize / 4;
8121 for(var i = 0; i < int32s; ++i) {
8122 md.fullMessageLength.push(0);
8123 }
8124 _input = forge.util.createBuffer();
8125 _h = new Array(_state.length);
8126 for(var i = 0; i < _state.length; ++i) {
8127 _h[i] = _state[i].slice(0);
8128 }
8129 return md;
8130 };
8131 // start digest automatically for first time
8132 md.start();
8133
8134 /**
8135 * Updates the digest with the given message input. The given input can
8136 * treated as raw input (no encoding will be applied) or an encoding of
8137 * 'utf8' maybe given to encode the input using UTF-8.
8138 *
8139 * @param msg the message input to update with.
8140 * @param encoding the encoding to use (default: 'raw', other: 'utf8').
8141 *
8142 * @return this digest object.
8143 */
8144 md.update = function(msg, encoding) {
8145 if(encoding === 'utf8') {
8146 msg = forge.util.encodeUtf8(msg);
8147 }
8148
8149 // update message length
8150 var len = msg.length;
8151 md.messageLength += len;
8152 len = [(len / 0x100000000) >>> 0, len >>> 0];
8153 for(var i = md.fullMessageLength.length - 1; i >= 0; --i) {
8154 md.fullMessageLength[i] += len[1];
8155 len[1] = len[0] + ((md.fullMessageLength[i] / 0x100000000) >>> 0);
8156 md.fullMessageLength[i] = md.fullMessageLength[i] >>> 0;
8157 len[0] = ((len[1] / 0x100000000) >>> 0);
8158 }
8159
8160 // add bytes to input buffer
8161 _input.putBytes(msg);
8162
8163 // process bytes
8164 _update(_h, _w, _input);
8165
8166 // compact input buffer every 2K or if empty
8167 if(_input.read > 2048 || _input.length() === 0) {
8168 _input.compact();
8169 }
8170
8171 return md;
8172 };
8173
8174 /**
8175 * Produces the digest.
8176 *
8177 * @return a byte buffer containing the digest value.
8178 */
8179 md.digest = function() {
8180 /* Note: Here we copy the remaining bytes in the input buffer and
8181 add the appropriate SHA-512 padding. Then we do the final update
8182 on a copy of the state so that if the user wants to get
8183 intermediate digests they can do so. */
8184
8185 /* Determine the number of bytes that must be added to the message
8186 to ensure its length is congruent to 896 mod 1024. In other words,
8187 the data to be digested must be a multiple of 1024 bits (or 128 bytes).
8188 This data includes the message, some padding, and the length of the
8189 message. Since the length of the message will be encoded as 16 bytes (128
8190 bits), that means that the last segment of the data must have 112 bytes
8191 (896 bits) of message and padding. Therefore, the length of the message
8192 plus the padding must be congruent to 896 mod 1024 because
8193 1024 - 128 = 896.
8194
8195 In order to fill up the message length it must be filled with
8196 padding that begins with 1 bit followed by all 0 bits. Padding
8197 must *always* be present, so if the message length is already
8198 congruent to 896 mod 1024, then 1024 padding bits must be added. */
8199
8200 var finalBlock = forge.util.createBuffer();
8201 finalBlock.putBytes(_input.bytes());
8202
8203 // compute remaining size to be digested (include message length size)
8204 var remaining = (
8205 md.fullMessageLength[md.fullMessageLength.length - 1] +
8206 md.messageLengthSize);
8207
8208 // add padding for overflow blockSize - overflow
8209 // _padding starts with 1 byte with first bit is set (byte value 128), then
8210 // there may be up to (blockSize - 1) other pad bytes
8211 var overflow = remaining & (md.blockLength - 1);
8212 finalBlock.putBytes(_padding.substr(0, md.blockLength - overflow));
8213
8214 // serialize message length in bits in big-endian order; since length
8215 // is stored in bytes we multiply by 8 and add carry from next int
8216 var next, carry;
8217 var bits = md.fullMessageLength[0] * 8;
8218 for(var i = 0; i < md.fullMessageLength.length - 1; ++i) {
8219 next = md.fullMessageLength[i + 1] * 8;
8220 carry = (next / 0x100000000) >>> 0;
8221 bits += carry;
8222 finalBlock.putInt32(bits >>> 0);
8223 bits = next >>> 0;
8224 }
8225 finalBlock.putInt32(bits);
8226
8227 var h = new Array(_h.length);
8228 for(var i = 0; i < _h.length; ++i) {
8229 h[i] = _h[i].slice(0);
8230 }
8231 _update(h, _w, finalBlock);
8232 var rval = forge.util.createBuffer();
8233 var hlen;
8234 if(algorithm === 'SHA-512') {
8235 hlen = h.length;
8236 } else if(algorithm === 'SHA-384') {
8237 hlen = h.length - 2;
8238 } else {
8239 hlen = h.length - 4;
8240 }
8241 for(var i = 0; i < hlen; ++i) {
8242 rval.putInt32(h[i][0]);
8243 if(i !== hlen - 1 || algorithm !== 'SHA-512/224') {
8244 rval.putInt32(h[i][1]);
8245 }
8246 }
8247 return rval;
8248 };
8249
8250 return md;
8251};
8252
8253// sha-512 padding bytes not initialized yet
8254var _padding = null;
8255var _initialized = false;
8256
8257// table of constants
8258var _k = null;
8259
8260// initial hash states
8261var _states = null;
8262
8263/**
8264 * Initializes the constant tables.
8265 */
8266function _init() {
8267 // create padding
8268 _padding = String.fromCharCode(128);
8269 _padding += forge.util.fillString(String.fromCharCode(0x00), 128);
8270
8271 // create K table for SHA-512
8272 _k = [
8273 [0x428a2f98, 0xd728ae22], [0x71374491, 0x23ef65cd],
8274 [0xb5c0fbcf, 0xec4d3b2f], [0xe9b5dba5, 0x8189dbbc],
8275 [0x3956c25b, 0xf348b538], [0x59f111f1, 0xb605d019],
8276 [0x923f82a4, 0xaf194f9b], [0xab1c5ed5, 0xda6d8118],
8277 [0xd807aa98, 0xa3030242], [0x12835b01, 0x45706fbe],
8278 [0x243185be, 0x4ee4b28c], [0x550c7dc3, 0xd5ffb4e2],
8279 [0x72be5d74, 0xf27b896f], [0x80deb1fe, 0x3b1696b1],
8280 [0x9bdc06a7, 0x25c71235], [0xc19bf174, 0xcf692694],
8281 [0xe49b69c1, 0x9ef14ad2], [0xefbe4786, 0x384f25e3],
8282 [0x0fc19dc6, 0x8b8cd5b5], [0x240ca1cc, 0x77ac9c65],
8283 [0x2de92c6f, 0x592b0275], [0x4a7484aa, 0x6ea6e483],
8284 [0x5cb0a9dc, 0xbd41fbd4], [0x76f988da, 0x831153b5],
8285 [0x983e5152, 0xee66dfab], [0xa831c66d, 0x2db43210],
8286 [0xb00327c8, 0x98fb213f], [0xbf597fc7, 0xbeef0ee4],
8287 [0xc6e00bf3, 0x3da88fc2], [0xd5a79147, 0x930aa725],
8288 [0x06ca6351, 0xe003826f], [0x14292967, 0x0a0e6e70],
8289 [0x27b70a85, 0x46d22ffc], [0x2e1b2138, 0x5c26c926],
8290 [0x4d2c6dfc, 0x5ac42aed], [0x53380d13, 0x9d95b3df],
8291 [0x650a7354, 0x8baf63de], [0x766a0abb, 0x3c77b2a8],
8292 [0x81c2c92e, 0x47edaee6], [0x92722c85, 0x1482353b],
8293 [0xa2bfe8a1, 0x4cf10364], [0xa81a664b, 0xbc423001],
8294 [0xc24b8b70, 0xd0f89791], [0xc76c51a3, 0x0654be30],
8295 [0xd192e819, 0xd6ef5218], [0xd6990624, 0x5565a910],
8296 [0xf40e3585, 0x5771202a], [0x106aa070, 0x32bbd1b8],
8297 [0x19a4c116, 0xb8d2d0c8], [0x1e376c08, 0x5141ab53],
8298 [0x2748774c, 0xdf8eeb99], [0x34b0bcb5, 0xe19b48a8],
8299 [0x391c0cb3, 0xc5c95a63], [0x4ed8aa4a, 0xe3418acb],
8300 [0x5b9cca4f, 0x7763e373], [0x682e6ff3, 0xd6b2b8a3],
8301 [0x748f82ee, 0x5defb2fc], [0x78a5636f, 0x43172f60],
8302 [0x84c87814, 0xa1f0ab72], [0x8cc70208, 0x1a6439ec],
8303 [0x90befffa, 0x23631e28], [0xa4506ceb, 0xde82bde9],
8304 [0xbef9a3f7, 0xb2c67915], [0xc67178f2, 0xe372532b],
8305 [0xca273ece, 0xea26619c], [0xd186b8c7, 0x21c0c207],
8306 [0xeada7dd6, 0xcde0eb1e], [0xf57d4f7f, 0xee6ed178],
8307 [0x06f067aa, 0x72176fba], [0x0a637dc5, 0xa2c898a6],
8308 [0x113f9804, 0xbef90dae], [0x1b710b35, 0x131c471b],
8309 [0x28db77f5, 0x23047d84], [0x32caab7b, 0x40c72493],
8310 [0x3c9ebe0a, 0x15c9bebc], [0x431d67c4, 0x9c100d4c],
8311 [0x4cc5d4be, 0xcb3e42b6], [0x597f299c, 0xfc657e2a],
8312 [0x5fcb6fab, 0x3ad6faec], [0x6c44198c, 0x4a475817]
8313 ];
8314
8315 // initial hash states
8316 _states = {};
8317 _states['SHA-512'] = [
8318 [0x6a09e667, 0xf3bcc908],
8319 [0xbb67ae85, 0x84caa73b],
8320 [0x3c6ef372, 0xfe94f82b],
8321 [0xa54ff53a, 0x5f1d36f1],
8322 [0x510e527f, 0xade682d1],
8323 [0x9b05688c, 0x2b3e6c1f],
8324 [0x1f83d9ab, 0xfb41bd6b],
8325 [0x5be0cd19, 0x137e2179]
8326 ];
8327 _states['SHA-384'] = [
8328 [0xcbbb9d5d, 0xc1059ed8],
8329 [0x629a292a, 0x367cd507],
8330 [0x9159015a, 0x3070dd17],
8331 [0x152fecd8, 0xf70e5939],
8332 [0x67332667, 0xffc00b31],
8333 [0x8eb44a87, 0x68581511],
8334 [0xdb0c2e0d, 0x64f98fa7],
8335 [0x47b5481d, 0xbefa4fa4]
8336 ];
8337 _states['SHA-512/256'] = [
8338 [0x22312194, 0xFC2BF72C],
8339 [0x9F555FA3, 0xC84C64C2],
8340 [0x2393B86B, 0x6F53B151],
8341 [0x96387719, 0x5940EABD],
8342 [0x96283EE2, 0xA88EFFE3],
8343 [0xBE5E1E25, 0x53863992],
8344 [0x2B0199FC, 0x2C85B8AA],
8345 [0x0EB72DDC, 0x81C52CA2]
8346 ];
8347 _states['SHA-512/224'] = [
8348 [0x8C3D37C8, 0x19544DA2],
8349 [0x73E19966, 0x89DCD4D6],
8350 [0x1DFAB7AE, 0x32FF9C82],
8351 [0x679DD514, 0x582F9FCF],
8352 [0x0F6D2B69, 0x7BD44DA8],
8353 [0x77E36F73, 0x04C48942],
8354 [0x3F9D85A8, 0x6A1D36C8],
8355 [0x1112E6AD, 0x91D692A1]
8356 ];
8357
8358 // now initialized
8359 _initialized = true;
8360}
8361
8362/**
8363 * Updates a SHA-512 state with the given byte buffer.
8364 *
8365 * @param s the SHA-512 state to update.
8366 * @param w the array to use to store words.
8367 * @param bytes the byte buffer to update with.
8368 */
8369function _update(s, w, bytes) {
8370 // consume 512 bit (128 byte) chunks
8371 var t1_hi, t1_lo;
8372 var t2_hi, t2_lo;
8373 var s0_hi, s0_lo;
8374 var s1_hi, s1_lo;
8375 var ch_hi, ch_lo;
8376 var maj_hi, maj_lo;
8377 var a_hi, a_lo;
8378 var b_hi, b_lo;
8379 var c_hi, c_lo;
8380 var d_hi, d_lo;
8381 var e_hi, e_lo;
8382 var f_hi, f_lo;
8383 var g_hi, g_lo;
8384 var h_hi, h_lo;
8385 var i, hi, lo, w2, w7, w15, w16;
8386 var len = bytes.length();
8387 while(len >= 128) {
8388 // the w array will be populated with sixteen 64-bit big-endian words
8389 // and then extended into 64 64-bit words according to SHA-512
8390 for(i = 0; i < 16; ++i) {
8391 w[i][0] = bytes.getInt32() >>> 0;
8392 w[i][1] = bytes.getInt32() >>> 0;
8393 }
8394 for(; i < 80; ++i) {
8395 // for word 2 words ago: ROTR 19(x) ^ ROTR 61(x) ^ SHR 6(x)
8396 w2 = w[i - 2];
8397 hi = w2[0];
8398 lo = w2[1];
8399
8400 // high bits
8401 t1_hi = (
8402 ((hi >>> 19) | (lo << 13)) ^ // ROTR 19
8403 ((lo >>> 29) | (hi << 3)) ^ // ROTR 61/(swap + ROTR 29)
8404 (hi >>> 6)) >>> 0; // SHR 6
8405 // low bits
8406 t1_lo = (
8407 ((hi << 13) | (lo >>> 19)) ^ // ROTR 19
8408 ((lo << 3) | (hi >>> 29)) ^ // ROTR 61/(swap + ROTR 29)
8409 ((hi << 26) | (lo >>> 6))) >>> 0; // SHR 6
8410
8411 // for word 15 words ago: ROTR 1(x) ^ ROTR 8(x) ^ SHR 7(x)
8412 w15 = w[i - 15];
8413 hi = w15[0];
8414 lo = w15[1];
8415
8416 // high bits
8417 t2_hi = (
8418 ((hi >>> 1) | (lo << 31)) ^ // ROTR 1
8419 ((hi >>> 8) | (lo << 24)) ^ // ROTR 8
8420 (hi >>> 7)) >>> 0; // SHR 7
8421 // low bits
8422 t2_lo = (
8423 ((hi << 31) | (lo >>> 1)) ^ // ROTR 1
8424 ((hi << 24) | (lo >>> 8)) ^ // ROTR 8
8425 ((hi << 25) | (lo >>> 7))) >>> 0; // SHR 7
8426
8427 // sum(t1, word 7 ago, t2, word 16 ago) modulo 2^64 (carry lo overflow)
8428 w7 = w[i - 7];
8429 w16 = w[i - 16];
8430 lo = (t1_lo + w7[1] + t2_lo + w16[1]);
8431 w[i][0] = (t1_hi + w7[0] + t2_hi + w16[0] +
8432 ((lo / 0x100000000) >>> 0)) >>> 0;
8433 w[i][1] = lo >>> 0;
8434 }
8435
8436 // initialize hash value for this chunk
8437 a_hi = s[0][0];
8438 a_lo = s[0][1];
8439 b_hi = s[1][0];
8440 b_lo = s[1][1];
8441 c_hi = s[2][0];
8442 c_lo = s[2][1];
8443 d_hi = s[3][0];
8444 d_lo = s[3][1];
8445 e_hi = s[4][0];
8446 e_lo = s[4][1];
8447 f_hi = s[5][0];
8448 f_lo = s[5][1];
8449 g_hi = s[6][0];
8450 g_lo = s[6][1];
8451 h_hi = s[7][0];
8452 h_lo = s[7][1];
8453
8454 // round function
8455 for(i = 0; i < 80; ++i) {
8456 // Sum1(e) = ROTR 14(e) ^ ROTR 18(e) ^ ROTR 41(e)
8457 s1_hi = (
8458 ((e_hi >>> 14) | (e_lo << 18)) ^ // ROTR 14
8459 ((e_hi >>> 18) | (e_lo << 14)) ^ // ROTR 18
8460 ((e_lo >>> 9) | (e_hi << 23))) >>> 0; // ROTR 41/(swap + ROTR 9)
8461 s1_lo = (
8462 ((e_hi << 18) | (e_lo >>> 14)) ^ // ROTR 14
8463 ((e_hi << 14) | (e_lo >>> 18)) ^ // ROTR 18
8464 ((e_lo << 23) | (e_hi >>> 9))) >>> 0; // ROTR 41/(swap + ROTR 9)
8465
8466 // Ch(e, f, g) (optimized the same way as SHA-1)
8467 ch_hi = (g_hi ^ (e_hi & (f_hi ^ g_hi))) >>> 0;
8468 ch_lo = (g_lo ^ (e_lo & (f_lo ^ g_lo))) >>> 0;
8469
8470 // Sum0(a) = ROTR 28(a) ^ ROTR 34(a) ^ ROTR 39(a)
8471 s0_hi = (
8472 ((a_hi >>> 28) | (a_lo << 4)) ^ // ROTR 28
8473 ((a_lo >>> 2) | (a_hi << 30)) ^ // ROTR 34/(swap + ROTR 2)
8474 ((a_lo >>> 7) | (a_hi << 25))) >>> 0; // ROTR 39/(swap + ROTR 7)
8475 s0_lo = (
8476 ((a_hi << 4) | (a_lo >>> 28)) ^ // ROTR 28
8477 ((a_lo << 30) | (a_hi >>> 2)) ^ // ROTR 34/(swap + ROTR 2)
8478 ((a_lo << 25) | (a_hi >>> 7))) >>> 0; // ROTR 39/(swap + ROTR 7)
8479
8480 // Maj(a, b, c) (optimized the same way as SHA-1)
8481 maj_hi = ((a_hi & b_hi) | (c_hi & (a_hi ^ b_hi))) >>> 0;
8482 maj_lo = ((a_lo & b_lo) | (c_lo & (a_lo ^ b_lo))) >>> 0;
8483
8484 // main algorithm
8485 // t1 = (h + s1 + ch + _k[i] + _w[i]) modulo 2^64 (carry lo overflow)
8486 lo = (h_lo + s1_lo + ch_lo + _k[i][1] + w[i][1]);
8487 t1_hi = (h_hi + s1_hi + ch_hi + _k[i][0] + w[i][0] +
8488 ((lo / 0x100000000) >>> 0)) >>> 0;
8489 t1_lo = lo >>> 0;
8490
8491 // t2 = s0 + maj modulo 2^64 (carry lo overflow)
8492 lo = s0_lo + maj_lo;
8493 t2_hi = (s0_hi + maj_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
8494 t2_lo = lo >>> 0;
8495
8496 h_hi = g_hi;
8497 h_lo = g_lo;
8498
8499 g_hi = f_hi;
8500 g_lo = f_lo;
8501
8502 f_hi = e_hi;
8503 f_lo = e_lo;
8504
8505 // e = (d + t1) modulo 2^64 (carry lo overflow)
8506 lo = d_lo + t1_lo;
8507 e_hi = (d_hi + t1_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
8508 e_lo = lo >>> 0;
8509
8510 d_hi = c_hi;
8511 d_lo = c_lo;
8512
8513 c_hi = b_hi;
8514 c_lo = b_lo;
8515
8516 b_hi = a_hi;
8517 b_lo = a_lo;
8518
8519 // a = (t1 + t2) modulo 2^64 (carry lo overflow)
8520 lo = t1_lo + t2_lo;
8521 a_hi = (t1_hi + t2_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
8522 a_lo = lo >>> 0;
8523 }
8524
8525 // update hash state (additional modulo 2^64)
8526 lo = s[0][1] + a_lo;
8527 s[0][0] = (s[0][0] + a_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
8528 s[0][1] = lo >>> 0;
8529
8530 lo = s[1][1] + b_lo;
8531 s[1][0] = (s[1][0] + b_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
8532 s[1][1] = lo >>> 0;
8533
8534 lo = s[2][1] + c_lo;
8535 s[2][0] = (s[2][0] + c_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
8536 s[2][1] = lo >>> 0;
8537
8538 lo = s[3][1] + d_lo;
8539 s[3][0] = (s[3][0] + d_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
8540 s[3][1] = lo >>> 0;
8541
8542 lo = s[4][1] + e_lo;
8543 s[4][0] = (s[4][0] + e_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
8544 s[4][1] = lo >>> 0;
8545
8546 lo = s[5][1] + f_lo;
8547 s[5][0] = (s[5][0] + f_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
8548 s[5][1] = lo >>> 0;
8549
8550 lo = s[6][1] + g_lo;
8551 s[6][0] = (s[6][0] + g_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
8552 s[6][1] = lo >>> 0;
8553
8554 lo = s[7][1] + h_lo;
8555 s[7][0] = (s[7][0] + h_hi + ((lo / 0x100000000) >>> 0)) >>> 0;
8556 s[7][1] = lo >>> 0;
8557
8558 len -= 128;
8559 }
8560}
8561
8562} // end module implementation
8563
8564/* ########## Begin module wrapper ########## */
8565var name = 'sha512';
8566if(typeof define !== 'function') {
8567 // NodeJS -> AMD
8568 if(typeof module === 'object' && module.exports) {
8569 var nodeJS = true;
8570 define = function(ids, factory) {
8571 factory(require, module);
8572 };
8573 } else {
8574 // <script>
8575 if(typeof forge === 'undefined') {
8576 forge = {};
8577 }
8578 return initModule(forge);
8579 }
8580}
8581// AMD
8582var deps;
8583var defineFunc = function(require, module) {
8584 module.exports = function(forge) {
8585 var mods = deps.map(function(dep) {
8586 return require(dep);
8587 }).concat(initModule);
8588 // handle circular dependencies
8589 forge = forge || {};
8590 forge.defined = forge.defined || {};
8591 if(forge.defined[name]) {
8592 return forge[name];
8593 }
8594 forge.defined[name] = true;
8595 for(var i = 0; i < mods.length; ++i) {
8596 mods[i](forge);
8597 }
8598 return forge[name];
8599 };
8600};
8601var tmpDefine = define;
8602define = function(ids, factory) {
8603 deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
8604 if(nodeJS) {
8605 delete define;
8606 return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
8607 }
8608 define = tmpDefine;
8609 return define.apply(null, Array.prototype.slice.call(arguments, 0));
8610};
8611define(['require', 'module', './util'], function() {
8612 defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
8613});
8614})();
8615
8616/**
8617 * Node.js module for Forge message digests.
8618 *
8619 * @author Dave Longley
8620 *
8621 * Copyright 2011-2014 Digital Bazaar, Inc.
8622 */
8623(function() {
8624/* ########## Begin module implementation ########## */
8625function initModule(forge) {
8626
8627forge.md = forge.md || {};
8628forge.md.algorithms = {
8629 md5: forge.md5,
8630 sha1: forge.sha1,
8631 sha256: forge.sha256
8632};
8633forge.md.md5 = forge.md5;
8634forge.md.sha1 = forge.sha1;
8635forge.md.sha256 = forge.sha256;
8636
8637} // end module implementation
8638
8639/* ########## Begin module wrapper ########## */
8640var name = 'md';
8641if(typeof define !== 'function') {
8642 // NodeJS -> AMD
8643 if(typeof module === 'object' && module.exports) {
8644 var nodeJS = true;
8645 define = function(ids, factory) {
8646 factory(require, module);
8647 };
8648 } else {
8649 // <script>
8650 if(typeof forge === 'undefined') {
8651 forge = {};
8652 }
8653 return initModule(forge);
8654 }
8655}
8656// AMD
8657var deps;
8658var defineFunc = function(require, module) {
8659 module.exports = function(forge) {
8660 var mods = deps.map(function(dep) {
8661 return require(dep);
8662 }).concat(initModule);
8663 // handle circular dependencies
8664 forge = forge || {};
8665 forge.defined = forge.defined || {};
8666 if(forge.defined[name]) {
8667 return forge[name];
8668 }
8669 forge.defined[name] = true;
8670 for(var i = 0; i < mods.length; ++i) {
8671 mods[i](forge);
8672 }
8673 return forge[name];
8674 };
8675};
8676var tmpDefine = define;
8677define = function(ids, factory) {
8678 deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
8679 if(nodeJS) {
8680 delete define;
8681 return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
8682 }
8683 define = tmpDefine;
8684 return define.apply(null, Array.prototype.slice.call(arguments, 0));
8685};
8686define(
8687 ['require', 'module', './md5', './sha1', './sha256', './sha512'], function() {
8688 defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
8689});
8690})();
8691
8692/**
8693 * Hash-based Message Authentication Code implementation. Requires a message
8694 * digest object that can be obtained, for example, from forge.md.sha1 or
8695 * forge.md.md5.
8696 *
8697 * @author Dave Longley
8698 *
8699 * Copyright (c) 2010-2012 Digital Bazaar, Inc. All rights reserved.
8700 */
8701(function() {
8702/* ########## Begin module implementation ########## */
8703function initModule(forge) {
8704
8705/* HMAC API */
8706var hmac = forge.hmac = forge.hmac || {};
8707
8708/**
8709 * Creates an HMAC object that uses the given message digest object.
8710 *
8711 * @return an HMAC object.
8712 */
8713hmac.create = function() {
8714 // the hmac key to use
8715 var _key = null;
8716
8717 // the message digest to use
8718 var _md = null;
8719
8720 // the inner padding
8721 var _ipadding = null;
8722
8723 // the outer padding
8724 var _opadding = null;
8725
8726 // hmac context
8727 var ctx = {};
8728
8729 /**
8730 * Starts or restarts the HMAC with the given key and message digest.
8731 *
8732 * @param md the message digest to use, null to reuse the previous one,
8733 * a string to use builtin 'sha1', 'md5', 'sha256'.
8734 * @param key the key to use as a string, array of bytes, byte buffer,
8735 * or null to reuse the previous key.
8736 */
8737 ctx.start = function(md, key) {
8738 if(md !== null) {
8739 if(typeof md === 'string') {
8740 // create builtin message digest
8741 md = md.toLowerCase();
8742 if(md in forge.md.algorithms) {
8743 _md = forge.md.algorithms[md].create();
8744 } else {
8745 throw new Error('Unknown hash algorithm "' + md + '"');
8746 }
8747 } else {
8748 // store message digest
8749 _md = md;
8750 }
8751 }
8752
8753 if(key === null) {
8754 // reuse previous key
8755 key = _key;
8756 } else {
8757 if(typeof key === 'string') {
8758 // convert string into byte buffer
8759 key = forge.util.createBuffer(key);
8760 } else if(forge.util.isArray(key)) {
8761 // convert byte array into byte buffer
8762 var tmp = key;
8763 key = forge.util.createBuffer();
8764 for(var i = 0; i < tmp.length; ++i) {
8765 key.putByte(tmp[i]);
8766 }
8767 }
8768
8769 // if key is longer than blocksize, hash it
8770 var keylen = key.length();
8771 if(keylen > _md.blockLength) {
8772 _md.start();
8773 _md.update(key.bytes());
8774 key = _md.digest();
8775 }
8776
8777 // mix key into inner and outer padding
8778 // ipadding = [0x36 * blocksize] ^ key
8779 // opadding = [0x5C * blocksize] ^ key
8780 _ipadding = forge.util.createBuffer();
8781 _opadding = forge.util.createBuffer();
8782 keylen = key.length();
8783 for(var i = 0; i < keylen; ++i) {
8784 var tmp = key.at(i);
8785 _ipadding.putByte(0x36 ^ tmp);
8786 _opadding.putByte(0x5C ^ tmp);
8787 }
8788
8789 // if key is shorter than blocksize, add additional padding
8790 if(keylen < _md.blockLength) {
8791 var tmp = _md.blockLength - keylen;
8792 for(var i = 0; i < tmp; ++i) {
8793 _ipadding.putByte(0x36);
8794 _opadding.putByte(0x5C);
8795 }
8796 }
8797 _key = key;
8798 _ipadding = _ipadding.bytes();
8799 _opadding = _opadding.bytes();
8800 }
8801
8802 // digest is done like so: hash(opadding | hash(ipadding | message))
8803
8804 // prepare to do inner hash
8805 // hash(ipadding | message)
8806 _md.start();
8807 _md.update(_ipadding);
8808 };
8809
8810 /**
8811 * Updates the HMAC with the given message bytes.
8812 *
8813 * @param bytes the bytes to update with.
8814 */
8815 ctx.update = function(bytes) {
8816 _md.update(bytes);
8817 };
8818
8819 /**
8820 * Produces the Message Authentication Code (MAC).
8821 *
8822 * @return a byte buffer containing the digest value.
8823 */
8824 ctx.getMac = function() {
8825 // digest is done like so: hash(opadding | hash(ipadding | message))
8826 // here we do the outer hashing
8827 var inner = _md.digest().bytes();
8828 _md.start();
8829 _md.update(_opadding);
8830 _md.update(inner);
8831 return _md.digest();
8832 };
8833 // alias for getMac
8834 ctx.digest = ctx.getMac;
8835
8836 return ctx;
8837};
8838
8839} // end module implementation
8840
8841/* ########## Begin module wrapper ########## */
8842var name = 'hmac';
8843if(typeof define !== 'function') {
8844 // NodeJS -> AMD
8845 if(typeof module === 'object' && module.exports) {
8846 var nodeJS = true;
8847 define = function(ids, factory) {
8848 factory(require, module);
8849 };
8850 } else {
8851 // <script>
8852 if(typeof forge === 'undefined') {
8853 forge = {};
8854 }
8855 return initModule(forge);
8856 }
8857}
8858// AMD
8859var deps;
8860var defineFunc = function(require, module) {
8861 module.exports = function(forge) {
8862 var mods = deps.map(function(dep) {
8863 return require(dep);
8864 }).concat(initModule);
8865 // handle circular dependencies
8866 forge = forge || {};
8867 forge.defined = forge.defined || {};
8868 if(forge.defined[name]) {
8869 return forge[name];
8870 }
8871 forge.defined[name] = true;
8872 for(var i = 0; i < mods.length; ++i) {
8873 mods[i](forge);
8874 }
8875 return forge[name];
8876 };
8877};
8878var tmpDefine = define;
8879define = function(ids, factory) {
8880 deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
8881 if(nodeJS) {
8882 delete define;
8883 return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
8884 }
8885 define = tmpDefine;
8886 return define.apply(null, Array.prototype.slice.call(arguments, 0));
8887};
8888define(['require', 'module', './md', './util'], function() {
8889 defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
8890});
8891})();
8892
8893/**
8894 * A javascript implementation of a cryptographically-secure
8895 * Pseudo Random Number Generator (PRNG). The Fortuna algorithm is followed
8896 * here though the use of SHA-256 is not enforced; when generating an
8897 * a PRNG context, the hashing algorithm and block cipher used for
8898 * the generator are specified via a plugin.
8899 *
8900 * @author Dave Longley
8901 *
8902 * Copyright (c) 2010-2014 Digital Bazaar, Inc.
8903 */
8904(function() {
8905/* ########## Begin module implementation ########## */
8906function initModule(forge) {
8907
8908var _nodejs = (
8909 typeof process !== 'undefined' && process.versions && process.versions.node);
8910var _crypto = null;
8911if(!forge.disableNativeCode && _nodejs && !process.versions['node-webkit']) {
8912 _crypto = require('crypto');
8913}
8914
8915/* PRNG API */
8916var prng = forge.prng = forge.prng || {};
8917
8918/**
8919 * Creates a new PRNG context.
8920 *
8921 * A PRNG plugin must be passed in that will provide:
8922 *
8923 * 1. A function that initializes the key and seed of a PRNG context. It
8924 * will be given a 16 byte key and a 16 byte seed. Any key expansion
8925 * or transformation of the seed from a byte string into an array of
8926 * integers (or similar) should be performed.
8927 * 2. The cryptographic function used by the generator. It takes a key and
8928 * a seed.
8929 * 3. A seed increment function. It takes the seed and returns seed + 1.
8930 * 4. An api to create a message digest.
8931 *
8932 * For an example, see random.js.
8933 *
8934 * @param plugin the PRNG plugin to use.
8935 */
8936prng.create = function(plugin) {
8937 var ctx = {
8938 plugin: plugin,
8939 key: null,
8940 seed: null,
8941 time: null,
8942 // number of reseeds so far
8943 reseeds: 0,
8944 // amount of data generated so far
8945 generated: 0
8946 };
8947
8948 // create 32 entropy pools (each is a message digest)
8949 var md = plugin.md;
8950 var pools = new Array(32);
8951 for(var i = 0; i < 32; ++i) {
8952 pools[i] = md.create();
8953 }
8954 ctx.pools = pools;
8955
8956 // entropy pools are written to cyclically, starting at index 0
8957 ctx.pool = 0;
8958
8959 /**
8960 * Generates random bytes. The bytes may be generated synchronously or
8961 * asynchronously. Web workers must use the asynchronous interface or
8962 * else the behavior is undefined.
8963 *
8964 * @param count the number of random bytes to generate.
8965 * @param [callback(err, bytes)] called once the operation completes.
8966 *
8967 * @return count random bytes as a string.
8968 */
8969 ctx.generate = function(count, callback) {
8970 // do synchronously
8971 if(!callback) {
8972 return ctx.generateSync(count);
8973 }
8974
8975 // simple generator using counter-based CBC
8976 var cipher = ctx.plugin.cipher;
8977 var increment = ctx.plugin.increment;
8978 var formatKey = ctx.plugin.formatKey;
8979 var formatSeed = ctx.plugin.formatSeed;
8980 var b = forge.util.createBuffer();
8981
8982 // reset key for every request
8983 ctx.key = null;
8984
8985 generate();
8986
8987 function generate(err) {
8988 if(err) {
8989 return callback(err);
8990 }
8991
8992 // sufficient bytes generated
8993 if(b.length() >= count) {
8994 return callback(null, b.getBytes(count));
8995 }
8996
8997 // if amount of data generated is greater than 1 MiB, trigger reseed
8998 if(ctx.generated > 0xfffff) {
8999 ctx.key = null;
9000 }
9001
9002 if(ctx.key === null) {
9003 // prevent stack overflow
9004 return forge.util.nextTick(function() {
9005 _reseed(generate);
9006 });
9007 }
9008
9009 // generate the random bytes
9010 var bytes = cipher(ctx.key, ctx.seed);
9011 ctx.generated += bytes.length;
9012 b.putBytes(bytes);
9013
9014 // generate bytes for a new key and seed
9015 ctx.key = formatKey(cipher(ctx.key, increment(ctx.seed)));
9016 ctx.seed = formatSeed(cipher(ctx.key, ctx.seed));
9017
9018 forge.util.setImmediate(generate);
9019 }
9020 };
9021
9022 /**
9023 * Generates random bytes synchronously.
9024 *
9025 * @param count the number of random bytes to generate.
9026 *
9027 * @return count random bytes as a string.
9028 */
9029 ctx.generateSync = function(count) {
9030 // simple generator using counter-based CBC
9031 var cipher = ctx.plugin.cipher;
9032 var increment = ctx.plugin.increment;
9033 var formatKey = ctx.plugin.formatKey;
9034 var formatSeed = ctx.plugin.formatSeed;
9035
9036 // reset key for every request
9037 ctx.key = null;
9038
9039 var b = forge.util.createBuffer();
9040 while(b.length() < count) {
9041 // if amount of data generated is greater than 1 MiB, trigger reseed
9042 if(ctx.generated > 0xfffff) {
9043 ctx.key = null;
9044 }
9045
9046 if(ctx.key === null) {
9047 _reseedSync();
9048 }
9049
9050 // generate the random bytes
9051 var bytes = cipher(ctx.key, ctx.seed);
9052 ctx.generated += bytes.length;
9053 b.putBytes(bytes);
9054
9055 // generate bytes for a new key and seed
9056 ctx.key = formatKey(cipher(ctx.key, increment(ctx.seed)));
9057 ctx.seed = formatSeed(cipher(ctx.key, ctx.seed));
9058 }
9059
9060 return b.getBytes(count);
9061 };
9062
9063 /**
9064 * Private function that asynchronously reseeds a generator.
9065 *
9066 * @param callback(err) called once the operation completes.
9067 */
9068 function _reseed(callback) {
9069 if(ctx.pools[0].messageLength >= 32) {
9070 _seed();
9071 return callback();
9072 }
9073 // not enough seed data...
9074 var needed = (32 - ctx.pools[0].messageLength) << 5;
9075 ctx.seedFile(needed, function(err, bytes) {
9076 if(err) {
9077 return callback(err);
9078 }
9079 ctx.collect(bytes);
9080 _seed();
9081 callback();
9082 });
9083 }
9084
9085 /**
9086 * Private function that synchronously reseeds a generator.
9087 */
9088 function _reseedSync() {
9089 if(ctx.pools[0].messageLength >= 32) {
9090 return _seed();
9091 }
9092 // not enough seed data...
9093 var needed = (32 - ctx.pools[0].messageLength) << 5;
9094 ctx.collect(ctx.seedFileSync(needed));
9095 _seed();
9096 }
9097
9098 /**
9099 * Private function that seeds a generator once enough bytes are available.
9100 */
9101 function _seed() {
9102 // create a plugin-based message digest
9103 var md = ctx.plugin.md.create();
9104
9105 // digest pool 0's entropy and restart it
9106 md.update(ctx.pools[0].digest().getBytes());
9107 ctx.pools[0].start();
9108
9109 // digest the entropy of other pools whose index k meet the
9110 // condition '2^k mod n == 0' where n is the number of reseeds
9111 var k = 1;
9112 for(var i = 1; i < 32; ++i) {
9113 // prevent signed numbers from being used
9114 k = (k === 31) ? 0x80000000 : (k << 2);
9115 if(k % ctx.reseeds === 0) {
9116 md.update(ctx.pools[i].digest().getBytes());
9117 ctx.pools[i].start();
9118 }
9119 }
9120
9121 // get digest for key bytes and iterate again for seed bytes
9122 var keyBytes = md.digest().getBytes();
9123 md.start();
9124 md.update(keyBytes);
9125 var seedBytes = md.digest().getBytes();
9126
9127 // update
9128 ctx.key = ctx.plugin.formatKey(keyBytes);
9129 ctx.seed = ctx.plugin.formatSeed(seedBytes);
9130 ctx.reseeds = (ctx.reseeds === 0xffffffff) ? 0 : ctx.reseeds + 1;
9131 ctx.generated = 0;
9132 }
9133
9134 /**
9135 * The built-in default seedFile. This seedFile is used when entropy
9136 * is needed immediately.
9137 *
9138 * @param needed the number of bytes that are needed.
9139 *
9140 * @return the random bytes.
9141 */
9142 function defaultSeedFile(needed) {
9143 // use window.crypto.getRandomValues strong source of entropy if available
9144 var getRandomValues = null;
9145 if(typeof window !== 'undefined') {
9146 var _crypto = window.crypto || window.msCrypto;
9147 if(_crypto && _crypto.getRandomValues) {
9148 getRandomValues = function(arr) {
9149 return _crypto.getRandomValues(arr);
9150 };
9151 }
9152 }
9153
9154 var b = forge.util.createBuffer();
9155 if(getRandomValues) {
9156 while(b.length() < needed) {
9157 // max byte length is 65536 before QuotaExceededError is thrown
9158 // http://www.w3.org/TR/WebCryptoAPI/#RandomSource-method-getRandomValues
9159 var count = Math.max(1, Math.min(needed - b.length(), 65536) / 4);
9160 var entropy = new Uint32Array(Math.floor(count));
9161 try {
9162 getRandomValues(entropy);
9163 for(var i = 0; i < entropy.length; ++i) {
9164 b.putInt32(entropy[i]);
9165 }
9166 } catch(e) {
9167 /* only ignore QuotaExceededError */
9168 if(!(typeof QuotaExceededError !== 'undefined' &&
9169 e instanceof QuotaExceededError)) {
9170 throw e;
9171 }
9172 }
9173 }
9174 }
9175
9176 // be sad and add some weak random data
9177 if(b.length() < needed) {
9178 /* Draws from Park-Miller "minimal standard" 31 bit PRNG,
9179 implemented with David G. Carta's optimization: with 32 bit math
9180 and without division (Public Domain). */
9181 var hi, lo, next;
9182 var seed = Math.floor(Math.random() * 0x010000);
9183 while(b.length() < needed) {
9184 lo = 16807 * (seed & 0xFFFF);
9185 hi = 16807 * (seed >> 16);
9186 lo += (hi & 0x7FFF) << 16;
9187 lo += hi >> 15;
9188 lo = (lo & 0x7FFFFFFF) + (lo >> 31);
9189 seed = lo & 0xFFFFFFFF;
9190
9191 // consume lower 3 bytes of seed
9192 for(var i = 0; i < 3; ++i) {
9193 // throw in more pseudo random
9194 next = seed >>> (i << 3);
9195 next ^= Math.floor(Math.random() * 0x0100);
9196 b.putByte(String.fromCharCode(next & 0xFF));
9197 }
9198 }
9199 }
9200
9201 return b.getBytes(needed);
9202 }
9203 // initialize seed file APIs
9204 if(_crypto) {
9205 // use nodejs async API
9206 ctx.seedFile = function(needed, callback) {
9207 _crypto.randomBytes(needed, function(err, bytes) {
9208 if(err) {
9209 return callback(err);
9210 }
9211 callback(null, bytes.toString());
9212 });
9213 };
9214 // use nodejs sync API
9215 ctx.seedFileSync = function(needed) {
9216 return _crypto.randomBytes(needed).toString();
9217 };
9218 } else {
9219 ctx.seedFile = function(needed, callback) {
9220 try {
9221 callback(null, defaultSeedFile(needed));
9222 } catch(e) {
9223 callback(e);
9224 }
9225 };
9226 ctx.seedFileSync = defaultSeedFile;
9227 }
9228
9229 /**
9230 * Adds entropy to a prng ctx's accumulator.
9231 *
9232 * @param bytes the bytes of entropy as a string.
9233 */
9234 ctx.collect = function(bytes) {
9235 // iterate over pools distributing entropy cyclically
9236 var count = bytes.length;
9237 for(var i = 0; i < count; ++i) {
9238 ctx.pools[ctx.pool].update(bytes.substr(i, 1));
9239 ctx.pool = (ctx.pool === 31) ? 0 : ctx.pool + 1;
9240 }
9241 };
9242
9243 /**
9244 * Collects an integer of n bits.
9245 *
9246 * @param i the integer entropy.
9247 * @param n the number of bits in the integer.
9248 */
9249 ctx.collectInt = function(i, n) {
9250 var bytes = '';
9251 for(var x = 0; x < n; x += 8) {
9252 bytes += String.fromCharCode((i >> x) & 0xFF);
9253 }
9254 ctx.collect(bytes);
9255 };
9256
9257 /**
9258 * Registers a Web Worker to receive immediate entropy from the main thread.
9259 * This method is required until Web Workers can access the native crypto
9260 * API. This method should be called twice for each created worker, once in
9261 * the main thread, and once in the worker itself.
9262 *
9263 * @param worker the worker to register.
9264 */
9265 ctx.registerWorker = function(worker) {
9266 // worker receives random bytes
9267 if(worker === self) {
9268 ctx.seedFile = function(needed, callback) {
9269 function listener(e) {
9270 var data = e.data;
9271 if(data.forge && data.forge.prng) {
9272 self.removeEventListener('message', listener);
9273 callback(data.forge.prng.err, data.forge.prng.bytes);
9274 }
9275 }
9276 self.addEventListener('message', listener);
9277 self.postMessage({forge: {prng: {needed: needed}}});
9278 };
9279 } else {
9280 // main thread sends random bytes upon request
9281 var listener = function(e) {
9282 var data = e.data;
9283 if(data.forge && data.forge.prng) {
9284 ctx.seedFile(data.forge.prng.needed, function(err, bytes) {
9285 worker.postMessage({forge: {prng: {err: err, bytes: bytes}}});
9286 });
9287 }
9288 };
9289 // TODO: do we need to remove the event listener when the worker dies?
9290 worker.addEventListener('message', listener);
9291 }
9292 };
9293
9294 return ctx;
9295};
9296
9297} // end module implementation
9298
9299/* ########## Begin module wrapper ########## */
9300var name = 'prng';
9301if(typeof define !== 'function') {
9302 // NodeJS -> AMD
9303 if(typeof module === 'object' && module.exports) {
9304 var nodeJS = true;
9305 define = function(ids, factory) {
9306 factory(require, module);
9307 };
9308 } else {
9309 // <script>
9310 if(typeof forge === 'undefined') {
9311 forge = {};
9312 }
9313 return initModule(forge);
9314 }
9315}
9316// AMD
9317var deps;
9318var defineFunc = function(require, module) {
9319 module.exports = function(forge) {
9320 var mods = deps.map(function(dep) {
9321 return require(dep);
9322 }).concat(initModule);
9323 // handle circular dependencies
9324 forge = forge || {};
9325 forge.defined = forge.defined || {};
9326 if(forge.defined[name]) {
9327 return forge[name];
9328 }
9329 forge.defined[name] = true;
9330 for(var i = 0; i < mods.length; ++i) {
9331 mods[i](forge);
9332 }
9333 return forge[name];
9334 };
9335};
9336var tmpDefine = define;
9337define = function(ids, factory) {
9338 deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
9339 if(nodeJS) {
9340 delete define;
9341 return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
9342 }
9343 define = tmpDefine;
9344 return define.apply(null, Array.prototype.slice.call(arguments, 0));
9345};
9346define(['require', 'module', './md', './util'], function() {
9347 defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
9348});
9349
9350})();
9351
9352/**
9353 * An API for getting cryptographically-secure random bytes. The bytes are
9354 * generated using the Fortuna algorithm devised by Bruce Schneier and
9355 * Niels Ferguson.
9356 *
9357 * Getting strong random bytes is not yet easy to do in javascript. The only
9358 * truish random entropy that can be collected is from the mouse, keyboard, or
9359 * from timing with respect to page loads, etc. This generator makes a poor
9360 * attempt at providing random bytes when those sources haven't yet provided
9361 * enough entropy to initially seed or to reseed the PRNG.
9362 *
9363 * @author Dave Longley
9364 *
9365 * Copyright (c) 2009-2014 Digital Bazaar, Inc.
9366 */
9367(function() {
9368/* ########## Begin module implementation ########## */
9369function initModule(forge) {
9370
9371// forge.random already defined
9372if(forge.random && forge.random.getBytes) {
9373 return;
9374}
9375
9376(function(jQuery) {
9377
9378// the default prng plugin, uses AES-128
9379var prng_aes = {};
9380var _prng_aes_output = new Array(4);
9381var _prng_aes_buffer = forge.util.createBuffer();
9382prng_aes.formatKey = function(key) {
9383 // convert the key into 32-bit integers
9384 var tmp = forge.util.createBuffer(key);
9385 key = new Array(4);
9386 key[0] = tmp.getInt32();
9387 key[1] = tmp.getInt32();
9388 key[2] = tmp.getInt32();
9389 key[3] = tmp.getInt32();
9390
9391 // return the expanded key
9392 return forge.aes._expandKey(key, false);
9393};
9394prng_aes.formatSeed = function(seed) {
9395 // convert seed into 32-bit integers
9396 var tmp = forge.util.createBuffer(seed);
9397 seed = new Array(4);
9398 seed[0] = tmp.getInt32();
9399 seed[1] = tmp.getInt32();
9400 seed[2] = tmp.getInt32();
9401 seed[3] = tmp.getInt32();
9402 return seed;
9403};
9404prng_aes.cipher = function(key, seed) {
9405 forge.aes._updateBlock(key, seed, _prng_aes_output, false);
9406 _prng_aes_buffer.putInt32(_prng_aes_output[0]);
9407 _prng_aes_buffer.putInt32(_prng_aes_output[1]);
9408 _prng_aes_buffer.putInt32(_prng_aes_output[2]);
9409 _prng_aes_buffer.putInt32(_prng_aes_output[3]);
9410 return _prng_aes_buffer.getBytes();
9411};
9412prng_aes.increment = function(seed) {
9413 // FIXME: do we care about carry or signed issues?
9414 ++seed[3];
9415 return seed;
9416};
9417prng_aes.md = forge.md.sha256;
9418
9419/**
9420 * Creates a new PRNG.
9421 */
9422function spawnPrng() {
9423 var ctx = forge.prng.create(prng_aes);
9424
9425 /**
9426 * Gets random bytes. If a native secure crypto API is unavailable, this
9427 * method tries to make the bytes more unpredictable by drawing from data that
9428 * can be collected from the user of the browser, eg: mouse movement.
9429 *
9430 * If a callback is given, this method will be called asynchronously.
9431 *
9432 * @param count the number of random bytes to get.
9433 * @param [callback(err, bytes)] called once the operation completes.
9434 *
9435 * @return the random bytes in a string.
9436 */
9437 ctx.getBytes = function(count, callback) {
9438 return ctx.generate(count, callback);
9439 };
9440
9441 /**
9442 * Gets random bytes asynchronously. If a native secure crypto API is
9443 * unavailable, this method tries to make the bytes more unpredictable by
9444 * drawing from data that can be collected from the user of the browser,
9445 * eg: mouse movement.
9446 *
9447 * @param count the number of random bytes to get.
9448 *
9449 * @return the random bytes in a string.
9450 */
9451 ctx.getBytesSync = function(count) {
9452 return ctx.generate(count);
9453 };
9454
9455 return ctx;
9456}
9457
9458// create default prng context
9459var _ctx = spawnPrng();
9460
9461// add other sources of entropy only if window.crypto.getRandomValues is not
9462// available -- otherwise this source will be automatically used by the prng
9463var _nodejs = (
9464 typeof process !== 'undefined' && process.versions && process.versions.node);
9465var getRandomValues = null;
9466if(typeof window !== 'undefined') {
9467 var _crypto = window.crypto || window.msCrypto;
9468 if(_crypto && _crypto.getRandomValues) {
9469 getRandomValues = function(arr) {
9470 return _crypto.getRandomValues(arr);
9471 };
9472 }
9473}
9474if(forge.disableNativeCode || (!_nodejs && !getRandomValues)) {
9475 // if this is a web worker, do not use weak entropy, instead register to
9476 // receive strong entropy asynchronously from the main thread
9477 if(typeof window === 'undefined' || window.document === undefined) {
9478 // FIXME:
9479 }
9480
9481 // get load time entropy
9482 _ctx.collectInt(+new Date(), 32);
9483
9484 // add some entropy from navigator object
9485 if(typeof(navigator) !== 'undefined') {
9486 var _navBytes = '';
9487 for(var key in navigator) {
9488 try {
9489 if(typeof(navigator[key]) == 'string') {
9490 _navBytes += navigator[key];
9491 }
9492 } catch(e) {
9493 /* Some navigator keys might not be accessible, e.g. the geolocation
9494 attribute throws an exception if touched in Mozilla chrome://
9495 context.
9496
9497 Silently ignore this and just don't use this as a source of
9498 entropy. */
9499 }
9500 }
9501 _ctx.collect(_navBytes);
9502 _navBytes = null;
9503 }
9504
9505 // add mouse and keyboard collectors if jquery is available
9506 if(jQuery) {
9507 // set up mouse entropy capture
9508 jQuery().mousemove(function(e) {
9509 // add mouse coords
9510 _ctx.collectInt(e.clientX, 16);
9511 _ctx.collectInt(e.clientY, 16);
9512 });
9513
9514 // set up keyboard entropy capture
9515 jQuery().keypress(function(e) {
9516 _ctx.collectInt(e.charCode, 8);
9517 });
9518 }
9519}
9520
9521/* Random API */
9522if(!forge.random) {
9523 forge.random = _ctx;
9524} else {
9525 // extend forge.random with _ctx
9526 for(var key in _ctx) {
9527 forge.random[key] = _ctx[key];
9528 }
9529}
9530
9531// expose spawn PRNG
9532forge.random.createInstance = spawnPrng;
9533
9534})(typeof(jQuery) !== 'undefined' ? jQuery : null);
9535
9536} // end module implementation
9537
9538/* ########## Begin module wrapper ########## */
9539var name = 'random';
9540if(typeof define !== 'function') {
9541 // NodeJS -> AMD
9542 if(typeof module === 'object' && module.exports) {
9543 var nodeJS = true;
9544 define = function(ids, factory) {
9545 factory(require, module);
9546 };
9547 } else {
9548 // <script>
9549 if(typeof forge === 'undefined') {
9550 forge = {};
9551 }
9552 return initModule(forge);
9553 }
9554}
9555// AMD
9556var deps;
9557var defineFunc = function(require, module) {
9558 module.exports = function(forge) {
9559 var mods = deps.map(function(dep) {
9560 return require(dep);
9561 }).concat(initModule);
9562 // handle circular dependencies
9563 forge = forge || {};
9564 forge.defined = forge.defined || {};
9565 if(forge.defined[name]) {
9566 return forge[name];
9567 }
9568 forge.defined[name] = true;
9569 for(var i = 0; i < mods.length; ++i) {
9570 mods[i](forge);
9571 }
9572 return forge[name];
9573 };
9574};
9575var tmpDefine = define;
9576define = function(ids, factory) {
9577 deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
9578 if(nodeJS) {
9579 delete define;
9580 return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
9581 }
9582 define = tmpDefine;
9583 return define.apply(null, Array.prototype.slice.call(arguments, 0));
9584};
9585define(['require', 'module', './aes', './md', './prng', './util'], function() {
9586 defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
9587});
9588})();
9589
9590// Copyright (c) 2005 Tom Wu
9591// All Rights Reserved.
9592// See "LICENSE" for details.
9593
9594// Basic JavaScript BN library - subset useful for RSA encryption.
9595
9596/*
9597Licensing (LICENSE)
9598-------------------
9599
9600This software is covered under the following copyright:
9601*/
9602/*
9603 * Copyright (c) 2003-2005 Tom Wu
9604 * All Rights Reserved.
9605 *
9606 * Permission is hereby granted, free of charge, to any person obtaining
9607 * a copy of this software and associated documentation files (the
9608 * "Software"), to deal in the Software without restriction, including
9609 * without limitation the rights to use, copy, modify, merge, publish,
9610 * distribute, sublicense, and/or sell copies of the Software, and to
9611 * permit persons to whom the Software is furnished to do so, subject to
9612 * the following conditions:
9613 *
9614 * The above copyright notice and this permission notice shall be
9615 * included in all copies or substantial portions of the Software.
9616 *
9617 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
9618 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
9619 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
9620 *
9621 * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
9622 * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
9623 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
9624 * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
9625 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
9626 *
9627 * In addition, the following condition applies:
9628 *
9629 * All redistributions must retain an intact copy of this copyright notice
9630 * and disclaimer.
9631 */
9632/*
9633Address all questions regarding this license to:
9634
9635 Tom Wu
9636 tjw@cs.Stanford.EDU
9637*/
9638
9639(function() {
9640/* ########## Begin module implementation ########## */
9641function initModule(forge) {
9642
9643// Bits per digit
9644var dbits;
9645
9646// JavaScript engine analysis
9647var canary = 0xdeadbeefcafe;
9648var j_lm = ((canary&0xffffff)==0xefcafe);
9649
9650// (public) Constructor
9651function BigInteger(a,b,c) {
9652 this.data = [];
9653 if(a != null)
9654 if("number" == typeof a) this.fromNumber(a,b,c);
9655 else if(b == null && "string" != typeof a) this.fromString(a,256);
9656 else this.fromString(a,b);
9657}
9658
9659// return new, unset BigInteger
9660function nbi() { return new BigInteger(null); }
9661
9662// am: Compute w_j += (x*this_i), propagate carries,
9663// c is initial carry, returns final carry.
9664// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
9665// We need to select the fastest one that works in this environment.
9666
9667// am1: use a single mult and divide to get the high bits,
9668// max digit bits should be 26 because
9669// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
9670function am1(i,x,w,j,c,n) {
9671 while(--n >= 0) {
9672 var v = x*this.data[i++]+w.data[j]+c;
9673 c = Math.floor(v/0x4000000);
9674 w.data[j++] = v&0x3ffffff;
9675 }
9676 return c;
9677}
9678// am2 avoids a big mult-and-extract completely.
9679// Max digit bits should be <= 30 because we do bitwise ops
9680// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
9681function am2(i,x,w,j,c,n) {
9682 var xl = x&0x7fff, xh = x>>15;
9683 while(--n >= 0) {
9684 var l = this.data[i]&0x7fff;
9685 var h = this.data[i++]>>15;
9686 var m = xh*l+h*xl;
9687 l = xl*l+((m&0x7fff)<<15)+w.data[j]+(c&0x3fffffff);
9688 c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
9689 w.data[j++] = l&0x3fffffff;
9690 }
9691 return c;
9692}
9693// Alternately, set max digit bits to 28 since some
9694// browsers slow down when dealing with 32-bit numbers.
9695function am3(i,x,w,j,c,n) {
9696 var xl = x&0x3fff, xh = x>>14;
9697 while(--n >= 0) {
9698 var l = this.data[i]&0x3fff;
9699 var h = this.data[i++]>>14;
9700 var m = xh*l+h*xl;
9701 l = xl*l+((m&0x3fff)<<14)+w.data[j]+c;
9702 c = (l>>28)+(m>>14)+xh*h;
9703 w.data[j++] = l&0xfffffff;
9704 }
9705 return c;
9706}
9707
9708// node.js (no browser)
9709if(typeof(navigator) === 'undefined')
9710{
9711 BigInteger.prototype.am = am3;
9712 dbits = 28;
9713} else if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
9714 BigInteger.prototype.am = am2;
9715 dbits = 30;
9716} else if(j_lm && (navigator.appName != "Netscape")) {
9717 BigInteger.prototype.am = am1;
9718 dbits = 26;
9719} else { // Mozilla/Netscape seems to prefer am3
9720 BigInteger.prototype.am = am3;
9721 dbits = 28;
9722}
9723
9724BigInteger.prototype.DB = dbits;
9725BigInteger.prototype.DM = ((1<<dbits)-1);
9726BigInteger.prototype.DV = (1<<dbits);
9727
9728var BI_FP = 52;
9729BigInteger.prototype.FV = Math.pow(2,BI_FP);
9730BigInteger.prototype.F1 = BI_FP-dbits;
9731BigInteger.prototype.F2 = 2*dbits-BI_FP;
9732
9733// Digit conversions
9734var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
9735var BI_RC = new Array();
9736var rr,vv;
9737rr = "0".charCodeAt(0);
9738for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
9739rr = "a".charCodeAt(0);
9740for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
9741rr = "A".charCodeAt(0);
9742for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
9743
9744function int2char(n) { return BI_RM.charAt(n); }
9745function intAt(s,i) {
9746 var c = BI_RC[s.charCodeAt(i)];
9747 return (c==null)?-1:c;
9748}
9749
9750// (protected) copy this to r
9751function bnpCopyTo(r) {
9752 for(var i = this.t-1; i >= 0; --i) r.data[i] = this.data[i];
9753 r.t = this.t;
9754 r.s = this.s;
9755}
9756
9757// (protected) set from integer value x, -DV <= x < DV
9758function bnpFromInt(x) {
9759 this.t = 1;
9760 this.s = (x<0)?-1:0;
9761 if(x > 0) this.data[0] = x;
9762 else if(x < -1) this.data[0] = x+this.DV;
9763 else this.t = 0;
9764}
9765
9766// return bigint initialized to value
9767function nbv(i) { var r = nbi(); r.fromInt(i); return r; }
9768
9769// (protected) set from string and radix
9770function bnpFromString(s,b) {
9771 var k;
9772 if(b == 16) k = 4;
9773 else if(b == 8) k = 3;
9774 else if(b == 256) k = 8; // byte array
9775 else if(b == 2) k = 1;
9776 else if(b == 32) k = 5;
9777 else if(b == 4) k = 2;
9778 else { this.fromRadix(s,b); return; }
9779 this.t = 0;
9780 this.s = 0;
9781 var i = s.length, mi = false, sh = 0;
9782 while(--i >= 0) {
9783 var x = (k==8)?s[i]&0xff:intAt(s,i);
9784 if(x < 0) {
9785 if(s.charAt(i) == "-") mi = true;
9786 continue;
9787 }
9788 mi = false;
9789 if(sh == 0)
9790 this.data[this.t++] = x;
9791 else if(sh+k > this.DB) {
9792 this.data[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
9793 this.data[this.t++] = (x>>(this.DB-sh));
9794 } else
9795 this.data[this.t-1] |= x<<sh;
9796 sh += k;
9797 if(sh >= this.DB) sh -= this.DB;
9798 }
9799 if(k == 8 && (s[0]&0x80) != 0) {
9800 this.s = -1;
9801 if(sh > 0) this.data[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
9802 }
9803 this.clamp();
9804 if(mi) BigInteger.ZERO.subTo(this,this);
9805}
9806
9807// (protected) clamp off excess high words
9808function bnpClamp() {
9809 var c = this.s&this.DM;
9810 while(this.t > 0 && this.data[this.t-1] == c) --this.t;
9811}
9812
9813// (public) return string representation in given radix
9814function bnToString(b) {
9815 if(this.s < 0) return "-"+this.negate().toString(b);
9816 var k;
9817 if(b == 16) k = 4;
9818 else if(b == 8) k = 3;
9819 else if(b == 2) k = 1;
9820 else if(b == 32) k = 5;
9821 else if(b == 4) k = 2;
9822 else return this.toRadix(b);
9823 var km = (1<<k)-1, d, m = false, r = "", i = this.t;
9824 var p = this.DB-(i*this.DB)%k;
9825 if(i-- > 0) {
9826 if(p < this.DB && (d = this.data[i]>>p) > 0) { m = true; r = int2char(d); }
9827 while(i >= 0) {
9828 if(p < k) {
9829 d = (this.data[i]&((1<<p)-1))<<(k-p);
9830 d |= this.data[--i]>>(p+=this.DB-k);
9831 } else {
9832 d = (this.data[i]>>(p-=k))&km;
9833 if(p <= 0) { p += this.DB; --i; }
9834 }
9835 if(d > 0) m = true;
9836 if(m) r += int2char(d);
9837 }
9838 }
9839 return m?r:"0";
9840}
9841
9842// (public) -this
9843function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }
9844
9845// (public) |this|
9846function bnAbs() { return (this.s<0)?this.negate():this; }
9847
9848// (public) return + if this > a, - if this < a, 0 if equal
9849function bnCompareTo(a) {
9850 var r = this.s-a.s;
9851 if(r != 0) return r;
9852 var i = this.t;
9853 r = i-a.t;
9854 if(r != 0) return (this.s<0)?-r:r;
9855 while(--i >= 0) if((r=this.data[i]-a.data[i]) != 0) return r;
9856 return 0;
9857}
9858
9859// returns bit length of the integer x
9860function nbits(x) {
9861 var r = 1, t;
9862 if((t=x>>>16) != 0) { x = t; r += 16; }
9863 if((t=x>>8) != 0) { x = t; r += 8; }
9864 if((t=x>>4) != 0) { x = t; r += 4; }
9865 if((t=x>>2) != 0) { x = t; r += 2; }
9866 if((t=x>>1) != 0) { x = t; r += 1; }
9867 return r;
9868}
9869
9870// (public) return the number of bits in "this"
9871function bnBitLength() {
9872 if(this.t <= 0) return 0;
9873 return this.DB*(this.t-1)+nbits(this.data[this.t-1]^(this.s&this.DM));
9874}
9875
9876// (protected) r = this << n*DB
9877function bnpDLShiftTo(n,r) {
9878 var i;
9879 for(i = this.t-1; i >= 0; --i) r.data[i+n] = this.data[i];
9880 for(i = n-1; i >= 0; --i) r.data[i] = 0;
9881 r.t = this.t+n;
9882 r.s = this.s;
9883}
9884
9885// (protected) r = this >> n*DB
9886function bnpDRShiftTo(n,r) {
9887 for(var i = n; i < this.t; ++i) r.data[i-n] = this.data[i];
9888 r.t = Math.max(this.t-n,0);
9889 r.s = this.s;
9890}
9891
9892// (protected) r = this << n
9893function bnpLShiftTo(n,r) {
9894 var bs = n%this.DB;
9895 var cbs = this.DB-bs;
9896 var bm = (1<<cbs)-1;
9897 var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
9898 for(i = this.t-1; i >= 0; --i) {
9899 r.data[i+ds+1] = (this.data[i]>>cbs)|c;
9900 c = (this.data[i]&bm)<<bs;
9901 }
9902 for(i = ds-1; i >= 0; --i) r.data[i] = 0;
9903 r.data[ds] = c;
9904 r.t = this.t+ds+1;
9905 r.s = this.s;
9906 r.clamp();
9907}
9908
9909// (protected) r = this >> n
9910function bnpRShiftTo(n,r) {
9911 r.s = this.s;
9912 var ds = Math.floor(n/this.DB);
9913 if(ds >= this.t) { r.t = 0; return; }
9914 var bs = n%this.DB;
9915 var cbs = this.DB-bs;
9916 var bm = (1<<bs)-1;
9917 r.data[0] = this.data[ds]>>bs;
9918 for(var i = ds+1; i < this.t; ++i) {
9919 r.data[i-ds-1] |= (this.data[i]&bm)<<cbs;
9920 r.data[i-ds] = this.data[i]>>bs;
9921 }
9922 if(bs > 0) r.data[this.t-ds-1] |= (this.s&bm)<<cbs;
9923 r.t = this.t-ds;
9924 r.clamp();
9925}
9926
9927// (protected) r = this - a
9928function bnpSubTo(a,r) {
9929 var i = 0, c = 0, m = Math.min(a.t,this.t);
9930 while(i < m) {
9931 c += this.data[i]-a.data[i];
9932 r.data[i++] = c&this.DM;
9933 c >>= this.DB;
9934 }
9935 if(a.t < this.t) {
9936 c -= a.s;
9937 while(i < this.t) {
9938 c += this.data[i];
9939 r.data[i++] = c&this.DM;
9940 c >>= this.DB;
9941 }
9942 c += this.s;
9943 } else {
9944 c += this.s;
9945 while(i < a.t) {
9946 c -= a.data[i];
9947 r.data[i++] = c&this.DM;
9948 c >>= this.DB;
9949 }
9950 c -= a.s;
9951 }
9952 r.s = (c<0)?-1:0;
9953 if(c < -1) r.data[i++] = this.DV+c;
9954 else if(c > 0) r.data[i++] = c;
9955 r.t = i;
9956 r.clamp();
9957}
9958
9959// (protected) r = this * a, r != this,a (HAC 14.12)
9960// "this" should be the larger one if appropriate.
9961function bnpMultiplyTo(a,r) {
9962 var x = this.abs(), y = a.abs();
9963 var i = x.t;
9964 r.t = i+y.t;
9965 while(--i >= 0) r.data[i] = 0;
9966 for(i = 0; i < y.t; ++i) r.data[i+x.t] = x.am(0,y.data[i],r,i,0,x.t);
9967 r.s = 0;
9968 r.clamp();
9969 if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
9970}
9971
9972// (protected) r = this^2, r != this (HAC 14.16)
9973function bnpSquareTo(r) {
9974 var x = this.abs();
9975 var i = r.t = 2*x.t;
9976 while(--i >= 0) r.data[i] = 0;
9977 for(i = 0; i < x.t-1; ++i) {
9978 var c = x.am(i,x.data[i],r,2*i,0,1);
9979 if((r.data[i+x.t]+=x.am(i+1,2*x.data[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
9980 r.data[i+x.t] -= x.DV;
9981 r.data[i+x.t+1] = 1;
9982 }
9983 }
9984 if(r.t > 0) r.data[r.t-1] += x.am(i,x.data[i],r,2*i,0,1);
9985 r.s = 0;
9986 r.clamp();
9987}
9988
9989// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
9990// r != q, this != m. q or r may be null.
9991function bnpDivRemTo(m,q,r) {
9992 var pm = m.abs();
9993 if(pm.t <= 0) return;
9994 var pt = this.abs();
9995 if(pt.t < pm.t) {
9996 if(q != null) q.fromInt(0);
9997 if(r != null) this.copyTo(r);
9998 return;
9999 }
10000 if(r == null) r = nbi();
10001 var y = nbi(), ts = this.s, ms = m.s;
10002 var nsh = this.DB-nbits(pm.data[pm.t-1]); // normalize modulus
10003 if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); } else { pm.copyTo(y); pt.copyTo(r); }
10004 var ys = y.t;
10005 var y0 = y.data[ys-1];
10006 if(y0 == 0) return;
10007 var yt = y0*(1<<this.F1)+((ys>1)?y.data[ys-2]>>this.F2:0);
10008 var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
10009 var i = r.t, j = i-ys, t = (q==null)?nbi():q;
10010 y.dlShiftTo(j,t);
10011 if(r.compareTo(t) >= 0) {
10012 r.data[r.t++] = 1;
10013 r.subTo(t,r);
10014 }
10015 BigInteger.ONE.dlShiftTo(ys,t);
10016 t.subTo(y,y); // "negative" y so we can replace sub with am later
10017 while(y.t < ys) y.data[y.t++] = 0;
10018 while(--j >= 0) {
10019 // Estimate quotient digit
10020 var qd = (r.data[--i]==y0)?this.DM:Math.floor(r.data[i]*d1+(r.data[i-1]+e)*d2);
10021 if((r.data[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out
10022 y.dlShiftTo(j,t);
10023 r.subTo(t,r);
10024 while(r.data[i] < --qd) r.subTo(t,r);
10025 }
10026 }
10027 if(q != null) {
10028 r.drShiftTo(ys,q);
10029 if(ts != ms) BigInteger.ZERO.subTo(q,q);
10030 }
10031 r.t = ys;
10032 r.clamp();
10033 if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder
10034 if(ts < 0) BigInteger.ZERO.subTo(r,r);
10035}
10036
10037// (public) this mod a
10038function bnMod(a) {
10039 var r = nbi();
10040 this.abs().divRemTo(a,null,r);
10041 if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
10042 return r;
10043}
10044
10045// Modular reduction using "classic" algorithm
10046function Classic(m) { this.m = m; }
10047function cConvert(x) {
10048 if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
10049 else return x;
10050}
10051function cRevert(x) { return x; }
10052function cReduce(x) { x.divRemTo(this.m,null,x); }
10053function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
10054function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
10055
10056Classic.prototype.convert = cConvert;
10057Classic.prototype.revert = cRevert;
10058Classic.prototype.reduce = cReduce;
10059Classic.prototype.mulTo = cMulTo;
10060Classic.prototype.sqrTo = cSqrTo;
10061
10062// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
10063// justification:
10064// xy == 1 (mod m)
10065// xy = 1+km
10066// xy(2-xy) = (1+km)(1-km)
10067// x[y(2-xy)] = 1-k^2m^2
10068// x[y(2-xy)] == 1 (mod m^2)
10069// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
10070// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
10071// JS multiply "overflows" differently from C/C++, so care is needed here.
10072function bnpInvDigit() {
10073 if(this.t < 1) return 0;
10074 var x = this.data[0];
10075 if((x&1) == 0) return 0;
10076 var y = x&3; // y == 1/x mod 2^2
10077 y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
10078 y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
10079 y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
10080 // last step - calculate inverse mod DV directly;
10081 // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
10082 y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits
10083 // we really want the negative inverse, and -DV < y < DV
10084 return (y>0)?this.DV-y:-y;
10085}
10086
10087// Montgomery reduction
10088function Montgomery(m) {
10089 this.m = m;
10090 this.mp = m.invDigit();
10091 this.mpl = this.mp&0x7fff;
10092 this.mph = this.mp>>15;
10093 this.um = (1<<(m.DB-15))-1;
10094 this.mt2 = 2*m.t;
10095}
10096
10097// xR mod m
10098function montConvert(x) {
10099 var r = nbi();
10100 x.abs().dlShiftTo(this.m.t,r);
10101 r.divRemTo(this.m,null,r);
10102 if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
10103 return r;
10104}
10105
10106// x/R mod m
10107function montRevert(x) {
10108 var r = nbi();
10109 x.copyTo(r);
10110 this.reduce(r);
10111 return r;
10112}
10113
10114// x = x/R mod m (HAC 14.32)
10115function montReduce(x) {
10116 while(x.t <= this.mt2) // pad x so am has enough room later
10117 x.data[x.t++] = 0;
10118 for(var i = 0; i < this.m.t; ++i) {
10119 // faster way of calculating u0 = x.data[i]*mp mod DV
10120 var j = x.data[i]&0x7fff;
10121 var u0 = (j*this.mpl+(((j*this.mph+(x.data[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
10122 // use am to combine the multiply-shift-add into one call
10123 j = i+this.m.t;
10124 x.data[j] += this.m.am(0,u0,x,i,0,this.m.t);
10125 // propagate carry
10126 while(x.data[j] >= x.DV) { x.data[j] -= x.DV; x.data[++j]++; }
10127 }
10128 x.clamp();
10129 x.drShiftTo(this.m.t,x);
10130 if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
10131}
10132
10133// r = "x^2/R mod m"; x != r
10134function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
10135
10136// r = "xy/R mod m"; x,y != r
10137function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
10138
10139Montgomery.prototype.convert = montConvert;
10140Montgomery.prototype.revert = montRevert;
10141Montgomery.prototype.reduce = montReduce;
10142Montgomery.prototype.mulTo = montMulTo;
10143Montgomery.prototype.sqrTo = montSqrTo;
10144
10145// (protected) true iff this is even
10146function bnpIsEven() { return ((this.t>0)?(this.data[0]&1):this.s) == 0; }
10147
10148// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
10149function bnpExp(e,z) {
10150 if(e > 0xffffffff || e < 1) return BigInteger.ONE;
10151 var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
10152 g.copyTo(r);
10153 while(--i >= 0) {
10154 z.sqrTo(r,r2);
10155 if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
10156 else { var t = r; r = r2; r2 = t; }
10157 }
10158 return z.revert(r);
10159}
10160
10161// (public) this^e % m, 0 <= e < 2^32
10162function bnModPowInt(e,m) {
10163 var z;
10164 if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
10165 return this.exp(e,z);
10166}
10167
10168// protected
10169BigInteger.prototype.copyTo = bnpCopyTo;
10170BigInteger.prototype.fromInt = bnpFromInt;
10171BigInteger.prototype.fromString = bnpFromString;
10172BigInteger.prototype.clamp = bnpClamp;
10173BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
10174BigInteger.prototype.drShiftTo = bnpDRShiftTo;
10175BigInteger.prototype.lShiftTo = bnpLShiftTo;
10176BigInteger.prototype.rShiftTo = bnpRShiftTo;
10177BigInteger.prototype.subTo = bnpSubTo;
10178BigInteger.prototype.multiplyTo = bnpMultiplyTo;
10179BigInteger.prototype.squareTo = bnpSquareTo;
10180BigInteger.prototype.divRemTo = bnpDivRemTo;
10181BigInteger.prototype.invDigit = bnpInvDigit;
10182BigInteger.prototype.isEven = bnpIsEven;
10183BigInteger.prototype.exp = bnpExp;
10184
10185// public
10186BigInteger.prototype.toString = bnToString;
10187BigInteger.prototype.negate = bnNegate;
10188BigInteger.prototype.abs = bnAbs;
10189BigInteger.prototype.compareTo = bnCompareTo;
10190BigInteger.prototype.bitLength = bnBitLength;
10191BigInteger.prototype.mod = bnMod;
10192BigInteger.prototype.modPowInt = bnModPowInt;
10193
10194// "constants"
10195BigInteger.ZERO = nbv(0);
10196BigInteger.ONE = nbv(1);
10197
10198// jsbn2 lib
10199
10200//Copyright (c) 2005-2009 Tom Wu
10201//All Rights Reserved.
10202//See "LICENSE" for details (See jsbn.js for LICENSE).
10203
10204//Extended JavaScript BN functions, required for RSA private ops.
10205
10206//Version 1.1: new BigInteger("0", 10) returns "proper" zero
10207
10208//(public)
10209function bnClone() { var r = nbi(); this.copyTo(r); return r; }
10210
10211//(public) return value as integer
10212function bnIntValue() {
10213if(this.s < 0) {
10214 if(this.t == 1) return this.data[0]-this.DV;
10215 else if(this.t == 0) return -1;
10216} else if(this.t == 1) return this.data[0];
10217else if(this.t == 0) return 0;
10218// assumes 16 < DB < 32
10219return ((this.data[1]&((1<<(32-this.DB))-1))<<this.DB)|this.data[0];
10220}
10221
10222//(public) return value as byte
10223function bnByteValue() { return (this.t==0)?this.s:(this.data[0]<<24)>>24; }
10224
10225//(public) return value as short (assumes DB>=16)
10226function bnShortValue() { return (this.t==0)?this.s:(this.data[0]<<16)>>16; }
10227
10228//(protected) return x s.t. r^x < DV
10229function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }
10230
10231//(public) 0 if this == 0, 1 if this > 0
10232function bnSigNum() {
10233if(this.s < 0) return -1;
10234else if(this.t <= 0 || (this.t == 1 && this.data[0] <= 0)) return 0;
10235else return 1;
10236}
10237
10238//(protected) convert to radix string
10239function bnpToRadix(b) {
10240if(b == null) b = 10;
10241if(this.signum() == 0 || b < 2 || b > 36) return "0";
10242var cs = this.chunkSize(b);
10243var a = Math.pow(b,cs);
10244var d = nbv(a), y = nbi(), z = nbi(), r = "";
10245this.divRemTo(d,y,z);
10246while(y.signum() > 0) {
10247 r = (a+z.intValue()).toString(b).substr(1) + r;
10248 y.divRemTo(d,y,z);
10249}
10250return z.intValue().toString(b) + r;
10251}
10252
10253//(protected) convert from radix string
10254function bnpFromRadix(s,b) {
10255this.fromInt(0);
10256if(b == null) b = 10;
10257var cs = this.chunkSize(b);
10258var d = Math.pow(b,cs), mi = false, j = 0, w = 0;
10259for(var i = 0; i < s.length; ++i) {
10260 var x = intAt(s,i);
10261 if(x < 0) {
10262 if(s.charAt(i) == "-" && this.signum() == 0) mi = true;
10263 continue;
10264 }
10265 w = b*w+x;
10266 if(++j >= cs) {
10267 this.dMultiply(d);
10268 this.dAddOffset(w,0);
10269 j = 0;
10270 w = 0;
10271 }
10272}
10273if(j > 0) {
10274 this.dMultiply(Math.pow(b,j));
10275 this.dAddOffset(w,0);
10276}
10277if(mi) BigInteger.ZERO.subTo(this,this);
10278}
10279
10280//(protected) alternate constructor
10281function bnpFromNumber(a,b,c) {
10282if("number" == typeof b) {
10283 // new BigInteger(int,int,RNG)
10284 if(a < 2) this.fromInt(1);
10285 else {
10286 this.fromNumber(a,c);
10287 if(!this.testBit(a-1)) // force MSB set
10288 this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);
10289 if(this.isEven()) this.dAddOffset(1,0); // force odd
10290 while(!this.isProbablePrime(b)) {
10291 this.dAddOffset(2,0);
10292 if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);
10293 }
10294 }
10295} else {
10296 // new BigInteger(int,RNG)
10297 var x = new Array(), t = a&7;
10298 x.length = (a>>3)+1;
10299 b.nextBytes(x);
10300 if(t > 0) x[0] &= ((1<<t)-1); else x[0] = 0;
10301 this.fromString(x,256);
10302}
10303}
10304
10305//(public) convert to bigendian byte array
10306function bnToByteArray() {
10307var i = this.t, r = new Array();
10308r[0] = this.s;
10309var p = this.DB-(i*this.DB)%8, d, k = 0;
10310if(i-- > 0) {
10311 if(p < this.DB && (d = this.data[i]>>p) != (this.s&this.DM)>>p)
10312 r[k++] = d|(this.s<<(this.DB-p));
10313 while(i >= 0) {
10314 if(p < 8) {
10315 d = (this.data[i]&((1<<p)-1))<<(8-p);
10316 d |= this.data[--i]>>(p+=this.DB-8);
10317 } else {
10318 d = (this.data[i]>>(p-=8))&0xff;
10319 if(p <= 0) { p += this.DB; --i; }
10320 }
10321 if((d&0x80) != 0) d |= -256;
10322 if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
10323 if(k > 0 || d != this.s) r[k++] = d;
10324 }
10325}
10326return r;
10327}
10328
10329function bnEquals(a) { return(this.compareTo(a)==0); }
10330function bnMin(a) { return(this.compareTo(a)<0)?this:a; }
10331function bnMax(a) { return(this.compareTo(a)>0)?this:a; }
10332
10333//(protected) r = this op a (bitwise)
10334function bnpBitwiseTo(a,op,r) {
10335var i, f, m = Math.min(a.t,this.t);
10336for(i = 0; i < m; ++i) r.data[i] = op(this.data[i],a.data[i]);
10337if(a.t < this.t) {
10338 f = a.s&this.DM;
10339 for(i = m; i < this.t; ++i) r.data[i] = op(this.data[i],f);
10340 r.t = this.t;
10341} else {
10342 f = this.s&this.DM;
10343 for(i = m; i < a.t; ++i) r.data[i] = op(f,a.data[i]);
10344 r.t = a.t;
10345}
10346r.s = op(this.s,a.s);
10347r.clamp();
10348}
10349
10350//(public) this & a
10351function op_and(x,y) { return x&y; }
10352function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }
10353
10354//(public) this | a
10355function op_or(x,y) { return x|y; }
10356function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }
10357
10358//(public) this ^ a
10359function op_xor(x,y) { return x^y; }
10360function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }
10361
10362//(public) this & ~a
10363function op_andnot(x,y) { return x&~y; }
10364function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }
10365
10366//(public) ~this
10367function bnNot() {
10368var r = nbi();
10369for(var i = 0; i < this.t; ++i) r.data[i] = this.DM&~this.data[i];
10370r.t = this.t;
10371r.s = ~this.s;
10372return r;
10373}
10374
10375//(public) this << n
10376function bnShiftLeft(n) {
10377var r = nbi();
10378if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);
10379return r;
10380}
10381
10382//(public) this >> n
10383function bnShiftRight(n) {
10384var r = nbi();
10385if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);
10386return r;
10387}
10388
10389//return index of lowest 1-bit in x, x < 2^31
10390function lbit(x) {
10391if(x == 0) return -1;
10392var r = 0;
10393if((x&0xffff) == 0) { x >>= 16; r += 16; }
10394if((x&0xff) == 0) { x >>= 8; r += 8; }
10395if((x&0xf) == 0) { x >>= 4; r += 4; }
10396if((x&3) == 0) { x >>= 2; r += 2; }
10397if((x&1) == 0) ++r;
10398return r;
10399}
10400
10401//(public) returns index of lowest 1-bit (or -1 if none)
10402function bnGetLowestSetBit() {
10403for(var i = 0; i < this.t; ++i)
10404 if(this.data[i] != 0) return i*this.DB+lbit(this.data[i]);
10405if(this.s < 0) return this.t*this.DB;
10406return -1;
10407}
10408
10409//return number of 1 bits in x
10410function cbit(x) {
10411var r = 0;
10412while(x != 0) { x &= x-1; ++r; }
10413return r;
10414}
10415
10416//(public) return number of set bits
10417function bnBitCount() {
10418var r = 0, x = this.s&this.DM;
10419for(var i = 0; i < this.t; ++i) r += cbit(this.data[i]^x);
10420return r;
10421}
10422
10423//(public) true iff nth bit is set
10424function bnTestBit(n) {
10425var j = Math.floor(n/this.DB);
10426if(j >= this.t) return(this.s!=0);
10427return((this.data[j]&(1<<(n%this.DB)))!=0);
10428}
10429
10430//(protected) this op (1<<n)
10431function bnpChangeBit(n,op) {
10432var r = BigInteger.ONE.shiftLeft(n);
10433this.bitwiseTo(r,op,r);
10434return r;
10435}
10436
10437//(public) this | (1<<n)
10438function bnSetBit(n) { return this.changeBit(n,op_or); }
10439
10440//(public) this & ~(1<<n)
10441function bnClearBit(n) { return this.changeBit(n,op_andnot); }
10442
10443//(public) this ^ (1<<n)
10444function bnFlipBit(n) { return this.changeBit(n,op_xor); }
10445
10446//(protected) r = this + a
10447function bnpAddTo(a,r) {
10448var i = 0, c = 0, m = Math.min(a.t,this.t);
10449while(i < m) {
10450 c += this.data[i]+a.data[i];
10451 r.data[i++] = c&this.DM;
10452 c >>= this.DB;
10453}
10454if(a.t < this.t) {
10455 c += a.s;
10456 while(i < this.t) {
10457 c += this.data[i];
10458 r.data[i++] = c&this.DM;
10459 c >>= this.DB;
10460 }
10461 c += this.s;
10462} else {
10463 c += this.s;
10464 while(i < a.t) {
10465 c += a.data[i];
10466 r.data[i++] = c&this.DM;
10467 c >>= this.DB;
10468 }
10469 c += a.s;
10470}
10471r.s = (c<0)?-1:0;
10472if(c > 0) r.data[i++] = c;
10473else if(c < -1) r.data[i++] = this.DV+c;
10474r.t = i;
10475r.clamp();
10476}
10477
10478//(public) this + a
10479function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }
10480
10481//(public) this - a
10482function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }
10483
10484//(public) this * a
10485function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }
10486
10487//(public) this / a
10488function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }
10489
10490//(public) this % a
10491function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }
10492
10493//(public) [this/a,this%a]
10494function bnDivideAndRemainder(a) {
10495var q = nbi(), r = nbi();
10496this.divRemTo(a,q,r);
10497return new Array(q,r);
10498}
10499
10500//(protected) this *= n, this >= 0, 1 < n < DV
10501function bnpDMultiply(n) {
10502this.data[this.t] = this.am(0,n-1,this,0,0,this.t);
10503++this.t;
10504this.clamp();
10505}
10506
10507//(protected) this += n << w words, this >= 0
10508function bnpDAddOffset(n,w) {
10509if(n == 0) return;
10510while(this.t <= w) this.data[this.t++] = 0;
10511this.data[w] += n;
10512while(this.data[w] >= this.DV) {
10513 this.data[w] -= this.DV;
10514 if(++w >= this.t) this.data[this.t++] = 0;
10515 ++this.data[w];
10516}
10517}
10518
10519//A "null" reducer
10520function NullExp() {}
10521function nNop(x) { return x; }
10522function nMulTo(x,y,r) { x.multiplyTo(y,r); }
10523function nSqrTo(x,r) { x.squareTo(r); }
10524
10525NullExp.prototype.convert = nNop;
10526NullExp.prototype.revert = nNop;
10527NullExp.prototype.mulTo = nMulTo;
10528NullExp.prototype.sqrTo = nSqrTo;
10529
10530//(public) this^e
10531function bnPow(e) { return this.exp(e,new NullExp()); }
10532
10533//(protected) r = lower n words of "this * a", a.t <= n
10534//"this" should be the larger one if appropriate.
10535function bnpMultiplyLowerTo(a,n,r) {
10536var i = Math.min(this.t+a.t,n);
10537r.s = 0; // assumes a,this >= 0
10538r.t = i;
10539while(i > 0) r.data[--i] = 0;
10540var j;
10541for(j = r.t-this.t; i < j; ++i) r.data[i+this.t] = this.am(0,a.data[i],r,i,0,this.t);
10542for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a.data[i],r,i,0,n-i);
10543r.clamp();
10544}
10545
10546//(protected) r = "this * a" without lower n words, n > 0
10547//"this" should be the larger one if appropriate.
10548function bnpMultiplyUpperTo(a,n,r) {
10549--n;
10550var i = r.t = this.t+a.t-n;
10551r.s = 0; // assumes a,this >= 0
10552while(--i >= 0) r.data[i] = 0;
10553for(i = Math.max(n-this.t,0); i < a.t; ++i)
10554 r.data[this.t+i-n] = this.am(n-i,a.data[i],r,0,0,this.t+i-n);
10555r.clamp();
10556r.drShiftTo(1,r);
10557}
10558
10559//Barrett modular reduction
10560function Barrett(m) {
10561// setup Barrett
10562this.r2 = nbi();
10563this.q3 = nbi();
10564BigInteger.ONE.dlShiftTo(2*m.t,this.r2);
10565this.mu = this.r2.divide(m);
10566this.m = m;
10567}
10568
10569function barrettConvert(x) {
10570if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);
10571else if(x.compareTo(this.m) < 0) return x;
10572else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }
10573}
10574
10575function barrettRevert(x) { return x; }
10576
10577//x = x mod m (HAC 14.42)
10578function barrettReduce(x) {
10579x.drShiftTo(this.m.t-1,this.r2);
10580if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }
10581this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);
10582this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);
10583while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);
10584x.subTo(this.r2,x);
10585while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
10586}
10587
10588//r = x^2 mod m; x != r
10589function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }
10590
10591//r = x*y mod m; x,y != r
10592function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
10593
10594Barrett.prototype.convert = barrettConvert;
10595Barrett.prototype.revert = barrettRevert;
10596Barrett.prototype.reduce = barrettReduce;
10597Barrett.prototype.mulTo = barrettMulTo;
10598Barrett.prototype.sqrTo = barrettSqrTo;
10599
10600//(public) this^e % m (HAC 14.85)
10601function bnModPow(e,m) {
10602var i = e.bitLength(), k, r = nbv(1), z;
10603if(i <= 0) return r;
10604else if(i < 18) k = 1;
10605else if(i < 48) k = 3;
10606else if(i < 144) k = 4;
10607else if(i < 768) k = 5;
10608else k = 6;
10609if(i < 8)
10610 z = new Classic(m);
10611else if(m.isEven())
10612 z = new Barrett(m);
10613else
10614 z = new Montgomery(m);
10615
10616// precomputation
10617var g = new Array(), n = 3, k1 = k-1, km = (1<<k)-1;
10618g[1] = z.convert(this);
10619if(k > 1) {
10620 var g2 = nbi();
10621 z.sqrTo(g[1],g2);
10622 while(n <= km) {
10623 g[n] = nbi();
10624 z.mulTo(g2,g[n-2],g[n]);
10625 n += 2;
10626 }
10627}
10628
10629var j = e.t-1, w, is1 = true, r2 = nbi(), t;
10630i = nbits(e.data[j])-1;
10631while(j >= 0) {
10632 if(i >= k1) w = (e.data[j]>>(i-k1))&km;
10633 else {
10634 w = (e.data[j]&((1<<(i+1))-1))<<(k1-i);
10635 if(j > 0) w |= e.data[j-1]>>(this.DB+i-k1);
10636 }
10637
10638 n = k;
10639 while((w&1) == 0) { w >>= 1; --n; }
10640 if((i -= n) < 0) { i += this.DB; --j; }
10641 if(is1) { // ret == 1, don't bother squaring or multiplying it
10642 g[w].copyTo(r);
10643 is1 = false;
10644 } else {
10645 while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }
10646 if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }
10647 z.mulTo(r2,g[w],r);
10648 }
10649
10650 while(j >= 0 && (e.data[j]&(1<<i)) == 0) {
10651 z.sqrTo(r,r2); t = r; r = r2; r2 = t;
10652 if(--i < 0) { i = this.DB-1; --j; }
10653 }
10654}
10655return z.revert(r);
10656}
10657
10658//(public) gcd(this,a) (HAC 14.54)
10659function bnGCD(a) {
10660var x = (this.s<0)?this.negate():this.clone();
10661var y = (a.s<0)?a.negate():a.clone();
10662if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
10663var i = x.getLowestSetBit(), g = y.getLowestSetBit();
10664if(g < 0) return x;
10665if(i < g) g = i;
10666if(g > 0) {
10667 x.rShiftTo(g,x);
10668 y.rShiftTo(g,y);
10669}
10670while(x.signum() > 0) {
10671 if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);
10672 if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);
10673 if(x.compareTo(y) >= 0) {
10674 x.subTo(y,x);
10675 x.rShiftTo(1,x);
10676 } else {
10677 y.subTo(x,y);
10678 y.rShiftTo(1,y);
10679 }
10680}
10681if(g > 0) y.lShiftTo(g,y);
10682return y;
10683}
10684
10685//(protected) this % n, n < 2^26
10686function bnpModInt(n) {
10687if(n <= 0) return 0;
10688var d = this.DV%n, r = (this.s<0)?n-1:0;
10689if(this.t > 0)
10690 if(d == 0) r = this.data[0]%n;
10691 else for(var i = this.t-1; i >= 0; --i) r = (d*r+this.data[i])%n;
10692return r;
10693}
10694
10695//(public) 1/this % m (HAC 14.61)
10696function bnModInverse(m) {
10697var ac = m.isEven();
10698if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
10699var u = m.clone(), v = this.clone();
10700var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
10701while(u.signum() != 0) {
10702 while(u.isEven()) {
10703 u.rShiftTo(1,u);
10704 if(ac) {
10705 if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }
10706 a.rShiftTo(1,a);
10707 } else if(!b.isEven()) b.subTo(m,b);
10708 b.rShiftTo(1,b);
10709 }
10710 while(v.isEven()) {
10711 v.rShiftTo(1,v);
10712 if(ac) {
10713 if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }
10714 c.rShiftTo(1,c);
10715 } else if(!d.isEven()) d.subTo(m,d);
10716 d.rShiftTo(1,d);
10717 }
10718 if(u.compareTo(v) >= 0) {
10719 u.subTo(v,u);
10720 if(ac) a.subTo(c,a);
10721 b.subTo(d,b);
10722 } else {
10723 v.subTo(u,v);
10724 if(ac) c.subTo(a,c);
10725 d.subTo(b,d);
10726 }
10727}
10728if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
10729if(d.compareTo(m) >= 0) return d.subtract(m);
10730if(d.signum() < 0) d.addTo(m,d); else return d;
10731if(d.signum() < 0) return d.add(m); else return d;
10732}
10733
10734var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509];
10735var lplim = (1<<26)/lowprimes[lowprimes.length-1];
10736
10737//(public) test primality with certainty >= 1-.5^t
10738function bnIsProbablePrime(t) {
10739var i, x = this.abs();
10740if(x.t == 1 && x.data[0] <= lowprimes[lowprimes.length-1]) {
10741 for(i = 0; i < lowprimes.length; ++i)
10742 if(x.data[0] == lowprimes[i]) return true;
10743 return false;
10744}
10745if(x.isEven()) return false;
10746i = 1;
10747while(i < lowprimes.length) {
10748 var m = lowprimes[i], j = i+1;
10749 while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];
10750 m = x.modInt(m);
10751 while(i < j) if(m%lowprimes[i++] == 0) return false;
10752}
10753return x.millerRabin(t);
10754}
10755
10756//(protected) true if probably prime (HAC 4.24, Miller-Rabin)
10757function bnpMillerRabin(t) {
10758var n1 = this.subtract(BigInteger.ONE);
10759var k = n1.getLowestSetBit();
10760if(k <= 0) return false;
10761var r = n1.shiftRight(k);
10762var prng = bnGetPrng();
10763var a;
10764for(var i = 0; i < t; ++i) {
10765 // select witness 'a' at random from between 1 and n1
10766 do {
10767 a = new BigInteger(this.bitLength(), prng);
10768 }
10769 while(a.compareTo(BigInteger.ONE) <= 0 || a.compareTo(n1) >= 0);
10770 var y = a.modPow(r,this);
10771 if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
10772 var j = 1;
10773 while(j++ < k && y.compareTo(n1) != 0) {
10774 y = y.modPowInt(2,this);
10775 if(y.compareTo(BigInteger.ONE) == 0) return false;
10776 }
10777 if(y.compareTo(n1) != 0) return false;
10778 }
10779}
10780return true;
10781}
10782
10783// get pseudo random number generator
10784function bnGetPrng() {
10785 // create prng with api that matches BigInteger secure random
10786 return {
10787 // x is an array to fill with bytes
10788 nextBytes: function(x) {
10789 for(var i = 0; i < x.length; ++i) {
10790 x[i] = Math.floor(Math.random() * 0x0100);
10791 }
10792 }
10793 };
10794}
10795
10796//protected
10797BigInteger.prototype.chunkSize = bnpChunkSize;
10798BigInteger.prototype.toRadix = bnpToRadix;
10799BigInteger.prototype.fromRadix = bnpFromRadix;
10800BigInteger.prototype.fromNumber = bnpFromNumber;
10801BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
10802BigInteger.prototype.changeBit = bnpChangeBit;
10803BigInteger.prototype.addTo = bnpAddTo;
10804BigInteger.prototype.dMultiply = bnpDMultiply;
10805BigInteger.prototype.dAddOffset = bnpDAddOffset;
10806BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
10807BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
10808BigInteger.prototype.modInt = bnpModInt;
10809BigInteger.prototype.millerRabin = bnpMillerRabin;
10810
10811//public
10812BigInteger.prototype.clone = bnClone;
10813BigInteger.prototype.intValue = bnIntValue;
10814BigInteger.prototype.byteValue = bnByteValue;
10815BigInteger.prototype.shortValue = bnShortValue;
10816BigInteger.prototype.signum = bnSigNum;
10817BigInteger.prototype.toByteArray = bnToByteArray;
10818BigInteger.prototype.equals = bnEquals;
10819BigInteger.prototype.min = bnMin;
10820BigInteger.prototype.max = bnMax;
10821BigInteger.prototype.and = bnAnd;
10822BigInteger.prototype.or = bnOr;
10823BigInteger.prototype.xor = bnXor;
10824BigInteger.prototype.andNot = bnAndNot;
10825BigInteger.prototype.not = bnNot;
10826BigInteger.prototype.shiftLeft = bnShiftLeft;
10827BigInteger.prototype.shiftRight = bnShiftRight;
10828BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
10829BigInteger.prototype.bitCount = bnBitCount;
10830BigInteger.prototype.testBit = bnTestBit;
10831BigInteger.prototype.setBit = bnSetBit;
10832BigInteger.prototype.clearBit = bnClearBit;
10833BigInteger.prototype.flipBit = bnFlipBit;
10834BigInteger.prototype.add = bnAdd;
10835BigInteger.prototype.subtract = bnSubtract;
10836BigInteger.prototype.multiply = bnMultiply;
10837BigInteger.prototype.divide = bnDivide;
10838BigInteger.prototype.remainder = bnRemainder;
10839BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
10840BigInteger.prototype.modPow = bnModPow;
10841BigInteger.prototype.modInverse = bnModInverse;
10842BigInteger.prototype.pow = bnPow;
10843BigInteger.prototype.gcd = bnGCD;
10844BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
10845
10846//BigInteger interfaces not implemented in jsbn:
10847
10848//BigInteger(int signum, byte[] magnitude)
10849//double doubleValue()
10850//float floatValue()
10851//int hashCode()
10852//long longValue()
10853//static BigInteger valueOf(long val)
10854
10855forge.jsbn = forge.jsbn || {};
10856forge.jsbn.BigInteger = BigInteger;
10857
10858} // end module implementation
10859
10860/* ########## Begin module wrapper ########## */
10861var name = 'jsbn';
10862if(typeof define !== 'function') {
10863 // NodeJS -> AMD
10864 if(typeof module === 'object' && module.exports) {
10865 var nodeJS = true;
10866 define = function(ids, factory) {
10867 factory(require, module);
10868 };
10869 } else {
10870 // <script>
10871 if(typeof forge === 'undefined') {
10872 forge = {};
10873 }
10874 return initModule(forge);
10875 }
10876}
10877// AMD
10878var deps;
10879var defineFunc = function(require, module) {
10880 module.exports = function(forge) {
10881 var mods = deps.map(function(dep) {
10882 return require(dep);
10883 }).concat(initModule);
10884 // handle circular dependencies
10885 forge = forge || {};
10886 forge.defined = forge.defined || {};
10887 if(forge.defined[name]) {
10888 return forge[name];
10889 }
10890 forge.defined[name] = true;
10891 for(var i = 0; i < mods.length; ++i) {
10892 mods[i](forge);
10893 }
10894 return forge[name];
10895 };
10896};
10897var tmpDefine = define;
10898define = function(ids, factory) {
10899 deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
10900 if(nodeJS) {
10901 delete define;
10902 return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
10903 }
10904 define = tmpDefine;
10905 return define.apply(null, Array.prototype.slice.call(arguments, 0));
10906};
10907define(['require', 'module'], function() {
10908 defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
10909});
10910})();
10911
10912/**
10913 * Partial implementation of PKCS#1 v2.2: RSA-OEAP
10914 *
10915 * Modified but based on the following MIT and BSD licensed code:
10916 *
10917 * https://github.com/kjur/jsjws/blob/master/rsa.js:
10918 *
10919 * The 'jsjws'(JSON Web Signature JavaScript Library) License
10920 *
10921 * Copyright (c) 2012 Kenji Urushima
10922 *
10923 * Permission is hereby granted, free of charge, to any person obtaining a copy
10924 * of this software and associated documentation files (the "Software"), to deal
10925 * in the Software without restriction, including without limitation the rights
10926 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10927 * copies of the Software, and to permit persons to whom the Software is
10928 * furnished to do so, subject to the following conditions:
10929 *
10930 * The above copyright notice and this permission notice shall be included in
10931 * all copies or substantial portions of the Software.
10932 *
10933 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10934 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
10935 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10936 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
10937 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
10938 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
10939 * THE SOFTWARE.
10940 *
10941 * http://webrsa.cvs.sourceforge.net/viewvc/webrsa/Client/RSAES-OAEP.js?content-type=text%2Fplain:
10942 *
10943 * RSAES-OAEP.js
10944 * $Id: RSAES-OAEP.js,v 1.1.1.1 2003/03/19 15:37:20 ellispritchard Exp $
10945 * JavaScript Implementation of PKCS #1 v2.1 RSA CRYPTOGRAPHY STANDARD (RSA Laboratories, June 14, 2002)
10946 * Copyright (C) Ellis Pritchard, Guardian Unlimited 2003.
10947 * Contact: ellis@nukinetics.com
10948 * Distributed under the BSD License.
10949 *
10950 * Official documentation: http://www.rsa.com/rsalabs/node.asp?id=2125
10951 *
10952 * @author Evan Jones (http://evanjones.ca/)
10953 * @author Dave Longley
10954 *
10955 * Copyright (c) 2013-2014 Digital Bazaar, Inc.
10956 */
10957(function() {
10958/* ########## Begin module implementation ########## */
10959function initModule(forge) {
10960
10961// shortcut for PKCS#1 API
10962var pkcs1 = forge.pkcs1 = forge.pkcs1 || {};
10963
10964/**
10965 * Encode the given RSAES-OAEP message (M) using key, with optional label (L)
10966 * and seed.
10967 *
10968 * This method does not perform RSA encryption, it only encodes the message
10969 * using RSAES-OAEP.
10970 *
10971 * @param key the RSA key to use.
10972 * @param message the message to encode.
10973 * @param options the options to use:
10974 * label an optional label to use.
10975 * seed the seed to use.
10976 * md the message digest object to use, undefined for SHA-1.
10977 * mgf1 optional mgf1 parameters:
10978 * md the message digest object to use for MGF1.
10979 *
10980 * @return the encoded message bytes.
10981 */
10982pkcs1.encode_rsa_oaep = function(key, message, options) {
10983 // parse arguments
10984 var label;
10985 var seed;
10986 var md;
10987 var mgf1Md;
10988 // legacy args (label, seed, md)
10989 if(typeof options === 'string') {
10990 label = options;
10991 seed = arguments[3] || undefined;
10992 md = arguments[4] || undefined;
10993 } else if(options) {
10994 label = options.label || undefined;
10995 seed = options.seed || undefined;
10996 md = options.md || undefined;
10997 if(options.mgf1 && options.mgf1.md) {
10998 mgf1Md = options.mgf1.md;
10999 }
11000 }
11001
11002 // default OAEP to SHA-1 message digest
11003 if(!md) {
11004 md = forge.md.sha1.create();
11005 } else {
11006 md.start();
11007 }
11008
11009 // default MGF-1 to same as OAEP
11010 if(!mgf1Md) {
11011 mgf1Md = md;
11012 }
11013
11014 // compute length in bytes and check output
11015 var keyLength = Math.ceil(key.n.bitLength() / 8);
11016 var maxLength = keyLength - 2 * md.digestLength - 2;
11017 if(message.length > maxLength) {
11018 var error = new Error('RSAES-OAEP input message length is too long.');
11019 error.length = message.length;
11020 error.maxLength = maxLength;
11021 throw error;
11022 }
11023
11024 if(!label) {
11025 label = '';
11026 }
11027 md.update(label, 'raw');
11028 var lHash = md.digest();
11029
11030 var PS = '';
11031 var PS_length = maxLength - message.length;
11032 for (var i = 0; i < PS_length; i++) {
11033 PS += '\x00';
11034 }
11035
11036 var DB = lHash.getBytes() + PS + '\x01' + message;
11037
11038 if(!seed) {
11039 seed = forge.random.getBytes(md.digestLength);
11040 } else if(seed.length !== md.digestLength) {
11041 var error = new Error('Invalid RSAES-OAEP seed. The seed length must ' +
11042 'match the digest length.')
11043 error.seedLength = seed.length;
11044 error.digestLength = md.digestLength;
11045 throw error;
11046 }
11047
11048 var dbMask = rsa_mgf1(seed, keyLength - md.digestLength - 1, mgf1Md);
11049 var maskedDB = forge.util.xorBytes(DB, dbMask, DB.length);
11050
11051 var seedMask = rsa_mgf1(maskedDB, md.digestLength, mgf1Md);
11052 var maskedSeed = forge.util.xorBytes(seed, seedMask, seed.length);
11053
11054 // return encoded message
11055 return '\x00' + maskedSeed + maskedDB;
11056};
11057
11058/**
11059 * Decode the given RSAES-OAEP encoded message (EM) using key, with optional
11060 * label (L).
11061 *
11062 * This method does not perform RSA decryption, it only decodes the message
11063 * using RSAES-OAEP.
11064 *
11065 * @param key the RSA key to use.
11066 * @param em the encoded message to decode.
11067 * @param options the options to use:
11068 * label an optional label to use.
11069 * md the message digest object to use for OAEP, undefined for SHA-1.
11070 * mgf1 optional mgf1 parameters:
11071 * md the message digest object to use for MGF1.
11072 *
11073 * @return the decoded message bytes.
11074 */
11075pkcs1.decode_rsa_oaep = function(key, em, options) {
11076 // parse args
11077 var label;
11078 var md;
11079 var mgf1Md;
11080 // legacy args
11081 if(typeof options === 'string') {
11082 label = options;
11083 md = arguments[3] || undefined;
11084 } else if(options) {
11085 label = options.label || undefined;
11086 md = options.md || undefined;
11087 if(options.mgf1 && options.mgf1.md) {
11088 mgf1Md = options.mgf1.md;
11089 }
11090 }
11091
11092 // compute length in bytes
11093 var keyLength = Math.ceil(key.n.bitLength() / 8);
11094
11095 if(em.length !== keyLength) {
11096 var error = new Error('RSAES-OAEP encoded message length is invalid.');
11097 error.length = em.length;
11098 error.expectedLength = keyLength;
11099 throw error;
11100 }
11101
11102 // default OAEP to SHA-1 message digest
11103 if(md === undefined) {
11104 md = forge.md.sha1.create();
11105 } else {
11106 md.start();
11107 }
11108
11109 // default MGF-1 to same as OAEP
11110 if(!mgf1Md) {
11111 mgf1Md = md;
11112 }
11113
11114 if(keyLength < 2 * md.digestLength + 2) {
11115 throw new Error('RSAES-OAEP key is too short for the hash function.');
11116 }
11117
11118 if(!label) {
11119 label = '';
11120 }
11121 md.update(label, 'raw');
11122 var lHash = md.digest().getBytes();
11123
11124 // split the message into its parts
11125 var y = em.charAt(0);
11126 var maskedSeed = em.substring(1, md.digestLength + 1);
11127 var maskedDB = em.substring(1 + md.digestLength);
11128
11129 var seedMask = rsa_mgf1(maskedDB, md.digestLength, mgf1Md);
11130 var seed = forge.util.xorBytes(maskedSeed, seedMask, maskedSeed.length);
11131
11132 var dbMask = rsa_mgf1(seed, keyLength - md.digestLength - 1, mgf1Md);
11133 var db = forge.util.xorBytes(maskedDB, dbMask, maskedDB.length);
11134
11135 var lHashPrime = db.substring(0, md.digestLength);
11136
11137 // constant time check that all values match what is expected
11138 var error = (y !== '\x00');
11139
11140 // constant time check lHash vs lHashPrime
11141 for(var i = 0; i < md.digestLength; ++i) {
11142 error |= (lHash.charAt(i) !== lHashPrime.charAt(i));
11143 }
11144
11145 // "constant time" find the 0x1 byte separating the padding (zeros) from the
11146 // message
11147 // TODO: It must be possible to do this in a better/smarter way?
11148 var in_ps = 1;
11149 var index = md.digestLength;
11150 for(var j = md.digestLength; j < db.length; j++) {
11151 var code = db.charCodeAt(j);
11152
11153 var is_0 = (code & 0x1) ^ 0x1;
11154
11155 // non-zero if not 0 or 1 in the ps section
11156 var error_mask = in_ps ? 0xfffe : 0x0000;
11157 error |= (code & error_mask);
11158
11159 // latch in_ps to zero after we find 0x1
11160 in_ps = in_ps & is_0;
11161 index += in_ps;
11162 }
11163
11164 if(error || db.charCodeAt(index) !== 0x1) {
11165 throw new Error('Invalid RSAES-OAEP padding.');
11166 }
11167
11168 return db.substring(index + 1);
11169};
11170
11171function rsa_mgf1(seed, maskLength, hash) {
11172 // default to SHA-1 message digest
11173 if(!hash) {
11174 hash = forge.md.sha1.create();
11175 }
11176 var t = '';
11177 var count = Math.ceil(maskLength / hash.digestLength);
11178 for(var i = 0; i < count; ++i) {
11179 var c = String.fromCharCode(
11180 (i >> 24) & 0xFF, (i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF);
11181 hash.start();
11182 hash.update(seed + c);
11183 t += hash.digest().getBytes();
11184 }
11185 return t.substring(0, maskLength);
11186}
11187
11188} // end module implementation
11189
11190/* ########## Begin module wrapper ########## */
11191var name = 'pkcs1';
11192if(typeof define !== 'function') {
11193 // NodeJS -> AMD
11194 if(typeof module === 'object' && module.exports) {
11195 var nodeJS = true;
11196 define = function(ids, factory) {
11197 factory(require, module);
11198 };
11199 } else {
11200 // <script>
11201 if(typeof forge === 'undefined') {
11202 forge = {};
11203 }
11204 return initModule(forge);
11205 }
11206}
11207// AMD
11208var deps;
11209var defineFunc = function(require, module) {
11210 module.exports = function(forge) {
11211 var mods = deps.map(function(dep) {
11212 return require(dep);
11213 }).concat(initModule);
11214 // handle circular dependencies
11215 forge = forge || {};
11216 forge.defined = forge.defined || {};
11217 if(forge.defined[name]) {
11218 return forge[name];
11219 }
11220 forge.defined[name] = true;
11221 for(var i = 0; i < mods.length; ++i) {
11222 mods[i](forge);
11223 }
11224 return forge[name];
11225 };
11226};
11227var tmpDefine = define;
11228define = function(ids, factory) {
11229 deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
11230 if(nodeJS) {
11231 delete define;
11232 return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
11233 }
11234 define = tmpDefine;
11235 return define.apply(null, Array.prototype.slice.call(arguments, 0));
11236};
11237define(['require', 'module', './util', './random', './sha1'], function() {
11238 defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
11239});
11240})();
11241
11242/**
11243 * Javascript implementation of basic RSA algorithms.
11244 *
11245 * @author Dave Longley
11246 *
11247 * Copyright (c) 2010-2014 Digital Bazaar, Inc.
11248 *
11249 * The only algorithm currently supported for PKI is RSA.
11250 *
11251 * An RSA key is often stored in ASN.1 DER format. The SubjectPublicKeyInfo
11252 * ASN.1 structure is composed of an algorithm of type AlgorithmIdentifier
11253 * and a subjectPublicKey of type bit string.
11254 *
11255 * The AlgorithmIdentifier contains an Object Identifier (OID) and parameters
11256 * for the algorithm, if any. In the case of RSA, there aren't any.
11257 *
11258 * SubjectPublicKeyInfo ::= SEQUENCE {
11259 * algorithm AlgorithmIdentifier,
11260 * subjectPublicKey BIT STRING
11261 * }
11262 *
11263 * AlgorithmIdentifer ::= SEQUENCE {
11264 * algorithm OBJECT IDENTIFIER,
11265 * parameters ANY DEFINED BY algorithm OPTIONAL
11266 * }
11267 *
11268 * For an RSA public key, the subjectPublicKey is:
11269 *
11270 * RSAPublicKey ::= SEQUENCE {
11271 * modulus INTEGER, -- n
11272 * publicExponent INTEGER -- e
11273 * }
11274 *
11275 * PrivateKeyInfo ::= SEQUENCE {
11276 * version Version,
11277 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
11278 * privateKey PrivateKey,
11279 * attributes [0] IMPLICIT Attributes OPTIONAL
11280 * }
11281 *
11282 * Version ::= INTEGER
11283 * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
11284 * PrivateKey ::= OCTET STRING
11285 * Attributes ::= SET OF Attribute
11286 *
11287 * An RSA private key as the following structure:
11288 *
11289 * RSAPrivateKey ::= SEQUENCE {
11290 * version Version,
11291 * modulus INTEGER, -- n
11292 * publicExponent INTEGER, -- e
11293 * privateExponent INTEGER, -- d
11294 * prime1 INTEGER, -- p
11295 * prime2 INTEGER, -- q
11296 * exponent1 INTEGER, -- d mod (p-1)
11297 * exponent2 INTEGER, -- d mod (q-1)
11298 * coefficient INTEGER -- (inverse of q) mod p
11299 * }
11300 *
11301 * Version ::= INTEGER
11302 *
11303 * The OID for the RSA key algorithm is: 1.2.840.113549.1.1.1
11304 */
11305(function() {
11306function initModule(forge) {
11307/* ########## Begin module implementation ########## */
11308
11309if(typeof BigInteger === 'undefined') {
11310 var BigInteger = forge.jsbn.BigInteger;
11311}
11312
11313// shortcut for asn.1 API
11314var asn1 = forge.asn1;
11315
11316/*
11317 * RSA encryption and decryption, see RFC 2313.
11318 */
11319forge.pki = forge.pki || {};
11320forge.pki.rsa = forge.rsa = forge.rsa || {};
11321var pki = forge.pki;
11322
11323// for finding primes, which are 30k+i for i = 1, 7, 11, 13, 17, 19, 23, 29
11324var GCD_30_DELTA = [6, 4, 2, 4, 2, 4, 6, 2];
11325
11326// validator for a PrivateKeyInfo structure
11327var privateKeyValidator = {
11328 // PrivateKeyInfo
11329 name: 'PrivateKeyInfo',
11330 tagClass: asn1.Class.UNIVERSAL,
11331 type: asn1.Type.SEQUENCE,
11332 constructed: true,
11333 value: [{
11334 // Version (INTEGER)
11335 name: 'PrivateKeyInfo.version',
11336 tagClass: asn1.Class.UNIVERSAL,
11337 type: asn1.Type.INTEGER,
11338 constructed: false,
11339 capture: 'privateKeyVersion'
11340 }, {
11341 // privateKeyAlgorithm
11342 name: 'PrivateKeyInfo.privateKeyAlgorithm',
11343 tagClass: asn1.Class.UNIVERSAL,
11344 type: asn1.Type.SEQUENCE,
11345 constructed: true,
11346 value: [{
11347 name: 'AlgorithmIdentifier.algorithm',
11348 tagClass: asn1.Class.UNIVERSAL,
11349 type: asn1.Type.OID,
11350 constructed: false,
11351 capture: 'privateKeyOid'
11352 }]
11353 }, {
11354 // PrivateKey
11355 name: 'PrivateKeyInfo',
11356 tagClass: asn1.Class.UNIVERSAL,
11357 type: asn1.Type.OCTETSTRING,
11358 constructed: false,
11359 capture: 'privateKey'
11360 }]
11361};
11362
11363// validator for an RSA private key
11364var rsaPrivateKeyValidator = {
11365 // RSAPrivateKey
11366 name: 'RSAPrivateKey',
11367 tagClass: asn1.Class.UNIVERSAL,
11368 type: asn1.Type.SEQUENCE,
11369 constructed: true,
11370 value: [{
11371 // Version (INTEGER)
11372 name: 'RSAPrivateKey.version',
11373 tagClass: asn1.Class.UNIVERSAL,
11374 type: asn1.Type.INTEGER,
11375 constructed: false,
11376 capture: 'privateKeyVersion'
11377 }, {
11378 // modulus (n)
11379 name: 'RSAPrivateKey.modulus',
11380 tagClass: asn1.Class.UNIVERSAL,
11381 type: asn1.Type.INTEGER,
11382 constructed: false,
11383 capture: 'privateKeyModulus'
11384 }, {
11385 // publicExponent (e)
11386 name: 'RSAPrivateKey.publicExponent',
11387 tagClass: asn1.Class.UNIVERSAL,
11388 type: asn1.Type.INTEGER,
11389 constructed: false,
11390 capture: 'privateKeyPublicExponent'
11391 }, {
11392 // privateExponent (d)
11393 name: 'RSAPrivateKey.privateExponent',
11394 tagClass: asn1.Class.UNIVERSAL,
11395 type: asn1.Type.INTEGER,
11396 constructed: false,
11397 capture: 'privateKeyPrivateExponent'
11398 }, {
11399 // prime1 (p)
11400 name: 'RSAPrivateKey.prime1',
11401 tagClass: asn1.Class.UNIVERSAL,
11402 type: asn1.Type.INTEGER,
11403 constructed: false,
11404 capture: 'privateKeyPrime1'
11405 }, {
11406 // prime2 (q)
11407 name: 'RSAPrivateKey.prime2',
11408 tagClass: asn1.Class.UNIVERSAL,
11409 type: asn1.Type.INTEGER,
11410 constructed: false,
11411 capture: 'privateKeyPrime2'
11412 }, {
11413 // exponent1 (d mod (p-1))
11414 name: 'RSAPrivateKey.exponent1',
11415 tagClass: asn1.Class.UNIVERSAL,
11416 type: asn1.Type.INTEGER,
11417 constructed: false,
11418 capture: 'privateKeyExponent1'
11419 }, {
11420 // exponent2 (d mod (q-1))
11421 name: 'RSAPrivateKey.exponent2',
11422 tagClass: asn1.Class.UNIVERSAL,
11423 type: asn1.Type.INTEGER,
11424 constructed: false,
11425 capture: 'privateKeyExponent2'
11426 }, {
11427 // coefficient ((inverse of q) mod p)
11428 name: 'RSAPrivateKey.coefficient',
11429 tagClass: asn1.Class.UNIVERSAL,
11430 type: asn1.Type.INTEGER,
11431 constructed: false,
11432 capture: 'privateKeyCoefficient'
11433 }]
11434};
11435
11436// validator for an RSA public key
11437var rsaPublicKeyValidator = {
11438 // RSAPublicKey
11439 name: 'RSAPublicKey',
11440 tagClass: asn1.Class.UNIVERSAL,
11441 type: asn1.Type.SEQUENCE,
11442 constructed: true,
11443 value: [{
11444 // modulus (n)
11445 name: 'RSAPublicKey.modulus',
11446 tagClass: asn1.Class.UNIVERSAL,
11447 type: asn1.Type.INTEGER,
11448 constructed: false,
11449 capture: 'publicKeyModulus'
11450 }, {
11451 // publicExponent (e)
11452 name: 'RSAPublicKey.exponent',
11453 tagClass: asn1.Class.UNIVERSAL,
11454 type: asn1.Type.INTEGER,
11455 constructed: false,
11456 capture: 'publicKeyExponent'
11457 }]
11458};
11459
11460// validator for an SubjectPublicKeyInfo structure
11461// Note: Currently only works with an RSA public key
11462var publicKeyValidator = forge.pki.rsa.publicKeyValidator = {
11463 name: 'SubjectPublicKeyInfo',
11464 tagClass: asn1.Class.UNIVERSAL,
11465 type: asn1.Type.SEQUENCE,
11466 constructed: true,
11467 captureAsn1: 'subjectPublicKeyInfo',
11468 value: [{
11469 name: 'SubjectPublicKeyInfo.AlgorithmIdentifier',
11470 tagClass: asn1.Class.UNIVERSAL,
11471 type: asn1.Type.SEQUENCE,
11472 constructed: true,
11473 value: [{
11474 name: 'AlgorithmIdentifier.algorithm',
11475 tagClass: asn1.Class.UNIVERSAL,
11476 type: asn1.Type.OID,
11477 constructed: false,
11478 capture: 'publicKeyOid'
11479 }]
11480 }, {
11481 // subjectPublicKey
11482 name: 'SubjectPublicKeyInfo.subjectPublicKey',
11483 tagClass: asn1.Class.UNIVERSAL,
11484 type: asn1.Type.BITSTRING,
11485 constructed: false,
11486 value: [{
11487 // RSAPublicKey
11488 name: 'SubjectPublicKeyInfo.subjectPublicKey.RSAPublicKey',
11489 tagClass: asn1.Class.UNIVERSAL,
11490 type: asn1.Type.SEQUENCE,
11491 constructed: true,
11492 optional: true,
11493 captureAsn1: 'rsaPublicKey'
11494 }]
11495 }]
11496};
11497
11498/**
11499 * Wrap digest in DigestInfo object.
11500 *
11501 * This function implements EMSA-PKCS1-v1_5-ENCODE as per RFC 3447.
11502 *
11503 * DigestInfo ::= SEQUENCE {
11504 * digestAlgorithm DigestAlgorithmIdentifier,
11505 * digest Digest
11506 * }
11507 *
11508 * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
11509 * Digest ::= OCTET STRING
11510 *
11511 * @param md the message digest object with the hash to sign.
11512 *
11513 * @return the encoded message (ready for RSA encrytion)
11514 */
11515var emsaPkcs1v15encode = function(md) {
11516 // get the oid for the algorithm
11517 var oid;
11518 if(md.algorithm in pki.oids) {
11519 oid = pki.oids[md.algorithm];
11520 } else {
11521 var error = new Error('Unknown message digest algorithm.');
11522 error.algorithm = md.algorithm;
11523 throw error;
11524 }
11525 var oidBytes = asn1.oidToDer(oid).getBytes();
11526
11527 // create the digest info
11528 var digestInfo = asn1.create(
11529 asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
11530 var digestAlgorithm = asn1.create(
11531 asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, []);
11532 digestAlgorithm.value.push(asn1.create(
11533 asn1.Class.UNIVERSAL, asn1.Type.OID, false, oidBytes));
11534 digestAlgorithm.value.push(asn1.create(
11535 asn1.Class.UNIVERSAL, asn1.Type.NULL, false, ''));
11536 var digest = asn1.create(
11537 asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING,
11538 false, md.digest().getBytes());
11539 digestInfo.value.push(digestAlgorithm);
11540 digestInfo.value.push(digest);
11541
11542 // encode digest info
11543 return asn1.toDer(digestInfo).getBytes();
11544};
11545
11546/**
11547 * Performs x^c mod n (RSA encryption or decryption operation).
11548 *
11549 * @param x the number to raise and mod.
11550 * @param key the key to use.
11551 * @param pub true if the key is public, false if private.
11552 *
11553 * @return the result of x^c mod n.
11554 */
11555var _modPow = function(x, key, pub) {
11556 if(pub) {
11557 return x.modPow(key.e, key.n);
11558 }
11559
11560 if(!key.p || !key.q) {
11561 // allow calculation without CRT params (slow)
11562 return x.modPow(key.d, key.n);
11563 }
11564
11565 // pre-compute dP, dQ, and qInv if necessary
11566 if(!key.dP) {
11567 key.dP = key.d.mod(key.p.subtract(BigInteger.ONE));
11568 }
11569 if(!key.dQ) {
11570 key.dQ = key.d.mod(key.q.subtract(BigInteger.ONE));
11571 }
11572 if(!key.qInv) {
11573 key.qInv = key.q.modInverse(key.p);
11574 }
11575
11576 /* Chinese remainder theorem (CRT) states:
11577
11578 Suppose n1, n2, ..., nk are positive integers which are pairwise
11579 coprime (n1 and n2 have no common factors other than 1). For any
11580 integers x1, x2, ..., xk there exists an integer x solving the
11581 system of simultaneous congruences (where ~= means modularly
11582 congruent so a ~= b mod n means a mod n = b mod n):
11583
11584 x ~= x1 mod n1
11585 x ~= x2 mod n2
11586 ...
11587 x ~= xk mod nk
11588
11589 This system of congruences has a single simultaneous solution x
11590 between 0 and n - 1. Furthermore, each xk solution and x itself
11591 is congruent modulo the product n = n1*n2*...*nk.
11592 So x1 mod n = x2 mod n = xk mod n = x mod n.
11593
11594 The single simultaneous solution x can be solved with the following
11595 equation:
11596
11597 x = sum(xi*ri*si) mod n where ri = n/ni and si = ri^-1 mod ni.
11598
11599 Where x is less than n, xi = x mod ni.
11600
11601 For RSA we are only concerned with k = 2. The modulus n = pq, where
11602 p and q are coprime. The RSA decryption algorithm is:
11603
11604 y = x^d mod n
11605
11606 Given the above:
11607
11608 x1 = x^d mod p
11609 r1 = n/p = q
11610 s1 = q^-1 mod p
11611 x2 = x^d mod q
11612 r2 = n/q = p
11613 s2 = p^-1 mod q
11614
11615 So y = (x1r1s1 + x2r2s2) mod n
11616 = ((x^d mod p)q(q^-1 mod p) + (x^d mod q)p(p^-1 mod q)) mod n
11617
11618 According to Fermat's Little Theorem, if the modulus P is prime,
11619 for any integer A not evenly divisible by P, A^(P-1) ~= 1 mod P.
11620 Since A is not divisible by P it follows that if:
11621 N ~= M mod (P - 1), then A^N mod P = A^M mod P. Therefore:
11622
11623 A^N mod P = A^(M mod (P - 1)) mod P. (The latter takes less effort
11624 to calculate). In order to calculate x^d mod p more quickly the
11625 exponent d mod (p - 1) is stored in the RSA private key (the same
11626 is done for x^d mod q). These values are referred to as dP and dQ
11627 respectively. Therefore we now have:
11628
11629 y = ((x^dP mod p)q(q^-1 mod p) + (x^dQ mod q)p(p^-1 mod q)) mod n
11630
11631 Since we'll be reducing x^dP by modulo p (same for q) we can also
11632 reduce x by p (and q respectively) before hand. Therefore, let
11633
11634 xp = ((x mod p)^dP mod p), and
11635 xq = ((x mod q)^dQ mod q), yielding:
11636
11637 y = (xp*q*(q^-1 mod p) + xq*p*(p^-1 mod q)) mod n
11638
11639 This can be further reduced to a simple algorithm that only
11640 requires 1 inverse (the q inverse is used) to be used and stored.
11641 The algorithm is called Garner's algorithm. If qInv is the
11642 inverse of q, we simply calculate:
11643
11644 y = (qInv*(xp - xq) mod p) * q + xq
11645
11646 However, there are two further complications. First, we need to
11647 ensure that xp > xq to prevent signed BigIntegers from being used
11648 so we add p until this is true (since we will be mod'ing with
11649 p anyway). Then, there is a known timing attack on algorithms
11650 using the CRT. To mitigate this risk, "cryptographic blinding"
11651 should be used. This requires simply generating a random number r
11652 between 0 and n-1 and its inverse and multiplying x by r^e before
11653 calculating y and then multiplying y by r^-1 afterwards. Note that
11654 r must be coprime with n (gcd(r, n) === 1) in order to have an
11655 inverse.
11656 */
11657
11658 // cryptographic blinding
11659 var r;
11660 do {
11661 r = new BigInteger(
11662 forge.util.bytesToHex(forge.random.getBytes(key.n.bitLength() / 8)),
11663 16);
11664 } while(r.compareTo(key.n) >= 0 || !r.gcd(key.n).equals(BigInteger.ONE));
11665 x = x.multiply(r.modPow(key.e, key.n)).mod(key.n);
11666
11667 // calculate xp and xq
11668 var xp = x.mod(key.p).modPow(key.dP, key.p);
11669 var xq = x.mod(key.q).modPow(key.dQ, key.q);
11670
11671 // xp must be larger than xq to avoid signed bit usage
11672 while(xp.compareTo(xq) < 0) {
11673 xp = xp.add(key.p);
11674 }
11675
11676 // do last step
11677 var y = xp.subtract(xq)
11678 .multiply(key.qInv).mod(key.p)
11679 .multiply(key.q).add(xq);
11680
11681 // remove effect of random for cryptographic blinding
11682 y = y.multiply(r.modInverse(key.n)).mod(key.n);
11683
11684 return y;
11685};
11686
11687/**
11688 * NOTE: THIS METHOD IS DEPRECATED, use 'sign' on a private key object or
11689 * 'encrypt' on a public key object instead.
11690 *
11691 * Performs RSA encryption.
11692 *
11693 * The parameter bt controls whether to put padding bytes before the
11694 * message passed in. Set bt to either true or false to disable padding
11695 * completely (in order to handle e.g. EMSA-PSS encoding seperately before),
11696 * signaling whether the encryption operation is a public key operation
11697 * (i.e. encrypting data) or not, i.e. private key operation (data signing).
11698 *
11699 * For PKCS#1 v1.5 padding pass in the block type to use, i.e. either 0x01
11700 * (for signing) or 0x02 (for encryption). The key operation mode (private
11701 * or public) is derived from this flag in that case).
11702 *
11703 * @param m the message to encrypt as a byte string.
11704 * @param key the RSA key to use.
11705 * @param bt for PKCS#1 v1.5 padding, the block type to use
11706 * (0x01 for private key, 0x02 for public),
11707 * to disable padding: true = public key, false = private key.
11708 *
11709 * @return the encrypted bytes as a string.
11710 */
11711pki.rsa.encrypt = function(m, key, bt) {
11712 var pub = bt;
11713 var eb;
11714
11715 // get the length of the modulus in bytes
11716 var k = Math.ceil(key.n.bitLength() / 8);
11717
11718 if(bt !== false && bt !== true) {
11719 // legacy, default to PKCS#1 v1.5 padding
11720 pub = (bt === 0x02);
11721 eb = _encodePkcs1_v1_5(m, key, bt);
11722 } else {
11723 eb = forge.util.createBuffer();
11724 eb.putBytes(m);
11725 }
11726
11727 // load encryption block as big integer 'x'
11728 // FIXME: hex conversion inefficient, get BigInteger w/byte strings
11729 var x = new BigInteger(eb.toHex(), 16);
11730
11731 // do RSA encryption
11732 var y = _modPow(x, key, pub);
11733
11734 // convert y into the encrypted data byte string, if y is shorter in
11735 // bytes than k, then prepend zero bytes to fill up ed
11736 // FIXME: hex conversion inefficient, get BigInteger w/byte strings
11737 var yhex = y.toString(16);
11738 var ed = forge.util.createBuffer();
11739 var zeros = k - Math.ceil(yhex.length / 2);
11740 while(zeros > 0) {
11741 ed.putByte(0x00);
11742 --zeros;
11743 }
11744 ed.putBytes(forge.util.hexToBytes(yhex));
11745 return ed.getBytes();
11746};
11747
11748/**
11749 * NOTE: THIS METHOD IS DEPRECATED, use 'decrypt' on a private key object or
11750 * 'verify' on a public key object instead.
11751 *
11752 * Performs RSA decryption.
11753 *
11754 * The parameter ml controls whether to apply PKCS#1 v1.5 padding
11755 * or not. Set ml = false to disable padding removal completely
11756 * (in order to handle e.g. EMSA-PSS later on) and simply pass back
11757 * the RSA encryption block.
11758 *
11759 * @param ed the encrypted data to decrypt in as a byte string.
11760 * @param key the RSA key to use.
11761 * @param pub true for a public key operation, false for private.
11762 * @param ml the message length, if known, false to disable padding.
11763 *
11764 * @return the decrypted message as a byte string.
11765 */
11766pki.rsa.decrypt = function(ed, key, pub, ml) {
11767 // get the length of the modulus in bytes
11768 var k = Math.ceil(key.n.bitLength() / 8);
11769
11770 // error if the length of the encrypted data ED is not k
11771 if(ed.length !== k) {
11772 var error = new Error('Encrypted message length is invalid.');
11773 error.length = ed.length;
11774 error.expected = k;
11775 throw error;
11776 }
11777
11778 // convert encrypted data into a big integer
11779 // FIXME: hex conversion inefficient, get BigInteger w/byte strings
11780 var y = new BigInteger(forge.util.createBuffer(ed).toHex(), 16);
11781
11782 // y must be less than the modulus or it wasn't the result of
11783 // a previous mod operation (encryption) using that modulus
11784 if(y.compareTo(key.n) >= 0) {
11785 throw new Error('Encrypted message is invalid.');
11786 }
11787
11788 // do RSA decryption
11789 var x = _modPow(y, key, pub);
11790
11791 // create the encryption block, if x is shorter in bytes than k, then
11792 // prepend zero bytes to fill up eb
11793 // FIXME: hex conversion inefficient, get BigInteger w/byte strings
11794 var xhex = x.toString(16);
11795 var eb = forge.util.createBuffer();
11796 var zeros = k - Math.ceil(xhex.length / 2);
11797 while(zeros > 0) {
11798 eb.putByte(0x00);
11799 --zeros;
11800 }
11801 eb.putBytes(forge.util.hexToBytes(xhex));
11802
11803 if(ml !== false) {
11804 // legacy, default to PKCS#1 v1.5 padding
11805 return _decodePkcs1_v1_5(eb.getBytes(), key, pub);
11806 }
11807
11808 // return message
11809 return eb.getBytes();
11810};
11811
11812/**
11813 * Creates an RSA key-pair generation state object. It is used to allow
11814 * key-generation to be performed in steps. It also allows for a UI to
11815 * display progress updates.
11816 *
11817 * @param bits the size for the private key in bits, defaults to 2048.
11818 * @param e the public exponent to use, defaults to 65537 (0x10001).
11819 * @param [options] the options to use.
11820 * prng a custom crypto-secure pseudo-random number generator to use,
11821 * that must define "getBytesSync".
11822 * algorithm the algorithm to use (default: 'PRIMEINC').
11823 *
11824 * @return the state object to use to generate the key-pair.
11825 */
11826pki.rsa.createKeyPairGenerationState = function(bits, e, options) {
11827 // TODO: migrate step-based prime generation code to forge.prime
11828
11829 // set default bits
11830 if(typeof(bits) === 'string') {
11831 bits = parseInt(bits, 10);
11832 }
11833 bits = bits || 2048;
11834
11835 // create prng with api that matches BigInteger secure random
11836 options = options || {};
11837 var prng = options.prng || forge.random;
11838 var rng = {
11839 // x is an array to fill with bytes
11840 nextBytes: function(x) {
11841 var b = prng.getBytesSync(x.length);
11842 for(var i = 0; i < x.length; ++i) {
11843 x[i] = b.charCodeAt(i);
11844 }
11845 }
11846 };
11847
11848 var algorithm = options.algorithm || 'PRIMEINC';
11849
11850 // create PRIMEINC algorithm state
11851 var rval;
11852 if(algorithm === 'PRIMEINC') {
11853 rval = {
11854 algorithm: algorithm,
11855 state: 0,
11856 bits: bits,
11857 rng: rng,
11858 eInt: e || 65537,
11859 e: new BigInteger(null),
11860 p: null,
11861 q: null,
11862 qBits: bits >> 1,
11863 pBits: bits - (bits >> 1),
11864 pqState: 0,
11865 num: null,
11866 keys: null
11867 };
11868 rval.e.fromInt(rval.eInt);
11869 } else {
11870 throw new Error('Invalid key generation algorithm: ' + algorithm);
11871 }
11872
11873 return rval;
11874};
11875
11876/**
11877 * Attempts to runs the key-generation algorithm for at most n seconds
11878 * (approximately) using the given state. When key-generation has completed,
11879 * the keys will be stored in state.keys.
11880 *
11881 * To use this function to update a UI while generating a key or to prevent
11882 * causing browser lockups/warnings, set "n" to a value other than 0. A
11883 * simple pattern for generating a key and showing a progress indicator is:
11884 *
11885 * var state = pki.rsa.createKeyPairGenerationState(2048);
11886 * var step = function() {
11887 * // step key-generation, run algorithm for 100 ms, repeat
11888 * if(!forge.pki.rsa.stepKeyPairGenerationState(state, 100)) {
11889 * setTimeout(step, 1);
11890 * } else {
11891 * // key-generation complete
11892 * // TODO: turn off progress indicator here
11893 * // TODO: use the generated key-pair in "state.keys"
11894 * }
11895 * };
11896 * // TODO: turn on progress indicator here
11897 * setTimeout(step, 0);
11898 *
11899 * @param state the state to use.
11900 * @param n the maximum number of milliseconds to run the algorithm for, 0
11901 * to run the algorithm to completion.
11902 *
11903 * @return true if the key-generation completed, false if not.
11904 */
11905pki.rsa.stepKeyPairGenerationState = function(state, n) {
11906 // set default algorithm if not set
11907 if(!('algorithm' in state)) {
11908 state.algorithm = 'PRIMEINC';
11909 }
11910
11911 // TODO: migrate step-based prime generation code to forge.prime
11912 // TODO: abstract as PRIMEINC algorithm
11913
11914 // do key generation (based on Tom Wu's rsa.js, see jsbn.js license)
11915 // with some minor optimizations and designed to run in steps
11916
11917 // local state vars
11918 var THIRTY = new BigInteger(null);
11919 THIRTY.fromInt(30);
11920 var deltaIdx = 0;
11921 var op_or = function(x,y) { return x|y; };
11922
11923 // keep stepping until time limit is reached or done
11924 var t1 = +new Date();
11925 var t2;
11926 var total = 0;
11927 while(state.keys === null && (n <= 0 || total < n)) {
11928 // generate p or q
11929 if(state.state === 0) {
11930 /* Note: All primes are of the form:
11931
11932 30k+i, for i < 30 and gcd(30, i)=1, where there are 8 values for i
11933
11934 When we generate a random number, we always align it at 30k + 1. Each
11935 time the number is determined not to be prime we add to get to the
11936 next 'i', eg: if the number was at 30k + 1 we add 6. */
11937 var bits = (state.p === null) ? state.pBits : state.qBits;
11938 var bits1 = bits - 1;
11939
11940 // get a random number
11941 if(state.pqState === 0) {
11942 state.num = new BigInteger(bits, state.rng);
11943 // force MSB set
11944 if(!state.num.testBit(bits1)) {
11945 state.num.bitwiseTo(
11946 BigInteger.ONE.shiftLeft(bits1), op_or, state.num);
11947 }
11948 // align number on 30k+1 boundary
11949 state.num.dAddOffset(31 - state.num.mod(THIRTY).byteValue(), 0);
11950 deltaIdx = 0;
11951
11952 ++state.pqState;
11953 } else if(state.pqState === 1) {
11954 // try to make the number a prime
11955 if(state.num.bitLength() > bits) {
11956 // overflow, try again
11957 state.pqState = 0;
11958 // do primality test
11959 } else if(state.num.isProbablePrime(
11960 _getMillerRabinTests(state.num.bitLength()))) {
11961 ++state.pqState;
11962 } else {
11963 // get next potential prime
11964 state.num.dAddOffset(GCD_30_DELTA[deltaIdx++ % 8], 0);
11965 }
11966 } else if(state.pqState === 2) {
11967 // ensure number is coprime with e
11968 state.pqState =
11969 (state.num.subtract(BigInteger.ONE).gcd(state.e)
11970 .compareTo(BigInteger.ONE) === 0) ? 3 : 0;
11971 } else if(state.pqState === 3) {
11972 // store p or q
11973 state.pqState = 0;
11974 if(state.p === null) {
11975 state.p = state.num;
11976 } else {
11977 state.q = state.num;
11978 }
11979
11980 // advance state if both p and q are ready
11981 if(state.p !== null && state.q !== null) {
11982 ++state.state;
11983 }
11984 state.num = null;
11985 }
11986 } else if(state.state === 1) {
11987 // ensure p is larger than q (swap them if not)
11988 if(state.p.compareTo(state.q) < 0) {
11989 state.num = state.p;
11990 state.p = state.q;
11991 state.q = state.num;
11992 }
11993 ++state.state;
11994 } else if(state.state === 2) {
11995 // compute phi: (p - 1)(q - 1) (Euler's totient function)
11996 state.p1 = state.p.subtract(BigInteger.ONE);
11997 state.q1 = state.q.subtract(BigInteger.ONE);
11998 state.phi = state.p1.multiply(state.q1);
11999 ++state.state;
12000 } else if(state.state === 3) {
12001 // ensure e and phi are coprime
12002 if(state.phi.gcd(state.e).compareTo(BigInteger.ONE) === 0) {
12003 // phi and e are coprime, advance
12004 ++state.state;
12005 } else {
12006 // phi and e aren't coprime, so generate a new p and q
12007 state.p = null;
12008 state.q = null;
12009 state.state = 0;
12010 }
12011 } else if(state.state === 4) {
12012 // create n, ensure n is has the right number of bits
12013 state.n = state.p.multiply(state.q);
12014
12015 // ensure n is right number of bits
12016 if(state.n.bitLength() === state.bits) {
12017 // success, advance
12018 ++state.state;
12019 } else {
12020 // failed, get new q
12021 state.q = null;
12022 state.state = 0;
12023 }
12024 } else if(state.state === 5) {
12025 // set keys
12026 var d = state.e.modInverse(state.phi);
12027 state.keys = {
12028 privateKey: pki.rsa.setPrivateKey(
12029 state.n, state.e, d, state.p, state.q,
12030 d.mod(state.p1), d.mod(state.q1),
12031 state.q.modInverse(state.p)),
12032 publicKey: pki.rsa.setPublicKey(state.n, state.e)
12033 };
12034 }
12035
12036 // update timing
12037 t2 = +new Date();
12038 total += t2 - t1;
12039 t1 = t2;
12040 }
12041
12042 return state.keys !== null;
12043};
12044
12045/**
12046 * Generates an RSA public-private key pair in a single call.
12047 *
12048 * To generate a key-pair in steps (to allow for progress updates and to
12049 * prevent blocking or warnings in slow browsers) then use the key-pair
12050 * generation state functions.
12051 *
12052 * To generate a key-pair asynchronously (either through web-workers, if
12053 * available, or by breaking up the work on the main thread), pass a
12054 * callback function.
12055 *
12056 * @param [bits] the size for the private key in bits, defaults to 2048.
12057 * @param [e] the public exponent to use, defaults to 65537.
12058 * @param [options] options for key-pair generation, if given then 'bits'
12059 * and 'e' must *not* be given:
12060 * bits the size for the private key in bits, (default: 2048).
12061 * e the public exponent to use, (default: 65537 (0x10001)).
12062 * workerScript the worker script URL.
12063 * workers the number of web workers (if supported) to use,
12064 * (default: 2).
12065 * workLoad the size of the work load, ie: number of possible prime
12066 * numbers for each web worker to check per work assignment,
12067 * (default: 100).
12068 * prng a custom crypto-secure pseudo-random number generator to use,
12069 * that must define "getBytesSync".
12070 * algorithm the algorithm to use (default: 'PRIMEINC').
12071 * @param [callback(err, keypair)] called once the operation completes.
12072 *
12073 * @return an object with privateKey and publicKey properties.
12074 */
12075pki.rsa.generateKeyPair = function(bits, e, options, callback) {
12076 // (bits), (options), (callback)
12077 if(arguments.length === 1) {
12078 if(typeof bits === 'object') {
12079 options = bits;
12080 bits = undefined;
12081 } else if(typeof bits === 'function') {
12082 callback = bits;
12083 bits = undefined;
12084 }
12085 } else if(arguments.length === 2) {
12086 // (bits, e), (bits, options), (bits, callback), (options, callback)
12087 if(typeof bits === 'number') {
12088 if(typeof e === 'function') {
12089 callback = e;
12090 e = undefined;
12091 } else if(typeof e !== 'number') {
12092 options = e;
12093 e = undefined;
12094 }
12095 } else {
12096 options = bits;
12097 callback = e;
12098 bits = undefined;
12099 e = undefined;
12100 }
12101 } else if(arguments.length === 3) {
12102 // (bits, e, options), (bits, e, callback), (bits, options, callback)
12103 if(typeof e === 'number') {
12104 if(typeof options === 'function') {
12105 callback = options;
12106 options = undefined;
12107 }
12108 } else {
12109 callback = options;
12110 options = e;
12111 e = undefined;
12112 }
12113 }
12114 options = options || {};
12115 if(bits === undefined) {
12116 bits = options.bits || 2048;
12117 }
12118 if(e === undefined) {
12119 e = options.e || 0x10001;
12120 }
12121
12122 // if native code is permitted and a callback is given, use native
12123 // key generation code if available and if parameters are acceptable
12124 if(!forge.disableNativeCode && callback &&
12125 bits >= 256 && bits <= 16384 && (e === 0x10001 || e === 3)) {
12126 if(_detectSubtleCrypto('generateKey') && _detectSubtleCrypto('exportKey')) {
12127 // use standard native generateKey
12128 return window.crypto.subtle.generateKey({
12129 name: 'RSASSA-PKCS1-v1_5',
12130 modulusLength: bits,
12131 publicExponent: _intToUint8Array(e),
12132 hash: {name: 'SHA-256'}
12133 }, true /* key can be exported*/, ['sign', 'verify'])
12134 .then(function(pair) {
12135 return window.crypto.subtle.exportKey('pkcs8', pair.privateKey);
12136 }).catch(function(err) {
12137 callback(err);
12138 }).then(function(pkcs8) {
12139 if(pkcs8) {
12140 var privateKey = pki.privateKeyFromAsn1(
12141 asn1.fromDer(forge.util.createBuffer(pkcs8)));
12142 callback(null, {
12143 privateKey: privateKey,
12144 publicKey: pki.setRsaPublicKey(privateKey.n, privateKey.e)
12145 });
12146 }
12147 });
12148 }
12149 if(_detectSubtleMsCrypto('generateKey') &&
12150 _detectSubtleMsCrypto('exportKey')) {
12151 var genOp = window.msCrypto.subtle.generateKey({
12152 name: 'RSASSA-PKCS1-v1_5',
12153 modulusLength: bits,
12154 publicExponent: _intToUint8Array(e),
12155 hash: {name: 'SHA-256'}
12156 }, true /* key can be exported*/, ['sign', 'verify']);
12157 genOp.oncomplete = function(e) {
12158 var pair = e.target.result;
12159 var exportOp = window.msCrypto.subtle.exportKey(
12160 'pkcs8', pair.privateKey);
12161 exportOp.oncomplete = function(e) {
12162 var pkcs8 = e.target.result;
12163 var privateKey = pki.privateKeyFromAsn1(
12164 asn1.fromDer(forge.util.createBuffer(pkcs8)));
12165 callback(null, {
12166 privateKey: privateKey,
12167 publicKey: pki.setRsaPublicKey(privateKey.n, privateKey.e)
12168 });
12169 };
12170 exportOp.onerror = function(err) {
12171 callback(err);
12172 };
12173 };
12174 genOp.onerror = function(err) {
12175 callback(err);
12176 };
12177 return;
12178 }
12179 }
12180
12181 // use JavaScript implementation
12182 var state = pki.rsa.createKeyPairGenerationState(bits, e, options);
12183 if(!callback) {
12184 pki.rsa.stepKeyPairGenerationState(state, 0);
12185 return state.keys;
12186 }
12187 _generateKeyPair(state, options, callback);
12188};
12189
12190/**
12191 * Sets an RSA public key from BigIntegers modulus and exponent.
12192 *
12193 * @param n the modulus.
12194 * @param e the exponent.
12195 *
12196 * @return the public key.
12197 */
12198pki.setRsaPublicKey = pki.rsa.setPublicKey = function(n, e) {
12199 var key = {
12200 n: n,
12201 e: e
12202 };
12203
12204 /**
12205 * Encrypts the given data with this public key. Newer applications
12206 * should use the 'RSA-OAEP' decryption scheme, 'RSAES-PKCS1-V1_5' is for
12207 * legacy applications.
12208 *
12209 * @param data the byte string to encrypt.
12210 * @param scheme the encryption scheme to use:
12211 * 'RSAES-PKCS1-V1_5' (default),
12212 * 'RSA-OAEP',
12213 * 'RAW', 'NONE', or null to perform raw RSA encryption,
12214 * an object with an 'encode' property set to a function
12215 * with the signature 'function(data, key)' that returns
12216 * a binary-encoded string representing the encoded data.
12217 * @param schemeOptions any scheme-specific options.
12218 *
12219 * @return the encrypted byte string.
12220 */
12221 key.encrypt = function(data, scheme, schemeOptions) {
12222 if(typeof scheme === 'string') {
12223 scheme = scheme.toUpperCase();
12224 } else if(scheme === undefined) {
12225 scheme = 'RSAES-PKCS1-V1_5';
12226 }
12227
12228 if(scheme === 'RSAES-PKCS1-V1_5') {
12229 scheme = {
12230 encode: function(m, key, pub) {
12231 return _encodePkcs1_v1_5(m, key, 0x02).getBytes();
12232 }
12233 };
12234 } else if(scheme === 'RSA-OAEP' || scheme === 'RSAES-OAEP') {
12235 scheme = {
12236 encode: function(m, key) {
12237 return forge.pkcs1.encode_rsa_oaep(key, m, schemeOptions);
12238 }
12239 };
12240 } else if(['RAW', 'NONE', 'NULL', null].indexOf(scheme) !== -1) {
12241 scheme = { encode: function(e) { return e; } };
12242 } else if(typeof scheme === 'string') {
12243 throw new Error('Unsupported encryption scheme: "' + scheme + '".');
12244 }
12245
12246 // do scheme-based encoding then rsa encryption
12247 var e = scheme.encode(data, key, true);
12248 return pki.rsa.encrypt(e, key, true);
12249 };
12250
12251 /**
12252 * Verifies the given signature against the given digest.
12253 *
12254 * PKCS#1 supports multiple (currently two) signature schemes:
12255 * RSASSA-PKCS1-V1_5 and RSASSA-PSS.
12256 *
12257 * By default this implementation uses the "old scheme", i.e.
12258 * RSASSA-PKCS1-V1_5, in which case once RSA-decrypted, the
12259 * signature is an OCTET STRING that holds a DigestInfo.
12260 *
12261 * DigestInfo ::= SEQUENCE {
12262 * digestAlgorithm DigestAlgorithmIdentifier,
12263 * digest Digest
12264 * }
12265 * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
12266 * Digest ::= OCTET STRING
12267 *
12268 * To perform PSS signature verification, provide an instance
12269 * of Forge PSS object as the scheme parameter.
12270 *
12271 * @param digest the message digest hash to compare against the signature,
12272 * as a binary-encoded string.
12273 * @param signature the signature to verify, as a binary-encoded string.
12274 * @param scheme signature verification scheme to use:
12275 * 'RSASSA-PKCS1-V1_5' or undefined for RSASSA PKCS#1 v1.5,
12276 * a Forge PSS object for RSASSA-PSS,
12277 * 'NONE' or null for none, DigestInfo will not be expected, but
12278 * PKCS#1 v1.5 padding will still be used.
12279 *
12280 * @return true if the signature was verified, false if not.
12281 */
12282 key.verify = function(digest, signature, scheme) {
12283 if(typeof scheme === 'string') {
12284 scheme = scheme.toUpperCase();
12285 } else if(scheme === undefined) {
12286 scheme = 'RSASSA-PKCS1-V1_5';
12287 }
12288
12289 if(scheme === 'RSASSA-PKCS1-V1_5') {
12290 scheme = {
12291 verify: function(digest, d) {
12292 // remove padding
12293 d = _decodePkcs1_v1_5(d, key, true);
12294 // d is ASN.1 BER-encoded DigestInfo
12295 var obj = asn1.fromDer(d);
12296 // compare the given digest to the decrypted one
12297 return digest === obj.value[1].value;
12298 }
12299 };
12300 } else if(scheme === 'NONE' || scheme === 'NULL' || scheme === null) {
12301 scheme = {
12302 verify: function(digest, d) {
12303 // remove padding
12304 d = _decodePkcs1_v1_5(d, key, true);
12305 return digest === d;
12306 }
12307 };
12308 }
12309
12310 // do rsa decryption w/o any decoding, then verify -- which does decoding
12311 var d = pki.rsa.decrypt(signature, key, true, false);
12312 return scheme.verify(digest, d, key.n.bitLength());
12313 };
12314
12315 return key;
12316};
12317
12318/**
12319 * Sets an RSA private key from BigIntegers modulus, exponent, primes,
12320 * prime exponents, and modular multiplicative inverse.
12321 *
12322 * @param n the modulus.
12323 * @param e the public exponent.
12324 * @param d the private exponent ((inverse of e) mod n).
12325 * @param p the first prime.
12326 * @param q the second prime.
12327 * @param dP exponent1 (d mod (p-1)).
12328 * @param dQ exponent2 (d mod (q-1)).
12329 * @param qInv ((inverse of q) mod p)
12330 *
12331 * @return the private key.
12332 */
12333pki.setRsaPrivateKey = pki.rsa.setPrivateKey = function(
12334 n, e, d, p, q, dP, dQ, qInv) {
12335 var key = {
12336 n: n,
12337 e: e,
12338 d: d,
12339 p: p,
12340 q: q,
12341 dP: dP,
12342 dQ: dQ,
12343 qInv: qInv
12344 };
12345
12346 /**
12347 * Decrypts the given data with this private key. The decryption scheme
12348 * must match the one used to encrypt the data.
12349 *
12350 * @param data the byte string to decrypt.
12351 * @param scheme the decryption scheme to use:
12352 * 'RSAES-PKCS1-V1_5' (default),
12353 * 'RSA-OAEP',
12354 * 'RAW', 'NONE', or null to perform raw RSA decryption.
12355 * @param schemeOptions any scheme-specific options.
12356 *
12357 * @return the decrypted byte string.
12358 */
12359 key.decrypt = function(data, scheme, schemeOptions) {
12360 if(typeof scheme === 'string') {
12361 scheme = scheme.toUpperCase();
12362 } else if(scheme === undefined) {
12363 scheme = 'RSAES-PKCS1-V1_5';
12364 }
12365
12366 // do rsa decryption w/o any decoding
12367 var d = pki.rsa.decrypt(data, key, false, false);
12368
12369 if(scheme === 'RSAES-PKCS1-V1_5') {
12370 scheme = { decode: _decodePkcs1_v1_5 };
12371 } else if(scheme === 'RSA-OAEP' || scheme === 'RSAES-OAEP') {
12372 scheme = {
12373 decode: function(d, key) {
12374 return forge.pkcs1.decode_rsa_oaep(key, d, schemeOptions);
12375 }
12376 };
12377 } else if(['RAW', 'NONE', 'NULL', null].indexOf(scheme) !== -1) {
12378 scheme = { decode: function(d) { return d; } };
12379 } else {
12380 throw new Error('Unsupported encryption scheme: "' + scheme + '".');
12381 }
12382
12383 // decode according to scheme
12384 return scheme.decode(d, key, false);
12385 };
12386
12387 /**
12388 * Signs the given digest, producing a signature.
12389 *
12390 * PKCS#1 supports multiple (currently two) signature schemes:
12391 * RSASSA-PKCS1-V1_5 and RSASSA-PSS.
12392 *
12393 * By default this implementation uses the "old scheme", i.e.
12394 * RSASSA-PKCS1-V1_5. In order to generate a PSS signature, provide
12395 * an instance of Forge PSS object as the scheme parameter.
12396 *
12397 * @param md the message digest object with the hash to sign.
12398 * @param scheme the signature scheme to use:
12399 * 'RSASSA-PKCS1-V1_5' or undefined for RSASSA PKCS#1 v1.5,
12400 * a Forge PSS object for RSASSA-PSS,
12401 * 'NONE' or null for none, DigestInfo will not be used but
12402 * PKCS#1 v1.5 padding will still be used.
12403 *
12404 * @return the signature as a byte string.
12405 */
12406 key.sign = function(md, scheme) {
12407 /* Note: The internal implementation of RSA operations is being
12408 transitioned away from a PKCS#1 v1.5 hard-coded scheme. Some legacy
12409 code like the use of an encoding block identifier 'bt' will eventually
12410 be removed. */
12411
12412 // private key operation
12413 var bt = false;
12414
12415 if(typeof scheme === 'string') {
12416 scheme = scheme.toUpperCase();
12417 }
12418
12419 if(scheme === undefined || scheme === 'RSASSA-PKCS1-V1_5') {
12420 scheme = { encode: emsaPkcs1v15encode };
12421 bt = 0x01;
12422 } else if(scheme === 'NONE' || scheme === 'NULL' || scheme === null) {
12423 scheme = { encode: function() { return md; } };
12424 bt = 0x01;
12425 }
12426
12427 // encode and then encrypt
12428 var d = scheme.encode(md, key.n.bitLength());
12429 return pki.rsa.encrypt(d, key, bt);
12430 };
12431
12432 return key;
12433};
12434
12435/**
12436 * Wraps an RSAPrivateKey ASN.1 object in an ASN.1 PrivateKeyInfo object.
12437 *
12438 * @param rsaKey the ASN.1 RSAPrivateKey.
12439 *
12440 * @return the ASN.1 PrivateKeyInfo.
12441 */
12442pki.wrapRsaPrivateKey = function(rsaKey) {
12443 // PrivateKeyInfo
12444 return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
12445 // version (0)
12446 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
12447 asn1.integerToDer(0).getBytes()),
12448 // privateKeyAlgorithm
12449 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
12450 asn1.create(
12451 asn1.Class.UNIVERSAL, asn1.Type.OID, false,
12452 asn1.oidToDer(pki.oids.rsaEncryption).getBytes()),
12453 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '')
12454 ]),
12455 // PrivateKey
12456 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OCTETSTRING, false,
12457 asn1.toDer(rsaKey).getBytes())
12458 ]);
12459};
12460
12461/**
12462 * Converts a private key from an ASN.1 object.
12463 *
12464 * @param obj the ASN.1 representation of a PrivateKeyInfo containing an
12465 * RSAPrivateKey or an RSAPrivateKey.
12466 *
12467 * @return the private key.
12468 */
12469pki.privateKeyFromAsn1 = function(obj) {
12470 // get PrivateKeyInfo
12471 var capture = {};
12472 var errors = [];
12473 if(asn1.validate(obj, privateKeyValidator, capture, errors)) {
12474 obj = asn1.fromDer(forge.util.createBuffer(capture.privateKey));
12475 }
12476
12477 // get RSAPrivateKey
12478 capture = {};
12479 errors = [];
12480 if(!asn1.validate(obj, rsaPrivateKeyValidator, capture, errors)) {
12481 var error = new Error('Cannot read private key. ' +
12482 'ASN.1 object does not contain an RSAPrivateKey.');
12483 error.errors = errors;
12484 throw error;
12485 }
12486
12487 // Note: Version is currently ignored.
12488 // capture.privateKeyVersion
12489 // FIXME: inefficient, get a BigInteger that uses byte strings
12490 var n, e, d, p, q, dP, dQ, qInv;
12491 n = forge.util.createBuffer(capture.privateKeyModulus).toHex();
12492 e = forge.util.createBuffer(capture.privateKeyPublicExponent).toHex();
12493 d = forge.util.createBuffer(capture.privateKeyPrivateExponent).toHex();
12494 p = forge.util.createBuffer(capture.privateKeyPrime1).toHex();
12495 q = forge.util.createBuffer(capture.privateKeyPrime2).toHex();
12496 dP = forge.util.createBuffer(capture.privateKeyExponent1).toHex();
12497 dQ = forge.util.createBuffer(capture.privateKeyExponent2).toHex();
12498 qInv = forge.util.createBuffer(capture.privateKeyCoefficient).toHex();
12499
12500 // set private key
12501 return pki.setRsaPrivateKey(
12502 new BigInteger(n, 16),
12503 new BigInteger(e, 16),
12504 new BigInteger(d, 16),
12505 new BigInteger(p, 16),
12506 new BigInteger(q, 16),
12507 new BigInteger(dP, 16),
12508 new BigInteger(dQ, 16),
12509 new BigInteger(qInv, 16));
12510};
12511
12512/**
12513 * Converts a private key to an ASN.1 RSAPrivateKey.
12514 *
12515 * @param key the private key.
12516 *
12517 * @return the ASN.1 representation of an RSAPrivateKey.
12518 */
12519pki.privateKeyToAsn1 = pki.privateKeyToRSAPrivateKey = function(key) {
12520 // RSAPrivateKey
12521 return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
12522 // version (0 = only 2 primes, 1 multiple primes)
12523 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
12524 asn1.integerToDer(0).getBytes()),
12525 // modulus (n)
12526 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
12527 _bnToBytes(key.n)),
12528 // publicExponent (e)
12529 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
12530 _bnToBytes(key.e)),
12531 // privateExponent (d)
12532 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
12533 _bnToBytes(key.d)),
12534 // privateKeyPrime1 (p)
12535 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
12536 _bnToBytes(key.p)),
12537 // privateKeyPrime2 (q)
12538 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
12539 _bnToBytes(key.q)),
12540 // privateKeyExponent1 (dP)
12541 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
12542 _bnToBytes(key.dP)),
12543 // privateKeyExponent2 (dQ)
12544 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
12545 _bnToBytes(key.dQ)),
12546 // coefficient (qInv)
12547 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
12548 _bnToBytes(key.qInv))
12549 ]);
12550};
12551
12552/**
12553 * Converts a public key from an ASN.1 SubjectPublicKeyInfo or RSAPublicKey.
12554 *
12555 * @param obj the asn1 representation of a SubjectPublicKeyInfo or RSAPublicKey.
12556 *
12557 * @return the public key.
12558 */
12559pki.publicKeyFromAsn1 = function(obj) {
12560 // get SubjectPublicKeyInfo
12561 var capture = {};
12562 var errors = [];
12563 if(asn1.validate(obj, publicKeyValidator, capture, errors)) {
12564 // get oid
12565 var oid = asn1.derToOid(capture.publicKeyOid);
12566 if(oid !== pki.oids.rsaEncryption) {
12567 var error = new Error('Cannot read public key. Unknown OID.');
12568 error.oid = oid;
12569 throw error;
12570 }
12571 obj = capture.rsaPublicKey;
12572 }
12573
12574 // get RSA params
12575 errors = [];
12576 if(!asn1.validate(obj, rsaPublicKeyValidator, capture, errors)) {
12577 var error = new Error('Cannot read public key. ' +
12578 'ASN.1 object does not contain an RSAPublicKey.');
12579 error.errors = errors;
12580 throw error;
12581 }
12582
12583 // FIXME: inefficient, get a BigInteger that uses byte strings
12584 var n = forge.util.createBuffer(capture.publicKeyModulus).toHex();
12585 var e = forge.util.createBuffer(capture.publicKeyExponent).toHex();
12586
12587 // set public key
12588 return pki.setRsaPublicKey(
12589 new BigInteger(n, 16),
12590 new BigInteger(e, 16));
12591};
12592
12593/**
12594 * Converts a public key to an ASN.1 SubjectPublicKeyInfo.
12595 *
12596 * @param key the public key.
12597 *
12598 * @return the asn1 representation of a SubjectPublicKeyInfo.
12599 */
12600pki.publicKeyToAsn1 = pki.publicKeyToSubjectPublicKeyInfo = function(key) {
12601 // SubjectPublicKeyInfo
12602 return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
12603 // AlgorithmIdentifier
12604 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
12605 // algorithm
12606 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
12607 asn1.oidToDer(pki.oids.rsaEncryption).getBytes()),
12608 // parameters (null)
12609 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '')
12610 ]),
12611 // subjectPublicKey
12612 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, [
12613 pki.publicKeyToRSAPublicKey(key)
12614 ])
12615 ]);
12616};
12617
12618/**
12619 * Converts a public key to an ASN.1 RSAPublicKey.
12620 *
12621 * @param key the public key.
12622 *
12623 * @return the asn1 representation of a RSAPublicKey.
12624 */
12625pki.publicKeyToRSAPublicKey = function(key) {
12626 // RSAPublicKey
12627 return asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
12628 // modulus (n)
12629 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
12630 _bnToBytes(key.n)),
12631 // publicExponent (e)
12632 asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
12633 _bnToBytes(key.e))
12634 ]);
12635};
12636
12637/**
12638 * Encodes a message using PKCS#1 v1.5 padding.
12639 *
12640 * @param m the message to encode.
12641 * @param key the RSA key to use.
12642 * @param bt the block type to use, i.e. either 0x01 (for signing) or 0x02
12643 * (for encryption).
12644 *
12645 * @return the padded byte buffer.
12646 */
12647function _encodePkcs1_v1_5(m, key, bt) {
12648 var eb = forge.util.createBuffer();
12649
12650 // get the length of the modulus in bytes
12651 var k = Math.ceil(key.n.bitLength() / 8);
12652
12653 /* use PKCS#1 v1.5 padding */
12654 if(m.length > (k - 11)) {
12655 var error = new Error('Message is too long for PKCS#1 v1.5 padding.');
12656 error.length = m.length;
12657 error.max = k - 11;
12658 throw error;
12659 }
12660
12661 /* A block type BT, a padding string PS, and the data D shall be
12662 formatted into an octet string EB, the encryption block:
12663
12664 EB = 00 || BT || PS || 00 || D
12665
12666 The block type BT shall be a single octet indicating the structure of
12667 the encryption block. For this version of the document it shall have
12668 value 00, 01, or 02. For a private-key operation, the block type
12669 shall be 00 or 01. For a public-key operation, it shall be 02.
12670
12671 The padding string PS shall consist of k-3-||D|| octets. For block
12672 type 00, the octets shall have value 00; for block type 01, they
12673 shall have value FF; and for block type 02, they shall be
12674 pseudorandomly generated and nonzero. This makes the length of the
12675 encryption block EB equal to k. */
12676
12677 // build the encryption block
12678 eb.putByte(0x00);
12679 eb.putByte(bt);
12680
12681 // create the padding
12682 var padNum = k - 3 - m.length;
12683 var padByte;
12684 // private key op
12685 if(bt === 0x00 || bt === 0x01) {
12686 padByte = (bt === 0x00) ? 0x00 : 0xFF;
12687 for(var i = 0; i < padNum; ++i) {
12688 eb.putByte(padByte);
12689 }
12690 } else {
12691 // public key op
12692 // pad with random non-zero values
12693 while(padNum > 0) {
12694 var numZeros = 0;
12695 var padBytes = forge.random.getBytes(padNum);
12696 for(var i = 0; i < padNum; ++i) {
12697 padByte = padBytes.charCodeAt(i);
12698 if(padByte === 0) {
12699 ++numZeros;
12700 } else {
12701 eb.putByte(padByte);
12702 }
12703 }
12704 padNum = numZeros;
12705 }
12706 }
12707
12708 // zero followed by message
12709 eb.putByte(0x00);
12710 eb.putBytes(m);
12711
12712 return eb;
12713}
12714
12715/**
12716 * Decodes a message using PKCS#1 v1.5 padding.
12717 *
12718 * @param em the message to decode.
12719 * @param key the RSA key to use.
12720 * @param pub true if the key is a public key, false if it is private.
12721 * @param ml the message length, if specified.
12722 *
12723 * @return the decoded bytes.
12724 */
12725function _decodePkcs1_v1_5(em, key, pub, ml) {
12726 // get the length of the modulus in bytes
12727 var k = Math.ceil(key.n.bitLength() / 8);
12728
12729 /* It is an error if any of the following conditions occurs:
12730
12731 1. The encryption block EB cannot be parsed unambiguously.
12732 2. The padding string PS consists of fewer than eight octets
12733 or is inconsisent with the block type BT.
12734 3. The decryption process is a public-key operation and the block
12735 type BT is not 00 or 01, or the decryption process is a
12736 private-key operation and the block type is not 02.
12737 */
12738
12739 // parse the encryption block
12740 var eb = forge.util.createBuffer(em);
12741 var first = eb.getByte();
12742 var bt = eb.getByte();
12743 if(first !== 0x00 ||
12744 (pub && bt !== 0x00 && bt !== 0x01) ||
12745 (!pub && bt != 0x02) ||
12746 (pub && bt === 0x00 && typeof(ml) === 'undefined')) {
12747 throw new Error('Encryption block is invalid.');
12748 }
12749
12750 var padNum = 0;
12751 if(bt === 0x00) {
12752 // check all padding bytes for 0x00
12753 padNum = k - 3 - ml;
12754 for(var i = 0; i < padNum; ++i) {
12755 if(eb.getByte() !== 0x00) {
12756 throw new Error('Encryption block is invalid.');
12757 }
12758 }
12759 } else if(bt === 0x01) {
12760 // find the first byte that isn't 0xFF, should be after all padding
12761 padNum = 0;
12762 while(eb.length() > 1) {
12763 if(eb.getByte() !== 0xFF) {
12764 --eb.read;
12765 break;
12766 }
12767 ++padNum;
12768 }
12769 } else if(bt === 0x02) {
12770 // look for 0x00 byte
12771 padNum = 0;
12772 while(eb.length() > 1) {
12773 if(eb.getByte() === 0x00) {
12774 --eb.read;
12775 break;
12776 }
12777 ++padNum;
12778 }
12779 }
12780
12781 // zero must be 0x00 and padNum must be (k - 3 - message length)
12782 var zero = eb.getByte();
12783 if(zero !== 0x00 || padNum !== (k - 3 - eb.length())) {
12784 throw new Error('Encryption block is invalid.');
12785 }
12786
12787 return eb.getBytes();
12788}
12789
12790/**
12791 * Runs the key-generation algorithm asynchronously, either in the background
12792 * via Web Workers, or using the main thread and setImmediate.
12793 *
12794 * @param state the key-pair generation state.
12795 * @param [options] options for key-pair generation:
12796 * workerScript the worker script URL.
12797 * workers the number of web workers (if supported) to use,
12798 * (default: 2, -1 to use estimated cores minus one).
12799 * workLoad the size of the work load, ie: number of possible prime
12800 * numbers for each web worker to check per work assignment,
12801 * (default: 100).
12802 * @param callback(err, keypair) called once the operation completes.
12803 */
12804function _generateKeyPair(state, options, callback) {
12805 if(typeof options === 'function') {
12806 callback = options;
12807 options = {};
12808 }
12809 options = options || {};
12810
12811 var opts = {
12812 algorithm: {
12813 name: options.algorithm || 'PRIMEINC',
12814 options: {
12815 workers: options.workers || 2,
12816 workLoad: options.workLoad || 100,
12817 workerScript: options.workerScript
12818 }
12819 }
12820 };
12821 if('prng' in options) {
12822 opts.prng = options.prng;
12823 }
12824
12825 generate();
12826
12827 function generate() {
12828 // find p and then q (done in series to simplify)
12829 getPrime(state.pBits, function(err, num) {
12830 if(err) {
12831 return callback(err);
12832 }
12833 state.p = num;
12834 if(state.q !== null) {
12835 return finish(err, state.q);
12836 }
12837 getPrime(state.qBits, finish);
12838 });
12839 }
12840
12841 function getPrime(bits, callback) {
12842 forge.prime.generateProbablePrime(bits, opts, callback);
12843 }
12844
12845 function finish(err, num) {
12846 if(err) {
12847 return callback(err);
12848 }
12849
12850 // set q
12851 state.q = num;
12852
12853 // ensure p is larger than q (swap them if not)
12854 if(state.p.compareTo(state.q) < 0) {
12855 var tmp = state.p;
12856 state.p = state.q;
12857 state.q = tmp;
12858 }
12859
12860 // ensure p is coprime with e
12861 if(state.p.subtract(BigInteger.ONE).gcd(state.e)
12862 .compareTo(BigInteger.ONE) !== 0) {
12863 state.p = null;
12864 generate();
12865 return;
12866 }
12867
12868 // ensure q is coprime with e
12869 if(state.q.subtract(BigInteger.ONE).gcd(state.e)
12870 .compareTo(BigInteger.ONE) !== 0) {
12871 state.q = null;
12872 getPrime(state.qBits, finish);
12873 return;
12874 }
12875
12876 // compute phi: (p - 1)(q - 1) (Euler's totient function)
12877 state.p1 = state.p.subtract(BigInteger.ONE);
12878 state.q1 = state.q.subtract(BigInteger.ONE);
12879 state.phi = state.p1.multiply(state.q1);
12880
12881 // ensure e and phi are coprime
12882 if(state.phi.gcd(state.e).compareTo(BigInteger.ONE) !== 0) {
12883 // phi and e aren't coprime, so generate a new p and q
12884 state.p = state.q = null;
12885 generate();
12886 return;
12887 }
12888
12889 // create n, ensure n is has the right number of bits
12890 state.n = state.p.multiply(state.q);
12891 if(state.n.bitLength() !== state.bits) {
12892 // failed, get new q
12893 state.q = null;
12894 getPrime(state.qBits, finish);
12895 return;
12896 }
12897
12898 // set keys
12899 var d = state.e.modInverse(state.phi);
12900 state.keys = {
12901 privateKey: pki.rsa.setPrivateKey(
12902 state.n, state.e, d, state.p, state.q,
12903 d.mod(state.p1), d.mod(state.q1),
12904 state.q.modInverse(state.p)),
12905 publicKey: pki.rsa.setPublicKey(state.n, state.e)
12906 };
12907
12908 callback(null, state.keys);
12909 }
12910}
12911
12912/**
12913 * Converts a positive BigInteger into 2's-complement big-endian bytes.
12914 *
12915 * @param b the big integer to convert.
12916 *
12917 * @return the bytes.
12918 */
12919function _bnToBytes(b) {
12920 // prepend 0x00 if first byte >= 0x80
12921 var hex = b.toString(16);
12922 if(hex[0] >= '8') {
12923 hex = '00' + hex;
12924 }
12925 var bytes = forge.util.hexToBytes(hex);
12926
12927 // ensure integer is minimally-encoded
12928 if(bytes.length > 1 &&
12929 // leading 0x00 for positive integer
12930 ((bytes.charCodeAt(0) === 0 &&
12931 (bytes.charCodeAt(1) & 0x80) === 0) ||
12932 // leading 0xFF for negative integer
12933 (bytes.charCodeAt(0) === 0xFF &&
12934 (bytes.charCodeAt(1) & 0x80) === 0x80))) {
12935 return bytes.substr(1);
12936 }
12937 return bytes;
12938}
12939
12940/**
12941 * Returns the required number of Miller-Rabin tests to generate a
12942 * prime with an error probability of (1/2)^80.
12943 *
12944 * See Handbook of Applied Cryptography Chapter 4, Table 4.4.
12945 *
12946 * @param bits the bit size.
12947 *
12948 * @return the required number of iterations.
12949 */
12950function _getMillerRabinTests(bits) {
12951 if(bits <= 100) return 27;
12952 if(bits <= 150) return 18;
12953 if(bits <= 200) return 15;
12954 if(bits <= 250) return 12;
12955 if(bits <= 300) return 9;
12956 if(bits <= 350) return 8;
12957 if(bits <= 400) return 7;
12958 if(bits <= 500) return 6;
12959 if(bits <= 600) return 5;
12960 if(bits <= 800) return 4;
12961 if(bits <= 1250) return 3;
12962 return 2;
12963}
12964
12965/**
12966 * Performs feature detection on the SubtleCrypto interface.
12967 *
12968 * @param fn the feature (function) to detect.
12969 *
12970 * @return true if detected, false if not.
12971 */
12972function _detectSubtleCrypto(fn) {
12973 return (typeof window !== 'undefined' &&
12974 typeof window.crypto === 'object' &&
12975 typeof window.crypto.subtle === 'object' &&
12976 typeof window.crypto.subtle[fn] === 'function');
12977}
12978
12979/**
12980 * Performs feature detection on the deprecated Microsoft Internet Explorer
12981 * outdated SubtleCrypto interface. This function should only be used after
12982 * checking for the modern, standard SubtleCrypto interface.
12983 *
12984 * @param fn the feature (function) to detect.
12985 *
12986 * @return true if detected, false if not.
12987 */
12988function _detectSubtleMsCrypto(fn) {
12989 return (typeof window !== 'undefined' &&
12990 typeof window.msCrypto === 'object' &&
12991 typeof window.msCrypto.subtle === 'object' &&
12992 typeof window.msCrypto.subtle[fn] === 'function');
12993}
12994
12995function _intToUint8Array(x) {
12996 var bytes = forge.util.hexToBytes(x.toString(16));
12997 var buffer = new Uint8Array(bytes.length);
12998 for(var i = 0; i < bytes.length; ++i) {
12999 buffer[i] = bytes.charCodeAt(i);
13000 }
13001 return buffer;
13002}
13003
13004function _privateKeyFromJwk(jwk) {
13005 if(jwk.kty !== 'RSA') {
13006 throw new Error(
13007 'Unsupported key algorithm "' + jwk.kty + '"; algorithm must be "RSA".');
13008 }
13009 return pki.setRsaPrivateKey(
13010 _base64ToBigInt(jwk.n),
13011 _base64ToBigInt(jwk.e),
13012 _base64ToBigInt(jwk.d),
13013 _base64ToBigInt(jwk.p),
13014 _base64ToBigInt(jwk.q),
13015 _base64ToBigInt(jwk.dp),
13016 _base64ToBigInt(jwk.dq),
13017 _base64ToBigInt(jwk.qi));
13018}
13019
13020function _publicKeyFromJwk(jwk) {
13021 if(jwk.kty !== 'RSA') {
13022 throw new Error('Key algorithm must be "RSA".');
13023 }
13024 return pki.setRsaPublicKey(
13025 _base64ToBigInt(jwk.n),
13026 _base64ToBigInt(jwk.e));
13027}
13028
13029function _base64ToBigInt(b64) {
13030 return new BigInteger(forge.util.bytesToHex(forge.util.decode64(b64)), 16);
13031}
13032
13033} // end module implementation
13034
13035/* ########## Begin module wrapper ########## */
13036var name = 'rsa';
13037if(typeof define !== 'function') {
13038 // NodeJS -> AMD
13039 if(typeof module === 'object' && module.exports) {
13040 var nodeJS = true;
13041 define = function(ids, factory) {
13042 factory(require, module);
13043 };
13044 } else {
13045 // <script>
13046 if(typeof forge === 'undefined') {
13047 forge = {};
13048 }
13049 return initModule(forge);
13050 }
13051}
13052// AMD
13053var deps;
13054var defineFunc = function(require, module) {
13055 module.exports = function(forge) {
13056 var mods = deps.map(function(dep) {
13057 return require(dep);
13058 }).concat(initModule);
13059 // handle circular dependencies
13060 forge = forge || {};
13061 forge.defined = forge.defined || {};
13062 if(forge.defined[name]) {
13063 return forge[name];
13064 }
13065 forge.defined[name] = true;
13066 for(var i = 0; i < mods.length; ++i) {
13067 mods[i](forge);
13068 }
13069 return forge[name];
13070 };
13071};
13072var tmpDefine = define;
13073define = function(ids, factory) {
13074 deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
13075 if(nodeJS) {
13076 delete define;
13077 return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
13078 }
13079 define = tmpDefine;
13080 return define.apply(null, Array.prototype.slice.call(arguments, 0));
13081};
13082define([
13083 'require',
13084 'module',
13085 './asn1',
13086 './jsbn',
13087 './oids',
13088 './pkcs1',
13089 './prime',
13090 './random',
13091 './util'
13092], function() {
13093 defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
13094});
13095})();
13096
13097/**
13098 * Node.js module for Forge.
13099 *
13100 * @author Dave Longley
13101 *
13102 * Copyright 2011-2014 Digital Bazaar, Inc.
13103 */
13104(function() {
13105var name = 'forge';
13106if(typeof define !== 'function') {
13107 // NodeJS -> AMD
13108 if(typeof module === 'object' && module.exports) {
13109 var nodeJS = true;
13110 define = function(ids, factory) {
13111 factory(require, module);
13112 };
13113 } else {
13114 // <script>
13115 if(typeof forge === 'undefined') {
13116 // set to true to disable native code if even it's available
13117 forge = {disableNativeCode: false};
13118 }
13119 return;
13120 }
13121}
13122// AMD
13123var deps;
13124var defineFunc = function(require, module) {
13125 module.exports = function(forge) {
13126 var mods = deps.map(function(dep) {
13127 return require(dep);
13128 });
13129 // handle circular dependencies
13130 forge = forge || {};
13131 forge.defined = forge.defined || {};
13132 if(forge.defined[name]) {
13133 return forge[name];
13134 }
13135 forge.defined[name] = true;
13136 for(var i = 0; i < mods.length; ++i) {
13137 if(typeof mods[i] === 'function') {
13138 mods[i](forge);
13139 }
13140 }
13141 return forge;
13142 };
13143 // set to true to disable native code if even it's available
13144 module.exports.disableNativeCode = false;
13145 module.exports(module.exports);
13146};
13147var tmpDefine = define;
13148define = function(ids, factory) {
13149 deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
13150 if(nodeJS) {
13151 delete define;
13152 return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
13153 }
13154 define = tmpDefine;
13155 return define.apply(null, Array.prototype.slice.call(arguments, 0));
13156};
13157define([
13158 'require',
13159 'module',
13160 './aes',
13161 './aesCipherSuites',
13162 './asn1',
13163 './cipher',
13164 './cipherModes',
13165 './debug',
13166 './des',
13167 './hmac',
13168 './kem',
13169 './log',
13170 './md',
13171 './mgf1',
13172 './pbkdf2',
13173 './pem',
13174 './pkcs7',
13175 './pkcs1',
13176 './pkcs12',
13177 './pki',
13178 './prime',
13179 './prng',
13180 './pss',
13181 './random',
13182 './rc2',
13183 './ssh',
13184 './task',
13185 './tls',
13186 './util'
13187], function() {
13188 defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
13189});
13190})();
13191
13192(function (global) {
13193 var connectsdk = {}, modules = {};
13194
13195 /* SDK internal function */
13196 connectsdk.define = function (module, dependencies, fn) {
13197 if (dependencies && dependencies.length) {
13198 for (var i = 0; i < dependencies.length; i++) {
13199 dependencies[i] = modules[dependencies[i]];
13200 }
13201 }
13202 modules[module] = fn.apply(this, dependencies || []);
13203 };
13204
13205 // Export `connectsdk` based on environment.
13206 global.connectsdk = connectsdk;
13207
13208 if (typeof exports !== 'undefined') {
13209 exports.connectsdk = connectsdk;
13210 }
13211
13212 connectsdk.define('connectsdk.core', [], function () {
13213 return connectsdk;
13214 });
13215
13216 // use require.js if available otherwise we use our own
13217 if (typeof define === 'undefined') {
13218 global.define = connectsdk.define;
13219 }
13220} (typeof window === 'undefined' ? this : window));
13221
13222// (re)define core
13223define("connectsdk.core", [], function () {
13224 var global = typeof window === 'undefined' ? this : window;
13225 var connectsdk = {};
13226 global.connectsdk = connectsdk;
13227 if (typeof exports !== 'undefined') {
13228 exports.connectsdk = connectsdk;
13229 }
13230 return connectsdk;
13231});
13232
13233define('connectsdk.promise', ['connectsdk.core'], function(turing) {
13234 function PromiseModule(global) {
13235 /**
13236 * The Promise class.
13237 */
13238 function Promise(singleton) {
13239 var self = this;
13240 this.pending = [];
13241
13242 /**
13243 * Resolves a promise.
13244 *
13245 * @param {Object} A value
13246 */
13247 this.resolve = function(result) {
13248 self.complete('resolve', result);
13249 },
13250
13251 /**
13252 * Rejects a promise.
13253 *
13254 * @param {Object} A value
13255 */
13256 this.reject = function(result) {
13257 self.complete('reject', result);
13258 };
13259
13260 if (singleton) {
13261 this.isSingleton = true;
13262 }
13263 }
13264
13265
13266 Promise.prototype = {
13267 /**
13268 * Adds a success and failure handler for completion of this Promise object.
13269 *
13270 * @param {Function} success The success handler
13271 * @param {Function} success The failure handler
13272 * @returns {Promise} `this`
13273 */
13274 then : function(success, failure) {
13275 this.pending.push({
13276 resolve : success,
13277 reject : failure
13278 });
13279 return this;
13280 },
13281
13282 /**
13283 * Runs through each pending 'thenable' based on type (resolve, reject).
13284 *
13285 * @param {String} type The thenable type
13286 * @param {Object} result A value
13287 */
13288 complete : function(type, result) {
13289 while (this.pending[0]) {
13290 this.pending.shift()[type](result);
13291 }
13292 }
13293 };
13294
13295 global.Promise = Promise;
13296 }
13297 PromiseModule(connectsdk);
13298
13299 return connectsdk.Promise;
13300});
13301define('connectsdk.net', ['connectsdk.core'], function(connectsdk) {
13302 var net = {};
13303
13304 /**
13305 * Ajax request options:
13306 *
13307 * - `method`: {String} HTTP method - GET, POST, etc.
13308 * - `success`: {Function} A callback to run when a request is successful
13309 * - `error`: {Function} A callback to run when the request fails
13310 * - `asynchronous`: {Boolean} Defaults to asynchronous
13311 * - `postBody`: {String} The HTTP POST body
13312 * - `contentType`: {String} The content type of the request, default is `application/x-www-form-urlencoded`
13313 *
13314 */
13315
13316 /**
13317 * Removes leading and trailing whitespace.
13318 * @param {String}
13319 * @return {String}
13320 */
13321 var trim = ''.trim
13322 ? function(s) { return s.trim(); }
13323 : function(s) { return s.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); };
13324
13325 function xhr() {
13326 if (typeof XMLHttpRequest !== 'undefined' && (window.location.protocol !== 'file:' || !window.ActiveXObject)) {
13327 return new XMLHttpRequest();
13328 } else {
13329 try {
13330 return new ActiveXObject('Msxml2.XMLHTTP.6.0');
13331 } catch(e) { }
13332 try {
13333 return new ActiveXObject('Msxml2.XMLHTTP.3.0');
13334 } catch(e) { }
13335 try {
13336 return new ActiveXObject('Msxml2.XMLHTTP');
13337 } catch(e) { }
13338 }
13339 return false;
13340 }
13341
13342 function successfulRequest(request) {
13343 return (request.status >= 200 && request.status < 300) ||
13344 request.status == 304 ||
13345 (request.status == 0 && request.responseText);
13346 }
13347
13348 /**
13349 * Serialize JavaScript for HTTP requests.
13350 *
13351 * @param {Object} object An Array or Object
13352 * @returns {String} A string suitable for a GET or POST request
13353 */
13354 net.serialize = function(object) {
13355 if (!object) return;
13356
13357 if (typeof object === 'string') {
13358 return object;
13359 }
13360
13361 var results = [];
13362 for (var key in object) {
13363 results.push(encodeURIComponent(key) + '=' + encodeURIComponent(object[key]));
13364 }
13365 return results.join('&');
13366 };
13367
13368 /**
13369 * JSON.parse support can be inferred using `connectsdk.detect('JSON.parse')`.
13370 */
13371 //connectsdk.addDetectionTest('JSON.parse', function() {
13372 // return window.JSON && window.JSON.parse;
13373 //});
13374
13375 /**
13376 * Parses JSON represented as a string.
13377 *
13378 * @param {String} string The original string
13379 * @returns {Object} A JavaScript object
13380 */
13381 net.parseJSON = function(string) {
13382 if (typeof string !== 'string' || !string) return null;
13383 string = trim(string);
13384 /*
13385 return connectsdk.detect('JSON.parse') ?
13386 window.JSON.parse(string) :
13387 (new Function('return ' + string))();
13388 */
13389 return window.JSON.parse(string);
13390 };
13391
13392 /**
13393 * Parses XML represented as a string.
13394 *
13395 * @param {String} string The original string
13396 * @returns {Object} A JavaScript object
13397 */
13398 if (window.DOMParser) {
13399 net.parseXML = function(text) {
13400 return new DOMParser().parseFromString(text, 'text/xml');
13401 };
13402 } else {
13403 net.parseXML = function(text) {
13404 var xml = new ActiveXObject('Microsoft.XMLDOM');
13405 xml.async = 'false';
13406 xml.loadXML(text);
13407 return xml;
13408 };
13409 }
13410
13411 /**
13412 * Creates an Ajax request. Returns an object that can be used
13413 * to chain calls. For example:
13414 *
13415 * $t.post('/post-test')
13416 * .data({ key: 'value' })
13417 * .end(function(res) {
13418 * assert.equal('value', res.responseText);
13419 * });
13420 *
13421 * $t.get('/get-test')
13422 * .set('Accept', 'text/html')
13423 * .end(function(res) {
13424 * assert.equal('Sample text', res.responseText);
13425 * });
13426 *
13427 * The available chained methods are:
13428 *
13429 * `set` -- set a HTTP header
13430 * `data` -- the postBody
13431 * `end` -- send the request over the network, and calls your callback with a `res` object
13432 * `send` -- sends the request and calls `data`: `.send({ data: value }, function(res) { });`
13433 *
13434 * @param {String} The URL to call
13435 * @param {Object} Optional settings
13436 * @returns {Object} A chainable object for further configuration
13437 */
13438 function ajax(url, options) {
13439 var request = xhr(),
13440 promise,
13441 then,
13442 response = {},
13443 chain;
13444 if (connectsdk.Promise) {
13445 promise = new connectsdk.Promise();
13446 }
13447
13448
13449 function respondToReadyState(readyState) {
13450 if (request.readyState == 4) {
13451 var contentType = request.mimeType || request.getResponseHeader('content-type') || '';
13452
13453 response.status = request.status;
13454 response.responseText = request.responseText;
13455 if (/json/.test(contentType)) {
13456 response.responseJSON = net.parseJSON(request.responseText);
13457 } else if (/xml/.test(contentType)) {
13458 response.responseXML = net.parseXML(request.responseText);
13459 }
13460
13461 response.success = successfulRequest(request);
13462
13463 if (options.callback) {
13464 return options.callback(response, request);
13465 }
13466
13467 if (response.success) {
13468 if (options.success) options.success(response, request);
13469 if (promise) promise.resolve(response, request);
13470 } else {
13471 if (options.error) options.error(response, request);
13472 if (promise) promise.reject(response, request);
13473 }
13474 }
13475 }
13476
13477 // Set the HTTP headers
13478 function setHeaders() {
13479 var defaults = {
13480 'Accept': 'text/javascript, application/json, text/html, application/xml, text/xml, */*',
13481 'Content-Type': 'application/json'
13482 };
13483
13484 /**
13485 * Merge headers with defaults.
13486 */
13487 for (var name in defaults) {
13488 if (!options.headers.hasOwnProperty(name))
13489 options.headers[name] = defaults[name];
13490 }
13491 for (var name in options.headers) {
13492 request.setRequestHeader(name, options.headers[name]);
13493 }
13494
13495 }
13496
13497 if (typeof options === 'undefined') options = {};
13498
13499 options.method = options.method ? options.method.toLowerCase() : 'get';
13500 options.asynchronous = options.asynchronous || true;
13501 options.postBody = options.postBody || '';
13502 request.onreadystatechange = respondToReadyState;
13503 request.open(options.method, url, options.asynchronous);
13504
13505 options.headers = options.headers || {};
13506 if (options.contentType) {
13507 options.headers['Content-Type'] = options.contentType;
13508 }
13509
13510 if (typeof options.postBody !== 'string') {
13511 // Serialize JavaScript
13512 options.postBody = net.serialize(options.postBody);
13513 }
13514
13515 // setHeaders();
13516
13517 function send() {
13518 try {
13519 setHeaders();
13520 request.send(options.postBody);
13521 } catch (e) {
13522 if (options.error) {
13523 options.error();
13524 }
13525 }
13526 }
13527
13528 chain = {
13529 set: function(key, value) {
13530 options.headers[key] = value;
13531 return chain;
13532 },
13533
13534 send: function(data, callback) {
13535 options.postBody = net.serialize(data);
13536 options.callback = callback;
13537 send();
13538 return chain;
13539 },
13540
13541 end: function(callback) {
13542 options.callback = callback;
13543 send();
13544 return chain;
13545 },
13546
13547 data: function(data) {
13548 options.postBody = net.serialize(data);
13549 return chain;
13550 },
13551
13552 then: function() {
13553 chain.end();
13554 if (promise) promise.then.apply(promise, arguments);
13555 return chain;
13556 }
13557 };
13558
13559 return chain;
13560 }
13561
13562 function JSONPCallback(url, success, failure) {
13563 var self = this;
13564 this.url = url;
13565 this.methodName = '__connectsdk_jsonp_' + parseInt(new Date().getTime());
13566 this.success = success;
13567 this.failure = failure;
13568
13569 function runCallback(json) {
13570 self.success(json);
13571 self.teardown();
13572 }
13573
13574 window[this.methodName] = runCallback;
13575 }
13576
13577 JSONPCallback.prototype.run = function() {
13578 this.scriptTag = document.createElement('script');
13579 this.scriptTag.id = this.methodName;
13580 this.scriptTag.src = this.url.replace('{callback}', this.methodName);
13581 var that = this;
13582 this.scriptTag.onerror = function() {
13583 that.failure();
13584 };
13585 document.body.appendChild(this.scriptTag);
13586 };
13587
13588 JSONPCallback.prototype.teardown = function() {
13589 window[this.methodName] = null;
13590 try {
13591 delete window[this.methodName];
13592 } catch (e) {}
13593 if (this.scriptTag) {
13594 document.body.removeChild(this.scriptTag);
13595 }
13596 };
13597
13598 /**
13599 * An Ajax GET request.
13600 *
13601 * $t.get('/get-test')
13602 * .set('Accept', 'text/html')
13603 * .end(function(res) {
13604 * assert.equal('Sample text', res.responseText);
13605 * });
13606 *
13607 * @param {String} url The URL to request
13608 * @param {Object} options The Ajax request options
13609 * @returns {Object} A chainable object for further configuration
13610 */
13611 net.get = function(url, options) {
13612 if (typeof options === 'undefined') options = {};
13613 options.method = 'get';
13614 return ajax(url, options);
13615 };
13616
13617 /**
13618 * An Ajax POST request.
13619 *
13620 * $t.post('/post-test')
13621 * .data({ key: 'value' })
13622 * .end(function(res) {
13623 * assert.equal('value', res.responseText);
13624 * });
13625 *
13626 * @param {String} url The URL to request
13627 * @param {Object} options The Ajax request options (`postBody` may come in handy here)
13628 * @returns {Object} An object for further chaining with promises
13629 */
13630 net.post = function(url, options) {
13631 if (typeof options === 'undefined') options = {};
13632 options.method = 'post';
13633 return ajax(url, options);
13634 };
13635
13636 /**
13637 * A jsonp request. Example:
13638 *
13639 * var url = 'http://feeds.delicious.com/v1/json/';
13640 * url += 'alex_young/javascript?callback={callback}';
13641 *
13642 * connectsdk.net.jsonp(url, {
13643 * success: function(json) {
13644 * console.log(json);
13645 * }
13646 * });
13647 *
13648 * @param {String} url The URL to request
13649 */
13650 net.jsonp = function(url, options) {
13651 if (typeof options === 'undefined') options = {};
13652 var callback = new JSONPCallback(url, options.success, options.failure);
13653 callback.run();
13654 };
13655
13656 /**
13657 * The Ajax methods are mapped to the `connectsdk` object:
13658 *
13659 * connectsdk.get();
13660 * connectsdk.post();
13661 * connectsdk.json();
13662 *
13663 */
13664 connectsdk.get = net.get;
13665 connectsdk.post = net.post;
13666 connectsdk.jsonp = net.jsonp;
13667
13668 net.ajax = ajax;
13669 connectsdk.net = net;
13670 return net;
13671});
13672define("connectsdk.Util", ["connectsdk.core"], function (connectsdk) {
13673
13674 // Create a singleton from Util so the same util function can be used in different modules
13675 var Util = (function () {
13676 var instance;
13677
13678 function createInstance() {
13679 // private variables to use in the public methods
13680 var applePayPaymentProductId = 302;
13681 var googlePayPaymentProductId = 320;
13682 var bancontactPaymentProductId = 3012;
13683
13684 return {
13685 applePayPaymentProductId: applePayPaymentProductId,
13686 googlePayPaymentProductId: googlePayPaymentProductId,
13687 bancontactPaymentProductId: bancontactPaymentProductId,
13688 getMetadata: function () {
13689 return {
13690 screenSize: window.innerWidth + "x" + window.innerHeight,
13691 platformIdentifier: window.navigator.userAgent,
13692 sdkIdentifier: ((document.GC && document.GC.rppEnabledPage) ? 'rpp-' : '') + 'JavaScriptClientSDK/v3.13.2',
13693 sdkCreator: 'Ingenico'
13694 };
13695 },
13696 collectDeviceInformation: function () {
13697 return {
13698 "timezoneOffsetUtcMinutes": new Date().getTimezoneOffset(),
13699 "locale": navigator.language,
13700 "browserData": {
13701 "javaScriptEnabled": true,
13702 "javaEnabled": navigator.javaEnabled(),
13703 "colorDepth": screen.colorDepth,
13704 "screenHeight": screen.height,
13705 "screenWidth": screen.width,
13706 "innerHeight": window.innerHeight,
13707 "innerWidth": window.innerWidth
13708 }
13709 };
13710 },
13711 base64Encode: function (data) {
13712 if (typeof data === "object") {
13713 try {
13714 data = JSON.stringify(data);
13715 } catch (e) {
13716 throw "data must be either a String or a JSON object";
13717 }
13718 }
13719
13720 var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
13721 var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, enc = '', tmp_arr = [];
13722
13723 if (!data) {
13724 return data;
13725 }
13726
13727 do {// pack three octets into four hexets
13728 o1 = data.charCodeAt(i++);
13729 o2 = data.charCodeAt(i++);
13730 o3 = data.charCodeAt(i++);
13731
13732 bits = o1 << 16 | o2 << 8 | o3;
13733
13734 h1 = bits >> 18 & 0x3f;
13735 h2 = bits >> 12 & 0x3f;
13736 h3 = bits >> 6 & 0x3f;
13737 h4 = bits & 0x3f;
13738
13739 // use hexets to index into b64, and append result to encoded string
13740 tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
13741 } while (i < data.length);
13742
13743 enc = tmp_arr.join('');
13744
13745 var r = data.length % 3;
13746
13747 return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
13748 },
13749 filterOutProductsThatAreNotSupportedInThisBrowser: function (json) {
13750 for (var i = json.paymentProducts.length - 1, il = 0; i >= il; i--) {
13751 var product = json.paymentProducts[i];
13752 if (product && this.paymentProductsThatAreNotSupportedInThisBrowser.indexOf(product.id) > -1) {
13753 json.paymentProducts.splice(i, 1);
13754 }
13755 }
13756 },
13757 paymentProductsThatAreNotSupportedInThisBrowser: [applePayPaymentProductId]
13758 }
13759 }
13760
13761 return {
13762 getInstance: function () {
13763 if (!instance) {
13764 instance = createInstance();
13765 }
13766 return instance;
13767 }
13768 };
13769 })();
13770
13771 connectsdk.Util = Util;
13772 return Util;
13773});
13774
13775define("connectsdk.GooglePay", ["connectsdk.core", "connectsdk.promise", "connectsdk.Util"], function (connectsdk, Promise, Util) {
13776
13777 var _util = Util.getInstance();
13778 var _C2SCommunicator = null;
13779 var _paymentProductSpecificInputs = null;
13780 var _context = null;
13781 var _gateway = null;
13782 var _networks = null;
13783 var paymentsClient = null;
13784
13785 // Only base is needed to trigger isReadyToPay
13786 var _getBaseCardPaymentMethod = function () {
13787 return {
13788 type: 'CARD',
13789 parameters: {
13790 allowedAuthMethods: ["PAN_ONLY", "CRYPTOGRAM_3DS"],
13791 allowedCardNetworks: _networks
13792 }
13793 }
13794 };
13795
13796 var _getTokenizationSpecification = function () {
13797 return {
13798 type: 'PAYMENT_GATEWAY',
13799 parameters: {
13800 'gateway': _gateway,
13801 'gatewayMerchantId': _paymentProductSpecificInputs.googlePay.gatewayMerchantId
13802 }
13803 }
13804 };
13805
13806 // To prefetch payment data we need base + tokenizationSpecification
13807 var _getCardPaymentMethod = function () {
13808 return Object.assign(
13809 {},
13810 _getBaseCardPaymentMethod(),
13811 {
13812 tokenizationSpecification: _getTokenizationSpecification()
13813 }
13814 );
13815 };
13816
13817 var _getTransactionInfo = function () {
13818 return {
13819 "totalPriceStatus": "NOT_CURRENTLY_KNOWN",
13820 "currencyCode": _context.currency
13821 };
13822 };
13823
13824 var _getMerchantInfo = function () {
13825 return {
13826 "merchantName": _paymentProductSpecificInputs.googlePay.merchantName
13827 };
13828 };
13829
13830 var _getGooglePaymentDataRequest = function () {
13831 return {
13832 apiVersion: 2,
13833 apiVersionMinor: 0,
13834 allowedPaymentMethods: [_getBaseCardPaymentMethod()]
13835 };
13836 };
13837
13838 var _getGooglePaymentDataRequestForPrefetch = function () {
13839 // transactionInfo must be set but does not affect cache
13840 return {
13841 apiVersion: 2,
13842 apiVersionMinor: 0,
13843 allowedPaymentMethods: [_getCardPaymentMethod()],
13844 transactionInfo: _getTransactionInfo(),
13845 merchantInfo: _getMerchantInfo()
13846 };
13847 };
13848
13849 function _getGooglePaymentsClient() {
13850 if (paymentsClient === null) {
13851 var googlePayEnvironment = 'TEST';
13852 if (_context.environment === 'PROD') {
13853 googlePayEnvironment = 'PROD';
13854 }
13855 if (window.google) {
13856 paymentsClient = new google.payments.api.PaymentsClient({environment: googlePayEnvironment});
13857 } else {
13858 console.error("The Google Pay API script was not loaded https://developers.google.com/pay/api/web/guides/tutorial#js-load");
13859 }
13860 }
13861 return paymentsClient;
13862 }
13863
13864 /**
13865 * Prefetch payment data to improve performance
13866 *
13867 * @see {@link https://developers.google.com/pay/api/web/reference/client#prefetchPaymentData|prefetchPaymentData()}
13868 */
13869 function prefetchGooglePaymentData() {
13870 var paymentDataRequest = _getGooglePaymentDataRequestForPrefetch();
13871
13872 var paymentsClient = _getGooglePaymentsClient();
13873
13874 // Prefetching is only effective when all information is provided
13875 if (_paymentProductSpecificInputs.googlePay.gatewayMerchantId &&
13876 _paymentProductSpecificInputs.googlePay.merchantName) {
13877 paymentsClient.prefetchPaymentData(paymentDataRequest);
13878 } else {
13879 console.warn("Prefetching payment data was not triggered because of missing information. " +
13880 "gatewayMerchantId: " + _paymentProductSpecificInputs.googlePay.gatewayMerchantId +
13881 ", merchantName: " + _paymentProductSpecificInputs.googlePay.merchantName)
13882 }
13883 }
13884
13885 var GooglePay = function (C2SCommunicator) {
13886 _C2SCommunicator = C2SCommunicator;
13887 this.isGooglePayAvailable = function (context, paymentProductSpecificInputs, googlePayData) {
13888 _context = context;
13889 _paymentProductSpecificInputs = paymentProductSpecificInputs;
13890 if (googlePayData && googlePayData.networks) {
13891 _gateway = googlePayData.gateway;
13892 _networks = googlePayData.networks;
13893 } else {
13894 _gateway = "ingenicoglobalcollect";
13895 _networks = googlePayData;
13896 }
13897 var promise = new Promise();
13898 // This setTimeout is essential to make the following (not fully asynchronous) code work in a promise way in all scenarios. (not needed in happy flow)
13899 // The SDK has it's only PolyFill for the promise which is not feature complete.
13900 setTimeout(function () {
13901 if (_networks && _networks.length > 0) {
13902 var paymentsClient = _getGooglePaymentsClient();
13903 if (!paymentsClient) {
13904 _util.paymentProductsThatAreNotSupportedInThisBrowser.push(_util.googlePayPaymentProductId);
13905 promise.reject("The Google Pay API script was not loaded https://developers.google.com/pay/api/web/guides/tutorial#js-load");
13906 } else {
13907 paymentsClient.isReadyToPay(_getGooglePaymentDataRequest())
13908 .then(function (response) {
13909 promise.resolve(response);
13910
13911 prefetchGooglePaymentData();
13912 })
13913 .catch(function () {
13914 _util.paymentProductsThatAreNotSupportedInThisBrowser.push(_util.googlePayPaymentProductId);
13915 promise.reject('failed to run isReadyToPay() with Google Pay API');
13916 });
13917 }
13918 } else {
13919 _util.paymentProductsThatAreNotSupportedInThisBrowser.push(_util.googlePayPaymentProductId);
13920 promise.reject('There are no product networks available');
13921 }
13922 }, 0);
13923 return promise;
13924 };
13925
13926 this.isMerchantIdProvided = function (paymentProductSpecificInputs) {
13927 if (paymentProductSpecificInputs.googlePay.merchantId) {
13928 return paymentProductSpecificInputs.googlePay.merchantId;
13929 } else {
13930 _util.paymentProductsThatAreNotSupportedInThisBrowser.push(_util.googlePayPaymentProductId);
13931 return false;
13932 }
13933 }
13934 };
13935 connectsdk.GooglePay = GooglePay;
13936 return GooglePay;
13937});
13938
13939define("connectsdk.PublicKeyResponse", ["connectsdk.core"], function(connectsdk) {
13940
13941 var PublicKeyResponse = function(json) {
13942 this.json = json;
13943 this.keyId = json.keyId;
13944 this.publicKey = json.publicKey;
13945 };
13946
13947 connectsdk.PublicKeyResponse = PublicKeyResponse;
13948 return PublicKeyResponse;
13949});
13950define("connectsdk.C2SCommunicatorConfiguration", ["connectsdk.core"], function (connectsdk) {
13951
13952 var C2SCommunicatorConfiguration = function (sessionDetails, apiVersion) {
13953 this.endpoints = {
13954 PROD: {
13955 EU: {
13956 API: "https://ams1.api-ingenico.com/client/v1",
13957 ASSETS: "https://assets.pay1.secured-by-ingenico.com"
13958 },
13959 US: {
13960 API: "https://us.api-ingenico.com/client/v1",
13961 ASSETS: "https://assets.pay2.secured-by-ingenico.com"
13962 },
13963 AMS: {
13964 API: "https://ams2.api-ingenico.com/client/v1",
13965 ASSETS: "https://assets.pay3.secured-by-ingenico.com"
13966 },
13967 PAR: {
13968 API: "https://par.api-ingenico.com/client/v1",
13969 ASSETS: "https://assets.pay4.secured-by-ingenico.com"
13970 }
13971 },
13972 PREPROD: {
13973 EU: {
13974 API: "https://ams1.preprod.api-ingenico.com/client/v1",
13975 ASSETS: "https://assets.pay1.preprod.secured-by-ingenico.com"
13976 },
13977 US: {
13978 API: "https://us.preprod.api-ingenico.com/client/v1",
13979 ASSETS: "https://assets.pay2.preprod.secured-by-ingenico.com"
13980 },
13981 AMS: {
13982 API: "https://ams2.preprod.api-ingenico.com/client/v1",
13983 ASSETS: "https://assets.pay3.preprod.secured-by-ingenico.com"
13984 },
13985 PAR: {
13986 API: "https://par-preprod.api-ingenico.com/client/v1",
13987 ASSETS: "https://assets.pay4.preprod.secured-by-ingenico.com"
13988 }
13989 },
13990 SANDBOX: {
13991 EU: {
13992 API: "https://ams1.sandbox.api-ingenico.com/client/v1",
13993 ASSETS: "https://assets.pay1.sandbox.secured-by-ingenico.com"
13994 },
13995 US: {
13996 API: "https://us.sandbox.api-ingenico.com/client/v1",
13997 ASSETS: "https://assets.pay2.sandbox.secured-by-ingenico.com"
13998 },
13999 AMS: {
14000 API: "https://ams2.sandbox.api-ingenico.com/client/v1",
14001 ASSETS: "https://assets.pay3.sandbox.secured-by-ingenico.com"
14002 },
14003 PAR: {
14004 API: "https://par.sandbox.api-ingenico.com/client/v1",
14005 ASSETS: "https://assets.pay4.sandbox.secured-by-ingenico.com"
14006 }
14007 }
14008
14009 // Non public settings. Only needed in GC development environment. Do not use
14010 // these, they will not work outside GC.
14011 ,
14012 INTEGRATION: {
14013 EU: {
14014 API: "https://int-test-api.gcsip.nl:4443/client/v1",
14015 ASSETS: "https://assets.int-test-rpp.gcsip.nl:4443"
14016 },
14017 US: {
14018 API: "https://int-test-api.gcsip.nl:4443/client/v1",
14019 ASSETS: "https://assets.int-test-rpp.gcsip.nl:4443"
14020 },
14021 AMS: {
14022 API: "https://int-test-api.gcsip.nl:4443/client/v1",
14023 ASSETS: "https://assets.int-test-rpp.gcsip.nl:4443"
14024 },
14025 PAR: {
14026 API: "https://int-test-api.gcsip.nl:4443/client/v1",
14027 ASSETS: "https://assets.int-test-rpp.gcsip.nl:4443"
14028 }
14029 },
14030 DEV_NAMI: {
14031 EU: {
14032 API: "https://nami-test-api.gcsip.nl:4443/client/v1",
14033 ASSETS: "https://assets.nami-test-rpp.gcsip.nl:4443"
14034 },
14035 US: {
14036 API: "https://nami-test-api.gcsip.nl:4443/client/v1",
14037 ASSETS: "https://assets.nami-test-rpp.gcsip.nl:4443"
14038 },
14039 AMS: {
14040 API: "https://nami-test-api.gcsip.nl:4443/client/v1",
14041 ASSETS: "https://assets.nami-test-rpp.gcsip.nl:4443"
14042 },
14043 PAR: {
14044 API: "https://nami-test-api.gcsip.nl:4443/client/v1",
14045 ASSETS: "https://assets.nami-test-rpp.gcsip.nl:4443"
14046 }
14047 },
14048 DEV_ISC: {
14049 EU: {
14050 API: "//api.gc-dev.isaac.local/client/v1",
14051 ASSETS: "//rpp.gc-dev.isaac.local"
14052 },
14053 US: {
14054 API: "//api.gc-ci-dev.isaac.local/client/v1",
14055 ASSETS: "//rpp.gc-ci-dev.isaac.local"
14056 },
14057 AMS: {
14058 API: "//api.gc-dev.isaac.local/client/v1",
14059 ASSETS: "//rpp.gc-dev.isaac.local"
14060 },
14061 PAR: {
14062 API: "//api.gc-dev.isaac.local/client/v1",
14063 ASSETS: "//rpp.gc-dev.isaac.local"
14064 }
14065 }
14066 };
14067
14068 // clientSessionID, assetBaseUrl and apiBaseUrl are deprecated but still may be used. Here we check for presense of new variables, if they dont exist... Use the old variables.
14069 if (!sessionDetails.clientSessionId) {
14070 sessionDetails.clientSessionId = sessionDetails.clientSessionID;
14071 } else if (sessionDetails.clientSessionID) {
14072 throw new Error("You cannot use both the clientSessionId and the clientSessionID at the same time, please use the clientSessionId only.");
14073 }
14074 if (!sessionDetails.assetUrl) {
14075 sessionDetails.assetUrl = sessionDetails.assetsBaseUrl
14076 } else if (sessionDetails.assetsBaseUrl) {
14077 throw new Error("You cannot use both the assetUrl and the assetsBaseUrl at the same time, please use the assetUrl only.");
14078 }
14079 if (!sessionDetails.clientApiUrl) {
14080 sessionDetails.clientApiUrl = sessionDetails.apiBaseUrl
14081 } else if (sessionDetails.apiBaseUrl) {
14082 throw new Error("You cannot use both the clientApiUrl and the apiBaseUrl at the same time, please use the clientApiUrl only.");
14083 }
14084
14085 this.clientSessionId = sessionDetails.clientSessionId;
14086 this.customerId = sessionDetails.customerId;
14087
14088 // can be removed in a newer version of the SDK from this line
14089 if (sessionDetails.region && !sessionDetails.clientApiUrl) {
14090 // use regions; old stuff
14091 console.warn("Using regions is deprecated, switch to clientApiUrl");
14092 this.clientApiUrl = this.endpoints[sessionDetails.environment][sessionDetails.region].API;
14093 this.assetUrl = this.endpoints[sessionDetails.environment][sessionDetails.region].ASSETS;
14094 } else {
14095 // till this line; normal behaviour is below
14096 // ignore the region here
14097 this.clientApiUrl = sessionDetails.clientApiUrl;
14098 this.assetUrl = sessionDetails.assetUrl;
14099 if (!this.clientApiUrl) {
14100 throw new Error("This version of the connectSDK requires an clientApiUrl, which you did not provide.");
14101 }
14102 if (!this.assetUrl) {
14103 throw new Error("This version of the connectSDK requires an assetUrl, which you did not provide.");
14104 }
14105
14106 // now that the clientApiUrl is set check when if the api version is set in the URL, its the correct version break if not.
14107 if (this.clientApiUrl.indexOf("//") === -1) {
14108 throw new Error("A valid URL is required for the clientApiUrl, you provided '" + this.clientApiUrl + "'");
14109 }
14110 var tester = this.clientApiUrl.split("/"); // [0] = (http(s): || "") , [1] = "", [2] = "host:port", [3+] = path
14111 if (tester[0] !== "" && tester[0].indexOf("http") !== 0) {
14112 throw new Error("A valid URL is required for the clientApiUrl, you provided '" + this.clientApiUrl + "'");
14113 }
14114 // if you cannot provide an URL that starts with (http(s)::)// and want an error: please provide a PR :)
14115
14116 var path = tester.splice(3).join("/"); // the path (if no path; path = "").
14117 if (!path) { //If path == ""
14118 this.clientApiUrl += "/" + apiVersion;
14119 } else if (path === 'client') { //If path == client
14120 this.clientApiUrl += "/" + apiVersion.split('/')[1];
14121 } else if (path.indexOf(apiVersion) !== 0 || path.length !== apiVersion.length) {
14122 throw new Error("This version of the connectSDK is only compatible with " + apiVersion + ", you supplied: '" + path + "'");
14123 }
14124 }
14125 };
14126 connectsdk.C2SCommunicatorConfiguration = C2SCommunicatorConfiguration;
14127 return C2SCommunicatorConfiguration;
14128});
14129define("connectsdk.IinDetailsResponse", ["connectsdk.core", "connectsdk.promise"], function(connectsdk, Promise) {
14130
14131 var IinDetailsResponse = function () {
14132 this.status = '';
14133 this.countryCode = '';
14134 this.paymentProductId = '';
14135 this.isAllowedInContext = '';
14136 this.coBrands = [];
14137 };
14138 connectsdk.IinDetailsResponse = IinDetailsResponse;
14139 return IinDetailsResponse;
14140});
14141define("connectsdk.C2SCommunicator", ["connectsdk.core", "connectsdk.promise", "connectsdk.net", "connectsdk.Util", "connectsdk.PublicKeyResponse", "connectsdk.IinDetailsResponse", "connectsdk.GooglePay"], function (connectsdk, Promise, Net, Util, PublicKeyResponse, IinDetailsResponse, GooglePay) {
14142 var C2SCommunicator = function (c2SCommunicatorConfiguration, paymentProduct) {
14143 var _c2SCommunicatorConfiguration = c2SCommunicatorConfiguration;
14144 var _util = Util.getInstance();
14145 var _cache = {};
14146 var _providedPaymentProduct = paymentProduct;
14147 var that = this;
14148 var _GooglePay = new GooglePay(that);
14149
14150 var _mapType = {
14151 "expirydate": "tel",
14152 "string": "text",
14153 "numericstring": "tel",
14154 "integer": "number",
14155 "expirationDate": "tel"
14156 };
14157
14158 var formatUrl = function (url) {
14159 return (url && endsWith(url, '/')) ? url : url + '/';
14160 };
14161
14162 var formatImageUrl = function(url, imageUrl) {
14163 url = formatUrl(url);
14164 // _cleanJSON can be called multiple times with the same data (which is cached between calls).
14165 // Don't prepend the url after the first time.
14166 if (startsWith(imageUrl, url)) {
14167 return imageUrl;
14168 }
14169 return url + imageUrl;
14170 };
14171
14172 var startsWith = function(string, prefix) {
14173 return string.indexOf(prefix) === 0;
14174 };
14175
14176 var endsWith = function(string, suffix) {
14177 return string.indexOf(suffix, string.length - suffix.length) !== -1;
14178 };
14179
14180 var _cleanJSON = function (json, url) {
14181 for (var i = 0, il = json.fields.length; i < il; i++) {
14182 var field = json.fields[i];
14183 field.type = (field.displayHints && field.displayHints.obfuscate) ? "password" : _mapType[field.type];
14184
14185 // helper code for templating tools like Handlebars
14186 for (validatorKey in field.dataRestrictions.validators) {
14187 field.validators = field.validators || [];
14188 field.validators.push(validatorKey);
14189 }
14190 if (field.displayHints && field.displayHints.formElement && field.displayHints.formElement.type === 'list') {
14191 field.displayHints.formElement.list = true;
14192 }
14193
14194 // full image paths
14195 if (field.displayHints && field.displayHints.tooltip && field.displayHints.tooltip.image) {
14196 field.displayHints.tooltip.image = formatImageUrl(url, field.displayHints.tooltip.image);
14197 }
14198 }
14199 // The server orders in a different way, so we apply the sortorder
14200 json.fields.sort(function (a, b) {
14201 if (a.displayHints.displayOrder < b.displayHints.displayOrder) {
14202 return -1;
14203 }
14204 return 1;
14205 });
14206 // set full image path
14207 json.displayHints.logo = formatImageUrl(url, json.displayHints.logo);
14208 return json;
14209 };
14210
14211 var _extendLogoUrl = function (json, url, postfix) {
14212 for (var i = 0, il = json["paymentProduct" + postfix].length; i < il; i++) {
14213 var product = json["paymentProduct" + postfix][i];
14214 product.displayHints.logo = formatImageUrl(url, product.displayHints.logo);
14215 }
14216 json["paymentProduct" + postfix].sort(function (a, b) {
14217 if (a.displayHints.displayOrder < b.displayHints.displayOrder) {
14218 return -1;
14219 }
14220 return 1;
14221 });
14222 return json;
14223 };
14224
14225 var _isPaymentProductInList = function (list, paymentProductId) {
14226 for (var i = list.length - 1, il = 0; i >= il; i--) {
14227 var product = list[i];
14228 if (product && (product.id === paymentProductId)) {
14229 return true;
14230 }
14231 }
14232 return false;
14233 };
14234
14235 var _getGooglePayData = function (list, paymentProductId) {
14236 for (var i = list.length - 1, il = 0; i >= il; i--) {
14237 var product = list[i];
14238 if (product && (product.id === paymentProductId)) {
14239 return product.paymentProduct320SpecificData;
14240 }
14241 }
14242 return false;
14243 };
14244
14245 var metadata = _util.getMetadata();
14246
14247 this.getBasicPaymentProducts = function (context, paymentProductSpecificInputs) {
14248 var cacheKeyLocale= context.locale ? context.locale + "_" : '';
14249 paymentProductSpecificInputs = paymentProductSpecificInputs || {};
14250 var promise = new Promise()
14251 , cacheBust = new Date().getTime()
14252 , cacheKey = "getPaymentProducts-" + context.totalAmount + "_" + context.countryCode + "_"
14253 + cacheKeyLocale + context.isRecurring + "_" + context.currency + "_" + JSON.stringify(paymentProductSpecificInputs);
14254
14255 if (_cache[cacheKey]) {
14256 setTimeout(function () {
14257 promise.resolve(_cache[cacheKey]);
14258 }, 0);
14259 } else {
14260 var urlParameterLocale = context.locale ? "&locale=" + context.locale: '';
14261 Net.get(formatUrl(_c2SCommunicatorConfiguration.clientApiUrl) + _c2SCommunicatorConfiguration.customerId
14262 + "/products" + "?countryCode=" + context.countryCode + "&isRecurring=" + context.isRecurring
14263 + "&amount=" + context.totalAmount + "¤cyCode=" + context.currency
14264 + "&hide=fields" + urlParameterLocale + "&cacheBust=" + cacheBust)
14265 .set('X-GCS-ClientMetaInfo', _util.base64Encode(metadata))
14266 .set('Authorization', 'GCS v1Client:' + _c2SCommunicatorConfiguration.clientSessionId)
14267 .end(function (res) {
14268 if (res.success) {
14269 var json = _extendLogoUrl(res.responseJSON, _c2SCommunicatorConfiguration.assetUrl, "s");
14270 if (_isPaymentProductInList(json.paymentProducts, _util.googlePayPaymentProductId)) {
14271 if (_GooglePay.isMerchantIdProvided(paymentProductSpecificInputs)) {
14272 var googlePayData = _getGooglePayData(json.paymentProducts, _util.googlePayPaymentProductId);
14273 _GooglePay.isGooglePayAvailable(context, paymentProductSpecificInputs, googlePayData).then(function (isGooglePayAvailable) {
14274 _util.filterOutProductsThatAreNotSupportedInThisBrowser(json);
14275 if (json.paymentProducts.length === 0) {
14276 promise.reject('No payment products available');
14277 }
14278 _cache[cacheKey] = json;
14279 promise.resolve(json);
14280 }, function () {
14281 _util.filterOutProductsThatAreNotSupportedInThisBrowser(json);
14282 if (json.paymentProducts.length === 0) {
14283 promise.reject('No payment products available');
14284 }
14285 _cache[cacheKey] = json;
14286 promise.resolve(json);
14287 });
14288 } else {
14289 //GooglePay does not have merchantId
14290 _util.filterOutProductsThatAreNotSupportedInThisBrowser(json);
14291 console.warn('You have not provided a merchantId for Google Pay, you can set this in the paymentProductSpecificInputs object');
14292 promise.resolve(json);
14293 }
14294 } else {
14295 _util.filterOutProductsThatAreNotSupportedInThisBrowser(json);
14296 if (json.paymentProducts.length === 0) {
14297 promise.reject('No payment products available');
14298 }
14299 _cache[cacheKey] = json;
14300 promise.resolve(json);
14301 }
14302 } else {
14303 promise.reject('failed to retrieve Basic Payment Products', res);
14304 }
14305 });
14306 }
14307 return promise;
14308 };
14309
14310 this.getBasicPaymentProductGroups = function (context) {
14311 var cacheKeyLocale = context.locale ? context.locale + "_" : '';
14312 var promise = new Promise()
14313 , cacheBust = new Date().getTime()
14314 , cacheKey = "getPaymentProductGroups-" + context.totalAmount + "_" + context.countryCode + "_"
14315 + cacheKeyLocale + context.isRecurring + "_" + context.currency;
14316
14317 if (_cache[cacheKey]) {
14318 setTimeout(function () {
14319 promise.resolve(_cache[cacheKey]);
14320 }, 0);
14321 } else {
14322 var urlParameterLocale = context.locale ? "&locale=" + context.locale: '';
14323 Net.get(formatUrl(_c2SCommunicatorConfiguration.clientApiUrl) + _c2SCommunicatorConfiguration.customerId
14324 + "/productgroups" + "?countryCode=" + context.countryCode + "&isRecurring=" + context.isRecurring
14325 + "&amount=" + context.totalAmount + "¤cyCode=" + context.currency
14326 + "&hide=fields" + urlParameterLocale + "&cacheBust=" + cacheBust)
14327 .set('X-GCS-ClientMetaInfo', _util.base64Encode(metadata))
14328 .set('Authorization', 'GCS v1Client:' + _c2SCommunicatorConfiguration.clientSessionId)
14329 .end(function (res) {
14330 if (res.success) {
14331 var json = _extendLogoUrl(res.responseJSON, _c2SCommunicatorConfiguration.assetUrl, "Groups");
14332 _cache[cacheKey] = json;
14333 promise.resolve(json);
14334 } else {
14335 promise.reject();
14336 }
14337 });
14338 }
14339 return promise;
14340 };
14341
14342 this.getPaymentProduct = function (paymentProductId, context, paymentProductSpecificInputs) {
14343 paymentProductSpecificInputs = paymentProductSpecificInputs || {};
14344 var cacheKeyLocale = context.locale ? context.locale + "_" : '';
14345 var promise = new Promise()
14346 , cacheBust = new Date().getTime()
14347 , cacheKey = "getPaymentProduct-" + paymentProductId + "_" + context.totalAmount + "_"
14348 + context.countryCode + "_" + cacheKeyLocale + context.isRecurring + "_"
14349 + context.currency + "_" + JSON.stringify(paymentProductSpecificInputs);
14350 if (_util.paymentProductsThatAreNotSupportedInThisBrowser.indexOf(paymentProductId) > -1) {
14351 setTimeout(function () {
14352 promise.reject({
14353 "errorId": "48b78d2d-1b35-4f8b-92cb-57cc2638e901",
14354 "errors": [{
14355 "code": "1007",
14356 "propertyName": "productId",
14357 "message": "UNKNOWN_PRODUCT_ID",
14358 "httpStatusCode": 404
14359 }]
14360 });
14361 }, 0);
14362 } else {
14363 if (_providedPaymentProduct && _providedPaymentProduct.id === paymentProductId) {
14364 if (!_cache[cacheKey]) {
14365 _cache[cacheKey] = _cleanJSON(_providedPaymentProduct, _c2SCommunicatorConfiguration.assetUrl);
14366 }
14367 setTimeout(function () {
14368 promise.resolve(_cache[cacheKey]);
14369 }, 0);
14370 } else if (_cache[cacheKey]) {
14371 setTimeout(function () {
14372 promise.resolve(_cache[cacheKey]);
14373 }, 0);
14374 } else {
14375 var urlParameterlocale = context.locale ? "&locale=" + context.locale: '';
14376 var getPaymentProductUrl = formatUrl(_c2SCommunicatorConfiguration.clientApiUrl) + _c2SCommunicatorConfiguration.customerId
14377 + "/products/" + paymentProductId + "?countryCode=" + context.countryCode
14378 + "&isRecurring=" + context.isRecurring + "&amount=" + context.totalAmount
14379 + "¤cyCode=" + context.currency + urlParameterlocale;
14380
14381 if ((paymentProductId === _util.bancontactPaymentProductId) &&
14382 paymentProductSpecificInputs &&
14383 paymentProductSpecificInputs.bancontact &&
14384 paymentProductSpecificInputs.bancontact.forceBasicFlow) {
14385 // Add query parameter to products call to force basic flow for bancontact
14386 getPaymentProductUrl += "&forceBasicFlow=" + paymentProductSpecificInputs.bancontact.forceBasicFlow
14387 }
14388
14389 getPaymentProductUrl += "&cacheBust=" + cacheBust;
14390
14391 Net.get(getPaymentProductUrl)
14392 .set('X-GCS-ClientMetaInfo', _util.base64Encode(metadata))
14393 .set('Authorization', 'GCS v1Client:' + _c2SCommunicatorConfiguration.clientSessionId)
14394 .end(function (res) {
14395 if (res.success) {
14396 var cleanedJSON = _cleanJSON(res.responseJSON, c2SCommunicatorConfiguration.assetUrl);
14397 if (paymentProductId === _util.googlePayPaymentProductId) {
14398 if (_GooglePay.isMerchantIdProvided(paymentProductSpecificInputs)) {
14399 var networks = cleanedJSON.paymentProduct320SpecificData.networks;
14400 _GooglePay.isGooglePayAvailable(context, paymentProductSpecificInputs, networks).then(function (isGooglePayAvailable) {
14401 if (isGooglePayAvailable) {
14402 _cache[cacheKey] = cleanedJSON;
14403 promise.resolve(cleanedJSON);
14404 } else {
14405 _cache[cacheKey] = cleanedJSON;
14406 //_isGooglePayAvailable returned false so google pay is not available, so reject getPaymentProduct
14407 promise.reject(cleanedJSON);
14408 }
14409 }, function () {
14410 _cache[cacheKey] = cleanedJSON;
14411 //_isGooglePayAvailable rejected so not available
14412 promise.reject(cleanedJSON);
14413 });
14414 } else {
14415 _cache[cacheKey] = cleanedJSON;
14416 // merchantId is not provided so reject
14417 promise.reject(cleanedJSON);
14418 }
14419 } else {
14420 _cache[cacheKey] = cleanedJSON;
14421 promise.resolve(cleanedJSON);
14422 }
14423 } else {
14424 promise.reject('failed to retrieve Payment Product', res);
14425 }
14426 });
14427 }
14428 }
14429 return promise;
14430 };
14431
14432 this.getPaymentProductGroup = function (paymentProductGroupId, context) {
14433 var cacheKeyLocale = context.locale ? context.locale + "_" : '';
14434 var promise = new Promise()
14435 , cacheBust = new Date().getTime()
14436 , cacheKey = "getPaymentProductGroup-" + paymentProductGroupId + "_" + context.totalAmount + "_"
14437 + context.countryCode + "_" + cacheKeyLocale + context.isRecurring + "_"
14438 + context.currency;
14439 if (_providedPaymentProduct && _providedPaymentProduct.id === paymentProductGroupId) {
14440 if (_cache[cacheKey]) {
14441 setTimeout(function () {
14442 promise.resolve(_cache[cacheKey]);
14443 }, 0);
14444 } else {
14445 _cache[cacheKey] = _cleanJSON(_providedPaymentProduct, _c2SCommunicatorConfiguration.assetUrl);
14446 setTimeout(function () {
14447 promise.resolve(_cache[cacheKey]);
14448 }, 0);
14449 }
14450 } else if (_cache[cacheKey]) {
14451 setTimeout(function () {
14452 promise.resolve(_cache[cacheKey]);
14453 }, 0);
14454 } else {
14455 var urlParameterlocale = context.locale ? "&locale=" + context.locale: '';
14456 Net.get(formatUrl(_c2SCommunicatorConfiguration.clientApiUrl) + _c2SCommunicatorConfiguration.customerId
14457 + "/productgroups/" + paymentProductGroupId + "?countryCode=" + context.countryCode
14458 + "&isRecurring=" + context.isRecurring + "&amount=" + context.totalAmount
14459 + "¤cyCode=" + context.currency + urlParameterlocale + "&cacheBust=" + cacheBust)
14460 .set('X-GCS-ClientMetaInfo', _util.base64Encode(metadata))
14461 .set('Authorization', 'GCS v1Client:' + _c2SCommunicatorConfiguration.clientSessionId)
14462 .end(function (res) {
14463 if (res.success) {
14464 var cleanedJSON = _cleanJSON(res.responseJSON, c2SCommunicatorConfiguration.assetUrl);
14465 _cache[cacheKey] = cleanedJSON;
14466 promise.resolve(cleanedJSON);
14467 } else {
14468 promise.reject();
14469 }
14470 });
14471 }
14472 return promise;
14473 };
14474
14475 this.getPaymentProductIdByCreditCardNumber = function (partialCreditCardNumber, context) {
14476 var promise = new Promise()
14477 , iinDetailsResponse = new IinDetailsResponse()
14478 , cacheKey = "getPaymentProductIdByCreditCardNumber-" + partialCreditCardNumber;
14479
14480 var that = this;
14481 this.context = context;
14482 if (_cache[cacheKey]) {// cache is based on digit 1-6
14483 setTimeout(function () {
14484 promise.resolve(_cache[cacheKey]);
14485 }, 0);
14486 } else {
14487 var isEnoughDigits = function (partialCreditCardNumber) {
14488 return partialCreditCardNumber.length >= 6;
14489 };
14490 if (isEnoughDigits(partialCreditCardNumber)) {
14491 Net.post(formatUrl(_c2SCommunicatorConfiguration.clientApiUrl) + _c2SCommunicatorConfiguration.customerId + "/services/getIINdetails")
14492 .data(JSON.stringify(this.convertContextToIinDetailsContext(partialCreditCardNumber, this.context)))
14493 .set('X-GCS-ClientMetaInfo', _util.base64Encode(metadata))
14494 .set('Authorization', 'GCS v1Client:' + _c2SCommunicatorConfiguration.clientSessionId)
14495 .end(function (res) {
14496 if (res.success) {
14497 iinDetailsResponse.json = res.responseJSON;
14498 iinDetailsResponse.countryCode = res.responseJSON.countryCode;
14499 iinDetailsResponse.paymentProductId = res.responseJSON.paymentProductId;
14500 iinDetailsResponse.isAllowedInContext = res.responseJSON.isAllowedInContext;
14501 iinDetailsResponse.coBrands = res.responseJSON.coBrands;
14502 // check if this card is supported
14503 // if isAllowedInContext is available in the response set status and resolve
14504 if (res.responseJSON.hasOwnProperty('isAllowedInContext')) {
14505 iinDetailsResponse.status = "SUPPORTED";
14506 if (iinDetailsResponse.isAllowedInContext === false) {
14507 iinDetailsResponse.status = "EXISTING_BUT_NOT_ALLOWED";
14508 }
14509 _cache[cacheKey] = iinDetailsResponse;
14510 promise.resolve(iinDetailsResponse);
14511 } else {
14512 //if isAllowedInContext is not available get the payment product again to determine status and resolve
14513 that.getPaymentProduct(iinDetailsResponse.paymentProductId, that.context).then(function (paymentProduct) {
14514 if (paymentProduct) {
14515 iinDetailsResponse.status = "SUPPORTED";
14516 } else {
14517 iinDetailsResponse.status = "UNSUPPORTED";
14518 }
14519 _cache[cacheKey] = iinDetailsResponse;
14520 promise.resolve(iinDetailsResponse);
14521 }, function () {
14522 iinDetailsResponse.status = "UNKNOWN";
14523 promise.reject(iinDetailsResponse);
14524 });
14525 }
14526 } else {
14527 iinDetailsResponse.status = "UNKNOWN";
14528 promise.reject(iinDetailsResponse);
14529 }
14530 });
14531 } else {
14532 iinDetailsResponse.status = "NOT_ENOUGH_DIGITS";
14533 setTimeout(function () {
14534 promise.resolve(iinDetailsResponse);
14535 }, 0);
14536 }
14537 }
14538 return promise;
14539 };
14540
14541 this.convertContextToIinDetailsContext = function (partialCreditCardNumber, context) {
14542 var payload = {
14543 "bin": partialCreditCardNumber,
14544 "paymentContext": {
14545 "countryCode": context.countryCode,
14546 "isRecurring": context.isRecurring,
14547 "amountOfMoney": {
14548 "amount": context.totalAmount,
14549 "currencyCode": context.currency
14550 }
14551 }
14552 };
14553
14554 // Account on file id is needed only in case when the merchant
14555 // uses multiple payment platforms at the same time.
14556 if (typeof context.accountOnFileId !== 'undefined') {
14557 payload.accountOnFileId = context.accountOnFileId;
14558 }
14559
14560 return payload;
14561 };
14562
14563 this.getPublicKey = function () {
14564 var promise = new Promise()
14565 , cacheKey = "publicKey";
14566
14567 if (_cache[cacheKey]) {
14568 setTimeout(function () {
14569 promise.resolve(_cache[cacheKey]);
14570 }, 0);
14571 } else {
14572 Net.get(formatUrl(_c2SCommunicatorConfiguration.clientApiUrl) + _c2SCommunicatorConfiguration.customerId + "/crypto/publickey")
14573 .set("X-GCS-ClientMetaInfo", _util.base64Encode(metadata))
14574 .set('Authorization', 'GCS v1Client:' + _c2SCommunicatorConfiguration.clientSessionId)
14575 .end(function (res) {
14576 if (res.success) {
14577 var publicKeyResponse = new PublicKeyResponse(res.responseJSON);
14578 _cache[cacheKey] = publicKeyResponse;
14579 promise.resolve(publicKeyResponse);
14580 } else {
14581 promise.reject("unable to get public key");
14582 }
14583 });
14584 }
14585 return promise;
14586 };
14587
14588 this.getPaymentProductNetworks = function (paymentProductId, context) {
14589 var promise = new Promise()
14590 , cacheKey = "paymentProductNetworks-" + paymentProductId + "_" + context.countryCode + "_" + context.currency + "_"
14591 + context.totalAmount + "_" + context.isRecurring;
14592
14593 if (_cache[cacheKey]) {
14594 setTimeout(function () {
14595 promise.resolve(_cache[cacheKey]);
14596 }, 0);
14597 } else {
14598 Net.get(formatUrl(_c2SCommunicatorConfiguration.clientApiUrl) + _c2SCommunicatorConfiguration.customerId
14599 + "/products/" + paymentProductId + "/networks" + "?countryCode=" + context.countryCode + "¤cyCode=" + context.currency
14600 + "&amount=" + context.totalAmount + "&isRecurring=" + context.isRecurring)
14601 .set('X-GCS-ClientMetaInfo', _util.base64Encode(metadata))
14602 .set('Authorization', 'GCS v1Client:' + _c2SCommunicatorConfiguration.clientSessionId)
14603 .end(function (res) {
14604 if (res.success) {
14605 _cache[cacheKey] = res.responseJSON;
14606 promise.resolve(res.responseJSON);
14607 } else {
14608 promise.reject();
14609 }
14610 });
14611 }
14612 return promise;
14613 };
14614
14615 this.getPaymentProductDirectory = function (paymentProductId, currencyCode, countryCode) {
14616 var promise = new Promise()
14617 , cacheKey = "getPaymentProductDirectory-" + paymentProductId + "_" + currencyCode + "_" + countryCode;
14618
14619 if (_cache[cacheKey]) {
14620 setTimeout(function () {
14621 promise.resolve(_cache[cacheKey]);
14622 }, 0);
14623 } else {
14624 Net.get(formatUrl(_c2SCommunicatorConfiguration.clientApiUrl) + _c2SCommunicatorConfiguration.customerId + "/products/" + paymentProductId + "/directory?countryCode=" + countryCode + "¤cyCode=" + currencyCode)
14625 .set("X-GCS-ClientMetaInfo", _util.base64Encode(metadata))
14626 .set('Authorization', 'GCS v1Client:' + _c2SCommunicatorConfiguration.clientSessionId)
14627 .end(function (res) {
14628 if (res.success) {
14629 _cache[cacheKey] = res.responseJSON;
14630 promise.resolve(res.responseJSON);
14631 } else {
14632 promise.reject("unable to retrieve payment product directory");
14633 }
14634 });
14635 }
14636 return promise;
14637 };
14638
14639 this.convertAmount = function (amount, source, target) {
14640 var promise = new Promise()
14641 , cacheKey = "convertAmount-" + amount + "_" + source + "_" + target;
14642
14643 if (_cache[cacheKey]) {
14644 setTimeout(function () {
14645 promise.resolve(_cache[cacheKey]);
14646 }, 0);
14647 } else {
14648 Net.get(formatUrl(_c2SCommunicatorConfiguration.clientApiUrl) + _c2SCommunicatorConfiguration.customerId + "/services/convert/amount?source=" + source + "&target=" + target + "&amount=" + amount)
14649 .set("X-GCS-ClientMetaInfo", _util.base64Encode(metadata))
14650 .set('Authorization', 'GCS v1Client:' + _c2SCommunicatorConfiguration.clientSessionId)
14651 .end(function (res) {
14652 if (res.success) {
14653 _cache[cacheKey] = res.responseJSON;
14654 promise.resolve(res.responseJSON);
14655 } else {
14656 promise.reject("unable to convert amount");
14657 }
14658 });
14659 }
14660 return promise;
14661 };
14662
14663 this.getThirdPartyPaymentStatus = function (paymentId) {
14664 var promise = new Promise();
14665
14666 Net.get(formatUrl(_c2SCommunicatorConfiguration.clientApiUrl) + _c2SCommunicatorConfiguration.customerId + "/payments/" + paymentId + "/thirdpartystatus")
14667 .set("X-GCS-ClientMetaInfo", _util.base64Encode(metadata))
14668 .set('Authorization', 'GCS v1Client:' + _c2SCommunicatorConfiguration.clientSessionId)
14669 .end(function (res) {
14670 if (res.success) {
14671 promise.resolve(res.responseJSON);
14672 } else {
14673 promise.reject("unable to retrieve third party status");
14674 }
14675 });
14676 return promise;
14677 };
14678
14679 this.getCustomerDetails = function(paymentProductId, context) {
14680
14681 var promise = new Promise();
14682 var cacheKey = "getCustomerDetails_" + context.countryCode;
14683 cacheKey = constructCacheKeyFromKeyValues(cacheKey, context.values);
14684 if (_cache[cacheKey]) {
14685 setTimeout(function () {
14686 promise.resolve(_cache[cacheKey]);
14687 }, 0);
14688 } else {
14689 Net.post(formatUrl(_c2SCommunicatorConfiguration.clientApiUrl) + _c2SCommunicatorConfiguration.customerId + "/products/" + paymentProductId + "/customerDetails")
14690 .data(JSON.stringify(context))
14691 .set("X-GCS-ClientMetaInfo", _util.base64Encode(metadata))
14692 .set('Authorization', 'GCS v1Client:' + _c2SCommunicatorConfiguration.clientSessionId)
14693 .end(function (res) {
14694 if (res.success) {
14695 _cache[cacheKey] = res.responseJSON;
14696 promise.resolve(res.responseJSON);
14697 } else {
14698 promise.reject(res.responseJSON);
14699 }
14700 });
14701 }
14702 return promise;
14703 };
14704
14705 var constructCacheKeyFromKeyValues = function(prefix, values) {
14706 var cacheKey = prefix;
14707 for (var key in values){
14708 if (values.hasOwnProperty(key)) {
14709 cacheKey += "_" + values[key].key + "_" + values[key].value;
14710 }
14711 }
14712 return cacheKey;
14713 };
14714
14715 /* Transforms the JSON representation of a payment product (group) so it matches the result of getPaymentProduct and getPaymentProductGroup. */
14716 this.transformPaymentProductJSON = function (json) {
14717 return _cleanJSON(json, _c2SCommunicatorConfiguration.assetUrl)
14718 };
14719 };
14720
14721 connectsdk.C2SCommunicator = C2SCommunicator;
14722 return C2SCommunicator;
14723});
14724
14725define("connectsdk.LabelTemplateElement", ["connectsdk.core"], function(connectsdk) {
14726
14727 var LabelTemplateElement = function (json) {
14728 this.json = json;
14729 this.attributeKey = json.attributeKey;
14730 this.mask = json.mask;
14731 this.wildcardMask = json.mask ? json.mask.replace(/9/g, "*") : "";
14732 };
14733
14734 connectsdk.LabelTemplateElement = LabelTemplateElement;
14735 return LabelTemplateElement;
14736});
14737define("connectsdk.Attribute", ["connectsdk.core"], function(connectsdk) {
14738
14739 var Attribute = function (json) {
14740 this.json = json;
14741 this.key = json.key;
14742 this.value = json.value;
14743 this.status = json.status;
14744 this.mustWriteReason = json.mustWriteReason;
14745 };
14746
14747 connectsdk.Attribute = Attribute;
14748 return Attribute;
14749});
14750define("connectsdk.AccountOnFileDisplayHints", ["connectsdk.core", "connectsdk.LabelTemplateElement"], function(connectsdk, LabelTemplateElement) {
14751
14752 var _parseJSON = function (_json, _labelTemplate, _labelTemplateElementByAttributeKey) {
14753 if (_json.labelTemplate) {
14754 for (var i = 0, l = _json.labelTemplate.length; i < l; i++) {
14755 var labelTemplateElement = new LabelTemplateElement(_json.labelTemplate[i]);
14756 _labelTemplate.push(labelTemplateElement);
14757 _labelTemplateElementByAttributeKey[labelTemplateElement.attributeKey] = labelTemplateElement;
14758 }
14759 }
14760 };
14761
14762 var AccountOnFileDisplayHints = function (json) {
14763 this.json = json;
14764 this.labelTemplate = [];
14765 this.labelTemplateElementByAttributeKey = {};
14766
14767 _parseJSON(json, this.labelTemplate, this.labelTemplateElementByAttributeKey);
14768 };
14769
14770 connectsdk.AccountOnFileDisplayHints = AccountOnFileDisplayHints;
14771 return AccountOnFileDisplayHints;
14772});
14773define("connectsdk.AccountOnFile", ["connectsdk.core" ,"connectsdk.AccountOnFileDisplayHints", "connectsdk.Attribute"], function(connectsdk, AccountOnFileDisplayHints, Attribute) {
14774
14775 var _parseJSON = function (_json, _attributes, _attributeByKey) {
14776 if (_json.attributes) {
14777 for (var i = 0, l = _json.attributes.length; i < l; i++) {
14778 var attribute = new Attribute(_json.attributes[i]);
14779 _attributes.push(attribute);
14780 _attributeByKey[attribute.key] = attribute;
14781 }
14782 }
14783 };
14784
14785 var AccountOnFile = function (json) {
14786 var that = this;
14787 this.json = json;
14788 this.attributes = [];
14789 this.attributeByKey = {};
14790 this.displayHints = new AccountOnFileDisplayHints(json.displayHints);
14791 this.id = json.id;
14792 this.paymentProductId = json.paymentProductId;
14793
14794 this.getMaskedValueByAttributeKey = function(attributeKey) {
14795 var value = this.attributeByKey[attributeKey].value;
14796 var wildcardMask;
14797 try {
14798 wildcardMask = this.displayHints.labelTemplateElementByAttributeKey[attributeKey].wildcardMask;
14799 } catch (e) {}
14800 if (value !== undefined && wildcardMask !== undefined) {
14801 var maskingUtil = new connectsdk.MaskingUtil();
14802 return maskingUtil.applyMask(wildcardMask, value);
14803 }
14804 return undefined;
14805 };
14806
14807 _parseJSON(json, this.attributes, this.attributeByKey);
14808 };
14809
14810 connectsdk.AccountOnFile = AccountOnFile;
14811 return AccountOnFile;
14812});
14813define("connectsdk.PaymentProduct302SpecificData", ["connectsdk.core"], function(connectsdk) {
14814
14815 var PaymentProduct302SpecificData = function (json) {
14816 this.json = json;
14817 this.networks = json.networks;
14818 };
14819
14820 connectsdk.PaymentProduct302SpecificData = PaymentProduct302SpecificData;
14821 return PaymentProduct302SpecificData;
14822});
14823define("connectsdk.PaymentProduct320SpecificData", ["connectsdk.core"], function(connectsdk) {
14824
14825 var PaymentProduct320SpecificData = function (json) {
14826 this.json = json;
14827 this.gateway = json.gateway;
14828 this.networks = json.networks;
14829 };
14830
14831 connectsdk.PaymentProduct320SpecificData = PaymentProduct320SpecificData;
14832 return PaymentProduct320SpecificData;
14833});
14834define("connectsdk.PaymentProduct863SpecificData", ["connectsdk.core"], function(connectsdk) {
14835
14836 var PaymentProduct863SpecificData = function (json) {
14837 this.json = json;
14838 this.integrationTypes = json.integrationTypes;
14839 };
14840
14841 connectsdk.PaymentProduct863SpecificData = PaymentProduct863SpecificData;
14842 return PaymentProduct863SpecificData;
14843});
14844define("connectsdk.PaymentProductDisplayHints", ["connectsdk.core"], function(connectsdk) {
14845
14846 var PaymentProductDisplayHints = function (json) {
14847 this.json = json;
14848 this.displayOrder = json.displayOrder;
14849 this.label = json.label;
14850 this.logo = json.logo;
14851 };
14852
14853 connectsdk.PaymentProductDisplayHints = PaymentProductDisplayHints;
14854 return PaymentProductDisplayHints;
14855});
14856define("connectsdk.BasicPaymentProduct", ["connectsdk.core", "connectsdk.AccountOnFile", "connectsdk.PaymentProductDisplayHints", "connectsdk.PaymentProduct302SpecificData", "connectsdk.PaymentProduct320SpecificData", "connectsdk.PaymentProduct863SpecificData"], function(connectsdk, AccountOnFile, PaymentProductDisplayHints, PaymentProduct302SpecificData, PaymentProduct320SpecificData, PaymentProduct863SpecificData) {
14857
14858 var _parseJSON = function (_json, _paymentProduct, _accountsOnFile, _accountOnFileById) {
14859 if (_json.accountsOnFile) {
14860 for (var i = 0, il = _json.accountsOnFile.length; i < il; i++) {
14861 var accountOnFile = new AccountOnFile(_json.accountsOnFile[i]);
14862 _accountsOnFile.push(accountOnFile);
14863 _accountOnFileById[accountOnFile.id] = accountOnFile;
14864 }
14865 }
14866 if (_json.paymentProduct302SpecificData) {
14867 _paymentProduct.paymentProduct302SpecificData = new PaymentProduct302SpecificData(_json.paymentProduct302SpecificData);
14868 }
14869 if (_json.paymentProduct320SpecificData) {
14870 _paymentProduct.paymentProduct320SpecificData = new PaymentProduct320SpecificData(_json.paymentProduct320SpecificData);
14871 }
14872 if (_json.paymentProduct863SpecificData) {
14873 _paymentProduct.paymentProduct863SpecificData = new PaymentProduct863SpecificData(_json.paymentProduct863SpecificData);
14874 }
14875 };
14876
14877 var BasicPaymentProduct = function (json) {
14878 this.json = json;
14879 this.json.type = "product";
14880 this.accountsOnFile = [];
14881 this.accountOnFileById = {};
14882 this.allowsRecurring = json.allowsRecurring;
14883 this.allowsTokenization = json.allowsTokenization;
14884 this.autoTokenized = json.autoTokenized ;
14885 this.displayHints = new PaymentProductDisplayHints(json.displayHints);
14886 this.id = json.id;
14887 this.maxAmount = json.maxAmount;
14888 this.minAmount = json.minAmount;
14889 this.paymentMethod = json.paymentMethod;
14890 this.mobileIntegrationLevel = json.mobileIntegrationLevel;
14891 this.usesRedirectionTo3rdParty = json.usesRedirectionTo3rdParty;
14892 this.paymentProductGroup = json.paymentProductGroup;
14893
14894 _parseJSON(json, this, this.accountsOnFile, this.accountOnFileById);
14895 };
14896
14897 connectsdk.BasicPaymentProduct = BasicPaymentProduct;
14898 return BasicPaymentProduct;
14899});
14900define("connectsdk.BasicPaymentProductGroup", ["connectsdk.core", "connectsdk.AccountOnFile", "connectsdk.PaymentProductDisplayHints"], function(connectsdk, AccountOnFile, PaymentProductDisplayHints) {
14901
14902 var _parseJSON = function (_json, _accountsOnFile, _accountOnFileById) {
14903 if (_json.accountsOnFile) {
14904 for (var i = 0, il = _json.accountsOnFile.length; i < il; i++) {
14905 var accountOnFile = new AccountOnFile(_json.accountsOnFile[i]);
14906 _accountsOnFile.push(accountOnFile);
14907 _accountOnFileById[accountOnFile.id] = accountOnFile;
14908 }
14909 }
14910 };
14911
14912 var BasicPaymentProductGroup = function (json) {
14913 this.json = json;
14914 this.json.type = "group";
14915 this.id = json.id;
14916 this.displayHints = new PaymentProductDisplayHints(json.displayHints);
14917 this.accountsOnFile = [];
14918 this.accountOnFileById = {};
14919 _parseJSON(json, this.accountsOnFile, this.accountOnFileById);
14920 };
14921
14922 connectsdk.BasicPaymentProductGroup = BasicPaymentProductGroup;
14923 return BasicPaymentProductGroup;
14924});
14925define("connectsdk.MaskedString", ["connectsdk.core"], function(connectsdk) {
14926
14927 var MaskedString = function(formattedValue, cursorIndex) {
14928
14929 this.formattedValue = formattedValue;
14930 this.cursorIndex = cursorIndex;
14931 };
14932
14933 connectsdk.MaskedString = MaskedString;
14934 return MaskedString;
14935});
14936define("connectsdk.MaskingUtil", ["connectsdk.core", "connectsdk.MaskedString"], function(connectsdk, MaskedString) {
14937
14938 var _fillBuffer = function(index, offset, buffer, tempMask, valuec) {
14939 if (index+offset < valuec.length && index < tempMask.length) {
14940 if ((tempMask[index] === "9" && Number(valuec[index+offset]) > -1 && valuec[index+offset] !== " ") || tempMask[index] === "*") {
14941 buffer.push(valuec[index+offset]);
14942 } else {
14943 if (valuec[index+offset] === tempMask[index]) {
14944 buffer.push(valuec[index+offset]);
14945 } else if (tempMask[index] !== "9" && tempMask[index] !== "*") {
14946 buffer.push(tempMask[index]);
14947 offset--;
14948 } else {
14949 // offset++;
14950 valuec.splice(index+offset, 1);
14951 index--;
14952 }
14953 }
14954 _fillBuffer(index+1, offset, buffer, tempMask, valuec);
14955 }
14956 };
14957
14958 var MaskingUtil = function () {
14959 this.applyMask = function (mask, newValue, oldValue) {
14960 var buffer = [],
14961 valuec = newValue.split("");
14962 if (mask) {
14963 var maskc = mask.split(""),
14964 tempMask = [];
14965 for (var i = 0, il = maskc.length; i < il; i++) {
14966 // the char '{' and '}' should ALWAYS be ignored
14967 var c = maskc[i];
14968 if (c === "{" || c === "}") {
14969 // ignore
14970 } else {
14971 tempMask.push(c);
14972 }
14973 }
14974 // tempmask now contains the replaceable chars and the non-replaceable masks at the correct index
14975 _fillBuffer(0, 0, buffer, tempMask, valuec);
14976 } else {
14977 // send back as is
14978 for (var i = 0, il = valuec.length; i < il; i++) {
14979 var c = valuec[i];
14980 buffer.push(c);
14981 }
14982 }
14983 newValue = buffer.join("");
14984 var cursor = 1;
14985 // calculate the cursor index
14986 if (oldValue) {
14987 var tester = oldValue.split("");
14988 for (var i = 0, il = buffer.length; i < il; i++) {
14989 if (buffer[i] !== tester[i]) {
14990 cursor = i+1;
14991 break;
14992 }
14993 }
14994 }
14995 if (newValue.substring(0, newValue.length -1) === oldValue) {
14996 cursor = newValue.length + 1;
14997 }
14998 return new MaskedString(newValue, cursor);
14999 };
15000
15001 this.getMaxLengthBasedOnMask = function (mask) {
15002 if (mask) {
15003 var maskc = mask.split(""),
15004 newLength = -1;
15005 for (var i = 0, il = maskc.length; i < il; i++) {
15006 newLength++;
15007 var c = maskc[i];
15008 if (c === "{" || c === "}") {
15009 newLength--;
15010 }
15011 }
15012 return newLength;
15013 }
15014 };
15015
15016 this.removeMask = function (mask, value) {
15017 // remove the mask from the masked input
15018 var buffer = [],
15019 valuec = (value) ? value.split("") : [];
15020 if (mask) {
15021 var maskc = mask.split(""),
15022 valueIndex = -1,
15023 inMask = false;
15024 for (var i = 0, il = maskc.length; i < il; i++) {
15025 valueIndex++;
15026 // the char '{' and '}' should ALWAYS be ignored
15027 var c = maskc[i];
15028 if (c === "{" || c === "}") {
15029 valueIndex--;
15030 if (c === "{") {
15031 inMask = true;
15032 } else if (c === "}") {
15033 inMask = false;
15034 }
15035 } else {
15036 if (inMask && valuec[valueIndex]) {
15037 buffer.push(valuec[valueIndex]);
15038 }
15039 }
15040 }
15041 } else {
15042 // send back as is
15043 for (var i = 0, il = valuec.length; i < il; i++) {
15044 var c = valuec[i];
15045 buffer.push(c);
15046 }
15047 }
15048 return buffer.join("").trim();
15049 };
15050 };
15051
15052 connectsdk.MaskingUtil = MaskingUtil;
15053 return MaskingUtil;
15054});
15055define("connectsdk.ValidationRuleLuhn", ["connectsdk.core"], function(connectsdk) {
15056
15057 var ValidationRuleLuhn = function (json) {
15058 this.json = json;
15059 this.type = json.type,
15060 this.errorMessageId = json.type;
15061 this.validate = function (value) {
15062 var luhnArr = [[0,2,4,6,8,1,3,5,7,9],[0,1,2,3,4,5,6,7,8,9]]
15063 ,sum = 0;
15064
15065 value.replace(/\D+/g,"").replace(/[\d]/g, function(c, p, o) {
15066 sum += luhnArr[ (o.length-p)&1 ][ parseInt(c,10) ];
15067 });
15068 return (sum%10 === 0) && (sum > 0);
15069 };
15070 };
15071
15072 connectsdk.ValidationRuleLuhn = ValidationRuleLuhn;
15073 return ValidationRuleLuhn;
15074});
15075define("connectsdk.ValidationRuleExpirationDate", ["connectsdk.core"], function (connectsdk) {
15076
15077 var _validateDateFormat = function (value) {
15078 // value is mmYY or mmYYYY
15079 var pattern = /\d{4}|\d{6}$/g;
15080 return pattern.test(value);
15081 };
15082
15083 var ValidationRuleExpirationDate = function (json) {
15084 this.json = json;
15085 this.type = json.type;
15086 this.errorMessageId = json.type;
15087
15088 this.validate = function (value) {
15089
15090 value = value.replace(/[^\d]/g, '');
15091 if (!_validateDateFormat(value)) {
15092 return false;
15093 }
15094
15095 var split;
15096 if (value.length === 4) {
15097 split = [value.substring(0, 2), "20" + value.substring(2, 4)];
15098 } else if (value.length === 6) {
15099 split = [value.substring(0, 2), value.substring(2, 6)];
15100 } else {
15101 return false;
15102 }
15103
15104 // The month is zero-based, so subtract one.
15105 var expirationMonth = split[0] - 1;
15106 var expirationYear = split[1];
15107 var expirationDate = new Date(expirationYear, expirationMonth, 1);
15108
15109 // Compare the input with the parsed date, to check if the date rolled over.
15110 if (expirationDate.getMonth() !== Number(expirationMonth) || expirationDate.getFullYear() !== Number(expirationYear)) {
15111 return false;
15112 }
15113
15114 // For comparison, set the current year & month and the maximum allowed expiration date.
15115 var nowWithDay = new Date();
15116 var now = new Date(nowWithDay.getFullYear(), nowWithDay.getMonth(), 1);
15117 var maxExpirationDate = new Date(nowWithDay.getFullYear() + 25, 11, 1);
15118
15119 // The card is still valid if it expires this month.
15120 return expirationDate >= now && expirationDate <= maxExpirationDate;
15121 };
15122 };
15123
15124 connectsdk.ValidationRuleExpirationDate = ValidationRuleExpirationDate;
15125 return ValidationRuleExpirationDate;
15126});
15127
15128define("connectsdk.ValidationRuleFixedList", ["connectsdk.core"], function(connectsdk) {
15129
15130 var ValidationRuleFixedList = function (json) {
15131 this.json = json;
15132 this.type = json.type,
15133 this.errorMessageId = json.type;
15134 this.allowedValues = json.attributes.allowedValues;
15135
15136 this.validate = function (value) {
15137 for (var i = 0, il = this.allowedValues.length; i < il; i++) {
15138 if (this.allowedValues[i] === value) {
15139 return true;
15140 }
15141 }
15142 return false;
15143 };
15144 };
15145
15146 connectsdk.ValidationRuleFixedList = ValidationRuleFixedList;
15147 return ValidationRuleFixedList;
15148});
15149define("connectsdk.ValidationRuleLength", ["connectsdk.core"], function(connectsdk) {
15150
15151 var ValidationRuleLength = function (json) {
15152 this.json = json;
15153 this.type = json.type,
15154 this.errorMessageId = json.type;
15155 this.maxLength = json.attributes.maxLength;
15156 this.minLength = json.attributes.minLength;
15157
15158 this.validate = function (value) {
15159 return this.minLength <= value.length && value.length <= this.maxLength;
15160 };
15161 };
15162
15163 connectsdk.ValidationRuleLength = ValidationRuleLength;
15164 return ValidationRuleLength;
15165});
15166define("connectsdk.ValidationRuleRange", ["connectsdk.core"], function(connectsdk) {
15167
15168 var ValidationRuleRange = function(json) {
15169 this.json = json;
15170 this.type = json.type,
15171 this.errorMessageId = json.type;
15172 this.maxValue = json.attributes.maxValue;
15173 this.minValue = json.attributes.minValue;
15174
15175 this.validate = function(value) {
15176 if (isNaN(value)) {
15177 return false;
15178 }
15179 value = Number(value);
15180 return this.minValue <= value && value <= this.maxValue;
15181 };
15182 };
15183
15184 connectsdk.ValidationRuleRange = ValidationRuleRange;
15185 return ValidationRuleRange;
15186});
15187define("connectsdk.ValidationRuleRegularExpression", ["connectsdk.core"], function(connectsdk) {
15188
15189 var ValidationRuleRegularExpression = function(json) {
15190 this.json = json;
15191 this.type = json.type,
15192 this.errorMessageId = json.type;
15193 this.regularExpression = json.attributes.regularExpression;
15194
15195 this.validate = function(value) {
15196 var regexp = new RegExp(this.regularExpression);
15197 return regexp.test(value);
15198 };
15199 };
15200
15201 connectsdk.ValidationRuleRegularExpression = ValidationRuleRegularExpression;
15202 return ValidationRuleRegularExpression;
15203});
15204define("connectsdk.ValidationRuleEmailAddress", ["connectsdk.core"], function(connectsdk) {
15205
15206 var ValidationRuleEmailAddress = function(json) {
15207 this.json = json;
15208 this.type = json.type,
15209 this.errorMessageId = json.type;
15210
15211 this.validate = function(value) {
15212 var regexp = new RegExp(/^[^@\.]+(\.[^@\.]+)*@([^@\.]+\.)*[^@\.]+\.[^@\.][^@\.]+$/i);
15213 return regexp.test(value);
15214 };
15215 };
15216
15217 connectsdk.ValidationRuleEmailAddress = ValidationRuleEmailAddress;
15218 return ValidationRuleEmailAddress;
15219});
15220define("connectsdk.ValidationRuleTermsAndConditions", ["connectsdk.core"], function(connectsdk) {
15221
15222 var ValidationRuleTermsAndConditions = function(json) {
15223 this.json = json;
15224 this.type = json.type,
15225 this.errorMessageId = json.type;
15226
15227 this.validate = function(value) {
15228 return true === value || "true" === value;
15229 };
15230 };
15231
15232 connectsdk.ValidationRuleTermsAndConditions = ValidationRuleTermsAndConditions;
15233 return ValidationRuleTermsAndConditions;
15234});
15235define("connectsdk.ValidationRuleBoletoBancarioRequiredness", ["connectsdk.core"], function(connectsdk) {
15236
15237 var ValidationRuleBoletoBancarioRequiredness = function (json) {
15238 this.json = json;
15239 this.type = json.type,
15240 this.errorMessageId = json.type;
15241 this.fiscalNumberLength = json.attributes.fiscalNumberLength;
15242
15243 this.validate = function (value, fiscalNumberValue) {
15244 if (typeof fiscalNumberValue === 'undefined') {
15245 fiscalNumberValue = '';
15246 }
15247
15248 return (fiscalNumberValue.length === this.fiscalNumberLength && value.length > 0) || fiscalNumberValue.length !== this.fiscalNumberLength;
15249 };
15250 };
15251
15252 connectsdk.ValidationRuleBoletoBancarioRequiredness = ValidationRuleBoletoBancarioRequiredness;
15253 return ValidationRuleBoletoBancarioRequiredness;
15254});
15255define('connectsdk.ValidationRuleIban', ['connectsdk.core'], function (connectsdk) {
15256
15257 /**
15258 * Sanitize value by remove all unwanted chars of a Iban format
15259 *
15260 * @param {String} value
15261 * @returns {string}
15262 * @private
15263 */
15264 var _sanitizeValue = function (value) {
15265 return value.replace(/[^\d\w]+/g, '').toUpperCase();
15266 };
15267
15268 /**
15269 * Get state if given value is a valid Iban format
15270 *
15271 * @param {String} value
15272 * @returns {boolean}
15273 * @private
15274 */
15275 var _isValidFormat = function (value) {
15276 return typeof value === 'string' && /^[A-Z]{2}[0-9]{2}[A-Z0-9]{4}[0-9]{7}([A-Z0-9]?){0,16}$/.test(_sanitizeValue(value));
15277 };
15278
15279 /**
15280 * Convert a value to a string needed for validation calculations
15281 *
15282 * @param {String} value
15283 * @returns {string}
15284 * @private
15285 */
15286 var _toComputedString = function (value) {
15287 return _sanitizeValue(value)
15288
15289 // place the first 4 chars to the end
15290 .replace(/(^.{4})(.*)/, '$2$1')
15291
15292 // replace letters by corresponding numbers A=10 / Z=35
15293 .replace(/[A-Z]/g, function (d) {
15294 return d.charCodeAt(0) - 55;
15295 });
15296 }
15297
15298 /**
15299 * Validate Iban by given json
15300 *
15301 * @param {Object} json
15302 * @constructor
15303 */
15304 var ValidationRuleIban = function (json) {
15305 this.json = json;
15306 this.type = json.type;
15307 this.errorMessageId = json.type;
15308
15309 /**
15310 * Validate Iban nrule
15311 *
15312 * @see https://github.com/arhs/iban.js/blob/master/iban.js
15313 *
15314 * @param {string} value
15315 * @returns {boolean}
15316 */
15317 this.validate = function (value) {
15318
15319 // bail if format is invalid
15320 if (!_isValidFormat(value)) {
15321 return false;
15322 }
15323
15324 // Check if reminder module 97 equals 1
15325 // only then it should pass the validation
15326 var remainder = _toComputedString(value),
15327 block;
15328
15329 while (remainder.length > 2) {
15330 block = remainder.slice(0, 9);
15331 remainder = parseInt(block, 10) % 97 + remainder.slice(block.length);
15332 }
15333
15334 return (parseInt(remainder, 10) % 97) === 1;
15335 };
15336 };
15337
15338 connectsdk.ValidationRuleIban = ValidationRuleIban;
15339 return ValidationRuleIban;
15340});
15341define("connectsdk.ValidationRuleFactory", ["connectsdk.core", "connectsdk.ValidationRuleEmailAddress", "connectsdk.ValidationRuleTermsAndConditions", "connectsdk.ValidationRuleExpirationDate", "connectsdk.ValidationRuleFixedList", "connectsdk.ValidationRuleLength", "connectsdk.ValidationRuleLuhn", "connectsdk.ValidationRuleRange", "connectsdk.ValidationRuleRegularExpression", "connectsdk.ValidationRuleBoletoBancarioRequiredness", "connectsdk.ValidationRuleIban"], function (connectsdk, ValidationRuleEmailAddress, ValidationRuleTermsAndConditions, ValidationRuleExpirationDate, ValidationRuleFixedList, ValidationRuleLength, ValidationRuleLuhn, ValidationRuleRange, ValidationRuleRegularExpression, ValidationRuleBoletoBancarioRequiredness, ValidationRuleIban) {
15342
15343 var ValidationRuleFactory = function () {
15344
15345 this.makeValidator = function (json) {
15346 // create new class based on the rule
15347 try {
15348 var classType = json.type.charAt(0).toUpperCase() + json.type.slice(1), // camel casing
15349 className = eval("ValidationRule" + classType);
15350 return new className(json);
15351 } catch (e) {
15352 console.warn('no validator for ', classType);
15353 }
15354 return null;
15355 };
15356 };
15357
15358 connectsdk.ValidationRuleFactory = ValidationRuleFactory;
15359 return ValidationRuleFactory;
15360});
15361define("connectsdk.DataRestrictions", ["connectsdk.core", "connectsdk.ValidationRuleExpirationDate", "connectsdk.ValidationRuleFixedList", "connectsdk.ValidationRuleLength", "connectsdk.ValidationRuleLuhn", "connectsdk.ValidationRuleRange", "connectsdk.ValidationRuleRegularExpression", "connectsdk.ValidationRuleEmailAddress", "connectsdk.ValidationRuleTermsAndConditions", "connectsdk.ValidationRuleIban", "connectsdk.ValidationRuleFactory"], function(connectsdk, ValidationRuleExpirationDate, ValidationRuleFixedList, ValidationRuleLength, ValidationRuleLuhn, ValidationRuleRange, ValidationRuleRegularExpression, ValidationRuleEmailAddress, ValidationRuleTermsAndConditions, ValidationRuleIban, ValidationRuleFactory) {
15362
15363 var DataRestrictions = function (json, mask) {
15364
15365 var _parseJSON = function (_json, _validationRules, _validationRuleByType) {
15366 var validationRuleFactory = new ValidationRuleFactory();
15367 if (_json.validators) {
15368 for (var key in _json.validators) {
15369 var validationRule = validationRuleFactory.makeValidator({type: key, attributes: _json.validators[key]});
15370 if (validationRule) {
15371 _validationRules.push(validationRule);
15372 _validationRuleByType[validationRule.type] = validationRule;
15373 }
15374 }
15375 }
15376 };
15377
15378 this.json = json;
15379 this.isRequired = json.isRequired;
15380 this.validationRules = [];
15381 this.validationRuleByType = {};
15382
15383 _parseJSON(json, this.validationRules, this.validationRuleByType);
15384 };
15385
15386 connectsdk.DataRestrictions = DataRestrictions;
15387 return DataRestrictions;
15388});
15389define("connectsdk.ValueMappingElement", ["connectsdk.core"], function(connectsdk) {
15390
15391 var ValueMappingElement = function (json) {
15392 this.json = json;
15393 this.displayName = json.displayName;
15394 this.value = json.value;
15395 };
15396
15397 connectsdk.ValueMappingElement = ValueMappingElement;
15398 return ValueMappingElement;
15399});
15400define("connectsdk.FormElement", ["connectsdk.core", "connectsdk.ValueMappingElement"], function(connectsdk, ValueMappingElement) {
15401
15402 var FormElement = function (json) {
15403
15404 var _parseJSON = function (_json, _valueMapping) {
15405 if (_json.valueMapping) {
15406 for (var i = 0, l = _json.valueMapping.length; i < l; i++) {
15407 _valueMapping.push(new ValueMappingElement(_json.valueMapping[i]));
15408 }
15409 }
15410 };
15411
15412 this.json = json;
15413 this.type = json.type;
15414 this.valueMapping = [];
15415
15416 _parseJSON(json, this.valueMapping);
15417 };
15418
15419 connectsdk.FormElement = FormElement;
15420 return FormElement;
15421});
15422define("connectsdk.Tooltip", ["connectsdk.core"], function(connectsdk) {
15423
15424 var Tooltip = function (json) {
15425 this.json = json;
15426 this.image = json.image;
15427 this.label = json.label;
15428 };
15429
15430 connectsdk.Tooltip = Tooltip;
15431 return Tooltip;
15432});
15433define("connectsdk.PaymentProductFieldDisplayHints", ["connectsdk.core", "connectsdk.Tooltip", "connectsdk.FormElement"], function(connectsdk, Tooltip, FormElement) {
15434
15435 var PaymentProductFieldDisplayHints = function (json) {
15436 this.json = json;
15437 this.displayOrder = json.displayOrder;
15438 if (json.formElement) {
15439 this.formElement = new FormElement(json.formElement);
15440 }
15441 this.label = json.label;
15442 this.mask = json.mask;
15443 this.obfuscate = json.obfuscate;
15444 this.placeholderLabel = json.placeholderLabel;
15445 this.preferredInputType = json.preferredInputType;
15446 this.tooltip = json.tooltip? new Tooltip(json.tooltip): undefined;
15447 this.alwaysShow = json.alwaysShow;
15448 this.wildcardMask = json.mask ? json.mask.replace(/9/g, "*") : "";
15449 };
15450
15451 connectsdk.PaymentProductFieldDisplayHints = PaymentProductFieldDisplayHints;
15452 return PaymentProductFieldDisplayHints;
15453});
15454define("connectsdk.PaymentProductField", ["connectsdk.core", "connectsdk.PaymentProductFieldDisplayHints", "connectsdk.DataRestrictions", "connectsdk.MaskingUtil"], function(connectsdk, PaymentProductFieldDisplayHints, DataRestrictions, MaskingUtil) {
15455 var PaymentProductField = function (json) {
15456 this.json = json;
15457 this.displayHints = json.displayHints ? new PaymentProductFieldDisplayHints(json.displayHints) : '';
15458 this.dataRestrictions = new DataRestrictions(json.dataRestrictions, this.displayHints ? this.displayHints.mask : '');
15459 this.id = json.id;
15460 this.type = json.type;
15461 var _errorCodes = [];
15462
15463 this.getErrorCodes = function (value) {
15464 if (value) {
15465 _errorCodes = [];
15466 this.isValid(value);
15467 }
15468 return _errorCodes;
15469 };
15470 this.isValid = function (value) {
15471 // isValid checks all datarestrictions
15472 var validators = this.dataRestrictions.validationRules;
15473 var hasError = false;
15474
15475 // Apply masking value first
15476 var maskedValue = this.applyMask(value);
15477 value = this.removeMask(maskedValue.formattedValue);
15478 for (var i = 0, il = validators.length; i < il; i++) {
15479 var validator = validators[i];
15480 if (!validator.validate(value)) {
15481 hasError = true;
15482 _errorCodes.push(validator.errorMessageId);
15483 }
15484 }
15485 return !hasError;
15486 };
15487 this.applyMask = function (newValue, oldValue) {
15488 var maskingUtil = new MaskingUtil();
15489 return maskingUtil.applyMask(this.displayHints.mask, newValue, oldValue);
15490 };
15491 this.applyWildcardMask = function (newValue, oldValue) {
15492 var maskingUtil = new MaskingUtil();
15493 return maskingUtil.applyMask(this.displayHints.wildcardMask, newValue, oldValue);
15494 };
15495 this.removeMask = function (value) {
15496 var maskingUtil = new MaskingUtil();
15497 return maskingUtil.removeMask(this.displayHints.mask, value);
15498 };
15499 };
15500
15501 connectsdk.PaymentProductField = PaymentProductField;
15502 return PaymentProductField;
15503});
15504define("connectsdk.PaymentProduct", ["connectsdk.core", "connectsdk.BasicPaymentProduct", "connectsdk.PaymentProductField"], function(connectsdk, BasicPaymentProduct, PaymentProductField) {
15505
15506 var _parseJSON = function (_json, _paymentProductFields, _paymentProductFieldById) {
15507 if (_json.fields) {
15508 for (var i = 0, il = _json.fields.length; i < il; i++) {
15509 var paymentProductField = new PaymentProductField(_json.fields[i]);
15510 _paymentProductFields.push(paymentProductField);
15511 _paymentProductFieldById[paymentProductField.id] = paymentProductField;
15512 }
15513 }
15514 };
15515
15516 var PaymentProduct = function (json) {
15517 var basicPaymentProduct = new BasicPaymentProduct(json);
15518 basicPaymentProduct.paymentProductFields = [];
15519 basicPaymentProduct.paymentProductFieldById = {};
15520
15521 _parseJSON(basicPaymentProduct.json, basicPaymentProduct.paymentProductFields, basicPaymentProduct.paymentProductFieldById);
15522
15523 return basicPaymentProduct;
15524 };
15525
15526 connectsdk.PaymentProduct = PaymentProduct;
15527 return PaymentProduct;
15528});
15529
15530define("connectsdk.PaymentProductGroup", ["connectsdk.core", "connectsdk.BasicPaymentProduct", "connectsdk.PaymentProductField"], function(connectsdk, BasicPaymentProduct, PaymentProductField) {
15531
15532 var _parseJSON = function (_json, _paymentProductFields, _paymentProductFieldById) {
15533 if (_json.fields) {
15534 for (var i = 0, il = _json.fields.length; i < il; i++) {
15535 var paymentProductField = new PaymentProductField(_json.fields[i]);
15536 _paymentProductFields.push(paymentProductField);
15537 _paymentProductFieldById[paymentProductField.id] = paymentProductField;
15538 }
15539 }
15540 };
15541
15542 var PaymentProductGroup = function (json) {
15543 var basicPaymentProduct = new BasicPaymentProduct(json);
15544 basicPaymentProduct.json = json;
15545 basicPaymentProduct.json.type = "group";
15546 basicPaymentProduct.paymentProductFields = [];
15547 basicPaymentProduct.paymentProductFieldById = {};
15548
15549 _parseJSON(basicPaymentProduct.json, basicPaymentProduct.paymentProductFields, basicPaymentProduct.paymentProductFieldById);
15550
15551 return basicPaymentProduct;
15552 };
15553
15554 connectsdk.PaymentProductGroup = PaymentProductGroup;
15555 return PaymentProductGroup;
15556});
15557define("connectsdk.BasicPaymentProducts", ["connectsdk.core", "connectsdk.BasicPaymentProduct"], function(connectsdk, BasicPaymentProduct) {
15558
15559 var _parseJson = function (_json, _paymentProducts, _accountsOnFile, _paymentProductById, _accountOnFileById, _paymentProductByAccountOnFileId) {
15560 if (_json.paymentProducts) {
15561 for (var i = 0, il = _json.paymentProducts.length; i < il; i++) {
15562 var paymentProduct = new BasicPaymentProduct(_json.paymentProducts[i]);
15563 _paymentProducts.push(paymentProduct);
15564 _paymentProductById[paymentProduct.id] = paymentProduct;
15565
15566 if (paymentProduct.accountsOnFile) {
15567 var aofs = paymentProduct.accountsOnFile;
15568 for (var j = 0, jl = aofs.length; j < jl; j++) {
15569 var aof = aofs[j];
15570 _accountsOnFile.push(aof);
15571 _accountOnFileById[aof.id] = aof;
15572 _paymentProductByAccountOnFileId[aof.id] = paymentProduct;
15573 }
15574 }
15575 }
15576 }
15577 };
15578
15579 var BasicPaymentProducts = function (json) {
15580 this.basicPaymentProducts = [];
15581 this.basicPaymentProductById = {};
15582 this.basicPaymentProductByAccountOnFileId = {};
15583 this.accountsOnFile = [];
15584 this.accountOnFileById = {};
15585 this.json = json;
15586
15587 _parseJson(json, this.basicPaymentProducts, this.accountsOnFile, this.basicPaymentProductById, this.accountOnFileById, this.basicPaymentProductByAccountOnFileId);
15588 };
15589
15590 connectsdk.BasicPaymentProducts = BasicPaymentProducts;
15591 return BasicPaymentProducts;
15592});
15593define("connectsdk.BasicPaymentProductGroups", ["connectsdk.core", "connectsdk.BasicPaymentProductGroup"], function(connectsdk, BasicPaymentProductGroup) {
15594
15595 var _parseJson = function (_json, _paymentProductGroups, _accountsOnFile, _paymentProductGroupById, _accountOnFileById) {
15596 if (_json.paymentProductGroups) {
15597 for (var i = 0, il = _json.paymentProductGroups.length; i < il; i++) {
15598 var paymentProductGroup = new BasicPaymentProductGroup(_json.paymentProductGroups[i]);
15599 _paymentProductGroups.push(paymentProductGroup);
15600 _paymentProductGroupById[paymentProductGroup.id] = paymentProductGroup;
15601
15602 if (paymentProductGroup.accountsOnFile) {
15603 var aofs = paymentProductGroup.accountsOnFile;
15604 for (var j = 0, jl = aofs.length; j < jl; j++) {
15605 var aof = aofs[j];
15606 _accountsOnFile.push(aof);
15607 _accountOnFileById[aof.id] = aof;
15608 }
15609 }
15610 }
15611 }
15612 };
15613
15614 var BasicPaymentProductGroups = function (json) {
15615 this.basicPaymentProductGroups = [];
15616 this.basicPaymentProductGroupById = {};
15617 this.accountsOnFile = [];
15618 this.accountOnFileById = {};
15619 this.json = json;
15620
15621 _parseJson(json, this.basicPaymentProductGroups, this.accountsOnFile, this.basicPaymentProductGroupById, this.accountOnFileById);
15622 };
15623
15624 connectsdk.BasicPaymentProductGroups = BasicPaymentProductGroups;
15625 return BasicPaymentProductGroups;
15626});
15627define("connectsdk.BasicPaymentItems", ["connectsdk.core"], function(connectsdk) {
15628 "use strict";
15629
15630 var _parseJson = function (_products, _groups, _basicPaymentItems) {
15631 var doRemove = [];
15632 if (_groups) {
15633 for (var i = 0, il = _groups.basicPaymentProductGroups.length; i < il; i++) {
15634 var groupId = _groups.basicPaymentProductGroups[i].id,
15635 groupReplaced = false;
15636 for (var j = 0, jl = _products.basicPaymentProducts.length; j < jl; j++) {
15637 var productMethod = _products.basicPaymentProducts[j].paymentProductGroup;
15638 if (productMethod === groupId && groupReplaced === false) {
15639 // replace instance by group
15640 _products.basicPaymentProducts.splice(j, 1, _groups.basicPaymentProductGroups[i]);
15641 groupReplaced = true;
15642 } else if (productMethod === groupId && groupReplaced === true) {
15643 // mark for removal
15644 doRemove.push(j);
15645 }
15646 }
15647 }
15648 for (var i = doRemove.length -1, il = 0; i >= il; i--) {
15649 _products.basicPaymentProducts.splice(doRemove[i], 1);
15650 }
15651 }
15652 _basicPaymentItems.basicPaymentItems = JSON.parse(JSON.stringify(_products.basicPaymentProducts));
15653 for (var i = 0, il = _basicPaymentItems.basicPaymentItems.length; i < il; i++) {
15654 var basicPaymentItem = _basicPaymentItems.basicPaymentItems[i];
15655 _basicPaymentItems.basicPaymentItemById[basicPaymentItem.id] = basicPaymentItem;
15656 if (basicPaymentItem.accountsOnFile) {
15657 var aofs = basicPaymentItem.accountsOnFile;
15658 for (var j = 0, jl = aofs.length; j < jl; j++) {
15659 var aof = aofs[j];
15660 _basicPaymentItems.accountsOnFile.push(aof);
15661 _basicPaymentItems.accountOnFileById[aof.id] = aof;
15662 }
15663 }
15664 };
15665 };
15666
15667 var BasicPaymentItems = function (products, groups) {
15668 this.basicPaymentItems = [];
15669 this.basicPaymentItemById = {};
15670 this.accountsOnFile = [];
15671 this.accountOnFileById = {};
15672 _parseJson(products, groups, this);
15673 };
15674 connectsdk.BasicPaymentItems = BasicPaymentItems;
15675 return BasicPaymentItems;
15676});
15677define("connectsdk.PaymentRequest", ["connectsdk.core"], function(connectsdk) {
15678 var PaymentRequest = function(clientSessionID) {
15679 var _clientSessionID = clientSessionID;
15680 var _fieldValues = {};
15681 var _paymentProduct = null;
15682 var _accountOnFile = null;
15683 var _tokenize = false;
15684
15685 this.isValid = function() {
15686 var errors = this.getErrorMessageIds();
15687 // besides checking the fields for errors check if all mandatory fields are present as well
15688 var paymentProduct = this.getPaymentProduct();
15689 if (!paymentProduct) {
15690 return false;
15691 }
15692 var allRequiredFieldsPresent = true;
15693 for (var i = 0; i < paymentProduct.paymentProductFields.length; i++) {
15694 var field = paymentProduct.paymentProductFields[i];
15695 if (field.dataRestrictions.isRequired) {
15696 // is this field present in the request?
15697 var storedValue = this.getValue(field.id);
15698 if (!storedValue && !this.getAccountOnFile()) {
15699 // if we have an acoount on file the account on file could have the field, so we can ignore it
15700 allRequiredFieldsPresent = false;
15701 }
15702 }
15703 }
15704 return errors.length === 0 && allRequiredFieldsPresent;
15705 };
15706 this.setValue = function(paymentProductFieldId, value) {
15707 _fieldValues[paymentProductFieldId] = value;
15708 };
15709 this.setTokenize = function(tokenize) {
15710 _tokenize = tokenize;
15711 };
15712 this.getTokenize = function() {
15713 return _tokenize;
15714 };
15715 this.getErrorMessageIds = function() {
15716 var errors = [];
15717 for (key in _fieldValues) {
15718 var paymentProductField = _paymentProduct.paymentProductFieldById[key];
15719 if (paymentProductField) {
15720 errors = errors.concat(paymentProductField.getErrorCodes(_fieldValues[key]));
15721 }
15722 }
15723 return errors;
15724 };
15725 this.getValue = function(paymentProductFieldId) {
15726 return _fieldValues[paymentProductFieldId];
15727 };
15728 this.getValues = function() {
15729 return _fieldValues;
15730 };
15731 this.getMaskedValue = function(paymentProductFieldId) {
15732 var paymentProductField = _paymentProduct.paymentProductFieldById[paymentProductFieldId];
15733 var maskedString = paymentProductField.applyMask(this.getValue(paymentProductFieldId));
15734 return maskedString.formattedValue();
15735 };
15736 this.getMaskedValues = function() {
15737 var fields = _fieldValues;
15738 var result = [];
15739 for (var paymentProductFieldId in fields) {
15740 var paymentProductField = _paymentProduct.paymentProductFieldById[paymentProductFieldId];
15741 var maskedString = paymentProductField.applyMask(this.getValue(paymentProductFieldId));
15742 result[paymentProductFieldId] = maskedString.formattedValue;
15743 }
15744 return result;
15745 };
15746 this.getUnmaskedValues = function() {
15747 var fields = _fieldValues;
15748 var result = [];
15749 for (var paymentProductFieldId in fields) {
15750 var paymentProductField = _paymentProduct.paymentProductFieldById[paymentProductFieldId];
15751 if (paymentProductField) {
15752 var maskedString = paymentProductField.applyMask(this.getValue(paymentProductFieldId));
15753 var formattedValue = maskedString.formattedValue;
15754 result[paymentProductFieldId] = paymentProductField.removeMask(formattedValue);
15755 }
15756 }
15757 return result;
15758 };
15759 this.setPaymentProduct = function(paymentProduct) {
15760 if (paymentProduct.type === "group") {
15761 return;
15762 }
15763 _paymentProduct = paymentProduct;
15764 };
15765 this.getPaymentProduct = function() {
15766 return _paymentProduct;
15767 };
15768 this.setAccountOnFile = function(accountOnFile) {
15769 for (var i = 0, il = accountOnFile.attributes.length; i < il; i++) {
15770 var attribute = accountOnFile.attributes[i];
15771 delete _fieldValues[attribute.key];
15772 }
15773 _accountOnFile = accountOnFile;
15774 };
15775 this.getAccountOnFile = function() {
15776 return _accountOnFile;
15777 };
15778 this.getClientSessionID = function() {
15779 return clientSessionID;
15780 };
15781 };
15782 connectsdk.PaymentRequest = PaymentRequest;
15783 return PaymentRequest;
15784});
15785define("connectsdk.C2SPaymentProductContext", ["connectsdk.core"], function(connectsdk) {
15786
15787 var C2SPaymentProductContext = function (payload) {
15788 this.totalAmount = typeof payload.totalAmount !== 'undefined' ? payload.totalAmount : '';
15789 this.countryCode = payload.countryCode;
15790 this.isRecurring = typeof payload.isRecurring !== 'undefined' ? payload.isRecurring : '';
15791 this.currency = payload.currency;
15792
15793 if (typeof payload.locale !== 'undefined') {
15794 this.locale = payload.locale;
15795 }
15796
15797 if (typeof payload.accountOnFileId !== 'undefined') {
15798 this.accountOnFileId = parseInt(payload.accountOnFileId);
15799 }
15800 };
15801
15802 connectsdk.C2SPaymentProductContext = C2SPaymentProductContext;
15803 return C2SPaymentProductContext;
15804});
15805
15806define("connectsdk.JOSEEncryptor", ["connectsdk.core"], function(connectsdk) {
15807
15808 var pki = forge.pki;
15809 var asn1 = forge.asn1;
15810 var CEKKEYLENGTH = 512;
15811 var IVLENGTH = 128;
15812
15813 var base64UrlEncode = function(str) {
15814 str = forge.util.encode64(str);
15815 str = str.split('=')[0];
15816 str = str.replace(/\+/g, '-');
15817 str = str.replace(/\//g, '_');
15818 return str;
15819 };
15820
15821 var createProtectedHeader = function(kid) {
15822 var JOSEHeader = {
15823 "alg" : "RSA-OAEP",
15824 "enc" : "A256CBC-HS512",
15825 "kid" : kid
15826 };
15827 return JSON.stringify(JOSEHeader);
15828 };
15829
15830 var decodePemPublicKey = function(publickeyB64Encoded) {
15831 // step 1: base64decode
15832 var publickeyB64Decoded = forge.util.decode64(publickeyB64Encoded);
15833 // create a bytebuffer with these bytes
15834 var buffer2 = forge.util.createBuffer(publickeyB64Decoded, 'raw');
15835 // convert DER to ASN1 object
15836 var publickeyObject2 = forge.asn1.fromDer(buffer2);
15837 // convert to publicKey object
15838 var publicKey2 = pki.publicKeyFromAsn1(publickeyObject2);
15839 return publicKey2;
15840 };
15841
15842 var encryptContentEncryptionKey = function(CEK, publicKey) {
15843 // encrypt CEK with OAEP+SHA-1+MGF1Padding
15844 var encryptedCEK = publicKey.encrypt(CEK, 'RSA-OAEP');
15845 return encryptedCEK;
15846 };
15847
15848 var encryptPayload = function(payload, encKey, initializationVector) {
15849 var cipher = forge.cipher.createCipher('AES-CBC', encKey);
15850 cipher.start({
15851 iv : initializationVector
15852 });
15853 cipher.update(forge.util.createBuffer(payload));
15854 cipher.finish();
15855 return cipher.output.bytes();
15856 };
15857
15858 var calculateAdditionalAuthenticatedDataLength = function(encodededProtectedHeader) {
15859 var buffer = forge.util.createBuffer(encodededProtectedHeader);
15860 var lengthInBits = buffer.length() * 8;
15861
15862 var buffer2 = forge.util.createBuffer();
15863 // convert int to 64bit big endian
15864 buffer2.putInt32(0);
15865 buffer2.putInt32(lengthInBits);
15866 return buffer2.bytes();
15867 };
15868
15869 var calculateHMAC = function(macKey, encodededProtectedHeader, initializationVector, cipherText, al) {
15870 var buffer = forge.util.createBuffer();
15871 buffer.putBytes(encodededProtectedHeader);
15872 buffer.putBytes(initializationVector);
15873 buffer.putBytes(cipherText);
15874 buffer.putBytes(al);
15875
15876 var hmacInput = buffer.bytes();
15877
15878 var hmac = forge.hmac.create();
15879 hmac.start(forge.sha512.create(), macKey);
15880 hmac.update(hmacInput);
15881 return hmac.digest().bytes();
15882 };
15883
15884 var JOSEEncryptor = function() {
15885
15886 this.encrypt = function(plainTextValues, publicKeyResponse) {
15887 // Create protected header and encode it with Base64 encoding
15888 var payload = JSON.stringify(plainTextValues);
15889 var protectedHeader = createProtectedHeader(publicKeyResponse.keyId);
15890 var encodededProtectedHeader = base64UrlEncode(protectedHeader);
15891
15892 // Create ContentEncryptionKey, is a random byte[]
15893 var CEK = forge.random.getBytesSync(CEKKEYLENGTH / 8);
15894 var publicKey = decodePemPublicKey(publicKeyResponse.publicKey);
15895
15896 // Encrypt the contentEncryptionKey with the GC gateway publickey and encode it with Base64 encoding
15897 var encryptedContentEncryptionKey = encryptContentEncryptionKey(CEK, publicKey);
15898 var encodedEncryptedContentEncryptionKey = base64UrlEncode(encryptedContentEncryptionKey);
15899
15900 // Split the contentEncryptionKey in ENC_KEY and MAC_KEY for using hmac
15901 var macKey = CEK.substring(0, CEKKEYLENGTH / 2 / 8);
15902 var encKey = CEK.substring(CEKKEYLENGTH / 2 / 8);
15903
15904 // Create Initialization Vector
15905 var initializationVector = forge.random.getBytesSync(IVLENGTH / 8);
15906 var encodededinitializationVector = base64UrlEncode(initializationVector);
15907
15908 // Encrypt content with ContentEncryptionKey and Initialization Vector
15909 var cipherText = encryptPayload(payload, encKey, initializationVector);
15910 var encodedCipherText = base64UrlEncode(cipherText);
15911
15912 // Create Additional Authenticated Data and Additional Authenticated Data Length
15913 var al = calculateAdditionalAuthenticatedDataLength(encodededProtectedHeader);
15914
15915 // Calculates HMAC
15916 var calculatedHmac = calculateHMAC(macKey, encodededProtectedHeader, initializationVector, cipherText, al);
15917
15918 // Truncate HMAC Value to Create Authentication Tag
15919 var authenticationTag = calculatedHmac.substring(0, calculatedHmac.length / 2);
15920 var encodedAuthenticationTag = base64UrlEncode(authenticationTag);
15921
15922 return encodededProtectedHeader + "." + encodedEncryptedContentEncryptionKey + "." + encodededinitializationVector + "." + encodedCipherText + "." + encodedAuthenticationTag;
15923 };
15924 };
15925
15926 connectsdk.JOSEEncryptor = JOSEEncryptor;
15927 return JOSEEncryptor;
15928});
15929define("connectsdk.Encryptor", ["connectsdk.core", "connectsdk.promise", "connectsdk.JOSEEncryptor", "connectsdk.Util"], function(connectsdk, Promise, JOSEEncryptor, Util) {
15930
15931 var _util = Util.getInstance();
15932
15933 var Encryptor = function(publicKeyResponsePromise) {
15934 this.encrypt = function(paymentRequest) {
15935 var promise = new Promise();
15936 var encryptedString = '';
15937 publicKeyResponsePromise.then(function (publicKeyResponse) {
15938 if (paymentRequest.isValid()) {
15939
15940 var blob = {
15941 clientSessionId: paymentRequest.getClientSessionID()
15942 ,nonce: forge.util.bytesToHex(forge.random.getBytesSync(16))
15943 ,paymentProductId: paymentRequest.getPaymentProduct().id
15944 ,tokenize: paymentRequest.getTokenize()
15945 };
15946
15947 if (paymentRequest.getAccountOnFile()) {
15948 blob["accountOnFileId"] = paymentRequest.getAccountOnFile().id;
15949 }
15950
15951 var paymentValues = [], values = paymentRequest.getUnmaskedValues();
15952 var ownValues = Object.getOwnPropertyNames(values);
15953 for (var i = 0; i < ownValues.length; i++) {
15954 var propertyName = ownValues[i];
15955 if (propertyName !== "length") {
15956 paymentValues.push({
15957 key: propertyName,
15958 value: values[propertyName]
15959 })
15960 }
15961 }
15962 blob["paymentValues"] = paymentValues;
15963
15964 blob["collectedDeviceInformation"] = _util.collectDeviceInformation();
15965
15966 // use blob to encrypt
15967 var joseEncryptor = new JOSEEncryptor();
15968 encryptedString = joseEncryptor.encrypt(blob, publicKeyResponse);
15969 promise.resolve(encryptedString);
15970 } else {
15971 promise.reject(paymentRequest.getErrorMessageIds());
15972 }
15973 }, function (error) {
15974 promise.reject(error);
15975 });
15976 return promise;
15977 };
15978 };
15979
15980 connectsdk.Encryptor = Encryptor;
15981 return Encryptor;
15982});
15983
15984define("connectsdk.Session", ["connectsdk.core", "connectsdk.C2SCommunicator", "connectsdk.C2SCommunicatorConfiguration", "connectsdk.IinDetailsResponse", "connectsdk.promise", "connectsdk.C2SPaymentProductContext", "connectsdk.BasicPaymentProducts", "connectsdk.BasicPaymentProductGroups", "connectsdk.PaymentProduct", "connectsdk.PaymentProductGroup", "connectsdk.BasicPaymentItems", "connectsdk.PaymentRequest", "connectsdk.Encryptor"], function (connectsdk, C2SCommunicator, C2SCommunicatorConfiguration, IinDetailsResponse, Promise, C2SPaymentProductContext, BasicPaymentProducts, BasicPaymentProductGroups, PaymentProduct, PaymentProductGroup, BasicPaymentItems, PaymentRequest, Encryptor) {
15985 var APIVERSION = "client/v1";
15986 var session = function (sessionDetails, paymentProduct) {
15987
15988 var _c2SCommunicatorConfiguration = new C2SCommunicatorConfiguration(sessionDetails, APIVERSION),
15989 _c2sCommunicator = new C2SCommunicator(_c2SCommunicatorConfiguration, paymentProduct),
15990 _session = this,
15991 _paymentProductId, _paymentProduct, _paymentRequestPayload, _paymentRequest, _paymentProductGroupId, _paymentProductGroup;
15992 this.clientApiUrl = _c2SCommunicatorConfiguration.clientApiUrl;
15993 this.assetUrl = _c2SCommunicatorConfiguration.assetUrl;
15994
15995 this.getBasicPaymentProducts = function (paymentRequestPayload, paymentProductSpecificInputs) {
15996 var promise = new Promise();
15997 var c2SPaymentProductContext = new C2SPaymentProductContext(paymentRequestPayload);
15998 _c2sCommunicator.getBasicPaymentProducts(c2SPaymentProductContext, paymentProductSpecificInputs).then(function (json) {
15999 _paymentRequestPayload = paymentRequestPayload;
16000 var paymentProducts = new BasicPaymentProducts(json);
16001 promise.resolve(paymentProducts);
16002 }, function () {
16003 promise.reject();
16004 });
16005 return promise;
16006 };
16007
16008 this.getBasicPaymentProductGroups = function (paymentRequestPayload) {
16009 var promise = new Promise();
16010 var c2SPaymentProductContext = new C2SPaymentProductContext(paymentRequestPayload);
16011 _c2sCommunicator.getBasicPaymentProductGroups(c2SPaymentProductContext).then(function (json) {
16012 _paymentRequestPayload = paymentRequestPayload;
16013 var paymentProductGroups = new BasicPaymentProductGroups(json);
16014 promise.resolve(paymentProductGroups);
16015 }, function () {
16016 promise.reject();
16017 });
16018 return promise;
16019 };
16020
16021 this.getBasicPaymentItems = function (paymentRequestPayload, useGroups, paymentProductSpecificInputs) {
16022 var promise = new Promise();
16023 // get products & groups
16024 if (useGroups) {
16025 _session.getBasicPaymentProducts(paymentRequestPayload, paymentProductSpecificInputs).then(function (products) {
16026 _session.getBasicPaymentProductGroups(paymentRequestPayload).then(function (groups) {
16027 var basicPaymentItems = new BasicPaymentItems(products, groups);
16028 promise.resolve(basicPaymentItems);
16029 }, function () {
16030 promise.reject();
16031 });
16032 }, function () {
16033 promise.reject();
16034 });
16035 } else {
16036 _session.getBasicPaymentProducts(paymentRequestPayload, paymentProductSpecificInputs).then(function (products) {
16037 var basicPaymentItems = new BasicPaymentItems(products, null);
16038 promise.resolve(basicPaymentItems);
16039 }, function () {
16040 promise.reject();
16041 });
16042 }
16043 return promise;
16044 };
16045
16046 this.getPaymentProduct = function (paymentProductId, paymentRequestPayload, paymentProductSpecificInputs) {
16047 var promise = new Promise();
16048 _paymentProductId = paymentProductId;
16049 var c2SPaymentProductContext = new C2SPaymentProductContext(_paymentRequestPayload || paymentRequestPayload);
16050 _c2sCommunicator.getPaymentProduct(paymentProductId, c2SPaymentProductContext, paymentProductSpecificInputs).then(function (response) {
16051 _paymentProduct = new PaymentProduct(response);
16052 promise.resolve(_paymentProduct);
16053 }, function () {
16054 _paymentProduct = null;
16055 promise.reject();
16056 });
16057 return promise;
16058 };
16059
16060 this.getPaymentProductGroup = function (paymentProductGroupId, paymentRequestPayload) {
16061 var promise = new Promise();
16062 _paymentProductGroupId = paymentProductGroupId;
16063 var c2SPaymentProductContext = new C2SPaymentProductContext(_paymentRequestPayload || paymentRequestPayload);
16064 _c2sCommunicator.getPaymentProductGroup(paymentProductGroupId, c2SPaymentProductContext).then(function (response) {
16065 _paymentProductGroup = new PaymentProductGroup(response);
16066 promise.resolve(_paymentProductGroup);
16067 }, function () {
16068 _paymentProductGroup = null;
16069 promise.reject();
16070 });
16071 return promise;
16072 };
16073
16074 this.getIinDetails = function (partialCreditCardNumber, paymentRequestPayload) {
16075 partialCreditCardNumber = partialCreditCardNumber.replace(/ /g, '').substring(0, 6);
16076 var c2SPaymentProductContext = new C2SPaymentProductContext(_paymentRequestPayload || paymentRequestPayload);
16077 return _c2sCommunicator.getPaymentProductIdByCreditCardNumber(partialCreditCardNumber, c2SPaymentProductContext);
16078 };
16079
16080 this.getPublicKey = function () {
16081 return _c2sCommunicator.getPublicKey();
16082 };
16083
16084 this.getPaymentProductNetworks = function (paymentProductId, paymentRequestPayload) {
16085 var promise = new Promise();
16086 var c2SPaymentProductContext = new C2SPaymentProductContext(paymentRequestPayload);
16087 _c2sCommunicator.getPaymentProductNetworks(paymentProductId, c2SPaymentProductContext).then(function (response) {
16088 _paymentRequestPayload = paymentRequestPayload;
16089 promise.resolve(response);
16090 }, function () {
16091 promise.reject();
16092 });
16093 return promise;
16094 };
16095
16096 this.getPaymentProductDirectory = function (paymentProductId, currencyCode, countryCode) {
16097 return _c2sCommunicator.getPaymentProductDirectory(paymentProductId, currencyCode, countryCode);
16098 };
16099
16100 this.convertAmount = function (amount, source, target) {
16101 return _c2sCommunicator.convertAmount(amount, source, target);
16102 };
16103
16104 this.getPaymentRequest = function () {
16105 if (!_paymentRequest) {
16106 _paymentRequest = new PaymentRequest(_c2SCommunicatorConfiguration.clientSessionId);
16107 }
16108 return _paymentRequest;
16109 };
16110
16111 this.getEncryptor = function () {
16112 var publicKeyResponsePromise = _c2sCommunicator.getPublicKey();
16113 return new Encryptor(publicKeyResponsePromise);
16114 };
16115
16116 this.getThirdPartyPaymentStatus = function (paymentId) {
16117 var promise = new Promise();
16118 _c2sCommunicator.getThirdPartyPaymentStatus(paymentId).then(function (response) {
16119 promise.resolve(response);
16120 }, function () {
16121 promise.reject();
16122 });
16123 return promise;
16124 };
16125
16126 this.getCustomerDetails = function (paymentProductId, paymentRequestPayload) {
16127 return _c2sCommunicator.getCustomerDetails(paymentProductId, paymentRequestPayload);
16128 };
16129
16130 /* In case a full JSON representation of a payment product is already available in context,
16131 this method can be used instead of getPaymentProduct for the same (but synchronous) result. */
16132 this.transformPaymentProductJSON = function(json) {
16133 return new PaymentProduct(_c2sCommunicator.transformPaymentProductJSON(json))
16134 };
16135
16136 /* In case a full JSON representation of a payment product group is already available in context,
16137 this method can be used instead of getPaymentProductGroup for the same (but synchronous) result. */
16138 this.transformPaymentProductGroupJSON = function(json) {
16139 return new PaymentProductGroup(_c2sCommunicator.transformPaymentProductJSON(json))
16140 };
16141 };
16142 connectsdk.Session = session;
16143 return session;
16144});