diff options
Diffstat (limited to 'core/ccm.js')
-rw-r--r-- | core/ccm.js | 88 |
1 files changed, 60 insertions, 28 deletions
diff --git a/core/ccm.js b/core/ccm.js index 8a32c5a..1efde02 100644 --- a/core/ccm.js +++ b/core/ccm.js @@ -15,6 +15,27 @@ sjcl.mode.ccm = { */ 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. @@ -25,7 +46,7 @@ sjcl.mode.ccm = { * @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; + 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 || []; @@ -59,7 +80,7 @@ sjcl.mode.ccm = { decrypt: function(prf, ciphertext, iv, adata, tlen) { tlen = tlen || 64; adata = adata || []; - var L, i, + var L, w=sjcl.bitArray, ivl = w.bitLength(iv) / 8, ol = w.bitLength(ciphertext), @@ -90,6 +111,36 @@ sjcl.mode.ccm = { 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. @@ -101,7 +152,7 @@ sjcl.mode.ccm = { */ _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; + var mac, i, w=sjcl.bitArray, xor = w._xor4; tlen /= 8; @@ -115,31 +166,8 @@ sjcl.mode.ccm = { 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 = sjcl.mode.ccm._macAdditionalData(prf, adata, iv, tlen, w.bitLength(plaintext)/8, L); - // 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]))); @@ -161,7 +189,7 @@ sjcl.mode.ccm = { * @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); + 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); @@ -173,6 +201,10 @@ sjcl.mode.ccm = { 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]; |