padloc/packages/core/vendor/sjcl.js

916 lines
26 KiB
JavaScript

/** @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 */
/**
* The Stanford Javascript Crypto Library, top-level namespace.
* @namespace
*/
var sjcl = {
/**
* Symmetric ciphers.
* @namespace
*/
cipher: {},
/**
* Hash functions. Right now only SHA256 is implemented.
* @namespace
*/
hash: {},
/**
* Key exchange functions. Right now only SRP is implemented.
* @namespace
*/
keyexchange: {},
/**
* Cipher modes of operation.
* @namespace
*/
mode: {},
/**
* Miscellaneous. HMAC and PBKDF2.
* @namespace
*/
misc: {},
/**
* Bit array encoders and decoders.
* @namespace
*
* @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: {},
/**
* Exceptions.
* @namespace
*/
exception: {
/**
* Ciphertext is corrupt.
* @constructor
*/
corrupt: function (message) {
this.toString = function () {
return "CORRUPT: " + this.message;
};
this.message = message;
},
/**
* Invalid parameter.
* @constructor
*/
invalid: function (message) {
this.toString = function () {
return "INVALID: " + this.message;
};
this.message = message;
},
/**
* Bug or missing feature in SJCL.
* @constructor
*/
bug: function (message) {
this.toString = function () {
return "BUG: " + this.message;
};
this.message = message;
},
/**
* Something isn't ready.
* @constructor
*/
notReady: function (message) {
this.toString = function () {
return "NOT READY: " + this.message;
};
this.message = message;
},
},
};
/** @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.
*/
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
*/
/**
* Arrays of bits, encoded as arrays of Numbers.
* @namespace
* @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} blength 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} [_end=0] 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
*/
/**
* UTF-8 strings
* @namespace
*/
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 >>> 8) >>> 8) >>> 8);
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
*/
/**
* Arrays of bytes
* @namespace
*/
sjcl.codec.bytes = {
/** Convert from a bitArray to an array of bytes. */
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.push(tmp >>> 24);
tmp <<= 8;
}
return out;
},
/** Convert from an array of bytes to a bitArray. */
toBits: function (bytes) {
var out = [],
i,
tmp = 0;
for (i = 0; i < bytes.length; i++) {
tmp = (tmp << 8) | bytes[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 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
*/
/**
* CTR mode with CBC MAC.
* @namespace
*/
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=[]] adata The authenticated data.
* @param {Number} [tlen=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) };
},
};
export { sjcl };