| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- /** @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);
- }
- };
- };
|