initital commit
This commit is contained in:
@@ -0,0 +1,378 @@
|
||||
/*!
|
||||
* 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;
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user