MVC: Solve some design feedback (filter selector in catalog) CatalogApi: Move models from infrastructure to Model folder.
8897 lines
275 KiB
JavaScript
8897 lines
275 KiB
JavaScript
(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<<dbits)-1);
|
|
BigInteger.prototype.DV = (1<<dbits);
|
|
|
|
var BI_FP = 52;
|
|
BigInteger.prototype.FV = Math.pow(2,BI_FP);
|
|
BigInteger.prototype.F1 = BI_FP-dbits;
|
|
BigInteger.prototype.F2 = 2*dbits-BI_FP;
|
|
|
|
// Digit conversions
|
|
var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
var BI_RC = new Array();
|
|
var rr,vv;
|
|
rr = "0".charCodeAt(0);
|
|
for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
|
|
rr = "a".charCodeAt(0);
|
|
for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
|
|
rr = "A".charCodeAt(0);
|
|
for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
|
|
|
|
function int2char(n) { return BI_RM.charAt(n); }
|
|
function intAt(s,i) {
|
|
var c = BI_RC[s.charCodeAt(i)];
|
|
return (c==null)?-1:c;
|
|
}
|
|
|
|
// (protected) copy this to r
|
|
function bnpCopyTo(r) {
|
|
for(var i = this.t-1; i >= 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))<<sh;
|
|
this[this.t++] = (x>>(this.DB-sh));
|
|
}
|
|
else
|
|
this[this.t-1] |= x<<sh;
|
|
sh += k;
|
|
if(sh >= 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)<<sh;
|
|
}
|
|
this.clamp();
|
|
if(mi) BigInteger.ZERO.subTo(this,this);
|
|
}
|
|
|
|
// (protected) clamp off excess high words
|
|
function bnpClamp() {
|
|
var c = this.s&this.DM;
|
|
while(this.t > 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<<k)-1, d, m = false, r = "", i = this.t;
|
|
var p = this.DB-(i*this.DB)%k;
|
|
if(i-- > 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)-1))<<(k-p);
|
|
d |= this[--i]>>(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<<cbs)-1;
|
|
var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
|
|
for(i = this.t-1; i >= 0; --i) {
|
|
r[i+ds+1] = (this[i]>>cbs)|c;
|
|
c = (this[i]&bm)<<bs;
|
|
}
|
|
for(i = ds-1; i >= 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)-1;
|
|
r[0] = this[ds]>>bs;
|
|
for(var i = ds+1; i < this.t; ++i) {
|
|
r[i-ds-1] |= (this[i]&bm)<<cbs;
|
|
r[i-ds] = this[i]>>bs;
|
|
}
|
|
if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
|
|
r.t = this.t-ds;
|
|
r.clamp();
|
|
}
|
|
|
|
// (protected) r = this - a
|
|
function bnpSubTo(a,r) {
|
|
var i = 0, c = 0, m = Math.min(a.t,this.t);
|
|
while(i < m) {
|
|
c += this[i]-a[i];
|
|
r[i++] = c&this.DM;
|
|
c >>= 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<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
|
|
var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
|
|
var i = r.t, j = i-ys, t = (q==null)?nbi():q;
|
|
y.dlShiftTo(j,t);
|
|
if(r.compareTo(t) >= 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<<i)) > 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))<<this.DB)|this[0];
|
|
}
|
|
|
|
// (public) return value as byte
|
|
function bnByteValue() { return (this.t==0)?this.s:(this[0]<<24)>>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<<t)-1); else x[0] = 0;
|
|
this.fromString(x,256);
|
|
}
|
|
}
|
|
|
|
// (public) convert to bigendian byte array
|
|
function bnToByteArray() {
|
|
var i = this.t, r = new Array();
|
|
r[0] = this.s;
|
|
var p = this.DB-(i*this.DB)%8, d, k = 0;
|
|
if(i-- > 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)-1))<<(8-p);
|
|
d |= this[--i]>>(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<<n)
|
|
function bnpChangeBit(n,op) {
|
|
var r = BigInteger.ONE.shiftLeft(n);
|
|
this.bitwiseTo(r,op,r);
|
|
return r;
|
|
}
|
|
|
|
// (public) this | (1<<n)
|
|
function bnSetBit(n) { return this.changeBit(n,op_or); }
|
|
|
|
// (public) this & ~(1<<n)
|
|
function bnClearBit(n) { return this.changeBit(n,op_andnot); }
|
|
|
|
// (public) this ^ (1<<n)
|
|
function bnFlipBit(n) { return this.changeBit(n,op_xor); }
|
|
|
|
// (protected) r = this + a
|
|
function bnpAddTo(a,r) {
|
|
var i = 0, c = 0, m = Math.min(a.t,this.t);
|
|
while(i < m) {
|
|
c += this[i]+a[i];
|
|
r[i++] = c&this.DM;
|
|
c >>= 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<<k)-1;
|
|
g[1] = z.convert(this);
|
|
if(k > 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<<i)) == 0) {
|
|
z.sqrTo(r,r2); t = r; r = r2; r2 = t;
|
|
if(--i < 0) { i = this.DB-1; --j; }
|
|
}
|
|
}
|
|
return z.revert(r);
|
|
}
|
|
|
|
// (public) gcd(this,a) (HAC 14.54)
|
|
function bnGCD(a) {
|
|
var x = (this.s<0)?this.negate():this.clone();
|
|
var y = (a.s<0)?a.negate():a.clone();
|
|
if(x.compareTo(y) < 0) { var t = x; x = y; y = t; }
|
|
var i = x.getLowestSetBit(), g = y.getLowestSetBit();
|
|
if(g < 0) return x;
|
|
if(i < g) g = i;
|
|
if(g > 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 <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
|
|
*/
|
|
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<a;b++){c=c+"0"}return c+e}function _rsasign_signString(d,a){var b=function(e){return KJUR.crypto.Util.hashString(e,a)};var c=b(d);return this.signWithMessageHash(c,a)}function _rsasign_signWithMessageHash(e,c){var f=KJUR.crypto.Util.getPaddedDigestInfoHex(e,c,this.n.bitLength());var b=parseBigInt(f,16);var d=this.doPrivate(b);var a=d.toString(16);return _zeroPaddingOfSignature(a,this.n.bitLength())}function _rsasign_signStringWithSHA1(a){return _rsasign_signString.call(this,a,"sha1")}function _rsasign_signStringWithSHA256(a){return _rsasign_signString.call(this,a,"sha256")}function pss_mgf1_str(c,a,e){var b="",d=0;while(b.length<a){b+=hextorstr(e(rstrtohex(c+String.fromCharCode.apply(String,[(d&4278190080)>>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<c-k-g-2;d+=1){j[d]=0}var e=String.fromCharCode.apply(String,j)+"\x01"+f;var h=pss_mgf1_str(n,e.length,o);var q=[];for(d=0;d<e.length;d+=1){q[d]=e.charCodeAt(d)^h.charCodeAt(d)}var p=(65280>>(8*c-m))&255;q[0]&=~p;for(d=0;d<g;d++){q.push(n.charCodeAt(d))}q.push(188);return _zeroPaddingOfSignature(this.doPrivate(new BigInteger(q)).toString(16),this.n.bitLength())}function _rsasign_getDecryptSignatureBI(a,d,c){var b=new RSAKey();b.setPublic(d,c);var e=b.doPublic(a);return e}function _rsasign_getHexDigestInfoFromSig(a,c,b){var e=_rsasign_getDecryptSignatureBI(a,c,b);var d=e.toString(16).replace(/^1f+00/,"");return d}function _rsasign_getAlgNameAndHashFromHexDisgestInfo(f){for(var e in KJUR.crypto.Util.DIGESTINFOHEAD){var d=KJUR.crypto.Util.DIGESTINFOHEAD[e];var b=d.length;if(f.substring(0,b)==d){var c=[e,f.substring(b)];return c}}return[]}function _rsasign_verifySignatureWithArgs(f,b,g,j){var e=_rsasign_getHexDigestInfoFromSig(b,g,j);var h=_rsasign_getAlgNameAndHashFromHexDisgestInfo(e);if(h.length==0){return false}var d=h[0];var i=h[1];var a=function(k){return KJUR.crypto.Util.hashString(k,d)};var c=a(f);return(i==c)}function _rsasign_verifyHexSignatureForMessage(c,b){var d=parseBigInt(c,16);var a=_rsasign_verifySignatureWithArgs(b,d,this.n.toString(16),this.e.toString(16));return a}function _rsasign_verifyString(f,j){j=j.replace(_RE_HEXDECONLY,"");j=j.replace(/[ \n]+/g,"");var b=parseBigInt(j,16);if(b.bitLength()>this.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<a.length;q+=1){a[q]&=255}while(a.length<m){a.unshift(0)}if(a[m-1]!==188){throw"encoded message does not end in 0xbc"}a=String.fromCharCode.apply(String,a);var d=a.substr(0,m-h-1);var e=a.substr(d.length,h);var p=(65280>>(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;q<d.length;q+=1){o[q]=d.charCodeAt(q)^n.charCodeAt(q)}o[0]&=~p;var b=m-h-c-2;for(q=0;q<b;q+=1){if(o[q]!==0){throw"leftmost octets not zero"}}if(o[b]!==1){throw"0x01 marker not found"}return e===hextorstr(r(rstrtohex("\x00\x00\x00\x00\x00\x00\x00\x00"+j+String.fromCharCode.apply(String,o.slice(-c)))))}RSAKey.prototype.signWithMessageHash=_rsasign_signWithMessageHash;RSAKey.prototype.signString=_rsasign_signString;RSAKey.prototype.signStringWithSHA1=_rsasign_signStringWithSHA1;RSAKey.prototype.signStringWithSHA256=_rsasign_signStringWithSHA256;RSAKey.prototype.sign=_rsasign_signString;RSAKey.prototype.signWithSHA1=_rsasign_signStringWithSHA1;RSAKey.prototype.signWithSHA256=_rsasign_signStringWithSHA256;RSAKey.prototype.signWithMessageHashPSS=_rsasign_signWithMessageHashPSS;RSAKey.prototype.signStringPSS=_rsasign_signStringPSS;RSAKey.prototype.signPSS=_rsasign_signStringPSS;RSAKey.SALT_LEN_HLEN=-1;RSAKey.SALT_LEN_MAX=-2;RSAKey.prototype.verifyWithMessageHash=_rsasign_verifyWithMessageHash;RSAKey.prototype.verifyString=_rsasign_verifyString;RSAKey.prototype.verifyHexSignatureForMessage=_rsasign_verifyHexSignatureForMessage;RSAKey.prototype.verify=_rsasign_verifyString;RSAKey.prototype.verifyHexSignatureForByteArrayMessage=_rsasign_verifyHexSignatureForMessage;RSAKey.prototype.verifyWithMessageHashPSS=_rsasign_verifyWithMessageHashPSS;RSAKey.prototype.verifyStringPSS=_rsasign_verifyStringPSS;RSAKey.prototype.verifyPSS=_rsasign_verifyStringPSS;RSAKey.SALT_LEN_RECOVER=-2;
|
|
/*! asn1hex-1.1.5.js (c) 2012-2014 Kenji Urushima | kjur.github.com/jsrsasign/license
|
|
*/
|
|
/*
|
|
* asn1hex.js - Hexadecimal represented ASN.1 string library
|
|
*
|
|
* 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 asn1hex-1.1.js
|
|
* @author Kenji Urushima kenji.urushima@gmail.com
|
|
* @version asn1hex 1.1.5 (2014-May-25)
|
|
* @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
|
|
*/
|
|
|
|
/*
|
|
* 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 <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
|
|
*/
|
|
|
|
/*
|
|
* Depends:
|
|
* base64.js
|
|
* rsa.js
|
|
* asn1hex.js
|
|
*/
|
|
|
|
/**
|
|
* X.509 certificate class.<br/>
|
|
* @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 <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
|
|
*/
|
|
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.<br/>
|
|
* @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.<br/>
|
|
* @name getIssuerHex
|
|
* @memberOf X509#
|
|
* @function
|
|
*/
|
|
this.getIssuerHex = function() {
|
|
return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]);
|
|
};
|
|
|
|
/**
|
|
* get string of issuer field of certificate.<br/>
|
|
* @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.<br/>
|
|
* @name getSubjectHex
|
|
* @memberOf X509#
|
|
* @function
|
|
*/
|
|
this.getSubjectHex = function() {
|
|
return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]);
|
|
};
|
|
|
|
/**
|
|
* get string of subject field of certificate.<br/>
|
|
* @name getSubjectString
|
|
* @memberOf X509#
|
|
* @function
|
|
*/
|
|
this.getSubjectString = function() {
|
|
return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]));
|
|
};
|
|
|
|
/**
|
|
* get notBefore field string of certificate.<br/>
|
|
* @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.<br/>
|
|
* @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.<br/>
|
|
* @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:
|
|
* <ul>
|
|
* <li>algoid - hexadecimal string of OID of asymmetric key algorithm</li>
|
|
* <li>algparam - hexadecimal string of OID of ECC curve name or null</li>
|
|
* <li>keyhex - hexadecimal string of key in the certificate</li>
|
|
* </ul>
|
|
* @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 <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a>
|
|
*/
|
|
|
|
/**
|
|
* 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
|
|
* <p>
|
|
* This namespace privides following crytpgrahic classes.
|
|
* <ul>
|
|
* <li>{@link KJUR.crypto.MessageDigest} - Java JCE(cryptograhic extension) style MessageDigest class</li>
|
|
* <li>{@link KJUR.crypto.Signature} - Java JCE(cryptograhic extension) style Signature class</li>
|
|
* <li>{@link KJUR.crypto.Util} - cryptographic utility functions and properties</li>
|
|
* </ul>
|
|
* NOTE: Please ignore method summary and document of this namespace. This caused by a bug of jsdoc2.
|
|
* </p>
|
|
* @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
|
|
* <br/>
|
|
* Currently this supports following algorithm and providers combination:
|
|
* <ul>
|
|
* <li>md5 - cryptojs</li>
|
|
* <li>sha1 - cryptojs</li>
|
|
* <li>sha224 - cryptojs</li>
|
|
* <li>sha256 - cryptojs</li>
|
|
* <li>sha384 - cryptojs</li>
|
|
* <li>sha512 - cryptojs</li>
|
|
* <li>ripemd160 - cryptojs</li>
|
|
* <li>sha256 - sjcl (NEW from crypto.js 1.0.4)</li>
|
|
* </ul>
|
|
* @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
|
|
* <br/>
|
|
* Currently this supports following algorithm and providers combination:
|
|
* <ul>
|
|
* <li>hmacmd5 - cryptojs</li>
|
|
* <li>hmacsha1 - cryptojs</li>
|
|
* <li>hmacsha224 - cryptojs</li>
|
|
* <li>hmacsha256 - cryptojs</li>
|
|
* <li>hmacsha384 - cryptojs</li>
|
|
* <li>hmacsha512 - cryptojs</li>
|
|
* </ul>
|
|
* 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
|
|
* <br/>
|
|
* As for params of constructor's argument, it can be specify following attributes:
|
|
* <ul>
|
|
* <li>alg - signature algorithm name (ex. {MD5,SHA1,SHA224,SHA256,SHA384,SHA512,RIPEMD160}with{RSA,ECDSA,DSA})</li>
|
|
* <li>provider - currently 'cryptojs/jsrsa' only</li>
|
|
* </ul>
|
|
* <h4>SUPPORTED ALGORITHMS AND PROVIDERS</h4>
|
|
* This Signature class supports following signature algorithm and provider names:
|
|
* <ul>
|
|
* <li>MD5withRSA - cryptojs/jsrsa</li>
|
|
* <li>SHA1withRSA - cryptojs/jsrsa</li>
|
|
* <li>SHA224withRSA - cryptojs/jsrsa</li>
|
|
* <li>SHA256withRSA - cryptojs/jsrsa</li>
|
|
* <li>SHA384withRSA - cryptojs/jsrsa</li>
|
|
* <li>SHA512withRSA - cryptojs/jsrsa</li>
|
|
* <li>RIPEMD160withRSA - cryptojs/jsrsa</li>
|
|
* <li>MD5withECDSA - cryptojs/jsrsa</li>
|
|
* <li>SHA1withECDSA - cryptojs/jsrsa</li>
|
|
* <li>SHA224withECDSA - cryptojs/jsrsa</li>
|
|
* <li>SHA256withECDSA - cryptojs/jsrsa</li>
|
|
* <li>SHA384withECDSA - cryptojs/jsrsa</li>
|
|
* <li>SHA512withECDSA - cryptojs/jsrsa</li>
|
|
* <li>RIPEMD160withECDSA - cryptojs/jsrsa</li>
|
|
* <li>MD5withRSAandMGF1 - cryptojs/jsrsa</li>
|
|
* <li>SHA1withRSAandMGF1 - cryptojs/jsrsa</li>
|
|
* <li>SHA224withRSAandMGF1 - cryptojs/jsrsa</li>
|
|
* <li>SHA256withRSAandMGF1 - cryptojs/jsrsa</li>
|
|
* <li>SHA384withRSAandMGF1 - cryptojs/jsrsa</li>
|
|
* <li>SHA512withRSAandMGF1 - cryptojs/jsrsa</li>
|
|
* <li>RIPEMD160withRSAandMGF1 - cryptojs/jsrsa</li>
|
|
* <li>SHA1withDSA - cryptojs/jsrsa</li>
|
|
* <li>SHA224withDSA - cryptojs/jsrsa</li>
|
|
* <li>SHA256withDSA - cryptojs/jsrsa</li>
|
|
* </ul>
|
|
* Here are supported elliptic cryptographic curve names and their aliases for ECDSA:
|
|
* <ul>
|
|
* <li>secp256k1</li>
|
|
* <li>secp256r1, NIST P-256, P-256, prime256v1</li>
|
|
* <li>secp384r1, NIST P-384, P-384</li>
|
|
* </ul>
|
|
* NOTE1: DSA signing algorithm is also supported since crypto 1.1.5.
|
|
* <h4>EXAMPLES</h4>
|
|
* @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:
|
|
* <h5>signing</h5>
|
|
* <ul>
|
|
* <li>PEM formatted PKCS#8 encrypted RSA/ECDSA private key concluding "BEGIN ENCRYPTED PRIVATE KEY"</li>
|
|
* <li>PEM formatted PKCS#5 encrypted RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" and ",ENCRYPTED"</li>
|
|
* <li>PEM formatted PKCS#8 plain RSA/ECDSA private key concluding "BEGIN PRIVATE KEY"</li>
|
|
* <li>PEM formatted PKCS#5 plain RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" without ",ENCRYPTED"</li>
|
|
* <li>RSAKey object of private key</li>
|
|
* <li>KJUR.crypto.ECDSA object of private key</li>
|
|
* <li>KJUR.crypto.DSA object of private key</li>
|
|
* </ul>
|
|
* <h5>verification</h5>
|
|
* <ul>
|
|
* <li>PEM formatted PKCS#8 RSA/EC/DSA public key concluding "BEGIN PUBLIC KEY"</li>
|
|
* <li>PEM formatted X.509 certificate with RSA/EC/DSA public key concluding
|
|
* "BEGIN CERTIFICATE", "BEGIN X509 CERTIFICATE" or "BEGIN TRUSTED CERTIFICATE".</li>
|
|
* <li>RSAKey object of public key</li>
|
|
* <li>KJUR.crypto.ECDSA object of public key</li>
|
|
* <li>KJUR.crypto.DSA object of public key</li>
|
|
* </ul>
|
|
* @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:
|
|
* <ul>
|
|
* <li>{@link RSAKey} object for RSA verification</li>
|
|
* <li>associative array for ECDSA verification
|
|
* (ex. <code>{'ecpubhex': '041f..', 'eccurvename': 'secp256r1'}</code>)
|
|
* </li>
|
|
* </ul>
|
|
* @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:
|
|
* <ul>
|
|
* <li>{@link RSAKey} object for RSA signing</li>
|
|
* <li>associative array for ECDSA signing
|
|
* (ex. <code>{'ecprvhex': '1d3f..', 'eccurvename': 'secp256r1'}</code>)</li>
|
|
* </ul>
|
|
* @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.<br/>
|
|
* 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.
|
|
* <ul>
|
|
* <li>(ASCII) String</li>
|
|
* <li>UTF8 String including CJK, Latin and other characters</li>
|
|
* <li>byte array</li>
|
|
* <li>hexadecimal encoded String</li>
|
|
* <li>Full URIComponent encoded String (such like "%69%94")</li>
|
|
* <li>Base64 encoded String</li>
|
|
* <li>Base64URL encoded String</li>
|
|
* </ul>
|
|
* 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 <a href="http://kjur.github.com/jsjws/">'jwjws'(JWS JavaScript Library) home page http://kjur.github.com/jsjws/</a>
|
|
* @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
|
|
*/
|
|
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.<br/>
|
|
* @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.<br/>
|
|
* 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.<br/>
|
|
* 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.<br/>
|
|
* 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.<br/>
|
|
* 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.<br/>
|
|
* 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.<br/>
|
|
* 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.<br/>
|
|
* @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.<br/>
|
|
* @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.<br/>
|
|
* @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.<br/>
|
|
* @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.<br/>
|
|
* @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.<br/>
|
|
* @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.<br/>
|
|
* @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.<br/>
|
|
* 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.<br/>
|
|
* @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.<br/>
|
|
* @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.<br/>
|
|
* @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".<br/>
|
|
* @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".<br/>
|
|
* Note that these "<code>0-9A-Za-z!'()*-._~</code>" 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 <mikesamuel@gmail.com>
|
|
*/
|
|
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 <a href="http://kjur.github.io/jsjws/license/">MIT License</a>
|
|
*/
|
|
|
|
if (typeof KJUR == "undefined" || !KJUR) KJUR = {};
|
|
if (typeof KJUR.jws == "undefined" || !KJUR.jws) KJUR.jws = {};
|
|
|
|
/**
|
|
* JSON Web Signature(JWS) class.<br/>
|
|
* @name KJUR.jws.JWS
|
|
* @class JSON Web Signature(JWS) class
|
|
* @property {Dictionary} parsedJWS This property is set after JWS signature verification. <br/>
|
|
* 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 <a href="http://kjur.github.com/jsjws/">'jwjws'(JWS JavaScript Library) home page http://kjur.github.com/jsjws/</a>
|
|
* @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a>
|
|
* @see <a href="http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-14">IETF I-D JSON Web Algorithms (JWA)</a>
|
|
* @since jsjws 1.0
|
|
* @description
|
|
* <h4>Supported Algorithms</h4>
|
|
* Here is supported algorithm names for {@link KJUR.jws.JWS.sign} and {@link KJUR.jws.JWS.verify}
|
|
* methods.
|
|
* <table>
|
|
* <tr><th>alg value</th><th>spec requirement</th><th>jsjws support</th></tr>
|
|
* <tr><td>HS256</td><td>REQUIRED</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>HS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>HS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>RS256</td><td>RECOMMENDED</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>RS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>RS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>ES256</td><td>RECOMMENDED+</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>ES384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>ES512</td><td>OPTIONAL</td><td>-</td></tr>
|
|
* <tr><td>PS256</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>PS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>PS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>none</td><td>REQUIRED</td><td>SUPPORTED</td></tr>
|
|
* </table>
|
|
* 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.<br/>
|
|
* @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.<br/>
|
|
* 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.<br/>
|
|
* 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.<br/>
|
|
* 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.<br/>
|
|
* 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.<br/>
|
|
* 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.<br/>
|
|
* 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<br/>
|
|
* 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<br/>
|
|
* @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 <a href="http://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Signature.html">jsrsasign KJUR.crypto.Signature method</a>
|
|
* @see <a href="http://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Mac.html">jsrsasign KJUR.crypto.Mac method</a>
|
|
* @description
|
|
* This method supports following algorithms.
|
|
* <table>
|
|
* <tr><th>alg value</th><th>spec requirement</th><th>jsjws support</th></tr>
|
|
* <tr><td>HS256</td><td>REQUIRED</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>HS384</td><td>OPTIONAL</td><td>-</td></tr>
|
|
* <tr><td>HS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>RS256</td><td>RECOMMENDED</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>RS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>RS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>ES256</td><td>RECOMMENDED+</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>ES384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>ES512</td><td>OPTIONAL</td><td>-</td></tr>
|
|
* <tr><td>PS256</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>PS384</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>PS512</td><td>OPTIONAL</td><td>SUPPORTED</td></tr>
|
|
* <tr><td>none</td><td>REQUIRED</td><td>SUPPORTED</td></tr>
|
|
* </table>
|
|
* <dl>
|
|
* <dt>NOTE1:
|
|
* <dd>salt length of RSAPSS signature is the same as the hash algorithm length
|
|
* because of <a href="http://www.ietf.org/mail-archive/web/jose/current/msg02901.html">IETF JOSE ML discussion</a>.
|
|
* <dt>NOTE2:
|
|
* <dd>The reason of HS384 unsupport is
|
|
* <a href="https://code.google.com/p/crypto-js/issues/detail?id=84">CryptoJS HmacSHA384 bug</a>.
|
|
* </dl>
|
|
*/
|
|
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<br/>
|
|
* @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 <a href="http://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Signature.html">jsrsasign KJUR.crypto.Signature method</a>
|
|
* @see <a href="http://kjur.github.io/jsrsasign/api/symbols/KJUR.crypto.Mac.html">jsrsasign KJUR.crypto.Mac method</a>
|
|
*/
|
|
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.<br/>
|
|
* 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.<br/>
|
|
* 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.<br/>
|
|
* @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.
|
|
* <ul>
|
|
* <li>now - current time</li>
|
|
* <li>now + 1hour - after 1 hour from now</li>
|
|
* <li>now + 1day - after 1 day from now</li>
|
|
* <li>now + 1month - after 30 days from now</li>
|
|
* <li>now + 1year - after 365 days from now</li>
|
|
* <li>YYYYmmDDHHMMSSZ - UTC time (ex. 20130828235959Z)</li>
|
|
* <li>number - UNIX origin time (seconds from 1970-01-01 00:00:00) (ex. 1377714748)</li>
|
|
* </ul>
|
|
*/
|
|
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.<string, string>} 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.<string, string> }} [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.<string, string> })}} 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;
|
|
})();
|