/*!
|
* 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;
|
|
})();
|