123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 |
- /*!
- * Crypto-JS contribution from Simon Greatrix
- */
- (function(){
- var C = (typeof window === 'undefined') ? require('./Crypto').Crypto : window.Crypto;
- // Create pad namespace
- var C_pad = C.pad = {};
- // Calculate the number of padding bytes required.
- function _requiredPadding(cipher, message) {
- var blockSizeInBytes = cipher._blocksize * 4;
- var reqd = blockSizeInBytes - message.length % blockSizeInBytes;
- return reqd;
- };
- // Remove padding when the final byte gives the number of padding bytes.
- var _unpadLength = function (message) {
- var pad = message.pop();
- for (var i = 1; i < pad; i++) {
- message.pop();
- }
- };
- // No-operation padding, used for stream ciphers
- C_pad.NoPadding = {
- pad : function (cipher,message) {},
- unpad : function (message) {}
- };
- // Zero Padding.
- //
- // If the message is not an exact number of blocks, the final block is
- // completed with 0x00 bytes. There is no unpadding.
- C_pad.ZeroPadding = {
- pad : function (cipher, message) {
- var blockSizeInBytes = cipher._blocksize * 4;
- var reqd = message.length % blockSizeInBytes;
- if( reqd!=0 ) {
- for(reqd = blockSizeInBytes - reqd; reqd>0; reqd--) {
- message.push(0x00);
- }
- }
- },
- unpad : function (message) {}
- };
- // ISO/IEC 7816-4 padding.
- //
- // Pads the plain text with an 0x80 byte followed by as many 0x00
- // bytes are required to complete the block.
- C_pad.iso7816 = {
- pad : function (cipher, message) {
- var reqd = _requiredPadding(cipher, message);
- message.push(0x80);
- for (; reqd > 1; reqd--) {
- message.push(0x00);
- }
- },
- unpad : function (message) {
- while (message.pop() != 0x80) {}
- }
- };
- // ANSI X.923 padding
- //
- // The final block is padded with zeros except for the last byte of the
- // last block which contains the number of padding bytes.
- C_pad.ansix923 = {
- pad : function (cipher, message) {
- var reqd = _requiredPadding(cipher, message);
- for (var i = 1; i < reqd; i++) {
- message.push(0x00);
- }
- message.push(reqd);
- },
- unpad : _unpadLength
- };
- // ISO 10126
- //
- // The final block is padded with random bytes except for the last
- // byte of the last block which contains the number of padding bytes.
- C_pad.iso10126 = {
- pad : function (cipher, message) {
- var reqd = _requiredPadding(cipher, message);
- for (var i = 1; i < reqd; i++) {
- message.push(Math.floor(Math.random() * 256));
- }
- message.push(reqd);
- },
- unpad : _unpadLength
- };
- // PKCS7 padding
- //
- // PKCS7 is described in RFC 5652. Padding is in whole bytes. The
- // value of each added byte is the number of bytes that are added,
- // i.e. N bytes, each of value N are added.
- C_pad.pkcs7 = {
- pad : function (cipher, message) {
- var reqd = _requiredPadding(cipher, message);
- for (var i = 0; i < reqd; i++) {
- message.push(reqd);
- }
- },
- unpad : _unpadLength
- };
- // Create mode namespace
- var C_mode = C.mode = {};
- /**
- * Mode base "class".
- */
- var Mode = C_mode.Mode = function (padding) {
- if (padding) {
- this._padding = padding;
- }
- };
- Mode.prototype = {
- encrypt: function (cipher, m, iv) {
- this._padding.pad(cipher, m);
- this._doEncrypt(cipher, m, iv);
- },
- decrypt: function (cipher, m, iv) {
- this._doDecrypt(cipher, m, iv);
- this._padding.unpad(m);
- },
- // Default padding
- _padding: C_pad.iso7816
- };
- /**
- * Electronic Code Book mode.
- *
- * ECB applies the cipher directly against each block of the input.
- *
- * ECB does not require an initialization vector.
- */
- var ECB = C_mode.ECB = function () {
- // Call parent constructor
- Mode.apply(this, arguments);
- };
- // Inherit from Mode
- var ECB_prototype = ECB.prototype = new Mode;
- // Concrete steps for Mode template
- ECB_prototype._doEncrypt = function (cipher, m, iv) {
- var blockSizeInBytes = cipher._blocksize * 4;
- // Encrypt each block
- for (var offset = 0; offset < m.length; offset += blockSizeInBytes) {
- cipher._encryptblock(m, offset);
- }
- };
- ECB_prototype._doDecrypt = function (cipher, c, iv) {
- var blockSizeInBytes = cipher._blocksize * 4;
- // Decrypt each block
- for (var offset = 0; offset < c.length; offset += blockSizeInBytes) {
- cipher._decryptblock(c, offset);
- }
- };
- // ECB never uses an IV
- ECB_prototype.fixOptions = function (options) {
- options.iv = [];
- };
- /**
- * Cipher block chaining
- *
- * The first block is XORed with the IV. Subsequent blocks are XOR with the
- * previous cipher output.
- */
- var CBC = C_mode.CBC = function () {
- // Call parent constructor
- Mode.apply(this, arguments);
- };
- // Inherit from Mode
- var CBC_prototype = CBC.prototype = new Mode;
- // Concrete steps for Mode template
- CBC_prototype._doEncrypt = function (cipher, m, iv) {
- var blockSizeInBytes = cipher._blocksize * 4;
- // Encrypt each block
- for (var offset = 0; offset < m.length; offset += blockSizeInBytes) {
- if (offset == 0) {
- // XOR first block using IV
- for (var i = 0; i < blockSizeInBytes; i++)
- m[i] ^= iv[i];
- } else {
- // XOR this block using previous crypted block
- for (var i = 0; i < blockSizeInBytes; i++)
- m[offset + i] ^= m[offset + i - blockSizeInBytes];
- }
- // Encrypt block
- cipher._encryptblock(m, offset);
- }
- };
- CBC_prototype._doDecrypt = function (cipher, c, iv) {
- var blockSizeInBytes = cipher._blocksize * 4;
- // At the start, the previously crypted block is the IV
- var prevCryptedBlock = iv;
- // Decrypt each block
- for (var offset = 0; offset < c.length; offset += blockSizeInBytes) {
- // Save this crypted block
- var thisCryptedBlock = c.slice(offset, offset + blockSizeInBytes);
- // Decrypt block
- cipher._decryptblock(c, offset);
- // XOR decrypted block using previous crypted block
- for (var i = 0; i < blockSizeInBytes; i++) {
- c[offset + i] ^= prevCryptedBlock[i];
- }
- prevCryptedBlock = thisCryptedBlock;
- }
- };
- /**
- * Cipher feed back
- *
- * The cipher output is XORed with the plain text to produce the cipher output,
- * which is then fed back into the cipher to produce a bit pattern to XOR the
- * next block with.
- *
- * This is a stream cipher mode and does not require padding.
- */
- var CFB = C_mode.CFB = function () {
- // Call parent constructor
- Mode.apply(this, arguments);
- };
- // Inherit from Mode
- var CFB_prototype = CFB.prototype = new Mode;
- // Override padding
- CFB_prototype._padding = C_pad.NoPadding;
- // Concrete steps for Mode template
- CFB_prototype._doEncrypt = function (cipher, m, iv) {
- var blockSizeInBytes = cipher._blocksize * 4,
- keystream = iv.slice(0);
- // Encrypt each byte
- for (var i = 0; i < m.length; i++) {
- var j = i % blockSizeInBytes;
- if (j == 0) cipher._encryptblock(keystream, 0);
- m[i] ^= keystream[j];
- keystream[j] = m[i];
- }
- };
- CFB_prototype._doDecrypt = function (cipher, c, iv) {
- var blockSizeInBytes = cipher._blocksize * 4,
- keystream = iv.slice(0);
- // Encrypt each byte
- for (var i = 0; i < c.length; i++) {
- var j = i % blockSizeInBytes;
- if (j == 0) cipher._encryptblock(keystream, 0);
- var b = c[i];
- c[i] ^= keystream[j];
- keystream[j] = b;
- }
- };
- /**
- * Output feed back
- *
- * The cipher repeatedly encrypts its own output. The output is XORed with the
- * plain text to produce the cipher text.
- *
- * This is a stream cipher mode and does not require padding.
- */
- var OFB = C_mode.OFB = function () {
- // Call parent constructor
- Mode.apply(this, arguments);
- };
- // Inherit from Mode
- var OFB_prototype = OFB.prototype = new Mode;
- // Override padding
- OFB_prototype._padding = C_pad.NoPadding;
- // Concrete steps for Mode template
- OFB_prototype._doEncrypt = function (cipher, m, iv) {
- var blockSizeInBytes = cipher._blocksize * 4,
- keystream = iv.slice(0);
- // Encrypt each byte
- for (var i = 0; i < m.length; i++) {
- // Generate keystream
- if (i % blockSizeInBytes == 0)
- cipher._encryptblock(keystream, 0);
- // Encrypt byte
- m[i] ^= keystream[i % blockSizeInBytes];
- }
- };
- OFB_prototype._doDecrypt = OFB_prototype._doEncrypt;
- /**
- * Counter
- * @author Gergely Risko
- *
- * After every block the last 4 bytes of the IV is increased by one
- * with carry and that IV is used for the next block.
- *
- * This is a stream cipher mode and does not require padding.
- */
- var CTR = C_mode.CTR = function () {
- // Call parent constructor
- Mode.apply(this, arguments);
- };
- // Inherit from Mode
- var CTR_prototype = CTR.prototype = new Mode;
- // Override padding
- CTR_prototype._padding = C_pad.NoPadding;
- CTR_prototype._doEncrypt = function (cipher, m, iv) {
- var blockSizeInBytes = cipher._blocksize * 4;
- var counter = iv.slice(0);
- for (var i = 0; i < m.length;) {
- // do not lose iv
- var keystream = counter.slice(0);
- // Generate keystream for next block
- cipher._encryptblock(keystream, 0);
- // XOR keystream with block
- for (var j = 0; i < m.length && j < blockSizeInBytes; j++, i++) {
- m[i] ^= keystream[j];
- }
- // Increase counter
- if(++(counter[blockSizeInBytes-1]) == 256) {
- counter[blockSizeInBytes-1] = 0;
- if(++(counter[blockSizeInBytes-2]) == 256) {
- counter[blockSizeInBytes-2] = 0;
- if(++(counter[blockSizeInBytes-3]) == 256) {
- counter[blockSizeInBytes-3] = 0;
- ++(counter[blockSizeInBytes-4]);
- }
- }
- }
- }
- };
- CTR_prototype._doDecrypt = CTR_prototype._doEncrypt;
- })();
|