Source: ctr.js

/** @fileOverview CTR mode implementation
 *
 * @author Torben Haase
 */

if (sjcl.beware === undefined) {
  sjcl.beware = {};
}
sjcl.beware["CTR mode is dangerous because it doesn't protect message integrity."
] = function() {
  /**
   * Dangerous: CTR mode.
   * @namespace
   * @author Torben Haase
   */
  sjcl.mode.ctr = {
    /** The name of the mode.
     * @constant
     */
    name: "ctr",

    /** Encrypt in CTR mode.
     * @param {Object} prf The pseudorandom function.  It must have a block size of 16 bytes.
     * @param {bitArray} plaintext The plaintext data.
     * @param {bitArray} iv The initialization value.  It must be 128 bits.
     * @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(prf, plaintext, iv, adata) {
      return sjcl.mode.ctr._calculate(prf, plaintext, iv, adata);
    },

    /** Decrypt in CTR mode.
     * @param {Object} prf The pseudorandom function.  It must have a block size of 16 bytes.
     * @param {bitArray} ciphertext The ciphertext data.
     * @param {bitArray} iv The initialization value.  It must be 128 bits.
     * @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(prf, ciphertext, iv, adata) {
      return sjcl.mode.ctr._calculate(prf, ciphertext, iv, adata);
    },

    _calculate: function(prf, data, iv, adata) {
      var l, bl, res, c, d, e, i;
      if (adata && adata.length) {
        throw new sjcl.exception.invalid("ctr can't authenticate data");
      }
      if (sjcl.bitArray.bitLength(iv) !== 128) {
        throw new sjcl.exception.invalid("ctr iv must be 128 bits");
      }
      if (!(l = data.length)) {
        return [];
      }
      c = iv.slice(0);
      d = data.slice(0);
      bl = sjcl.bitArray.bitLength(d);
      for (i=0; i<l; i+=4) {
        e = prf.encrypt(c);
        d[i] ^= e[0];
        d[i+1] ^= e[1];
        d[i+2] ^= e[2];
        d[i+3] ^= e[3];
        c[3]++;
      }
      return sjcl.bitArray.clamp(d, bl);
    }
  };
};