895 lines
29 KiB
JavaScript
895 lines
29 KiB
JavaScript
|
;(function (root, factory, undef) {
|
||
|
if (typeof exports === "object") {
|
||
|
// CommonJS
|
||
|
module.exports = exports = factory(require("./core"), require("./evpkdf"));
|
||
|
}
|
||
|
else if (typeof define === "function" && define.amd) {
|
||
|
// AMD
|
||
|
define(["./core", "./evpkdf"], factory);
|
||
|
}
|
||
|
else {
|
||
|
// Global (browser)
|
||
|
factory(root.CryptoJS);
|
||
|
}
|
||
|
}(this, function (CryptoJS) {
|
||
|
|
||
|
/**
|
||
|
* Cipher core components.
|
||
|
*/
|
||
|
CryptoJS.lib.Cipher || (function (undefined) {
|
||
|
// Shortcuts
|
||
|
var C = CryptoJS;
|
||
|
var C_lib = C.lib;
|
||
|
var Base = C_lib.Base;
|
||
|
var WordArray = C_lib.WordArray;
|
||
|
var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm;
|
||
|
var C_enc = C.enc;
|
||
|
var Utf8 = C_enc.Utf8;
|
||
|
var Base64 = C_enc.Base64;
|
||
|
var C_algo = C.algo;
|
||
|
var EvpKDF = C_algo.EvpKDF;
|
||
|
|
||
|
/**
|
||
|
* Abstract base cipher template.
|
||
|
*
|
||
|
* @property {number} keySize This cipher's key size. Default: 4 (128 bits)
|
||
|
* @property {number} ivSize This cipher's IV size. Default: 4 (128 bits)
|
||
|
* @property {number} _ENC_XFORM_MODE A constant representing encryption mode.
|
||
|
* @property {number} _DEC_XFORM_MODE A constant representing decryption mode.
|
||
|
*/
|
||
|
var Cipher = C_lib.Cipher = BufferedBlockAlgorithm.extend({
|
||
|
/**
|
||
|
* Configuration options.
|
||
|
*
|
||
|
* @property {WordArray} iv The IV to use for this operation.
|
||
|
*/
|
||
|
cfg: Base.extend(),
|
||
|
|
||
|
/**
|
||
|
* Creates this cipher in encryption mode.
|
||
|
*
|
||
|
* @param {WordArray} key The key.
|
||
|
* @param {Object} cfg (Optional) The configuration options to use for this operation.
|
||
|
*
|
||
|
* @return {Cipher} A cipher instance.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray });
|
||
|
*/
|
||
|
createEncryptor: function (key, cfg) {
|
||
|
return this.create(this._ENC_XFORM_MODE, key, cfg);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Creates this cipher in decryption mode.
|
||
|
*
|
||
|
* @param {WordArray} key The key.
|
||
|
* @param {Object} cfg (Optional) The configuration options to use for this operation.
|
||
|
*
|
||
|
* @return {Cipher} A cipher instance.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray });
|
||
|
*/
|
||
|
createDecryptor: function (key, cfg) {
|
||
|
return this.create(this._DEC_XFORM_MODE, key, cfg);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Initializes a newly created cipher.
|
||
|
*
|
||
|
* @param {number} xformMode Either the encryption or decryption transormation mode constant.
|
||
|
* @param {WordArray} key The key.
|
||
|
* @param {Object} cfg (Optional) The configuration options to use for this operation.
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var cipher = CryptoJS.algo.AES.create(CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray });
|
||
|
*/
|
||
|
init: function (xformMode, key, cfg) {
|
||
|
// Apply config defaults
|
||
|
this.cfg = this.cfg.extend(cfg);
|
||
|
|
||
|
// Store transform mode and key
|
||
|
this._xformMode = xformMode;
|
||
|
this._key = key;
|
||
|
|
||
|
// Set initial values
|
||
|
this.reset();
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Resets this cipher to its initial state.
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* cipher.reset();
|
||
|
*/
|
||
|
reset: function () {
|
||
|
// Reset data buffer
|
||
|
BufferedBlockAlgorithm.reset.call(this);
|
||
|
|
||
|
// Perform concrete-cipher logic
|
||
|
this._doReset();
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Adds data to be encrypted or decrypted.
|
||
|
*
|
||
|
* @param {WordArray|string} dataUpdate The data to encrypt or decrypt.
|
||
|
*
|
||
|
* @return {WordArray} The data after processing.
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var encrypted = cipher.process('data');
|
||
|
* var encrypted = cipher.process(wordArray);
|
||
|
*/
|
||
|
process: function (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.
|
||
|
*
|
||
|
* @param {WordArray|string} dataUpdate The final data to encrypt or decrypt.
|
||
|
*
|
||
|
* @return {WordArray} The data after final processing.
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var encrypted = cipher.finalize();
|
||
|
* var encrypted = cipher.finalize('data');
|
||
|
* var encrypted = cipher.finalize(wordArray);
|
||
|
*/
|
||
|
finalize: function (dataUpdate) {
|
||
|
// Final data update
|
||
|
if (dataUpdate) {
|
||
|
this._append(dataUpdate);
|
||
|
}
|
||
|
|
||
|
// Perform concrete-cipher logic
|
||
|
var finalProcessedData = this._doFinalize();
|
||
|
|
||
|
return finalProcessedData;
|
||
|
},
|
||
|
|
||
|
keySize: 128/32,
|
||
|
|
||
|
ivSize: 128/32,
|
||
|
|
||
|
_ENC_XFORM_MODE: 1,
|
||
|
|
||
|
_DEC_XFORM_MODE: 2,
|
||
|
|
||
|
/**
|
||
|
* Creates shortcut functions to a cipher's object interface.
|
||
|
*
|
||
|
* @param {Cipher} cipher The cipher to create a helper for.
|
||
|
*
|
||
|
* @return {Object} An object with encrypt and decrypt shortcut functions.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES);
|
||
|
*/
|
||
|
_createHelper: (function () {
|
||
|
function selectCipherStrategy(key) {
|
||
|
if (typeof key == 'string') {
|
||
|
return PasswordBasedCipher;
|
||
|
} else {
|
||
|
return SerializableCipher;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return function (cipher) {
|
||
|
return {
|
||
|
encrypt: function (message, key, cfg) {
|
||
|
return selectCipherStrategy(key).encrypt(cipher, message, key, cfg);
|
||
|
},
|
||
|
|
||
|
decrypt: function (ciphertext, key, cfg) {
|
||
|
return selectCipherStrategy(key).decrypt(cipher, ciphertext, key, cfg);
|
||
|
}
|
||
|
};
|
||
|
};
|
||
|
}())
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
* Abstract base stream cipher template.
|
||
|
*
|
||
|
* @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 1 (32 bits)
|
||
|
*/
|
||
|
var StreamCipher = C_lib.StreamCipher = Cipher.extend({
|
||
|
_doFinalize: function () {
|
||
|
// Process partial blocks
|
||
|
var finalProcessedBlocks = this._process(!!'flush');
|
||
|
|
||
|
return finalProcessedBlocks;
|
||
|
},
|
||
|
|
||
|
blockSize: 1
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
* Mode namespace.
|
||
|
*/
|
||
|
var C_mode = C.mode = {};
|
||
|
|
||
|
/**
|
||
|
* Abstract base block cipher mode template.
|
||
|
*/
|
||
|
var BlockCipherMode = C_lib.BlockCipherMode = Base.extend({
|
||
|
/**
|
||
|
* Creates this mode for encryption.
|
||
|
*
|
||
|
* @param {Cipher} cipher A block cipher instance.
|
||
|
* @param {Array} iv The IV words.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words);
|
||
|
*/
|
||
|
createEncryptor: function (cipher, iv) {
|
||
|
return this.Encryptor.create(cipher, iv);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Creates this mode for decryption.
|
||
|
*
|
||
|
* @param {Cipher} cipher A block cipher instance.
|
||
|
* @param {Array} iv The IV words.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words);
|
||
|
*/
|
||
|
createDecryptor: function (cipher, iv) {
|
||
|
return this.Decryptor.create(cipher, iv);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Initializes a newly created mode.
|
||
|
*
|
||
|
* @param {Cipher} cipher A block cipher instance.
|
||
|
* @param {Array} iv The IV words.
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words);
|
||
|
*/
|
||
|
init: function (cipher, iv) {
|
||
|
this._cipher = cipher;
|
||
|
this._iv = iv;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
* Cipher Block Chaining mode.
|
||
|
*/
|
||
|
var CBC = C_mode.CBC = (function () {
|
||
|
/**
|
||
|
* Abstract base CBC mode.
|
||
|
*/
|
||
|
var CBC = BlockCipherMode.extend();
|
||
|
|
||
|
/**
|
||
|
* CBC encryptor.
|
||
|
*/
|
||
|
CBC.Encryptor = CBC.extend({
|
||
|
/**
|
||
|
* Processes the data block at offset.
|
||
|
*
|
||
|
* @param {Array} words The data words to operate on.
|
||
|
* @param {number} offset The offset where the block starts.
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* mode.processBlock(data.words, offset);
|
||
|
*/
|
||
|
processBlock: function (words, offset) {
|
||
|
// Shortcuts
|
||
|
var cipher = this._cipher;
|
||
|
var blockSize = cipher.blockSize;
|
||
|
|
||
|
// XOR and encrypt
|
||
|
xorBlock.call(this, words, offset, blockSize);
|
||
|
cipher.encryptBlock(words, offset);
|
||
|
|
||
|
// Remember this block to use with next block
|
||
|
this._prevBlock = words.slice(offset, offset + blockSize);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
* CBC decryptor.
|
||
|
*/
|
||
|
CBC.Decryptor = CBC.extend({
|
||
|
/**
|
||
|
* Processes the data block at offset.
|
||
|
*
|
||
|
* @param {Array} words The data words to operate on.
|
||
|
* @param {number} offset The offset where the block starts.
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* mode.processBlock(data.words, offset);
|
||
|
*/
|
||
|
processBlock: function (words, offset) {
|
||
|
// Shortcuts
|
||
|
var cipher = this._cipher;
|
||
|
var blockSize = cipher.blockSize;
|
||
|
|
||
|
// Remember this block to use with next block
|
||
|
var thisBlock = words.slice(offset, offset + blockSize);
|
||
|
|
||
|
// Decrypt and XOR
|
||
|
cipher.decryptBlock(words, offset);
|
||
|
xorBlock.call(this, words, offset, blockSize);
|
||
|
|
||
|
// This block becomes the previous block
|
||
|
this._prevBlock = thisBlock;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
function xorBlock(words, offset, blockSize) {
|
||
|
var block;
|
||
|
|
||
|
// Shortcut
|
||
|
var iv = this._iv;
|
||
|
|
||
|
// Choose mixing block
|
||
|
if (iv) {
|
||
|
block = iv;
|
||
|
|
||
|
// Remove IV for subsequent blocks
|
||
|
this._iv = undefined;
|
||
|
} else {
|
||
|
block = this._prevBlock;
|
||
|
}
|
||
|
|
||
|
// XOR blocks
|
||
|
for (var i = 0; i < blockSize; i++) {
|
||
|
words[offset + i] ^= block[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return CBC;
|
||
|
}());
|
||
|
|
||
|
/**
|
||
|
* Padding namespace.
|
||
|
*/
|
||
|
var C_pad = C.pad = {};
|
||
|
|
||
|
/**
|
||
|
* PKCS #5/7 padding strategy.
|
||
|
*/
|
||
|
var Pkcs7 = C_pad.Pkcs7 = {
|
||
|
/**
|
||
|
* Pads data using the algorithm defined in PKCS #5/7.
|
||
|
*
|
||
|
* @param {WordArray} data The data to pad.
|
||
|
* @param {number} blockSize The multiple that the data should be padded to.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* CryptoJS.pad.Pkcs7.pad(wordArray, 4);
|
||
|
*/
|
||
|
pad: function (data, blockSize) {
|
||
|
// Shortcut
|
||
|
var blockSizeBytes = blockSize * 4;
|
||
|
|
||
|
// Count padding bytes
|
||
|
var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes;
|
||
|
|
||
|
// Create padding word
|
||
|
var paddingWord = (nPaddingBytes << 24) | (nPaddingBytes << 16) | (nPaddingBytes << 8) | nPaddingBytes;
|
||
|
|
||
|
// Create padding
|
||
|
var paddingWords = [];
|
||
|
for (var i = 0; i < nPaddingBytes; i += 4) {
|
||
|
paddingWords.push(paddingWord);
|
||
|
}
|
||
|
var padding = WordArray.create(paddingWords, nPaddingBytes);
|
||
|
|
||
|
// Add padding
|
||
|
data.concat(padding);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Unpads data that had been padded using the algorithm defined in PKCS #5/7.
|
||
|
*
|
||
|
* @param {WordArray} data The data to unpad.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* CryptoJS.pad.Pkcs7.unpad(wordArray);
|
||
|
*/
|
||
|
unpad: function (data) {
|
||
|
// Get number of padding bytes from last byte
|
||
|
var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff;
|
||
|
|
||
|
// Remove padding
|
||
|
data.sigBytes -= nPaddingBytes;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Abstract base block cipher template.
|
||
|
*
|
||
|
* @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 4 (128 bits)
|
||
|
*/
|
||
|
var BlockCipher = C_lib.BlockCipher = Cipher.extend({
|
||
|
/**
|
||
|
* Configuration options.
|
||
|
*
|
||
|
* @property {Mode} mode The block mode to use. Default: CBC
|
||
|
* @property {Padding} padding The padding strategy to use. Default: Pkcs7
|
||
|
*/
|
||
|
cfg: Cipher.cfg.extend({
|
||
|
mode: CBC,
|
||
|
padding: Pkcs7
|
||
|
}),
|
||
|
|
||
|
reset: function () {
|
||
|
var modeCreator;
|
||
|
|
||
|
// Reset cipher
|
||
|
Cipher.reset.call(this);
|
||
|
|
||
|
// Shortcuts
|
||
|
var cfg = this.cfg;
|
||
|
var iv = cfg.iv;
|
||
|
var mode = cfg.mode;
|
||
|
|
||
|
// Reset block mode
|
||
|
if (this._xformMode == this._ENC_XFORM_MODE) {
|
||
|
modeCreator = mode.createEncryptor;
|
||
|
} else /* if (this._xformMode == this._DEC_XFORM_MODE) */ {
|
||
|
modeCreator = 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, iv && iv.words);
|
||
|
} else {
|
||
|
this._mode = modeCreator.call(mode, this, iv && iv.words);
|
||
|
this._mode.__creator = modeCreator;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_doProcessBlock: function (words, offset) {
|
||
|
this._mode.processBlock(words, offset);
|
||
|
},
|
||
|
|
||
|
_doFinalize: function () {
|
||
|
var finalProcessedBlocks;
|
||
|
|
||
|
// Shortcut
|
||
|
var padding = this.cfg.padding;
|
||
|
|
||
|
// Finalize
|
||
|
if (this._xformMode == this._ENC_XFORM_MODE) {
|
||
|
// Pad data
|
||
|
padding.pad(this._data, this.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
|
||
|
padding.unpad(finalProcessedBlocks);
|
||
|
}
|
||
|
|
||
|
return finalProcessedBlocks;
|
||
|
},
|
||
|
|
||
|
blockSize: 128/32
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
* A collection of cipher parameters.
|
||
|
*
|
||
|
* @property {WordArray} ciphertext The raw ciphertext.
|
||
|
* @property {WordArray} key The key to this ciphertext.
|
||
|
* @property {WordArray} iv The IV used in the ciphering operation.
|
||
|
* @property {WordArray} salt The salt used with a key derivation function.
|
||
|
* @property {Cipher} algorithm The cipher algorithm.
|
||
|
* @property {Mode} mode The block mode used in the ciphering operation.
|
||
|
* @property {Padding} padding The padding scheme used in the ciphering operation.
|
||
|
* @property {number} blockSize The block size of the cipher.
|
||
|
* @property {Format} formatter The default formatting strategy to convert this cipher params object to a string.
|
||
|
*/
|
||
|
var CipherParams = C_lib.CipherParams = Base.extend({
|
||
|
/**
|
||
|
* Initializes a newly created cipher params object.
|
||
|
*
|
||
|
* @param {Object} cipherParams An object with any of the possible cipher parameters.
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var cipherParams = CryptoJS.lib.CipherParams.create({
|
||
|
* ciphertext: ciphertextWordArray,
|
||
|
* key: keyWordArray,
|
||
|
* iv: ivWordArray,
|
||
|
* salt: saltWordArray,
|
||
|
* algorithm: CryptoJS.algo.AES,
|
||
|
* mode: CryptoJS.mode.CBC,
|
||
|
* padding: CryptoJS.pad.PKCS7,
|
||
|
* blockSize: 4,
|
||
|
* formatter: CryptoJS.format.OpenSSL
|
||
|
* });
|
||
|
*/
|
||
|
init: function (cipherParams) {
|
||
|
this.mixIn(cipherParams);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Converts this cipher params object to a string.
|
||
|
*
|
||
|
* @param {Format} formatter (Optional) The formatting strategy to use.
|
||
|
*
|
||
|
* @return {string} The stringified cipher params.
|
||
|
*
|
||
|
* @throws Error If neither the formatter nor the default formatter is set.
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var string = cipherParams + '';
|
||
|
* var string = cipherParams.toString();
|
||
|
* var string = cipherParams.toString(CryptoJS.format.OpenSSL);
|
||
|
*/
|
||
|
toString: function (formatter) {
|
||
|
return (formatter || this.formatter).stringify(this);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
* Format namespace.
|
||
|
*/
|
||
|
var C_format = C.format = {};
|
||
|
|
||
|
/**
|
||
|
* OpenSSL formatting strategy.
|
||
|
*/
|
||
|
var OpenSSLFormatter = C_format.OpenSSL = {
|
||
|
/**
|
||
|
* Converts a cipher params object to an OpenSSL-compatible string.
|
||
|
*
|
||
|
* @param {CipherParams} cipherParams The cipher params object.
|
||
|
*
|
||
|
* @return {string} The OpenSSL-compatible string.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams);
|
||
|
*/
|
||
|
stringify: function (cipherParams) {
|
||
|
var wordArray;
|
||
|
|
||
|
// Shortcuts
|
||
|
var ciphertext = cipherParams.ciphertext;
|
||
|
var salt = cipherParams.salt;
|
||
|
|
||
|
// Format
|
||
|
if (salt) {
|
||
|
wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext);
|
||
|
} else {
|
||
|
wordArray = ciphertext;
|
||
|
}
|
||
|
|
||
|
return wordArray.toString(Base64);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Converts an OpenSSL-compatible string to a cipher params object.
|
||
|
*
|
||
|
* @param {string} openSSLStr The OpenSSL-compatible string.
|
||
|
*
|
||
|
* @return {CipherParams} The cipher params object.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString);
|
||
|
*/
|
||
|
parse: function (openSSLStr) {
|
||
|
var salt;
|
||
|
|
||
|
// Parse base64
|
||
|
var ciphertext = Base64.parse(openSSLStr);
|
||
|
|
||
|
// Shortcut
|
||
|
var ciphertextWords = ciphertext.words;
|
||
|
|
||
|
// Test for salt
|
||
|
if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) {
|
||
|
// Extract salt
|
||
|
salt = WordArray.create(ciphertextWords.slice(2, 4));
|
||
|
|
||
|
// Remove salt from ciphertext
|
||
|
ciphertextWords.splice(0, 4);
|
||
|
ciphertext.sigBytes -= 16;
|
||
|
}
|
||
|
|
||
|
return CipherParams.create({ ciphertext: ciphertext, salt: salt });
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* A cipher wrapper that returns ciphertext as a serializable cipher params object.
|
||
|
*/
|
||
|
var SerializableCipher = C_lib.SerializableCipher = Base.extend({
|
||
|
/**
|
||
|
* Configuration options.
|
||
|
*
|
||
|
* @property {Formatter} format The formatting strategy to convert cipher param objects to and from a string. Default: OpenSSL
|
||
|
*/
|
||
|
cfg: Base.extend({
|
||
|
format: OpenSSLFormatter
|
||
|
}),
|
||
|
|
||
|
/**
|
||
|
* Encrypts a message.
|
||
|
*
|
||
|
* @param {Cipher} cipher The cipher algorithm to use.
|
||
|
* @param {WordArray|string} message The message to encrypt.
|
||
|
* @param {WordArray} key The key.
|
||
|
* @param {Object} cfg (Optional) The configuration options to use for this operation.
|
||
|
*
|
||
|
* @return {CipherParams} A cipher params object.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key);
|
||
|
* var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv });
|
||
|
* var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL });
|
||
|
*/
|
||
|
encrypt: function (cipher, message, key, cfg) {
|
||
|
// Apply config defaults
|
||
|
cfg = this.cfg.extend(cfg);
|
||
|
|
||
|
// Encrypt
|
||
|
var encryptor = cipher.createEncryptor(key, cfg);
|
||
|
var ciphertext = encryptor.finalize(message);
|
||
|
|
||
|
// Shortcut
|
||
|
var cipherCfg = encryptor.cfg;
|
||
|
|
||
|
// Create and return serializable cipher params
|
||
|
return CipherParams.create({
|
||
|
ciphertext: ciphertext,
|
||
|
key: key,
|
||
|
iv: cipherCfg.iv,
|
||
|
algorithm: cipher,
|
||
|
mode: cipherCfg.mode,
|
||
|
padding: cipherCfg.padding,
|
||
|
blockSize: cipher.blockSize,
|
||
|
formatter: cfg.format
|
||
|
});
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Decrypts serialized ciphertext.
|
||
|
*
|
||
|
* @param {Cipher} cipher The cipher algorithm to use.
|
||
|
* @param {CipherParams|string} ciphertext The ciphertext to decrypt.
|
||
|
* @param {WordArray} key The key.
|
||
|
* @param {Object} cfg (Optional) The configuration options to use for this operation.
|
||
|
*
|
||
|
* @return {WordArray} The plaintext.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, key, { iv: iv, format: CryptoJS.format.OpenSSL });
|
||
|
* var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, key, { iv: iv, format: CryptoJS.format.OpenSSL });
|
||
|
*/
|
||
|
decrypt: function (cipher, ciphertext, key, cfg) {
|
||
|
// Apply config defaults
|
||
|
cfg = this.cfg.extend(cfg);
|
||
|
|
||
|
// Convert string to CipherParams
|
||
|
ciphertext = this._parse(ciphertext, cfg.format);
|
||
|
|
||
|
// Decrypt
|
||
|
var plaintext = cipher.createDecryptor(key, cfg).finalize(ciphertext.ciphertext);
|
||
|
|
||
|
return plaintext;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Converts serialized ciphertext to CipherParams,
|
||
|
* else assumed CipherParams already and returns ciphertext unchanged.
|
||
|
*
|
||
|
* @param {CipherParams|string} ciphertext The ciphertext.
|
||
|
* @param {Formatter} format The formatting strategy to use to parse serialized ciphertext.
|
||
|
*
|
||
|
* @return {CipherParams} The unserialized ciphertext.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format);
|
||
|
*/
|
||
|
_parse: function (ciphertext, format) {
|
||
|
if (typeof ciphertext == 'string') {
|
||
|
return format.parse(ciphertext, this);
|
||
|
} else {
|
||
|
return ciphertext;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
* Key derivation function namespace.
|
||
|
*/
|
||
|
var C_kdf = C.kdf = {};
|
||
|
|
||
|
/**
|
||
|
* OpenSSL key derivation function.
|
||
|
*/
|
||
|
var OpenSSLKdf = C_kdf.OpenSSL = {
|
||
|
/**
|
||
|
* Derives a key and IV from a password.
|
||
|
*
|
||
|
* @param {string} password The password to derive from.
|
||
|
* @param {number} keySize The size in words of the key to generate.
|
||
|
* @param {number} ivSize The size in words of the IV to generate.
|
||
|
* @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly.
|
||
|
*
|
||
|
* @return {CipherParams} A cipher params object with the key, IV, and salt.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32);
|
||
|
* var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt');
|
||
|
*/
|
||
|
execute: function (password, keySize, ivSize, salt, hasher) {
|
||
|
// Generate random salt
|
||
|
if (!salt) {
|
||
|
salt = WordArray.random(64/8);
|
||
|
}
|
||
|
|
||
|
// Derive key and IV
|
||
|
if (!hasher) {
|
||
|
var key = EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt);
|
||
|
} else {
|
||
|
var key = EvpKDF.create({ keySize: keySize + ivSize, hasher: hasher }).compute(password, salt);
|
||
|
}
|
||
|
|
||
|
|
||
|
// Separate key and IV
|
||
|
var iv = WordArray.create(key.words.slice(keySize), ivSize * 4);
|
||
|
key.sigBytes = keySize * 4;
|
||
|
|
||
|
// Return params
|
||
|
return CipherParams.create({ key: key, iv: iv, salt: salt });
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* A serializable cipher wrapper that derives the key from a password,
|
||
|
* and returns ciphertext as a serializable cipher params object.
|
||
|
*/
|
||
|
var PasswordBasedCipher = C_lib.PasswordBasedCipher = SerializableCipher.extend({
|
||
|
/**
|
||
|
* Configuration options.
|
||
|
*
|
||
|
* @property {KDF} kdf The key derivation function to use to generate a key and IV from a password. Default: OpenSSL
|
||
|
*/
|
||
|
cfg: SerializableCipher.cfg.extend({
|
||
|
kdf: OpenSSLKdf
|
||
|
}),
|
||
|
|
||
|
/**
|
||
|
* Encrypts a message using a password.
|
||
|
*
|
||
|
* @param {Cipher} cipher The cipher algorithm to use.
|
||
|
* @param {WordArray|string} message The message to encrypt.
|
||
|
* @param {string} password The password.
|
||
|
* @param {Object} cfg (Optional) The configuration options to use for this operation.
|
||
|
*
|
||
|
* @return {CipherParams} A cipher params object.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password');
|
||
|
* var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL });
|
||
|
*/
|
||
|
encrypt: function (cipher, message, password, cfg) {
|
||
|
// Apply config defaults
|
||
|
cfg = this.cfg.extend(cfg);
|
||
|
|
||
|
// Derive key and other params
|
||
|
var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, cfg.salt, cfg.hasher);
|
||
|
|
||
|
// Add IV to config
|
||
|
cfg.iv = derivedParams.iv;
|
||
|
|
||
|
// Encrypt
|
||
|
var ciphertext = SerializableCipher.encrypt.call(this, cipher, message, derivedParams.key, cfg);
|
||
|
|
||
|
// Mix in derived params
|
||
|
ciphertext.mixIn(derivedParams);
|
||
|
|
||
|
return ciphertext;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Decrypts serialized ciphertext using a password.
|
||
|
*
|
||
|
* @param {Cipher} cipher The cipher algorithm to use.
|
||
|
* @param {CipherParams|string} ciphertext The ciphertext to decrypt.
|
||
|
* @param {string} password The password.
|
||
|
* @param {Object} cfg (Optional) The configuration options to use for this operation.
|
||
|
*
|
||
|
* @return {WordArray} The plaintext.
|
||
|
*
|
||
|
* @static
|
||
|
*
|
||
|
* @example
|
||
|
*
|
||
|
* var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password', { format: CryptoJS.format.OpenSSL });
|
||
|
* var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, 'password', { format: CryptoJS.format.OpenSSL });
|
||
|
*/
|
||
|
decrypt: function (cipher, ciphertext, password, cfg) {
|
||
|
// Apply config defaults
|
||
|
cfg = this.cfg.extend(cfg);
|
||
|
|
||
|
// Convert string to CipherParams
|
||
|
ciphertext = this._parse(ciphertext, cfg.format);
|
||
|
|
||
|
// Derive key and other params
|
||
|
var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt, cfg.hasher);
|
||
|
|
||
|
// Add IV to config
|
||
|
cfg.iv = derivedParams.iv;
|
||
|
|
||
|
// Decrypt
|
||
|
var plaintext = SerializableCipher.decrypt.call(this, cipher, ciphertext, derivedParams.key, cfg);
|
||
|
|
||
|
return plaintext;
|
||
|
}
|
||
|
});
|
||
|
}());
|
||
|
|
||
|
|
||
|
}));
|