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