forked from bitwiseshiftleft/sjcl
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
Mike Hamburg
committed
May 23, 2011
1 parent
5170137
commit 514276a
Showing
9 changed files
with
998 additions
and
2 deletions.
There are no files selected for viewing
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
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
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,115 @@ | ||
/** @fileOverview CBC mode implementation | ||
* | ||
* @author Emily Stark | ||
* @author Mike Hamburg | ||
* @author Dan Boneh | ||
*/ | ||
|
||
/** @namespace | ||
* Dangerous: CBC mode with PKCS#5 padding. | ||
* | ||
* @author Emily Stark | ||
* @author Mike Hamburg | ||
* @author Dan Boneh | ||
*/ | ||
if (sjcl.beware === undefined) { | ||
sjcl.beware = {}; | ||
} | ||
sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity." | ||
] = function() { | ||
sjcl.mode.cbc = { | ||
/** The name of the mode. | ||
* @constant | ||
*/ | ||
name: "cbc", | ||
|
||
/** Encrypt in CBC mode with PKCS#5 padding. | ||
* @param {Object} prp The block cipher. It must have a block size of 16 bytes. | ||
* @param {bitArray} plaintext The plaintext data. | ||
* @param {bitArray} iv The initialization value. | ||
* @param {bitArray} [adata=[]] The authenticated data. Must be empty. | ||
* @return The encrypted data, an array of bytes. | ||
* @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits, or if any adata is specified. | ||
*/ | ||
encrypt: function(prp, plaintext, iv, adata) { | ||
if (adata && adata.length) { | ||
throw new sjcl.exception.invalid("cbc can't authenticate data"); | ||
} | ||
if (sjcl.bitArray.bitLength(iv) !== 128) { | ||
throw new sjcl.exception.invalid("cbc iv must be 128 bits"); | ||
} | ||
var i, | ||
w = sjcl.bitArray, | ||
xor = w._xor4, | ||
bl = w.bitLength(plaintext), | ||
bp = 0, | ||
output = []; | ||
|
||
if (bl&7) { | ||
throw new sjcl.exception.invalid("pkcs#5 padding only works for multiples of a byte"); | ||
} | ||
|
||
for (i=0; bp+128 <= bl; i+=4, bp+=128) { | ||
/* Encrypt a non-final block */ | ||
iv = prp.encrypt(xor(iv, plaintext.slice(i,i+4))); | ||
output.splice(i,0,iv[0],iv[1],iv[2],iv[3]); | ||
} | ||
|
||
/* Construct the pad. */ | ||
bl = (16 - ((bl >> 3) & 15)) * 0x1010101; | ||
|
||
/* Pad and encrypt. */ | ||
iv = prp.encrypt(xor(iv,w.concat(plaintext,[bl,bl,bl,bl]).slice(i,i+4))); | ||
output.splice(i,0,iv[0],iv[1],iv[2],iv[3]); | ||
return output; | ||
}, | ||
|
||
/** Decrypt in CBC mode. | ||
* @param {Object} prp The block cipher. It must have a block size of 16 bytes. | ||
* @param {bitArray} ciphertext The ciphertext data. | ||
* @param {bitArray} iv The initialization value. | ||
* @param {bitArray} [adata=[]] The authenticated data. It must be empty. | ||
* @return The decrypted data, an array of bytes. | ||
* @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits, or if any adata is specified. | ||
* @throws {sjcl.exception.corrupt} if if the message is corrupt. | ||
*/ | ||
decrypt: function(prp, ciphertext, iv, adata) { | ||
if (adata && adata.length) { | ||
throw new sjcl.exception.invalid("cbc can't authenticate data"); | ||
} | ||
if (sjcl.bitArray.bitLength(iv) !== 128) { | ||
throw new sjcl.exception.invalid("cbc iv must be 128 bits"); | ||
} | ||
if ((sjcl.bitArray.bitLength(ciphertext) & 127) || !ciphertext.length) { | ||
throw new sjcl.exception.corrupt("cbc ciphertext must be a positive multiple of the block size"); | ||
} | ||
var i, | ||
w = sjcl.bitArray, | ||
xor = w._xor4, | ||
bi, bo, | ||
output = []; | ||
|
||
adata = adata || []; | ||
|
||
for (i=0; i<ciphertext.length; i+=4) { | ||
bi = ciphertext.slice(i,i+4); | ||
bo = xor(iv,prp.decrypt(bi)); | ||
output.splice(i,0,bo[0],bo[1],bo[2],bo[3]); | ||
iv = bi; | ||
} | ||
|
||
/* check and remove the pad */ | ||
bi = output[i-1] & 255; | ||
if (bi == 0 || bi > 16) { | ||
throw new sjcl.exception.corrupt("pkcs#5 padding corrupt"); | ||
} | ||
bo = bi * 0x1010101; | ||
if (!w.equal(w.bitSlice([bo,bo,bo,bo], 0, bi*8), | ||
w.bitSlice(output, output.length*32 - bi*8, output.length*32))) { | ||
throw new sjcl.exception.corrupt("pkcs#5 padding corrupt"); | ||
} | ||
|
||
return w.bitSlice(output, 0, output.length*32 - bi*8); | ||
} | ||
}; | ||
}; |
Oops, something went wrong.