/* cryptojs v3.1.2 code.google.com/p/crypto-js (c) 2009-2013 by jeff mott. all rights reserved. code.google.com/p/crypto-js/wiki/license */ /** * 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) { // shortcut var iv = this._iv; // choose mixing block if (iv) { var block = iv; // remove iv for subsequent blocks this._iv = undefined; } else { var 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 () { // 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) { var modecreator = mode.createencryptor; } else /* if (this._xformmode == this._dec_xform_mode) */ { var modecreator = mode.createdecryptor; // keep at least one block in the buffer for unpadding this._minbuffersize = 1; } this._mode = modecreator.call(mode, this, iv && iv.words); }, _doprocessblock: function (words, offset) { this._mode.processblock(words, offset); }, _dofinalize: function () { // 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 var finalprocessedblocks = this._process(!!'flush'); } else /* if (this._xformmode == this._dec_xform_mode) */ { // process final blocks var 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) { // shortcuts var ciphertext = cipherparams.ciphertext; var salt = cipherparams.salt; // format if (salt) { var wordarray = wordarray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext); } else { var 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) { // parse base64 var ciphertext = base64.parse(opensslstr); // shortcut var ciphertextwords = ciphertext.words; // test for salt if (ciphertextwords[0] == 0x53616c74 && ciphertextwords[1] == 0x65645f5f) { // extract salt var 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) { // generate random salt if (!salt) { salt = wordarray.random(64/8); } // derive key and iv var key = evpkdf.create({ keysize: keysize + ivsize }).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); // 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); // add iv to config cfg.iv = derivedparams.iv; // decrypt var plaintext = serializablecipher.decrypt.call(this, cipher, ciphertext, derivedparams.key, cfg); return plaintext; } }); }());