(function () { // globals var _promiseFactory; var _httpRequest; /* CryptoJS v3.1.2 code.google.com/p/crypto-js (c) 2009-2013 by Jeff Mott. All rights reserved. code.google.com/p/crypto-js/wiki/License */ /** * CryptoJS core components. */ var CryptoJS = CryptoJS || (function (Math, undefined) { /** * CryptoJS namespace. */ var C = {}; /** * Library namespace. */ var C_lib = C.lib = {}; /** * Base object for prototypal inheritance. */ var Base = C_lib.Base = (function () { function F() {} return { /** * Creates a new object that inherits from this object. * * @param {Object} overrides Properties to copy into the new object. * * @return {Object} The new object. * * @static * * @example * * var MyType = CryptoJS.lib.Base.extend({ * field: 'value', * * method: function () { * } * }); */ extend: function (overrides) { // Spawn F.prototype = this; var subtype = new F(); // Augment if (overrides) { subtype.mixIn(overrides); } // Create default initializer if (!subtype.hasOwnProperty('init')) { subtype.init = function () { subtype.$super.init.apply(this, arguments); }; } // Initializer's prototype is the subtype object subtype.init.prototype = subtype; // Reference supertype subtype.$super = this; return subtype; }, /** * Extends this object and runs the init method. * Arguments to create() will be passed to init(). * * @return {Object} The new object. * * @static * * @example * * var instance = MyType.create(); */ create: function () { var instance = this.extend(); instance.init.apply(instance, arguments); return instance; }, /** * Initializes a newly created object. * Override this method to add some logic when your objects are created. * * @example * * var MyType = CryptoJS.lib.Base.extend({ * init: function () { * // ... * } * }); */ init: function () { }, /** * Copies properties into this object. * * @param {Object} properties The properties to mix in. * * @example * * MyType.mixIn({ * field: 'value' * }); */ mixIn: function (properties) { for (var propertyName in properties) { if (properties.hasOwnProperty(propertyName)) { this[propertyName] = properties[propertyName]; } } // IE won't copy toString using the loop above if (properties.hasOwnProperty('toString')) { this.toString = properties.toString; } }, /** * Creates a copy of this object. * * @return {Object} The clone. * * @example * * var clone = instance.clone(); */ clone: function () { return this.init.prototype.extend(this); } }; }()); /** * An array of 32-bit words. * * @property {Array} words The array of 32-bit words. * @property {number} sigBytes The number of significant bytes in this word array. */ var WordArray = C_lib.WordArray = Base.extend({ /** * Initializes a newly created word array. * * @param {Array} words (Optional) An array of 32-bit words. * @param {number} sigBytes (Optional) The number of significant bytes in the words. * * @example * * var wordArray = CryptoJS.lib.WordArray.create(); * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]); * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6); */ init: function (words, sigBytes) { words = this.words = words || []; if (sigBytes != undefined) { this.sigBytes = sigBytes; } else { this.sigBytes = words.length * 4; } }, /** * Converts this word array to a string. * * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex * * @return {string} The stringified word array. * * @example * * var string = wordArray + ''; * var string = wordArray.toString(); * var string = wordArray.toString(CryptoJS.enc.Utf8); */ toString: function (encoder) { return (encoder || Hex).stringify(this); }, /** * Concatenates a word array to this word array. * * @param {WordArray} wordArray The word array to append. * * @return {WordArray} This word array. * * @example * * wordArray1.concat(wordArray2); */ concat: function (wordArray) { // Shortcuts var thisWords = this.words; var thatWords = wordArray.words; var thisSigBytes = this.sigBytes; var thatSigBytes = wordArray.sigBytes; // Clamp excess bits this.clamp(); // Concat if (thisSigBytes % 4) { // Copy one byte at a time for (var i = 0; i < thatSigBytes; i++) { var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); } } else if (thatWords.length > 0xffff) { // Copy one word at a time for (var i = 0; i < thatSigBytes; i += 4) { thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2]; } } else { // Copy all words at once thisWords.push.apply(thisWords, thatWords); } this.sigBytes += thatSigBytes; // Chainable return this; }, /** * Removes insignificant bits. * * @example * * wordArray.clamp(); */ clamp: function () { // Shortcuts var words = this.words; var sigBytes = this.sigBytes; // Clamp words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); words.length = Math.ceil(sigBytes / 4); }, /** * Creates a copy of this word array. * * @return {WordArray} The clone. * * @example * * var clone = wordArray.clone(); */ clone: function () { var clone = Base.clone.call(this); clone.words = this.words.slice(0); return clone; }, /** * Creates a word array filled with random bytes. * * @param {number} nBytes The number of random bytes to generate. * * @return {WordArray} The random word array. * * @static * * @example * * var wordArray = CryptoJS.lib.WordArray.random(16); */ random: function (nBytes) { var words = []; for (var i = 0; i < nBytes; i += 4) { words.push((Math.random() * 0x100000000) | 0); } return new WordArray.init(words, nBytes); } }); /** * Encoder namespace. */ var C_enc = C.enc = {}; /** * Hex encoding strategy. */ var Hex = C_enc.Hex = { /** * Converts a word array to a hex string. * * @param {WordArray} wordArray The word array. * * @return {string} The hex string. * * @static * * @example * * var hexString = CryptoJS.enc.Hex.stringify(wordArray); */ stringify: function (wordArray) { // Shortcuts var words = wordArray.words; var sigBytes = wordArray.sigBytes; // Convert var hexChars = []; for (var i = 0; i < sigBytes; i++) { var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; hexChars.push((bite >>> 4).toString(16)); hexChars.push((bite & 0x0f).toString(16)); } return hexChars.join(''); }, /** * Converts a hex string to a word array. * * @param {string} hexStr The hex string. * * @return {WordArray} The word array. * * @static * * @example * * var wordArray = CryptoJS.enc.Hex.parse(hexString); */ parse: function (hexStr) { // Shortcut var hexStrLength = hexStr.length; // Convert var words = []; for (var i = 0; i < hexStrLength; i += 2) { words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); } return new WordArray.init(words, hexStrLength / 2); } }; /** * Latin1 encoding strategy. */ var Latin1 = C_enc.Latin1 = { /** * Converts a word array to a Latin1 string. * * @param {WordArray} wordArray The word array. * * @return {string} The Latin1 string. * * @static * * @example * * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray); */ stringify: function (wordArray) { // Shortcuts var words = wordArray.words; var sigBytes = wordArray.sigBytes; // Convert var latin1Chars = []; for (var i = 0; i < sigBytes; i++) { var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; latin1Chars.push(String.fromCharCode(bite)); } return latin1Chars.join(''); }, /** * Converts a Latin1 string to a word array. * * @param {string} latin1Str The Latin1 string. * * @return {WordArray} The word array. * * @static * * @example * * var wordArray = CryptoJS.enc.Latin1.parse(latin1String); */ parse: function (latin1Str) { // Shortcut var latin1StrLength = latin1Str.length; // Convert var words = []; for (var i = 0; i < latin1StrLength; i++) { words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); } return new WordArray.init(words, latin1StrLength); } }; /** * UTF-8 encoding strategy. */ var Utf8 = C_enc.Utf8 = { /** * Converts a word array to a UTF-8 string. * * @param {WordArray} wordArray The word array. * * @return {string} The UTF-8 string. * * @static * * @example * * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray); */ stringify: function (wordArray) { try { return decodeURIComponent(escape(Latin1.stringify(wordArray))); } catch (e) { throw new Error('Malformed UTF-8 data'); } }, /** * Converts a UTF-8 string to a word array. * * @param {string} utf8Str The UTF-8 string. * * @return {WordArray} The word array. * * @static * * @example * * var wordArray = CryptoJS.enc.Utf8.parse(utf8String); */ parse: function (utf8Str) { return Latin1.parse(unescape(encodeURIComponent(utf8Str))); } }; /** * Abstract buffered block algorithm template. * * The property blockSize must be implemented in a concrete subtype. * * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0 */ var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ /** * Resets this block algorithm's data buffer to its initial state. * * @example * * bufferedBlockAlgorithm.reset(); */ reset: function () { // Initial values this._data = new WordArray.init(); this._nDataBytes = 0; }, /** * Adds new data to this block algorithm's buffer. * * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8. * * @example * * bufferedBlockAlgorithm._append('data'); * bufferedBlockAlgorithm._append(wordArray); */ _append: function (data) { // Convert string to WordArray, else assume WordArray already if (typeof data == 'string') { data = Utf8.parse(data); } // Append this._data.concat(data); this._nDataBytes += data.sigBytes; }, /** * Processes available data blocks. * * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype. * * @param {boolean} doFlush Whether all blocks and partial blocks should be processed. * * @return {WordArray} The processed data. * * @example * * var processedData = bufferedBlockAlgorithm._process(); * var processedData = bufferedBlockAlgorithm._process(!!'flush'); */ _process: function (doFlush) { // Shortcuts var data = this._data; var dataWords = data.words; var dataSigBytes = data.sigBytes; var blockSize = this.blockSize; var blockSizeBytes = blockSize * 4; // Count blocks ready var nBlocksReady = dataSigBytes / blockSizeBytes; if (doFlush) { // Round up to include partial blocks nBlocksReady = Math.ceil(nBlocksReady); } else { // Round down to include only full blocks, // less the number of blocks that must remain in the buffer nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); } // Count words ready var nWordsReady = nBlocksReady * blockSize; // Count bytes ready var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); // Process blocks if (nWordsReady) { for (var offset = 0; offset < nWordsReady; offset += blockSize) { // Perform concrete-algorithm logic this._doProcessBlock(dataWords, offset); } // Remove processed words var processedWords = dataWords.splice(0, nWordsReady); data.sigBytes -= nBytesReady; } // Return processed words return new WordArray.init(processedWords, nBytesReady); }, /** * Creates a copy of this object. * * @return {Object} The clone. * * @example * * var clone = bufferedBlockAlgorithm.clone(); */ clone: function () { var clone = Base.clone.call(this); clone._data = this._data.clone(); return clone; }, _minBufferSize: 0 }); /** * Abstract hasher template. * * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits) */ var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({ /** * Configuration options. */ cfg: Base.extend(), /** * Initializes a newly created hasher. * * @param {Object} cfg (Optional) The configuration options to use for this hash computation. * * @example * * var hasher = CryptoJS.algo.SHA256.create(); */ init: function (cfg) { // Apply config defaults this.cfg = this.cfg.extend(cfg); // Set initial values this.reset(); }, /** * Resets this hasher to its initial state. * * @example * * hasher.reset(); */ reset: function () { // Reset data buffer BufferedBlockAlgorithm.reset.call(this); // Perform concrete-hasher logic this._doReset(); }, /** * Updates this hasher with a message. * * @param {WordArray|string} messageUpdate The message to append. * * @return {Hasher} This hasher. * * @example * * hasher.update('message'); * hasher.update(wordArray); */ update: function (messageUpdate) { // Append this._append(messageUpdate); // Update the hash this._process(); // Chainable return this; }, /** * Finalizes the hash computation. * Note that the finalize operation is effectively a destructive, read-once operation. * * @param {WordArray|string} messageUpdate (Optional) A final message update. * * @return {WordArray} The hash. * * @example * * var hash = hasher.finalize(); * var hash = hasher.finalize('message'); * var hash = hasher.finalize(wordArray); */ finalize: function (messageUpdate) { // Final message update if (messageUpdate) { this._append(messageUpdate); } // Perform concrete-hasher logic var hash = this._doFinalize(); return hash; }, blockSize: 512/32, /** * Creates a shortcut function to a hasher's object interface. * * @param {Hasher} hasher The hasher to create a helper for. * * @return {Function} The shortcut function. * * @static * * @example * * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256); */ _createHelper: function (hasher) { return function (message, cfg) { return new hasher.init(cfg).finalize(message); }; }, /** * Creates a shortcut function to the HMAC's object interface. * * @param {Hasher} hasher The hasher to use in this HMAC helper. * * @return {Function} The shortcut function. * * @static * * @example * * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256); */ _createHmacHelper: function (hasher) { return function (message, key) { return new C_algo.HMAC.init(hasher, key).finalize(message); }; } }); /** * Algorithm namespace. */ var C_algo = C.algo = {}; return C; }(Math)); /* CryptoJS v3.1.2 code.google.com/p/crypto-js (c) 2009-2013 by Jeff Mott. All rights reserved. code.google.com/p/crypto-js/wiki/License */ (function () { // Shortcuts var C = CryptoJS; var C_lib = C.lib; var WordArray = C_lib.WordArray; var Hasher = C_lib.Hasher; var C_algo = C.algo; // Reusable object var W = []; /** * SHA-1 hash algorithm. */ var SHA1 = C_algo.SHA1 = Hasher.extend({ _doReset: function () { this._hash = new WordArray.init([ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 ]); }, _doProcessBlock: function (M, offset) { // Shortcut var H = this._hash.words; // Working variables var a = H[0]; var b = H[1]; var c = H[2]; var d = H[3]; var e = H[4]; // Computation for (var i = 0; i < 80; i++) { if (i < 16) { W[i] = M[offset + i] | 0; } else { var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]; W[i] = (n << 1) | (n >>> 31); } var t = ((a << 5) | (a >>> 27)) + e + W[i]; if (i < 20) { t += ((b & c) | (~b & d)) + 0x5a827999; } else if (i < 40) { t += (b ^ c ^ d) + 0x6ed9eba1; } else if (i < 60) { t += ((b & c) | (b & d) | (c & d)) - 0x70e44324; } else /* if (i < 80) */ { t += (b ^ c ^ d) - 0x359d3e2a; } e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t; } // Intermediate hash value H[0] = (H[0] + a) | 0; H[1] = (H[1] + b) | 0; H[2] = (H[2] + c) | 0; H[3] = (H[3] + d) | 0; H[4] = (H[4] + e) | 0; }, _doFinalize: function () { // Shortcuts var data = this._data; var dataWords = data.words; var nBitsTotal = this._nDataBytes * 8; var nBitsLeft = data.sigBytes * 8; // Add padding dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; data.sigBytes = dataWords.length * 4; // Hash final blocks this._process(); // Return final computed hash return this._hash; }, clone: function () { var clone = Hasher.clone.call(this); clone._hash = this._hash.clone(); return clone; } }); /** * Shortcut function to the hasher's object interface. * * @param {WordArray|string} message The message to hash. * * @return {WordArray} The hash. * * @static * * @example * * var hash = CryptoJS.SHA1('message'); * var hash = CryptoJS.SHA1(wordArray); */ C.SHA1 = Hasher._createHelper(SHA1); /** * Shortcut function to the HMAC's object interface. * * @param {WordArray|string} message The message to hash. * @param {WordArray|string} key The secret key. * * @return {WordArray} The HMAC. * * @static * * @example * * var hmac = CryptoJS.HmacSHA1(message, key); */ C.HmacSHA1 = Hasher._createHmacHelper(SHA1); }()); /* CryptoJS v3.1.2 code.google.com/p/crypto-js (c) 2009-2013 by Jeff Mott. All rights reserved. code.google.com/p/crypto-js/wiki/License */ (function (Math) { // Shortcuts var C = CryptoJS; var C_lib = C.lib; var WordArray = C_lib.WordArray; var Hasher = C_lib.Hasher; var C_algo = C.algo; // Initialization and round constants tables var H = []; var K = []; // Compute constants (function () { function isPrime(n) { var sqrtN = Math.sqrt(n); for (var factor = 2; factor <= sqrtN; factor++) { if (!(n % factor)) { return false; } } return true; } function getFractionalBits(n) { return ((n - (n | 0)) * 0x100000000) | 0; } var n = 2; var nPrime = 0; while (nPrime < 64) { if (isPrime(n)) { if (nPrime < 8) { H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2)); } K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3)); nPrime++; } n++; } }()); // Reusable object var W = []; /** * SHA-256 hash algorithm. */ var SHA256 = C_algo.SHA256 = Hasher.extend({ _doReset: function () { this._hash = new WordArray.init(H.slice(0)); }, _doProcessBlock: function (M, offset) { // Shortcut var H = this._hash.words; // Working variables var a = H[0]; var b = H[1]; var c = H[2]; var d = H[3]; var e = H[4]; var f = H[5]; var g = H[6]; var h = H[7]; // Computation for (var i = 0; i < 64; i++) { if (i < 16) { W[i] = M[offset + i] | 0; } else { var gamma0x = W[i - 15]; var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ ((gamma0x << 14) | (gamma0x >>> 18)) ^ (gamma0x >>> 3); var gamma1x = W[i - 2]; var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ ((gamma1x << 13) | (gamma1x >>> 19)) ^ (gamma1x >>> 10); W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]; } var ch = (e & f) ^ (~e & g); var maj = (a & b) ^ (a & c) ^ (b & c); var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22)); var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25)); var t1 = h + sigma1 + ch + K[i] + W[i]; var t2 = sigma0 + maj; h = g; g = f; f = e; e = (d + t1) | 0; d = c; c = b; b = a; a = (t1 + t2) | 0; } // Intermediate hash value H[0] = (H[0] + a) | 0; H[1] = (H[1] + b) | 0; H[2] = (H[2] + c) | 0; H[3] = (H[3] + d) | 0; H[4] = (H[4] + e) | 0; H[5] = (H[5] + f) | 0; H[6] = (H[6] + g) | 0; H[7] = (H[7] + h) | 0; }, _doFinalize: function () { // Shortcuts var data = this._data; var dataWords = data.words; var nBitsTotal = this._nDataBytes * 8; var nBitsLeft = data.sigBytes * 8; // Add padding dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; data.sigBytes = dataWords.length * 4; // Hash final blocks this._process(); // Return final computed hash return this._hash; }, clone: function () { var clone = Hasher.clone.call(this); clone._hash = this._hash.clone(); return clone; } }); /** * Shortcut function to the hasher's object interface. * * @param {WordArray|string} message The message to hash. * * @return {WordArray} The hash. * * @static * * @example * * var hash = CryptoJS.SHA256('message'); * var hash = CryptoJS.SHA256(wordArray); */ C.SHA256 = Hasher._createHelper(SHA256); /** * Shortcut function to the HMAC's object interface. * * @param {WordArray|string} message The message to hash. * @param {WordArray|string} key The secret key. * * @return {WordArray} The HMAC. * * @static * * @example * * var hmac = CryptoJS.HmacSHA256(message, key); */ C.HmacSHA256 = Hasher._createHmacHelper(SHA256); }(Math)); /* CryptoJS v3.1.2 code.google.com/p/crypto-js (c) 2009-2013 by Jeff Mott. All rights reserved. code.google.com/p/crypto-js/wiki/License */ (function (undefined) { // Shortcuts var C = CryptoJS; var C_lib = C.lib; var Base = C_lib.Base; var X32WordArray = C_lib.WordArray; /** * x64 namespace. */ var C_x64 = C.x64 = {}; /** * A 64-bit word. */ var X64Word = C_x64.Word = Base.extend({ /** * Initializes a newly created 64-bit word. * * @param {number} high The high 32 bits. * @param {number} low The low 32 bits. * * @example * * var x64Word = CryptoJS.x64.Word.create(0x00010203, 0x04050607); */ init: function (high, low) { this.high = high; this.low = low; } /** * Bitwise NOTs this word. * * @return {X64Word} A new x64-Word object after negating. * * @example * * var negated = x64Word.not(); */ // not: function () { // var high = ~this.high; // var low = ~this.low; // return X64Word.create(high, low); // }, /** * Bitwise ANDs this word with the passed word. * * @param {X64Word} word The x64-Word to AND with this word. * * @return {X64Word} A new x64-Word object after ANDing. * * @example * * var anded = x64Word.and(anotherX64Word); */ // and: function (word) { // var high = this.high & word.high; // var low = this.low & word.low; // return X64Word.create(high, low); // }, /** * Bitwise ORs this word with the passed word. * * @param {X64Word} word The x64-Word to OR with this word. * * @return {X64Word} A new x64-Word object after ORing. * * @example * * var ored = x64Word.or(anotherX64Word); */ // or: function (word) { // var high = this.high | word.high; // var low = this.low | word.low; // return X64Word.create(high, low); // }, /** * Bitwise XORs this word with the passed word. * * @param {X64Word} word The x64-Word to XOR with this word. * * @return {X64Word} A new x64-Word object after XORing. * * @example * * var xored = x64Word.xor(anotherX64Word); */ // xor: function (word) { // var high = this.high ^ word.high; // var low = this.low ^ word.low; // return X64Word.create(high, low); // }, /** * Shifts this word n bits to the left. * * @param {number} n The number of bits to shift. * * @return {X64Word} A new x64-Word object after shifting. * * @example * * var shifted = x64Word.shiftL(25); */ // shiftL: function (n) { // if (n < 32) { // var high = (this.high << n) | (this.low >>> (32 - n)); // var low = this.low << n; // } else { // var high = this.low << (n - 32); // var low = 0; // } // return X64Word.create(high, low); // }, /** * Shifts this word n bits to the right. * * @param {number} n The number of bits to shift. * * @return {X64Word} A new x64-Word object after shifting. * * @example * * var shifted = x64Word.shiftR(7); */ // shiftR: function (n) { // if (n < 32) { // var low = (this.low >>> n) | (this.high << (32 - n)); // var high = this.high >>> n; // } else { // var low = this.high >>> (n - 32); // var high = 0; // } // return X64Word.create(high, low); // }, /** * Rotates this word n bits to the left. * * @param {number} n The number of bits to rotate. * * @return {X64Word} A new x64-Word object after rotating. * * @example * * var rotated = x64Word.rotL(25); */ // rotL: function (n) { // return this.shiftL(n).or(this.shiftR(64 - n)); // }, /** * Rotates this word n bits to the right. * * @param {number} n The number of bits to rotate. * * @return {X64Word} A new x64-Word object after rotating. * * @example * * var rotated = x64Word.rotR(7); */ // rotR: function (n) { // return this.shiftR(n).or(this.shiftL(64 - n)); // }, /** * Adds this word with the passed word. * * @param {X64Word} word The x64-Word to add with this word. * * @return {X64Word} A new x64-Word object after adding. * * @example * * var added = x64Word.add(anotherX64Word); */ // add: function (word) { // var low = (this.low + word.low) | 0; // var carry = (low >>> 0) < (this.low >>> 0) ? 1 : 0; // var high = (this.high + word.high + carry) | 0; // return X64Word.create(high, low); // } }); /** * An array of 64-bit words. * * @property {Array} words The array of CryptoJS.x64.Word objects. * @property {number} sigBytes The number of significant bytes in this word array. */ var X64WordArray = C_x64.WordArray = Base.extend({ /** * Initializes a newly created word array. * * @param {Array} words (Optional) An array of CryptoJS.x64.Word objects. * @param {number} sigBytes (Optional) The number of significant bytes in the words. * * @example * * var wordArray = CryptoJS.x64.WordArray.create(); * * var wordArray = CryptoJS.x64.WordArray.create([ * CryptoJS.x64.Word.create(0x00010203, 0x04050607), * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) * ]); * * var wordArray = CryptoJS.x64.WordArray.create([ * CryptoJS.x64.Word.create(0x00010203, 0x04050607), * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) * ], 10); */ init: function (words, sigBytes) { words = this.words = words || []; if (sigBytes != undefined) { this.sigBytes = sigBytes; } else { this.sigBytes = words.length * 8; } }, /** * Converts this 64-bit word array to a 32-bit word array. * * @return {CryptoJS.lib.WordArray} This word array's data as a 32-bit word array. * * @example * * var x32WordArray = x64WordArray.toX32(); */ toX32: function () { // Shortcuts var x64Words = this.words; var x64WordsLength = x64Words.length; // Convert var x32Words = []; for (var i = 0; i < x64WordsLength; i++) { var x64Word = x64Words[i]; x32Words.push(x64Word.high); x32Words.push(x64Word.low); } return X32WordArray.create(x32Words, this.sigBytes); }, /** * Creates a copy of this word array. * * @return {X64WordArray} The clone. * * @example * * var clone = x64WordArray.clone(); */ clone: function () { var clone = Base.clone.call(this); // Clone "words" array var words = clone.words = this.words.slice(0); // Clone each X64Word object var wordsLength = words.length; for (var i = 0; i < wordsLength; i++) { words[i] = words[i].clone(); } return clone; } }); }()); /* CryptoJS v3.1.2 code.google.com/p/crypto-js (c) 2009-2013 by Jeff Mott. All rights reserved. code.google.com/p/crypto-js/wiki/License */ (function () { // Shortcuts var C = CryptoJS; var C_lib = C.lib; var Hasher = C_lib.Hasher; var C_x64 = C.x64; var X64Word = C_x64.Word; var X64WordArray = C_x64.WordArray; var C_algo = C.algo; function X64Word_create() { return X64Word.create.apply(X64Word, arguments); } // Constants var K = [ X64Word_create(0x428a2f98, 0xd728ae22), X64Word_create(0x71374491, 0x23ef65cd), X64Word_create(0xb5c0fbcf, 0xec4d3b2f), X64Word_create(0xe9b5dba5, 0x8189dbbc), X64Word_create(0x3956c25b, 0xf348b538), X64Word_create(0x59f111f1, 0xb605d019), X64Word_create(0x923f82a4, 0xaf194f9b), X64Word_create(0xab1c5ed5, 0xda6d8118), X64Word_create(0xd807aa98, 0xa3030242), X64Word_create(0x12835b01, 0x45706fbe), X64Word_create(0x243185be, 0x4ee4b28c), X64Word_create(0x550c7dc3, 0xd5ffb4e2), X64Word_create(0x72be5d74, 0xf27b896f), X64Word_create(0x80deb1fe, 0x3b1696b1), X64Word_create(0x9bdc06a7, 0x25c71235), X64Word_create(0xc19bf174, 0xcf692694), X64Word_create(0xe49b69c1, 0x9ef14ad2), X64Word_create(0xefbe4786, 0x384f25e3), X64Word_create(0x0fc19dc6, 0x8b8cd5b5), X64Word_create(0x240ca1cc, 0x77ac9c65), X64Word_create(0x2de92c6f, 0x592b0275), X64Word_create(0x4a7484aa, 0x6ea6e483), X64Word_create(0x5cb0a9dc, 0xbd41fbd4), X64Word_create(0x76f988da, 0x831153b5), X64Word_create(0x983e5152, 0xee66dfab), X64Word_create(0xa831c66d, 0x2db43210), X64Word_create(0xb00327c8, 0x98fb213f), X64Word_create(0xbf597fc7, 0xbeef0ee4), X64Word_create(0xc6e00bf3, 0x3da88fc2), X64Word_create(0xd5a79147, 0x930aa725), X64Word_create(0x06ca6351, 0xe003826f), X64Word_create(0x14292967, 0x0a0e6e70), X64Word_create(0x27b70a85, 0x46d22ffc), X64Word_create(0x2e1b2138, 0x5c26c926), X64Word_create(0x4d2c6dfc, 0x5ac42aed), X64Word_create(0x53380d13, 0x9d95b3df), X64Word_create(0x650a7354, 0x8baf63de), X64Word_create(0x766a0abb, 0x3c77b2a8), X64Word_create(0x81c2c92e, 0x47edaee6), X64Word_create(0x92722c85, 0x1482353b), X64Word_create(0xa2bfe8a1, 0x4cf10364), X64Word_create(0xa81a664b, 0xbc423001), X64Word_create(0xc24b8b70, 0xd0f89791), X64Word_create(0xc76c51a3, 0x0654be30), X64Word_create(0xd192e819, 0xd6ef5218), X64Word_create(0xd6990624, 0x5565a910), X64Word_create(0xf40e3585, 0x5771202a), X64Word_create(0x106aa070, 0x32bbd1b8), X64Word_create(0x19a4c116, 0xb8d2d0c8), X64Word_create(0x1e376c08, 0x5141ab53), X64Word_create(0x2748774c, 0xdf8eeb99), X64Word_create(0x34b0bcb5, 0xe19b48a8), X64Word_create(0x391c0cb3, 0xc5c95a63), X64Word_create(0x4ed8aa4a, 0xe3418acb), X64Word_create(0x5b9cca4f, 0x7763e373), X64Word_create(0x682e6ff3, 0xd6b2b8a3), X64Word_create(0x748f82ee, 0x5defb2fc), X64Word_create(0x78a5636f, 0x43172f60), X64Word_create(0x84c87814, 0xa1f0ab72), X64Word_create(0x8cc70208, 0x1a6439ec), X64Word_create(0x90befffa, 0x23631e28), X64Word_create(0xa4506ceb, 0xde82bde9), X64Word_create(0xbef9a3f7, 0xb2c67915), X64Word_create(0xc67178f2, 0xe372532b), X64Word_create(0xca273ece, 0xea26619c), X64Word_create(0xd186b8c7, 0x21c0c207), X64Word_create(0xeada7dd6, 0xcde0eb1e), X64Word_create(0xf57d4f7f, 0xee6ed178), X64Word_create(0x06f067aa, 0x72176fba), X64Word_create(0x0a637dc5, 0xa2c898a6), X64Word_create(0x113f9804, 0xbef90dae), X64Word_create(0x1b710b35, 0x131c471b), X64Word_create(0x28db77f5, 0x23047d84), X64Word_create(0x32caab7b, 0x40c72493), X64Word_create(0x3c9ebe0a, 0x15c9bebc), X64Word_create(0x431d67c4, 0x9c100d4c), X64Word_create(0x4cc5d4be, 0xcb3e42b6), X64Word_create(0x597f299c, 0xfc657e2a), X64Word_create(0x5fcb6fab, 0x3ad6faec), X64Word_create(0x6c44198c, 0x4a475817) ]; // Reusable objects var W = []; (function () { for (var i = 0; i < 80; i++) { W[i] = X64Word_create(); } }()); /** * SHA-512 hash algorithm. */ var SHA512 = C_algo.SHA512 = Hasher.extend({ _doReset: function () { this._hash = new X64WordArray.init([ new X64Word.init(0x6a09e667, 0xf3bcc908), new X64Word.init(0xbb67ae85, 0x84caa73b), new X64Word.init(0x3c6ef372, 0xfe94f82b), new X64Word.init(0xa54ff53a, 0x5f1d36f1), new X64Word.init(0x510e527f, 0xade682d1), new X64Word.init(0x9b05688c, 0x2b3e6c1f), new X64Word.init(0x1f83d9ab, 0xfb41bd6b), new X64Word.init(0x5be0cd19, 0x137e2179) ]); }, _doProcessBlock: function (M, offset) { // Shortcuts var H = this._hash.words; var H0 = H[0]; var H1 = H[1]; var H2 = H[2]; var H3 = H[3]; var H4 = H[4]; var H5 = H[5]; var H6 = H[6]; var H7 = H[7]; var H0h = H0.high; var H0l = H0.low; var H1h = H1.high; var H1l = H1.low; var H2h = H2.high; var H2l = H2.low; var H3h = H3.high; var H3l = H3.low; var H4h = H4.high; var H4l = H4.low; var H5h = H5.high; var H5l = H5.low; var H6h = H6.high; var H6l = H6.low; var H7h = H7.high; var H7l = H7.low; // Working variables var ah = H0h; var al = H0l; var bh = H1h; var bl = H1l; var ch = H2h; var cl = H2l; var dh = H3h; var dl = H3l; var eh = H4h; var el = H4l; var fh = H5h; var fl = H5l; var gh = H6h; var gl = H6l; var hh = H7h; var hl = H7l; // Rounds for (var i = 0; i < 80; i++) { // Shortcut var Wi = W[i]; // Extend message if (i < 16) { var Wih = Wi.high = M[offset + i * 2] | 0; var Wil = Wi.low = M[offset + i * 2 + 1] | 0; } else { // Gamma0 var gamma0x = W[i - 15]; var gamma0xh = gamma0x.high; var gamma0xl = gamma0x.low; var gamma0h = ((gamma0xh >>> 1) | (gamma0xl << 31)) ^ ((gamma0xh >>> 8) | (gamma0xl << 24)) ^ (gamma0xh >>> 7); var gamma0l = ((gamma0xl >>> 1) | (gamma0xh << 31)) ^ ((gamma0xl >>> 8) | (gamma0xh << 24)) ^ ((gamma0xl >>> 7) | (gamma0xh << 25)); // Gamma1 var gamma1x = W[i - 2]; var gamma1xh = gamma1x.high; var gamma1xl = gamma1x.low; var gamma1h = ((gamma1xh >>> 19) | (gamma1xl << 13)) ^ ((gamma1xh << 3) | (gamma1xl >>> 29)) ^ (gamma1xh >>> 6); var gamma1l = ((gamma1xl >>> 19) | (gamma1xh << 13)) ^ ((gamma1xl << 3) | (gamma1xh >>> 29)) ^ ((gamma1xl >>> 6) | (gamma1xh << 26)); // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16] var Wi7 = W[i - 7]; var Wi7h = Wi7.high; var Wi7l = Wi7.low; var Wi16 = W[i - 16]; var Wi16h = Wi16.high; var Wi16l = Wi16.low; var Wil = gamma0l + Wi7l; var Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0); var Wil = Wil + gamma1l; var Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0); var Wil = Wil + Wi16l; var Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0); Wi.high = Wih; Wi.low = Wil; } var chh = (eh & fh) ^ (~eh & gh); var chl = (el & fl) ^ (~el & gl); var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch); var majl = (al & bl) ^ (al & cl) ^ (bl & cl); var sigma0h = ((ah >>> 28) | (al << 4)) ^ ((ah << 30) | (al >>> 2)) ^ ((ah << 25) | (al >>> 7)); var sigma0l = ((al >>> 28) | (ah << 4)) ^ ((al << 30) | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7)); var sigma1h = ((eh >>> 14) | (el << 18)) ^ ((eh >>> 18) | (el << 14)) ^ ((eh << 23) | (el >>> 9)); var sigma1l = ((el >>> 14) | (eh << 18)) ^ ((el >>> 18) | (eh << 14)) ^ ((el << 23) | (eh >>> 9)); // t1 = h + sigma1 + ch + K[i] + W[i] var Ki = K[i]; var Kih = Ki.high; var Kil = Ki.low; var t1l = hl + sigma1l; var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0); var t1l = t1l + chl; var t1h = t1h + chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0); var t1l = t1l + Kil; var t1h = t1h + Kih + ((t1l >>> 0) < (Kil >>> 0) ? 1 : 0); var t1l = t1l + Wil; var t1h = t1h + Wih + ((t1l >>> 0) < (Wil >>> 0) ? 1 : 0); // t2 = sigma0 + maj var t2l = sigma0l + majl; var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0); // Update working variables hh = gh; hl = gl; gh = fh; gl = fl; fh = eh; fl = el; el = (dl + t1l) | 0; eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0; dh = ch; dl = cl; ch = bh; cl = bl; bh = ah; bl = al; al = (t1l + t2l) | 0; ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0; } // Intermediate hash value H0l = H0.low = (H0l + al); H0.high = (H0h + ah + ((H0l >>> 0) < (al >>> 0) ? 1 : 0)); H1l = H1.low = (H1l + bl); H1.high = (H1h + bh + ((H1l >>> 0) < (bl >>> 0) ? 1 : 0)); H2l = H2.low = (H2l + cl); H2.high = (H2h + ch + ((H2l >>> 0) < (cl >>> 0) ? 1 : 0)); H3l = H3.low = (H3l + dl); H3.high = (H3h + dh + ((H3l >>> 0) < (dl >>> 0) ? 1 : 0)); H4l = H4.low = (H4l + el); H4.high = (H4h + eh + ((H4l >>> 0) < (el >>> 0) ? 1 : 0)); H5l = H5.low = (H5l + fl); H5.high = (H5h + fh + ((H5l >>> 0) < (fl >>> 0) ? 1 : 0)); H6l = H6.low = (H6l + gl); H6.high = (H6h + gh + ((H6l >>> 0) < (gl >>> 0) ? 1 : 0)); H7l = H7.low = (H7l + hl); H7.high = (H7h + hh + ((H7l >>> 0) < (hl >>> 0) ? 1 : 0)); }, _doFinalize: function () { // Shortcuts var data = this._data; var dataWords = data.words; var nBitsTotal = this._nDataBytes * 8; var nBitsLeft = data.sigBytes * 8; // Add padding dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 30] = Math.floor(nBitsTotal / 0x100000000); dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 31] = nBitsTotal; data.sigBytes = dataWords.length * 4; // Hash final blocks this._process(); // Convert hash to 32-bit word array before returning var hash = this._hash.toX32(); // Return final computed hash return hash; }, clone: function () { var clone = Hasher.clone.call(this); clone._hash = this._hash.clone(); return clone; }, blockSize: 1024/32 }); /** * Shortcut function to the hasher's object interface. * * @param {WordArray|string} message The message to hash. * * @return {WordArray} The hash. * * @static * * @example * * var hash = CryptoJS.SHA512('message'); * var hash = CryptoJS.SHA512(wordArray); */ C.SHA512 = Hasher._createHelper(SHA512); /** * Shortcut function to the HMAC's object interface. * * @param {WordArray|string} message The message to hash. * @param {WordArray|string} key The secret key. * * @return {WordArray} The HMAC. * * @static * * @example * * var hmac = CryptoJS.HmacSHA512(message, key); */ C.HmacSHA512 = Hasher._createHmacHelper(SHA512); }()); /*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ */ var b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var b64pad="="; function hex2b64(h) { var i; var c; var ret = ""; for(i = 0; i+3 <= h.length; i+=3) { c = parseInt(h.substring(i,i+3),16); ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63); } if(i+1 == h.length) { c = parseInt(h.substring(i,i+1),16); ret += b64map.charAt(c << 2); } else if(i+2 == h.length) { c = parseInt(h.substring(i,i+2),16); ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4); } if (b64pad) while((ret.length & 3) > 0) ret += b64pad; return ret; } // convert a base64 string to hex function b64tohex(s) { var ret = "" var i; var k = 0; // b64 state, 0-3 var slop; var v; for(i = 0; i < s.length; ++i) { if(s.charAt(i) == b64pad) break; v = b64map.indexOf(s.charAt(i)); if(v < 0) continue; if(k == 0) { ret += int2char(v >> 2); slop = v & 3; k = 1; } else if(k == 1) { ret += int2char((slop << 2) | (v >> 4)); slop = v & 0xf; k = 2; } else if(k == 2) { ret += int2char(slop); ret += int2char(v >> 2); slop = v & 3; k = 3; } else { ret += int2char((slop << 2) | (v >> 4)); ret += int2char(v & 0xf); k = 0; } } if(k == 1) ret += int2char(slop << 2); return ret; } // convert a base64 string to a byte/number array function b64toBA(s) { //piggyback on b64tohex for now, optimize later var h = b64tohex(s); var i; var a = new Array(); for(i = 0; 2*i < h.length; ++i) { a[i] = parseInt(h.substring(2*i,2*i+2),16); } return a; } /*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ */ // Copyright (c) 2005 Tom Wu // All Rights Reserved. // See "LICENSE" for details. // Basic JavaScript BN library - subset useful for RSA encryption. // Bits per digit var dbits; // JavaScript engine analysis var canary = 0xdeadbeefcafe; var j_lm = ((canary&0xffffff)==0xefcafe); // (public) Constructor function BigInteger(a,b,c) { if(a != null) if("number" == typeof a) this.fromNumber(a,b,c); else if(b == null && "string" != typeof a) this.fromString(a,256); else this.fromString(a,b); } // return new, unset BigInteger function nbi() { return new BigInteger(null); } // am: Compute w_j += (x*this_i), propagate carries, // c is initial carry, returns final carry. // c < 3*dvalue, x < 2*dvalue, this_i < dvalue // We need to select the fastest one that works in this environment. // am1: use a single mult and divide to get the high bits, // max digit bits should be 26 because // max internal value = 2*dvalue^2-2*dvalue (< 2^53) function am1(i,x,w,j,c,n) { while(--n >= 0) { var v = x*this[i++]+w[j]+c; c = Math.floor(v/0x4000000); w[j++] = v&0x3ffffff; } return c; } // am2 avoids a big mult-and-extract completely. // Max digit bits should be <= 30 because we do bitwise ops // on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) function am2(i,x,w,j,c,n) { var xl = x&0x7fff, xh = x>>15; while(--n >= 0) { var l = this[i]&0x7fff; var h = this[i++]>>15; var m = xh*l+h*xl; l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff); c = (l>>>30)+(m>>>15)+xh*h+(c>>>30); w[j++] = l&0x3fffffff; } return c; } // Alternately, set max digit bits to 28 since some // browsers slow down when dealing with 32-bit numbers. function am3(i,x,w,j,c,n) { var xl = x&0x3fff, xh = x>>14; while(--n >= 0) { var l = this[i]&0x3fff; var h = this[i++]>>14; var m = xh*l+h*xl; l = xl*l+((m&0x3fff)<<14)+w[j]+c; c = (l>>28)+(m>>14)+xh*h; w[j++] = l&0xfffffff; } return c; } if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) { BigInteger.prototype.am = am2; dbits = 30; } else if(j_lm && (navigator.appName != "Netscape")) { BigInteger.prototype.am = am1; dbits = 26; } else { // Mozilla/Netscape seems to prefer am3 BigInteger.prototype.am = am3; dbits = 28; } BigInteger.prototype.DB = dbits; BigInteger.prototype.DM = ((1<= 0; --i) r[i] = this[i]; r.t = this.t; r.s = this.s; } // (protected) set from integer value x, -DV <= x < DV function bnpFromInt(x) { this.t = 1; this.s = (x<0)?-1:0; if(x > 0) this[0] = x; else if(x < -1) this[0] = x+this.DV; else this.t = 0; } // return bigint initialized to value function nbv(i) { var r = nbi(); r.fromInt(i); return r; } // (protected) set from string and radix function bnpFromString(s,b) { var k; if(b == 16) k = 4; else if(b == 8) k = 3; else if(b == 256) k = 8; // byte array else if(b == 2) k = 1; else if(b == 32) k = 5; else if(b == 4) k = 2; else { this.fromRadix(s,b); return; } this.t = 0; this.s = 0; var i = s.length, mi = false, sh = 0; while(--i >= 0) { var x = (k==8)?s[i]&0xff:intAt(s,i); if(x < 0) { if(s.charAt(i) == "-") mi = true; continue; } mi = false; if(sh == 0) this[this.t++] = x; else if(sh+k > this.DB) { this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<>(this.DB-sh)); } else this[this.t-1] |= x<= this.DB) sh -= this.DB; } if(k == 8 && (s[0]&0x80) != 0) { this.s = -1; if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)< 0 && this[this.t-1] == c) --this.t; } // (public) return string representation in given radix function bnToString(b) { if(this.s < 0) return "-"+this.negate().toString(b); var k; if(b == 16) k = 4; else if(b == 8) k = 3; else if(b == 2) k = 1; else if(b == 32) k = 5; else if(b == 4) k = 2; else return this.toRadix(b); var km = (1< 0) { if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); } while(i >= 0) { if(p < k) { d = (this[i]&((1<>(p+=this.DB-k); } else { d = (this[i]>>(p-=k))&km; if(p <= 0) { p += this.DB; --i; } } if(d > 0) m = true; if(m) r += int2char(d); } } return m?r:"0"; } // (public) -this function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; } // (public) |this| function bnAbs() { return (this.s<0)?this.negate():this; } // (public) return + if this > a, - if this < a, 0 if equal function bnCompareTo(a) { var r = this.s-a.s; if(r != 0) return r; var i = this.t; r = i-a.t; if(r != 0) return (this.s<0)?-r:r; while(--i >= 0) if((r=this[i]-a[i]) != 0) return r; return 0; } // returns bit length of the integer x function nbits(x) { var r = 1, t; if((t=x>>>16) != 0) { x = t; r += 16; } if((t=x>>8) != 0) { x = t; r += 8; } if((t=x>>4) != 0) { x = t; r += 4; } if((t=x>>2) != 0) { x = t; r += 2; } if((t=x>>1) != 0) { x = t; r += 1; } return r; } // (public) return the number of bits in "this" function bnBitLength() { if(this.t <= 0) return 0; return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM)); } // (protected) r = this << n*DB function bnpDLShiftTo(n,r) { var i; for(i = this.t-1; i >= 0; --i) r[i+n] = this[i]; for(i = n-1; i >= 0; --i) r[i] = 0; r.t = this.t+n; r.s = this.s; } // (protected) r = this >> n*DB function bnpDRShiftTo(n,r) { for(var i = n; i < this.t; ++i) r[i-n] = this[i]; r.t = Math.max(this.t-n,0); r.s = this.s; } // (protected) r = this << n function bnpLShiftTo(n,r) { var bs = n%this.DB; var cbs = this.DB-bs; var bm = (1<= 0; --i) { r[i+ds+1] = (this[i]>>cbs)|c; c = (this[i]&bm)<= 0; --i) r[i] = 0; r[ds] = c; r.t = this.t+ds+1; r.s = this.s; r.clamp(); } // (protected) r = this >> n function bnpRShiftTo(n,r) { r.s = this.s; var ds = Math.floor(n/this.DB); if(ds >= this.t) { r.t = 0; return; } var bs = n%this.DB; var cbs = this.DB-bs; var bm = (1<>bs; for(var i = ds+1; i < this.t; ++i) { r[i-ds-1] |= (this[i]&bm)<>bs; } if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<>= this.DB; } if(a.t < this.t) { c -= a.s; while(i < this.t) { c += this[i]; r[i++] = c&this.DM; c >>= this.DB; } c += this.s; } else { c += this.s; while(i < a.t) { c -= a[i]; r[i++] = c&this.DM; c >>= this.DB; } c -= a.s; } r.s = (c<0)?-1:0; if(c < -1) r[i++] = this.DV+c; else if(c > 0) r[i++] = c; r.t = i; r.clamp(); } // (protected) r = this * a, r != this,a (HAC 14.12) // "this" should be the larger one if appropriate. function bnpMultiplyTo(a,r) { var x = this.abs(), y = a.abs(); var i = x.t; r.t = i+y.t; while(--i >= 0) r[i] = 0; for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t); r.s = 0; r.clamp(); if(this.s != a.s) BigInteger.ZERO.subTo(r,r); } // (protected) r = this^2, r != this (HAC 14.16) function bnpSquareTo(r) { var x = this.abs(); var i = r.t = 2*x.t; while(--i >= 0) r[i] = 0; for(i = 0; i < x.t-1; ++i) { var c = x.am(i,x[i],r,2*i,0,1); if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) { r[i+x.t] -= x.DV; r[i+x.t+1] = 1; } } if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1); r.s = 0; r.clamp(); } // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) // r != q, this != m. q or r may be null. function bnpDivRemTo(m,q,r) { var pm = m.abs(); if(pm.t <= 0) return; var pt = this.abs(); if(pt.t < pm.t) { if(q != null) q.fromInt(0); if(r != null) this.copyTo(r); return; } if(r == null) r = nbi(); var y = nbi(), ts = this.s, ms = m.s; var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); } else { pm.copyTo(y); pt.copyTo(r); } var ys = y.t; var y0 = y[ys-1]; if(y0 == 0) return; var yt = y0*(1<1)?y[ys-2]>>this.F2:0); var d1 = this.FV/yt, d2 = (1<= 0) { r[r.t++] = 1; r.subTo(t,r); } BigInteger.ONE.dlShiftTo(ys,t); t.subTo(y,y); // "negative" y so we can replace sub with am later while(y.t < ys) y[y.t++] = 0; while(--j >= 0) { // Estimate quotient digit var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2); if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out y.dlShiftTo(j,t); r.subTo(t,r); while(r[i] < --qd) r.subTo(t,r); } } if(q != null) { r.drShiftTo(ys,q); if(ts != ms) BigInteger.ZERO.subTo(q,q); } r.t = ys; r.clamp(); if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder if(ts < 0) BigInteger.ZERO.subTo(r,r); } // (public) this mod a function bnMod(a) { var r = nbi(); this.abs().divRemTo(a,null,r); if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r); return r; } // Modular reduction using "classic" algorithm function Classic(m) { this.m = m; } function cConvert(x) { if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); else return x; } function cRevert(x) { return x; } function cReduce(x) { x.divRemTo(this.m,null,x); } function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); } Classic.prototype.convert = cConvert; Classic.prototype.revert = cRevert; Classic.prototype.reduce = cReduce; Classic.prototype.mulTo = cMulTo; Classic.prototype.sqrTo = cSqrTo; // (protected) return "-1/this % 2^DB"; useful for Mont. reduction // justification: // xy == 1 (mod m) // xy = 1+km // xy(2-xy) = (1+km)(1-km) // x[y(2-xy)] = 1-k^2m^2 // x[y(2-xy)] == 1 (mod m^2) // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 // should reduce x and y(2-xy) by m^2 at each step to keep size bounded. // JS multiply "overflows" differently from C/C++, so care is needed here. function bnpInvDigit() { if(this.t < 1) return 0; var x = this[0]; if((x&1) == 0) return 0; var y = x&3; // y == 1/x mod 2^2 y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4 y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8 y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16 // last step - calculate inverse mod DV directly; // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits // we really want the negative inverse, and -DV < y < DV return (y>0)?this.DV-y:-y; } // Montgomery reduction function Montgomery(m) { this.m = m; this.mp = m.invDigit(); this.mpl = this.mp&0x7fff; this.mph = this.mp>>15; this.um = (1<<(m.DB-15))-1; this.mt2 = 2*m.t; } // xR mod m function montConvert(x) { var r = nbi(); x.abs().dlShiftTo(this.m.t,r); r.divRemTo(this.m,null,r); if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r); return r; } // x/R mod m function montRevert(x) { var r = nbi(); x.copyTo(r); this.reduce(r); return r; } // x = x/R mod m (HAC 14.32) function montReduce(x) { while(x.t <= this.mt2) // pad x so am has enough room later x[x.t++] = 0; for(var i = 0; i < this.m.t; ++i) { // faster way of calculating u0 = x[i]*mp mod DV var j = x[i]&0x7fff; var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM; // use am to combine the multiply-shift-add into one call j = i+this.m.t; x[j] += this.m.am(0,u0,x,i,0,this.m.t); // propagate carry while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; } } x.clamp(); x.drShiftTo(this.m.t,x); if(x.compareTo(this.m) >= 0) x.subTo(this.m,x); } // r = "x^2/R mod m"; x != r function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); } // r = "xy/R mod m"; x,y != r function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } Montgomery.prototype.convert = montConvert; Montgomery.prototype.revert = montRevert; Montgomery.prototype.reduce = montReduce; Montgomery.prototype.mulTo = montMulTo; Montgomery.prototype.sqrTo = montSqrTo; // (protected) true iff this is even function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; } // (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) function bnpExp(e,z) { if(e > 0xffffffff || e < 1) return BigInteger.ONE; var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1; g.copyTo(r); while(--i >= 0) { z.sqrTo(r,r2); if((e&(1< 0) z.mulTo(r2,g,r); else { var t = r; r = r2; r2 = t; } } return z.revert(r); } // (public) this^e % m, 0 <= e < 2^32 function bnModPowInt(e,m) { var z; if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); return this.exp(e,z); } // protected BigInteger.prototype.copyTo = bnpCopyTo; BigInteger.prototype.fromInt = bnpFromInt; BigInteger.prototype.fromString = bnpFromString; BigInteger.prototype.clamp = bnpClamp; BigInteger.prototype.dlShiftTo = bnpDLShiftTo; BigInteger.prototype.drShiftTo = bnpDRShiftTo; BigInteger.prototype.lShiftTo = bnpLShiftTo; BigInteger.prototype.rShiftTo = bnpRShiftTo; BigInteger.prototype.subTo = bnpSubTo; BigInteger.prototype.multiplyTo = bnpMultiplyTo; BigInteger.prototype.squareTo = bnpSquareTo; BigInteger.prototype.divRemTo = bnpDivRemTo; BigInteger.prototype.invDigit = bnpInvDigit; BigInteger.prototype.isEven = bnpIsEven; BigInteger.prototype.exp = bnpExp; // public BigInteger.prototype.toString = bnToString; BigInteger.prototype.negate = bnNegate; BigInteger.prototype.abs = bnAbs; BigInteger.prototype.compareTo = bnCompareTo; BigInteger.prototype.bitLength = bnBitLength; BigInteger.prototype.mod = bnMod; BigInteger.prototype.modPowInt = bnModPowInt; // "constants" BigInteger.ZERO = nbv(0); BigInteger.ONE = nbv(1); /*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ */ // Copyright (c) 2005-2009 Tom Wu // All Rights Reserved. // See "LICENSE" for details. // Extended JavaScript BN functions, required for RSA private ops. // Version 1.1: new BigInteger("0", 10) returns "proper" zero // Version 1.2: square() API, isProbablePrime fix // (public) function bnClone() { var r = nbi(); this.copyTo(r); return r; } // (public) return value as integer function bnIntValue() { if(this.s < 0) { if(this.t == 1) return this[0]-this.DV; else if(this.t == 0) return -1; } else if(this.t == 1) return this[0]; else if(this.t == 0) return 0; // assumes 16 < DB < 32 return ((this[1]&((1<<(32-this.DB))-1))<>24; } // (public) return value as short (assumes DB>=16) function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; } // (protected) return x s.t. r^x < DV function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); } // (public) 0 if this == 0, 1 if this > 0 function bnSigNum() { if(this.s < 0) return -1; else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0; else return 1; } // (protected) convert to radix string function bnpToRadix(b) { if(b == null) b = 10; if(this.signum() == 0 || b < 2 || b > 36) return "0"; var cs = this.chunkSize(b); var a = Math.pow(b,cs); var d = nbv(a), y = nbi(), z = nbi(), r = ""; this.divRemTo(d,y,z); while(y.signum() > 0) { r = (a+z.intValue()).toString(b).substr(1) + r; y.divRemTo(d,y,z); } return z.intValue().toString(b) + r; } // (protected) convert from radix string function bnpFromRadix(s,b) { this.fromInt(0); if(b == null) b = 10; var cs = this.chunkSize(b); var d = Math.pow(b,cs), mi = false, j = 0, w = 0; for(var i = 0; i < s.length; ++i) { var x = intAt(s,i); if(x < 0) { if(s.charAt(i) == "-" && this.signum() == 0) mi = true; continue; } w = b*w+x; if(++j >= cs) { this.dMultiply(d); this.dAddOffset(w,0); j = 0; w = 0; } } if(j > 0) { this.dMultiply(Math.pow(b,j)); this.dAddOffset(w,0); } if(mi) BigInteger.ZERO.subTo(this,this); } // (protected) alternate constructor function bnpFromNumber(a,b,c) { if("number" == typeof b) { // new BigInteger(int,int,RNG) if(a < 2) this.fromInt(1); else { this.fromNumber(a,c); if(!this.testBit(a-1)) // force MSB set this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this); if(this.isEven()) this.dAddOffset(1,0); // force odd while(!this.isProbablePrime(b)) { this.dAddOffset(2,0); if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this); } } } else { // new BigInteger(int,RNG) var x = new Array(), t = a&7; x.length = (a>>3)+1; b.nextBytes(x); if(t > 0) x[0] &= ((1< 0) { if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p) r[k++] = d|(this.s<<(this.DB-p)); while(i >= 0) { if(p < 8) { d = (this[i]&((1<>(p+=this.DB-8); } else { d = (this[i]>>(p-=8))&0xff; if(p <= 0) { p += this.DB; --i; } } if((d&0x80) != 0) d |= -256; if(k == 0 && (this.s&0x80) != (d&0x80)) ++k; if(k > 0 || d != this.s) r[k++] = d; } } return r; } function bnEquals(a) { return(this.compareTo(a)==0); } function bnMin(a) { return(this.compareTo(a)<0)?this:a; } function bnMax(a) { return(this.compareTo(a)>0)?this:a; } // (protected) r = this op a (bitwise) function bnpBitwiseTo(a,op,r) { var i, f, m = Math.min(a.t,this.t); for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]); if(a.t < this.t) { f = a.s&this.DM; for(i = m; i < this.t; ++i) r[i] = op(this[i],f); r.t = this.t; } else { f = this.s&this.DM; for(i = m; i < a.t; ++i) r[i] = op(f,a[i]); r.t = a.t; } r.s = op(this.s,a.s); r.clamp(); } // (public) this & a function op_and(x,y) { return x&y; } function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; } // (public) this | a function op_or(x,y) { return x|y; } function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; } // (public) this ^ a function op_xor(x,y) { return x^y; } function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; } // (public) this & ~a function op_andnot(x,y) { return x&~y; } function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; } // (public) ~this function bnNot() { var r = nbi(); for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i]; r.t = this.t; r.s = ~this.s; return r; } // (public) this << n function bnShiftLeft(n) { var r = nbi(); if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r); return r; } // (public) this >> n function bnShiftRight(n) { var r = nbi(); if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r); return r; } // return index of lowest 1-bit in x, x < 2^31 function lbit(x) { if(x == 0) return -1; var r = 0; if((x&0xffff) == 0) { x >>= 16; r += 16; } if((x&0xff) == 0) { x >>= 8; r += 8; } if((x&0xf) == 0) { x >>= 4; r += 4; } if((x&3) == 0) { x >>= 2; r += 2; } if((x&1) == 0) ++r; return r; } // (public) returns index of lowest 1-bit (or -1 if none) function bnGetLowestSetBit() { for(var i = 0; i < this.t; ++i) if(this[i] != 0) return i*this.DB+lbit(this[i]); if(this.s < 0) return this.t*this.DB; return -1; } // return number of 1 bits in x function cbit(x) { var r = 0; while(x != 0) { x &= x-1; ++r; } return r; } // (public) return number of set bits function bnBitCount() { var r = 0, x = this.s&this.DM; for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x); return r; } // (public) true iff nth bit is set function bnTestBit(n) { var j = Math.floor(n/this.DB); if(j >= this.t) return(this.s!=0); return((this[j]&(1<<(n%this.DB)))!=0); } // (protected) this op (1<>= this.DB; } if(a.t < this.t) { c += a.s; while(i < this.t) { c += this[i]; r[i++] = c&this.DM; c >>= this.DB; } c += this.s; } else { c += this.s; while(i < a.t) { c += a[i]; r[i++] = c&this.DM; c >>= this.DB; } c += a.s; } r.s = (c<0)?-1:0; if(c > 0) r[i++] = c; else if(c < -1) r[i++] = this.DV+c; r.t = i; r.clamp(); } // (public) this + a function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; } // (public) this - a function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; } // (public) this * a function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; } // (public) this^2 function bnSquare() { var r = nbi(); this.squareTo(r); return r; } // (public) this / a function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; } // (public) this % a function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; } // (public) [this/a,this%a] function bnDivideAndRemainder(a) { var q = nbi(), r = nbi(); this.divRemTo(a,q,r); return new Array(q,r); } // (protected) this *= n, this >= 0, 1 < n < DV function bnpDMultiply(n) { this[this.t] = this.am(0,n-1,this,0,0,this.t); ++this.t; this.clamp(); } // (protected) this += n << w words, this >= 0 function bnpDAddOffset(n,w) { if(n == 0) return; while(this.t <= w) this[this.t++] = 0; this[w] += n; while(this[w] >= this.DV) { this[w] -= this.DV; if(++w >= this.t) this[this.t++] = 0; ++this[w]; } } // A "null" reducer function NullExp() {} function nNop(x) { return x; } function nMulTo(x,y,r) { x.multiplyTo(y,r); } function nSqrTo(x,r) { x.squareTo(r); } NullExp.prototype.convert = nNop; NullExp.prototype.revert = nNop; NullExp.prototype.mulTo = nMulTo; NullExp.prototype.sqrTo = nSqrTo; // (public) this^e function bnPow(e) { return this.exp(e,new NullExp()); } // (protected) r = lower n words of "this * a", a.t <= n // "this" should be the larger one if appropriate. function bnpMultiplyLowerTo(a,n,r) { var i = Math.min(this.t+a.t,n); r.s = 0; // assumes a,this >= 0 r.t = i; while(i > 0) r[--i] = 0; var j; for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t); for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i); r.clamp(); } // (protected) r = "this * a" without lower n words, n > 0 // "this" should be the larger one if appropriate. function bnpMultiplyUpperTo(a,n,r) { --n; var i = r.t = this.t+a.t-n; r.s = 0; // assumes a,this >= 0 while(--i >= 0) r[i] = 0; for(i = Math.max(n-this.t,0); i < a.t; ++i) r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n); r.clamp(); r.drShiftTo(1,r); } // Barrett modular reduction function Barrett(m) { // setup Barrett this.r2 = nbi(); this.q3 = nbi(); BigInteger.ONE.dlShiftTo(2*m.t,this.r2); this.mu = this.r2.divide(m); this.m = m; } function barrettConvert(x) { if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m); else if(x.compareTo(this.m) < 0) return x; else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; } } function barrettRevert(x) { return x; } // x = x mod m (HAC 14.42) function barrettReduce(x) { x.drShiftTo(this.m.t-1,this.r2); if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); } this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3); this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2); while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1); x.subTo(this.r2,x); while(x.compareTo(this.m) >= 0) x.subTo(this.m,x); } // r = x^2 mod m; x != r function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); } // r = x*y mod m; x,y != r function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } Barrett.prototype.convert = barrettConvert; Barrett.prototype.revert = barrettRevert; Barrett.prototype.reduce = barrettReduce; Barrett.prototype.mulTo = barrettMulTo; Barrett.prototype.sqrTo = barrettSqrTo; // (public) this^e % m (HAC 14.85) function bnModPow(e,m) { var i = e.bitLength(), k, r = nbv(1), z; if(i <= 0) return r; else if(i < 18) k = 1; else if(i < 48) k = 3; else if(i < 144) k = 4; else if(i < 768) k = 5; else k = 6; if(i < 8) z = new Classic(m); else if(m.isEven()) z = new Barrett(m); else z = new Montgomery(m); // precomputation var g = new Array(), n = 3, k1 = k-1, km = (1< 1) { var g2 = nbi(); z.sqrTo(g[1],g2); while(n <= km) { g[n] = nbi(); z.mulTo(g2,g[n-2],g[n]); n += 2; } } var j = e.t-1, w, is1 = true, r2 = nbi(), t; i = nbits(e[j])-1; while(j >= 0) { if(i >= k1) w = (e[j]>>(i-k1))&km; else { w = (e[j]&((1<<(i+1))-1))<<(k1-i); if(j > 0) w |= e[j-1]>>(this.DB+i-k1); } n = k; while((w&1) == 0) { w >>= 1; --n; } if((i -= n) < 0) { i += this.DB; --j; } if(is1) { // ret == 1, don't bother squaring or multiplying it g[w].copyTo(r); is1 = false; } else { while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; } if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; } z.mulTo(r2,g[w],r); } while(j >= 0 && (e[j]&(1< 0) { x.rShiftTo(g,x); y.rShiftTo(g,y); } while(x.signum() > 0) { if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x); if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y); if(x.compareTo(y) >= 0) { x.subTo(y,x); x.rShiftTo(1,x); } else { y.subTo(x,y); y.rShiftTo(1,y); } } if(g > 0) y.lShiftTo(g,y); return y; } // (protected) this % n, n < 2^26 function bnpModInt(n) { if(n <= 0) return 0; var d = this.DV%n, r = (this.s<0)?n-1:0; if(this.t > 0) if(d == 0) r = this[0]%n; else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n; return r; } // (public) 1/this % m (HAC 14.61) function bnModInverse(m) { var ac = m.isEven(); if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO; var u = m.clone(), v = this.clone(); var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1); while(u.signum() != 0) { while(u.isEven()) { u.rShiftTo(1,u); if(ac) { if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); } a.rShiftTo(1,a); } else if(!b.isEven()) b.subTo(m,b); b.rShiftTo(1,b); } while(v.isEven()) { v.rShiftTo(1,v); if(ac) { if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); } c.rShiftTo(1,c); } else if(!d.isEven()) d.subTo(m,d); d.rShiftTo(1,d); } if(u.compareTo(v) >= 0) { u.subTo(v,u); if(ac) a.subTo(c,a); b.subTo(d,b); } else { v.subTo(u,v); if(ac) c.subTo(a,c); d.subTo(b,d); } } if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO; if(d.compareTo(m) >= 0) return d.subtract(m); if(d.signum() < 0) d.addTo(m,d); else return d; if(d.signum() < 0) return d.add(m); else return d; } var 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,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997]; var lplim = (1<<26)/lowprimes[lowprimes.length-1]; // (public) test primality with certainty >= 1-.5^t function bnIsProbablePrime(t) { var i, x = this.abs(); if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) { for(i = 0; i < lowprimes.length; ++i) if(x[0] == lowprimes[i]) return true; return false; } if(x.isEven()) return false; i = 1; while(i < lowprimes.length) { var m = lowprimes[i], j = i+1; while(j < lowprimes.length && m < lplim) m *= lowprimes[j++]; m = x.modInt(m); while(i < j) if(m%lowprimes[i++] == 0) return false; } return x.millerRabin(t); } // (protected) true if probably prime (HAC 4.24, Miller-Rabin) function bnpMillerRabin(t) { var n1 = this.subtract(BigInteger.ONE); var k = n1.getLowestSetBit(); if(k <= 0) return false; var r = n1.shiftRight(k); t = (t+1)>>1; if(t > lowprimes.length) t = lowprimes.length; var a = nbi(); for(var i = 0; i < t; ++i) { //Pick bases at random, instead of starting at 2 a.fromInt(lowprimes[Math.floor(Math.random()*lowprimes.length)]); var y = a.modPow(r,this); if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) { var j = 1; while(j++ < k && y.compareTo(n1) != 0) { y = y.modPowInt(2,this); if(y.compareTo(BigInteger.ONE) == 0) return false; } if(y.compareTo(n1) != 0) return false; } } return true; } // protected BigInteger.prototype.chunkSize = bnpChunkSize; BigInteger.prototype.toRadix = bnpToRadix; BigInteger.prototype.fromRadix = bnpFromRadix; BigInteger.prototype.fromNumber = bnpFromNumber; BigInteger.prototype.bitwiseTo = bnpBitwiseTo; BigInteger.prototype.changeBit = bnpChangeBit; BigInteger.prototype.addTo = bnpAddTo; BigInteger.prototype.dMultiply = bnpDMultiply; BigInteger.prototype.dAddOffset = bnpDAddOffset; BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo; BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo; BigInteger.prototype.modInt = bnpModInt; BigInteger.prototype.millerRabin = bnpMillerRabin; // public BigInteger.prototype.clone = bnClone; BigInteger.prototype.intValue = bnIntValue; BigInteger.prototype.byteValue = bnByteValue; BigInteger.prototype.shortValue = bnShortValue; BigInteger.prototype.signum = bnSigNum; BigInteger.prototype.toByteArray = bnToByteArray; BigInteger.prototype.equals = bnEquals; BigInteger.prototype.min = bnMin; BigInteger.prototype.max = bnMax; BigInteger.prototype.and = bnAnd; BigInteger.prototype.or = bnOr; BigInteger.prototype.xor = bnXor; BigInteger.prototype.andNot = bnAndNot; BigInteger.prototype.not = bnNot; BigInteger.prototype.shiftLeft = bnShiftLeft; BigInteger.prototype.shiftRight = bnShiftRight; BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit; BigInteger.prototype.bitCount = bnBitCount; BigInteger.prototype.testBit = bnTestBit; BigInteger.prototype.setBit = bnSetBit; BigInteger.prototype.clearBit = bnClearBit; BigInteger.prototype.flipBit = bnFlipBit; BigInteger.prototype.add = bnAdd; BigInteger.prototype.subtract = bnSubtract; BigInteger.prototype.multiply = bnMultiply; BigInteger.prototype.divide = bnDivide; BigInteger.prototype.remainder = bnRemainder; BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder; BigInteger.prototype.modPow = bnModPow; BigInteger.prototype.modInverse = bnModInverse; BigInteger.prototype.pow = bnPow; BigInteger.prototype.gcd = bnGCD; BigInteger.prototype.isProbablePrime = bnIsProbablePrime; // JSBN-specific extension BigInteger.prototype.square = bnSquare; // BigInteger interfaces not implemented in jsbn: // BigInteger(int signum, byte[] magnitude) // double doubleValue() // float floatValue() // int hashCode() // long longValue() // static BigInteger valueOf(long val) /*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ */ // Depends on jsbn.js and rng.js // Version 1.1: support utf-8 encoding in pkcs1pad2 // convert a (hex) string to a bignum object function parseBigInt(str,r) { return new BigInteger(str,r); } function linebrk(s,n) { var ret = ""; var i = 0; while(i + n < s.length) { ret += s.substring(i,i+n) + "\n"; i += n; } return ret + s.substring(i,s.length); } function byte2Hex(b) { if(b < 0x10) return "0" + b.toString(16); else return b.toString(16); } // PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint function pkcs1pad2(s,n) { if(n < s.length + 11) { // TODO: fix for utf-8 alert("Message too long for RSA"); return null; } var ba = new Array(); var i = s.length - 1; while(i >= 0 && n > 0) { var c = s.charCodeAt(i--); if(c < 128) { // encode using utf-8 ba[--n] = c; } else if((c > 127) && (c < 2048)) { ba[--n] = (c & 63) | 128; ba[--n] = (c >> 6) | 192; } else { ba[--n] = (c & 63) | 128; ba[--n] = ((c >> 6) & 63) | 128; ba[--n] = (c >> 12) | 224; } } ba[--n] = 0; var rng = new SecureRandom(); var x = new Array(); while(n > 2) { // random non-zero pad x[0] = 0; while(x[0] == 0) rng.nextBytes(x); ba[--n] = x[0]; } ba[--n] = 2; ba[--n] = 0; return new BigInteger(ba); } // PKCS#1 (OAEP) mask generation function function oaep_mgf1_arr(seed, len, hash) { var mask = '', i = 0; while (mask.length < len) { mask += hash(String.fromCharCode.apply(String, seed.concat([ (i & 0xff000000) >> 24, (i & 0x00ff0000) >> 16, (i & 0x0000ff00) >> 8, i & 0x000000ff]))); i += 1; } return mask; } var SHA1_SIZE = 20; // PKCS#1 (OAEP) pad input string s to n bytes, and return a bigint function oaep_pad(s, n, hash) { if (s.length + 2 * SHA1_SIZE + 2 > n) { throw "Message too long for RSA"; } var PS = '', i; for (i = 0; i < n - s.length - 2 * SHA1_SIZE - 2; i += 1) { PS += '\x00'; } var DB = rstr_sha1('') + PS + '\x01' + s; var seed = new Array(SHA1_SIZE); new SecureRandom().nextBytes(seed); var dbMask = oaep_mgf1_arr(seed, DB.length, hash || rstr_sha1); var maskedDB = []; for (i = 0; i < DB.length; i += 1) { maskedDB[i] = DB.charCodeAt(i) ^ dbMask.charCodeAt(i); } var seedMask = oaep_mgf1_arr(maskedDB, seed.length, rstr_sha1); var maskedSeed = [0]; for (i = 0; i < seed.length; i += 1) { maskedSeed[i + 1] = seed[i] ^ seedMask.charCodeAt(i); } return new BigInteger(maskedSeed.concat(maskedDB)); } // "empty" RSA key constructor function RSAKey() { this.n = null; this.e = 0; this.d = null; this.p = null; this.q = null; this.dmp1 = null; this.dmq1 = null; this.coeff = null; } // Set the public key fields N and e from hex strings function RSASetPublic(N,E) { this.isPublic = true; if (typeof N !== "string") { this.n = N; this.e = E; } else if(N != null && E != null && N.length > 0 && E.length > 0) { this.n = parseBigInt(N,16); this.e = parseInt(E,16); } else alert("Invalid RSA public key"); } // Perform raw public operation on "x": return x^e (mod n) function RSADoPublic(x) { return x.modPowInt(this.e, this.n); } // Return the PKCS#1 RSA encryption of "text" as an even-length hex string function RSAEncrypt(text) { var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3); if(m == null) return null; var c = this.doPublic(m); if(c == null) return null; var h = c.toString(16); if((h.length & 1) == 0) return h; else return "0" + h; } // Return the PKCS#1 OAEP RSA encryption of "text" as an even-length hex string function RSAEncryptOAEP(text, hash) { var m = oaep_pad(text, (this.n.bitLength()+7)>>3, hash); if(m == null) return null; var c = this.doPublic(m); if(c == null) return null; var h = c.toString(16); if((h.length & 1) == 0) return h; else return "0" + h; } // Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string //function RSAEncryptB64(text) { // var h = this.encrypt(text); // if(h) return hex2b64(h); else return null; //} // protected RSAKey.prototype.doPublic = RSADoPublic; // public RSAKey.prototype.setPublic = RSASetPublic; RSAKey.prototype.encrypt = RSAEncrypt; RSAKey.prototype.encryptOAEP = RSAEncryptOAEP; //RSAKey.prototype.encrypt_b64 = RSAEncryptB64; RSAKey.prototype.type = "RSA"; /*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ */ // Depends on rsa.js and jsbn2.js // Version 1.1: support utf-8 decoding in pkcs1unpad2 // Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext function pkcs1unpad2(d,n) { var b = d.toByteArray(); var i = 0; while(i < b.length && b[i] == 0) ++i; if(b.length-i != n-1 || b[i] != 2) return null; ++i; while(b[i] != 0) if(++i >= b.length) return null; var ret = ""; while(++i < b.length) { var c = b[i] & 255; if(c < 128) { // utf-8 decode ret += String.fromCharCode(c); } else if((c > 191) && (c < 224)) { ret += String.fromCharCode(((c & 31) << 6) | (b[i+1] & 63)); ++i; } else { ret += String.fromCharCode(((c & 15) << 12) | ((b[i+1] & 63) << 6) | (b[i+2] & 63)); i += 2; } } return ret; } // PKCS#1 (OAEP) mask generation function function oaep_mgf1_str(seed, len, hash) { var mask = '', i = 0; while (mask.length < len) { mask += hash(seed + String.fromCharCode.apply(String, [ (i & 0xff000000) >> 24, (i & 0x00ff0000) >> 16, (i & 0x0000ff00) >> 8, i & 0x000000ff])); i += 1; } return mask; } var SHA1_SIZE = 20; // Undo PKCS#1 (OAEP) padding and, if valid, return the plaintext function oaep_unpad(d, n, hash) { d = d.toByteArray(); var i; for (i = 0; i < d.length; i += 1) { d[i] &= 0xff; } while (d.length < n) { d.unshift(0); } d = String.fromCharCode.apply(String, d); if (d.length < 2 * SHA1_SIZE + 2) { throw "Cipher too short"; } var maskedSeed = d.substr(1, SHA1_SIZE) var maskedDB = d.substr(SHA1_SIZE + 1); var seedMask = oaep_mgf1_str(maskedDB, SHA1_SIZE, hash || rstr_sha1); var seed = [], i; for (i = 0; i < maskedSeed.length; i += 1) { seed[i] = maskedSeed.charCodeAt(i) ^ seedMask.charCodeAt(i); } var dbMask = oaep_mgf1_str(String.fromCharCode.apply(String, seed), d.length - SHA1_SIZE, rstr_sha1); var DB = []; for (i = 0; i < maskedDB.length; i += 1) { DB[i] = maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i); } DB = String.fromCharCode.apply(String, DB); if (DB.substr(0, SHA1_SIZE) !== rstr_sha1('')) { throw "Hash mismatch"; } DB = DB.substr(SHA1_SIZE); var first_one = DB.indexOf('\x01'); var last_zero = (first_one != -1) ? DB.substr(0, first_one).lastIndexOf('\x00') : -1; if (last_zero + 1 != first_one) { throw "Malformed data"; } return DB.substr(first_one + 1); } // Set the private key fields N, e, and d from hex strings function RSASetPrivate(N,E,D) { this.isPrivate = true; if (typeof N !== "string") { this.n = N; this.e = E; this.d = D; } else if(N != null && E != null && N.length > 0 && E.length > 0) { this.n = parseBigInt(N,16); this.e = parseInt(E,16); this.d = parseBigInt(D,16); } else alert("Invalid RSA private key"); } // Set the private key fields N, e, d and CRT params from hex strings function RSASetPrivateEx(N,E,D,P,Q,DP,DQ,C) { this.isPrivate = true; if (N == null) throw "RSASetPrivateEx N == null"; if (E == null) throw "RSASetPrivateEx E == null"; if (N.length == 0) throw "RSASetPrivateEx N.length == 0"; if (E.length == 0) throw "RSASetPrivateEx E.length == 0"; if (N != null && E != null && N.length > 0 && E.length > 0) { this.n = parseBigInt(N,16); this.e = parseInt(E,16); this.d = parseBigInt(D,16); this.p = parseBigInt(P,16); this.q = parseBigInt(Q,16); this.dmp1 = parseBigInt(DP,16); this.dmq1 = parseBigInt(DQ,16); this.coeff = parseBigInt(C,16); } else { alert("Invalid RSA private key in RSASetPrivateEx"); } } // Generate a new random private key B bits long, using public expt E function RSAGenerate(B,E) { var rng = new SecureRandom(); var qs = B>>1; this.e = parseInt(E,16); var ee = new BigInteger(E,16); for(;;) { for(;;) { this.p = new BigInteger(B-qs,1,rng); if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break; } for(;;) { this.q = new BigInteger(qs,1,rng); if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break; } if(this.p.compareTo(this.q) <= 0) { var t = this.p; this.p = this.q; this.q = t; } var p1 = this.p.subtract(BigInteger.ONE); // p1 = p - 1 var q1 = this.q.subtract(BigInteger.ONE); // q1 = q - 1 var phi = p1.multiply(q1); if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) { this.n = this.p.multiply(this.q); // this.n = p * q this.d = ee.modInverse(phi); // this.d = this.dmp1 = this.d.mod(p1); // this.dmp1 = d mod (p - 1) this.dmq1 = this.d.mod(q1); // this.dmq1 = d mod (q - 1) this.coeff = this.q.modInverse(this.p); // this.coeff = (q ^ -1) mod p break; } } this.isPrivate = true; } // Perform raw private operation on "x": return x^d (mod n) function RSADoPrivate(x) { if(this.p == null || this.q == null) return x.modPow(this.d, this.n); // TODO: re-calculate any missing CRT params var xp = x.mod(this.p).modPow(this.dmp1, this.p); // xp=cp? var xq = x.mod(this.q).modPow(this.dmq1, this.q); // xq=cq? while(xp.compareTo(xq) < 0) xp = xp.add(this.p); // NOTE: // xp.subtract(xq) => cp -cq // xp.subtract(xq).multiply(this.coeff).mod(this.p) => (cp - cq) * u mod p = h // xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq) => cq + (h * q) = M return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq); } // Return the PKCS#1 RSA decryption of "ctext". // "ctext" is an even-length hex string and the output is a plain string. function RSADecrypt(ctext) { var c = parseBigInt(ctext, 16); var m = this.doPrivate(c); if(m == null) return null; return pkcs1unpad2(m, (this.n.bitLength()+7)>>3); } // Return the PKCS#1 OAEP RSA decryption of "ctext". // "ctext" is an even-length hex string and the output is a plain string. function RSADecryptOAEP(ctext, hash) { var c = parseBigInt(ctext, 16); var m = this.doPrivate(c); if(m == null) return null; return oaep_unpad(m, (this.n.bitLength()+7)>>3, hash); } // Return the PKCS#1 RSA decryption of "ctext". // "ctext" is a Base64-encoded string and the output is a plain string. //function RSAB64Decrypt(ctext) { // var h = b64tohex(ctext); // if(h) return this.decrypt(h); else return null; //} // protected RSAKey.prototype.doPrivate = RSADoPrivate; // public RSAKey.prototype.setPrivate = RSASetPrivate; RSAKey.prototype.setPrivateEx = RSASetPrivateEx; RSAKey.prototype.generate = RSAGenerate; RSAKey.prototype.decrypt = RSADecrypt; RSAKey.prototype.decryptOAEP = RSADecryptOAEP; //RSAKey.prototype.b64_decrypt = RSAB64Decrypt; /*! rsapem-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license */ // // rsa-pem.js - adding function for reading/writing PKCS#1 PEM private key // to RSAKey class. // // version: 1.1.1 (2013-Apr-12) // // Copyright (c) 2010-2013 Kenji Urushima (kenji.urushima@gmail.com) // // This software is licensed under the terms of the MIT License. // http://kjur.github.com/jsrsasign/license/ // // The above copyright and license notice shall be // included in all copies or substantial portions of the Software. // // // Depends on: // // // // _RSApem_pemToBase64(sPEM) // // removing PEM header, PEM footer and space characters including // new lines from PEM formatted RSA private key string. // /** * @fileOverview * @name rsapem-1.1.js * @author Kenji Urushima kenji.urushima@gmail.com * @version 1.1 * @license MIT License */ function _rsapem_pemToBase64(sPEMPrivateKey) { var s = sPEMPrivateKey; s = s.replace("-----BEGIN RSA PRIVATE KEY-----", ""); s = s.replace("-----END RSA PRIVATE KEY-----", ""); s = s.replace(/[ \n]+/g, ""); return s; } function _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey) { var a = new Array(); var v1 = ASN1HEX.getStartPosOfV_AtObj(hPrivateKey, 0); var n1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, v1); var e1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, n1); var d1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, e1); var p1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, d1); var q1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, p1); var dp1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, q1); var dq1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dp1); var co1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dq1); a.push(v1, n1, e1, d1, p1, q1, dp1, dq1, co1); return a; } function _rsapem_getHexValueArrayOfChildrenFromHex(hPrivateKey) { var posArray = _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey); var v = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[0]); var n = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[1]); var e = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[2]); var d = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[3]); var p = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[4]); var q = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[5]); var dp = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[6]); var dq = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[7]); var co = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[8]); var a = new Array(); a.push(v, n, e, d, p, q, dp, dq, co); return a; } /** * read RSA private key from a ASN.1 hexadecimal string * @name readPrivateKeyFromASN1HexString * @memberOf RSAKey# * @function * @param {String} keyHex ASN.1 hexadecimal string of PKCS#1 private key. * @since 1.1.1 */ function _rsapem_readPrivateKeyFromASN1HexString(keyHex) { var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex); this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]); } /** * read PKCS#1 private key from a string * @name readPrivateKeyFromPEMString * @memberOf RSAKey# * @function * @param {String} keyPEM string of PKCS#1 private key. */ function _rsapem_readPrivateKeyFromPEMString(keyPEM) { var keyB64 = _rsapem_pemToBase64(keyPEM); var keyHex = b64tohex(keyB64) // depends base64.js var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex); this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]); } RSAKey.prototype.readPrivateKeyFromPEMString = _rsapem_readPrivateKeyFromPEMString; RSAKey.prototype.readPrivateKeyFromASN1HexString = _rsapem_readPrivateKeyFromASN1HexString; /*! rsasign-1.2.7.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license */ var _RE_HEXDECONLY=new RegExp("");_RE_HEXDECONLY.compile("[^0-9a-f]","gi");function _rsasign_getHexPaddedDigestInfoForString(d,e,a){var b=function(f){return KJUR.crypto.Util.hashString(f,a)};var c=b(d);return KJUR.crypto.Util.getPaddedDigestInfoHex(c,a,e)}function _zeroPaddingOfSignature(e,d){var c="";var a=d/4-e.length;for(var b=0;b>24,(d&16711680)>>16,(d&65280)>>8,d&255]))));d+=1}return b}function _rsasign_signStringPSS(e,a,d){var c=function(f){return KJUR.crypto.Util.hashHex(f,a)};var b=c(rstrtohex(e));if(d===undefined){d=-1}return this.signWithMessageHashPSS(b,a,d)}function _rsasign_signWithMessageHashPSS(l,a,k){var b=hextorstr(l);var g=b.length;var m=this.n.bitLength()-1;var c=Math.ceil(m/8);var d;var o=function(i){return KJUR.crypto.Util.hashHex(i,a)};if(k===-1||k===undefined){k=g}else{if(k===-2){k=c-g-2}else{if(k<-2){throw"invalid salt length"}}}if(c<(g+k+2)){throw"data too long"}var f="";if(k>0){f=new Array(k);new SecureRandom().nextBytes(f);f=String.fromCharCode.apply(String,f)}var n=hextorstr(o(rstrtohex("\x00\x00\x00\x00\x00\x00\x00\x00"+b+f)));var j=[];for(d=0;d>(8*c-m))&255;q[0]&=~p;for(d=0;dthis.n.bitLength()){return 0}var i=this.doPublic(b);var e=i.toString(16).replace(/^1f+00/,"");var g=_rsasign_getAlgNameAndHashFromHexDisgestInfo(e);if(g.length==0){return false}var d=g[0];var h=g[1];var a=function(k){return KJUR.crypto.Util.hashString(k,d)};var c=a(f);return(h==c)}function _rsasign_verifyWithMessageHash(e,a){a=a.replace(_RE_HEXDECONLY,"");a=a.replace(/[ \n]+/g,"");var b=parseBigInt(a,16);if(b.bitLength()>this.n.bitLength()){return 0}var h=this.doPublic(b);var g=h.toString(16).replace(/^1f+00/,"");var c=_rsasign_getAlgNameAndHashFromHexDisgestInfo(g);if(c.length==0){return false}var d=c[0];var f=c[1];return(f==e)}function _rsasign_verifyStringPSS(c,b,a,f){var e=function(g){return KJUR.crypto.Util.hashHex(g,a)};var d=e(rstrtohex(c));if(f===undefined){f=-1}return this.verifyWithMessageHashPSS(d,b,a,f)}function _rsasign_verifyWithMessageHashPSS(f,s,l,c){var k=new BigInteger(s,16);if(k.bitLength()>this.n.bitLength()){return false}var r=function(i){return KJUR.crypto.Util.hashHex(i,l)};var j=hextorstr(f);var h=j.length;var g=this.n.bitLength()-1;var m=Math.ceil(g/8);var q;if(c===-1||c===undefined){c=h}else{if(c===-2){c=m-h-2}else{if(c<-2){throw"invalid salt length"}}}if(m<(h+c+2)){throw"data too long"}var a=this.doPublic(k).toByteArray();for(q=0;q>(8*m-g))&255;if((d.charCodeAt(0)&p)!==0){throw"bits beyond keysize not zero"}var n=pss_mgf1_str(e,d.length,r);var o=[];for(q=0;qMIT License */ /* * MEMO: * f('3082025b02...', 2) ... 82025b ... 3bytes * f('020100', 2) ... 01 ... 1byte * f('0203001...', 2) ... 03 ... 1byte * f('02818003...', 2) ... 8180 ... 2bytes * f('3080....0000', 2) ... 80 ... -1 * * Requirements: * - ASN.1 type octet length MUST be 1. * (i.e. ASN.1 primitives like SET, SEQUENCE, INTEGER, OCTETSTRING ...) */ /** * ASN.1 DER encoded hexadecimal string utility class * @name ASN1HEX * @class ASN.1 DER encoded hexadecimal string utility class * @since jsrsasign 1.1 */ var ASN1HEX = new function() { /** * get byte length for ASN.1 L(length) bytes * @name getByteLengthOfL_AtObj * @memberOf ASN1HEX * @function * @param {String} s hexadecimal string of ASN.1 DER encoded data * @param {Number} pos string index * @return byte length for ASN.1 L(length) bytes */ this.getByteLengthOfL_AtObj = function(s, pos) { if (s.substring(pos + 2, pos + 3) != '8') return 1; var i = parseInt(s.substring(pos + 3, pos + 4)); if (i == 0) return -1; // length octet '80' indefinite length if (0 < i && i < 10) return i + 1; // including '8?' octet; return -2; // malformed format }; /** * get hexadecimal string for ASN.1 L(length) bytes * @name getHexOfL_AtObj * @memberOf ASN1HEX * @function * @param {String} s hexadecimal string of ASN.1 DER encoded data * @param {Number} pos string index * @return {String} hexadecimal string for ASN.1 L(length) bytes */ this.getHexOfL_AtObj = function(s, pos) { var len = this.getByteLengthOfL_AtObj(s, pos); if (len < 1) return ''; return s.substring(pos + 2, pos + 2 + len * 2); }; // getting ASN.1 length value at the position 'idx' of // hexa decimal string 's'. // // f('3082025b02...', 0) ... 82025b ... ??? // f('020100', 0) ... 01 ... 1 // f('0203001...', 0) ... 03 ... 3 // f('02818003...', 0) ... 8180 ... 128 /** * get integer value of ASN.1 length for ASN.1 data * @name getIntOfL_AtObj * @memberOf ASN1HEX * @function * @param {String} s hexadecimal string of ASN.1 DER encoded data * @param {Number} pos string index * @return ASN.1 L(length) integer value */ this.getIntOfL_AtObj = function(s, pos) { var hLength = this.getHexOfL_AtObj(s, pos); if (hLength == '') return -1; var bi; if (parseInt(hLength.substring(0, 1)) < 8) { bi = new BigInteger(hLength, 16); } else { bi = new BigInteger(hLength.substring(2), 16); } return bi.intValue(); }; /** * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'. * @name getStartPosOfV_AtObj * @memberOf ASN1HEX * @function * @param {String} s hexadecimal string of ASN.1 DER encoded data * @param {Number} pos string index */ this.getStartPosOfV_AtObj = function(s, pos) { var l_len = this.getByteLengthOfL_AtObj(s, pos); if (l_len < 0) return l_len; return pos + (l_len + 1) * 2; }; /** * get hexadecimal string of ASN.1 V(value) * @name getHexOfV_AtObj * @memberOf ASN1HEX * @function * @param {String} s hexadecimal string of ASN.1 DER encoded data * @param {Number} pos string index * @return {String} hexadecimal string of ASN.1 value. */ this.getHexOfV_AtObj = function(s, pos) { var pos1 = this.getStartPosOfV_AtObj(s, pos); var len = this.getIntOfL_AtObj(s, pos); return s.substring(pos1, pos1 + len * 2); }; /** * get hexadecimal string of ASN.1 TLV at * @name getHexOfTLV_AtObj * @memberOf ASN1HEX * @function * @param {String} s hexadecimal string of ASN.1 DER encoded data * @param {Number} pos string index * @return {String} hexadecimal string of ASN.1 TLV. * @since 1.1 */ this.getHexOfTLV_AtObj = function(s, pos) { var hT = s.substr(pos, 2); var hL = this.getHexOfL_AtObj(s, pos); var hV = this.getHexOfV_AtObj(s, pos); return hT + hL + hV; }; /** * get next sibling starting index for ASN.1 object string * @name getPosOfNextSibling_AtObj * @memberOf ASN1HEX * @function * @param {String} s hexadecimal string of ASN.1 DER encoded data * @param {Number} pos string index * @return next sibling starting index for ASN.1 object string */ this.getPosOfNextSibling_AtObj = function(s, pos) { var pos1 = this.getStartPosOfV_AtObj(s, pos); var len = this.getIntOfL_AtObj(s, pos); return pos1 + len * 2; }; /** * get array of indexes of child ASN.1 objects * @name getPosArrayOfChildren_AtObj * @memberOf ASN1HEX * @function * @param {String} s hexadecimal string of ASN.1 DER encoded data * @param {Number} start string index of ASN.1 object * @return {Array of Number} array of indexes for childen of ASN.1 objects */ this.getPosArrayOfChildren_AtObj = function(h, pos) { var a = new Array(); var p0 = this.getStartPosOfV_AtObj(h, pos); a.push(p0); var len = this.getIntOfL_AtObj(h, pos); var p = p0; var k = 0; while (1) { var pNext = this.getPosOfNextSibling_AtObj(h, p); if (pNext == null || (pNext - p0 >= (len * 2))) break; if (k >= 200) break; a.push(pNext); p = pNext; k++; } return a; }; /** * get string index of nth child object of ASN.1 object refered by h, idx * @name getNthChildIndex_AtObj * @memberOf ASN1HEX * @function * @param {String} h hexadecimal string of ASN.1 DER encoded data * @param {Number} idx start string index of ASN.1 object * @param {Number} nth for child * @return {Number} string index of nth child. * @since 1.1 */ this.getNthChildIndex_AtObj = function(h, idx, nth) { var a = this.getPosArrayOfChildren_AtObj(h, idx); return a[nth]; }; // ========== decendant methods ============================== /** * get string index of nth child object of ASN.1 object refered by h, idx * @name getDecendantIndexByNthList * @memberOf ASN1HEX * @function * @param {String} h hexadecimal string of ASN.1 DER encoded data * @param {Number} currentIndex start string index of ASN.1 object * @param {Array of Number} nthList array list of nth * @return {Number} string index refered by nthList * @since 1.1 * @example * The "nthList" is a index list of structured ASN.1 object * reference. Here is a sample structure and "nthList"s which * refers each objects. * * SQUENCE - * SEQUENCE - [0] * IA5STRING 000 - [0, 0] * UTF8STRING 001 - [0, 1] * SET - [1] * IA5STRING 010 - [1, 0] * UTF8STRING 011 - [1, 1] */ this.getDecendantIndexByNthList = function(h, currentIndex, nthList) { if (nthList.length == 0) { return currentIndex; } var firstNth = nthList.shift(); var a = this.getPosArrayOfChildren_AtObj(h, currentIndex); return this.getDecendantIndexByNthList(h, a[firstNth], nthList); }; /** * get hexadecimal string of ASN.1 TLV refered by current index and nth index list. * @name getDecendantHexTLVByNthList * @memberOf ASN1HEX * @function * @param {String} h hexadecimal string of ASN.1 DER encoded data * @param {Number} currentIndex start string index of ASN.1 object * @param {Array of Number} nthList array list of nth * @return {Number} hexadecimal string of ASN.1 TLV refered by nthList * @since 1.1 */ this.getDecendantHexTLVByNthList = function(h, currentIndex, nthList) { var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList); return this.getHexOfTLV_AtObj(h, idx); }; /** * get hexadecimal string of ASN.1 V refered by current index and nth index list. * @name getDecendantHexVByNthList * @memberOf ASN1HEX * @function * @param {String} h hexadecimal string of ASN.1 DER encoded data * @param {Number} currentIndex start string index of ASN.1 object * @param {Array of Number} nthList array list of nth * @return {Number} hexadecimal string of ASN.1 V refered by nthList * @since 1.1 */ this.getDecendantHexVByNthList = function(h, currentIndex, nthList) { var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList); return this.getHexOfV_AtObj(h, idx); }; }; /* * @since asn1hex 1.1.4 */ ASN1HEX.getVbyList = function(h, currentIndex, nthList, checkingTag) { var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList); if (idx === undefined) { throw "can't find nthList object"; } if (checkingTag !== undefined) { if (h.substr(idx, 2) != checkingTag) { throw "checking tag doesn't match: " + h.substr(idx,2) + "!=" + checkingTag; } } return this.getHexOfV_AtObj(h, idx); }; /** * get OID string from hexadecimal encoded value * @name hextooidstr * @memberOf ASN1HEX * @function * @param {String} hex hexadecmal string of ASN.1 DER encoded OID value * @return {String} OID string (ex. '1.2.3.4.567') * @since asn1hex 1.1.5 */ ASN1HEX.hextooidstr = function(hex) { var zeroPadding = function(s, len) { if (s.length >= len) return s; return new Array(len - s.length + 1).join('0') + s; }; var a = []; // a[0], a[1] var hex0 = hex.substr(0, 2); var i0 = parseInt(hex0, 16); a[0] = new String(Math.floor(i0 / 40)); a[1] = new String(i0 % 40); // a[2]..a[n] var hex1 = hex.substr(2); var b = []; for (var i = 0; i < hex1.length / 2; i++) { b.push(parseInt(hex1.substr(i * 2, 2), 16)); } var c = []; var cbin = ""; for (var i = 0; i < b.length; i++) { if (b[i] & 0x80) { cbin = cbin + zeroPadding((b[i] & 0x7f).toString(2), 7); } else { cbin = cbin + zeroPadding((b[i] & 0x7f).toString(2), 7); c.push(new String(parseInt(cbin, 2))); cbin = ""; } } var s = a.join("."); if (c.length > 0) s = s + "." + c.join("."); return s; }; /*! x509-1.1.3.js (c) 2012-2014 Kenji Urushima | kjur.github.com/jsrsasign/license */ /* * x509.js - X509 class to read subject public key from certificate. * * Copyright (c) 2010-2014 Kenji Urushima (kenji.urushima@gmail.com) * * This software is licensed under the terms of the MIT License. * http://kjur.github.com/jsrsasign/license * * The above copyright and license notice shall be * included in all copies or substantial portions of the Software. */ /** * @fileOverview * @name x509-1.1.js * @author Kenji Urushima kenji.urushima@gmail.com * @version x509 1.1.3 (2014-May-17) * @since jsrsasign 1.x.x * @license MIT License */ /* * Depends: * base64.js * rsa.js * asn1hex.js */ /** * X.509 certificate class.
* @class X.509 certificate class * @property {RSAKey} subjectPublicKeyRSA Tom Wu's RSAKey object * @property {String} subjectPublicKeyRSA_hN hexadecimal string for modulus of RSA public key * @property {String} subjectPublicKeyRSA_hE hexadecimal string for public exponent of RSA public key * @property {String} hex hexacedimal string for X.509 certificate. * @author Kenji Urushima * @version 1.0.1 (08 May 2012) * @see 'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/ */ function X509() { this.subjectPublicKeyRSA = null; this.subjectPublicKeyRSA_hN = null; this.subjectPublicKeyRSA_hE = null; this.hex = null; // ===== get basic fields from hex ===================================== /** * get hexadecimal string of serialNumber field of certificate.
* @name getSerialNumberHex * @memberOf X509# * @function */ this.getSerialNumberHex = function() { return ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 1]); }; /** * get hexadecimal string of issuer field TLV of certificate.
* @name getIssuerHex * @memberOf X509# * @function */ this.getIssuerHex = function() { return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]); }; /** * get string of issuer field of certificate.
* @name getIssuerString * @memberOf X509# * @function */ this.getIssuerString = function() { return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3])); }; /** * get hexadecimal string of subject field of certificate.
* @name getSubjectHex * @memberOf X509# * @function */ this.getSubjectHex = function() { return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]); }; /** * get string of subject field of certificate.
* @name getSubjectString * @memberOf X509# * @function */ this.getSubjectString = function() { return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5])); }; /** * get notBefore field string of certificate.
* @name getNotBefore * @memberOf X509# * @function */ this.getNotBefore = function() { var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 0]); s = s.replace(/(..)/g, "%$1"); s = decodeURIComponent(s); return s; }; /** * get notAfter field string of certificate.
* @name getNotAfter * @memberOf X509# * @function */ this.getNotAfter = function() { var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 1]); s = s.replace(/(..)/g, "%$1"); s = decodeURIComponent(s); return s; }; // ===== read certificate public key ========================== // ===== read certificate ===================================== /** * read PEM formatted X.509 certificate from string.
* @name readCertPEM * @memberOf X509# * @function * @param {String} sCertPEM string for PEM formatted X.509 certificate */ this.readCertPEM = function(sCertPEM) { var hCert = X509.pemToHex(sCertPEM); var a = X509.getPublicKeyHexArrayFromCertHex(hCert); var rsa = new RSAKey(); rsa.setPublic(a[0], a[1]); this.subjectPublicKeyRSA = rsa; this.subjectPublicKeyRSA_hN = a[0]; this.subjectPublicKeyRSA_hE = a[1]; this.hex = hCert; }; this.readCertPEMWithoutRSAInit = function(sCertPEM) { var hCert = X509.pemToHex(sCertPEM); var a = X509.getPublicKeyHexArrayFromCertHex(hCert); this.subjectPublicKeyRSA.setPublic(a[0], a[1]); this.subjectPublicKeyRSA_hN = a[0]; this.subjectPublicKeyRSA_hE = a[1]; this.hex = hCert; }; }; X509.pemToBase64 = function(sCertPEM) { var s = sCertPEM; s = s.replace("-----BEGIN CERTIFICATE-----", ""); s = s.replace("-----END CERTIFICATE-----", ""); s = s.replace(/[ \n]+/g, ""); return s; }; X509.pemToHex = function(sCertPEM) { var b64Cert = X509.pemToBase64(sCertPEM); var hCert = b64tohex(b64Cert); return hCert; }; // NOTE: Without BITSTRING encapsulation. X509.getSubjectPublicKeyPosFromCertHex = function(hCert) { var pInfo = X509.getSubjectPublicKeyInfoPosFromCertHex(hCert); if (pInfo == -1) return -1; var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pInfo); if (a.length != 2) return -1; var pBitString = a[1]; if (hCert.substring(pBitString, pBitString + 2) != '03') return -1; var pBitStringV = ASN1HEX.getStartPosOfV_AtObj(hCert, pBitString); if (hCert.substring(pBitStringV, pBitStringV + 2) != '00') return -1; return pBitStringV + 2; }; // NOTE: privateKeyUsagePeriod field of X509v2 not supported. // NOTE: v1 and v3 supported X509.getSubjectPublicKeyInfoPosFromCertHex = function(hCert) { var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0); var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pTbsCert); if (a.length < 1) return -1; if (hCert.substring(a[0], a[0] + 10) == "a003020102") { // v3 if (a.length < 6) return -1; return a[6]; } else { if (a.length < 5) return -1; return a[5]; } }; X509.getPublicKeyHexArrayFromCertHex = function(hCert) { var p = X509.getSubjectPublicKeyPosFromCertHex(hCert); var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p); if (a.length != 2) return []; var hN = ASN1HEX.getHexOfV_AtObj(hCert, a[0]); var hE = ASN1HEX.getHexOfV_AtObj(hCert, a[1]); if (hN != null && hE != null) { return [hN, hE]; } else { return []; } }; X509.getHexTbsCertificateFromCert = function(hCert) { var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0); return pTbsCert; }; X509.getPublicKeyHexArrayFromCertPEM = function(sCertPEM) { var hCert = X509.pemToHex(sCertPEM); var a = X509.getPublicKeyHexArrayFromCertHex(hCert); return a; }; X509.hex2dn = function(hDN) { var s = ""; var a = ASN1HEX.getPosArrayOfChildren_AtObj(hDN, 0); for (var i = 0; i < a.length; i++) { var hRDN = ASN1HEX.getHexOfTLV_AtObj(hDN, a[i]); s = s + "/" + X509.hex2rdn(hRDN); } return s; }; X509.hex2rdn = function(hRDN) { var hType = ASN1HEX.getDecendantHexTLVByNthList(hRDN, 0, [0, 0]); var hValue = ASN1HEX.getDecendantHexVByNthList(hRDN, 0, [0, 1]); var type = ""; try { type = X509.DN_ATTRHEX[hType]; } catch (ex) { type = hType; } hValue = hValue.replace(/(..)/g, "%$1"); var value = decodeURIComponent(hValue); return type + "=" + value; }; X509.DN_ATTRHEX = { "0603550406": "C", "060355040a": "O", "060355040b": "OU", "0603550403": "CN", "0603550405": "SN", "0603550408": "ST", "0603550407": "L", }; /** * get RSAKey/ECDSA public key object from PEM certificate string * @name getPublicKeyFromCertPEM * @memberOf X509 * @function * @param {String} sCertPEM PEM formatted RSA/ECDSA/DSA X.509 certificate * @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key * @since x509 1.1.1 * @description * NOTE: DSA is also supported since x509 1.1.2. */ X509.getPublicKeyFromCertPEM = function(sCertPEM) { var info = X509.getPublicKeyInfoPropOfCertPEM(sCertPEM); if (info.algoid == "2a864886f70d010101") { // RSA var aRSA = KEYUTIL.parsePublicRawRSAKeyHex(info.keyhex); var key = new RSAKey(); key.setPublic(aRSA.n, aRSA.e); return key; } else if (info.algoid == "2a8648ce3d0201") { // ECC var curveName = KJUR.crypto.OID.oidhex2name[info.algparam]; var key = new KJUR.crypto.ECDSA({'curve': curveName, 'info': info.keyhex}); key.setPublicKeyHex(info.keyhex); return key; } else if (info.algoid == "2a8648ce380401") { // DSA 1.2.840.10040.4.1 var p = ASN1HEX.getVbyList(info.algparam, 0, [0], "02"); var q = ASN1HEX.getVbyList(info.algparam, 0, [1], "02"); var g = ASN1HEX.getVbyList(info.algparam, 0, [2], "02"); var y = ASN1HEX.getHexOfV_AtObj(info.keyhex, 0); y = y.substr(2); var key = new KJUR.crypto.DSA(); key.setPublic(new BigInteger(p, 16), new BigInteger(q, 16), new BigInteger(g, 16), new BigInteger(y, 16)); return key; } else { throw "unsupported key"; } }; /** * get public key information from PEM certificate * @name getPublicKeyInfoPropOfCertPEM * @memberOf X509 * @function * @param {String} sCertPEM string of PEM formatted certificate * @return {Hash} hash of information for public key * @since x509 1.1.1 * @description * Resulted associative array has following properties: *
    *
  • algoid - hexadecimal string of OID of asymmetric key algorithm
  • *
  • algparam - hexadecimal string of OID of ECC curve name or null
  • *
  • keyhex - hexadecimal string of key in the certificate
  • *
* @since x509 1.1.1 */ X509.getPublicKeyInfoPropOfCertPEM = function(sCertPEM) { var result = {}; result.algparam = null; var hCert = X509.pemToHex(sCertPEM); // 1. Certificate ASN.1 var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, 0); if (a1.length != 3) throw "malformed X.509 certificate PEM (code:001)"; // not 3 item of seq Cert // 2. tbsCertificate if (hCert.substr(a1[0], 2) != "30") throw "malformed X.509 certificate PEM (code:002)"; // tbsCert not seq var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a1[0]); // 3. subjectPublicKeyInfo if (a2.length < 7) throw "malformed X.509 certificate PEM (code:003)"; // no subjPubKeyInfo var a3 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a2[6]); if (a3.length != 2) throw "malformed X.509 certificate PEM (code:004)"; // not AlgId and PubKey // 4. AlgId var a4 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a3[0]); if (a4.length != 2) throw "malformed X.509 certificate PEM (code:005)"; // not 2 item in AlgId result.algoid = ASN1HEX.getHexOfV_AtObj(hCert, a4[0]); if (hCert.substr(a4[1], 2) == "06") { // EC result.algparam = ASN1HEX.getHexOfV_AtObj(hCert, a4[1]); } else if (hCert.substr(a4[1], 2) == "30") { // DSA result.algparam = ASN1HEX.getHexOfTLV_AtObj(hCert, a4[1]); } // 5. Public Key Hex if (hCert.substr(a3[1], 2) != "03") throw "malformed X.509 certificate PEM (code:006)"; // not bitstring var unusedBitAndKeyHex = ASN1HEX.getHexOfV_AtObj(hCert, a3[1]); result.keyhex = unusedBitAndKeyHex.substr(2); return result; }; /* X509.prototype.readCertPEM = _x509_readCertPEM; X509.prototype.readCertPEMWithoutRSAInit = _x509_readCertPEMWithoutRSAInit; X509.prototype.getSerialNumberHex = _x509_getSerialNumberHex; X509.prototype.getIssuerHex = _x509_getIssuerHex; X509.prototype.getSubjectHex = _x509_getSubjectHex; X509.prototype.getIssuerString = _x509_getIssuerString; X509.prototype.getSubjectString = _x509_getSubjectString; X509.prototype.getNotBefore = _x509_getNotBefore; X509.prototype.getNotAfter = _x509_getNotAfter; */ /*! crypto-1.1.5.js (c) 2013 Kenji Urushima | kjur.github.com/jsrsasign/license */ /* * crypto.js - Cryptographic Algorithm Provider class * * Copyright (c) 2013 Kenji Urushima (kenji.urushima@gmail.com) * * This software is licensed under the terms of the MIT License. * http://kjur.github.com/jsrsasign/license * * The above copyright and license notice shall be * included in all copies or substantial portions of the Software. */ /** * @fileOverview * @name crypto-1.1.js * @author Kenji Urushima kenji.urushima@gmail.com * @version 1.1.5 (2013-Oct-06) * @since jsrsasign 2.2 * @license MIT License */ /** * kjur's class library name space * @name KJUR * @namespace kjur's class library name space */ if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; /** * kjur's cryptographic algorithm provider library name space *

* This namespace privides following crytpgrahic classes. *

    *
  • {@link KJUR.crypto.MessageDigest} - Java JCE(cryptograhic extension) style MessageDigest class
  • *
  • {@link KJUR.crypto.Signature} - Java JCE(cryptograhic extension) style Signature class
  • *
  • {@link KJUR.crypto.Util} - cryptographic utility functions and properties
  • *
* NOTE: Please ignore method summary and document of this namespace. This caused by a bug of jsdoc2. *

* @name KJUR.crypto * @namespace */ if (typeof KJUR.crypto == "undefined" || !KJUR.crypto) KJUR.crypto = {}; /** * static object for cryptographic function utilities * @name KJUR.crypto.Util * @class static object for cryptographic function utilities * @property {Array} DIGESTINFOHEAD PKCS#1 DigestInfo heading hexadecimal bytes for each hash algorithms * @property {Array} DEFAULTPROVIDER associative array of default provider name for each hash and signature algorithms * @description */ KJUR.crypto.Util = new function() { this.DIGESTINFOHEAD = { 'sha1': "3021300906052b0e03021a05000414", 'sha224': "302d300d06096086480165030402040500041c", 'sha256': "3031300d060960864801650304020105000420", 'sha384': "3041300d060960864801650304020205000430", 'sha512': "3051300d060960864801650304020305000440", 'md2': "3020300c06082a864886f70d020205000410", 'md5': "3020300c06082a864886f70d020505000410", 'ripemd160': "3021300906052b2403020105000414", }; /* * @since crypto 1.1.1 */ this.DEFAULTPROVIDER = { 'md5': 'cryptojs', 'sha1': 'cryptojs', 'sha224': 'cryptojs', 'sha256': 'cryptojs', 'sha384': 'cryptojs', 'sha512': 'cryptojs', 'ripemd160': 'cryptojs', 'hmacmd5': 'cryptojs', 'hmacsha1': 'cryptojs', 'hmacsha224': 'cryptojs', 'hmacsha256': 'cryptojs', 'hmacsha384': 'cryptojs', 'hmacsha512': 'cryptojs', 'hmacripemd160': 'cryptojs', 'MD5withRSA': 'cryptojs/jsrsa', 'SHA1withRSA': 'cryptojs/jsrsa', 'SHA224withRSA': 'cryptojs/jsrsa', 'SHA256withRSA': 'cryptojs/jsrsa', 'SHA384withRSA': 'cryptojs/jsrsa', 'SHA512withRSA': 'cryptojs/jsrsa', 'RIPEMD160withRSA': 'cryptojs/jsrsa', 'MD5withECDSA': 'cryptojs/jsrsa', 'SHA1withECDSA': 'cryptojs/jsrsa', 'SHA224withECDSA': 'cryptojs/jsrsa', 'SHA256withECDSA': 'cryptojs/jsrsa', 'SHA384withECDSA': 'cryptojs/jsrsa', 'SHA512withECDSA': 'cryptojs/jsrsa', 'RIPEMD160withECDSA': 'cryptojs/jsrsa', 'SHA1withDSA': 'cryptojs/jsrsa', 'SHA224withDSA': 'cryptojs/jsrsa', 'SHA256withDSA': 'cryptojs/jsrsa', 'MD5withRSAandMGF1': 'cryptojs/jsrsa', 'SHA1withRSAandMGF1': 'cryptojs/jsrsa', 'SHA224withRSAandMGF1': 'cryptojs/jsrsa', 'SHA256withRSAandMGF1': 'cryptojs/jsrsa', 'SHA384withRSAandMGF1': 'cryptojs/jsrsa', 'SHA512withRSAandMGF1': 'cryptojs/jsrsa', 'RIPEMD160withRSAandMGF1': 'cryptojs/jsrsa', }; /* * @since crypto 1.1.2 */ this.CRYPTOJSMESSAGEDIGESTNAME = { 'md5': 'CryptoJS.algo.MD5', 'sha1': 'CryptoJS.algo.SHA1', 'sha224': 'CryptoJS.algo.SHA224', 'sha256': 'CryptoJS.algo.SHA256', 'sha384': 'CryptoJS.algo.SHA384', 'sha512': 'CryptoJS.algo.SHA512', 'ripemd160': 'CryptoJS.algo.RIPEMD160' }; /** * get hexadecimal DigestInfo * @name getDigestInfoHex * @memberOf KJUR.crypto.Util * @function * @param {String} hHash hexadecimal hash value * @param {String} alg hash algorithm name (ex. 'sha1') * @return {String} hexadecimal string DigestInfo ASN.1 structure */ this.getDigestInfoHex = function(hHash, alg) { if (typeof this.DIGESTINFOHEAD[alg] == "undefined") throw "alg not supported in Util.DIGESTINFOHEAD: " + alg; return this.DIGESTINFOHEAD[alg] + hHash; }; /** * get PKCS#1 padded hexadecimal DigestInfo * @name getPaddedDigestInfoHex * @memberOf KJUR.crypto.Util * @function * @param {String} hHash hexadecimal hash value of message to be signed * @param {String} alg hash algorithm name (ex. 'sha1') * @param {Integer} keySize key bit length (ex. 1024) * @return {String} hexadecimal string of PKCS#1 padded DigestInfo */ this.getPaddedDigestInfoHex = function(hHash, alg, keySize) { var hDigestInfo = this.getDigestInfoHex(hHash, alg); var pmStrLen = keySize / 4; // minimum PM length if (hDigestInfo.length + 22 > pmStrLen) // len(0001+ff(*8)+00+hDigestInfo)=22 throw "key is too short for SigAlg: keylen=" + keySize + "," + alg; var hHead = "0001"; var hTail = "00" + hDigestInfo; var hMid = ""; var fLen = pmStrLen - hHead.length - hTail.length; for (var i = 0; i < fLen; i += 2) { hMid += "ff"; } var hPaddedMessage = hHead + hMid + hTail; return hPaddedMessage; }; /** * get hexadecimal hash of string with specified algorithm * @name hashString * @memberOf KJUR.crypto.Util * @function * @param {String} s input string to be hashed * @param {String} alg hash algorithm name * @return {String} hexadecimal string of hash value * @since 1.1.1 */ this.hashString = function(s, alg) { var md = new KJUR.crypto.MessageDigest({'alg': alg}); return md.digestString(s); }; /** * get hexadecimal hash of hexadecimal string with specified algorithm * @name hashHex * @memberOf KJUR.crypto.Util * @function * @param {String} sHex input hexadecimal string to be hashed * @param {String} alg hash algorithm name * @return {String} hexadecimal string of hash value * @since 1.1.1 */ this.hashHex = function(sHex, alg) { var md = new KJUR.crypto.MessageDigest({'alg': alg}); return md.digestHex(sHex); }; /** * get hexadecimal SHA1 hash of string * @name sha1 * @memberOf KJUR.crypto.Util * @function * @param {String} s input string to be hashed * @return {String} hexadecimal string of hash value * @since 1.0.3 */ this.sha1 = function(s) { var md = new KJUR.crypto.MessageDigest({'alg':'sha1', 'prov':'cryptojs'}); return md.digestString(s); }; /** * get hexadecimal SHA256 hash of string * @name sha256 * @memberOf KJUR.crypto.Util * @function * @param {String} s input string to be hashed * @return {String} hexadecimal string of hash value * @since 1.0.3 */ this.sha256 = function(s) { var md = new KJUR.crypto.MessageDigest({'alg':'sha256', 'prov':'cryptojs'}); return md.digestString(s); }; this.sha256Hex = function(s) { var md = new KJUR.crypto.MessageDigest({'alg':'sha256', 'prov':'cryptojs'}); return md.digestHex(s); }; /** * get hexadecimal SHA512 hash of string * @name sha512 * @memberOf KJUR.crypto.Util * @function * @param {String} s input string to be hashed * @return {String} hexadecimal string of hash value * @since 1.0.3 */ this.sha512 = function(s) { var md = new KJUR.crypto.MessageDigest({'alg':'sha512', 'prov':'cryptojs'}); return md.digestString(s); }; this.sha512Hex = function(s) { var md = new KJUR.crypto.MessageDigest({'alg':'sha512', 'prov':'cryptojs'}); return md.digestHex(s); }; /** * get hexadecimal MD5 hash of string * @name md5 * @memberOf KJUR.crypto.Util * @function * @param {String} s input string to be hashed * @return {String} hexadecimal string of hash value * @since 1.0.3 */ this.md5 = function(s) { var md = new KJUR.crypto.MessageDigest({'alg':'md5', 'prov':'cryptojs'}); return md.digestString(s); }; /** * get hexadecimal RIPEMD160 hash of string * @name ripemd160 * @memberOf KJUR.crypto.Util * @function * @param {String} s input string to be hashed * @return {String} hexadecimal string of hash value * @since 1.0.3 */ this.ripemd160 = function(s) { var md = new KJUR.crypto.MessageDigest({'alg':'ripemd160', 'prov':'cryptojs'}); return md.digestString(s); }; /* * @since 1.1.2 */ this.getCryptoJSMDByName = function(s) { }; }; /** * MessageDigest class which is very similar to java.security.MessageDigest class * @name KJUR.crypto.MessageDigest * @class MessageDigest class which is very similar to java.security.MessageDigest class * @param {Array} params parameters for constructor * @description *
* Currently this supports following algorithm and providers combination: *
    *
  • md5 - cryptojs
  • *
  • sha1 - cryptojs
  • *
  • sha224 - cryptojs
  • *
  • sha256 - cryptojs
  • *
  • sha384 - cryptojs
  • *
  • sha512 - cryptojs
  • *
  • ripemd160 - cryptojs
  • *
  • sha256 - sjcl (NEW from crypto.js 1.0.4)
  • *
* @example * // CryptoJS provider sample * <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/core.js"></script> * <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/sha1.js"></script> * <script src="crypto-1.0.js"></script> * var md = new KJUR.crypto.MessageDigest({alg: "sha1", prov: "cryptojs"}); * md.updateString('aaa') * var mdHex = md.digest() * * // SJCL(Stanford JavaScript Crypto Library) provider sample * <script src="http://bitwiseshiftleft.github.io/sjcl/sjcl.js"></script> * <script src="crypto-1.0.js"></script> * var md = new KJUR.crypto.MessageDigest({alg: "sha256", prov: "sjcl"}); // sjcl supports sha256 only * md.updateString('aaa') * var mdHex = md.digest() */ KJUR.crypto.MessageDigest = function(params) { var md = null; var algName = null; var provName = null; /** * set hash algorithm and provider * @name setAlgAndProvider * @memberOf KJUR.crypto.MessageDigest * @function * @param {String} alg hash algorithm name * @param {String} prov provider name * @description * @example * // for SHA1 * md.setAlgAndProvider('sha1', 'cryptojs'); * // for RIPEMD160 * md.setAlgAndProvider('ripemd160', 'cryptojs'); */ this.setAlgAndProvider = function(alg, prov) { if (alg != null && prov === undefined) prov = KJUR.crypto.Util.DEFAULTPROVIDER[alg]; // for cryptojs if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(alg) != -1 && prov == 'cryptojs') { try { this.md = eval(KJUR.crypto.Util.CRYPTOJSMESSAGEDIGESTNAME[alg]).create(); } catch (ex) { throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex; } this.updateString = function(str) { this.md.update(str); }; this.updateHex = function(hex) { var wHex = CryptoJS.enc.Hex.parse(hex); this.md.update(wHex); }; this.digest = function() { var hash = this.md.finalize(); return hash.toString(CryptoJS.enc.Hex); }; this.digestString = function(str) { this.updateString(str); return this.digest(); }; this.digestHex = function(hex) { this.updateHex(hex); return this.digest(); }; } if (':sha256:'.indexOf(alg) != -1 && prov == 'sjcl') { try { this.md = new sjcl.hash.sha256(); } catch (ex) { throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex; } this.updateString = function(str) { this.md.update(str); }; this.updateHex = function(hex) { var baHex = sjcl.codec.hex.toBits(hex); this.md.update(baHex); }; this.digest = function() { var hash = this.md.finalize(); return sjcl.codec.hex.fromBits(hash); }; this.digestString = function(str) { this.updateString(str); return this.digest(); }; this.digestHex = function(hex) { this.updateHex(hex); return this.digest(); }; } }; /** * update digest by specified string * @name updateString * @memberOf KJUR.crypto.MessageDigest * @function * @param {String} str string to update * @description * @example * md.updateString('New York'); */ this.updateString = function(str) { throw "updateString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName; }; /** * update digest by specified hexadecimal string * @name updateHex * @memberOf KJUR.crypto.MessageDigest * @function * @param {String} hex hexadecimal string to update * @description * @example * md.updateHex('0afe36'); */ this.updateHex = function(hex) { throw "updateHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName; }; /** * completes hash calculation and returns hash result * @name digest * @memberOf KJUR.crypto.MessageDigest * @function * @description * @example * md.digest() */ this.digest = function() { throw "digest() not supported for this alg/prov: " + this.algName + "/" + this.provName; }; /** * performs final update on the digest using string, then completes the digest computation * @name digestString * @memberOf KJUR.crypto.MessageDigest * @function * @param {String} str string to final update * @description * @example * md.digestString('aaa') */ this.digestString = function(str) { throw "digestString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName; }; /** * performs final update on the digest using hexadecimal string, then completes the digest computation * @name digestHex * @memberOf KJUR.crypto.MessageDigest * @function * @param {String} hex hexadecimal string to final update * @description * @example * md.digestHex('0f2abd') */ this.digestHex = function(hex) { throw "digestHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName; }; if (params !== undefined) { if (params['alg'] !== undefined) { this.algName = params['alg']; if (params['prov'] === undefined) this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName]; this.setAlgAndProvider(this.algName, this.provName); } } }; /** * Mac(Message Authentication Code) class which is very similar to java.security.Mac class * @name KJUR.crypto.Mac * @class Mac class which is very similar to java.security.Mac class * @param {Array} params parameters for constructor * @description *
* Currently this supports following algorithm and providers combination: *
    *
  • hmacmd5 - cryptojs
  • *
  • hmacsha1 - cryptojs
  • *
  • hmacsha224 - cryptojs
  • *
  • hmacsha256 - cryptojs
  • *
  • hmacsha384 - cryptojs
  • *
  • hmacsha512 - cryptojs
  • *
* NOTE: HmacSHA224 and HmacSHA384 issue was fixed since jsrsasign 4.1.4. * Please use 'ext/cryptojs-312-core-fix*.js' instead of 'core.js' of original CryptoJS * to avoid those issue. * @example * var mac = new KJUR.crypto.Mac({alg: "HmacSHA1", prov: "cryptojs", "pass": "pass"}); * mac.updateString('aaa') * var macHex = md.doFinal() */ KJUR.crypto.Mac = function(params) { var mac = null; var pass = null; var algName = null; var provName = null; var algProv = null; this.setAlgAndProvider = function(alg, prov) { if (alg == null) alg = "hmacsha1"; alg = alg.toLowerCase(); if (alg.substr(0, 4) != "hmac") { throw "setAlgAndProvider unsupported HMAC alg: " + alg; } if (prov === undefined) prov = KJUR.crypto.Util.DEFAULTPROVIDER[alg]; this.algProv = alg + "/" + prov; var hashAlg = alg.substr(4); // for cryptojs if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(hashAlg) != -1 && prov == 'cryptojs') { try { var mdObj = eval(KJUR.crypto.Util.CRYPTOJSMESSAGEDIGESTNAME[hashAlg]); this.mac = CryptoJS.algo.HMAC.create(mdObj, this.pass); } catch (ex) { throw "setAlgAndProvider hash alg set fail hashAlg=" + hashAlg + "/" + ex; } this.updateString = function(str) { this.mac.update(str); }; this.updateHex = function(hex) { var wHex = CryptoJS.enc.Hex.parse(hex); this.mac.update(wHex); }; this.doFinal = function() { var hash = this.mac.finalize(); return hash.toString(CryptoJS.enc.Hex); }; this.doFinalString = function(str) { this.updateString(str); return this.doFinal(); }; this.doFinalHex = function(hex) { this.updateHex(hex); return this.doFinal(); }; } }; /** * update digest by specified string * @name updateString * @memberOf KJUR.crypto.Mac * @function * @param {String} str string to update * @description * @example * md.updateString('New York'); */ this.updateString = function(str) { throw "updateString(str) not supported for this alg/prov: " + this.algProv; }; /** * update digest by specified hexadecimal string * @name updateHex * @memberOf KJUR.crypto.Mac * @function * @param {String} hex hexadecimal string to update * @description * @example * md.updateHex('0afe36'); */ this.updateHex = function(hex) { throw "updateHex(hex) not supported for this alg/prov: " + this.algProv; }; /** * completes hash calculation and returns hash result * @name doFinal * @memberOf KJUR.crypto.Mac * @function * @description * @example * md.digest() */ this.doFinal = function() { throw "digest() not supported for this alg/prov: " + this.algProv; }; /** * performs final update on the digest using string, then completes the digest computation * @name doFinalString * @memberOf KJUR.crypto.Mac * @function * @param {String} str string to final update * @description * @example * md.digestString('aaa') */ this.doFinalString = function(str) { throw "digestString(str) not supported for this alg/prov: " + this.algProv; }; /** * performs final update on the digest using hexadecimal string, * then completes the digest computation * @name doFinalHex * @memberOf KJUR.crypto.Mac * @function * @param {String} hex hexadecimal string to final update * @description * @example * md.digestHex('0f2abd') */ this.doFinalHex = function(hex) { throw "digestHex(hex) not supported for this alg/prov: " + this.algProv; }; if (params !== undefined) { if (params['pass'] !== undefined) { this.pass = params['pass']; } if (params['alg'] !== undefined) { this.algName = params['alg']; if (params['prov'] === undefined) this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName]; this.setAlgAndProvider(this.algName, this.provName); } } }; /** * Signature class which is very similar to java.security.Signature class * @name KJUR.crypto.Signature * @class Signature class which is very similar to java.security.Signature class * @param {Array} params parameters for constructor * @property {String} state Current state of this signature object whether 'SIGN', 'VERIFY' or null * @description *
* As for params of constructor's argument, it can be specify following attributes: *
    *
  • alg - signature algorithm name (ex. {MD5,SHA1,SHA224,SHA256,SHA384,SHA512,RIPEMD160}with{RSA,ECDSA,DSA})
  • *
  • provider - currently 'cryptojs/jsrsa' only
  • *
*

SUPPORTED ALGORITHMS AND PROVIDERS

* This Signature class supports following signature algorithm and provider names: *
    *
  • MD5withRSA - cryptojs/jsrsa
  • *
  • SHA1withRSA - cryptojs/jsrsa
  • *
  • SHA224withRSA - cryptojs/jsrsa
  • *
  • SHA256withRSA - cryptojs/jsrsa
  • *
  • SHA384withRSA - cryptojs/jsrsa
  • *
  • SHA512withRSA - cryptojs/jsrsa
  • *
  • RIPEMD160withRSA - cryptojs/jsrsa
  • *
  • MD5withECDSA - cryptojs/jsrsa
  • *
  • SHA1withECDSA - cryptojs/jsrsa
  • *
  • SHA224withECDSA - cryptojs/jsrsa
  • *
  • SHA256withECDSA - cryptojs/jsrsa
  • *
  • SHA384withECDSA - cryptojs/jsrsa
  • *
  • SHA512withECDSA - cryptojs/jsrsa
  • *
  • RIPEMD160withECDSA - cryptojs/jsrsa
  • *
  • MD5withRSAandMGF1 - cryptojs/jsrsa
  • *
  • SHA1withRSAandMGF1 - cryptojs/jsrsa
  • *
  • SHA224withRSAandMGF1 - cryptojs/jsrsa
  • *
  • SHA256withRSAandMGF1 - cryptojs/jsrsa
  • *
  • SHA384withRSAandMGF1 - cryptojs/jsrsa
  • *
  • SHA512withRSAandMGF1 - cryptojs/jsrsa
  • *
  • RIPEMD160withRSAandMGF1 - cryptojs/jsrsa
  • *
  • SHA1withDSA - cryptojs/jsrsa
  • *
  • SHA224withDSA - cryptojs/jsrsa
  • *
  • SHA256withDSA - cryptojs/jsrsa
  • *
* Here are supported elliptic cryptographic curve names and their aliases for ECDSA: *
    *
  • secp256k1
  • *
  • secp256r1, NIST P-256, P-256, prime256v1
  • *
  • secp384r1, NIST P-384, P-384
  • *
* NOTE1: DSA signing algorithm is also supported since crypto 1.1.5. *

EXAMPLES

* @example * // RSA signature generation * var sig = new KJUR.crypto.Signature({"alg": "SHA1withRSA"}); * sig.init(prvKeyPEM); * sig.updateString('aaa'); * var hSigVal = sig.sign(); * * // DSA signature validation * var sig2 = new KJUR.crypto.Signature({"alg": "SHA1withDSA"}); * sig2.init(certPEM); * sig.updateString('aaa'); * var isValid = sig2.verify(hSigVal); * * // ECDSA signing * var sig = new KJUR.crypto.Signature({'alg':'SHA1withECDSA'}); * sig.init(prvKeyPEM); * sig.updateString('aaa'); * var sigValueHex = sig.sign(); * * // ECDSA verifying * var sig2 = new KJUR.crypto.Signature({'alg':'SHA1withECDSA'}); * sig.init(certPEM); * sig.updateString('aaa'); * var isValid = sig.verify(sigValueHex); */ KJUR.crypto.Signature = function(params) { var prvKey = null; // RSAKey/KJUR.crypto.{ECDSA,DSA} object for signing var pubKey = null; // RSAKey/KJUR.crypto.{ECDSA,DSA} object for verifying var md = null; // KJUR.crypto.MessageDigest object var sig = null; var algName = null; var provName = null; var algProvName = null; var mdAlgName = null; var pubkeyAlgName = null; // rsa,ecdsa,rsaandmgf1(=rsapss) var state = null; var pssSaltLen = -1; var initParams = null; var sHashHex = null; // hex hash value for hex var hDigestInfo = null; var hPaddedDigestInfo = null; var hSign = null; this._setAlgNames = function() { if (this.algName.match(/^(.+)with(.+)$/)) { this.mdAlgName = RegExp.$1.toLowerCase(); this.pubkeyAlgName = RegExp.$2.toLowerCase(); } }; this._zeroPaddingOfSignature = function(hex, bitLength) { var s = ""; var nZero = bitLength / 4 - hex.length; for (var i = 0; i < nZero; i++) { s = s + "0"; } return s + hex; }; /** * set signature algorithm and provider * @name setAlgAndProvider * @memberOf KJUR.crypto.Signature * @function * @param {String} alg signature algorithm name * @param {String} prov provider name * @description * @example * md.setAlgAndProvider('SHA1withRSA', 'cryptojs/jsrsa'); */ this.setAlgAndProvider = function(alg, prov) { this._setAlgNames(); if (prov != 'cryptojs/jsrsa') throw "provider not supported: " + prov; if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(this.mdAlgName) != -1) { try { this.md = new KJUR.crypto.MessageDigest({'alg':this.mdAlgName}); } catch (ex) { throw "setAlgAndProvider hash alg set fail alg=" + this.mdAlgName + "/" + ex; } this.init = function(keyparam, pass) { var keyObj = null; try { if (pass === undefined) { keyObj = KEYUTIL.getKey(keyparam); } else { keyObj = KEYUTIL.getKey(keyparam, pass); } } catch (ex) { throw "init failed:" + ex; } if (keyObj.isPrivate === true) { this.prvKey = keyObj; this.state = "SIGN"; } else if (keyObj.isPublic === true) { this.pubKey = keyObj; this.state = "VERIFY"; } else { throw "init failed.:" + keyObj; } }; this.initSign = function(params) { if (typeof params['ecprvhex'] == 'string' && typeof params['eccurvename'] == 'string') { this.ecprvhex = params['ecprvhex']; this.eccurvename = params['eccurvename']; } else { this.prvKey = params; } this.state = "SIGN"; }; this.initVerifyByPublicKey = function(params) { if (typeof params['ecpubhex'] == 'string' && typeof params['eccurvename'] == 'string') { this.ecpubhex = params['ecpubhex']; this.eccurvename = params['eccurvename']; } else if (params instanceof KJUR.crypto.ECDSA) { this.pubKey = params; } else if (params instanceof RSAKey) { this.pubKey = params; } this.state = "VERIFY"; }; this.initVerifyByCertificatePEM = function(certPEM) { var x509 = new X509(); x509.readCertPEM(certPEM); this.pubKey = x509.subjectPublicKeyRSA; this.state = "VERIFY"; }; this.updateString = function(str) { this.md.updateString(str); }; this.updateHex = function(hex) { this.md.updateHex(hex); }; this.sign = function() { this.sHashHex = this.md.digest(); if (typeof this.ecprvhex != "undefined" && typeof this.eccurvename != "undefined") { var ec = new KJUR.crypto.ECDSA({'curve': this.eccurvename}); this.hSign = ec.signHex(this.sHashHex, this.ecprvhex); } else if (this.pubkeyAlgName == "rsaandmgf1") { this.hSign = this.prvKey.signWithMessageHashPSS(this.sHashHex, this.mdAlgName, this.pssSaltLen); } else if (this.pubkeyAlgName == "rsa") { this.hSign = this.prvKey.signWithMessageHash(this.sHashHex, this.mdAlgName); } else if (this.prvKey instanceof KJUR.crypto.ECDSA) { this.hSign = this.prvKey.signWithMessageHash(this.sHashHex); } else if (this.prvKey instanceof KJUR.crypto.DSA) { this.hSign = this.prvKey.signWithMessageHash(this.sHashHex); } else { throw "Signature: unsupported public key alg: " + this.pubkeyAlgName; } return this.hSign; }; this.signString = function(str) { this.updateString(str); return this.sign(); }; this.signHex = function(hex) { this.updateHex(hex); return this.sign(); }; this.verify = function(hSigVal) { this.sHashHex = this.md.digest(); if (typeof this.ecpubhex != "undefined" && typeof this.eccurvename != "undefined") { var ec = new KJUR.crypto.ECDSA({curve: this.eccurvename}); return ec.verifyHex(this.sHashHex, hSigVal, this.ecpubhex); } else if (this.pubkeyAlgName == "rsaandmgf1") { return this.pubKey.verifyWithMessageHashPSS(this.sHashHex, hSigVal, this.mdAlgName, this.pssSaltLen); } else if (this.pubkeyAlgName == "rsa") { return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal); } else if (this.pubKey instanceof KJUR.crypto.ECDSA) { return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal); } else if (this.pubKey instanceof KJUR.crypto.DSA) { return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal); } else { throw "Signature: unsupported public key alg: " + this.pubkeyAlgName; } }; } }; /** * Initialize this object for signing or verifying depends on key * @name init * @memberOf KJUR.crypto.Signature * @function * @param {Object} key specifying public or private key as plain/encrypted PKCS#5/8 PEM file, certificate PEM or {@link RSAKey}, {@link KJUR.crypto.DSA} or {@link KJUR.crypto.ECDSA} object * @param {String} pass (OPTION) passcode for encrypted private key * @since crypto 1.1.3 * @description * This method is very useful initialize method for Signature class since * you just specify key then this method will automatically initialize it * using {@link KEYUTIL.getKey} method. * As for 'key', following argument type are supported: *
signing
*
    *
  • PEM formatted PKCS#8 encrypted RSA/ECDSA private key concluding "BEGIN ENCRYPTED PRIVATE KEY"
  • *
  • PEM formatted PKCS#5 encrypted RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" and ",ENCRYPTED"
  • *
  • PEM formatted PKCS#8 plain RSA/ECDSA private key concluding "BEGIN PRIVATE KEY"
  • *
  • PEM formatted PKCS#5 plain RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" without ",ENCRYPTED"
  • *
  • RSAKey object of private key
  • *
  • KJUR.crypto.ECDSA object of private key
  • *
  • KJUR.crypto.DSA object of private key
  • *
*
verification
*
    *
  • PEM formatted PKCS#8 RSA/EC/DSA public key concluding "BEGIN PUBLIC KEY"
  • *
  • PEM formatted X.509 certificate with RSA/EC/DSA public key concluding * "BEGIN CERTIFICATE", "BEGIN X509 CERTIFICATE" or "BEGIN TRUSTED CERTIFICATE".
  • *
  • RSAKey object of public key
  • *
  • KJUR.crypto.ECDSA object of public key
  • *
  • KJUR.crypto.DSA object of public key
  • *
* @example * sig.init(sCertPEM) */ this.init = function(key, pass) { throw "init(key, pass) not supported for this alg:prov=" + this.algProvName; }; /** * Initialize this object for verifying with a public key * @name initVerifyByPublicKey * @memberOf KJUR.crypto.Signature * @function * @param {Object} param RSAKey object of public key or associative array for ECDSA * @since 1.0.2 * @deprecated from crypto 1.1.5. please use init() method instead. * @description * Public key information will be provided as 'param' parameter and the value will be * following: *
    *
  • {@link RSAKey} object for RSA verification
  • *
  • associative array for ECDSA verification * (ex. {'ecpubhex': '041f..', 'eccurvename': 'secp256r1'}) *
  • *
* @example * sig.initVerifyByPublicKey(rsaPrvKey) */ this.initVerifyByPublicKey = function(rsaPubKey) { throw "initVerifyByPublicKey(rsaPubKeyy) not supported for this alg:prov=" + this.algProvName; }; /** * Initialize this object for verifying with a certficate * @name initVerifyByCertificatePEM * @memberOf KJUR.crypto.Signature * @function * @param {String} certPEM PEM formatted string of certificate * @since 1.0.2 * @deprecated from crypto 1.1.5. please use init() method instead. * @description * @example * sig.initVerifyByCertificatePEM(certPEM) */ this.initVerifyByCertificatePEM = function(certPEM) { throw "initVerifyByCertificatePEM(certPEM) not supported for this alg:prov=" + this.algProvName; }; /** * Initialize this object for signing * @name initSign * @memberOf KJUR.crypto.Signature * @function * @param {Object} param RSAKey object of public key or associative array for ECDSA * @deprecated from crypto 1.1.5. please use init() method instead. * @description * Private key information will be provided as 'param' parameter and the value will be * following: *
    *
  • {@link RSAKey} object for RSA signing
  • *
  • associative array for ECDSA signing * (ex. {'ecprvhex': '1d3f..', 'eccurvename': 'secp256r1'})
  • *
* @example * sig.initSign(prvKey) */ this.initSign = function(prvKey) { throw "initSign(prvKey) not supported for this alg:prov=" + this.algProvName; }; /** * Updates the data to be signed or verified by a string * @name updateString * @memberOf KJUR.crypto.Signature * @function * @param {String} str string to use for the update * @description * @example * sig.updateString('aaa') */ this.updateString = function(str) { throw "updateString(str) not supported for this alg:prov=" + this.algProvName; }; /** * Updates the data to be signed or verified by a hexadecimal string * @name updateHex * @memberOf KJUR.crypto.Signature * @function * @param {String} hex hexadecimal string to use for the update * @description * @example * sig.updateHex('1f2f3f') */ this.updateHex = function(hex) { throw "updateHex(hex) not supported for this alg:prov=" + this.algProvName; }; /** * Returns the signature bytes of all data updates as a hexadecimal string * @name sign * @memberOf KJUR.crypto.Signature * @function * @return the signature bytes as a hexadecimal string * @description * @example * var hSigValue = sig.sign() */ this.sign = function() { throw "sign() not supported for this alg:prov=" + this.algProvName; }; /** * performs final update on the sign using string, then returns the signature bytes of all data updates as a hexadecimal string * @name signString * @memberOf KJUR.crypto.Signature * @function * @param {String} str string to final update * @return the signature bytes of a hexadecimal string * @description * @example * var hSigValue = sig.signString('aaa') */ this.signString = function(str) { throw "digestString(str) not supported for this alg:prov=" + this.algProvName; }; /** * performs final update on the sign using hexadecimal string, then returns the signature bytes of all data updates as a hexadecimal string * @name signHex * @memberOf KJUR.crypto.Signature * @function * @param {String} hex hexadecimal string to final update * @return the signature bytes of a hexadecimal string * @description * @example * var hSigValue = sig.signHex('1fdc33') */ this.signHex = function(hex) { throw "digestHex(hex) not supported for this alg:prov=" + this.algProvName; }; /** * verifies the passed-in signature. * @name verify * @memberOf KJUR.crypto.Signature * @function * @param {String} str string to final update * @return {Boolean} true if the signature was verified, otherwise false * @description * @example * var isValid = sig.verify('1fbcefdca4823a7(snip)') */ this.verify = function(hSigVal) { throw "verify(hSigVal) not supported for this alg:prov=" + this.algProvName; }; this.initParams = params; if (params !== undefined) { if (params['alg'] !== undefined) { this.algName = params['alg']; if (params['prov'] === undefined) { this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName]; } else { this.provName = params['prov']; } this.algProvName = this.algName + ":" + this.provName; this.setAlgAndProvider(this.algName, this.provName); this._setAlgNames(); } if (params['psssaltlen'] !== undefined) this.pssSaltLen = params['psssaltlen']; if (params['prvkeypem'] !== undefined) { if (params['prvkeypas'] !== undefined) { throw "both prvkeypem and prvkeypas parameters not supported"; } else { try { var prvKey = new RSAKey(); prvKey.readPrivateKeyFromPEMString(params['prvkeypem']); this.initSign(prvKey); } catch (ex) { throw "fatal error to load pem private key: " + ex; } } } } }; /** * static object for cryptographic function utilities * @name KJUR.crypto.OID * @class static object for cryptography related OIDs * @property {Array} oidhex2name key value of hexadecimal OID and its name * (ex. '2a8648ce3d030107' and 'secp256r1') * @since crypto 1.1.3 * @description */ KJUR.crypto.OID = new function() { this.oidhex2name = { '2a864886f70d010101': 'rsaEncryption', '2a8648ce3d0201': 'ecPublicKey', '2a8648ce380401': 'dsa', '2a8648ce3d030107': 'secp256r1', '2b8104001f': 'secp192k1', '2b81040021': 'secp224r1', '2b8104000a': 'secp256k1', '2b81040023': 'secp521r1', '2b81040022': 'secp384r1', '2a8648ce380403': 'SHA1withDSA', // 1.2.840.10040.4.3 '608648016503040301': 'SHA224withDSA', // 2.16.840.1.101.3.4.3.1 '608648016503040302': 'SHA256withDSA', // 2.16.840.1.101.3.4.3.2 }; }; /*! base64x-1.1.3 (c) 2012-2014 Kenji Urushima | kjur.github.com/jsjws/license */ /* * base64x.js - Base64url and supplementary functions for Tom Wu's base64.js library * * version: 1.1.3 (2014 May 25) * * Copyright (c) 2012-2014 Kenji Urushima (kenji.urushima@gmail.com) * * This software is licensed under the terms of the MIT License. * http://kjur.github.com/jsjws/license/ * * The above copyright and license notice shall be * included in all copies or substantial portions of the Software. * * DEPENDS ON: * - base64.js - Tom Wu's Base64 library */ /** * Base64URL and supplementary functions for Tom Wu's base64.js library.
* This class is just provide information about global functions * defined in 'base64x.js'. The 'base64x.js' script file provides * global functions for converting following data each other. *
    *
  • (ASCII) String
  • *
  • UTF8 String including CJK, Latin and other characters
  • *
  • byte array
  • *
  • hexadecimal encoded String
  • *
  • Full URIComponent encoded String (such like "%69%94")
  • *
  • Base64 encoded String
  • *
  • Base64URL encoded String
  • *
* All functions in 'base64x.js' are defined in {@link _global_} and not * in this class. * * @class Base64URL and supplementary functions for Tom Wu's base64.js library * @author Kenji Urushima * @version 1.1 (07 May 2012) * @requires base64.js * @see 'jwjws'(JWS JavaScript Library) home page http://kjur.github.com/jsjws/ * @see 'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/ */ function Base64x() { } // ==== string / byte array ================================ /** * convert a string to an array of character codes * @param {String} s * @return {Array of Numbers} */ function stoBA(s) { var a = new Array(); for (var i = 0; i < s.length; i++) { a[i] = s.charCodeAt(i); } return a; } /** * convert an array of character codes to a string * @param {Array of Numbers} a array of character codes * @return {String} s */ function BAtos(a) { var s = ""; for (var i = 0; i < a.length; i++) { s = s + String.fromCharCode(a[i]); } return s; } // ==== byte array / hex ================================ /** * convert an array of bytes(Number) to hexadecimal string.
* @param {Array of Numbers} a array of bytes * @return {String} hexadecimal string */ function BAtohex(a) { var s = ""; for (var i = 0; i < a.length; i++) { var hex1 = a[i].toString(16); if (hex1.length == 1) hex1 = "0" + hex1; s = s + hex1; } return s; } // ==== string / hex ================================ /** * convert a ASCII string to a hexadecimal string of ASCII codes.
* NOTE: This can't be used for non ASCII characters. * @param {s} s ASCII string * @return {String} hexadecimal string */ function stohex(s) { return BAtohex(stoBA(s)); } // ==== string / base64 ================================ /** * convert a ASCII string to a Base64 encoded string.
* NOTE: This can't be used for non ASCII characters. * @param {s} s ASCII string * @return {String} Base64 encoded string */ function stob64(s) { return hex2b64(stohex(s)); } // ==== string / base64url ================================ /** * convert a ASCII string to a Base64URL encoded string.
* NOTE: This can't be used for non ASCII characters. * @param {s} s ASCII string * @return {String} Base64URL encoded string */ function stob64u(s) { return b64tob64u(hex2b64(stohex(s))); } /** * convert a Base64URL encoded string to a ASCII string.
* NOTE: This can't be used for Base64URL encoded non ASCII characters. * @param {s} s Base64URL encoded string * @return {String} ASCII string */ function b64utos(s) { return BAtos(b64toBA(b64utob64(s))); } // ==== base64 / base64url ================================ /** * convert a Base64 encoded string to a Base64URL encoded string.
* Example: "ab+c3f/==" → "ab-c3f_" * @param {String} s Base64 encoded string * @return {String} Base64URL encoded string */ function b64tob64u(s) { s = s.replace(/\=/g, ""); s = s.replace(/\+/g, "-"); s = s.replace(/\//g, "_"); return s; } /** * convert a Base64URL encoded string to a Base64 encoded string.
* Example: "ab-c3f_" → "ab+c3f/==" * @param {String} s Base64URL encoded string * @return {String} Base64 encoded string */ function b64utob64(s) { if (s.length % 4 == 2) s = s + "=="; else if (s.length % 4 == 3) s = s + "="; s = s.replace(/-/g, "+"); s = s.replace(/_/g, "/"); return s; } // ==== hex / base64url ================================ /** * convert a hexadecimal string to a Base64URL encoded string.
* @param {String} s hexadecimal string * @return {String} Base64URL encoded string */ function hextob64u(s) { return b64tob64u(hex2b64(s)); } /** * convert a Base64URL encoded string to a hexadecimal string.
* @param {String} s Base64URL encoded string * @return {String} hexadecimal string */ function b64utohex(s) { return b64tohex(b64utob64(s)); } var utf8tob64u, b64utoutf8; if (typeof Buffer === 'function') { utf8tob64u = function (s) { return b64tob64u(new Buffer(s, 'utf8').toString('base64')); }; b64utoutf8 = function (s) { return new Buffer(b64utob64(s), 'base64').toString('utf8'); }; } else { // ==== utf8 / base64url ================================ /** * convert a UTF-8 encoded string including CJK or Latin to a Base64URL encoded string.
* @param {String} s UTF-8 encoded string * @return {String} Base64URL encoded string * @since 1.1 */ utf8tob64u = function (s) { return hextob64u(uricmptohex(encodeURIComponentAll(s))); }; /** * convert a Base64URL encoded string to a UTF-8 encoded string including CJK or Latin.
* @param {String} s Base64URL encoded string * @return {String} UTF-8 encoded string * @since 1.1 */ b64utoutf8 = function (s) { return decodeURIComponent(hextouricmp(b64utohex(s))); }; } // ==== utf8 / base64url ================================ /** * convert a UTF-8 encoded string including CJK or Latin to a Base64 encoded string.
* @param {String} s UTF-8 encoded string * @return {String} Base64 encoded string * @since 1.1.1 */ function utf8tob64(s) { return hex2b64(uricmptohex(encodeURIComponentAll(s))); } /** * convert a Base64 encoded string to a UTF-8 encoded string including CJK or Latin.
* @param {String} s Base64 encoded string * @return {String} UTF-8 encoded string * @since 1.1.1 */ function b64toutf8(s) { return decodeURIComponent(hextouricmp(b64tohex(s))); } // ==== utf8 / hex ================================ /** * convert a UTF-8 encoded string including CJK or Latin to a hexadecimal encoded string.
* @param {String} s UTF-8 encoded string * @return {String} hexadecimal encoded string * @since 1.1.1 */ function utf8tohex(s) { return uricmptohex(encodeURIComponentAll(s)); } /** * convert a hexadecimal encoded string to a UTF-8 encoded string including CJK or Latin.
* Note that when input is improper hexadecimal string as UTF-8 string, this function returns * 'null'. * @param {String} s hexadecimal encoded string * @return {String} UTF-8 encoded string or null * @since 1.1.1 */ function hextoutf8(s) { return decodeURIComponent(hextouricmp(s)); } /** * convert a hexadecimal encoded string to raw string including non printable characters.
* @param {String} s hexadecimal encoded string * @return {String} raw string * @since 1.1.2 * @example * hextorstr("610061") → "a\x00a" */ function hextorstr(sHex) { var s = ""; for (var i = 0; i < sHex.length - 1; i += 2) { s += String.fromCharCode(parseInt(sHex.substr(i, 2), 16)); } return s; } /** * convert a raw string including non printable characters to hexadecimal encoded string.
* @param {String} s raw string * @return {String} hexadecimal encoded string * @since 1.1.2 * @example * rstrtohex("a\x00a") → "610061" */ function rstrtohex(s) { var result = ""; for (var i = 0; i < s.length; i++) { result += ("0" + s.charCodeAt(i).toString(16)).slice(-2); } return result; } // ==== hex / b64nl ======================================= /* * since base64x 1.1.3 */ function hextob64(s) { return hex2b64(s); } /* * since base64x 1.1.3 */ function hextob64nl(s) { var b64 = hextob64(s); var b64nl = b64.replace(/(.{64})/g, "$1\r\n"); b64nl = b64nl.replace(/\r\n$/, ''); return b64nl; } /* * since base64x 1.1.3 */ function b64nltohex(s) { var b64 = s.replace(/[^0-9A-Za-z\/+=]*/g, ''); var hex = b64tohex(b64); return hex; } // ==== URIComponent / hex ================================ /** * convert a URLComponent string such like "%67%68" to a hexadecimal string.
* @param {String} s URIComponent string such like "%67%68" * @return {String} hexadecimal string * @since 1.1 */ function uricmptohex(s) { return s.replace(/%/g, ""); } /** * convert a hexadecimal string to a URLComponent string such like "%67%68".
* @param {String} s hexadecimal string * @return {String} URIComponent string such like "%67%68" * @since 1.1 */ function hextouricmp(s) { return s.replace(/(..)/g, "%$1"); } // ==== URIComponent ================================ /** * convert UTFa hexadecimal string to a URLComponent string such like "%67%68".
* Note that these "0-9A-Za-z!'()*-._~" characters will not * converted to "%xx" format by builtin 'encodeURIComponent()' function. * However this 'encodeURIComponentAll()' function will convert * all of characters into "%xx" format. * @param {String} s hexadecimal string * @return {String} URIComponent string such like "%67%68" * @since 1.1 */ function encodeURIComponentAll(u8) { var s = encodeURIComponent(u8); var s2 = ""; for (var i = 0; i < s.length; i++) { if (s[i] == "%") { s2 = s2 + s.substr(i, 3); i = i + 2; } else { s2 = s2 + "%" + stohex(s[i]); } } return s2; } // ==== new lines ================================ /** * convert all DOS new line("\r\n") to UNIX new line("\n") in * a String "s". * @param {String} s string * @return {String} converted string */ function newline_toUnix(s) { s = s.replace(/\r\n/mg, "\n"); return s; } /** * convert all UNIX new line("\r\n") to DOS new line("\n") in * a String "s". * @param {String} s string * @return {String} converted string */ function newline_toDos(s) { s = s.replace(/\r\n/mg, "\n"); s = s.replace(/\n/mg, "\r\n"); return s; } /*! Mike Samuel (c) 2009 | code.google.com/p/json-sans-eval */ // This source code is free for use in the public domain. // NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. // http://code.google.com/p/json-sans-eval/ /** * Parses a string of well-formed JSON text. * * If the input is not well-formed, then behavior is undefined, but it is * deterministic and is guaranteed not to modify any object other than its * return value. * * This does not use `eval` so is less likely to have obscure security bugs than * json2.js. * It is optimized for speed, so is much faster than json_parse.js. * * This library should be used whenever security is a concern (when JSON may * come from an untrusted source), speed is a concern, and erroring on malformed * JSON is *not* a concern. * * Pros Cons * +-----------------------+-----------------------+ * json_sans_eval.js | Fast, secure | Not validating | * +-----------------------+-----------------------+ * json_parse.js | Validating, secure | Slow | * +-----------------------+-----------------------+ * json2.js | Fast, some validation | Potentially insecure | * +-----------------------+-----------------------+ * * json2.js is very fast, but potentially insecure since it calls `eval` to * parse JSON data, so an attacker might be able to supply strange JS that * looks like JSON, but that executes arbitrary javascript. * If you do have to use json2.js with untrusted data, make sure you keep * your version of json2.js up to date so that you get patches as they're * released. * * @param {string} json per RFC 4627 * @param {function (this:Object, string, *):*} opt_reviver optional function * that reworks JSON objects post-parse per Chapter 15.12 of EcmaScript3.1. * If supplied, the function is called with a string key, and a value. * The value is the property of 'this'. The reviver should return * the value to use in its place. So if dates were serialized as * {@code { "type": "Date", "time": 1234 }}, then a reviver might look like * {@code * function (key, value) { * if (value && typeof value === 'object' && 'Date' === value.type) { * return new Date(value.time); * } else { * return value; * } * }}. * If the reviver returns {@code undefined} then the property named by key * will be deleted from its container. * {@code this} is bound to the object containing the specified property. * @return {Object|Array} * @author Mike Samuel */ var jsonParse = (function () { var number = '(?:-?\\b(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b)'; var oneChar = '(?:[^\\0-\\x08\\x0a-\\x1f\"\\\\]' + '|\\\\(?:[\"/\\\\bfnrt]|u[0-9A-Fa-f]{4}))'; var string = '(?:\"' + oneChar + '*\")'; // Will match a value in a well-formed JSON file. // If the input is not well-formed, may match strangely, but not in an unsafe // way. // Since this only matches value tokens, it does not match whitespace, colons, // or commas. var jsonToken = new RegExp( '(?:false|true|null|[\\{\\}\\[\\]]' + '|' + number + '|' + string + ')', 'g'); // Matches escape sequences in a string literal var escapeSequence = new RegExp('\\\\(?:([^u])|u(.{4}))', 'g'); // Decodes escape sequences in object literals var escapes = { '"': '"', '/': '/', '\\': '\\', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t' }; function unescapeOne(_, ch, hex) { return ch ? escapes[ch] : String.fromCharCode(parseInt(hex, 16)); } // A non-falsy value that coerces to the empty string when used as a key. var EMPTY_STRING = new String(''); var SLASH = '\\'; // Constructor to use based on an open token. var firstTokenCtors = { '{': Object, '[': Array }; var hop = Object.hasOwnProperty; return function (json, opt_reviver) { // Split into tokens var toks = json.match(jsonToken); // Construct the object to return var result; var tok = toks[0]; var topLevelPrimitive = false; if ('{' === tok) { result = {}; } else if ('[' === tok) { result = []; } else { // The RFC only allows arrays or objects at the top level, but the JSON.parse // defined by the EcmaScript 5 draft does allow strings, booleans, numbers, and null // at the top level. result = []; topLevelPrimitive = true; } // If undefined, the key in an object key/value record to use for the next // value parsed. var key; // Loop over remaining tokens maintaining a stack of uncompleted objects and // arrays. var stack = [result]; for (var i = 1 - topLevelPrimitive, n = toks.length; i < n; ++i) { tok = toks[i]; var cont; switch (tok.charCodeAt(0)) { default: // sign or digit cont = stack[0]; cont[key || cont.length] = +(tok); key = void 0; break; case 0x22: // '"' tok = tok.substring(1, tok.length - 1); if (tok.indexOf(SLASH) !== -1) { tok = tok.replace(escapeSequence, unescapeOne); } cont = stack[0]; if (!key) { if (cont instanceof Array) { key = cont.length; } else { key = tok || EMPTY_STRING; // Use as key for next value seen. break; } } cont[key] = tok; key = void 0; break; case 0x5b: // '[' cont = stack[0]; stack.unshift(cont[key || cont.length] = []); key = void 0; break; case 0x5d: // ']' stack.shift(); break; case 0x66: // 'f' cont = stack[0]; cont[key || cont.length] = false; key = void 0; break; case 0x6e: // 'n' cont = stack[0]; cont[key || cont.length] = null; key = void 0; break; case 0x74: // 't' cont = stack[0]; cont[key || cont.length] = true; key = void 0; break; case 0x7b: // '{' cont = stack[0]; stack.unshift(cont[key || cont.length] = {}); key = void 0; break; case 0x7d: // '}' stack.shift(); break; } } // Fail if we've got an uncompleted object. if (topLevelPrimitive) { if (stack.length !== 1) { throw new Error(); } result = result[0]; } else { if (stack.length) { throw new Error(); } } if (opt_reviver) { // Based on walk as implemented in http://www.json.org/json2.js var walk = function (holder, key) { var value = holder[key]; if (value && typeof value === 'object') { var toDelete = null; for (var k in value) { if (hop.call(value, k) && value !== holder) { // Recurse to properties first. This has the effect of causing // the reviver to be called on the object graph depth-first. // Since 'this' is bound to the holder of the property, the // reviver can access sibling properties of k including ones // that have not yet been revived. // The value returned by the reviver is used in place of the // current value of property k. // If it returns undefined then the property is deleted. var v = walk(value, k); if (v !== void 0) { value[k] = v; } else { // Deleting properties inside the loop has vaguely defined // semantics in ES3 and ES3.1. if (!toDelete) { toDelete = []; } toDelete.push(k); } } } if (toDelete) { for (var i = toDelete.length; --i >= 0;) { delete value[toDelete[i]]; } } } return opt_reviver.call(holder, key, value); }; result = walk({ '': result }, ''); } return result; }; })(); /*! jws-3.0.2 (c) 2013 Kenji Urushima | kjur.github.com/jsjws/license */ /* * jws.js - JSON Web Signature Class * * version: 3.0.2 (2013 Sep 24) * * Copyright (c) 2010-2013 Kenji Urushima (kenji.urushima@gmail.com) * * This software is licensed under the terms of the MIT License. * http://kjur.github.com/jsjws/license/ * * The above copyright and license notice shall be * included in all copies or substantial portions of the Software. */ /** * @fileOverview * @name jws-3.0.js * @author Kenji Urushima kenji.urushima@gmail.com * @version 3.0.1 (2013-Sep-24) * @since jsjws 1.0 * @license MIT License */ if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; if (typeof KJUR.jws == "undefined" || !KJUR.jws) KJUR.jws = {}; /** * JSON Web Signature(JWS) class.
* @name KJUR.jws.JWS * @class JSON Web Signature(JWS) class * @property {Dictionary} parsedJWS This property is set after JWS signature verification.
* Following "parsedJWS_*" properties can be accessed as "parsedJWS.*" because of * JsDoc restriction. * @property {String} parsedJWS_headB64U string of Encrypted JWS Header * @property {String} parsedJWS_payloadB64U string of Encrypted JWS Payload * @property {String} parsedJWS_sigvalB64U string of Encrypted JWS signature value * @property {String} parsedJWS_si string of Signature Input * @property {String} parsedJWS_sigvalH hexadecimal string of JWS signature value * @property {String} parsedJWS_sigvalBI BigInteger(defined in jsbn.js) object of JWS signature value * @property {String} parsedJWS_headS string of decoded JWS Header * @property {String} parsedJWS_headS string of decoded JWS Payload * @requires base64x.js, json-sans-eval.js and jsrsasign library * @see 'jwjws'(JWS JavaScript Library) home page http://kjur.github.com/jsjws/ * @see 'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/ * @see IETF I-D JSON Web Algorithms (JWA) * @since jsjws 1.0 * @description *

Supported Algorithms

* Here is supported algorithm names for {@link KJUR.jws.JWS.sign} and {@link KJUR.jws.JWS.verify} * methods. * * * * * * * * * * * * * * * *
alg valuespec requirementjsjws support
HS256REQUIREDSUPPORTED
HS384OPTIONALSUPPORTED
HS512OPTIONALSUPPORTED
RS256RECOMMENDEDSUPPORTED
RS384OPTIONALSUPPORTED
RS512OPTIONALSUPPORTED
ES256RECOMMENDED+SUPPORTED
ES384OPTIONALSUPPORTED
ES512OPTIONAL-
PS256OPTIONALSUPPORTED
PS384OPTIONALSUPPORTED
PS512OPTIONALSUPPORTED
noneREQUIREDSUPPORTED
* NOTE: HS384 is supported since jsjws 3.0.2 with jsrsasign 4.1.4. */ KJUR.jws.JWS = function() { // === utility ============================================================= /** * parse JWS string and set public property 'parsedJWS' dictionary.
* @name parseJWS * @memberOf KJUR.jws.JWS * @function * @param {String} sJWS JWS signature string to be parsed. * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". * @throws if JWS Header is a malformed JSON string. * @since jws 1.1 */ this.parseJWS = function(sJWS, sigValNotNeeded) { if ((this.parsedJWS !== undefined) && (sigValNotNeeded || (this.parsedJWS.sigvalH !== undefined))) { return; } if (sJWS.match(/^([^.]+)\.([^.]+)\.([^.]+)$/) == null) { throw "JWS signature is not a form of 'Head.Payload.SigValue'."; } var b6Head = RegExp.$1; var b6Payload = RegExp.$2; var b6SigVal = RegExp.$3; var sSI = b6Head + "." + b6Payload; this.parsedJWS = {}; this.parsedJWS.headB64U = b6Head; this.parsedJWS.payloadB64U = b6Payload; this.parsedJWS.sigvalB64U = b6SigVal; this.parsedJWS.si = sSI; if (!sigValNotNeeded) { var hSigVal = b64utohex(b6SigVal); var biSigVal = parseBigInt(hSigVal, 16); this.parsedJWS.sigvalH = hSigVal; this.parsedJWS.sigvalBI = biSigVal; } var sHead = b64utoutf8(b6Head); var sPayload = b64utoutf8(b6Payload); this.parsedJWS.headS = sHead; this.parsedJWS.payloadS = sPayload; if (!KJUR.jws.JWS.isSafeJSONString(sHead, this.parsedJWS, 'headP')) throw "malformed JSON string for JWS Head: " + sHead; }; // ==== JWS Validation ========================================================= function _getSignatureInputByString(sHead, sPayload) { return utf8tob64u(sHead) + "." + utf8tob64u(sPayload); }; function _getHashBySignatureInput(sSignatureInput, sHashAlg) { var hashfunc = function(s) { return KJUR.crypto.Util.hashString(s, sHashAlg); }; if (hashfunc == null) throw "hash function not defined in jsrsasign: " + sHashAlg; return hashfunc(sSignatureInput); }; function _jws_verifySignature(sHead, sPayload, hSig, hN, hE) { var sSignatureInput = _getSignatureInputByString(sHead, sPayload); var biSig = parseBigInt(hSig, 16); return _rsasign_verifySignatureWithArgs(sSignatureInput, biSig, hN, hE); }; /** * verify JWS signature with naked RSA public key.
* This only supports "RS256" and "RS512" algorithm. * @name verifyJWSByNE * @memberOf KJUR.jws.JWS * @function * @param {String} sJWS JWS signature string to be verified * @param {String} hN hexadecimal string for modulus of RSA public key * @param {String} hE hexadecimal string for public exponent of RSA public key * @return {String} returns 1 when JWS signature is valid, otherwise returns 0 * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". * @throws if JWS Header is a malformed JSON string. * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify} */ this.verifyJWSByNE = function(sJWS, hN, hE) { this.parseJWS(sJWS); return _rsasign_verifySignatureWithArgs(this.parsedJWS.si, this.parsedJWS.sigvalBI, hN, hE); }; /** * verify JWS signature with RSA public key.
* This only supports "RS256", "RS512", "PS256" and "PS512" algorithms. * @name verifyJWSByKey * @memberOf KJUR.jws.JWS * @function * @param {String} sJWS JWS signature string to be verified * @param {RSAKey} key RSA public key * @return {Boolean} returns true when JWS signature is valid, otherwise returns false * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". * @throws if JWS Header is a malformed JSON string. * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify} */ this.verifyJWSByKey = function(sJWS, key) { this.parseJWS(sJWS); var hashAlg = _jws_getHashAlgFromParsedHead(this.parsedJWS.headP); var isPSS = this.parsedJWS.headP['alg'].substr(0, 2) == "PS"; if (key.hashAndVerify) { return key.hashAndVerify(hashAlg, new Buffer(this.parsedJWS.si, 'utf8').toString('base64'), b64utob64(this.parsedJWS.sigvalB64U), 'base64', isPSS); } else if (isPSS) { return key.verifyStringPSS(this.parsedJWS.si, this.parsedJWS.sigvalH, hashAlg); } else { return key.verifyString(this.parsedJWS.si, this.parsedJWS.sigvalH); } }; /** * verify JWS signature by PEM formatted X.509 certificate.
* This only supports "RS256" and "RS512" algorithm. * @name verifyJWSByPemX509Cert * @memberOf KJUR.jws.JWS * @function * @param {String} sJWS JWS signature string to be verified * @param {String} sPemX509Cert string of PEM formatted X.509 certificate * @return {String} returns 1 when JWS signature is valid, otherwise returns 0 * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". * @throws if JWS Header is a malformed JSON string. * @since 1.1 * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify} */ this.verifyJWSByPemX509Cert = function(sJWS, sPemX509Cert) { this.parseJWS(sJWS); var x509 = new X509(); x509.readCertPEM(sPemX509Cert); return x509.subjectPublicKeyRSA.verifyString(this.parsedJWS.si, this.parsedJWS.sigvalH); }; // ==== JWS Generation ========================================================= function _jws_getHashAlgFromParsedHead(head) { var sigAlg = head["alg"]; var hashAlg = ""; if (sigAlg != "RS256" && sigAlg != "RS512" && sigAlg != "PS256" && sigAlg != "PS512") throw "JWS signature algorithm not supported: " + sigAlg; if (sigAlg.substr(2) == "256") hashAlg = "sha256"; if (sigAlg.substr(2) == "512") hashAlg = "sha512"; return hashAlg; }; function _jws_getHashAlgFromHead(sHead) { return _jws_getHashAlgFromParsedHead(jsonParse(sHead)); }; function _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD) { var rsa = new RSAKey(); rsa.setPrivate(hN, hE, hD); var hashAlg = _jws_getHashAlgFromHead(sHead); var sigValue = rsa.signString(sSI, hashAlg); return sigValue; }; function _jws_generateSignatureValueBySI_Key(sHead, sPayload, sSI, key, head) { var hashAlg = null; if (typeof head == "undefined") { hashAlg = _jws_getHashAlgFromHead(sHead); } else { hashAlg = _jws_getHashAlgFromParsedHead(head); } var isPSS = head['alg'].substr(0, 2) == "PS"; if (key.hashAndSign) { return b64tob64u(key.hashAndSign(hashAlg, sSI, 'binary', 'base64', isPSS)); } else if (isPSS) { return hextob64u(key.signStringPSS(sSI, hashAlg)); } else { return hextob64u(key.signString(sSI, hashAlg)); } }; function _jws_generateSignatureValueByNED(sHead, sPayload, hN, hE, hD) { var sSI = _getSignatureInputByString(sHead, sPayload); return _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD); }; /** * generate JWS signature by Header, Payload and a naked RSA private key.
* This only supports "RS256" and "RS512" algorithm. * @name generateJWSByNED * @memberOf KJUR.jws.JWS * @function * @param {String} sHead string of JWS Header * @param {String} sPayload string of JWS Payload * @param {String} hN hexadecimal string for modulus of RSA public key * @param {String} hE hexadecimal string for public exponent of RSA public key * @param {String} hD hexadecimal string for private exponent of RSA private key * @return {String} JWS signature string * @throws if sHead is a malformed JSON string. * @throws if supported signature algorithm was not specified in JSON Header. * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign} */ this.generateJWSByNED = function(sHead, sPayload, hN, hE, hD) { if (!KJUR.jws.JWS.isSafeJSONString(sHead)) throw "JWS Head is not safe JSON string: " + sHead; var sSI = _getSignatureInputByString(sHead, sPayload); var hSigValue = _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD); var b64SigValue = hextob64u(hSigValue); this.parsedJWS = {}; this.parsedJWS.headB64U = sSI.split(".")[0]; this.parsedJWS.payloadB64U = sSI.split(".")[1]; this.parsedJWS.sigvalB64U = b64SigValue; return sSI + "." + b64SigValue; }; /** * generate JWS signature by Header, Payload and a RSA private key.
* This only supports "RS256", "RS512", "PS256" and "PS512" algorithms. * @name generateJWSByKey * @memberOf KJUR.jws.JWS * @function * @param {String} sHead string of JWS Header * @param {String} sPayload string of JWS Payload * @param {RSAKey} RSA private key * @return {String} JWS signature string * @throws if sHead is a malformed JSON string. * @throws if supported signature algorithm was not specified in JSON Header. * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign} */ this.generateJWSByKey = function(sHead, sPayload, key) { var obj = {}; if (!KJUR.jws.JWS.isSafeJSONString(sHead, obj, 'headP')) throw "JWS Head is not safe JSON string: " + sHead; var sSI = _getSignatureInputByString(sHead, sPayload); var b64SigValue = _jws_generateSignatureValueBySI_Key(sHead, sPayload, sSI, key, obj.headP); this.parsedJWS = {}; this.parsedJWS.headB64U = sSI.split(".")[0]; this.parsedJWS.payloadB64U = sSI.split(".")[1]; this.parsedJWS.sigvalB64U = b64SigValue; return sSI + "." + b64SigValue; }; // === sign with PKCS#1 RSA private key ===================================================== function _jws_generateSignatureValueBySI_PemPrvKey(sHead, sPayload, sSI, sPemPrvKey) { var rsa = new RSAKey(); rsa.readPrivateKeyFromPEMString(sPemPrvKey); var hashAlg = _jws_getHashAlgFromHead(sHead); var sigValue = rsa.signString(sSI, hashAlg); return sigValue; }; /** * generate JWS signature by Header, Payload and a PEM formatted PKCS#1 RSA private key.
* This only supports "RS256" and "RS512" algorithm. * @name generateJWSByP1PrvKey * @memberOf KJUR.jws.JWS * @function * @param {String} sHead string of JWS Header * @param {String} sPayload string of JWS Payload * @param {String} string for sPemPrvKey PEM formatted PKCS#1 RSA private key
* Heading and trailing space characters in PEM key will be ignored. * @return {String} JWS signature string * @throws if sHead is a malformed JSON string. * @throws if supported signature algorithm was not specified in JSON Header. * @since 1.1 * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign} */ this.generateJWSByP1PrvKey = function(sHead, sPayload, sPemPrvKey) { if (!KJUR.jws.JWS.isSafeJSONString(sHead)) throw "JWS Head is not safe JSON string: " + sHead; var sSI = _getSignatureInputByString(sHead, sPayload); var hSigValue = _jws_generateSignatureValueBySI_PemPrvKey(sHead, sPayload, sSI, sPemPrvKey); var b64SigValue = hextob64u(hSigValue); this.parsedJWS = {}; this.parsedJWS.headB64U = sSI.split(".")[0]; this.parsedJWS.payloadB64U = sSI.split(".")[1]; this.parsedJWS.sigvalB64U = b64SigValue; return sSI + "." + b64SigValue; }; }; // === major static method ======================================================== /** * generate JWS signature by specified key
* @name sign * @memberOf KJUR.jws.JWS * @function * @static * @param {String} alg JWS algorithm name to sign and force set to sHead or null * @param {String} sHead string of JWS Header * @param {String} sPayload string of JWS Payload * @param {String} key string of private key or key object to sign * @param {String} pass (OPTION)passcode to use encrypted private key * @return {String} JWS signature string * @since jws 3.0.0 * @see jsrsasign KJUR.crypto.Signature method * @see jsrsasign KJUR.crypto.Mac method * @description * This method supports following algorithms. * * * * * * * * * * * * * * * *
alg valuespec requirementjsjws support
HS256REQUIREDSUPPORTED
HS384OPTIONAL-
HS512OPTIONALSUPPORTED
RS256RECOMMENDEDSUPPORTED
RS384OPTIONALSUPPORTED
RS512OPTIONALSUPPORTED
ES256RECOMMENDED+SUPPORTED
ES384OPTIONALSUPPORTED
ES512OPTIONAL-
PS256OPTIONALSUPPORTED
PS384OPTIONALSUPPORTED
PS512OPTIONALSUPPORTED
noneREQUIREDSUPPORTED
*
*
NOTE1: *
salt length of RSAPSS signature is the same as the hash algorithm length * because of IETF JOSE ML discussion. *
NOTE2: *
The reason of HS384 unsupport is * CryptoJS HmacSHA384 bug. *
*/ KJUR.jws.JWS.sign = function(alg, sHeader, sPayload, key, pass) { var ns1 = KJUR.jws.JWS; if (! ns1.isSafeJSONString(sHeader)) throw "JWS Head is not safe JSON string: " + sHead; var pHeader = ns1.readSafeJSONString(sHeader); // 1. use alg if defined in sHeader if ((alg == '' || alg == null) && pHeader['alg'] !== undefined) { alg = pHeader['alg']; } // 2. set alg in sHeader if undefined if ((alg != '' && alg != null) && pHeader['alg'] === undefined) { pHeader['alg'] = alg; sHeader = JSON.stringify(pHeader); } // 3. set signature algorithm like SHA1withRSA var sigAlg = null; if (ns1.jwsalg2sigalg[alg] === undefined) { throw "unsupported alg name: " + alg; } else { sigAlg = ns1.jwsalg2sigalg[alg]; } var uHeader = utf8tob64u(sHeader); var uPayload = utf8tob64u(sPayload); var uSignatureInput = uHeader + "." + uPayload // 4. sign var hSig = ""; if (sigAlg.substr(0, 4) == "Hmac") { if (key === undefined) throw "hexadecimal key shall be specified for HMAC"; var mac = new KJUR.crypto.Mac({'alg': sigAlg, 'pass': hextorstr(key)}); mac.updateString(uSignatureInput); hSig = mac.doFinal(); } else if (sigAlg.indexOf("withECDSA") != -1) { var sig = new KJUR.crypto.Signature({'alg': sigAlg}); sig.init(key, pass); sig.updateString(uSignatureInput); hASN1Sig = sig.sign(); hSig = KJUR.crypto.ECDSA.asn1SigToConcatSig(hASN1Sig); } else if (sigAlg != "none") { var sig = new KJUR.crypto.Signature({'alg': sigAlg}); sig.init(key, pass); sig.updateString(uSignatureInput); hSig = sig.sign(); } var uSig = hextob64u(hSig); return uSignatureInput + "." + uSig; }; /** * verify JWS signature by specified key or certificate
* @name verify * @memberOf KJUR.jws.JWS * @function * @static * @param {String} sJWS string of JWS signature to verify * @param {String} key string of public key, certificate or key object to verify * @return {Boolean} true if the signature is valid otherwise false * @since jws 3.0.0 * @see jsrsasign KJUR.crypto.Signature method * @see jsrsasign KJUR.crypto.Mac method */ KJUR.jws.JWS.verify = function(sJWS, key) { var jws = KJUR.jws.JWS; var a = sJWS.split("."); var uHeader = a[0]; var uPayload = a[1]; var uSignatureInput = uHeader + "." + uPayload; var hSig = b64utohex(a[2]); var pHeader = jws.readSafeJSONString(b64utoutf8(a[0])); var alg = null; if (pHeader.alg === undefined) { throw "algorithm not specified in header"; } else { alg = pHeader.alg; } var sigAlg = null; if (jws.jwsalg2sigalg[pHeader.alg] === undefined) { throw "unsupported alg name: " + alg; } else { sigAlg = jws.jwsalg2sigalg[alg]; } // x. verify if (sigAlg == "none") { return true; } else if (sigAlg.substr(0, 4) == "Hmac") { if (key === undefined) throw "hexadecimal key shall be specified for HMAC"; var mac = new KJUR.crypto.Mac({'alg': sigAlg, 'pass': hextorstr(key)}); mac.updateString(uSignatureInput); hSig2 = mac.doFinal(); return hSig == hSig2; } else if (sigAlg.indexOf("withECDSA") != -1) { var hASN1Sig = null; try { hASN1Sig = KJUR.crypto.ECDSA.concatSigToASN1Sig(hSig); } catch (ex) { return false; } var sig = new KJUR.crypto.Signature({'alg': sigAlg}); sig.init(key) sig.updateString(uSignatureInput); return sig.verify(hASN1Sig); } else { var sig = new KJUR.crypto.Signature({'alg': sigAlg}); sig.init(key) sig.updateString(uSignatureInput); return sig.verify(hSig); } }; /* * @since jws 3.0.0 */ KJUR.jws.JWS.jwsalg2sigalg = { "HS256": "HmacSHA256", //"HS384": "HmacSHA384", // unsupported because of CryptoJS bug "HS512": "HmacSHA512", "RS256": "SHA256withRSA", "RS384": "SHA384withRSA", "RS512": "SHA512withRSA", "ES256": "SHA256withECDSA", "ES384": "SHA384withECDSA", //"ES512": "SHA512withECDSA", // unsupported because of jsrsasign's bug "PS256": "SHA256withRSAandMGF1", "PS384": "SHA384withRSAandMGF1", "PS512": "SHA512withRSAandMGF1", "none": "none", }; // === utility static method ====================================================== /** * check whether a String "s" is a safe JSON string or not.
* If a String "s" is a malformed JSON string or an other object type * this returns 0, otherwise this returns 1. * @name isSafeJSONString * @memberOf KJUR.jws.JWS * @function * @static * @param {String} s JSON string * @return {Number} 1 or 0 */ KJUR.jws.JWS.isSafeJSONString = function(s, h, p) { var o = null; try { o = jsonParse(s); if (typeof o != "object") return 0; if (o.constructor === Array) return 0; if (h) h[p] = o; return 1; } catch (ex) { return 0; } }; /** * read a String "s" as JSON object if it is safe.
* If a String "s" is a malformed JSON string or not JSON string, * this returns null, otherwise returns JSON object. * @name readSafeJSONString * @memberOf KJUR.jws.JWS * @function * @static * @param {String} s JSON string * @return {Object} JSON object or null * @since 1.1.1 */ KJUR.jws.JWS.readSafeJSONString = function(s) { var o = null; try { o = jsonParse(s); if (typeof o != "object") return null; if (o.constructor === Array) return null; return o; } catch (ex) { return null; } }; /** * get Encoed Signature Value from JWS string.
* @name getEncodedSignatureValueFromJWS * @memberOf KJUR.jws.JWS * @function * @static * @param {String} sJWS JWS signature string to be verified * @return {String} string of Encoded Signature Value * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". */ KJUR.jws.JWS.getEncodedSignatureValueFromJWS = function(sJWS) { if (sJWS.match(/^[^.]+\.[^.]+\.([^.]+)$/) == null) { throw "JWS signature is not a form of 'Head.Payload.SigValue'."; } return RegExp.$1; }; /** * IntDate class for time representation for JSON Web Token(JWT) * @class KJUR.jws.IntDate class * @name KJUR.jws.IntDate * @since jws 3.0.1 * @description * Utility class for IntDate which is integer representation of UNIX origin time * used in JSON Web Token(JWT). */ KJUR.jws.IntDate = function() { }; /** * @name get * @memberOf KJUR.jws.IntDate * @function * @static * @param {String} s string of time representation * @return {Integer} UNIX origin time in seconds for argument 's' * @since jws 3.0.1 * @throws "unsupported format: s" when malformed format * @description * This method will accept following representation of time. *
    *
  • now - current time
  • *
  • now + 1hour - after 1 hour from now
  • *
  • now + 1day - after 1 day from now
  • *
  • now + 1month - after 30 days from now
  • *
  • now + 1year - after 365 days from now
  • *
  • YYYYmmDDHHMMSSZ - UTC time (ex. 20130828235959Z)
  • *
  • number - UNIX origin time (seconds from 1970-01-01 00:00:00) (ex. 1377714748)
  • *
*/ KJUR.jws.IntDate.get = function(s) { if (s == "now") { return KJUR.jws.IntDate.getNow(); } else if (s == "now + 1hour") { return KJUR.jws.IntDate.getNow() + 60 * 60; } else if (s == "now + 1day") { return KJUR.jws.IntDate.getNow() + 60 * 60 * 24; } else if (s == "now + 1month") { return KJUR.jws.IntDate.getNow() + 60 * 60 * 24 * 30; } else if (s == "now + 1year") { return KJUR.jws.IntDate.getNow() + 60 * 60 * 24 * 365; } else if (s.match(/Z$/)) { return KJUR.jws.IntDate.getZulu(s); } else if (s.match(/^[0-9]+$/)) { return parseInt(s); } throw "unsupported format: " + s; }; KJUR.jws.IntDate.getZulu = function(s) { if (a = s.match(/(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)Z/)) { var year = parseInt(RegExp.$1); var month = parseInt(RegExp.$2) - 1; var day = parseInt(RegExp.$3); var hour = parseInt(RegExp.$4); var min = parseInt(RegExp.$5); var sec = parseInt(RegExp.$6); var d = new Date(Date.UTC(year, month, day, hour, min, sec)); return ~~(d / 1000); } throw "unsupported format: " + s; }; /* * @since jws 3.0.1 */ KJUR.jws.IntDate.getNow = function() { var d = ~~(new Date() / 1000); return d; }; /* * @since jws 3.0.1 */ KJUR.jws.IntDate.intDate2UTCString = function(intDate) { var d = new Date(intDate * 1000); return d.toUTCString(); }; /* * @since jws 3.0.1 */ KJUR.jws.IntDate.intDate2Zulu = function(intDate) { var d = new Date(intDate * 1000); var year = ("0000" + d.getUTCFullYear()).slice(-4); var mon = ("00" + (d.getUTCMonth() + 1)).slice(-2); var day = ("00" + d.getUTCDate()).slice(-2); var hour = ("00" + d.getUTCHours()).slice(-2); var min = ("00" + d.getUTCMinutes()).slice(-2); var sec = ("00" + d.getUTCSeconds()).slice(-2); return year + mon + day + hour + min + sec + "Z"; }; /*! * @overview es6-promise - a tiny implementation of Promises/A+. * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) * @license Licensed under MIT license * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE * @version 3.0.2 */ (function() { "use strict"; function lib$es6$promise$utils$$objectOrFunction(x) { return typeof x === 'function' || (typeof x === 'object' && x !== null); } function lib$es6$promise$utils$$isFunction(x) { return typeof x === 'function'; } function lib$es6$promise$utils$$isMaybeThenable(x) { return typeof x === 'object' && x !== null; } var lib$es6$promise$utils$$_isArray; if (!Array.isArray) { lib$es6$promise$utils$$_isArray = function (x) { return Object.prototype.toString.call(x) === '[object Array]'; }; } else { lib$es6$promise$utils$$_isArray = Array.isArray; } var lib$es6$promise$utils$$isArray = lib$es6$promise$utils$$_isArray; var lib$es6$promise$asap$$len = 0; var lib$es6$promise$asap$$toString = {}.toString; var lib$es6$promise$asap$$vertxNext; var lib$es6$promise$asap$$customSchedulerFn; var lib$es6$promise$asap$$asap = function asap(callback, arg) { lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len] = callback; lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len + 1] = arg; lib$es6$promise$asap$$len += 2; if (lib$es6$promise$asap$$len === 2) { // If len is 2, that means that we need to schedule an async flush. // If additional callbacks are queued before the queue is flushed, they // will be processed by this flush that we are scheduling. if (lib$es6$promise$asap$$customSchedulerFn) { lib$es6$promise$asap$$customSchedulerFn(lib$es6$promise$asap$$flush); } else { lib$es6$promise$asap$$scheduleFlush(); } } } function lib$es6$promise$asap$$setScheduler(scheduleFn) { lib$es6$promise$asap$$customSchedulerFn = scheduleFn; } function lib$es6$promise$asap$$setAsap(asapFn) { lib$es6$promise$asap$$asap = asapFn; } var lib$es6$promise$asap$$browserWindow = (typeof window !== 'undefined') ? window : undefined; var lib$es6$promise$asap$$browserGlobal = lib$es6$promise$asap$$browserWindow || {}; var lib$es6$promise$asap$$BrowserMutationObserver = lib$es6$promise$asap$$browserGlobal.MutationObserver || lib$es6$promise$asap$$browserGlobal.WebKitMutationObserver; var lib$es6$promise$asap$$isNode = typeof process !== 'undefined' && {}.toString.call(process) === '[object process]'; // test for web worker but not in IE10 var lib$es6$promise$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined'; // node function lib$es6$promise$asap$$useNextTick() { // node version 0.10.x displays a deprecation warning when nextTick is used recursively // see https://github.com/cujojs/when/issues/410 for details return function() { process.nextTick(lib$es6$promise$asap$$flush); }; } // vertx function lib$es6$promise$asap$$useVertxTimer() { return function() { lib$es6$promise$asap$$vertxNext(lib$es6$promise$asap$$flush); }; } function lib$es6$promise$asap$$useMutationObserver() { var iterations = 0; var observer = new lib$es6$promise$asap$$BrowserMutationObserver(lib$es6$promise$asap$$flush); var node = document.createTextNode(''); observer.observe(node, { characterData: true }); return function() { node.data = (iterations = ++iterations % 2); }; } // web worker function lib$es6$promise$asap$$useMessageChannel() { var channel = new MessageChannel(); channel.port1.onmessage = lib$es6$promise$asap$$flush; return function () { channel.port2.postMessage(0); }; } function lib$es6$promise$asap$$useSetTimeout() { return function() { setTimeout(lib$es6$promise$asap$$flush, 1); }; } var lib$es6$promise$asap$$queue = new Array(1000); function lib$es6$promise$asap$$flush() { for (var i = 0; i < lib$es6$promise$asap$$len; i+=2) { var callback = lib$es6$promise$asap$$queue[i]; var arg = lib$es6$promise$asap$$queue[i+1]; callback(arg); lib$es6$promise$asap$$queue[i] = undefined; lib$es6$promise$asap$$queue[i+1] = undefined; } lib$es6$promise$asap$$len = 0; } function lib$es6$promise$asap$$attemptVertx() { try { var r = require; var vertx = r('vertx'); lib$es6$promise$asap$$vertxNext = vertx.runOnLoop || vertx.runOnContext; return lib$es6$promise$asap$$useVertxTimer(); } catch(e) { return lib$es6$promise$asap$$useSetTimeout(); } } var lib$es6$promise$asap$$scheduleFlush; // Decide what async method to use to triggering processing of queued callbacks: if (lib$es6$promise$asap$$isNode) { lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useNextTick(); } else if (lib$es6$promise$asap$$BrowserMutationObserver) { lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMutationObserver(); } else if (lib$es6$promise$asap$$isWorker) { lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMessageChannel(); } else if (lib$es6$promise$asap$$browserWindow === undefined && typeof require === 'function') { lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$attemptVertx(); } else { lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useSetTimeout(); } function lib$es6$promise$$internal$$noop() {} var lib$es6$promise$$internal$$PENDING = void 0; var lib$es6$promise$$internal$$FULFILLED = 1; var lib$es6$promise$$internal$$REJECTED = 2; var lib$es6$promise$$internal$$GET_THEN_ERROR = new lib$es6$promise$$internal$$ErrorObject(); function lib$es6$promise$$internal$$selfFulfillment() { return new TypeError("You cannot resolve a promise with itself"); } function lib$es6$promise$$internal$$cannotReturnOwn() { return new TypeError('A promises callback cannot return that same promise.'); } function lib$es6$promise$$internal$$getThen(promise) { try { return promise.then; } catch(error) { lib$es6$promise$$internal$$GET_THEN_ERROR.error = error; return lib$es6$promise$$internal$$GET_THEN_ERROR; } } function lib$es6$promise$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) { try { then.call(value, fulfillmentHandler, rejectionHandler); } catch(e) { return e; } } function lib$es6$promise$$internal$$handleForeignThenable(promise, thenable, then) { lib$es6$promise$asap$$asap(function(promise) { var sealed = false; var error = lib$es6$promise$$internal$$tryThen(then, thenable, function(value) { if (sealed) { return; } sealed = true; if (thenable !== value) { lib$es6$promise$$internal$$resolve(promise, value); } else { lib$es6$promise$$internal$$fulfill(promise, value); } }, function(reason) { if (sealed) { return; } sealed = true; lib$es6$promise$$internal$$reject(promise, reason); }, 'Settle: ' + (promise._label || ' unknown promise')); if (!sealed && error) { sealed = true; lib$es6$promise$$internal$$reject(promise, error); } }, promise); } function lib$es6$promise$$internal$$handleOwnThenable(promise, thenable) { if (thenable._state === lib$es6$promise$$internal$$FULFILLED) { lib$es6$promise$$internal$$fulfill(promise, thenable._result); } else if (thenable._state === lib$es6$promise$$internal$$REJECTED) { lib$es6$promise$$internal$$reject(promise, thenable._result); } else { lib$es6$promise$$internal$$subscribe(thenable, undefined, function(value) { lib$es6$promise$$internal$$resolve(promise, value); }, function(reason) { lib$es6$promise$$internal$$reject(promise, reason); }); } } function lib$es6$promise$$internal$$handleMaybeThenable(promise, maybeThenable) { if (maybeThenable.constructor === promise.constructor) { lib$es6$promise$$internal$$handleOwnThenable(promise, maybeThenable); } else { var then = lib$es6$promise$$internal$$getThen(maybeThenable); if (then === lib$es6$promise$$internal$$GET_THEN_ERROR) { lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$GET_THEN_ERROR.error); } else if (then === undefined) { lib$es6$promise$$internal$$fulfill(promise, maybeThenable); } else if (lib$es6$promise$utils$$isFunction(then)) { lib$es6$promise$$internal$$handleForeignThenable(promise, maybeThenable, then); } else { lib$es6$promise$$internal$$fulfill(promise, maybeThenable); } } } function lib$es6$promise$$internal$$resolve(promise, value) { if (promise === value) { lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$selfFulfillment()); } else if (lib$es6$promise$utils$$objectOrFunction(value)) { lib$es6$promise$$internal$$handleMaybeThenable(promise, value); } else { lib$es6$promise$$internal$$fulfill(promise, value); } } function lib$es6$promise$$internal$$publishRejection(promise) { if (promise._onerror) { promise._onerror(promise._result); } lib$es6$promise$$internal$$publish(promise); } function lib$es6$promise$$internal$$fulfill(promise, value) { if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; } promise._result = value; promise._state = lib$es6$promise$$internal$$FULFILLED; if (promise._subscribers.length !== 0) { lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, promise); } } function lib$es6$promise$$internal$$reject(promise, reason) { if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; } promise._state = lib$es6$promise$$internal$$REJECTED; promise._result = reason; lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publishRejection, promise); } function lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection) { var subscribers = parent._subscribers; var length = subscribers.length; parent._onerror = null; subscribers[length] = child; subscribers[length + lib$es6$promise$$internal$$FULFILLED] = onFulfillment; subscribers[length + lib$es6$promise$$internal$$REJECTED] = onRejection; if (length === 0 && parent._state) { lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, parent); } } function lib$es6$promise$$internal$$publish(promise) { var subscribers = promise._subscribers; var settled = promise._state; if (subscribers.length === 0) { return; } var child, callback, detail = promise._result; for (var i = 0; i < subscribers.length; i += 3) { child = subscribers[i]; callback = subscribers[i + settled]; if (child) { lib$es6$promise$$internal$$invokeCallback(settled, child, callback, detail); } else { callback(detail); } } promise._subscribers.length = 0; } function lib$es6$promise$$internal$$ErrorObject() { this.error = null; } var lib$es6$promise$$internal$$TRY_CATCH_ERROR = new lib$es6$promise$$internal$$ErrorObject(); function lib$es6$promise$$internal$$tryCatch(callback, detail) { try { return callback(detail); } catch(e) { lib$es6$promise$$internal$$TRY_CATCH_ERROR.error = e; return lib$es6$promise$$internal$$TRY_CATCH_ERROR; } } function lib$es6$promise$$internal$$invokeCallback(settled, promise, callback, detail) { var hasCallback = lib$es6$promise$utils$$isFunction(callback), value, error, succeeded, failed; if (hasCallback) { value = lib$es6$promise$$internal$$tryCatch(callback, detail); if (value === lib$es6$promise$$internal$$TRY_CATCH_ERROR) { failed = true; error = value.error; value = null; } else { succeeded = true; } if (promise === value) { lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$cannotReturnOwn()); return; } } else { value = detail; succeeded = true; } if (promise._state !== lib$es6$promise$$internal$$PENDING) { // noop } else if (hasCallback && succeeded) { lib$es6$promise$$internal$$resolve(promise, value); } else if (failed) { lib$es6$promise$$internal$$reject(promise, error); } else if (settled === lib$es6$promise$$internal$$FULFILLED) { lib$es6$promise$$internal$$fulfill(promise, value); } else if (settled === lib$es6$promise$$internal$$REJECTED) { lib$es6$promise$$internal$$reject(promise, value); } } function lib$es6$promise$$internal$$initializePromise(promise, resolver) { try { resolver(function resolvePromise(value){ lib$es6$promise$$internal$$resolve(promise, value); }, function rejectPromise(reason) { lib$es6$promise$$internal$$reject(promise, reason); }); } catch(e) { lib$es6$promise$$internal$$reject(promise, e); } } function lib$es6$promise$enumerator$$Enumerator(Constructor, input) { var enumerator = this; enumerator._instanceConstructor = Constructor; enumerator.promise = new Constructor(lib$es6$promise$$internal$$noop); if (enumerator._validateInput(input)) { enumerator._input = input; enumerator.length = input.length; enumerator._remaining = input.length; enumerator._init(); if (enumerator.length === 0) { lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result); } else { enumerator.length = enumerator.length || 0; enumerator._enumerate(); if (enumerator._remaining === 0) { lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result); } } } else { lib$es6$promise$$internal$$reject(enumerator.promise, enumerator._validationError()); } } lib$es6$promise$enumerator$$Enumerator.prototype._validateInput = function(input) { return lib$es6$promise$utils$$isArray(input); }; lib$es6$promise$enumerator$$Enumerator.prototype._validationError = function() { return new Error('Array Methods must be provided an Array'); }; lib$es6$promise$enumerator$$Enumerator.prototype._init = function() { this._result = new Array(this.length); }; var lib$es6$promise$enumerator$$default = lib$es6$promise$enumerator$$Enumerator; lib$es6$promise$enumerator$$Enumerator.prototype._enumerate = function() { var enumerator = this; var length = enumerator.length; var promise = enumerator.promise; var input = enumerator._input; for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) { enumerator._eachEntry(input[i], i); } }; lib$es6$promise$enumerator$$Enumerator.prototype._eachEntry = function(entry, i) { var enumerator = this; var c = enumerator._instanceConstructor; if (lib$es6$promise$utils$$isMaybeThenable(entry)) { if (entry.constructor === c && entry._state !== lib$es6$promise$$internal$$PENDING) { entry._onerror = null; enumerator._settledAt(entry._state, i, entry._result); } else { enumerator._willSettleAt(c.resolve(entry), i); } } else { enumerator._remaining--; enumerator._result[i] = entry; } }; lib$es6$promise$enumerator$$Enumerator.prototype._settledAt = function(state, i, value) { var enumerator = this; var promise = enumerator.promise; if (promise._state === lib$es6$promise$$internal$$PENDING) { enumerator._remaining--; if (state === lib$es6$promise$$internal$$REJECTED) { lib$es6$promise$$internal$$reject(promise, value); } else { enumerator._result[i] = value; } } if (enumerator._remaining === 0) { lib$es6$promise$$internal$$fulfill(promise, enumerator._result); } }; lib$es6$promise$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) { var enumerator = this; lib$es6$promise$$internal$$subscribe(promise, undefined, function(value) { enumerator._settledAt(lib$es6$promise$$internal$$FULFILLED, i, value); }, function(reason) { enumerator._settledAt(lib$es6$promise$$internal$$REJECTED, i, reason); }); }; function lib$es6$promise$promise$all$$all(entries) { return new lib$es6$promise$enumerator$$default(this, entries).promise; } var lib$es6$promise$promise$all$$default = lib$es6$promise$promise$all$$all; function lib$es6$promise$promise$race$$race(entries) { /*jshint validthis:true */ var Constructor = this; var promise = new Constructor(lib$es6$promise$$internal$$noop); if (!lib$es6$promise$utils$$isArray(entries)) { lib$es6$promise$$internal$$reject(promise, new TypeError('You must pass an array to race.')); return promise; } var length = entries.length; function onFulfillment(value) { lib$es6$promise$$internal$$resolve(promise, value); } function onRejection(reason) { lib$es6$promise$$internal$$reject(promise, reason); } for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) { lib$es6$promise$$internal$$subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection); } return promise; } var lib$es6$promise$promise$race$$default = lib$es6$promise$promise$race$$race; function lib$es6$promise$promise$resolve$$resolve(object) { /*jshint validthis:true */ var Constructor = this; if (object && typeof object === 'object' && object.constructor === Constructor) { return object; } var promise = new Constructor(lib$es6$promise$$internal$$noop); lib$es6$promise$$internal$$resolve(promise, object); return promise; } var lib$es6$promise$promise$resolve$$default = lib$es6$promise$promise$resolve$$resolve; function lib$es6$promise$promise$reject$$reject(reason) { /*jshint validthis:true */ var Constructor = this; var promise = new Constructor(lib$es6$promise$$internal$$noop); lib$es6$promise$$internal$$reject(promise, reason); return promise; } var lib$es6$promise$promise$reject$$default = lib$es6$promise$promise$reject$$reject; var lib$es6$promise$promise$$counter = 0; function lib$es6$promise$promise$$needsResolver() { throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); } function lib$es6$promise$promise$$needsNew() { throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); } var lib$es6$promise$promise$$default = lib$es6$promise$promise$$Promise; /** Promise objects represent the eventual result of an asynchronous operation. The primary way of interacting with a promise is through its `then` method, which registers callbacks to receive either a promise's eventual value or the reason why the promise cannot be fulfilled. Terminology ----------- - `promise` is an object or function with a `then` method whose behavior conforms to this specification. - `thenable` is an object or function that defines a `then` method. - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). - `exception` is a value that is thrown using the throw statement. - `reason` is a value that indicates why a promise was rejected. - `settled` the final resting state of a promise, fulfilled or rejected. A promise can be in one of three states: pending, fulfilled, or rejected. Promises that are fulfilled have a fulfillment value and are in the fulfilled state. Promises that are rejected have a rejection reason and are in the rejected state. A fulfillment value is never a thenable. Promises can also be said to *resolve* a value. If this value is also a promise, then the original promise's settled state will match the value's settled state. So a promise that *resolves* a promise that rejects will itself reject, and a promise that *resolves* a promise that fulfills will itself fulfill. Basic Usage: ------------ ```js var promise = new Promise(function(resolve, reject) { // on success resolve(value); // on failure reject(reason); }); promise.then(function(value) { // on fulfillment }, function(reason) { // on rejection }); ``` Advanced Usage: --------------- Promises shine when abstracting away asynchronous interactions such as `XMLHttpRequest`s. ```js function getJSON(url) { return new Promise(function(resolve, reject){ var xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.onreadystatechange = handler; xhr.responseType = 'json'; xhr.setRequestHeader('Accept', 'application/json'); xhr.send(); function handler() { if (this.readyState === this.DONE) { if (this.status === 200) { resolve(this.response); } else { reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); } } }; }); } getJSON('/posts.json').then(function(json) { // on fulfillment }, function(reason) { // on rejection }); ``` Unlike callbacks, promises are great composable primitives. ```js Promise.all([ getJSON('/posts'), getJSON('/comments') ]).then(function(values){ values[0] // => postsJSON values[1] // => commentsJSON return values; }); ``` @class Promise @param {function} resolver Useful for tooling. @constructor */ function lib$es6$promise$promise$$Promise(resolver) { this._id = lib$es6$promise$promise$$counter++; this._state = undefined; this._result = undefined; this._subscribers = []; if (lib$es6$promise$$internal$$noop !== resolver) { if (!lib$es6$promise$utils$$isFunction(resolver)) { lib$es6$promise$promise$$needsResolver(); } if (!(this instanceof lib$es6$promise$promise$$Promise)) { lib$es6$promise$promise$$needsNew(); } lib$es6$promise$$internal$$initializePromise(this, resolver); } } lib$es6$promise$promise$$Promise.all = lib$es6$promise$promise$all$$default; lib$es6$promise$promise$$Promise.race = lib$es6$promise$promise$race$$default; lib$es6$promise$promise$$Promise.resolve = lib$es6$promise$promise$resolve$$default; lib$es6$promise$promise$$Promise.reject = lib$es6$promise$promise$reject$$default; lib$es6$promise$promise$$Promise._setScheduler = lib$es6$promise$asap$$setScheduler; lib$es6$promise$promise$$Promise._setAsap = lib$es6$promise$asap$$setAsap; lib$es6$promise$promise$$Promise._asap = lib$es6$promise$asap$$asap; lib$es6$promise$promise$$Promise.prototype = { constructor: lib$es6$promise$promise$$Promise, /** The primary way of interacting with a promise is through its `then` method, which registers callbacks to receive either a promise's eventual value or the reason why the promise cannot be fulfilled. ```js findUser().then(function(user){ // user is available }, function(reason){ // user is unavailable, and you are given the reason why }); ``` Chaining -------- The return value of `then` is itself a promise. This second, 'downstream' promise is resolved with the return value of the first promise's fulfillment or rejection handler, or rejected if the handler throws an exception. ```js findUser().then(function (user) { return user.name; }, function (reason) { return 'default name'; }).then(function (userName) { // If `findUser` fulfilled, `userName` will be the user's name, otherwise it // will be `'default name'` }); findUser().then(function (user) { throw new Error('Found user, but still unhappy'); }, function (reason) { throw new Error('`findUser` rejected and we're unhappy'); }).then(function (value) { // never reached }, function (reason) { // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. }); ``` If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. ```js findUser().then(function (user) { throw new PedagogicalException('Upstream error'); }).then(function (value) { // never reached }).then(function (value) { // never reached }, function (reason) { // The `PedgagocialException` is propagated all the way down to here }); ``` Assimilation ------------ Sometimes the value you want to propagate to a downstream promise can only be retrieved asynchronously. This can be achieved by returning a promise in the fulfillment or rejection handler. The downstream promise will then be pending until the returned promise is settled. This is called *assimilation*. ```js findUser().then(function (user) { return findCommentsByAuthor(user); }).then(function (comments) { // The user's comments are now available }); ``` If the assimliated promise rejects, then the downstream promise will also reject. ```js findUser().then(function (user) { return findCommentsByAuthor(user); }).then(function (comments) { // If `findCommentsByAuthor` fulfills, we'll have the value here }, function (reason) { // If `findCommentsByAuthor` rejects, we'll have the reason here }); ``` Simple Example -------------- Synchronous Example ```javascript var result; try { result = findResult(); // success } catch(reason) { // failure } ``` Errback Example ```js findResult(function(result, err){ if (err) { // failure } else { // success } }); ``` Promise Example; ```javascript findResult().then(function(result){ // success }, function(reason){ // failure }); ``` Advanced Example -------------- Synchronous Example ```javascript var author, books; try { author = findAuthor(); books = findBooksByAuthor(author); // success } catch(reason) { // failure } ``` Errback Example ```js function foundBooks(books) { } function failure(reason) { } findAuthor(function(author, err){ if (err) { failure(err); // failure } else { try { findBoooksByAuthor(author, function(books, err) { if (err) { failure(err); } else { try { foundBooks(books); } catch(reason) { failure(reason); } } }); } catch(error) { failure(err); } // success } }); ``` Promise Example; ```javascript findAuthor(). then(findBooksByAuthor). then(function(books){ // found books }).catch(function(reason){ // something went wrong }); ``` @method then @param {Function} onFulfilled @param {Function} onRejected Useful for tooling. @return {Promise} */ then: function(onFulfillment, onRejection) { var parent = this; var state = parent._state; if (state === lib$es6$promise$$internal$$FULFILLED && !onFulfillment || state === lib$es6$promise$$internal$$REJECTED && !onRejection) { return this; } var child = new this.constructor(lib$es6$promise$$internal$$noop); var result = parent._result; if (state) { var callback = arguments[state - 1]; lib$es6$promise$asap$$asap(function(){ lib$es6$promise$$internal$$invokeCallback(state, child, callback, result); }); } else { lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection); } return child; }, /** `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same as the catch block of a try/catch statement. ```js function findAuthor(){ throw new Error('couldn't find that author'); } // synchronous try { findAuthor(); } catch(reason) { // something went wrong } // async with promises findAuthor().catch(function(reason){ // something went wrong }); ``` @method catch @param {Function} onRejection Useful for tooling. @return {Promise} */ 'catch': function(onRejection) { return this.then(null, onRejection); } }; function lib$es6$promise$polyfill$$polyfill() { var local; if (typeof global !== 'undefined') { local = global; } else if (typeof self !== 'undefined') { local = self; } else { try { local = Function('return this')(); } catch (e) { throw new Error('polyfill failed because global object is unavailable in this environment'); } } var P = local.Promise; if (P && Object.prototype.toString.call(P.resolve()) === '[object Promise]' && !P.cast) { return; } local.Promise = lib$es6$promise$promise$$default; } var lib$es6$promise$polyfill$$default = lib$es6$promise$polyfill$$polyfill; var lib$es6$promise$umd$$ES6Promise = { 'Promise': lib$es6$promise$promise$$default, 'polyfill': lib$es6$promise$polyfill$$default }; /* global define:true module:true window: true */ if (typeof define === 'function' && define['amd']) { define(function() { return lib$es6$promise$umd$$ES6Promise; }); } else if (typeof module !== 'undefined' && module['exports']) { module['exports'] = lib$es6$promise$umd$$ES6Promise; } else if (typeof this !== 'undefined') { this['ES6Promise'] = lib$es6$promise$umd$$ES6Promise; } lib$es6$promise$polyfill$$default(); }).call(this); /** * @constructor */ function DefaultHttpRequest() { /** * @name _promiseFactory * @type DefaultPromiseFactory */ /** * @param {XMLHttpRequest} xhr * @param {object.} headers */ function setHeaders(xhr, headers) { var keys = Object.keys(headers); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = headers[key]; xhr.setRequestHeader(key, value); } } /** * @param {string} url * @param {{ headers: object. }} [config] * @returns {Promise} */ this.getJSON = function (url, config) { return _promiseFactory.create(function (resolve, reject) { try { var xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.responseType = "json"; if (config) { if (config.headers) { setHeaders(xhr, config.headers); } } xhr.onload = function () { try { if (xhr.status === 200) { var response = ""; // To support IE9 get the response from xhr.responseText not xhr.response if (window.XDomainRequest) { response = xhr.responseText; } else { response = xhr.response; } if (typeof response === "string") { response = JSON.parse(response); } resolve(response); } else { reject(Error(xhr.statusText + "(" + xhr.status + ")")); } } catch (err) { reject(err); } }; xhr.onerror = function () { reject(Error("Network error")); }; xhr.send(); } catch (err) { return reject(err); } }); }; } _httpRequest = new DefaultHttpRequest(); /** * @constructor * @param {Promise} promise */ function DefaultPromise(promise) { /** * @param {function(*):*} successCallback * @param {function(*):*} errorCallback * @returns {DefaultPromise} */ this.then = function (successCallback, errorCallback) { var childPromise = promise.then(successCallback, errorCallback); return new DefaultPromise(childPromise); }; /** * * @param {function(*):*} errorCallback * @returns {DefaultPromise} */ this.catch = function (errorCallback) { var childPromise = promise.catch(errorCallback); return new DefaultPromise(childPromise); }; } /** * @constructor */ function DefaultPromiseFactory() { this.resolve = function (value) { return new DefaultPromise(Promise.resolve(value)); }; this.reject = function (reason) { return new DefaultPromise(Promise.reject(reason)); }; /** * @param {function(resolve:function, reject:function)} callback * @returns {DefaultPromise} */ this.create = function (callback) { return new DefaultPromise(new Promise(callback)); }; } _promiseFactory = new DefaultPromiseFactory(); /* * Copyright 2015 Dominick Baier, Brock Allen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function log() { //var param = [].join.call(arguments); //console.log(param); } function copy(obj, target) { target = target || {}; for (var key in obj) { if (obj.hasOwnProperty(key)) { target[key] = obj[key]; } } return target; } function rand() { return ((Date.now() + Math.random()) * Math.random()).toString().replace(".", ""); } function resolve(param) { return _promiseFactory.resolve(param); } function error(message) { return _promiseFactory.reject(Error(message)); } function parseOidcResult(queryString) { log("parseOidcResult"); queryString = queryString || location.hash; var idx = queryString.lastIndexOf("#"); if (idx >= 0) { queryString = queryString.substr(idx + 1); } var params = {}, regex = /([^&=]+)=([^&]*)/g, m; var counter = 0; while (m = regex.exec(queryString)) { params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]); if (counter++ > 50) { return { error: "Response exceeded expected number of parameters" }; } } for (var prop in params) { return params; } } function getJson(url, token) { log("getJson", url); var config = {}; if (token) { config.headers = {"Authorization": "Bearer " + token}; } return _httpRequest.getJSON(url, config); } function OidcClient(settings) { this._settings = settings || {}; if (!this._settings.request_state_key) { this._settings.request_state_key = "OidcClient.request_state"; } if (!this._settings.request_state_store) { this._settings.request_state_store = window.localStorage; } if (typeof this._settings.load_user_profile === 'undefined') { this._settings.load_user_profile = true; } if (typeof this._settings.filter_protocol_claims === 'undefined') { this._settings.filter_protocol_claims = true; } if (this._settings.authority && this._settings.authority.indexOf('.well-known/openid-configuration') < 0) { if (this._settings.authority[this._settings.authority.length - 1] !== '/') { this._settings.authority += '/'; } this._settings.authority += '.well-known/openid-configuration'; } if (!this._settings.response_type) { this._settings.response_type = "id_token token"; } Object.defineProperty(this, "isOidc", { get: function () { if (this._settings.response_type) { var result = this._settings.response_type.split(/\s+/g).filter(function (item) { return item === "id_token"; }); return !!(result[0]); } return false; } }); Object.defineProperty(this, "isOAuth", { get: function () { if (this._settings.response_type) { var result = this._settings.response_type.split(/\s+/g).filter(function (item) { return item === "token"; }); return !!(result[0]); } return false; } }); } OidcClient.parseOidcResult = parseOidcResult; OidcClient.prototype.loadMetadataAsync = function () { log("OidcClient.loadMetadataAsync"); var settings = this._settings; if (settings.metadata) { return resolve(settings.metadata); } if (!settings.authority) { return error("No authority configured"); } return getJson(settings.authority) .then(function (metadata) { settings.metadata = metadata; return metadata; }, function (err) { return error("Failed to load metadata (" + err && err.message + ")"); }); }; OidcClient.prototype.loadX509SigningKeyAsync = function () { log("OidcClient.loadX509SigningKeyAsync"); var settings = this._settings; function getKeyAsync(jwks) { if (!jwks.keys || !jwks.keys.length) { return error("Signing keys empty"); } var key = jwks.keys[0]; if (key.kty !== "RSA") { return error("Signing key not RSA"); } if (!key.x5c || !key.x5c.length) { return error("RSA keys empty"); } return resolve(key.x5c[0]); } if (settings.jwks) { return getKeyAsync(settings.jwks); } return this.loadMetadataAsync().then(function (metadata) { if (!metadata.jwks_uri) { return error("Metadata does not contain jwks_uri"); } return getJson(metadata.jwks_uri).then(function (jwks) { settings.jwks = jwks; return getKeyAsync(jwks); }, function (err) { return error("Failed to load signing keys (" + err && err.message + ")"); }); }); }; OidcClient.prototype.loadUserProfile = function (access_token) { log("OidcClient.loadUserProfile"); return this.loadMetadataAsync().then(function (metadata) { if (!metadata.userinfo_endpoint) { return error("Metadata does not contain userinfo_endpoint"); } return getJson(metadata.userinfo_endpoint, access_token); }); } OidcClient.prototype.loadAuthorizationEndpoint = function () { log("OidcClient.loadAuthorizationEndpoint"); if (this._settings.authorization_endpoint) { return resolve(this._settings.authorization_endpoint); } if (!this._settings.authority) { return error("No authorization_endpoint configured"); } return this.loadMetadataAsync().then(function (metadata) { if (!metadata.authorization_endpoint) { return error("Metadata does not contain authorization_endpoint"); } return metadata.authorization_endpoint; }); }; OidcClient.prototype.createTokenRequestAsync = function () { log("OidcClient.createTokenRequestAsync"); var client = this; var settings = client._settings; return client.loadAuthorizationEndpoint().then(function (authorization_endpoint) { var state = rand(); var url = authorization_endpoint + "?state=" + encodeURIComponent(state); if (client.isOidc) { var nonce = rand(); url += "&nonce=" + encodeURIComponent(nonce); } var required = ["client_id", "redirect_uri", "response_type", "scope"]; required.forEach(function (key) { var value = settings[key]; if (value) { url += "&" + key + "=" + encodeURIComponent(value); } }); var optional = ["prompt", "display", "max_age", "ui_locales", "id_token_hint", "login_hint", "acr_values"]; optional.forEach(function (key) { var value = settings[key]; if (value) { url += "&" + key + "=" + encodeURIComponent(value); } }); var request_state = { oidc: client.isOidc, oauth: client.isOAuth, state: state }; if (nonce) { request_state["nonce"] = nonce; } settings.request_state_store.setItem(settings.request_state_key, JSON.stringify(request_state)); return { request_state: request_state, url: url }; }); } OidcClient.prototype.createLogoutRequestAsync = function (id_token_hint) { log("OidcClient.createLogoutRequestAsync"); var settings = this._settings; return this.loadMetadataAsync().then(function (metadata) { if (!metadata.end_session_endpoint) { return error("No end_session_endpoint in metadata"); } var url = metadata.end_session_endpoint; if (id_token_hint && settings.post_logout_redirect_uri) { url += "?post_logout_redirect_uri=" + encodeURIComponent(settings.post_logout_redirect_uri); url += "&id_token_hint=" + encodeURIComponent(id_token_hint); } return url; }); } OidcClient.prototype.validateIdTokenAsync = function (id_token, nonce, access_token) { log("OidcClient.validateIdTokenAsync"); var client = this; var settings = client._settings; return client.loadX509SigningKeyAsync().then(function (cert) { var jws = new KJUR.jws.JWS(); if (jws.verifyJWSByPemX509Cert(id_token, cert)) { var id_token_contents = JSON.parse(jws.parsedJWS.payloadS); if (nonce !== id_token_contents.nonce) { return error("Invalid nonce"); } return client.loadMetadataAsync().then(function (metadata) { if (id_token_contents.iss !== metadata.issuer) { return error("Invalid issuer"); } if (id_token_contents.aud !== settings.client_id) { return error("Invalid audience"); } var now = parseInt(Date.now() / 1000); // accept tokens issues up to 5 mins ago var diff = now - id_token_contents.iat; if (diff > (5 * 60)) { return error("Token issued too long ago"); } if (id_token_contents.exp < now) { return error("Token expired"); } if (access_token && settings.load_user_profile) { // if we have an access token, then call user info endpoint return client.loadUserProfile(access_token, id_token_contents).then(function (profile) { return copy(profile, id_token_contents); }); } else { // no access token, so we have all our claims return id_token_contents; } }); } else { return error("JWT failed to validate"); } }); }; OidcClient.prototype.validateAccessTokenAsync = function (id_token_contents, access_token) { log("OidcClient.validateAccessTokenAsync"); if (!id_token_contents.at_hash) { return error("No at_hash in id_token"); } var hash = KJUR.crypto.Util.sha256(access_token); var left = hash.substr(0, hash.length / 2); var left_b64u = hextob64u(left); if (left_b64u !== id_token_contents.at_hash) { return error("at_hash failed to validate"); } return resolve(); }; OidcClient.prototype.validateIdTokenAndAccessTokenAsync = function (id_token, nonce, access_token) { log("OidcClient.validateIdTokenAndAccessTokenAsync"); var client = this; return client.validateIdTokenAsync(id_token, nonce, access_token).then(function (id_token_contents) { return client.validateAccessTokenAsync(id_token_contents, access_token).then(function () { return id_token_contents; }); }); } OidcClient.prototype.processResponseAsync = function (queryString) { log("OidcClient.processResponseAsync"); var client = this; var settings = client._settings; var request_state = settings.request_state_store.getItem(settings.request_state_key); settings.request_state_store.removeItem(settings.request_state_key); if (!request_state) { return error("No request state loaded"); } request_state = JSON.parse(request_state); if (!request_state) { return error("No request state loaded"); } if (!request_state.state) { return error("No state loaded"); } var result = parseOidcResult(queryString); if (!result) { return error("No OIDC response"); } if (result.error) { return error(result.error); } if (result.state !== request_state.state) { return error("Invalid state"); } if (request_state.oidc) { if (!result.id_token) { return error("No identity token"); } if (!request_state.nonce) { return error("No nonce loaded"); } } if (request_state.oauth) { if (!result.access_token) { return error("No access token"); } if (!result.token_type || result.token_type.toLowerCase() !== "bearer") { return error("Invalid token type"); } if (!result.expires_in) { return error("No token expiration"); } } var promise = resolve(); if (request_state.oidc && request_state.oauth) { promise = client.validateIdTokenAndAccessTokenAsync(result.id_token, request_state.nonce, result.access_token); } else if (request_state.oidc) { promise = client.validateIdTokenAsync(result.id_token, request_state.nonce); } return promise.then(function (profile) { if (profile && settings.filter_protocol_claims) { var remove = ["nonce", "at_hash", "iat", "nbf", "exp", "aud", "iss"]; remove.forEach(function (key) { delete profile[key]; }); } return { profile: profile, id_token: result.id_token, access_token: result.access_token, expires_in: result.expires_in, scope: result.scope, session_state : result.session_state }; }); } // exports OidcClient._promiseFactory = _promiseFactory; OidcClient._httpRequest = _httpRequest; window.OidcClient = OidcClient; })(); (function () { /* * Copyright 2014-2016 Dominick Baier, Brock Allen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // globals var _promiseFactory = OidcClient._promiseFactory; var _httpRequest = OidcClient._httpRequest; function copy(obj, target) { target = target || {}; for (var key in obj) { if (obj.hasOwnProperty(key)) { target[key] = obj[key]; } } return target; } function Token(other) { if (other) { this.profile = other.profile; this.id_token = other.id_token; this.access_token = other.access_token; if (other.access_token) { this.expires_at = parseInt(other.expires_at); } else if (other.id_token) { this.expires_at = other.profile.exp; } else { throw Error("Either access_token or id_token required."); } this.scope = other.scope; this.session_state = other.session_state; } else { this.expires_at = 0; } Object.defineProperty(this, "scopes", { get: function () { return (this.scope || "").split(" "); } }); Object.defineProperty(this, "expired", { get: function () { var now = parseInt(Date.now() / 1000); return this.expires_at < now; } }); Object.defineProperty(this, "expires_in", { get: function () { var now = parseInt(Date.now() / 1000); return this.expires_at - now; } }); } Token.fromResponse = function (response) { if (response.access_token) { var now = parseInt(Date.now() / 1000); response.expires_at = now + parseInt(response.expires_in); } return new Token(response); } Token.fromJSON = function (json) { if (json) { try { var obj = JSON.parse(json); return new Token(obj); } catch (e) { } } return new Token(null); } Token.prototype.toJSON = function () { return JSON.stringify({ profile: this.profile, id_token: this.id_token, access_token: this.access_token, expires_at: this.expires_at, scope: this.scopes.join(" "), session_state: this.session_state }); } function FrameLoader(url, config) { this.url = url; config = config || {}; config.cancelDelay = config.cancelDelay || 5000; this.config = config; } FrameLoader.prototype.loadAsync = function (url) { var self = this; url = url || this.url; if (!url) { return _promiseFactory.reject(Error("No url provided")); } return _promiseFactory.create(function (resolve, reject) { var frame = window.document.createElement("iframe"); frame.style.display = "none"; function cleanup() { window.removeEventListener("message", message, false); if (handle) { window.clearTimeout(handle); } handle = null; window.document.body.removeChild(frame); } function cancel(e) { cleanup(); reject(); } function message(e) { if (handle && e.origin === location.protocol + "//" + location.host && e.source == frame.contentWindow) { cleanup(); resolve(e.data); } } var handle = window.setTimeout(cancel, self.config.cancelDelay); window.addEventListener("message", message, false); window.document.body.appendChild(frame); frame.src = url; }); } function loadToken(mgr) { mgr._token = null; if (mgr._settings.persist) { var tokenJson = mgr._settings.store.getItem(mgr._settings.persistKey); if (tokenJson) { var token = Token.fromJSON(tokenJson); if (!token.expired) { mgr._token = token; } } } } function configureTokenExpiring(mgr) { function callback() { handle = null; mgr._callTokenExpiring(); } var handle = null; function cancel() { if (handle) { window.clearTimeout(handle); handle = null; } } function setup(duration) { handle = window.setTimeout(callback, duration * 1000); } function configure() { cancel(); if (!mgr.expired) { var duration = mgr.expires_in; if (duration > 60) { setup(duration - 60); } else { callback(); } } } configure(); mgr.addOnTokenObtained(configure); mgr.addOnTokenRemoved(cancel); } function configureAutoRenewToken(mgr) { if (mgr._settings.silent_redirect_uri && mgr._settings.silent_renew) { mgr.addOnTokenExpiring(function () { mgr.renewTokenSilentAsync().catch(function (e) { mgr._callSilentTokenRenewFailed(); console.error(e && e.message || "Unknown error"); }); }); } } function configureTokenExpired(mgr) { function callback() { handle = null; if (mgr._token) { mgr.saveToken(null); } mgr._callTokenExpired(); } var handle = null; function cancel() { if (handle) { window.clearTimeout(handle); handle = null; } } function setup(duration) { handle = window.setTimeout(callback, duration * 1000); } function configure() { cancel(); if (mgr.expires_in > 0) { // register 1 second beyond expiration so we don't get into edge conditions for expiration setup(mgr.expires_in + 1); } } configure(); mgr.addOnTokenObtained(configure); mgr.addOnTokenRemoved(cancel); } function TokenManager(settings) { this._settings = settings || {}; if (typeof this._settings.persist === 'undefined') { this._settings.persist = true; } this._settings.store = this._settings.store || window.localStorage; this._settings.persistKey = this._settings.persistKey || "TokenManager.token"; this.oidcClient = new OidcClient(this._settings); this._callbacks = { tokenRemovedCallbacks: [], tokenExpiringCallbacks: [], tokenExpiredCallbacks: [], tokenObtainedCallbacks: [], silentTokenRenewFailedCallbacks: [] }; Object.defineProperty(this, "profile", { get: function () { if (this._token) { return this._token.profile; } } }); Object.defineProperty(this, "id_token", { get: function () { if (this._token) { return this._token.id_token; } } }); Object.defineProperty(this, "access_token", { get: function () { if (this._token && !this._token.expired) { return this._token.access_token; } } }); Object.defineProperty(this, "expired", { get: function () { if (this._token) { return this._token.expired; } return true; } }); Object.defineProperty(this, "expires_in", { get: function () { if (this._token) { return this._token.expires_in; } return 0; } }); Object.defineProperty(this, "expires_at", { get: function () { if (this._token) { return this._token.expires_at; } return 0; } }); Object.defineProperty(this, "scope", { get: function () { return this._token && this._token.scope; } }); Object.defineProperty(this, "scopes", { get: function () { if (this._token) { return [].concat(this._token.scopes); } return []; } }); Object.defineProperty(this, "session_state", { get: function () { if (this._token) { return this._token.session_state; } } }); var mgr = this; loadToken(mgr); if (mgr._settings.store instanceof window.localStorage.constructor) { window.addEventListener("storage", function (e) { if (e.key === mgr._settings.persistKey) { loadToken(mgr); if (mgr._token) { mgr._callTokenObtained(); } else { mgr._callTokenRemoved(); } } }); } configureTokenExpired(mgr); configureAutoRenewToken(mgr); // delay this so consuming apps can register for callbacks first window.setTimeout(function () { configureTokenExpiring(mgr); }, 0); } /** * @param {{ create:function(successCallback:function(), errorCallback:function()):Promise, resolve:function(value:*):Promise, reject:function():Promise}} promiseFactory */ TokenManager.setPromiseFactory = function (promiseFactory) { _promiseFactory = promiseFactory; }; /** * @param {{getJSON:function(url:string, config:{ headers: object. })}} httpRequest */ TokenManager.setHttpRequest = function (httpRequest) { if ((typeof httpRequest !== 'object') || (typeof httpRequest.getJSON !== 'function')) { throw Error('The provided value is not a valid http request.'); } _httpRequest = httpRequest; }; TokenManager.prototype._callTokenRemoved = function () { this._callbacks.tokenRemovedCallbacks.forEach(function (cb) { cb(); }); } TokenManager.prototype._callTokenExpiring = function () { this._callbacks.tokenExpiringCallbacks.forEach(function (cb) { cb(); }); } TokenManager.prototype._callTokenExpired = function () { this._callbacks.tokenExpiredCallbacks.forEach(function (cb) { cb(); }); } TokenManager.prototype._callTokenObtained = function () { this._callbacks.tokenObtainedCallbacks.forEach(function (cb) { cb(); }); } TokenManager.prototype._callSilentTokenRenewFailed = function () { this._callbacks.silentTokenRenewFailedCallbacks.forEach(function (cb) { cb(); }); } TokenManager.prototype.saveToken = function (token) { if (token && !(token instanceof Token)) { token = Token.fromResponse(token); } this._token = token; if (this._settings.persist && !this.expired) { this._settings.store.setItem(this._settings.persistKey, token.toJSON()); } else { this._settings.store.removeItem(this._settings.persistKey); } if (token) { this._callTokenObtained(); } else { this._callTokenRemoved(); } } TokenManager.prototype.addOnTokenRemoved = function (cb) { this._callbacks.tokenRemovedCallbacks.push(cb); } TokenManager.prototype.addOnTokenObtained = function (cb) { this._callbacks.tokenObtainedCallbacks.push(cb); } TokenManager.prototype.addOnTokenExpiring = function (cb) { this._callbacks.tokenExpiringCallbacks.push(cb); } TokenManager.prototype.addOnTokenExpired = function (cb) { this._callbacks.tokenExpiredCallbacks.push(cb); } TokenManager.prototype.addOnSilentTokenRenewFailed = function (cb) { this._callbacks.silentTokenRenewFailedCallbacks.push(cb); } TokenManager.prototype.removeToken = function () { this.saveToken(null); } TokenManager.prototype.redirectForToken = function () { var oidc = this.oidcClient; return oidc.createTokenRequestAsync().then(function (request) { window.location = request.url; }, function (err) { console.error("TokenManager.redirectForToken error: " + (err && err.message || "Unknown error")); return _promiseFactory.reject(err); }); } TokenManager.prototype.redirectForLogout = function () { var mgr = this; return mgr.oidcClient.createLogoutRequestAsync(mgr.id_token).then(function (url) { mgr.removeToken(); window.location = url; }, function (err) { console.error("TokenManager.redirectForLogout error: " + (err && err.message || "Unknown error")); return _promiseFactory.reject(err); }); } TokenManager.prototype.processTokenCallbackAsync = function (queryString) { var mgr = this; return mgr.oidcClient.processResponseAsync(queryString).then(function (token) { mgr.saveToken(token); }); } TokenManager.prototype.renewTokenSilentAsync = function () { var mgr = this; if (!mgr._settings.silent_redirect_uri) { return _promiseFactory.reject(Error("silent_redirect_uri not configured")); } var settings = copy(mgr._settings); settings.redirect_uri = settings.silent_redirect_uri; if (!settings.prompt) { settings.prompt = "none"; } var oidc = new OidcClient(settings); return oidc.createTokenRequestAsync().then(function (request) { var frame = new FrameLoader(request.url, { cancelDelay: mgr._settings.silent_renew_timeout }); return frame.loadAsync().then(function (hash) { return oidc.processResponseAsync(hash).then(function (token) { mgr.saveToken(token); }); }); }); } TokenManager.prototype.processTokenCallbackSilent = function (hash) { if (window.parent && window !== window.parent) { var hash = hash || window.location.hash; if (hash) { window.parent.postMessage(hash, location.protocol + "//" + location.host); } } } TokenManager.prototype.openPopupForTokenAsync = function (popupSettings) { popupSettings = popupSettings || {}; popupSettings.features = popupSettings.features || "location=no,toolbar=no"; popupSettings.target = popupSettings.target || "_blank"; var callback_prefix = "tokenmgr_callback_"; // this is a shared callback if (!window.openPopupForTokenAsyncCallback) { window.openPopupForTokenAsyncCallback = function (hash) { var result = OidcClient.parseOidcResult(hash); if (result && result.state && window[callback_prefix + result.state]) { window[callback_prefix + result.state](hash); } } } var mgr = this; var settings = copy(mgr._settings); settings.redirect_uri = settings.popup_redirect_uri || settings.redirect_uri; if (mgr._pendingPopup) { return _promiseFactory.create(function (resolve, reject) { reject(Error("Already a pending popup token request.")); }); } var popup = window.open(settings.redirect_uri, popupSettings.target, popupSettings.features); if (!popup) { return _promiseFactory.create(function (resolve, reject) { reject(Error("Error opening popup.")); }); } mgr._pendingPopup = true; function cleanup(name) { if (handle) { window.clearInterval(handle); } popup.close(); delete mgr._pendingPopup; if (name) { delete window[name]; } } var reject_popup; function checkClosed() { if (!popup.window) { cleanup(); reject_popup(Error("Popup closed")); } } var handle = window.setInterval(checkClosed, 1000); return _promiseFactory.create(function (resolve, reject) { reject_popup = reject; var oidc = new OidcClient(settings); oidc.createTokenRequestAsync().then(function (request) { var callback_name = callback_prefix + request.request_state.state; window[callback_name] = function (hash) { cleanup(callback_name); oidc.processResponseAsync(hash).then(function (token) { mgr.saveToken(token); resolve(); }, function (err) { reject(err); }); }; // give the popup 5 seconds to ready itself, otherwise fail var seconds_to_wait = 5; var interval = 500; var total_times = (seconds_to_wait*1000) / interval; var count = 0; function redirectPopup() { if (popup.setUrl) { popup.setUrl(request.url); } else if (count < total_times) { count++; window.setTimeout(redirectPopup, interval); } else { cleanup(callback_name); reject(Error("Timeout error on popup")); } } redirectPopup(); }, function (err) { cleanup(); reject(err); }); }); } TokenManager.prototype.processTokenPopup = function (hash) { hash = hash || window.location.hash; window.setUrl = function (url) { window.location = url; } if (hash) { window.opener.openPopupForTokenAsyncCallback(hash); } } // exports window.OidcTokenManager = TokenManager; })();