2278 lines
72 KiB
TypeScript
2278 lines
72 KiB
TypeScript
/**
|
|
* @license crypto-ts
|
|
* MIT license
|
|
*/
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class Hex {
|
|
/**
|
|
* Converts a word array to a hex string.
|
|
*
|
|
* \@example
|
|
*
|
|
* let hexString = Hex.stringify(wordArray);
|
|
* @param {?} wordArray The word array.
|
|
*
|
|
* @return {?} The hex string.
|
|
*
|
|
*/
|
|
static stringify(wordArray) {
|
|
// Convert
|
|
const /** @type {?} */ hexChars = [];
|
|
for (let /** @type {?} */ i = 0; i < wordArray.sigBytes; i++) {
|
|
const /** @type {?} */ bite = (wordArray.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.
|
|
*
|
|
* \@example
|
|
*
|
|
* let wordArray = Hex.parse(hexString);
|
|
* @param {?} hexStr The hex string.
|
|
*
|
|
* @return {?} The word array.
|
|
*
|
|
*/
|
|
static parse(hexStr) {
|
|
// Shortcut
|
|
const /** @type {?} */ hexStrLength = hexStr.length;
|
|
// Convert
|
|
const /** @type {?} */ words = [];
|
|
for (let /** @type {?} */ i = 0; i < hexStrLength; i += 2) {
|
|
words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
|
|
}
|
|
return new WordArray(words, hexStrLength / 2);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class WordArray {
|
|
/**
|
|
* Creates a word array filled with random bytes.
|
|
*
|
|
* \@example
|
|
*
|
|
* let wordArray = WordArray.random(16);
|
|
* @param {?} nBytes The number of random bytes to generate.
|
|
*
|
|
* @return {?} The random word array.
|
|
*
|
|
*/
|
|
static random(nBytes) {
|
|
const /** @type {?} */ words = [];
|
|
const /** @type {?} */ r = (function (m_w) {
|
|
let /** @type {?} */ m_z = 0x3ade68b1;
|
|
const /** @type {?} */ mask = 0xffffffff;
|
|
return function () {
|
|
m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask;
|
|
m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask;
|
|
let /** @type {?} */ result = ((m_z << 0x10) + m_w) & mask;
|
|
result /= 0x100000000;
|
|
result += 0.5;
|
|
return result * (Math.random() > .5 ? 1 : -1);
|
|
};
|
|
});
|
|
for (let /** @type {?} */ i = 0, /** @type {?} */ rcache; i < nBytes; i += 4) {
|
|
const /** @type {?} */ _r = r((rcache || Math.random()) * 0x100000000);
|
|
rcache = _r() * 0x3ade67b7;
|
|
words.push((_r() * 0x100000000) | 0);
|
|
}
|
|
return new WordArray(words, nBytes);
|
|
}
|
|
/**
|
|
* Initializes a newly created word array.
|
|
*
|
|
* \@example
|
|
*
|
|
* let wordArray = new WordArray();
|
|
* let wordArray = new WordArray([0x00010203, 0x04050607]);
|
|
* let wordArray = new WordArray([0x00010203, 0x04050607], 6);
|
|
* @param {?=} words (Optional) An array of 32-bit words.
|
|
* @param {?=} sigBytes (Optional) The number of significant bytes in the words.
|
|
*
|
|
*/
|
|
constructor(words, sigBytes) {
|
|
this.words = words || [];
|
|
if (sigBytes !== undefined) {
|
|
this.sigBytes = sigBytes;
|
|
}
|
|
else {
|
|
this.sigBytes = this.words.length * 4;
|
|
}
|
|
}
|
|
/**
|
|
* Converts this word array to a string.
|
|
*
|
|
* \@example
|
|
*
|
|
* let string = wordArray + '';
|
|
* let string = wordArray.toString();
|
|
* let string = wordArray.toString(CryptoJS.enc.Utf8);
|
|
* @param {?=} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex
|
|
*
|
|
* @return {?} The stringified word array.
|
|
*
|
|
*/
|
|
toString(encoder) {
|
|
return (encoder || Hex).stringify(this);
|
|
}
|
|
/**
|
|
* Concatenates a word array to this word array.
|
|
*
|
|
* \@example
|
|
*
|
|
* wordArray1.concat(wordArray2);
|
|
* @param {?} wordArray The word array to append.
|
|
*
|
|
* @return {?} This word array.
|
|
*
|
|
*/
|
|
concat(wordArray) {
|
|
// Clamp excess bits
|
|
this.clamp();
|
|
// Concat
|
|
if (this.sigBytes % 4) {
|
|
// Copy one byte at a time
|
|
for (let /** @type {?} */ i = 0; i < wordArray.sigBytes; i++) {
|
|
const /** @type {?} */ thatByte = (wordArray.words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
|
|
this.words[(this.sigBytes + i) >>> 2] |= thatByte << (24 - ((this.sigBytes + i) % 4) * 8);
|
|
}
|
|
}
|
|
else {
|
|
// Copy one word at a time
|
|
for (let /** @type {?} */ i = 0; i < wordArray.sigBytes; i += 4) {
|
|
this.words[(this.sigBytes + i) >>> 2] = wordArray.words[i >>> 2];
|
|
}
|
|
}
|
|
this.sigBytes += wordArray.sigBytes;
|
|
// Chainable
|
|
return this;
|
|
}
|
|
/**
|
|
* Removes insignificant bits.
|
|
*
|
|
* \@example
|
|
*
|
|
* wordArray.clamp();
|
|
* @return {?}
|
|
*/
|
|
clamp() {
|
|
// Clamp
|
|
this.words[this.sigBytes >>> 2] &= 0xffffffff << (32 - (this.sigBytes % 4) * 8);
|
|
this.words.length = Math.ceil(this.sigBytes / 4);
|
|
}
|
|
/**
|
|
* Creates a copy of this word array.
|
|
*
|
|
* \@example
|
|
*
|
|
* let clone = wordArray.clone();
|
|
* @return {?} The clone.
|
|
*
|
|
*/
|
|
clone() {
|
|
return new WordArray(this.words.slice(0), this.sigBytes);
|
|
}
|
|
|
|
slice(start, end){
|
|
// console.log("slice:", start, end, this.words.length);
|
|
this.words = this.words.slice(start, end);
|
|
this.sigBytes = this.words.length * 4;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class Latin1 {
|
|
/**
|
|
* Converts a word array to a Latin1 string.
|
|
*
|
|
* \@example
|
|
*
|
|
* let latin1String = Latin1.stringify(wordArray);
|
|
* @param {?} wordArray The word array.
|
|
*
|
|
* @return {?} The Latin1 string.
|
|
*
|
|
*/
|
|
static stringify(wordArray) {
|
|
// Convert
|
|
const /** @type {?} */ latin1Chars = [];
|
|
for (let /** @type {?} */ i = 0; i < wordArray.sigBytes; i++) {
|
|
const /** @type {?} */ bite = (wordArray.words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
|
|
latin1Chars.push(String.fromCharCode(bite));
|
|
}
|
|
return latin1Chars.join('');
|
|
}
|
|
/**
|
|
* Converts a Latin1 string to a word array.
|
|
*
|
|
* \@example
|
|
*
|
|
* let wordArray = Latin1.parse(latin1String);
|
|
* @param {?} latin1Str The Latin1 string.
|
|
*
|
|
* @return {?} The word array.
|
|
*
|
|
*/
|
|
static parse(latin1Str) {
|
|
// Shortcut
|
|
const /** @type {?} */ latin1StrLength = latin1Str.length;
|
|
// Convert
|
|
const /** @type {?} */ words = [];
|
|
for (let /** @type {?} */ i = 0; i < latin1StrLength; i++) {
|
|
words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);
|
|
}
|
|
return new WordArray(words, latin1StrLength);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class Utf8 {
|
|
/**
|
|
* Converts a word array to a UTF-8 string.
|
|
*
|
|
* \@example
|
|
*
|
|
* let utf8String = Utf8.stringify(wordArray);
|
|
* @param {?} wordArray The word array.
|
|
*
|
|
* @return {?} The UTF-8 string.
|
|
*
|
|
*/
|
|
static stringify(wordArray) {
|
|
try {
|
|
return decodeURIComponent(escape(Latin1.stringify(wordArray)));
|
|
}
|
|
catch (/** @type {?} */ e) {
|
|
throw new Error('Malformed UTF-8 data');
|
|
}
|
|
}
|
|
/**
|
|
* Converts a UTF-8 string to a word array.
|
|
*
|
|
* \@example
|
|
*
|
|
* let wordArray = Utf8.parse(utf8String);
|
|
* @param {?} utf8Str The UTF-8 string.
|
|
*
|
|
* @return {?} The word array.
|
|
*
|
|
*/
|
|
static parse(utf8Str) {
|
|
return Latin1.parse(unescape(encodeURIComponent(utf8Str)));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
/**
|
|
* @abstract
|
|
*/
|
|
class BufferedBlockAlgorithm {
|
|
/**
|
|
* @param {?=} cfg
|
|
*/
|
|
constructor(cfg) {
|
|
this._minBufferSize = 0;
|
|
this.cfg = Object.assign({
|
|
blockSize: 1
|
|
}, cfg);
|
|
// Initial values
|
|
this._data = new WordArray();
|
|
this._nDataBytes = 0;
|
|
}
|
|
/**
|
|
* Resets this block algorithm's data buffer to its initial state.
|
|
*
|
|
* \@example
|
|
*
|
|
* bufferedBlockAlgorithm.reset();
|
|
* @return {?}
|
|
*/
|
|
reset() {
|
|
// Initial values
|
|
this._data = new WordArray();
|
|
this._nDataBytes = 0;
|
|
}
|
|
/**
|
|
* Adds new data to this block algorithm's buffer.
|
|
*
|
|
* \@example
|
|
*
|
|
* bufferedBlockAlgorithm._append('data');
|
|
* bufferedBlockAlgorithm._append(wordArray);
|
|
* @param {?} data The data to append. Strings are converted to a WordArray using UTF-8.
|
|
*
|
|
* @return {?}
|
|
*/
|
|
_append(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.
|
|
*
|
|
* \@example
|
|
*
|
|
* let processedData = bufferedBlockAlgorithm._process();
|
|
* let processedData = bufferedBlockAlgorithm._process(!!'flush');
|
|
* @param {?=} doFlush Whether all blocks and partial blocks should be processed.
|
|
*
|
|
* @return {?} The processed data.
|
|
*
|
|
*/
|
|
_process(doFlush) {
|
|
if (!this.cfg.blockSize) {
|
|
throw new Error('missing blockSize in config');
|
|
}
|
|
// Shortcuts
|
|
const /** @type {?} */ blockSizeBytes = this.cfg.blockSize * 4;
|
|
// Count blocks ready
|
|
let /** @type {?} */ nBlocksReady = this._data.sigBytes / 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
|
|
const /** @type {?} */ nWordsReady = nBlocksReady * this.cfg.blockSize;
|
|
// Count bytes ready
|
|
const /** @type {?} */ nBytesReady = Math.min(nWordsReady * 4, this._data.sigBytes);
|
|
// Process blocks
|
|
let /** @type {?} */ processedWords;
|
|
if (nWordsReady) {
|
|
for (let /** @type {?} */ offset = 0; offset < nWordsReady; offset += this.cfg.blockSize) {
|
|
// Perform concrete-algorithm logic
|
|
this._doProcessBlock(this._data.words, offset);
|
|
}
|
|
// Remove processed words
|
|
processedWords = this._data.words.splice(0, nWordsReady);
|
|
this._data.sigBytes -= nBytesReady;
|
|
}
|
|
// Return processed words
|
|
return new WordArray(processedWords, nBytesReady);
|
|
}
|
|
/**
|
|
* Creates a copy of this object.
|
|
*
|
|
* \@example
|
|
*
|
|
* let clone = bufferedBlockAlgorithm.clone();
|
|
* @return {?} The clone.
|
|
*
|
|
*/
|
|
clone() {
|
|
const /** @type {?} */ clone = this.constructor();
|
|
for (const /** @type {?} */ attr in this) {
|
|
if (this.hasOwnProperty(attr)) {
|
|
clone[attr] = this[attr];
|
|
}
|
|
}
|
|
clone._data = this._data.clone();
|
|
return clone;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class Base {
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class CipherParams extends Base {
|
|
/**
|
|
* Initializes a newly created cipher params object.
|
|
*
|
|
* \@example
|
|
*
|
|
* let cipherParams = CipherParams.create({
|
|
* ciphertext: ciphertextWordArray,
|
|
* key: keyWordArray,
|
|
* iv: ivWordArray,
|
|
* salt: saltWordArray,
|
|
* algorithm: AESAlgorithm,
|
|
* mode: CBC,
|
|
* padding: PKCS7,
|
|
* blockSize: 4,
|
|
* formatter: OpenSSLFormatter
|
|
* });
|
|
* @param {?} cipherParams An object with any of the possible cipher parameters.
|
|
*
|
|
*/
|
|
constructor(cipherParams) {
|
|
super();
|
|
this.ciphertext = cipherParams.ciphertext;
|
|
this.key = cipherParams.key;
|
|
this.iv = cipherParams.iv;
|
|
this.salt = cipherParams.salt;
|
|
this.algorithm = cipherParams.algorithm;
|
|
this.mode = cipherParams.mode;
|
|
this.padding = cipherParams.padding;
|
|
this.blockSize = cipherParams.blockSize;
|
|
this.formatter = cipherParams.formatter;
|
|
}
|
|
/**
|
|
* @param {?} additionalParams
|
|
* @return {?}
|
|
*/
|
|
extend(additionalParams) {
|
|
if (additionalParams.ciphertext !== undefined) {
|
|
this.ciphertext = additionalParams.ciphertext;
|
|
}
|
|
if (additionalParams.key !== undefined) {
|
|
this.key = additionalParams.key;
|
|
}
|
|
if (additionalParams.iv !== undefined) {
|
|
this.iv = additionalParams.iv;
|
|
}
|
|
if (additionalParams.salt !== undefined) {
|
|
this.salt = additionalParams.salt;
|
|
}
|
|
if (additionalParams.algorithm !== undefined) {
|
|
this.algorithm = additionalParams.algorithm;
|
|
}
|
|
if (additionalParams.mode !== undefined) {
|
|
this.mode = additionalParams.mode;
|
|
}
|
|
if (additionalParams.padding !== undefined) {
|
|
this.padding = additionalParams.padding;
|
|
}
|
|
if (additionalParams.blockSize !== undefined) {
|
|
this.blockSize = additionalParams.blockSize;
|
|
}
|
|
if (additionalParams.formatter !== undefined) {
|
|
this.formatter = additionalParams.formatter;
|
|
}
|
|
return this;
|
|
}
|
|
/**
|
|
* Converts this cipher params object to a string.
|
|
*
|
|
* @throws Error If neither the formatter nor the default formatter is set.
|
|
*
|
|
* \@example
|
|
*
|
|
* let string = cipherParams + '';
|
|
* let string = cipherParams.toString();
|
|
* let string = cipherParams.toString(CryptoJS.format.OpenSSL);
|
|
* @param {?=} formatter (Optional) The formatting strategy to use.
|
|
*
|
|
* @return {?} The stringified cipher params.
|
|
*
|
|
*/
|
|
toString(formatter) {
|
|
if (formatter) {
|
|
return formatter.stringify(this);
|
|
}
|
|
else if (this.formatter) {
|
|
return this.formatter.stringify(this);
|
|
}
|
|
else {
|
|
throw new Error('cipher needs a formatter to be able to convert the result into a string');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class Base64 {
|
|
/**
|
|
* Converts a word array to a Base64 string.
|
|
*
|
|
* \@example
|
|
*
|
|
* let base64String = Base64.stringify(wordArray);
|
|
* @param {?} wordArray The word array.
|
|
*
|
|
* @return {?} The Base64 string.
|
|
*
|
|
*/
|
|
static stringify(wordArray) {
|
|
// Clamp excess bits
|
|
wordArray.clamp();
|
|
// Convert
|
|
const /** @type {?} */ base64Chars = [];
|
|
for (let /** @type {?} */ i = 0; i < wordArray.sigBytes; i += 3) {
|
|
const /** @type {?} */ byte1 = (wordArray.words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
|
|
const /** @type {?} */ byte2 = (wordArray.words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff;
|
|
const /** @type {?} */ byte3 = (wordArray.words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff;
|
|
const /** @type {?} */ triplet = (byte1 << 16) | (byte2 << 8) | byte3;
|
|
for (let /** @type {?} */ j = 0; (j < 4) && (i + j * 0.75 < wordArray.sigBytes); j++) {
|
|
base64Chars.push(this._map.charAt((triplet >>> (6 * (3 - j))) & 0x3f));
|
|
}
|
|
}
|
|
// Add padding
|
|
const /** @type {?} */ paddingChar = this._map.charAt(64);
|
|
if (paddingChar) {
|
|
while (base64Chars.length % 4) {
|
|
base64Chars.push(paddingChar);
|
|
}
|
|
}
|
|
return base64Chars.join('');
|
|
}
|
|
/**
|
|
* Converts a Base64 string to a word array.
|
|
*
|
|
* \@example
|
|
*
|
|
* let wordArray = Base64.parse(base64String);
|
|
* @param {?} base64Str The Base64 string.
|
|
*
|
|
* @return {?} The word array.
|
|
*
|
|
*/
|
|
static parse(base64Str) {
|
|
// Shortcuts
|
|
let /** @type {?} */ base64StrLength = base64Str.length;
|
|
if (this._reverseMap === undefined) {
|
|
this._reverseMap = [];
|
|
for (let /** @type {?} */ j = 0; j < this._map.length; j++) {
|
|
this._reverseMap[this._map.charCodeAt(j)] = j;
|
|
}
|
|
}
|
|
// Ignore padding
|
|
const /** @type {?} */ paddingChar = this._map.charAt(64);
|
|
if (paddingChar) {
|
|
const /** @type {?} */ paddingIndex = base64Str.indexOf(paddingChar);
|
|
if (paddingIndex !== -1) {
|
|
base64StrLength = paddingIndex;
|
|
}
|
|
}
|
|
// Convert
|
|
return this.parseLoop(base64Str, base64StrLength, this._reverseMap);
|
|
}
|
|
/**
|
|
* @param {?} base64Str
|
|
* @param {?} base64StrLength
|
|
* @param {?} reverseMap
|
|
* @return {?}
|
|
*/
|
|
static parseLoop(base64Str, base64StrLength, reverseMap) {
|
|
const /** @type {?} */ words = [];
|
|
let /** @type {?} */ nBytes = 0;
|
|
for (let /** @type {?} */ i = 0; i < base64StrLength; i++) {
|
|
if (i % 4) {
|
|
const /** @type {?} */ bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2);
|
|
const /** @type {?} */ bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2);
|
|
words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8);
|
|
nBytes++;
|
|
}
|
|
}
|
|
return new WordArray(words, nBytes);
|
|
}
|
|
}
|
|
Base64._map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
|
Base64._reverseMap = undefined;
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class OpenSSL {
|
|
/**
|
|
* Converts a cipher params object to an OpenSSL-compatible string.
|
|
*
|
|
* \@example
|
|
*
|
|
* let openSSLString = OpenSSLFormatter.stringify(cipherParams);
|
|
* @param {?} cipherParams The cipher params object.
|
|
*
|
|
* @return {?} The OpenSSL-compatible string.
|
|
*
|
|
*/
|
|
static stringify(cipherParams) {
|
|
if (!cipherParams.ciphertext) {
|
|
throw new Error('missing ciphertext in params');
|
|
}
|
|
// Shortcuts
|
|
const /** @type {?} */ ciphertext = cipherParams.ciphertext;
|
|
const /** @type {?} */ salt = cipherParams.salt;
|
|
// Format
|
|
let /** @type {?} */ wordArray;
|
|
if (salt) {
|
|
if (typeof salt === 'string') {
|
|
throw new Error('salt is expected to be a WordArray');
|
|
}
|
|
wordArray = (new WordArray([0x53616c74, 0x65645f5f])).concat(salt).concat(ciphertext);
|
|
}
|
|
else {
|
|
wordArray = ciphertext;
|
|
}
|
|
return wordArray.toString(Base64);
|
|
}
|
|
/**
|
|
* Converts an OpenSSL-compatible string to a cipher params object.
|
|
*
|
|
* \@example
|
|
*
|
|
* let cipherParams = OpenSSLFormatter.parse(openSSLString);
|
|
* @param {?} openSSLStr The OpenSSL-compatible string.
|
|
*
|
|
* @return {?} The cipher params object.
|
|
*
|
|
*/
|
|
static parse(openSSLStr) {
|
|
// Parse base64
|
|
const /** @type {?} */ ciphertext = Base64.parse(openSSLStr);
|
|
// Test for salt
|
|
let /** @type {?} */ salt;
|
|
if (ciphertext.words[0] === 0x53616c74 && ciphertext.words[1] === 0x65645f5f) {
|
|
// Extract salt
|
|
salt = new WordArray(ciphertext.words.slice(2, 4));
|
|
// Remove salt from ciphertext
|
|
ciphertext.words.splice(0, 4);
|
|
ciphertext.sigBytes -= 16;
|
|
}
|
|
return new CipherParams({ ciphertext: ciphertext, salt: salt });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class SerializableCipher {
|
|
/**
|
|
* Encrypts a message.
|
|
*
|
|
* \@example
|
|
*
|
|
* let ciphertextParams = SerializableCipher.encrypt(CryptoJS.algo.AES, message, key);
|
|
* let ciphertextParams = SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv });
|
|
* let ciphertextParams = SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, {
|
|
* iv: iv,
|
|
* format: CryptoJS.format.OpenSSL
|
|
* });
|
|
* @param {?} cipher The cipher algorithm to use.
|
|
* @param {?} message The message to encrypt.
|
|
* @param {?} key The key.
|
|
* @param {?=} cfg (Optional) The configuration options to use for this operation.
|
|
*
|
|
* @return {?} A cipher params object.
|
|
*
|
|
*/
|
|
static encrypt(cipher, message, key, cfg) {
|
|
// Apply config defaults
|
|
const /** @type {?} */ config = Object.assign({}, this.cfg, cfg);
|
|
// Encrypt
|
|
const /** @type {?} */ encryptor = cipher.createEncryptor(key, config);
|
|
const /** @type {?} */ ciphertext = encryptor.finalize(message);
|
|
// Create and return serializable cipher params
|
|
return new CipherParams({
|
|
ciphertext: ciphertext,
|
|
key: key,
|
|
iv: encryptor.cfg.iv,
|
|
algorithm: cipher,
|
|
mode: (/** @type {?} */ (encryptor.cfg)).mode,
|
|
padding: (/** @type {?} */ (encryptor.cfg)).padding,
|
|
blockSize: encryptor.cfg.blockSize,
|
|
formatter: config.format
|
|
});
|
|
}
|
|
/**
|
|
* Decrypts serialized ciphertext.
|
|
*
|
|
* \@example
|
|
*
|
|
* let plaintext = SerializableCipher.decrypt(
|
|
* AESAlgorithm,
|
|
* formattedCiphertext,
|
|
* key, {
|
|
* iv: iv,
|
|
* format: CryptoJS.format.OpenSSL
|
|
* }
|
|
* );
|
|
*
|
|
* let plaintext = SerializableCipher.decrypt(
|
|
* AESAlgorithm,
|
|
* ciphertextParams,
|
|
* key, {
|
|
* iv: iv,
|
|
* format: CryptoJS.format.OpenSSL
|
|
* }
|
|
* );
|
|
* @param {?} cipher The cipher algorithm to use.
|
|
* @param {?} ciphertext The ciphertext to decrypt.
|
|
* @param {?} key The key.
|
|
* @param {?=} optionalCfg
|
|
* @return {?} The plaintext.
|
|
*
|
|
*/
|
|
static decrypt(cipher, ciphertext, key, optionalCfg) {
|
|
// Apply config defaults
|
|
const /** @type {?} */ cfg = Object.assign({}, this.cfg, optionalCfg);
|
|
if (!cfg.format) {
|
|
throw new Error('could not determine format');
|
|
}
|
|
// Convert string to CipherParams
|
|
ciphertext = this._parse(ciphertext, cfg.format);
|
|
if (!ciphertext.ciphertext) {
|
|
throw new Error('could not determine ciphertext');
|
|
}
|
|
// Decrypt
|
|
const /** @type {?} */ plaintext = cipher.createDecryptor(key, cfg).finalize(ciphertext.ciphertext);
|
|
return plaintext;
|
|
}
|
|
/**
|
|
* Converts serialized ciphertext to CipherParams,
|
|
* else assumed CipherParams already and returns ciphertext unchanged.
|
|
*
|
|
* \@example
|
|
*
|
|
* var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format);
|
|
* @param {?} ciphertext The ciphertext.
|
|
* @param {?} format The formatting strategy to use to parse serialized ciphertext.
|
|
*
|
|
* @return {?} The unserialized ciphertext.
|
|
*
|
|
*/
|
|
static _parse(ciphertext, format) {
|
|
if (typeof ciphertext === 'string') {
|
|
return format.parse(ciphertext);
|
|
}
|
|
else {
|
|
return ciphertext;
|
|
}
|
|
}
|
|
}
|
|
SerializableCipher.cfg = {
|
|
blockSize: 4,
|
|
iv: new WordArray([]),
|
|
format: OpenSSL
|
|
};
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
/**
|
|
* @abstract
|
|
*/
|
|
class Hasher extends BufferedBlockAlgorithm {
|
|
/**
|
|
* Creates a shortcut function to a hasher's object interface.
|
|
*
|
|
* \@example
|
|
*
|
|
* let SHA256 = Hasher._createHelper(SHA256);
|
|
* @param {?} hasher The hasher to create a helper for.
|
|
*
|
|
* @return {?} The shortcut function.
|
|
*
|
|
*/
|
|
static _createHelper(hasher) {
|
|
/**
|
|
* @param {?} message
|
|
* @param {?=} cfg
|
|
* @return {?}
|
|
*/
|
|
function helper(message, cfg) {
|
|
const /** @type {?} */ hasherClass = hasher;
|
|
const /** @type {?} */ hasherInstance = new hasherClass(cfg);
|
|
return hasherInstance.finalize(message);
|
|
}
|
|
return helper;
|
|
}
|
|
/**
|
|
* Initializes a newly created hasher.
|
|
*
|
|
* \@example
|
|
*
|
|
* let hasher = CryptoJS.algo.SHA256.create();
|
|
* @param {?=} cfg (Optional) The configuration options to use for this hash computation.
|
|
*
|
|
*/
|
|
constructor(cfg) {
|
|
// Apply config defaults
|
|
super(Object.assign({
|
|
blockSize: 512 / 32
|
|
}, cfg));
|
|
// Set initial values
|
|
this.reset();
|
|
}
|
|
/**
|
|
* Updates this hasher with a message.
|
|
*
|
|
* \@example
|
|
*
|
|
* hasher.update('message');
|
|
* hasher.update(wordArray);
|
|
* @param {?} messageUpdate The message to append.
|
|
*
|
|
* @return {?} This hasher.
|
|
*
|
|
*/
|
|
update(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.
|
|
*
|
|
* \@example
|
|
*
|
|
* let hash = hasher.finalize();
|
|
* let hash = hasher.finalize('message');
|
|
* let hash = hasher.finalize(wordArray);
|
|
* @param {?} messageUpdate (Optional) A final message update.
|
|
*
|
|
* @return {?} The hash.
|
|
*
|
|
*/
|
|
finalize(messageUpdate) {
|
|
// Final message update
|
|
if (messageUpdate) {
|
|
this._append(messageUpdate);
|
|
}
|
|
// Perform concrete-hasher logic
|
|
const /** @type {?} */ hash = this._doFinalize();
|
|
return hash;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
// Constants table
|
|
const /** @type {?} */ T = [];
|
|
// Compute constants
|
|
for (let /** @type {?} */ i = 0; i < 64; i++) {
|
|
T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0;
|
|
}
|
|
class MD5 extends Hasher {
|
|
/**
|
|
* @param {?} a
|
|
* @param {?} b
|
|
* @param {?} c
|
|
* @param {?} d
|
|
* @param {?} x
|
|
* @param {?} s
|
|
* @param {?} t
|
|
* @return {?}
|
|
*/
|
|
static FF(a, b, c, d, x, s, t) {
|
|
const /** @type {?} */ n = a + ((b & c) | (~b & d)) + x + t;
|
|
return ((n << s) | (n >>> (32 - s))) + b;
|
|
}
|
|
/**
|
|
* @param {?} a
|
|
* @param {?} b
|
|
* @param {?} c
|
|
* @param {?} d
|
|
* @param {?} x
|
|
* @param {?} s
|
|
* @param {?} t
|
|
* @return {?}
|
|
*/
|
|
static GG(a, b, c, d, x, s, t) {
|
|
const /** @type {?} */ n = a + ((b & d) | (c & ~d)) + x + t;
|
|
return ((n << s) | (n >>> (32 - s))) + b;
|
|
}
|
|
/**
|
|
* @param {?} a
|
|
* @param {?} b
|
|
* @param {?} c
|
|
* @param {?} d
|
|
* @param {?} x
|
|
* @param {?} s
|
|
* @param {?} t
|
|
* @return {?}
|
|
*/
|
|
static HH(a, b, c, d, x, s, t) {
|
|
const /** @type {?} */ n = a + (b ^ c ^ d) + x + t;
|
|
return ((n << s) | (n >>> (32 - s))) + b;
|
|
}
|
|
/**
|
|
* @param {?} a
|
|
* @param {?} b
|
|
* @param {?} c
|
|
* @param {?} d
|
|
* @param {?} x
|
|
* @param {?} s
|
|
* @param {?} t
|
|
* @return {?}
|
|
*/
|
|
static II(a, b, c, d, x, s, t) {
|
|
const /** @type {?} */ n = a + (c ^ (b | ~d)) + x + t;
|
|
return ((n << s) | (n >>> (32 - s))) + b;
|
|
}
|
|
/**
|
|
* @return {?}
|
|
*/
|
|
reset() {
|
|
// reset core values
|
|
super.reset();
|
|
this._hash = new WordArray([
|
|
0x67452301, 0xefcdab89,
|
|
0x98badcfe, 0x10325476
|
|
]);
|
|
}
|
|
/**
|
|
* @param {?} M
|
|
* @param {?} offset
|
|
* @return {?}
|
|
*/
|
|
_doProcessBlock(M, offset) {
|
|
// Swap endian
|
|
for (let /** @type {?} */ i = 0; i < 16; i++) {
|
|
// Shortcuts
|
|
const /** @type {?} */ offset_i = offset + i;
|
|
const /** @type {?} */ M_offset_i = M[offset_i];
|
|
M[offset_i] = ((((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) |
|
|
(((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00));
|
|
}
|
|
// Shortcuts
|
|
const /** @type {?} */ H = this._hash.words;
|
|
const /** @type {?} */ M_offset_0 = M[offset + 0];
|
|
const /** @type {?} */ M_offset_1 = M[offset + 1];
|
|
const /** @type {?} */ M_offset_2 = M[offset + 2];
|
|
const /** @type {?} */ M_offset_3 = M[offset + 3];
|
|
const /** @type {?} */ M_offset_4 = M[offset + 4];
|
|
const /** @type {?} */ M_offset_5 = M[offset + 5];
|
|
const /** @type {?} */ M_offset_6 = M[offset + 6];
|
|
const /** @type {?} */ M_offset_7 = M[offset + 7];
|
|
const /** @type {?} */ M_offset_8 = M[offset + 8];
|
|
const /** @type {?} */ M_offset_9 = M[offset + 9];
|
|
const /** @type {?} */ M_offset_10 = M[offset + 10];
|
|
const /** @type {?} */ M_offset_11 = M[offset + 11];
|
|
const /** @type {?} */ M_offset_12 = M[offset + 12];
|
|
const /** @type {?} */ M_offset_13 = M[offset + 13];
|
|
const /** @type {?} */ M_offset_14 = M[offset + 14];
|
|
const /** @type {?} */ M_offset_15 = M[offset + 15];
|
|
// Working variables
|
|
let /** @type {?} */ a = H[0];
|
|
let /** @type {?} */ b = H[1];
|
|
let /** @type {?} */ c = H[2];
|
|
let /** @type {?} */ d = H[3];
|
|
// Computation
|
|
a = MD5.FF(a, b, c, d, M_offset_0, 7, T[0]);
|
|
d = MD5.FF(d, a, b, c, M_offset_1, 12, T[1]);
|
|
c = MD5.FF(c, d, a, b, M_offset_2, 17, T[2]);
|
|
b = MD5.FF(b, c, d, a, M_offset_3, 22, T[3]);
|
|
a = MD5.FF(a, b, c, d, M_offset_4, 7, T[4]);
|
|
d = MD5.FF(d, a, b, c, M_offset_5, 12, T[5]);
|
|
c = MD5.FF(c, d, a, b, M_offset_6, 17, T[6]);
|
|
b = MD5.FF(b, c, d, a, M_offset_7, 22, T[7]);
|
|
a = MD5.FF(a, b, c, d, M_offset_8, 7, T[8]);
|
|
d = MD5.FF(d, a, b, c, M_offset_9, 12, T[9]);
|
|
c = MD5.FF(c, d, a, b, M_offset_10, 17, T[10]);
|
|
b = MD5.FF(b, c, d, a, M_offset_11, 22, T[11]);
|
|
a = MD5.FF(a, b, c, d, M_offset_12, 7, T[12]);
|
|
d = MD5.FF(d, a, b, c, M_offset_13, 12, T[13]);
|
|
c = MD5.FF(c, d, a, b, M_offset_14, 17, T[14]);
|
|
b = MD5.FF(b, c, d, a, M_offset_15, 22, T[15]);
|
|
a = MD5.GG(a, b, c, d, M_offset_1, 5, T[16]);
|
|
d = MD5.GG(d, a, b, c, M_offset_6, 9, T[17]);
|
|
c = MD5.GG(c, d, a, b, M_offset_11, 14, T[18]);
|
|
b = MD5.GG(b, c, d, a, M_offset_0, 20, T[19]);
|
|
a = MD5.GG(a, b, c, d, M_offset_5, 5, T[20]);
|
|
d = MD5.GG(d, a, b, c, M_offset_10, 9, T[21]);
|
|
c = MD5.GG(c, d, a, b, M_offset_15, 14, T[22]);
|
|
b = MD5.GG(b, c, d, a, M_offset_4, 20, T[23]);
|
|
a = MD5.GG(a, b, c, d, M_offset_9, 5, T[24]);
|
|
d = MD5.GG(d, a, b, c, M_offset_14, 9, T[25]);
|
|
c = MD5.GG(c, d, a, b, M_offset_3, 14, T[26]);
|
|
b = MD5.GG(b, c, d, a, M_offset_8, 20, T[27]);
|
|
a = MD5.GG(a, b, c, d, M_offset_13, 5, T[28]);
|
|
d = MD5.GG(d, a, b, c, M_offset_2, 9, T[29]);
|
|
c = MD5.GG(c, d, a, b, M_offset_7, 14, T[30]);
|
|
b = MD5.GG(b, c, d, a, M_offset_12, 20, T[31]);
|
|
a = MD5.HH(a, b, c, d, M_offset_5, 4, T[32]);
|
|
d = MD5.HH(d, a, b, c, M_offset_8, 11, T[33]);
|
|
c = MD5.HH(c, d, a, b, M_offset_11, 16, T[34]);
|
|
b = MD5.HH(b, c, d, a, M_offset_14, 23, T[35]);
|
|
a = MD5.HH(a, b, c, d, M_offset_1, 4, T[36]);
|
|
d = MD5.HH(d, a, b, c, M_offset_4, 11, T[37]);
|
|
c = MD5.HH(c, d, a, b, M_offset_7, 16, T[38]);
|
|
b = MD5.HH(b, c, d, a, M_offset_10, 23, T[39]);
|
|
a = MD5.HH(a, b, c, d, M_offset_13, 4, T[40]);
|
|
d = MD5.HH(d, a, b, c, M_offset_0, 11, T[41]);
|
|
c = MD5.HH(c, d, a, b, M_offset_3, 16, T[42]);
|
|
b = MD5.HH(b, c, d, a, M_offset_6, 23, T[43]);
|
|
a = MD5.HH(a, b, c, d, M_offset_9, 4, T[44]);
|
|
d = MD5.HH(d, a, b, c, M_offset_12, 11, T[45]);
|
|
c = MD5.HH(c, d, a, b, M_offset_15, 16, T[46]);
|
|
b = MD5.HH(b, c, d, a, M_offset_2, 23, T[47]);
|
|
a = MD5.II(a, b, c, d, M_offset_0, 6, T[48]);
|
|
d = MD5.II(d, a, b, c, M_offset_7, 10, T[49]);
|
|
c = MD5.II(c, d, a, b, M_offset_14, 15, T[50]);
|
|
b = MD5.II(b, c, d, a, M_offset_5, 21, T[51]);
|
|
a = MD5.II(a, b, c, d, M_offset_12, 6, T[52]);
|
|
d = MD5.II(d, a, b, c, M_offset_3, 10, T[53]);
|
|
c = MD5.II(c, d, a, b, M_offset_10, 15, T[54]);
|
|
b = MD5.II(b, c, d, a, M_offset_1, 21, T[55]);
|
|
a = MD5.II(a, b, c, d, M_offset_8, 6, T[56]);
|
|
d = MD5.II(d, a, b, c, M_offset_15, 10, T[57]);
|
|
c = MD5.II(c, d, a, b, M_offset_6, 15, T[58]);
|
|
b = MD5.II(b, c, d, a, M_offset_13, 21, T[59]);
|
|
a = MD5.II(a, b, c, d, M_offset_4, 6, T[60]);
|
|
d = MD5.II(d, a, b, c, M_offset_11, 10, T[61]);
|
|
c = MD5.II(c, d, a, b, M_offset_2, 15, T[62]);
|
|
b = MD5.II(b, c, d, a, M_offset_9, 21, T[63]);
|
|
// 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;
|
|
}
|
|
/**
|
|
* @return {?}
|
|
*/
|
|
_doFinalize() {
|
|
// Shortcuts
|
|
const /** @type {?} */ data = this._data;
|
|
const /** @type {?} */ dataWords = data.words;
|
|
const /** @type {?} */ nBitsTotal = this._nDataBytes * 8;
|
|
const /** @type {?} */ nBitsLeft = data.sigBytes * 8;
|
|
// Add padding
|
|
dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
|
|
const /** @type {?} */ nBitsTotalH = Math.floor(nBitsTotal / 0x100000000);
|
|
const /** @type {?} */ nBitsTotalL = nBitsTotal;
|
|
dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = ((((nBitsTotalH << 8) | (nBitsTotalH >>> 24)) & 0x00ff00ff) |
|
|
(((nBitsTotalH << 24) | (nBitsTotalH >>> 8)) & 0xff00ff00));
|
|
dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = ((((nBitsTotalL << 8) | (nBitsTotalL >>> 24)) & 0x00ff00ff) |
|
|
(((nBitsTotalL << 24) | (nBitsTotalL >>> 8)) & 0xff00ff00));
|
|
data.sigBytes = (dataWords.length + 1) * 4;
|
|
// Hash final blocks
|
|
this._process();
|
|
// Shortcuts
|
|
const /** @type {?} */ hash = this._hash;
|
|
const /** @type {?} */ H = hash.words;
|
|
// Swap endian
|
|
for (let /** @type {?} */ i = 0; i < 4; i++) {
|
|
// Shortcut
|
|
const /** @type {?} */ H_i = H[i];
|
|
H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) |
|
|
(((H_i << 24) | (H_i >>> 8)) & 0xff00ff00);
|
|
}
|
|
// Return final computed hash
|
|
return hash;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class EvpKDF {
|
|
/**
|
|
* Initializes a newly created key derivation function.
|
|
*
|
|
* \@example
|
|
*
|
|
* let kdf = EvpKDF.create();
|
|
* let kdf = EvpKDF.create({ keySize: 8 });
|
|
* let kdf = EvpKDF.create({ keySize: 8, iterations: 1000 });
|
|
* @param {?=} cfg (Optional) The configuration options to use for the derivation.
|
|
*
|
|
*/
|
|
constructor(cfg) {
|
|
this.cfg = Object.assign({
|
|
keySize: 128 / 32,
|
|
hasher: MD5,
|
|
iterations: 1
|
|
}, cfg);
|
|
}
|
|
/**
|
|
* Derives a key from a password.
|
|
*
|
|
* \@example
|
|
*
|
|
* let key = kdf.compute(password, salt);
|
|
* @param {?} password The password.
|
|
* @param {?} salt A salt.
|
|
*
|
|
* @return {?} The derived key.
|
|
*
|
|
*/
|
|
compute(password, salt) {
|
|
// Init hasher
|
|
const /** @type {?} */ hasher = new (/** @type {?} */ (this.cfg.hasher))();
|
|
// Initial values
|
|
const /** @type {?} */ derivedKey = new WordArray();
|
|
// Generate key
|
|
let /** @type {?} */ block;
|
|
while (derivedKey.words.length < this.cfg.keySize) {
|
|
if (block) {
|
|
hasher.update(block);
|
|
}
|
|
block = hasher.update(password).finalize(salt);
|
|
hasher.reset();
|
|
// Iterations
|
|
for (let /** @type {?} */ i = 1; i < this.cfg.iterations; i++) {
|
|
block = hasher.finalize(block);
|
|
hasher.reset();
|
|
}
|
|
derivedKey.concat(block);
|
|
}
|
|
derivedKey.sigBytes = this.cfg.keySize * 4;
|
|
return derivedKey;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class OpenSSLKdf {
|
|
/**
|
|
* Derives a key and IV from a password.
|
|
*
|
|
* \@example
|
|
*
|
|
* let derivedParams = OpenSSL.execute('Password', 256/32, 128/32);
|
|
* let derivedParams = OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt');
|
|
* @param {?} password The password to derive from.
|
|
* @param {?} keySize The size in words of the key to generate.
|
|
* @param {?} ivSize The size in words of the IV to generate.
|
|
* @param {?=} salt (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly.
|
|
*
|
|
* @return {?} A cipher params object with the key, IV, and salt.
|
|
*
|
|
*/
|
|
static execute(password, keySize, ivSize, salt) {
|
|
// Generate random salt
|
|
if (!salt) {
|
|
salt = WordArray.random(64 / 8);
|
|
}
|
|
// Derive key and IV
|
|
const /** @type {?} */ key = (new EvpKDF({ keySize: keySize + ivSize })).compute(password, salt);
|
|
// Separate key and IV
|
|
const /** @type {?} */ iv = new WordArray(key.words.slice(keySize), ivSize * 4);
|
|
key.sigBytes = keySize * 4;
|
|
// Return params
|
|
return new CipherParams({ key: key, iv: iv, salt: salt });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class PasswordBasedCipher {
|
|
/**
|
|
* Encrypts a message using a password.
|
|
*
|
|
* \@example
|
|
*
|
|
* var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(AES, message, 'password');
|
|
* var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(AES, message, 'password', { format: OpenSSL });
|
|
* @param {?} cipher The cipher algorithm to use.
|
|
* @param {?} message The message to encrypt.
|
|
* @param {?} password The password.
|
|
* @param {?=} cfg (Optional) The configuration options to use for this operation.
|
|
*
|
|
* @return {?} A cipher params object.
|
|
*
|
|
*/
|
|
static encrypt(cipher, message, password, cfg) {
|
|
// Apply config defaults
|
|
const /** @type {?} */ config = Object.assign({}, this.cfg, cfg);
|
|
// Check if we have a kdf
|
|
if (config.kdf === undefined) {
|
|
throw new Error('missing kdf in config');
|
|
}
|
|
// Derive key and other params
|
|
const /** @type {?} */ derivedParams = config.kdf.execute(password, cipher.keySize, cipher.ivSize);
|
|
// Check if we have an IV
|
|
if (derivedParams.iv !== undefined) {
|
|
// Add IV to config
|
|
config.iv = derivedParams.iv;
|
|
}
|
|
// Encrypt
|
|
const /** @type {?} */ ciphertext = SerializableCipher.encrypt.call(this, cipher, message, derivedParams.key, config);
|
|
// Mix in derived params
|
|
return ciphertext.extend(derivedParams);
|
|
}
|
|
/**
|
|
* Decrypts serialized ciphertext using a password.
|
|
*
|
|
* \@example
|
|
*
|
|
* var plaintext = PasswordBasedCipher.decrypt(AES, formattedCiphertext, 'password', { format: OpenSSL });
|
|
* var plaintext = PasswordBasedCipher.decrypt(AES, ciphertextParams, 'password', { format: OpenSSL });
|
|
* @param {?} cipher The cipher algorithm to use.
|
|
* @param {?} ciphertext The ciphertext to decrypt.
|
|
* @param {?} password The password.
|
|
* @param {?=} cfg (Optional) The configuration options to use for this operation.
|
|
*
|
|
* @return {?} The plaintext.
|
|
*
|
|
*/
|
|
static decrypt(cipher, ciphertext, password, cfg) {
|
|
// Apply config defaults
|
|
const /** @type {?} */ config = Object.assign({}, this.cfg, cfg);
|
|
// Check if we have a kdf
|
|
if (config.format === undefined) {
|
|
throw new Error('missing format in config');
|
|
}
|
|
// Convert string to CipherParams
|
|
ciphertext = this._parse(ciphertext, config.format);
|
|
// Check if we have a kdf
|
|
if (config.kdf === undefined) {
|
|
throw new Error('the key derivation function must be set');
|
|
}
|
|
// Derive key and other params
|
|
const /** @type {?} */ derivedParams = config.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt);
|
|
// Check if we have an IV
|
|
if (derivedParams.iv !== undefined) {
|
|
// Add IV to config
|
|
config.iv = derivedParams.iv;
|
|
}
|
|
// Decrypt
|
|
const /** @type {?} */ plaintext = SerializableCipher.decrypt.call(this, cipher, ciphertext, derivedParams.key, config);
|
|
return plaintext;
|
|
}
|
|
/**
|
|
* Converts serialized ciphertext to CipherParams,
|
|
* else assumed CipherParams already and returns ciphertext unchanged.
|
|
*
|
|
* \@example
|
|
*
|
|
* var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format);
|
|
* @param {?} ciphertext The ciphertext.
|
|
* @param {?} format The formatting strategy to use to parse serialized ciphertext.
|
|
*
|
|
* @return {?} The unserialized ciphertext.
|
|
*
|
|
*/
|
|
static _parse(ciphertext, format) {
|
|
if (typeof ciphertext === 'string') {
|
|
return format.parse(ciphertext);
|
|
}
|
|
else {
|
|
return ciphertext;
|
|
}
|
|
}
|
|
}
|
|
PasswordBasedCipher.cfg = {
|
|
blockSize: 4,
|
|
iv: new WordArray([]),
|
|
format: OpenSSL,
|
|
kdf: OpenSSLKdf
|
|
};
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
/**
|
|
* @abstract
|
|
*/
|
|
class Cipher extends BufferedBlockAlgorithm {
|
|
/**
|
|
* Initializes a newly created cipher.
|
|
*
|
|
* \@example
|
|
*
|
|
* let cipher = AES.create(AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray });
|
|
* @param {?} xformMode Either the encryption or decryption transormation mode constant.
|
|
* @param {?} key The key.
|
|
* @param {?=} cfg (Optional) The configuration options to use for this operation.
|
|
*
|
|
*/
|
|
constructor(xformMode, key, cfg) {
|
|
// Apply config defaults
|
|
super(Object.assign({
|
|
blockSize: 1
|
|
}, cfg));
|
|
// Store transform mode and key
|
|
this._xformMode = xformMode;
|
|
this._key = key;
|
|
// Set initial values
|
|
this.reset();
|
|
}
|
|
/**
|
|
* Creates this cipher in encryption mode.
|
|
*
|
|
* \@example
|
|
*
|
|
* let cipher = AES.createEncryptor(keyWordArray, { iv: ivWordArray });
|
|
* @param {?} key The key.
|
|
* @param {?=} cfg (Optional) The configuration options to use for this operation.
|
|
*
|
|
* @return {?} A cipher instance.
|
|
*
|
|
*/
|
|
static createEncryptor(key, cfg) {
|
|
// workaround for typescript not being able to create a abstract creator function directly
|
|
const /** @type {?} */ thisClass = this;
|
|
return new thisClass(this._ENC_XFORM_MODE, key, cfg);
|
|
}
|
|
/**
|
|
* Creates this cipher in decryption mode.
|
|
*
|
|
* \@example
|
|
*
|
|
* let cipher = AES.createDecryptor(keyWordArray, { iv: ivWordArray });
|
|
* @param {?} key The key.
|
|
* @param {?=} cfg (Optional) The configuration options to use for this operation.
|
|
*
|
|
* @return {?} A cipher instance.
|
|
*
|
|
*/
|
|
static createDecryptor(key, cfg) {
|
|
// workaround for typescript not being able to create a abstract creator function directly
|
|
const /** @type {?} */ thisClass = this;
|
|
return new thisClass(this._DEC_XFORM_MODE, key, cfg);
|
|
}
|
|
/**
|
|
* Creates shortcut functions to a cipher's object interface.
|
|
*
|
|
* \@example
|
|
*
|
|
* let AES = Cipher._createHelper(AESAlgorithm);
|
|
* @param {?} cipher The cipher to create a helper for.
|
|
*
|
|
* @return {?} An object with encrypt and decrypt shortcut functions.
|
|
*
|
|
*/
|
|
static _createHelper(cipher) {
|
|
/**
|
|
* @param {?} message
|
|
* @param {?} key
|
|
* @param {?=} cfg
|
|
* @return {?}
|
|
*/
|
|
function encrypt(message, key, cfg) {
|
|
if (typeof key === 'string') {
|
|
return PasswordBasedCipher.encrypt(cipher, message, key, cfg);
|
|
}
|
|
else {
|
|
return SerializableCipher.encrypt(cipher, message, key, cfg);
|
|
}
|
|
}
|
|
/**
|
|
* @param {?} ciphertext
|
|
* @param {?} key
|
|
* @param {?=} cfg
|
|
* @return {?}
|
|
*/
|
|
function decrypt(ciphertext, key, cfg) {
|
|
if (typeof key === 'string') {
|
|
return PasswordBasedCipher.decrypt(cipher, ciphertext, key, cfg);
|
|
}
|
|
else {
|
|
return SerializableCipher.decrypt(cipher, ciphertext, key, cfg);
|
|
}
|
|
}
|
|
return {
|
|
encrypt: encrypt,
|
|
decrypt: decrypt
|
|
};
|
|
}
|
|
/**
|
|
* Adds data to be encrypted or decrypted.
|
|
*
|
|
* \@example
|
|
*
|
|
* let encrypted = cipher.process('data');
|
|
* let encrypted = cipher.process(wordArray);
|
|
* @param {?} dataUpdate The data to encrypt or decrypt.
|
|
*
|
|
* @return {?} The data after processing.
|
|
*
|
|
*/
|
|
process(dataUpdate) {
|
|
// Append
|
|
this._append(dataUpdate);
|
|
// Process available blocks
|
|
return this._process();
|
|
}
|
|
/**
|
|
* Finalizes the encryption or decryption process.
|
|
* Note that the finalize operation is effectively a destructive, read-once operation.
|
|
*
|
|
* \@example
|
|
*
|
|
* var encrypted = cipher.finalize();
|
|
* var encrypted = cipher.finalize('data');
|
|
* var encrypted = cipher.finalize(wordArray);
|
|
* @param {?=} dataUpdate The final data to encrypt or decrypt.
|
|
*
|
|
* @return {?} The data after final processing.
|
|
*
|
|
*/
|
|
finalize(dataUpdate) {
|
|
// Final data update
|
|
if (dataUpdate) {
|
|
this._append(dataUpdate);
|
|
}
|
|
// Perform concrete-cipher logic
|
|
const /** @type {?} */ finalProcessedData = this._doFinalize();
|
|
return finalProcessedData;
|
|
}
|
|
}
|
|
/**
|
|
* A constant representing encryption mode.
|
|
*/
|
|
Cipher._ENC_XFORM_MODE = 1;
|
|
/**
|
|
* A constant representing decryption mode.
|
|
*/
|
|
Cipher._DEC_XFORM_MODE = 2;
|
|
/**
|
|
* This cipher's key size. Default: 4 (128 bits / 32 Bits)
|
|
*/
|
|
Cipher.keySize = 4;
|
|
/**
|
|
* This cipher's IV size. Default: 4 (128 bits / 32 Bits)
|
|
*/
|
|
Cipher.ivSize = 4;
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
/**
|
|
* @abstract
|
|
*/
|
|
class BlockCipherModeAlgorithm {
|
|
/**
|
|
* @param {?} cipher
|
|
* @param {?} iv
|
|
*/
|
|
constructor(cipher, iv) {
|
|
this.init(cipher, iv);
|
|
}
|
|
/**
|
|
* Initializes a newly created mode.
|
|
*
|
|
* \@example
|
|
*
|
|
* var mode = CBC.Encryptor.create(cipher, iv.words);
|
|
* @param {?} cipher A block cipher instance.
|
|
* @param {?=} iv The IV words.
|
|
*
|
|
* @return {?}
|
|
*/
|
|
init(cipher, iv) {
|
|
this._cipher = cipher;
|
|
this._iv = iv;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
/**
|
|
* @abstract
|
|
*/
|
|
class BlockCipherMode {
|
|
/**
|
|
* Creates this mode for encryption.
|
|
*
|
|
* \@example
|
|
*
|
|
* var mode = CBC.createEncryptor(cipher, iv.words);
|
|
* @param {?} cipher A block cipher instance.
|
|
* @param {?} iv The IV words.
|
|
*
|
|
* @return {?}
|
|
*/
|
|
static createEncryptor(cipher, iv) {
|
|
// workaround for typescript not being able to create a abstract creator function directly
|
|
const /** @type {?} */ encryptorClass = this.Encryptor;
|
|
return new encryptorClass(cipher, iv);
|
|
}
|
|
/**
|
|
* Creates this mode for decryption.
|
|
*
|
|
* \@example
|
|
*
|
|
* var mode = CBC.createDecryptor(cipher, iv.words);
|
|
* @param {?} cipher A block cipher instance.
|
|
* @param {?} iv The IV words.
|
|
*
|
|
* @return {?}
|
|
*/
|
|
static createDecryptor(cipher, iv) {
|
|
// workaround for typescript not being able to create a abstract creator function directly
|
|
const /** @type {?} */ decryptorClass = this.Decryptor;
|
|
return new decryptorClass(cipher, iv);
|
|
}
|
|
}
|
|
BlockCipherMode.Encryptor = BlockCipherModeAlgorithm;
|
|
BlockCipherMode.Decryptor = BlockCipherModeAlgorithm;
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class CBCEncryptor extends BlockCipherModeAlgorithm {
|
|
/**
|
|
* Processes the data block at offset.
|
|
*
|
|
* \@example
|
|
*
|
|
* mode.processBlock(data.words, offset);
|
|
* @param {?} words The data words to operate on.
|
|
* @param {?} offset The offset where the block starts.
|
|
*
|
|
* @return {?}
|
|
*/
|
|
processBlock(words, offset) {
|
|
// Check if we have a blockSize
|
|
if (this._cipher.cfg.blockSize === undefined) {
|
|
throw new Error('missing blockSize in cipher config');
|
|
}
|
|
// XOR and encrypt
|
|
this.xorBlock(words, offset, this._cipher.cfg.blockSize);
|
|
this._cipher.encryptBlock(words, offset);
|
|
// Remember this block to use with next block
|
|
this._prevBlock = words.slice(offset, offset + this._cipher.cfg.blockSize);
|
|
}
|
|
/**
|
|
* @param {?} words
|
|
* @param {?} offset
|
|
* @param {?} blockSize
|
|
* @return {?}
|
|
*/
|
|
xorBlock(words, offset, blockSize) {
|
|
// Choose mixing block
|
|
let /** @type {?} */ block;
|
|
if (this._iv) {
|
|
block = this._iv;
|
|
// Remove IV for subsequent blocks
|
|
this._iv = undefined;
|
|
}
|
|
else {
|
|
block = this._prevBlock;
|
|
}
|
|
// block should never be undefined but we want to make typescript happy
|
|
if (block !== undefined) {
|
|
// XOR blocks
|
|
for (let /** @type {?} */ i = 0; i < blockSize; i++) {
|
|
words[offset + i] ^= block[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class CBCDecryptor extends BlockCipherModeAlgorithm {
|
|
/**
|
|
* Processes the data block at offset.
|
|
*
|
|
* \@example
|
|
*
|
|
* mode.processBlock(data.words, offset);
|
|
* @param {?} words The data words to operate on.
|
|
* @param {?} offset The offset where the block starts.
|
|
*
|
|
* @return {?}
|
|
*/
|
|
processBlock(words, offset) {
|
|
// Check if we have a blockSize
|
|
if (this._cipher.cfg.blockSize === undefined) {
|
|
throw new Error('missing blockSize in cipher config');
|
|
}
|
|
// Remember this block to use with next block
|
|
const /** @type {?} */ thisBlock = words.slice(offset, offset + this._cipher.cfg.blockSize);
|
|
// Decrypt and XOR
|
|
this._cipher.decryptBlock(words, offset);
|
|
this.xorBlock(words, offset, this._cipher.cfg.blockSize);
|
|
// This block becomes the previous block
|
|
this._prevBlock = thisBlock;
|
|
}
|
|
/**
|
|
* @param {?} words
|
|
* @param {?} offset
|
|
* @param {?} blockSize
|
|
* @return {?}
|
|
*/
|
|
xorBlock(words, offset, blockSize) {
|
|
// Choose mixing block
|
|
let /** @type {?} */ block;
|
|
if (this._iv) {
|
|
block = this._iv;
|
|
// Remove IV for subsequent blocks
|
|
this._iv = undefined;
|
|
}
|
|
else {
|
|
block = this._prevBlock;
|
|
}
|
|
// block should never be undefined but we want to make typescript happy
|
|
if (block !== undefined) {
|
|
// XOR blocks
|
|
for (let /** @type {?} */ i = 0; i < blockSize; i++) {
|
|
words[offset + i] ^= block[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
/**
|
|
* Cipher Block Chaining mode.
|
|
* @abstract
|
|
*/
|
|
class CBC extends BlockCipherMode {
|
|
}
|
|
CBC.Encryptor = CBCEncryptor;
|
|
CBC.Decryptor = CBCDecryptor;
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class PKCS7 {
|
|
/**
|
|
* Pads data using the algorithm defined in PKCS #5/7.
|
|
*
|
|
* \@example
|
|
*
|
|
* PKCS7.pad(wordArray, 4);
|
|
* @param {?} data The data to pad.
|
|
* @param {?} blockSize The multiple that the data should be padded to.
|
|
*
|
|
* @return {?}
|
|
*/
|
|
static pad(data, blockSize) {
|
|
// Shortcut
|
|
const /** @type {?} */ blockSizeBytes = blockSize * 4;
|
|
// Count padding bytes
|
|
const /** @type {?} */ nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes;
|
|
// Create padding word
|
|
const /** @type {?} */ paddingWord = (nPaddingBytes << 24) | (nPaddingBytes << 16) | (nPaddingBytes << 8) | nPaddingBytes;
|
|
// Create padding
|
|
const /** @type {?} */ paddingWords = [];
|
|
for (let /** @type {?} */ i = 0; i < nPaddingBytes; i += 4) {
|
|
paddingWords.push(paddingWord);
|
|
}
|
|
const /** @type {?} */ padding = new WordArray(paddingWords, nPaddingBytes);
|
|
// Add padding
|
|
data.concat(padding);
|
|
}
|
|
/**
|
|
* Unpads data that had been padded using the algorithm defined in PKCS #5/7.
|
|
*
|
|
* \@example
|
|
*
|
|
* PKCS7.unpad(wordArray);
|
|
* @param {?} data The data to unpad.
|
|
*
|
|
* @return {?}
|
|
*/
|
|
static unpad(data) {
|
|
// Get number of padding bytes from last byte
|
|
const /** @type {?} */ nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff;
|
|
// Remove padding
|
|
data.sigBytes -= nPaddingBytes;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class ZeroPadding {
|
|
|
|
static pad(data, blockSize) {
|
|
// Shortcut
|
|
const /** @type {?} */ blockSizeBytes = blockSize * 4;
|
|
// Count padding bytes
|
|
const /** @type {?} */ nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes;
|
|
// Create padding
|
|
const /** @type {?} */ paddingWords = [];
|
|
for (let /** @type {?} */ i = 0; i < nPaddingBytes; i += 4) {
|
|
paddingWords.push(0);
|
|
}
|
|
const /** @type {?} */ padding = new WordArray(paddingWords, nPaddingBytes);
|
|
// Add padding
|
|
data.concat(padding);
|
|
}
|
|
|
|
|
|
static unpad(data) {
|
|
|
|
// console.log("unpad 1:", data.clone());
|
|
for (let i = data.words.length - 1; i>=0; i--) {
|
|
if(data.words[i] != 0){
|
|
data.slice(0, i+1);
|
|
// console.log("unpad 2:", data);
|
|
return
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
/**
|
|
* @abstract
|
|
*/
|
|
class BlockCipher extends Cipher {
|
|
/**
|
|
* @param {?} xformMode
|
|
* @param {?} key
|
|
* @param {?=} cfg
|
|
*/
|
|
constructor(xformMode, key, cfg) {
|
|
super(xformMode, key, Object.assign({
|
|
// default: 128 / 32
|
|
blockSize: 4,
|
|
mode: CBC,
|
|
padding: PKCS7
|
|
}, cfg));
|
|
}
|
|
/**
|
|
* @return {?}
|
|
*/
|
|
reset() {
|
|
// Reset cipher
|
|
super.reset();
|
|
// Check if we have a blockSize
|
|
if (this.cfg.mode === undefined) {
|
|
throw new Error('missing mode in config');
|
|
}
|
|
// Reset block mode
|
|
let /** @type {?} */ modeCreator;
|
|
if (this._xformMode === (/** @type {?} */ (this.constructor))._ENC_XFORM_MODE) {
|
|
modeCreator = this.cfg.mode.createEncryptor;
|
|
}
|
|
else /* if (this._xformMode == this._DEC_XFORM_MODE) */ {
|
|
modeCreator = this.cfg.mode.createDecryptor;
|
|
// Keep at least one block in the buffer for unpadding
|
|
this._minBufferSize = 1;
|
|
}
|
|
if (this._mode && this._mode.__creator === modeCreator) {
|
|
this._mode.init(this, this.cfg.iv && this.cfg.iv.words);
|
|
}
|
|
else {
|
|
this._mode = modeCreator.call(this.cfg.mode, this, this.cfg.iv && this.cfg.iv.words);
|
|
this._mode.__creator = modeCreator;
|
|
}
|
|
}
|
|
/**
|
|
* @param {?} words
|
|
* @param {?} offset
|
|
* @return {?}
|
|
*/
|
|
_doProcessBlock(words, offset) {
|
|
this._mode.processBlock(words, offset);
|
|
}
|
|
/**
|
|
* @return {?}
|
|
*/
|
|
_doFinalize() {
|
|
// Check if we have a padding strategy
|
|
if (this.cfg.padding === undefined) {
|
|
throw new Error('missing padding in config');
|
|
}
|
|
// Finalize
|
|
let /** @type {?} */ finalProcessedBlocks;
|
|
if (this._xformMode === (/** @type {?} */ (this.constructor))._ENC_XFORM_MODE) {
|
|
// Check if we have a blockSize
|
|
if (this.cfg.blockSize === undefined) {
|
|
throw new Error('missing blockSize in config');
|
|
}
|
|
// Pad data
|
|
this.cfg.padding.pad(this._data, this.cfg.blockSize);
|
|
// Process final blocks
|
|
finalProcessedBlocks = this._process(!!'flush');
|
|
}
|
|
else /* if (this._xformMode == this._DEC_XFORM_MODE) */ {
|
|
// Process final blocks
|
|
finalProcessedBlocks = this._process(!!'flush');
|
|
// Unpad data
|
|
this.cfg.padding.unpad(finalProcessedBlocks);
|
|
}
|
|
return finalProcessedBlocks;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
// Define lookup tables
|
|
const /** @type {?} */ SBOX = [];
|
|
const /** @type {?} */ INV_SBOX = [];
|
|
const /** @type {?} */ SUB_MIX_0 = [];
|
|
const /** @type {?} */ SUB_MIX_1 = [];
|
|
const /** @type {?} */ SUB_MIX_2 = [];
|
|
const /** @type {?} */ SUB_MIX_3 = [];
|
|
const /** @type {?} */ INV_SUB_MIX_0 = [];
|
|
const /** @type {?} */ INV_SUB_MIX_1 = [];
|
|
const /** @type {?} */ INV_SUB_MIX_2 = [];
|
|
const /** @type {?} */ INV_SUB_MIX_3 = [];
|
|
// Compute lookup tables
|
|
(function () {
|
|
// Compute double table
|
|
const /** @type {?} */ d = [];
|
|
for (let /** @type {?} */ i = 0; i < 256; i++) {
|
|
if (i < 128) {
|
|
d[i] = i << 1;
|
|
}
|
|
else {
|
|
d[i] = (i << 1) ^ 0x11b;
|
|
}
|
|
}
|
|
// Walk GF(2^8)
|
|
let /** @type {?} */ x = 0;
|
|
let /** @type {?} */ xi = 0;
|
|
for (let /** @type {?} */ i = 0; i < 256; i++) {
|
|
// Compute sbox
|
|
let /** @type {?} */ sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4);
|
|
sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63;
|
|
SBOX[x] = sx;
|
|
INV_SBOX[sx] = x;
|
|
// Compute multiplication
|
|
const /** @type {?} */ x2 = d[x];
|
|
const /** @type {?} */ x4 = d[x2];
|
|
const /** @type {?} */ x8 = d[x4];
|
|
// Compute sub bytes, mix columns tables
|
|
let /** @type {?} */ t = (d[sx] * 0x101) ^ (sx * 0x1010100);
|
|
SUB_MIX_0[x] = (t << 24) | (t >>> 8);
|
|
SUB_MIX_1[x] = (t << 16) | (t >>> 16);
|
|
SUB_MIX_2[x] = (t << 8) | (t >>> 24);
|
|
SUB_MIX_3[x] = t;
|
|
// Compute inv sub bytes, inv mix columns tables
|
|
t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100);
|
|
INV_SUB_MIX_0[sx] = (t << 24) | (t >>> 8);
|
|
INV_SUB_MIX_1[sx] = (t << 16) | (t >>> 16);
|
|
INV_SUB_MIX_2[sx] = (t << 8) | (t >>> 24);
|
|
INV_SUB_MIX_3[sx] = t;
|
|
// Compute next counter
|
|
if (!x) {
|
|
x = xi = 1;
|
|
}
|
|
else {
|
|
x = x2 ^ d[d[d[x8 ^ x2]]];
|
|
xi ^= d[d[xi]];
|
|
}
|
|
}
|
|
}());
|
|
// Precomputed Rcon lookup
|
|
const /** @type {?} */ RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
|
|
class AES extends BlockCipher {
|
|
/**
|
|
* @param {?} xformMode
|
|
* @param {?} key
|
|
* @param {?=} cfg
|
|
*/
|
|
constructor(xformMode, key, cfg) {
|
|
super(xformMode, key, cfg);
|
|
}
|
|
/**
|
|
* @return {?}
|
|
*/
|
|
reset() {
|
|
// reset core values
|
|
super.reset();
|
|
// Skip reset of nRounds has been set before and key did not change
|
|
if (this._nRounds && this._keyPriorReset === this._key) {
|
|
return;
|
|
}
|
|
// Shortcuts
|
|
const /** @type {?} */ key = this._keyPriorReset = this._key;
|
|
const /** @type {?} */ keyWords = key.words;
|
|
const /** @type {?} */ keySize = key.sigBytes / 4;
|
|
// Compute number of rounds
|
|
const /** @type {?} */ nRounds = this._nRounds = keySize + 6;
|
|
// Compute number of key schedule rows
|
|
const /** @type {?} */ ksRows = (nRounds + 1) * 4;
|
|
// Compute key schedule
|
|
const /** @type {?} */ keySchedule = this._keySchedule = [];
|
|
for (let /** @type {?} */ ksRow = 0; ksRow < ksRows; ksRow++) {
|
|
if (ksRow < keySize) {
|
|
keySchedule[ksRow] = keyWords[ksRow];
|
|
}
|
|
else {
|
|
let /** @type {?} */ t = keySchedule[ksRow - 1];
|
|
if (!(ksRow % keySize)) {
|
|
// Rot word
|
|
t = (t << 8) | (t >>> 24);
|
|
// Sub word
|
|
t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff];
|
|
// Mix Rcon
|
|
t ^= RCON[(ksRow / keySize) | 0] << 24;
|
|
}
|
|
else if (keySize > 6 && ksRow % keySize === 4) {
|
|
// Sub word
|
|
t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff];
|
|
}
|
|
keySchedule[ksRow] = keySchedule[ksRow - keySize] ^ t;
|
|
}
|
|
}
|
|
// Compute inv key schedule
|
|
const /** @type {?} */ invKeySchedule = this._invKeySchedule = [];
|
|
for (let /** @type {?} */ invKsRow = 0; invKsRow < ksRows; invKsRow++) {
|
|
const /** @type {?} */ ksRow = ksRows - invKsRow;
|
|
let /** @type {?} */ t;
|
|
if (invKsRow % 4) {
|
|
t = keySchedule[ksRow];
|
|
}
|
|
else {
|
|
t = keySchedule[ksRow - 4];
|
|
}
|
|
if (invKsRow < 4 || ksRow <= 4) {
|
|
invKeySchedule[invKsRow] = t;
|
|
}
|
|
else {
|
|
invKeySchedule[invKsRow] = INV_SUB_MIX_0[SBOX[t >>> 24]] ^ INV_SUB_MIX_1[SBOX[(t >>> 16) & 0xff]] ^
|
|
INV_SUB_MIX_2[SBOX[(t >>> 8) & 0xff]] ^ INV_SUB_MIX_3[SBOX[t & 0xff]];
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* @param {?} M
|
|
* @param {?} offset
|
|
* @return {?}
|
|
*/
|
|
encryptBlock(M, offset) {
|
|
this._doCryptBlock(M, offset, this._keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX);
|
|
}
|
|
/**
|
|
* @param {?} M
|
|
* @param {?} offset
|
|
* @return {?}
|
|
*/
|
|
decryptBlock(M, offset) {
|
|
// Swap 2nd and 4th rows
|
|
let /** @type {?} */ t = M[offset + 1];
|
|
M[offset + 1] = M[offset + 3];
|
|
M[offset + 3] = t;
|
|
this._doCryptBlock(M, offset, this._invKeySchedule, INV_SUB_MIX_0, INV_SUB_MIX_1, INV_SUB_MIX_2, INV_SUB_MIX_3, INV_SBOX);
|
|
// Inv swap 2nd and 4th rows
|
|
t = M[offset + 1];
|
|
M[offset + 1] = M[offset + 3];
|
|
M[offset + 3] = t;
|
|
}
|
|
/**
|
|
* @param {?} M
|
|
* @param {?} offset
|
|
* @param {?} keySchedule
|
|
* @param {?} sub_mix_0
|
|
* @param {?} sub_mix_1
|
|
* @param {?} sub_mix_2
|
|
* @param {?} sub_mix_3
|
|
* @param {?} sbox
|
|
* @return {?}
|
|
*/
|
|
_doCryptBlock(M, offset, keySchedule, sub_mix_0, sub_mix_1, sub_mix_2, sub_mix_3, sbox) {
|
|
// Get input, add round key
|
|
let /** @type {?} */ s0 = M[offset] ^ keySchedule[0];
|
|
let /** @type {?} */ s1 = M[offset + 1] ^ keySchedule[1];
|
|
let /** @type {?} */ s2 = M[offset + 2] ^ keySchedule[2];
|
|
let /** @type {?} */ s3 = M[offset + 3] ^ keySchedule[3];
|
|
// Key schedule row counter
|
|
let /** @type {?} */ ksRow = 4;
|
|
// Rounds
|
|
for (let /** @type {?} */ round = 1; round < this._nRounds; round++) {
|
|
// Shift rows, sub bytes, mix columns, add round key
|
|
const /** @type {?} */ t0 = sub_mix_0[s0 >>> 24] ^ sub_mix_1[(s1 >>> 16) & 0xff] ^ sub_mix_2[(s2 >>> 8) & 0xff] ^ sub_mix_3[s3 & 0xff] ^
|
|
keySchedule[ksRow++];
|
|
const /** @type {?} */ t1 = sub_mix_0[s1 >>> 24] ^ sub_mix_1[(s2 >>> 16) & 0xff] ^ sub_mix_2[(s3 >>> 8) & 0xff] ^ sub_mix_3[s0 & 0xff] ^
|
|
keySchedule[ksRow++];
|
|
const /** @type {?} */ t2 = sub_mix_0[s2 >>> 24] ^ sub_mix_1[(s3 >>> 16) & 0xff] ^ sub_mix_2[(s0 >>> 8) & 0xff] ^ sub_mix_3[s1 & 0xff] ^
|
|
keySchedule[ksRow++];
|
|
const /** @type {?} */ t3 = sub_mix_0[s3 >>> 24] ^ sub_mix_1[(s0 >>> 16) & 0xff] ^ sub_mix_2[(s1 >>> 8) & 0xff] ^ sub_mix_3[s2 & 0xff] ^
|
|
keySchedule[ksRow++];
|
|
// Update state
|
|
s0 = t0;
|
|
s1 = t1;
|
|
s2 = t2;
|
|
s3 = t3;
|
|
}
|
|
// Shift rows, sub bytes, add round key
|
|
const /** @type {?} */ t0g = ((sbox[s0 >>> 24] << 24) | (sbox[(s1 >>> 16) & 0xff] << 16) | (sbox[(s2 >>> 8) & 0xff] << 8) | sbox[s3 & 0xff]) ^
|
|
keySchedule[ksRow++];
|
|
const /** @type {?} */ t1g = ((sbox[s1 >>> 24] << 24) | (sbox[(s2 >>> 16) & 0xff] << 16) | (sbox[(s3 >>> 8) & 0xff] << 8) | sbox[s0 & 0xff]) ^
|
|
keySchedule[ksRow++];
|
|
const /** @type {?} */ t2g = ((sbox[s2 >>> 24] << 24) | (sbox[(s3 >>> 16) & 0xff] << 16) | (sbox[(s0 >>> 8) & 0xff] << 8) | sbox[s1 & 0xff]) ^
|
|
keySchedule[ksRow++];
|
|
const /** @type {?} */ t3g = ((sbox[s3 >>> 24] << 24) | (sbox[(s0 >>> 16) & 0xff] << 16) | (sbox[(s1 >>> 8) & 0xff] << 8) | sbox[s2 & 0xff]) ^
|
|
keySchedule[ksRow++];
|
|
// Set output
|
|
M[offset] = t0g;
|
|
M[offset + 1] = t1g;
|
|
M[offset + 2] = t2g;
|
|
M[offset + 3] = t3g;
|
|
}
|
|
}
|
|
AES.keySize = 8;
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
// Initialization and round constants tables
|
|
const /** @type {?} */ H = [];
|
|
const /** @type {?} */ K = [];
|
|
// Reusable object
|
|
const /** @type {?} */ W = [];
|
|
class SHA256 extends Hasher {
|
|
/**
|
|
* @return {?}
|
|
*/
|
|
reset() {
|
|
// reset core values
|
|
super.reset();
|
|
this._hash = new WordArray(H.slice(0));
|
|
}
|
|
/**
|
|
* @param {?} M
|
|
* @param {?} offset
|
|
* @return {?}
|
|
*/
|
|
_doProcessBlock(M, offset) {
|
|
// Shortcut
|
|
const /** @type {?} */ Hl = this._hash.words;
|
|
// Working variables
|
|
let /** @type {?} */ a = Hl[0];
|
|
let /** @type {?} */ b = Hl[1];
|
|
let /** @type {?} */ c = Hl[2];
|
|
let /** @type {?} */ d = Hl[3];
|
|
let /** @type {?} */ e = Hl[4];
|
|
let /** @type {?} */ f = Hl[5];
|
|
let /** @type {?} */ g = Hl[6];
|
|
let /** @type {?} */ h = Hl[7];
|
|
// Computation
|
|
for (let /** @type {?} */ i = 0; i < 64; i++) {
|
|
if (i < 16) {
|
|
W[i] = M[offset + i] | 0;
|
|
}
|
|
else {
|
|
const /** @type {?} */ gamma0x = W[i - 15];
|
|
const /** @type {?} */ gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^
|
|
((gamma0x << 14) | (gamma0x >>> 18)) ^
|
|
(gamma0x >>> 3);
|
|
const /** @type {?} */ gamma1x = W[i - 2];
|
|
const /** @type {?} */ gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^
|
|
((gamma1x << 13) | (gamma1x >>> 19)) ^
|
|
(gamma1x >>> 10);
|
|
W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16];
|
|
}
|
|
const /** @type {?} */ ch = (e & f) ^ (~e & g);
|
|
const /** @type {?} */ maj = (a & b) ^ (a & c) ^ (b & c);
|
|
const /** @type {?} */ sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22));
|
|
const /** @type {?} */ sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25));
|
|
const /** @type {?} */ t1 = h + sigma1 + ch + K[i] + W[i];
|
|
const /** @type {?} */ 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
|
|
Hl[0] = (Hl[0] + a) | 0;
|
|
Hl[1] = (Hl[1] + b) | 0;
|
|
Hl[2] = (Hl[2] + c) | 0;
|
|
Hl[3] = (Hl[3] + d) | 0;
|
|
Hl[4] = (Hl[4] + e) | 0;
|
|
Hl[5] = (Hl[5] + f) | 0;
|
|
Hl[6] = (Hl[6] + g) | 0;
|
|
Hl[7] = (Hl[7] + h) | 0;
|
|
}
|
|
/**
|
|
* @return {?}
|
|
*/
|
|
_doFinalize() {
|
|
const /** @type {?} */ nBitsTotal = this._nDataBytes * 8;
|
|
const /** @type {?} */ nBitsLeft = this._data.sigBytes * 8;
|
|
// Add padding
|
|
this._data.words[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
|
|
this._data.words[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);
|
|
this._data.words[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;
|
|
this._data.sigBytes = this._data.words.length * 4;
|
|
// Hash final blocks
|
|
this._process();
|
|
// Return final computed hash
|
|
return this._hash;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class NoPadding {
|
|
/**
|
|
* Doesn't pad the data provided.
|
|
*
|
|
* \@example
|
|
*
|
|
* NoPadding.pad(wordArray, 4);
|
|
* @param {?} data The data to pad.
|
|
* @param {?} blockSize The multiple that the data should be padded to.
|
|
*
|
|
* @return {?}
|
|
*/
|
|
static pad(data, blockSize) {
|
|
}
|
|
/**
|
|
* Doesn't unpad the data provided.
|
|
*
|
|
* \@example
|
|
*
|
|
* NoPadding.unpad(wordArray);
|
|
* @param {?} data The data to unpad.
|
|
*
|
|
* @return {?}
|
|
*/
|
|
static unpad(data) {
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class ECBEncryptor extends BlockCipherModeAlgorithm {
|
|
/**
|
|
* Processes the data block at offset.
|
|
*
|
|
* \@example
|
|
*
|
|
* mode.processBlock(data.words, offset);
|
|
* @param {?} words The data words to operate on.
|
|
* @param {?} offset The offset where the block starts.
|
|
*
|
|
* @return {?}
|
|
*/
|
|
processBlock(words, offset) {
|
|
this._cipher.encryptBlock(words, offset);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
class ECBDecryptor extends BlockCipherModeAlgorithm {
|
|
/**
|
|
* Processes the data block at offset.
|
|
*
|
|
* \@example
|
|
*
|
|
* mode.processBlock(data.words, offset);
|
|
* @param {?} words The data words to operate on.
|
|
* @param {?} offset The offset where the block starts.
|
|
*
|
|
* @return {?}
|
|
*/
|
|
processBlock(words, offset) {
|
|
this._cipher.decryptBlock(words, offset);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
/**
|
|
* Cipher Block Chaining mode.
|
|
* @abstract
|
|
*/
|
|
class ECB extends BlockCipherMode {
|
|
}
|
|
ECB.Encryptor = ECBEncryptor;
|
|
ECB.Decryptor = ECBDecryptor;
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
const /** @type {?} */ lib = {
|
|
BlockCipher: BlockCipher,
|
|
WordArray: WordArray,
|
|
CipherParams: CipherParams,
|
|
Hasher: Hasher,
|
|
SerializableCipher: SerializableCipher,
|
|
PasswordBasedCipher: PasswordBasedCipher
|
|
};
|
|
const /** @type {?} */ algo = {
|
|
AES: AES,
|
|
SHA256: SHA256
|
|
};
|
|
const /** @type {?} */ enc = {
|
|
Utf8: Utf8,
|
|
Hex: Hex
|
|
};
|
|
const /** @type {?} */ pad = {
|
|
NoPadding: NoPadding,
|
|
PKCS7: PKCS7,
|
|
ZeroPadding: ZeroPadding,
|
|
};
|
|
const /** @type {?} */ mode = {
|
|
CBC: CBC,
|
|
ECB: ECB
|
|
};
|
|
// HELPERS /////////////////////////////////////////////////////////////////////////////////////////
|
|
const /** @type {?} */ AES$1 = lib.BlockCipher._createHelper(algo.AES);
|
|
const /** @type {?} */ SHA256$1 = lib.Hasher._createHelper(algo.SHA256);
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
|
|
/**
|
|
* @fileoverview added by tsickle
|
|
* @suppress {checkTypes} checked by tsc
|
|
*/
|
|
|
|
export {Base64, lib, algo, enc, pad, mode, AES$1 as AES, SHA256$1 as SHA256, AES as ɵl, SHA256 as ɵm, Hex as ɵp, Latin1 as ɵo, Utf8 as ɵn, Base as ɵg, BlockCipher as ɵa, BufferedBlockAlgorithm as ɵc, Cipher as ɵb, CipherParams as ɵf, Hasher as ɵi, PasswordBasedCipher as ɵk, SerializableCipher as ɵj, WordArray as ɵe, BlockCipherMode as ɵt, CBC as ɵs, ECB as ɵu, NoPadding as ɵq, PKCS7 as ɵr };
|
|
//# sourceMappingURL=crypto-ts.js.map
|