sjcl.mode.ccm = {
name: "ccm",
encrypt: function(a, b, c, d, e) {
var f, g = b.slice(0), h = sjcl.bitArray, l = h.bitLength(c) / 8, k = h.bitLength(g) / 8;
e = e || 64;
d = d || [];
7 > l && q(new sjcl.exception.invalid("ccm: iv must be at least 7 bytes"));
for (f = 2; 4 > f && k >>> 8 * f; f++)
;
f < 15 - l && (f = 15 - l);
c = h.clamp(c, 8 * (15 - f));
b = sjcl.mode.ccm.K(a, b, c, d, e, f);
g = sjcl.mode.ccm.n(a, g, c, b, e, f);
return h.concat(g.data, g.tag)
},
decrypt: function(a, b, c, d, e) {
e = e || 64;
d = d || [];
var f = sjcl.bitArray
, g = f.bitLength(c) / 8
, h = f.bitLength(b)
, l = f.clamp(b, h - e)
, k = f.bitSlice(b, h - e)
, h = (h - e) / 8;
7 > g && q(new sjcl.exception.invalid("ccm: iv must be at least 7 bytes"));
for (b = 2; 4 > b && h >>> 8 * b; b++)
;
b < 15 - g && (b = 15 - g);
c = f.clamp(c, 8 * (15 - b));
l = sjcl.mode.ccm.n(a, l, c, k, e, b);
a = sjcl.mode.ccm.K(a, l.data, c, d, e, b);
f.equal(l.tag, a) || q(new sjcl.exception.corrupt("ccm: tag doesn't match"));
return l.data
},
K: function(a, b, c, d, e, f) {
var g = []
, h = sjcl.bitArray
, l = h.k;
e /= 8;
(e % 2 || 4 > e || 16 < e) && q(new sjcl.exception.invalid("ccm: invalid tag length"));
(0xffffffff < d.length || 0xffffffff < b.length) && q(new sjcl.exception.bug("ccm: can't deal with 4GiB or more data"));
f = [h.partial(8, (d.length ? 64 : 0) | e - 2 << 2 | f - 1)];
f = h.concat(f, c);
f[3] |= h.bitLength(b) / 8;
f = a.encrypt(f);
if (d.length) {
c = h.bitLength(d) / 8;
65279 >= c ? g = [h.partial(16, c)] : 0xffffffff >= c && (g = h.concat([h.partial(16, 65534)], [c]));
g = h.concat(g, d);
for (d = 0; d < g.length; d += 4)
f = a.encrypt(l(f, g.slice(d, d + 4).concat([0, 0, 0])))
}
for (d = 0; d < b.length; d += 4)
f = a.encrypt(l(f, b.slice(d, d + 4).concat([0, 0, 0])));
return h.clamp(f, 8 * e)
},
n: function(a, b, c, d, e, f) {
var g, h = sjcl.bitArray;
g = h.k;
var l = b.length
, k = h.bitLength(b);
c = h.concat([h.partial(8, f - 1)], c).concat([0, 0, 0]).slice(0, 4);
d = h.bitSlice(g(d, a.encrypt(c)), 0, e);
if (!l)
return {
tag: d,
data: []
};
for (g = 0; g < l; g += 4)
c[3]++,
e = a.encrypt(c),
b[g] ^= e[0],
b[g + 1] ^= e[1],
b[g + 2] ^= e[2],
b[g + 3] ^= e[3];
return {
tag: d,
data: h.clamp(b, k)
}
}
};