diff --git a/Makefile b/Makefile index 22cc8191..72fe1053 100644 --- a/Makefile +++ b/Makefile @@ -63,6 +63,7 @@ TEST_SCRIPTS= $(TEST_COMMON) \ test/bitArray_vectors.js test/bitArray_test.js \ test/bn_vectors.js test/bn_test.js \ test/cbc_vectors.js test/cbc_test.js \ + test/ctr_vectors.js test/ctr_test.js \ test/ccm_vectors.js test/ccm_test.js \ test/ecc_vectors.js test/ecc_test.js \ test/ecc_conv.js \ diff --git a/configure b/configure index 198cb9a7..be855abd 100755 --- a/configure +++ b/configure @@ -4,7 +4,7 @@ use strict; my ($arg, $i, $j, $targ); -my @targets = qw/sjcl aes bitArray codecString codecHex codecBase32 codecBase64 codecBytes sha256 sha512 sha1 ccm cbc ocb2 ocb2progressive gcm hmac pbkdf2 scrypt random convenience bn ecc srp ccmArrayBuffer codecArrayBuffer ripemd160/; +my @targets = qw/sjcl aes bitArray codecString codecHex codecBase32 codecBase64 codecBytes sha256 sha512 sha1 ccm ctr cbc ocb2 ocb2progressive gcm hmac pbkdf2 scrypt random convenience bn ecc srp ccmArrayBuffer codecArrayBuffer ripemd160/; my %deps = ('aes'=>'sjcl', 'bitArray'=>'sjcl', 'codecString'=>'bitArray', @@ -17,6 +17,7 @@ my %deps = ('aes'=>'sjcl', 'sha1'=>'codecString', 'ripemd160' => 'codecString', 'ccm'=>'bitArray,aes', + 'ctr'=>'bitArray,aes', 'ocb2'=>'bitArray,aes', 'ocb2progressive'=>'ocb2', 'gcm'=>'bitArray,aes', diff --git a/core/ctr.js b/core/ctr.js new file mode 100644 index 00000000..39f4c74b --- /dev/null +++ b/core/ctr.js @@ -0,0 +1,72 @@ +/** @fileOverview CTR mode implementation + * + * @author Torben Haase + */ + +if (sjcl.beware === undefined) { + sjcl.beware = {}; +} +sjcl.beware["CTR mode is dangerous because it doesn't protect message integrity." +] = function() { + /** @namespace + * Dangerous: CTR mode. + * + * @author Torben Haase + */ + sjcl.mode.ctr = { + /** The name of the mode. + * @constant + */ + name: "ctr", + + /** Encrypt in CTR mode. + * @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. It must be 128 bits. + * @param {bitArray} [adata=[]] The authenticated data. Must be empty. + * @return The encrypted data, an array of bytes. + * @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits or if any adata is specified. + */ + encrypt: function(prf, plaintext, iv, adata) { + return sjcl.mode.ctr._calculate(prf, plaintext, iv, adata); + }, + + /** Decrypt in CTR mode. + * @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. It must be 128 bits. + * @param {bitArray} [adata=[]] The authenticated data. It must be empty. + * @return The decrypted data, an array of bytes. + * @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits or if any adata is specified. + * @throws {sjcl.exception.corrupt} if if the message is corrupt. + */ + decrypt: function(prf, ciphertext, iv, adata) { + return sjcl.mode.ctr._calculate(prf, ciphertext, iv, adata); + }, + + _calculate: function(prf, data, iv, adata) { + var l, bl, res, c, d, e, i; + if (adata && adata.length) { + throw new sjcl.exception.invalid("ctr can't authenticate data"); + } + if (sjcl.bitArray.bitLength(iv) !== 128) { + throw new sjcl.exception.invalid("ctr iv must be 128 bits"); + } + if (!(l = data.length)) { + return []; + } + c = iv.slice(0); + d = data.slice(0); + bl = sjcl.bitArray.bitLength(d); + for (i=0; i