>>0?1:0)|0;H=d[9]=H+p|0;d[8]=R+r+(H>>>0>>0?1:0)|0;I=d[11]=I+D|0;d[10]=S+L+(I>>>0>>0?1:0)|0;J=d[13]=J+E|0;d[12]=T+M+(J>>>0>>0?1:0)|0;K=d[15]=K+F|0;d[14]=U+O+(K>>>0>>0?1:0)|0}};sjcl.hash.sha1=function(a){a?(this.c=a.c.slice(0),this.b=a.b.slice(0),this.a=a.a):this.reset()};sjcl.hash.sha1.hash=function(a){return(new sjcl.hash.sha1).update(a).finalize()};
-sjcl.hash.sha1.prototype={blockSize:512,reset:function(){this.c=this.f.slice(0);this.b=[];this.a=0;return this},update:function(a){"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var b,c=this.b=sjcl.bitArray.concat(this.b,a);b=this.a;a=this.a=b+sjcl.bitArray.bitLength(a);for(b=this.blockSize+b&-this.blockSize;b<=a;b+=this.blockSize)this.e(c.splice(0,16));return this},finalize:function(){var a,b=this.b,c=this.c,b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);
-b.push(Math.floor(this.a/0x100000000));for(b.push(this.a|0);b.length;)this.e(b.splice(0,16));this.reset();return c},f:[1732584193,4023233417,2562383102,271733878,3285377520],d:[1518500249,1859775393,2400959708,3395469782],e:function(a){var b,c,e,d,h,k,f=a.slice(0),g=this.c;c=g[0];e=g[1];d=g[2];h=g[3];k=g[4];for(a=0;79>=a;a++)16<=a&&(f[a]=(f[a-3]^f[a-8]^f[a-14]^f[a-16])<<1|(f[a-3]^f[a-8]^f[a-14]^f[a-16])>>>31),b=19>=a?e&d|~e&h:39>=a?e^d^h:59>=a?e&d|e&h|d&h:79>=a?e^d^h:void 0,b=(c<<5|c>>>27)+b+k+f[a]+
-this.d[Math.floor(a/20)]|0,k=h,h=d,d=e<<30|e>>>2,e=c,c=b;g[0]=g[0]+c|0;g[1]=g[1]+e|0;g[2]=g[2]+d|0;g[3]=g[3]+h|0;g[4]=g[4]+k|0}};sjcl.misc.hmac=function(a,b){this.k=b=b||sjcl.hash.sha256;var c=[[],[]],e,d=b.prototype.blockSize/32;this.g=[new b,new b];a.length>d&&(a=b.hash(a));for(e=0;e>>24]<<24 ^ sbox[tmp>>16&255]<<16 ^ sbox[tmp>>8&255]<<8 ^ sbox[tmp&255];
+
+ // shift rows and add rcon
+ if (i%keyLen === 0) {
+ tmp = tmp<<8 ^ tmp>>>24 ^ rcon<<24;
+ rcon = rcon<<1 ^ (rcon>>7)*283;
+ }
+ }
+
+ encKey[i] = encKey[i-keyLen] ^ tmp;
+ }
+
+ // schedule decryption keys
+ for (j = 0; i; j++, i--) {
+ tmp = encKey[j&3 ? i : i - 4];
+ if (i<=4 || j<4) {
+ decKey[j] = tmp;
+ } else {
+ decKey[j] = decTable[0][sbox[tmp>>>24 ]] ^
+ decTable[1][sbox[tmp>>16 & 255]] ^
+ decTable[2][sbox[tmp>>8 & 255]] ^
+ decTable[3][sbox[tmp & 255]];
+ }
+ }
+};
+
+sjcl.cipher.aes.prototype = {
+ // public
+ /* Something like this might appear here eventually
+ name: "AES",
+ blockSize: 4,
+ keySizes: [4,6,8],
+ */
+
+ /**
+ * Encrypt an array of 4 big-endian words.
+ * @param {Array} data The plaintext.
+ * @return {Array} The ciphertext.
+ */
+ encrypt:function (data) { return this._crypt(data,0); },
+
+ /**
+ * Decrypt an array of 4 big-endian words.
+ * @param {Array} data The ciphertext.
+ * @return {Array} The plaintext.
+ */
+ decrypt:function (data) { return this._crypt(data,1); },
+
+ /**
+ * The expanded S-box and inverse S-box tables. These will be computed
+ * on the client so that we don't have to send them down the wire.
+ *
+ * There are two tables, _tables[0] is for encryption and
+ * _tables[1] is for decryption.
+ *
+ * The first 4 sub-tables are the expanded S-box with MixColumns. The
+ * last (_tables[01][4]) is the S-box itself.
+ *
+ * @private
+ */
+ _tables: [[[],[],[],[],[]],[[],[],[],[],[]]],
+
+ /**
+ * Expand the S-box tables.
+ *
+ * @private
+ */
+ _precompute: function () {
+ var encTable = this._tables[0], decTable = this._tables[1],
+ sbox = encTable[4], sboxInv = decTable[4],
+ i, x, xInv, d=[], th=[], x2, x4, x8, s, tEnc, tDec;
+
+ // Compute double and third tables
+ for (i = 0; i < 256; i++) {
+ th[( d[i] = i<<1 ^ (i>>7)*283 )^i]=i;
+ }
+
+ for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) {
+ // Compute sbox
+ s = xInv ^ xInv<<1 ^ xInv<<2 ^ xInv<<3 ^ xInv<<4;
+ s = s>>8 ^ s&255 ^ 99;
+ sbox[x] = s;
+ sboxInv[s] = x;
+
+ // Compute MixColumns
+ x8 = d[x4 = d[x2 = d[x]]];
+ tDec = x8*0x1010101 ^ x4*0x10001 ^ x2*0x101 ^ x*0x1010100;
+ tEnc = d[s]*0x101 ^ s*0x1010100;
+
+ for (i = 0; i < 4; i++) {
+ encTable[i][x] = tEnc = tEnc<<24 ^ tEnc>>>8;
+ decTable[i][s] = tDec = tDec<<24 ^ tDec>>>8;
+ }
+ }
+
+ // Compactify. Considerable speedup on Firefox.
+ for (i = 0; i < 5; i++) {
+ encTable[i] = encTable[i].slice(0);
+ decTable[i] = decTable[i].slice(0);
+ }
+ },
+
+ /**
+ * Encryption and decryption core.
+ * @param {Array} input Four words to be encrypted or decrypted.
+ * @param dir The direction, 0 for encrypt and 1 for decrypt.
+ * @return {Array} The four encrypted or decrypted words.
+ * @private
+ */
+ _crypt:function (input, dir) {
+ if (input.length !== 4) {
+ throw new sjcl.exception.invalid("invalid aes block size");
+ }
+
+ var key = this._key[dir],
+ // state variables a,b,c,d are loaded with pre-whitened data
+ a = input[0] ^ key[0],
+ b = input[dir ? 3 : 1] ^ key[1],
+ c = input[2] ^ key[2],
+ d = input[dir ? 1 : 3] ^ key[3],
+ a2, b2, c2,
+
+ nInnerRounds = key.length/4 - 2,
+ i,
+ kIndex = 4,
+ out = [0,0,0,0],
+ table = this._tables[dir],
+
+ // load up the tables
+ t0 = table[0],
+ t1 = table[1],
+ t2 = table[2],
+ t3 = table[3],
+ sbox = table[4];
+
+ // Inner rounds. Cribbed from OpenSSL.
+ for (i = 0; i < nInnerRounds; i++) {
+ a2 = t0[a>>>24] ^ t1[b>>16 & 255] ^ t2[c>>8 & 255] ^ t3[d & 255] ^ key[kIndex];
+ b2 = t0[b>>>24] ^ t1[c>>16 & 255] ^ t2[d>>8 & 255] ^ t3[a & 255] ^ key[kIndex + 1];
+ c2 = t0[c>>>24] ^ t1[d>>16 & 255] ^ t2[a>>8 & 255] ^ t3[b & 255] ^ key[kIndex + 2];
+ d = t0[d>>>24] ^ t1[a>>16 & 255] ^ t2[b>>8 & 255] ^ t3[c & 255] ^ key[kIndex + 3];
+ kIndex += 4;
+ a=a2; b=b2; c=c2;
+ }
+
+ // Last round.
+ for (i = 0; i < 4; i++) {
+ out[dir ? 3&-i : i] =
+ sbox[a>>>24 ]<<24 ^
+ sbox[b>>16 & 255]<<16 ^
+ sbox[c>>8 & 255]<<8 ^
+ sbox[d & 255] ^
+ key[kIndex++];
+ a2=a; a=b; b=c; c=d; d=a2;
+ }
+
+ return out;
+ }
+};
+
+/** @fileOverview Arrays of bits, encoded as arrays of Numbers.
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ */
+
+/** @namespace Arrays of bits, encoded as arrays of Numbers.
+ *
+ * @description
+ *
+ * These objects are the currency accepted by SJCL's crypto functions.
+ *
+ *
+ *
+ * Most of our crypto primitives operate on arrays of 4-byte words internally,
+ * but many of them can take arguments that are not a multiple of 4 bytes.
+ * This library encodes arrays of bits (whose size need not be a multiple of 8
+ * bits) as arrays of 32-bit words. The bits are packed, big-endian, into an
+ * array of words, 32 bits at a time. Since the words are double-precision
+ * floating point numbers, they fit some extra data. We use this (in a private,
+ * possibly-changing manner) to encode the number of bits actually present
+ * in the last word of the array.
+ *
+ *
+ *
+ * Because bitwise ops clear this out-of-band data, these arrays can be passed
+ * to ciphers like AES which want arrays of words.
+ *
+ */
+sjcl.bitArray = {
+ /**
+ * Array slices in units of bits.
+ * @param {bitArray} a The array to slice.
+ * @param {Number} bstart The offset to the start of the slice, in bits.
+ * @param {Number} bend The offset to the end of the slice, in bits. If this is undefined,
+ * slice until the end of the array.
+ * @return {bitArray} The requested slice.
+ */
+ bitSlice: function (a, bstart, bend) {
+ a = sjcl.bitArray._shiftRight(a.slice(bstart/32), 32 - (bstart & 31)).slice(1);
+ return (bend === undefined) ? a : sjcl.bitArray.clamp(a, bend-bstart);
+ },
+
+ /**
+ * Extract a number packed into a bit array.
+ * @param {bitArray} a The array to slice.
+ * @param {Number} bstart The offset to the start of the slice, in bits.
+ * @param {Number} length The length of the number to extract.
+ * @return {Number} The requested slice.
+ */
+ extract: function(a, bstart, blength) {
+ // FIXME: this Math.floor is not necessary at all, but for some reason
+ // seems to suppress a bug in the Chromium JIT.
+ var x, sh = Math.floor((-bstart-blength) & 31);
+ if ((bstart + blength - 1 ^ bstart) & -32) {
+ // it crosses a boundary
+ x = (a[bstart/32|0] << (32 - sh)) ^ (a[bstart/32+1|0] >>> sh);
+ } else {
+ // within a single word
+ x = a[bstart/32|0] >>> sh;
+ }
+ return x & ((1< 0 && len) {
+ a[l-1] = sjcl.bitArray.partial(len, a[l-1] & 0x80000000 >> (len-1), 1);
+ }
+ return a;
+ },
+
+ /**
+ * Make a partial word for a bit array.
+ * @param {Number} len The number of bits in the word.
+ * @param {Number} x The bits.
+ * @param {Number} [0] _end Pass 1 if x has already been shifted to the high side.
+ * @return {Number} The partial word.
+ */
+ partial: function (len, x, _end) {
+ if (len === 32) { return x; }
+ return (_end ? x|0 : x << (32-len)) + len * 0x10000000000;
+ },
+
+ /**
+ * Get the number of bits used by a partial word.
+ * @param {Number} x The partial word.
+ * @return {Number} The number of bits used by the partial word.
+ */
+ getPartial: function (x) {
+ return Math.round(x/0x10000000000) || 32;
+ },
+
+ /**
+ * Compare two arrays for equality in a predictable amount of time.
+ * @param {bitArray} a The first array.
+ * @param {bitArray} b The second array.
+ * @return {boolean} true if a == b; false otherwise.
+ */
+ equal: function (a, b) {
+ if (sjcl.bitArray.bitLength(a) !== sjcl.bitArray.bitLength(b)) {
+ return false;
+ }
+ var x = 0, i;
+ for (i=0; i= 32; shift -= 32) {
+ out.push(carry);
+ carry = 0;
+ }
+ if (shift === 0) {
+ return out.concat(a);
+ }
+
+ for (i=0; i>>shift);
+ carry = a[i] << (32-shift);
+ }
+ last2 = a.length ? a[a.length-1] : 0;
+ shift2 = sjcl.bitArray.getPartial(last2);
+ out.push(sjcl.bitArray.partial(shift+shift2 & 31, (shift + shift2 > 32) ? carry : out.pop(),1));
+ return out;
+ },
+
+ /** xor a block of 4 words together.
+ * @private
+ */
+ _xor4: function(x,y) {
+ return [x[0]^y[0],x[1]^y[1],x[2]^y[2],x[3]^y[3]];
+ }
+};
+/** @fileOverview Bit array codec implementations.
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ */
+
+/** @namespace UTF-8 strings */
+sjcl.codec.utf8String = {
+ /** Convert from a bitArray to a UTF-8 string. */
+ fromBits: function (arr) {
+ var out = "", bl = sjcl.bitArray.bitLength(arr), i, tmp;
+ for (i=0; i>> 24);
+ tmp <<= 8;
+ }
+ return decodeURIComponent(escape(out));
+ },
+
+ /** Convert from a UTF-8 string to a bitArray. */
+ toBits: function (str) {
+ str = unescape(encodeURIComponent(str));
+ var out = [], i, tmp=0;
+ for (i=0; i>>bits) >>> 26);
+ if (bits < 6) {
+ ta = arr[i] << (6-bits);
+ bits += 26;
+ i++;
+ } else {
+ ta <<= 6;
+ bits -= 6;
+ }
+ }
+ while ((out.length & 3) && !_noEquals) { out += "="; }
+ return out;
+ },
+
+ /** Convert from a base64 string to a bitArray */
+ toBits: function(str, _url) {
+ str = str.replace(/\s|=/g,'');
+ var out = [], i, bits=0, c = sjcl.codec.base64._chars, ta=0, x;
+ if (_url) {
+ c = c.substr(0,62) + '-_';
+ }
+ for (i=0; i 26) {
+ bits -= 26;
+ out.push(ta ^ x>>>bits);
+ ta = x << (32-bits);
+ } else {
+ bits += 6;
+ ta ^= x << (32-bits);
+ }
+ }
+ if (bits&56) {
+ out.push(sjcl.bitArray.partial(bits&56, ta, 1));
+ }
+ return out;
+ }
+};
+
+sjcl.codec.base64url = {
+ fromBits: function (arr) { return sjcl.codec.base64.fromBits(arr,1,1); },
+ toBits: function (str) { return sjcl.codec.base64.toBits(str,1); }
+};
+/** @fileOverview Javascript SHA-256 implementation.
+ *
+ * An older version of this implementation is available in the public
+ * domain, but this one is (c) Emily Stark, Mike Hamburg, Dan Boneh,
+ * Stanford University 2008-2010 and BSD-licensed for liability
+ * reasons.
+ *
+ * Special thanks to Aldo Cortesi for pointing out several bugs in
+ * this code.
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ */
+
+/**
+ * Context for a SHA-256 operation in progress.
+ * @constructor
+ * @class Secure Hash Algorithm, 256 bits.
+ */
+sjcl.hash.sha256 = function (hash) {
+ if (!this._key[0]) { this._precompute(); }
+ if (hash) {
+ this._h = hash._h.slice(0);
+ this._buffer = hash._buffer.slice(0);
+ this._length = hash._length;
+ } else {
+ this.reset();
+ }
+};
+
+/**
+ * Hash a string or an array of words.
+ * @static
+ * @param {bitArray|String} data the data to hash.
+ * @return {bitArray} The hash value, an array of 16 big-endian words.
+ */
+sjcl.hash.sha256.hash = function (data) {
+ return (new sjcl.hash.sha256()).update(data).finalize();
+};
+
+sjcl.hash.sha256.prototype = {
+ /**
+ * The hash's block size, in bits.
+ * @constant
+ */
+ blockSize: 512,
+
+ /**
+ * Reset the hash state.
+ * @return this
+ */
+ reset:function () {
+ this._h = this._init.slice(0);
+ this._buffer = [];
+ this._length = 0;
+ return this;
+ },
+
+ /**
+ * Input several words to the hash.
+ * @param {bitArray|String} data the data to hash.
+ * @return this
+ */
+ update: function (data) {
+ if (typeof data === "string") {
+ data = sjcl.codec.utf8String.toBits(data);
+ }
+ var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data),
+ ol = this._length,
+ nl = this._length = ol + sjcl.bitArray.bitLength(data);
+ for (i = 512+ol & -512; i <= nl; i+= 512) {
+ this._block(b.splice(0,16));
+ }
+ return this;
+ },
+
+ /**
+ * Complete hashing and output the hash value.
+ * @return {bitArray} The hash value, an array of 8 big-endian words.
+ */
+ finalize:function () {
+ var i, b = this._buffer, h = this._h;
+
+ // Round out and push the buffer
+ b = sjcl.bitArray.concat(b, [sjcl.bitArray.partial(1,1)]);
+
+ // Round out the buffer to a multiple of 16 words, less the 2 length words.
+ for (i = b.length + 2; i & 15; i++) {
+ b.push(0);
+ }
+
+ // append the length
+ b.push(Math.floor(this._length / 0x100000000));
+ b.push(this._length | 0);
+
+ while (b.length) {
+ this._block(b.splice(0,16));
+ }
+
+ this.reset();
+ return h;
+ },
+
+ /**
+ * The SHA-256 initialization vector, to be precomputed.
+ * @private
+ */
+ _init:[],
+ /*
+ _init:[0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19],
+ */
+
+ /**
+ * The SHA-256 hash key, to be precomputed.
+ * @private
+ */
+ _key:[],
+ /*
+ _key:
+ [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2],
+ */
+
+
+ /**
+ * Function to precompute _init and _key.
+ * @private
+ */
+ _precompute: function () {
+ var i = 0, prime = 2, factor;
+
+ function frac(x) { return (x-Math.floor(x)) * 0x100000000 | 0; }
+
+ outer: for (; i<64; prime++) {
+ for (factor=2; factor*factor <= prime; factor++) {
+ if (prime % factor === 0) {
+ // not a prime
+ continue outer;
+ }
+ }
+
+ if (i<8) {
+ this._init[i] = frac(Math.pow(prime, 1/2));
+ }
+ this._key[i] = frac(Math.pow(prime, 1/3));
+ i++;
+ }
+ },
+
+ /**
+ * Perform one cycle of SHA-256.
+ * @param {bitArray} words one block of words.
+ * @private
+ */
+ _block:function (words) {
+ var i, tmp, a, b,
+ w = words.slice(0),
+ h = this._h,
+ k = this._key,
+ h0 = h[0], h1 = h[1], h2 = h[2], h3 = h[3],
+ h4 = h[4], h5 = h[5], h6 = h[6], h7 = h[7];
+
+ /* Rationale for placement of |0 :
+ * If a value can overflow is original 32 bits by a factor of more than a few
+ * million (2^23 ish), there is a possibility that it might overflow the
+ * 53-bit mantissa and lose precision.
+ *
+ * To avoid this, we clamp back to 32 bits by |'ing with 0 on any value that
+ * propagates around the loop, and on the hash state h[]. I don't believe
+ * that the clamps on h4 and on h0 are strictly necessary, but it's close
+ * (for h4 anyway), and better safe than sorry.
+ *
+ * The clamps on h[] are necessary for the output to be correct even in the
+ * common case and for short inputs.
+ */
+ for (i=0; i<64; i++) {
+ // load up the input word for this round
+ if (i<16) {
+ tmp = w[i];
+ } else {
+ a = w[(i+1 ) & 15];
+ b = w[(i+14) & 15];
+ tmp = w[i&15] = ((a>>>7 ^ a>>>18 ^ a>>>3 ^ a<<25 ^ a<<14) +
+ (b>>>17 ^ b>>>19 ^ b>>>10 ^ b<<15 ^ b<<13) +
+ w[i&15] + w[(i+9) & 15]) | 0;
+ }
+
+ tmp = (tmp + h7 + (h4>>>6 ^ h4>>>11 ^ h4>>>25 ^ h4<<26 ^ h4<<21 ^ h4<<7) + (h6 ^ h4&(h5^h6)) + k[i]); // | 0;
+
+ // shift register
+ h7 = h6; h6 = h5; h5 = h4;
+ h4 = h3 + tmp | 0;
+ h3 = h2; h2 = h1; h1 = h0;
+
+ h0 = (tmp + ((h1&h2) ^ (h3&(h1^h2))) + (h1>>>2 ^ h1>>>13 ^ h1>>>22 ^ h1<<30 ^ h1<<19 ^ h1<<10)) | 0;
+ }
+
+ h[0] = h[0]+h0 | 0;
+ h[1] = h[1]+h1 | 0;
+ h[2] = h[2]+h2 | 0;
+ h[3] = h[3]+h3 | 0;
+ h[4] = h[4]+h4 | 0;
+ h[5] = h[5]+h5 | 0;
+ h[6] = h[6]+h6 | 0;
+ h[7] = h[7]+h7 | 0;
+ }
+};
+
+
+/** @fileOverview Javascript SHA-512 implementation.
+ *
+ * This implementation was written for CryptoJS by Jeff Mott and adapted for
+ * SJCL by Stefan Thomas.
+ *
+ * CryptoJS (c) 2009–2012 by Jeff Mott. All rights reserved.
+ * Released with New BSD License
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ * @author Jeff Mott
+ * @author Stefan Thomas
+ */
+
+/**
+ * Context for a SHA-512 operation in progress.
+ * @constructor
+ * @class Secure Hash Algorithm, 512 bits.
+ */
+sjcl.hash.sha512 = function (hash) {
+ if (!this._key[0]) { this._precompute(); }
+ if (hash) {
+ this._h = hash._h.slice(0);
+ this._buffer = hash._buffer.slice(0);
+ this._length = hash._length;
+ } else {
+ this.reset();
+ }
+};
+
+/**
+ * Hash a string or an array of words.
+ * @static
+ * @param {bitArray|String} data the data to hash.
+ * @return {bitArray} The hash value, an array of 16 big-endian words.
+ */
+sjcl.hash.sha512.hash = function (data) {
+ return (new sjcl.hash.sha512()).update(data).finalize();
+};
+
+sjcl.hash.sha512.prototype = {
+ /**
+ * The hash's block size, in bits.
+ * @constant
+ */
+ blockSize: 1024,
+
+ /**
+ * Reset the hash state.
+ * @return this
+ */
+ reset:function () {
+ this._h = this._init.slice(0);
+ this._buffer = [];
+ this._length = 0;
+ return this;
+ },
+
+ /**
+ * Input several words to the hash.
+ * @param {bitArray|String} data the data to hash.
+ * @return this
+ */
+ update: function (data) {
+ if (typeof data === "string") {
+ data = sjcl.codec.utf8String.toBits(data);
+ }
+ var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data),
+ ol = this._length,
+ nl = this._length = ol + sjcl.bitArray.bitLength(data);
+ for (i = 1024+ol & -1024; i <= nl; i+= 1024) {
+ this._block(b.splice(0,32));
+ }
+ return this;
+ },
+
+ /**
+ * Complete hashing and output the hash value.
+ * @return {bitArray} The hash value, an array of 16 big-endian words.
+ */
+ finalize:function () {
+ var i, b = this._buffer, h = this._h;
+
+ // Round out and push the buffer
+ b = sjcl.bitArray.concat(b, [sjcl.bitArray.partial(1,1)]);
+
+ // Round out the buffer to a multiple of 32 words, less the 4 length words.
+ for (i = b.length + 4; i & 31; i++) {
+ b.push(0);
+ }
+
+ // append the length
+ b.push(0);
+ b.push(0);
+ b.push(Math.floor(this._length / 0x100000000));
+ b.push(this._length | 0);
+
+ while (b.length) {
+ this._block(b.splice(0,32));
+ }
+
+ this.reset();
+ return h;
+ },
+
+ /**
+ * The SHA-512 initialization vector, to be precomputed.
+ * @private
+ */
+ _init:[],
+
+ /**
+ * Least significant 24 bits of SHA512 initialization values.
+ *
+ * Javascript only has 53 bits of precision, so we compute the 40 most
+ * significant bits and add the remaining 24 bits as constants.
+ *
+ * @private
+ */
+ _initr: [ 0xbcc908, 0xcaa73b, 0x94f82b, 0x1d36f1, 0xe682d1, 0x3e6c1f, 0x41bd6b, 0x7e2179 ],
+
+ /*
+ _init:
+ [0x6a09e667, 0xf3bcc908, 0xbb67ae85, 0x84caa73b, 0x3c6ef372, 0xfe94f82b, 0xa54ff53a, 0x5f1d36f1,
+ 0x510e527f, 0xade682d1, 0x9b05688c, 0x2b3e6c1f, 0x1f83d9ab, 0xfb41bd6b, 0x5be0cd19, 0x137e2179],
+ */
+
+ /**
+ * The SHA-512 hash key, to be precomputed.
+ * @private
+ */
+ _key:[],
+
+ /**
+ * Least significant 24 bits of SHA512 key values.
+ * @private
+ */
+ _keyr:
+ [0x28ae22, 0xef65cd, 0x4d3b2f, 0x89dbbc, 0x48b538, 0x05d019, 0x194f9b, 0x6d8118,
+ 0x030242, 0x706fbe, 0xe4b28c, 0xffb4e2, 0x7b896f, 0x1696b1, 0xc71235, 0x692694,
+ 0xf14ad2, 0x4f25e3, 0x8cd5b5, 0xac9c65, 0x2b0275, 0xa6e483, 0x41fbd4, 0x1153b5,
+ 0x66dfab, 0xb43210, 0xfb213f, 0xef0ee4, 0xa88fc2, 0x0aa725, 0x03826f, 0x0e6e70,
+ 0xd22ffc, 0x26c926, 0xc42aed, 0x95b3df, 0xaf63de, 0x77b2a8, 0xedaee6, 0x82353b,
+ 0xf10364, 0x423001, 0xf89791, 0x54be30, 0xef5218, 0x65a910, 0x71202a, 0xbbd1b8,
+ 0xd2d0c8, 0x41ab53, 0x8eeb99, 0x9b48a8, 0xc95a63, 0x418acb, 0x63e373, 0xb2b8a3,
+ 0xefb2fc, 0x172f60, 0xf0ab72, 0x6439ec, 0x631e28, 0x82bde9, 0xc67915, 0x72532b,
+ 0x26619c, 0xc0c207, 0xe0eb1e, 0x6ed178, 0x176fba, 0xc898a6, 0xf90dae, 0x1c471b,
+ 0x047d84, 0xc72493, 0xc9bebc, 0x100d4c, 0x3e42b6, 0x657e2a, 0xd6faec, 0x475817],
+
+ /*
+ _key:
+ [0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd, 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc,
+ 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019, 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118,
+ 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe, 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,
+ 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1, 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694,
+ 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3, 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65,
+ 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483, 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,
+ 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210, 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4,
+ 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725, 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70,
+ 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926, 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,
+ 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8, 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b,
+ 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001, 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30,
+ 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910, 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,
+ 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53, 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8,
+ 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb, 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3,
+ 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60, 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,
+ 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9, 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b,
+ 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207, 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178,
+ 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6, 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,
+ 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493, 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c,
+ 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a, 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817],
+ */
+
+ /**
+ * Function to precompute _init and _key.
+ * @private
+ */
+ _precompute: function () {
+ // XXX: This code is for precomputing the SHA256 constants, change for
+ // SHA512 and re-enable.
+ var i = 0, prime = 2, factor;
+
+ function frac(x) { return (x-Math.floor(x)) * 0x100000000 | 0; }
+ function frac2(x) { return (x-Math.floor(x)) * 0x10000000000 & 0xff; }
+
+ outer: for (; i<80; prime++) {
+ for (factor=2; factor*factor <= prime; factor++) {
+ if (prime % factor === 0) {
+ // not a prime
+ continue outer;
+ }
+ }
+
+ if (i<8) {
+ this._init[i*2] = frac(Math.pow(prime, 1/2));
+ this._init[i*2+1] = (frac2(Math.pow(prime, 1/2)) << 24) | this._initr[i];
+ }
+ this._key[i*2] = frac(Math.pow(prime, 1/3));
+ this._key[i*2+1] = (frac2(Math.pow(prime, 1/3)) << 24) | this._keyr[i];
+ i++;
+ }
+ },
+
+ /**
+ * Perform one cycle of SHA-512.
+ * @param {bitArray} words one block of words.
+ * @private
+ */
+ _block:function (words) {
+ var i, wrh, wrl,
+ w = words.slice(0),
+ h = this._h,
+ k = this._key,
+ h0h = h[ 0], h0l = h[ 1], h1h = h[ 2], h1l = h[ 3],
+ h2h = h[ 4], h2l = h[ 5], h3h = h[ 6], h3l = h[ 7],
+ h4h = h[ 8], h4l = h[ 9], h5h = h[10], h5l = h[11],
+ h6h = h[12], h6l = h[13], h7h = h[14], h7l = h[15];
+
+ // Working variables
+ var ah = h0h, al = h0l, bh = h1h, bl = h1l,
+ ch = h2h, cl = h2l, dh = h3h, dl = h3l,
+ eh = h4h, el = h4l, fh = h5h, fl = h5l,
+ gh = h6h, gl = h6l, hh = h7h, hl = h7l;
+
+ for (i=0; i<80; i++) {
+ // load up the input word for this round
+ if (i<16) {
+ wrh = w[i * 2];
+ wrl = w[i * 2 + 1];
+ } else {
+ // Gamma0
+ var gamma0xh = w[(i-15) * 2];
+ var gamma0xl = w[(i-15) * 2 + 1];
+ var gamma0h =
+ ((gamma0xl << 31) | (gamma0xh >>> 1)) ^
+ ((gamma0xl << 24) | (gamma0xh >>> 8)) ^
+ (gamma0xh >>> 7);
+ var gamma0l =
+ ((gamma0xh << 31) | (gamma0xl >>> 1)) ^
+ ((gamma0xh << 24) | (gamma0xl >>> 8)) ^
+ ((gamma0xh << 25) | (gamma0xl >>> 7));
+
+ // Gamma1
+ var gamma1xh = w[(i-2) * 2];
+ var gamma1xl = w[(i-2) * 2 + 1];
+ var gamma1h =
+ ((gamma1xl << 13) | (gamma1xh >>> 19)) ^
+ ((gamma1xh << 3) | (gamma1xl >>> 29)) ^
+ (gamma1xh >>> 6);
+ var gamma1l =
+ ((gamma1xh << 13) | (gamma1xl >>> 19)) ^
+ ((gamma1xl << 3) | (gamma1xh >>> 29)) ^
+ ((gamma1xh << 26) | (gamma1xl >>> 6));
+
+ // Shortcuts
+ var wr7h = w[(i-7) * 2];
+ var wr7l = w[(i-7) * 2 + 1];
+
+ var wr16h = w[(i-16) * 2];
+ var wr16l = w[(i-16) * 2 + 1];
+
+ // W(round) = gamma0 + W(round - 7) + gamma1 + W(round - 16)
+ wrl = gamma0l + wr7l;
+ wrh = gamma0h + wr7h + ((wrl >>> 0) < (gamma0l >>> 0) ? 1 : 0);
+ wrl += gamma1l;
+ wrh += gamma1h + ((wrl >>> 0) < (gamma1l >>> 0) ? 1 : 0);
+ wrl += wr16l;
+ wrh += wr16h + ((wrl >>> 0) < (wr16l >>> 0) ? 1 : 0);
+ }
+
+ w[i*2] = wrh |= 0;
+ w[i*2 + 1] = wrl |= 0;
+
+ // Ch
+ var chh = (eh & fh) ^ (~eh & gh);
+ var chl = (el & fl) ^ (~el & gl);
+
+ // Maj
+ var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch);
+ var majl = (al & bl) ^ (al & cl) ^ (bl & cl);
+
+ // Sigma0
+ var sigma0h = ((al << 4) | (ah >>> 28)) ^ ((ah << 30) | (al >>> 2)) ^ ((ah << 25) | (al >>> 7));
+ var sigma0l = ((ah << 4) | (al >>> 28)) ^ ((al << 30) | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7));
+
+ // Sigma1
+ var sigma1h = ((el << 18) | (eh >>> 14)) ^ ((el << 14) | (eh >>> 18)) ^ ((eh << 23) | (el >>> 9));
+ var sigma1l = ((eh << 18) | (el >>> 14)) ^ ((eh << 14) | (el >>> 18)) ^ ((el << 23) | (eh >>> 9));
+
+ // K(round)
+ var krh = k[i*2];
+ var krl = k[i*2+1];
+
+ // t1 = h + sigma1 + ch + K(round) + W(round)
+ var t1l = hl + sigma1l;
+ var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0);
+ t1l += chl;
+ t1h += chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0);
+ t1l += krl;
+ t1h += krh + ((t1l >>> 0) < (krl >>> 0) ? 1 : 0);
+ t1l += wrl;
+ t1h += wrh + ((t1l >>> 0) < (wrl >>> 0) ? 1 : 0);
+
+ // t2 = sigma0 + maj
+ var t2l = sigma0l + majl;
+ var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0);
+
+ // Update working variables
+ hh = gh;
+ hl = gl;
+ gh = fh;
+ gl = fl;
+ fh = eh;
+ fl = el;
+ el = (dl + t1l) | 0;
+ eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0;
+ dh = ch;
+ dl = cl;
+ ch = bh;
+ cl = bl;
+ bh = ah;
+ bl = al;
+ al = (t1l + t2l) | 0;
+ ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0;
+ }
+
+ // Intermediate hash
+ h0l = h[1] = (h0l + al) | 0;
+ h[0] = (h0h + ah + ((h0l >>> 0) < (al >>> 0) ? 1 : 0)) | 0;
+ h1l = h[3] = (h1l + bl) | 0;
+ h[2] = (h1h + bh + ((h1l >>> 0) < (bl >>> 0) ? 1 : 0)) | 0;
+ h2l = h[5] = (h2l + cl) | 0;
+ h[4] = (h2h + ch + ((h2l >>> 0) < (cl >>> 0) ? 1 : 0)) | 0;
+ h3l = h[7] = (h3l + dl) | 0;
+ h[6] = (h3h + dh + ((h3l >>> 0) < (dl >>> 0) ? 1 : 0)) | 0;
+ h4l = h[9] = (h4l + el) | 0;
+ h[8] = (h4h + eh + ((h4l >>> 0) < (el >>> 0) ? 1 : 0)) | 0;
+ h5l = h[11] = (h5l + fl) | 0;
+ h[10] = (h5h + fh + ((h5l >>> 0) < (fl >>> 0) ? 1 : 0)) | 0;
+ h6l = h[13] = (h6l + gl) | 0;
+ h[12] = (h6h + gh + ((h6l >>> 0) < (gl >>> 0) ? 1 : 0)) | 0;
+ h7l = h[15] = (h7l + hl) | 0;
+ h[14] = (h7h + hh + ((h7l >>> 0) < (hl >>> 0) ? 1 : 0)) | 0;
+ }
+};
+
+
+/** @fileOverview Javascript SHA-1 implementation.
+ *
+ * Based on the implementation in RFC 3174, method 1, and on the SJCL
+ * SHA-256 implementation.
+ *
+ * @author Quinn Slack
+ */
+
+/**
+ * Context for a SHA-1 operation in progress.
+ * @constructor
+ * @class Secure Hash Algorithm, 160 bits.
+ */
+sjcl.hash.sha1 = function (hash) {
+ if (hash) {
+ this._h = hash._h.slice(0);
+ this._buffer = hash._buffer.slice(0);
+ this._length = hash._length;
+ } else {
+ this.reset();
+ }
+};
+
+/**
+ * Hash a string or an array of words.
+ * @static
+ * @param {bitArray|String} data the data to hash.
+ * @return {bitArray} The hash value, an array of 5 big-endian words.
+ */
+sjcl.hash.sha1.hash = function (data) {
+ return (new sjcl.hash.sha1()).update(data).finalize();
+};
+
+sjcl.hash.sha1.prototype = {
+ /**
+ * The hash's block size, in bits.
+ * @constant
+ */
+ blockSize: 512,
+
+ /**
+ * Reset the hash state.
+ * @return this
+ */
+ reset:function () {
+ this._h = this._init.slice(0);
+ this._buffer = [];
+ this._length = 0;
+ return this;
+ },
+
+ /**
+ * Input several words to the hash.
+ * @param {bitArray|String} data the data to hash.
+ * @return this
+ */
+ update: function (data) {
+ if (typeof data === "string") {
+ data = sjcl.codec.utf8String.toBits(data);
+ }
+ var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data),
+ ol = this._length,
+ nl = this._length = ol + sjcl.bitArray.bitLength(data);
+ for (i = this.blockSize+ol & -this.blockSize; i <= nl;
+ i+= this.blockSize) {
+ this._block(b.splice(0,16));
+ }
+ return this;
+ },
+
+ /**
+ * Complete hashing and output the hash value.
+ * @return {bitArray} The hash value, an array of 5 big-endian words. TODO
+ */
+ finalize:function () {
+ var i, b = this._buffer, h = this._h;
+
+ // Round out and push the buffer
+ b = sjcl.bitArray.concat(b, [sjcl.bitArray.partial(1,1)]);
+ // Round out the buffer to a multiple of 16 words, less the 2 length words.
+ for (i = b.length + 2; i & 15; i++) {
+ b.push(0);
+ }
+
+ // append the length
+ b.push(Math.floor(this._length / 0x100000000));
+ b.push(this._length | 0);
+
+ while (b.length) {
+ this._block(b.splice(0,16));
+ }
+
+ this.reset();
+ return h;
+ },
+
+ /**
+ * The SHA-1 initialization vector.
+ * @private
+ */
+ _init:[0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0],
+
+ /**
+ * The SHA-1 hash key.
+ * @private
+ */
+ _key:[0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6],
+
+ /**
+ * The SHA-1 logical functions f(0), f(1), ..., f(79).
+ * @private
+ */
+ _f:function(t, b, c, d) {
+ if (t <= 19) {
+ return (b & c) | (~b & d);
+ } else if (t <= 39) {
+ return b ^ c ^ d;
+ } else if (t <= 59) {
+ return (b & c) | (b & d) | (c & d);
+ } else if (t <= 79) {
+ return b ^ c ^ d;
+ }
+ },
+
+ /**
+ * Circular left-shift operator.
+ * @private
+ */
+ _S:function(n, x) {
+ return (x << n) | (x >>> 32-n);
+ },
+
+ /**
+ * Perform one cycle of SHA-1.
+ * @param {bitArray} words one block of words.
+ * @private
+ */
+ _block:function (words) {
+ var t, tmp, a, b, c, d, e,
+ w = words.slice(0),
+ h = this._h,
+ k = this._key;
+
+ a = h[0]; b = h[1]; c = h[2]; d = h[3]; e = h[4];
+
+ for (t=0; t<=79; t++) {
+ if (t >= 16) {
+ w[t] = this._S(1, w[t-3] ^ w[t-8] ^ w[t-14] ^ w[t-16]);
+ }
+ tmp = (this._S(5, a) + this._f(t, b, c, d) + e + w[t] +
+ this._key[Math.floor(t/20)]) | 0;
+ e = d;
+ d = c;
+ c = this._S(30, b);
+ b = a;
+ a = tmp;
+ }
+
+ h[0] = (h[0]+a) |0;
+ h[1] = (h[1]+b) |0;
+ h[2] = (h[2]+c) |0;
+ h[3] = (h[3]+d) |0;
+ h[4] = (h[4]+e) |0;
+ }
+};
+/** @fileOverview CCM mode implementation.
+ *
+ * Special thanks to Roy Nicholson for pointing out a bug in our
+ * implementation.
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ */
+
+/** @namespace CTR mode with CBC MAC. */
+sjcl.mode.ccm = {
+ /** The name of the mode.
+ * @constant
+ */
+ name: "ccm",
+
+ /** Encrypt in CCM mode.
+ * @static
+ * @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.
+ * @param {bitArray} [adata=[]] The authenticated data.
+ * @param {Number} [tlen=64] the desired tag length, in bits.
+ * @return {bitArray} The encrypted data, an array of bytes.
+ */
+ encrypt: function(prf, plaintext, iv, adata, tlen) {
+ var L, i, out = plaintext.slice(0), tag, w=sjcl.bitArray, ivl = w.bitLength(iv) / 8, ol = w.bitLength(out) / 8;
+ tlen = tlen || 64;
+ adata = adata || [];
+
+ if (ivl < 7) {
+ throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");
+ }
+
+ // compute the length of the length
+ for (L=2; L<4 && ol >>> 8*L; L++) {}
+ if (L < 15 - ivl) { L = 15-ivl; }
+ iv = w.clamp(iv,8*(15-L));
+
+ // compute the tag
+ tag = sjcl.mode.ccm._computeTag(prf, plaintext, iv, adata, tlen, L);
+
+ // encrypt
+ out = sjcl.mode.ccm._ctrMode(prf, out, iv, tag, tlen, L);
+
+ return w.concat(out.data, out.tag);
+ },
+
+ /** Decrypt in CCM mode.
+ * @static
+ * @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.
+ * @param {bitArray} [[]] adata The authenticated data.
+ * @param {Number} [64] tlen the desired tag length, in bits.
+ * @return {bitArray} The decrypted data.
+ */
+ decrypt: function(prf, ciphertext, iv, adata, tlen) {
+ tlen = tlen || 64;
+ adata = adata || [];
+ var L, i,
+ w=sjcl.bitArray,
+ ivl = w.bitLength(iv) / 8,
+ ol = w.bitLength(ciphertext),
+ out = w.clamp(ciphertext, ol - tlen),
+ tag = w.bitSlice(ciphertext, ol - tlen), tag2;
+
+
+ ol = (ol - tlen) / 8;
+
+ if (ivl < 7) {
+ throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");
+ }
+
+ // compute the length of the length
+ for (L=2; L<4 && ol >>> 8*L; L++) {}
+ if (L < 15 - ivl) { L = 15-ivl; }
+ iv = w.clamp(iv,8*(15-L));
+
+ // decrypt
+ out = sjcl.mode.ccm._ctrMode(prf, out, iv, tag, tlen, L);
+
+ // check the tag
+ tag2 = sjcl.mode.ccm._computeTag(prf, out.data, iv, adata, tlen, L);
+ if (!w.equal(out.tag, tag2)) {
+ throw new sjcl.exception.corrupt("ccm: tag doesn't match");
+ }
+
+ return out.data;
+ },
+
+ /* Compute the (unencrypted) authentication tag, according to the CCM specification
+ * @param {Object} prf The pseudorandom function.
+ * @param {bitArray} plaintext The plaintext data.
+ * @param {bitArray} iv The initialization value.
+ * @param {bitArray} adata The authenticated data.
+ * @param {Number} tlen the desired tag length, in bits.
+ * @return {bitArray} The tag, but not yet encrypted.
+ * @private
+ */
+ _computeTag: function(prf, plaintext, iv, adata, tlen, L) {
+ // compute B[0]
+ var q, mac, field = 0, offset = 24, tmp, i, macData = [], w=sjcl.bitArray, xor = w._xor4;
+
+ tlen /= 8;
+
+ // check tag length and message length
+ if (tlen % 2 || tlen < 4 || tlen > 16) {
+ throw new sjcl.exception.invalid("ccm: invalid tag length");
+ }
+
+ if (adata.length > 0xFFFFFFFF || plaintext.length > 0xFFFFFFFF) {
+ // I don't want to deal with extracting high words from doubles.
+ throw new sjcl.exception.bug("ccm: can't deal with 4GiB or more data");
+ }
+
+ // mac the flags
+ mac = [w.partial(8, (adata.length ? 1<<6 : 0) | (tlen-2) << 2 | L-1)];
+
+ // mac the iv and length
+ mac = w.concat(mac, iv);
+ mac[3] |= w.bitLength(plaintext)/8;
+ mac = prf.encrypt(mac);
+
+
+ if (adata.length) {
+ // mac the associated data. start with its length...
+ tmp = w.bitLength(adata)/8;
+ if (tmp <= 0xFEFF) {
+ macData = [w.partial(16, tmp)];
+ } else if (tmp <= 0xFFFFFFFF) {
+ macData = w.concat([w.partial(16,0xFFFE)], [tmp]);
+ } // else ...
+
+ // mac the data itself
+ macData = w.concat(macData, adata);
+ for (i=0; i bs) {
+ key = Hash.hash(key);
+ }
+
+ for (i=0; iUse sjcl.random as a singleton for this class!