Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
2,862 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
|
||
})(); |
Oops, something went wrong.