diff options
| author | Zaran <zaran.krleza@gmail.com> | 2012-01-30 15:05:38 -0800 |
|---|---|---|
| committer | Zaran <zaran.krleza@gmail.com> | 2012-01-30 15:38:31 -0800 |
| commit | 49581200ca11dbca47c57675f0a036edaa8c185c (patch) | |
| tree | b8e07f81552029863315abdfb01721c0ee596741 /webclient/lib/sjcl.js | |
| parent | 3131e0333db40b7e9b029abe42dd7a539f299723 (diff) | |
| download | alias-49581200ca11dbca47c57675f0a036edaa8c185c.tar.gz | |
Create javascriptmvc application. Remove files which are now tracked in the submodules.
Diffstat (limited to 'webclient/lib/sjcl.js')
| -rw-r--r-- | webclient/lib/sjcl.js | 1915 |
1 files changed, 0 insertions, 1915 deletions
diff --git a/webclient/lib/sjcl.js b/webclient/lib/sjcl.js deleted file mode 100644 index 9730862..0000000 --- a/webclient/lib/sjcl.js +++ /dev/null @@ -1,1915 +0,0 @@ -/** @fileOverview Javascript cryptography implementation. - * - * Crush to remove comments, shorten variable names and - * generally reduce transmission size. - * - * @author Emily Stark - * @author Mike Hamburg - * @author Dan Boneh - */ - -"use strict"; -/*jslint indent: 2, bitwise: false, nomen: false, plusplus: false, white: false, regexp: false */ -/*global document, window, escape, unescape */ - -/** @namespace The Stanford Javascript Crypto Library, top-level namespace. */ -var sjcl = { - /** @namespace Symmetric ciphers. */ - cipher: {}, - - /** @namespace Hash functions. Right now only SHA256 is implemented. */ - hash: {}, - - /** @namespace Key exchange functions. Right now only SRP is implemented. */ - keyexchange: {}, - - /** @namespace Block cipher modes of operation. */ - mode: {}, - - /** @namespace Miscellaneous. HMAC and PBKDF2. */ - misc: {}, - - /** - * @namespace Bit array encoders and decoders. - * - * @description - * The members of this namespace are functions which translate between - * SJCL's bitArrays and other objects (usually strings). Because it - * isn't always clear which direction is encoding and which is decoding, - * the method names are "fromBits" and "toBits". - */ - codec: {}, - - /** @namespace Exceptions. */ - exception: { - /** @class Ciphertext is corrupt. */ - corrupt: function(message) { - this.toString = function() { return "CORRUPT: "+this.message; }; - this.message = message; - }, - - /** @class Invalid parameter. */ - invalid: function(message) { - this.toString = function() { return "INVALID: "+this.message; }; - this.message = message; - }, - - /** @class Bug or missing feature in SJCL. */ - bug: function(message) { - this.toString = function() { return "BUG: "+this.message; }; - this.message = message; - }, - - /** @class Something isn't ready. */ - notReady: function(message) { - this.toString = function() { return "NOT READY: "+this.message; }; - this.message = message; - } - } -}; - -if(typeof module != 'undefined' && module.exports){ - module.exports = sjcl; -} -/** @fileOverview Low-level AES implementation. - * - * This file contains a low-level implementation of AES, optimized for - * size and for efficiency on several browsers. It is based on - * OpenSSL's aes_core.c, a public-domain implementation by Vincent - * Rijmen, Antoon Bosselaers and Paulo Barreto. - * - * 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. - * - * @author Emily Stark - * @author Mike Hamburg - * @author Dan Boneh - */ - -/** - * Schedule out an AES key for both encryption and decryption. This - * is a low-level class. Use a cipher mode to do bulk encryption. - * - * @constructor - * @param {Array} key The key as an array of 4, 6 or 8 words. - * - * @class Advanced Encryption Standard (low-level interface) - */ -sjcl.cipher.aes = function (key) { - if (!this._tables[0][0][0]) { - this._precompute(); - } - - var i, j, tmp, - encKey, decKey, - sbox = this._tables[0][4], decTable = this._tables[1], - keyLen = key.length, rcon = 1; - - if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) { - throw new sjcl.exception.invalid("invalid aes key size"); - } - - this._key = [encKey = key.slice(0), decKey = []]; - - // schedule encryption keys - for (i = keyLen; i < 4 * keyLen + 28; i++) { - tmp = encKey[i-1]; - - // apply sbox - if (i%keyLen === 0 || (keyLen === 8 && i%keyLen === 4)) { - tmp = sbox[tmp>>>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 - * <p> - * These objects are the currency accepted by SJCL's crypto functions. - * </p> - * - * <p> - * 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. - * </p> - * - * <p> - * Because bitwise ops clear this out-of-band data, these arrays can be passed - * to ciphers like AES which want arrays of words. - * </p> - */ -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<<blength) - 1); - }, - - /** - * Concatenate two bit arrays. - * @param {bitArray} a1 The first array. - * @param {bitArray} a2 The second array. - * @return {bitArray} The concatenation of a1 and a2. - */ - concat: function (a1, a2) { - if (a1.length === 0 || a2.length === 0) { - return a1.concat(a2); - } - - var out, i, last = a1[a1.length-1], shift = sjcl.bitArray.getPartial(last); - if (shift === 32) { - return a1.concat(a2); - } else { - return sjcl.bitArray._shiftRight(a2, shift, last|0, a1.slice(0,a1.length-1)); - } - }, - - /** - * Find the length of an array of bits. - * @param {bitArray} a The array. - * @return {Number} The length of a, in bits. - */ - bitLength: function (a) { - var l = a.length, x; - if (l === 0) { return 0; } - x = a[l - 1]; - return (l-1) * 32 + sjcl.bitArray.getPartial(x); - }, - - /** - * Truncate an array. - * @param {bitArray} a The array. - * @param {Number} len The length to truncate to, in bits. - * @return {bitArray} A new array, truncated to len bits. - */ - clamp: function (a, len) { - if (a.length * 32 < len) { return a; } - a = a.slice(0, Math.ceil(len / 32)); - var l = a.length; - len = len & 31; - if (l > 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<a.length; i++) { - x |= a[i]^b[i]; - } - return (x === 0); - }, - - /** Shift an array right. - * @param {bitArray} a The array to shift. - * @param {Number} shift The number of bits to shift. - * @param {Number} [carry=0] A byte to carry in - * @param {bitArray} [out=[]] An array to prepend to the output. - * @private - */ - _shiftRight: function (a, shift, carry, out) { - var i, last2=0, shift2; - if (out === undefined) { out = []; } - - for (; shift >= 32; shift -= 32) { - out.push(carry); - carry = 0; - } - if (shift === 0) { - return out.concat(a); - } - - for (i=0; i<a.length; i++) { - out.push(carry | a[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<bl/8; i++) { - if ((i&3) === 0) { - tmp = arr[i/4]; - } - out += String.fromCharCode(tmp >>> 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<str.length; i++) { - tmp = tmp << 8 | str.charCodeAt(i); - if ((i&3) === 3) { - out.push(tmp); - tmp = 0; - } - } - if (i&3) { - out.push(sjcl.bitArray.partial(8*(i&3), tmp)); - } - return out; - } -}; -/** @fileOverview Bit array codec implementations. - * - * @author Emily Stark - * @author Mike Hamburg - * @author Dan Boneh - */ - -/** @namespace Hexadecimal */ -sjcl.codec.hex = { - /** Convert from a bitArray to a hex string. */ - fromBits: function (arr) { - var out = "", i, x; - for (i=0; i<arr.length; i++) { - out += ((arr[i]|0)+0xF00000000000).toString(16).substr(4); - } - return out.substr(0, sjcl.bitArray.bitLength(arr)/4);//.replace(/(.{8})/g, "$1 "); - }, - /** Convert from a hex string to a bitArray. */ - toBits: function (str) { - var i, out=[], len; - str = str.replace(/\s|0x/g, ""); - len = str.length; - str = str + "00000000"; - for (i=0; i<str.length; i+=8) { - out.push(parseInt(str.substr(i,8),16)^0); - } - return sjcl.bitArray.clamp(out, len*4); - } -}; - -/** @fileOverview Bit array codec implementations. - * - * @author Emily Stark - * @author Mike Hamburg - * @author Dan Boneh - */ - -/** @namespace Base64 encoding/decoding */ -sjcl.codec.base64 = { - /** The base64 alphabet. - * @private - */ - _chars: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", - - /** Convert from a bitArray to a base64 string. */ - fromBits: function (arr, _noEquals, _url) { - var out = "", i, bits=0, c = sjcl.codec.base64._chars, ta=0, bl = sjcl.bitArray.bitLength(arr); - if (_url) c = c.substr(0,62) + '-_'; - for (i=0; out.length * 6 < bl; ) { - out += c.charAt((ta ^ arr[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<str.length; i++) { - x = c.indexOf(str.charAt(i)); - if (x < 0) { - throw new sjcl.exception.invalid("this isn't base64!"); - } - if (bits > 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 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 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 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<macData.length; i += 4) { - mac = prf.encrypt(xor(mac, macData.slice(i,i+4).concat([0,0,0]))); - } - } - - // mac the plaintext - for (i=0; i<plaintext.length; i+=4) { - mac = prf.encrypt(xor(mac, plaintext.slice(i,i+4).concat([0,0,0]))); - } - - return w.clamp(mac, tlen * 8); - }, - - /** CCM CTR mode. - * Encrypt or decrypt data and tag with the prf in CCM-style CTR mode. - * May mutate its arguments. - * @param {Object} prf The PRF. - * @param {bitArray} data The data to be encrypted or decrypted. - * @param {bitArray} iv The initialization vector. - * @param {bitArray} tag The authentication tag. - * @param {Number} tlen The length of th etag, in bits. - * @param {Number} L The CCM L value. - * @return {Object} An object with data and tag, the en/decryption of data and tag values. - * @private - */ - _ctrMode: function(prf, data, iv, tag, tlen, L) { - var enc, i, w=sjcl.bitArray, xor = w._xor4, ctr, b, l = data.length, bl=w.bitLength(data); - - // start the ctr - ctr = w.concat([w.partial(8,L-1)],iv).concat([0,0,0]).slice(0,4); - - // en/decrypt the tag - tag = w.bitSlice(xor(tag,prf.encrypt(ctr)), 0, tlen); - - // en/decrypt the data - if (!l) { return {tag:tag, data:[]}; } - - for (i=0; i<l; i+=4) { - ctr[3]++; - enc = prf.encrypt(ctr); - data[i] ^= enc[0]; - data[i+1] ^= enc[1]; - data[i+2] ^= enc[2]; - data[i+3] ^= enc[3]; - } - return { tag:tag, data:w.clamp(data,bl) }; - } -}; -/** @fileOverview OCB 2.0 implementation - * - * @author Emily Stark - * @author Mike Hamburg - * @author Dan Boneh - */ - -/** @namespace - * Phil Rogaway's Offset CodeBook mode, version 2.0. - * May be covered by US and international patents. - * - * @author Emily Stark - * @author Mike Hamburg - * @author Dan Boneh - */ -sjcl.mode.ocb2 = { - /** The name of the mode. - * @constant - */ - name: "ocb2", - - /** Encrypt in OCB mode, version 2.0. - * @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. - * @param {Number} [tlen=64] the desired tag length, in bits. - * @param [false] premac 1 if the authentication data is pre-macced with PMAC. - * @return The encrypted data, an array of bytes. - * @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits. - */ - encrypt: function(prp, plaintext, iv, adata, tlen, premac) { - if (sjcl.bitArray.bitLength(iv) !== 128) { - throw new sjcl.exception.invalid("ocb iv must be 128 bits"); - } - var i, - times2 = sjcl.mode.ocb2._times2, - w = sjcl.bitArray, - xor = w._xor4, - checksum = [0,0,0,0], - delta = times2(prp.encrypt(iv)), - bi, bl, - output = [], - pad; - - adata = adata || []; - tlen = tlen || 64; - - for (i=0; i+4 < plaintext.length; i+=4) { - /* Encrypt a non-final block */ - bi = plaintext.slice(i,i+4); - checksum = xor(checksum, bi); - output = output.concat(xor(delta,prp.encrypt(xor(delta, bi)))); - delta = times2(delta); - } - - /* Chop out the final block */ - bi = plaintext.slice(i); - bl = w.bitLength(bi); - pad = prp.encrypt(xor(delta,[0,0,0,bl])); - bi = w.clamp(xor(bi.concat([0,0,0]),pad), bl); - - /* Checksum the final block, and finalize the checksum */ - checksum = xor(checksum,xor(bi.concat([0,0,0]),pad)); - checksum = prp.encrypt(xor(checksum,xor(delta,times2(delta)))); - - /* MAC the header */ - if (adata.length) { - checksum = xor(checksum, premac ? adata : sjcl.mode.ocb2.pmac(prp, adata)); - } - - return output.concat(w.concat(bi, w.clamp(checksum, tlen))); - }, - - /** Decrypt in OCB 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. - * @param {Number} [tlen=64] the desired tag length, in bits. - * @param {boolean} [premac=false] true if the authentication data is pre-macced with PMAC. - * @return The decrypted data, an array of bytes. - * @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits. - * @throws {sjcl.exception.corrupt} if if the message is corrupt. - */ - decrypt: function(prp, ciphertext, iv, adata, tlen, premac) { - if (sjcl.bitArray.bitLength(iv) !== 128) { - throw new sjcl.exception.invalid("ocb iv must be 128 bits"); - } - tlen = tlen || 64; - var i, - times2 = sjcl.mode.ocb2._times2, - w = sjcl.bitArray, - xor = w._xor4, - checksum = [0,0,0,0], - delta = times2(prp.encrypt(iv)), - bi, bl, - len = sjcl.bitArray.bitLength(ciphertext) - tlen, - output = [], - pad; - - adata = adata || []; - - for (i=0; i+4 < len/32; i+=4) { - /* Decrypt a non-final block */ - bi = xor(delta, prp.decrypt(xor(delta, ciphertext.slice(i,i+4)))); - checksum = xor(checksum, bi); - output = output.concat(bi); - delta = times2(delta); - } - - /* Chop out and decrypt the final block */ - bl = len-i*32; - pad = prp.encrypt(xor(delta,[0,0,0,bl])); - bi = xor(pad, w.clamp(ciphertext.slice(i),bl).concat([0,0,0])); - - /* Checksum the final block, and finalize the checksum */ - checksum = xor(checksum, bi); - checksum = prp.encrypt(xor(checksum, xor(delta, times2(delta)))); - - /* MAC the header */ - if (adata.length) { - checksum = xor(checksum, premac ? adata : sjcl.mode.ocb2.pmac(prp, adata)); - } - - if (!w.equal(w.clamp(checksum, tlen), w.bitSlice(ciphertext, len))) { - throw new sjcl.exception.corrupt("ocb: tag doesn't match"); - } - - return output.concat(w.clamp(bi,bl)); - }, - - /** PMAC authentication for OCB associated data. - * @param {Object} prp The block cipher. It must have a block size of 16 bytes. - * @param {bitArray} adata The authenticated data. - */ - pmac: function(prp, adata) { - var i, - times2 = sjcl.mode.ocb2._times2, - w = sjcl.bitArray, - xor = w._xor4, - checksum = [0,0,0,0], - delta = prp.encrypt([0,0,0,0]), - bi; - - delta = xor(delta,times2(times2(delta))); - - for (i=0; i+4<adata.length; i+=4) { - delta = times2(delta); - checksum = xor(checksum, prp.encrypt(xor(delta, adata.slice(i,i+4)))); - } - - bi = adata.slice(i); - if (w.bitLength(bi) < 128) { - delta = xor(delta,times2(delta)); - bi = w.concat(bi,[0x80000000|0,0,0,0]); - } - checksum = xor(checksum, bi); - return prp.encrypt(xor(times2(xor(delta,times2(delta))), checksum)); - }, - - /** Double a block of words, OCB style. - * @private - */ - _times2: function(x) { - return [x[0]<<1 ^ x[1]>>>31, - x[1]<<1 ^ x[2]>>>31, - x[2]<<1 ^ x[3]>>>31, - x[3]<<1 ^ (x[0]>>>31)*0x87]; - } -}; -/** @fileOverview HMAC implementation. - * - * @author Emily Stark - * @author Mike Hamburg - * @author Dan Boneh - */ - -/** HMAC with the specified hash function. - * @constructor - * @param {bitArray} key the key for HMAC. - * @param {Object} [hash=sjcl.hash.sha256] The hash function to use. - */ -sjcl.misc.hmac = function (key, Hash) { - this._hash = Hash = Hash || sjcl.hash.sha256; - var exKey = [[],[]], i, - bs = Hash.prototype.blockSize / 32; - this._baseHash = [new Hash(), new Hash()]; - - if (key.length > bs) { - key = Hash.hash(key); - } - - for (i=0; i<bs; i++) { - exKey[0][i] = key[i]^0x36363636; - exKey[1][i] = key[i]^0x5C5C5C5C; - } - - this._baseHash[0].update(exKey[0]); - this._baseHash[1].update(exKey[1]); -}; - -/** HMAC with the specified hash function. Also called encrypt since it's a prf. - * @param {bitArray|String} data The data to mac. - * @param {Codec} [encoding] the encoding function to use. - */ -sjcl.misc.hmac.prototype.encrypt = sjcl.misc.hmac.prototype.mac = function (data, encoding) { - var w = new (this._hash)(this._baseHash[0]).update(data, encoding).finalize(); - return new (this._hash)(this._baseHash[1]).update(w).finalize(); -}; - -/** @fileOverview Password-based key-derivation function, version 2.0. - * - * @author Emily Stark - * @author Mike Hamburg - * @author Dan Boneh - */ - -/** Password-Based Key-Derivation Function, version 2.0. - * - * Generate keys from passwords using PBKDF2-HMAC-SHA256. - * - * This is the method specified by RSA's PKCS #5 standard. - * - * @param {bitArray|String} password The password. - * @param {bitArray} salt The salt. Should have lots of entropy. - * @param {Number} [count=1000] The number of iterations. Higher numbers make the function slower but more secure. - * @param {Number} [length] The length of the derived key. Defaults to the - output size of the hash function. - * @param {Object} [Prff=sjcl.misc.hmac] The pseudorandom function family. - * @return {bitArray} the derived key. - */ -sjcl.misc.pbkdf2 = function (password, salt, count, length, Prff) { - count = count || 1000; - - if (length < 0 || count < 0) { - throw sjcl.exception.invalid("invalid params to pbkdf2"); - } - - if (typeof password === "string") { - password = sjcl.codec.utf8String.toBits(password); - } - - Prff = Prff || sjcl.misc.hmac; - - var prf = new Prff(password), - u, ui, i, j, k, out = [], b = sjcl.bitArray; - - for (k = 1; 32 * out.length < (length || 1); k++) { - u = ui = prf.encrypt(b.concat(salt,[k])); - - for (i=1; i<count; i++) { - ui = prf.encrypt(ui); - for (j=0; j<ui.length; j++) { - u[j] ^= ui[j]; - } - } - - out = out.concat(u); - } - - if (length) { out = b.clamp(out, length); } - - return out; -}; -/** @fileOverview Random number generator. - * - * @author Emily Stark - * @author Mike Hamburg - * @author Dan Boneh - */ - -/** @namespace Random number generator - * - * @description - * <p> - * This random number generator is a derivative of Ferguson and Schneier's - * generator Fortuna. It collects entropy from various events into several - * pools, implemented by streaming SHA-256 instances. It differs from - * ordinary Fortuna in a few ways, though. - * </p> - * - * <p> - * Most importantly, it has an entropy estimator. This is present because - * there is a strong conflict here between making the generator available - * as soon as possible, and making sure that it doesn't "run on empty". - * In Fortuna, there is a saved state file, and the system is likely to have - * time to warm up. - * </p> - * - * <p> - * Second, because users are unlikely to stay on the page for very long, - * and to speed startup time, the number of pools increases logarithmically: - * a new pool is created when the previous one is actually used for a reseed. - * This gives the same asymptotic guarantees as Fortuna, but gives more - * entropy to early reseeds. - * </p> - * - * <p> - * The entire mechanism here feels pretty klunky. Furthermore, there are - * several improvements that should be made, including support for - * dedicated cryptographic functions that may be present in some browsers; - * state files in local storage; cookies containing randomness; etc. So - * look for improvements in future versions. - * </p> - */ -sjcl.random = { - /** Generate several random words, and return them in an array - * @param {Number} nwords The number of words to generate. - */ - randomWords: function (nwords, paranoia) { - var out = [], i, readiness = this.isReady(paranoia), g; - - if (readiness === this._NOT_READY) { - throw new sjcl.exception.notReady("generator isn't seeded"); - } else if (readiness & this._REQUIRES_RESEED) { - this._reseedFromPools(!(readiness & this._READY)); - } - - for (i=0; i<nwords; i+= 4) { - if ((i+1) % this._MAX_WORDS_PER_BURST === 0) { - this._gate(); - } - - g = this._gen4words(); - out.push(g[0],g[1],g[2],g[3]); - } - this._gate(); - - return out.slice(0,nwords); - }, - - setDefaultParanoia: function (paranoia) { - this._defaultParanoia = paranoia; - }, - - /** - * Add entropy to the pools. - * @param data The entropic value. Should be a 32-bit integer, array of 32-bit integers, or string - * @param {Number} estimatedEntropy The estimated entropy of data, in bits - * @param {String} source The source of the entropy, eg "mouse" - */ - addEntropy: function (data, estimatedEntropy, source) { - source = source || "user"; - - var id, - i, ty = 0, tmp, - t = (new Date()).valueOf(), - robin = this._robins[source], - oldReady = this.isReady(); - - id = this._collectorIds[source]; - if (id === undefined) { id = this._collectorIds[source] = this._collectorIdNext ++; } - - if (robin === undefined) { robin = this._robins[source] = 0; } - this._robins[source] = ( this._robins[source] + 1 ) % this._pools.length; - - switch(typeof(data)) { - - case "number": - data=[data]; - ty=1; - break; - - case "object": - if (estimatedEntropy === undefined) { - /* horrible entropy estimator */ - estimatedEntropy = 0; - for (i=0; i<data.length; i++) { - tmp= data[i]; - while (tmp>0) { - estimatedEntropy++; - tmp = tmp >>> 1; - } - } - } - this._pools[robin].update([id,this._eventId++,ty||2,estimatedEntropy,t,data.length].concat(data)); - break; - - case "string": - if (estimatedEntropy === undefined) { - /* English text has just over 1 bit per character of entropy. - * But this might be HTML or something, and have far less - * entropy than English... Oh well, let's just say one bit. - */ - estimatedEntropy = data.length; - } - this._pools[robin].update([id,this._eventId++,3,estimatedEntropy,t,data.length]); - this._pools[robin].update(data); - break; - - default: - - throw new sjcl.exception.bug("random: addEntropy only supports number, array or string"); - } - - /* record the new strength */ - this._poolEntropy[robin] += estimatedEntropy; - this._poolStrength += estimatedEntropy; - - /* fire off events */ - if (oldReady === this._NOT_READY) { - if (this.isReady() !== this._NOT_READY) { - this._fireEvent("seeded", Math.max(this._strength, this._poolStrength)); - } - this._fireEvent("progress", this.getProgress()); - } - }, - - /** Is the generator ready? */ - isReady: function (paranoia) { - var entropyRequired = this._PARANOIA_LEVELS[ (paranoia !== undefined) ? paranoia : this._defaultParanoia ]; - - if (this._strength && this._strength >= entropyRequired) { - return (this._poolEntropy[0] > this._BITS_PER_RESEED && (new Date()).valueOf() > this._nextReseed) ? - this._REQUIRES_RESEED | this._READY : - this._READY; - } else { - return (this._poolStrength >= entropyRequired) ? - this._REQUIRES_RESEED | this._NOT_READY : - this._NOT_READY; - } - }, - - /** Get the generator's progress toward readiness, as a fraction */ - getProgress: function (paranoia) { - var entropyRequired = this._PARANOIA_LEVELS[ paranoia ? paranoia : this._defaultParanoia ]; - - if (this._strength >= entropyRequired) { - return 1.0; - } else { - return (this._poolStrength > entropyRequired) ? - 1.0 : - this._poolStrength / entropyRequired; - } - }, - - /** start the built-in entropy collectors */ - startCollectors: function () { - if (this._collectorsStarted) { return; } - - if (window.addEventListener) { - window.addEventListener("load", this._loadTimeCollector, false); - window.addEventListener("mousemove", this._mouseCollector, false); - } else if (document.attachEvent) { - document.attachEvent("onload", this._loadTimeCollector); - document.attachEvent("onmousemove", this._mouseCollector); - } - else { - throw new sjcl.exception.bug("can't attach event"); - } - - this._collectorsStarted = true; - }, - - /** stop the built-in entropy collectors */ - stopCollectors: function () { - if (!this._collectorsStarted) { return; } - - if (window.removeEventListener) { - window.removeEventListener("load", this._loadTimeCollector, false); - window.removeEventListener("mousemove", this._mouseCollector, false); - } else if (window.detachEvent) { - window.detachEvent("onload", this._loadTimeCollector); - window.detachEvent("onmousemove", this._mouseCollector); - } - this._collectorsStarted = false; - }, - - /* use a cookie to store entropy. - useCookie: function (all_cookies) { - throw new sjcl.exception.bug("random: useCookie is unimplemented"); - },*/ - - /** add an event listener for progress or seeded-ness. */ - addEventListener: function (name, callback) { - this._callbacks[name][this._callbackI++] = callback; - }, - - /** remove an event listener for progress or seeded-ness */ - removeEventListener: function (name, cb) { - var i, j, cbs=this._callbacks[name], jsTemp=[]; - - /* I'm not sure if this is necessary; in C++, iterating over a - * collection and modifying it at the same time is a no-no. - */ - - for (j in cbs) { - if (cbs.hasOwnProperty(j) && cbs[j] === cb) { - jsTemp.push(j); - } - } - - for (i=0; i<jsTemp.length; i++) { - j = jsTemp[i]; - delete cbs[j]; - } - }, - - /* private */ - _pools : [new sjcl.hash.sha256()], - _poolEntropy : [0], - _reseedCount : 0, - _robins : {}, - _eventId : 0, - - _collectorIds : {}, - _collectorIdNext : 0, - - _strength : 0, - _poolStrength : 0, - _nextReseed : 0, - _key : [0,0,0,0,0,0,0,0], - _counter : [0,0,0,0], - _cipher : undefined, - _defaultParanoia : 6, - - /* event listener stuff */ - _collectorsStarted : false, - _callbacks : {progress: {}, seeded: {}}, - _callbackI : 0, - - /* constants */ - _NOT_READY : 0, - _READY : 1, - _REQUIRES_RESEED : 2, - - _MAX_WORDS_PER_BURST : 65536, - _PARANOIA_LEVELS : [0,48,64,96,128,192,256,384,512,768,1024], - _MILLISECONDS_PER_RESEED : 30000, - _BITS_PER_RESEED : 80, - - /** Generate 4 random words, no reseed, no gate. - * @private - */ - _gen4words: function () { - for (var i=0; i<4; i++) { - this._counter[i] = this._counter[i]+1 | 0; - if (this._counter[i]) { break; } - } - return this._cipher.encrypt(this._counter); - }, - - /* Rekey the AES instance with itself after a request, or every _MAX_WORDS_PER_BURST words. - * @private - */ - _gate: function () { - this._key = this._gen4words().concat(this._gen4words()); - this._cipher = new sjcl.cipher.aes(this._key); - }, - - /** Reseed the generator with the given words - * @private - */ - _reseed: function (seedWords) { - this._key = sjcl.hash.sha256.hash(this._key.concat(seedWords)); - this._cipher = new sjcl.cipher.aes(this._key); - for (var i=0; i<4; i++) { - this._counter[i] = this._counter[i]+1 | 0; - if (this._counter[i]) { break; } - } - }, - - /** reseed the data from the entropy pools - * @param full If set, use all the entropy pools in the reseed. - */ - _reseedFromPools: function (full) { - var reseedData = [], strength = 0, i; - - this._nextReseed = reseedData[0] = - (new Date()).valueOf() + this._MILLISECONDS_PER_RESEED; - - for (i=0; i<16; i++) { - /* On some browsers, this is cryptographically random. So we might - * as well toss it in the pot and stir... - */ - reseedData.push(Math.random()*0x100000000|0); - } - - for (i=0; i<this._pools.length; i++) { - reseedData = reseedData.concat(this._pools[i].finalize()); - strength += this._poolEntropy[i]; - this._poolEntropy[i] = 0; - - if (!full && (this._reseedCount & (1<<i))) { break; } - } - - /* if we used the last pool, push a new one onto the stack */ - if (this._reseedCount >= 1 << this._pools.length) { - this._pools.push(new sjcl.hash.sha256()); - this._poolEntropy.push(0); - } - - /* how strong was this reseed? */ - this._poolStrength -= strength; - if (strength > this._strength) { - this._strength = strength; - } - - this._reseedCount ++; - this._reseed(reseedData); - }, - - _mouseCollector: function (ev) { - var x = ev.x || ev.clientX || ev.offsetX, y = ev.y || ev.clientY || ev.offsetY; - sjcl.random.addEntropy([x,y], 2, "mouse"); - }, - - _loadTimeCollector: function (ev) { - var d = new Date(); - sjcl.random.addEntropy(d, 2, "loadtime"); - }, - - _fireEvent: function (name, arg) { - var j, cbs=sjcl.random._callbacks[name], cbsTemp=[]; - /* TODO: there is a race condition between removing collectors and firing them */ - - /* I'm not sure if this is necessary; in C++, iterating over a - * collection and modifying it at the same time is a no-no. - */ - - for (j in cbs) { - if (cbs.hasOwnProperty(j)) { - cbsTemp.push(cbs[j]); - } - } - - for (j=0; j<cbsTemp.length; j++) { - cbsTemp[j](arg); - } - } -}; - -(function(){ - try { - // get cryptographically strong entropy in Webkit - var ab = new Uint32Array(32); - crypto.getRandomValues(ab); - sjcl.random.addEntropy(ab, 1024, "crypto.getRandomValues"); - } catch (e) { - // no getRandomValues :-( - } -})(); -/** @fileOverview Convenince functions centered around JSON encapsulation. - * - * @author Emily Stark - * @author Mike Hamburg - * @author Dan Boneh - */ - - /** @namespace JSON encapsulation */ - sjcl.json = { - /** Default values for encryption */ - defaults: { v:1, iter:1000, ks:128, ts:64, mode:"ccm", adata:"", cipher:"aes" }, - - /** Simple encryption function. - * @param {String|bitArray} password The password or key. - * @param {String} plaintext The data to encrypt. - * @param {Object} [params] The parameters including tag, iv and salt. - * @param {Object} [rp] A returned version with filled-in parameters. - * @return {String} The ciphertext. - * @throws {sjcl.exception.invalid} if a parameter is invalid. - */ - encrypt: function (password, plaintext, params, rp) { - params = params || {}; - rp = rp || {}; - - var j = sjcl.json, p = j._add({ iv: sjcl.random.randomWords(4,0) }, - j.defaults), tmp, prp; - j._add(p, params); - if (typeof p.salt === "string") { - p.salt = sjcl.codec.base64.toBits(p.salt); - } - if (typeof p.iv === "string") { - p.iv = sjcl.codec.base64.toBits(p.iv); - } - - if (!sjcl.mode[p.mode] || - !sjcl.cipher[p.cipher] || - (typeof password === "string" && p.iter <= 100) || - (p.ts !== 64 && p.ts !== 96 && p.ts !== 128) || - (p.ks !== 128 && p.ks !== 192 && p.ks !== 256) || - (p.iv.length < 2 || p.iv.length > 4)) { - throw new sjcl.exception.invalid("json encrypt: invalid parameters"); - } - - if (typeof password === "string") { - tmp = sjcl.misc.cachedPbkdf2(password, p); - password = tmp.key.slice(0,p.ks/32); - p.salt = tmp.salt; - } - if (typeof plaintext === "string") { - plaintext = sjcl.codec.utf8String.toBits(plaintext); - } - prp = new sjcl.cipher[p.cipher](password); - - /* return the json data */ - j._add(rp, p); - rp.key = password; - - /* do the encryption */ - p.ct = sjcl.mode[p.mode].encrypt(prp, plaintext, p.iv, p.adata, p.ts); - - return j.encode(j._subtract(p, j.defaults)); - }, - - /** Simple decryption function. - * @param {String|bitArray} password The password or key. - * @param {String} ciphertext The ciphertext to decrypt. - * @param {Object} [params] Additional non-default parameters. - * @param {Object} [rp] A returned object with filled parameters. - * @return {String} The plaintext. - * @throws {sjcl.exception.invalid} if a parameter is invalid. - * @throws {sjcl.exception.corrupt} if the ciphertext is corrupt. - */ - decrypt: function (password, ciphertext, params, rp) { - params = params || {}; - rp = rp || {}; - - var j = sjcl.json, p = j._add(j._add(j._add({},j.defaults),j.decode(ciphertext)), params, true), ct, tmp, prp; - if (typeof p.salt === "string") { - p.salt = sjcl.codec.base64.toBits(p.salt); - } - if (typeof p.iv === "string") { - p.iv = sjcl.codec.base64.toBits(p.iv); - } - - if (!sjcl.mode[p.mode] || - !sjcl.cipher[p.cipher] || - (typeof password === "string" && p.iter <= 100) || - (p.ts !== 64 && p.ts !== 96 && p.ts !== 128) || - (p.ks !== 128 && p.ks !== 192 && p.ks !== 256) || - (!p.iv) || - (p.iv.length < 2 || p.iv.length > 4)) { - throw new sjcl.exception.invalid("json decrypt: invalid parameters"); - } - - if (typeof password === "string") { - tmp = sjcl.misc.cachedPbkdf2(password, p); - password = tmp.key.slice(0,p.ks/32); - p.salt = tmp.salt; - } - prp = new sjcl.cipher[p.cipher](password); - - /* do the decryption */ - ct = sjcl.mode[p.mode].decrypt(prp, p.ct, p.iv, p.adata, p.ts); - - /* return the json data */ - j._add(rp, p); - rp.key = password; - - return sjcl.codec.utf8String.fromBits(ct); - }, - - /** Encode a flat structure into a JSON string. - * @param {Object} obj The structure to encode. - * @return {String} A JSON string. - * @throws {sjcl.exception.invalid} if obj has a non-alphanumeric property. - * @throws {sjcl.exception.bug} if a parameter has an unsupported type. - */ - encode: function (obj) { - var i, out='{', comma=''; - for (i in obj) { - if (obj.hasOwnProperty(i)) { - if (!i.match(/^[a-z0-9]+$/i)) { - throw new sjcl.exception.invalid("json encode: invalid property name"); - } - out += comma + '"' + i + '"' + ':'; - comma = ','; - - switch (typeof obj[i]) { - case 'number': - case 'boolean': - out += obj[i]; - break; - - case 'string': - out += '"' + escape(obj[i]) + '"'; - break; - - case 'object': - out += '"' + sjcl.codec.base64.fromBits(obj[i],1) + '"'; - break; - - default: - throw new sjcl.exception.bug("json encode: unsupported type"); - } - } - } - return out+'}'; - }, - - /** Decode a simple (flat) JSON string into a structure. The ciphertext, - * adata, salt and iv will be base64-decoded. - * @param {String} str The string. - * @return {Object} The decoded structure. - * @throws {sjcl.exception.invalid} if str isn't (simple) JSON. - */ - decode: function (str) { - str = str.replace(/\s/g,''); - if (!str.match(/^\{.*\}$/)) { - throw new sjcl.exception.invalid("json decode: this isn't json!"); - } - var a = str.replace(/^\{|\}$/g, '').split(/,/), out={}, i, m; - for (i=0; i<a.length; i++) { - if (!(m=a[i].match(/^(?:(["']?)([a-z][a-z0-9]*)\1):(?:(\d+)|"([a-z0-9+\/%*_.@=\-]*)")$/i))) { - throw new sjcl.exception.invalid("json decode: this isn't json!"); - } - if (m[3]) { - out[m[2]] = parseInt(m[3],10); - } else { - out[m[2]] = m[2].match(/^(ct|salt|iv)$/) ? sjcl.codec.base64.toBits(m[4]) : unescape(m[4]); - } - } - return out; - }, - - /** Insert all elements of src into target, modifying and returning target. - * @param {Object} target The object to be modified. - * @param {Object} src The object to pull data from. - * @param {boolean} [requireSame=false] If true, throw an exception if any field of target differs from corresponding field of src. - * @return {Object} target. - * @private - */ - _add: function (target, src, requireSame) { - if (target === undefined) { target = {}; } - if (src === undefined) { return target; } - var i; - for (i in src) { - if (src.hasOwnProperty(i)) { - if (requireSame && target[i] !== undefined && target[i] !== src[i]) { - throw new sjcl.exception.invalid("required parameter overridden"); - } - target[i] = src[i]; - } - } - return target; - }, - - /** Remove all elements of minus from plus. Does not modify plus. - * @private - */ - _subtract: function (plus, minus) { - var out = {}, i; - - for (i in plus) { - if (plus.hasOwnProperty(i) && plus[i] !== minus[i]) { - out[i] = plus[i]; - } - } - - return out; - }, - - /** Return only the specified elements of src. - * @private - */ - _filter: function (src, filter) { - var out = {}, i; - for (i=0; i<filter.length; i++) { - if (src[filter[i]] !== undefined) { - out[filter[i]] = src[filter[i]]; - } - } - return out; - } -}; - -/** Simple encryption function; convenient shorthand for sjcl.json.encrypt. - * @param {String|bitArray} password The password or key. - * @param {String} plaintext The data to encrypt. - * @param {Object} [params] The parameters including tag, iv and salt. - * @param {Object} [rp] A returned version with filled-in parameters. - * @return {String} The ciphertext. - */ -sjcl.encrypt = sjcl.json.encrypt; - -/** Simple decryption function; convenient shorthand for sjcl.json.decrypt. - * @param {String|bitArray} password The password or key. - * @param {String} ciphertext The ciphertext to decrypt. - * @param {Object} [params] Additional non-default parameters. - * @param {Object} [rp] A returned object with filled parameters. - * @return {String} The plaintext. - */ -sjcl.decrypt = sjcl.json.decrypt; - -/** The cache for cachedPbkdf2. - * @private - */ -sjcl.misc._pbkdf2Cache = {}; - -/** Cached PBKDF2 key derivation. - * @param {String} The password. - * @param {Object} The derivation params (iteration count and optional salt). - * @return {Object} The derived data in key, the salt in salt. - */ -sjcl.misc.cachedPbkdf2 = function (password, obj) { - var cache = sjcl.misc._pbkdf2Cache, c, cp, str, salt, iter; - - obj = obj || {}; - iter = obj.iter || 1000; - - /* open the cache for this password and iteration count */ - cp = cache[password] = cache[password] || {}; - c = cp[iter] = cp[iter] || { firstSalt: (obj.salt && obj.salt.length) ? - obj.salt.slice(0) : sjcl.random.randomWords(2,0) }; - - salt = (obj.salt === undefined) ? c.firstSalt : obj.salt; - - c[salt] = c[salt] || sjcl.misc.pbkdf2(password, salt, obj.iter); - return { key: c[salt].slice(0), salt:salt.slice(0) }; -}; - - |
