UNPKG

nadachat

Version:

simple secure chat with end to end encyption

1,677 lines (1,463 loc) 110 kB
/** @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, module, require, Uint32Array */ /** @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: { /** @constructor Ciphertext is corrupt. */ corrupt: function(message) { this.toString = function() { return "CORRUPT: "+this.message; }; this.message = message; }, /** @constructor Invalid parameter. */ invalid: function(message) { this.toString = function() { return "INVALID: "+this.message; }; this.message = message; }, /** @constructor Bug or missing feature in SJCL. @constructor */ bug: function(message) { this.toString = function() { return "BUG: "+this.message; }; this.message = message; }, /** @constructor 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; } if (typeof define === "function") { define([], function () { return 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 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]]; }, /** byteswap a word array inplace. * (does not handle partial words) * @param {sjcl.bitArray} a word array * @return {sjcl.bitArray} byteswapped array */ byteswapM: function(a) { var i, v, m = 0xff00; for (i = 0; i < a.length; ++i) { v = a[i]; a[i] = (v >>> 24) | ((v >>> 8) & m) | ((v & m) << 8) | (v << 24); } return a; } }; /** @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; 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 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 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", _progressListeners: [], listenProgress: function (cb) { sjcl.mode.ccm._progressListeners.push(cb); }, unListenProgress: function (cb) { var index = sjcl.mode.ccm._progressListeners.indexOf(cb); if (index > -1) { sjcl.mode.ccm._progressListeners.splice(index, 1); } }, _callProgressListener: function (val) { var p = sjcl.mode.ccm._progressListeners.slice(), i; for (i = 0; i < p.length; i += 1) { p[i](val); } }, /** 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, 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, 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; }, _macAdditionalData: function (prf, adata, iv, tlen, ol, L) { var mac, tmp, i, macData = [], w=sjcl.bitArray, xor = w._xor4; // 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] |= ol; 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]))); } } return mac; }, /* 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 mac, i, 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 = sjcl.mode.ccm._macAdditionalData(prf, adata, iv, tlen, w.bitLength(plaintext)/8, L); // 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, l = data.length, bl=w.bitLength(data), n = l/50, p = n; // 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) { if (i > n) { sjcl.mode.ccm._callProgressListener(i/l); n += p; } 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 GCM mode implementation. * * @author Juho Vähä-Herttua */ /** @namespace Galois/Counter mode. */ sjcl.mode.gcm = { /** The name of the mode. * @constant */ name: "gcm", /** Encrypt in GCM 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=128] The desired tag length, in bits. * @return {bitArray} The encrypted data, an array of bytes. */ encrypt: function (prf, plaintext, iv, adata, tlen) { var out, data = plaintext.slice(0), w=sjcl.bitArray; tlen = tlen || 128; adata = adata || []; // encrypt and tag out = sjcl.mode.gcm._ctrMode(true, prf, data, adata, iv, tlen); return w.concat(out.data, out.tag); }, /** Decrypt in GCM 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} [tlen=128] The desired tag length, in bits. * @return {bitArray} The decrypted data. */ decrypt: function (prf, ciphertext, iv, adata, tlen) { var out, data = ciphertext.slice(0), tag, w=sjcl.bitArray, l=w.bitLength(data); tlen = tlen || 128; adata = adata || []; // Slice tag out of data if (tlen <= l) { tag = w.bitSlice(data, l-tlen); data = w.bitSlice(data, 0, l-tlen); } else { tag = data; data = []; } // decrypt and tag out = sjcl.mode.gcm._ctrMode(false, prf, data, adata, iv, tlen); if (!w.equal(out.tag, tag)) { throw new sjcl.exception.corrupt("gcm: tag doesn't match"); } return out.data; }, /* Compute the galois multiplication of X and Y * @private */ _galoisMultiply: function (x, y) { var i, j, xi, Zi, Vi, lsb_Vi, w=sjcl.bitArray, xor=w._xor4; Zi = [0,0,0,0]; Vi = y.slice(0); // Block size is 128 bits, run 128 times to get Z_128 for (i=0; i<128; i++) { xi = (x[Math.floor(i/32)] & (1 << (31-i%32))) !== 0; if (xi) { // Z_i+1 = Z_i ^ V_i Zi = xor(Zi, Vi); } // Store the value of LSB(V_i) lsb_Vi = (Vi[3] & 1) !== 0; // V_i+1 = V_i >> 1 for (j=3; j>0; j--) { Vi[j] = (Vi[j] >>> 1) | ((Vi[j-1]&1) << 31); } Vi[0] = Vi[0] >>> 1; // If LSB(V_i) is 1, V_i+1 = (V_i >> 1) ^ R if (lsb_Vi) { Vi[0] = Vi[0] ^ (0xe1 << 24); } } return Zi; }, _ghash: function(H, Y0, data) { var Yi, i, l = data.length; Yi = Y0.slice(0); for (i=0; i<l; i+=4) { Yi[0] ^= 0xffffffff&data[i]; Yi[1] ^= 0xffffffff&data[i+1]; Yi[2] ^= 0xffffffff&data[i+2]; Yi[3] ^= 0xffffffff&data[i+3]; Yi = sjcl.mode.gcm._galoisMultiply(Yi, H); } return Yi; }, /** GCM CTR mode. * Encrypt or decrypt data and tag with the prf in GCM-style CTR mode. * @param {Boolean} encrypt True if encrypt, false if decrypt. * @param {Object} prf The PRF. * @param {bitArray} data The data to be encrypted or decrypted. * @param {bitArray} iv The initialization vector. * @param {bitArray} adata The associated data to be tagged. * @param {Number} tlen The length of the tag, in bits. */ _ctrMode: function(encrypt, prf, data, adata, iv, tlen) { var H, J0, S0, enc, i, ctr, tag, last, l, bl, abl, ivbl, w=sjcl.bitArray; // Calculate data lengths l = data.length; bl = w.bitLength(data); abl = w.bitLength(adata); ivbl = w.bitLength(iv); // Calculate the parameters H = prf.encrypt([0,0,0,0]); if (ivbl === 96) { J0 = iv.slice(0); J0 = w.concat(J0, [1]); } else { J0 = sjcl.mode.gcm._ghash(H, [0,0,0,0], iv); J0 = sjcl.mode.gcm._ghash(H, J0, [0,0,Math.floor(ivbl/0x100000000),ivbl&0xffffffff]); } S0 = sjcl.mode.gcm._ghash(H, [0,0,0,0], adata); // Initialize ctr and tag ctr = J0.slice(0); tag = S0.slice(0); // If decrypting, calculate hash if (!encrypt) { tag = sjcl.mode.gcm._ghash(H, S0, data); } // Encrypt all the 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]; } data = w.clamp(data, bl); // If encrypting, calculate hash if (encrypt) { tag = sjcl.mode.gcm._ghash(H, S0, data); } // Calculate last block from bit lengths, ugly because bitwise operations are 32-bit last = [ Math.floor(abl/0x100000000), abl&0xffffffff, Math.floor(bl/0x100000000), bl&0xffffffff ]; // Calculate the final tag block tag = sjcl.mode.gcm._ghash(H, tag, last); enc = prf.encrypt(J0); tag[0] ^= enc[0]; tag[1] ^= enc[1]; tag[2] ^= enc[2]; tag[3] ^= enc[3]; return { tag:w.bitSlice(tag, 0, tlen), data:data }; } }; /** @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]); this._resultHash = new Hash(this._baseHash[0]); }; /** HMAC with the specified hash function. Also called encrypt since it's a prf. * @param {bitArray|String} data The data to mac. */ sjcl.misc.hmac.prototype.encrypt = sjcl.misc.hmac.prototype.mac = function (data) { if (!this._updated) { this.update(data); return this.digest(data); } else { throw new sjcl.exception.invalid("encrypt on already updated hmac called!"); } }; sjcl.misc.hmac.prototype.reset = function () { this._resultHash = new this._hash(this._baseHash[0]); this._updated = false; }; sjcl.misc.hmac.prototype.update = function (data) { this._updated = true; this._resultHash.update(data); }; sjcl.misc.hmac.prototype.digest = function () { var w = this._resultHash.finalize(), result = new (this._hash)(this._baseHash[1]).update(w).finalize(); this.reset(); return result; };/** @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|String} 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); } if (typeof salt === "string") { salt = sjcl.codec.utf8String.toBits(salt); } 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 * @author Michael Brooks */ /** @constructor * @class Random number generator * @description * <b>Use sjcl.random as a singleton for this class!</b> * <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.prng = function(defaultParanoia) { /* private */ this._pools = [new sjcl.hash.sha256()]; this._poolEntropy = [0]; this._reseedCount = 0; this._robins = {}; this._eventId = 0; this._collectorIds = {}; this._collectorIdNext = 0; this._strength = 0; this._poolStrength = 0; this._nextReseed = 0; this._key = [0,0,0,0,0,0,0,0]; this._counter = [0,0,0,0]; this._cipher = undefined; this._defaultParanoia = defaultParanoia; /* event listener stuff */ this._collectorsStarted = false; this._callbacks = {progress: {}, seeded: {}}; this._callbackI = 0; /* constants */ this._NOT_READY = 0; this._READY = 1; this._REQUIRES_RESEED = 2; this._MAX_WORDS_PER_BURST = 65536; this._PARANOIA_LEVELS = [0,48,64,96,128,192,256,384,512,768,1024]; this._MILLISECONDS_PER_RESEED = 30000; this._BITS_PER_RESEED = 80; }; sjcl.prng.prototype = { /** Generate several random words, and return them in an array. * A word consists of 32 bits (4 bytes) * @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, allowZeroParanoia) { if (paranoia === 0 && allowZeroParanoia !== "Setting paranoia=0 will ruin your security; use it only for testing") { throw "Setting paranoia=0 will ruin your security; use it only for testing"; } 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, tmp, t = (new Date()).valueOf(), robin = this._robins[source], oldReady = this.isReady(), err = 0, objName; 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": if (estimatedEntropy === undefined) { estimatedEntropy = 1; } this._pools[robin].update([id,this._eventId++,1,estimatedEntropy,t,1,data|0]); break; case "object": objName = Object.prototype.toString.call(data); if (objName === "[object Uint32Array]") { tmp = []; for (i =