From 873671f0115aaf0cf30a52c6b1ce957f5daa036b Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Sat, 31 Aug 2013 16:09:25 +0200 Subject: [PATCH] add symmetric batch encryption to crypto, delete unnecessary crypto code --- src/js/crypto/aes-batch-worker.js | 42 --- src/js/crypto/aes-cbc.js | 2 +- src/js/crypto/aes-worker.js | 42 --- src/js/crypto/crypto-batch-worker.js | 32 +- src/js/crypto/crypto-batch.js | 491 ++++++++++++++++----------- src/js/crypto/crypto.js | 83 ++--- test/unit/crypto-test.js | 36 +- test/unit/main.js | 25 +- 8 files changed, 395 insertions(+), 358 deletions(-) delete mode 100644 src/js/crypto/aes-batch-worker.js delete mode 100644 src/js/crypto/aes-worker.js diff --git a/src/js/crypto/aes-batch-worker.js b/src/js/crypto/aes-batch-worker.js deleted file mode 100644 index c90e332..0000000 --- a/src/js/crypto/aes-batch-worker.js +++ /dev/null @@ -1,42 +0,0 @@ -(function() { - 'use strict'; - - // import web worker dependencies - importScripts('../../lib/require.js'); - - /** - * In the web worker thread context, 'this' and 'self' can be used as a global - * variable namespace similar to the 'window' object in the main thread - */ - self.onmessage = function(e) { - // fetch dependencies via require.js - require(['../../require-config'], function() { - require.config({ - baseUrl: '../../lib' - }); - - require(['cryptoLib/crypto-batch'], function(batch) { - - var i = e.data, - output = null; - - if (i.type === 'encrypt' && i.list) { - // start encryption - output = batch.encryptList(i.list); - - } else if (i.type === 'decrypt' && i.list) { - // start decryption - output = batch.decryptList(i.list); - - } else { - throw 'Not all arguments for web worker crypto are defined!'; - } - - // pass output back to main thread - self.postMessage(output); - - }); - }); - }; - -}()); \ No newline at end of file diff --git a/src/js/crypto/aes-cbc.js b/src/js/crypto/aes-cbc.js index 6f5ad6f..effa2ee 100644 --- a/src/js/crypto/aes-cbc.js +++ b/src/js/crypto/aes-cbc.js @@ -64,7 +64,7 @@ var self = this; // validate args - if (!parts || !key) { + if (!parts || parts.length < 1 || !key) { throw new Error("Missing args for hmac processing!"); } diff --git a/src/js/crypto/aes-worker.js b/src/js/crypto/aes-worker.js deleted file mode 100644 index b0153dc..0000000 --- a/src/js/crypto/aes-worker.js +++ /dev/null @@ -1,42 +0,0 @@ -(function() { - 'use strict'; - - // import web worker dependencies - importScripts('../../lib/require.js'); - - /** - * In the web worker thread context, 'this' and 'self' can be used as a global - * variable namespace similar to the 'window' object in the main thread - */ - self.onmessage = function(e) { - // fetch dependencies via require.js - require(['../../require-config'], function() { - require.config({ - baseUrl: '../../lib' - }); - - require(['cryptoLib/aes-cbc'], function(aes) { - - var i = e.data, - output = null; - - if (i.type === 'encrypt' && i.plaintext && i.key && i.iv) { - // start encryption - output = aes.encrypt(i.plaintext, i.key, i.iv); - - } else if (i.type === 'decrypt' && i.ciphertext && i.key && i.iv) { - // start decryption - output = aes.decrypt(i.ciphertext, i.key, i.iv); - - } else { - throw 'Not all arguments for web worker crypto are defined!'; - } - - // pass output back to main thread - self.postMessage(output); - - }); - }); - }; - -}()); \ No newline at end of file diff --git a/src/js/crypto/crypto-batch-worker.js b/src/js/crypto/crypto-batch-worker.js index 05a06cd..59aaa63 100644 --- a/src/js/crypto/crypto-batch-worker.js +++ b/src/js/crypto/crypto-batch-worker.js @@ -39,23 +39,47 @@ function doOperation(batch, i) { var output; - if (i.type === 'encrypt' && i.receiverPubkeys && i.senderPrivkey && i.list) { + // + // Asymmetric encryption + // + + if (i.type === 'asymEncrypt' && i.receiverPubkeys && i.senderPrivkey && i.list) { // start encryption output = batch.encryptListForUser(i.list, i.receiverPubkeys, i.senderPrivkey); - } else if (i.type === 'decrypt' && i.senderPubkeys && i.receiverPrivkey && i.list) { + } else if (i.type === 'asymDecrypt' && i.senderPubkeys && i.receiverPrivkey && i.list) { // start decryption output = batch.decryptListForUser(i.list, i.senderPubkeys, i.receiverPrivkey); + } - } else if (i.type === 'reencrypt' && i.senderPubkeys && i.receiverPrivkey && i.list && i.symKey) { + // + // Symmetric encryption + // + else if (i.type === 'symEncrypt' && i.list) { + // start encryption + output = batch.authEncryptList(i.list); + + } else if (i.type === 'symDecrypt' && i.list && i.keys) { + // start decryption + output = batch.authDecryptList(i.list, i.keys); + } + + // + // Reencryption of asymmetric items to symmetric items + // + else if (i.type === 'reencrypt' && i.senderPubkeys && i.receiverPrivkey && i.list && i.symKey) { // start validation and re-encryption output = batch.reencryptListKeysForUser(i.list, i.senderPubkeys, i.receiverPrivkey, i.symKey); } else if (i.type === 'decryptItems' && i.symKey && i.list) { // start decryption output = batch.decryptKeysAndList(i.list, i.symKey); + } - } else { + // + // Error + // + else { output = { err: { errMsg: 'Not all arguments for web worker crypto are defined!' diff --git a/src/js/crypto/crypto-batch.js b/src/js/crypto/crypto-batch.js index 66a865a..bb39e59 100644 --- a/src/js/crypto/crypto-batch.js +++ b/src/js/crypto/crypto-batch.js @@ -1,248 +1,341 @@ (function() { - 'use strict'; + 'use strict'; - /** - * Crypto batch library for processing large sets of data - */ - var CryptoBatch = function(aes, rsa, util, _) { + /** + * Crypto batch library for processing large sets of data + */ + var CryptoBatch = function(aes, rsa, util, _) { + this._aes = aes; + this._rsa = rsa; + this._util = util; + this.__ = _; + }; - // - // Encrypt batch - // + // + // Encrypt batch for user AES/RSA + // - /** - * Encrypt and sign an item using AES and RSA - * @param i [Object] The item to encrypt - * @param receiverPubkey [String] The public key used to encrypt - * @param senderKeyId [String] The sender's private key ID used to sign - */ - this.encryptItemForUser = function(i, receiverPubkey, senderKeyId) { - // set rsa public key used to encrypt - rsa.init(receiverPubkey); + /** + * Encrypt and sign a list of items using AES and RSA + * @param list [Array] The list of items to encrypt + * @param receiverPubkeys [Array] A list of public keys used to encrypt + * @param senderPrivkey [Array] The sender's private key used to sign + */ + CryptoBatch.prototype.encryptListForUser = function(list, receiverPubkeys, senderPrivkey) { + var receiverPk, + self = this; - // stringify to JSON before symmetric encryption - i.ciphertext = aes.encrypt(JSON.stringify(i.plaintext), i.key, i.iv); + // encrypt a list of items + self.encryptList(list); - // encrypt symmetric item key for user - i.encryptedKey = rsa.encrypt(i.key); - // set sender's keypair id for later verification - i.senderPk = senderKeyId; - // sign the bundle - i.signature = rsa.sign([i.iv, util.str2Base64(i.senderPk), i.encryptedKey, i.ciphertext]); + // set sender private key + self._rsa.init(null, senderPrivkey.privateKey); - // delete plaintext values - delete i.plaintext; - delete i.key; - delete i.receiverPk; + list.forEach(function(i) { + // fetch correct public key for encryption + receiverPk = null; + receiverPk = self.__.findWhere(receiverPubkeys, { + _id: i.receiverPk + }); - return i; - }; + // encrypt item for user + self.encryptItemKeyForUser(i, receiverPk.publicKey, senderPrivkey._id); + }); - /** - * Encrypt and sign a list of items using AES and RSA - * @param list [Array] The list of items to encrypt - * @param receiverPubkeys [Array] A list of public keys used to encrypt - * @param senderPrivkey [Array] The sender's private key used to sign - */ - this.encryptListForUser = function(list, receiverPubkeys, senderPrivkey) { - var receiverPk, - self = this; + return list; + }; - // set sender private key - rsa.init(null, senderPrivkey.privateKey); + /** + * Encrypt and sign an item using AES and RSA + * @param i [Object] The item to encrypt + * @param receiverPubkey [String] The public key used to encrypt + * @param senderKeyId [String] The sender's private key ID used to sign + */ + CryptoBatch.prototype.encryptItemKeyForUser = function(i, receiverPubkey, senderKeyId) { + var self = this; - list.forEach(function(i) { - // fetch correct public key for encryption - receiverPk = null; - receiverPk = _.findWhere(receiverPubkeys, { - _id: i.receiverPk - }); + // set rsa public key used to encrypt + self._rsa.init(receiverPubkey); + // encrypt symmetric item key for user + i.encryptedKey = self._rsa.encrypt(i.key); + // set sender's keypair id for later verification + i.senderPk = senderKeyId; + // sign the bundle + i.signature = self._rsa.sign([i.iv, self._util.str2Base64(i.senderPk), i.encryptedKey, i.ciphertext]); - // encrypt item for user - self.encryptItemForUser(i, receiverPk.publicKey, senderPrivkey._id); - }); + // delete plaintext values + delete i.key; + delete i.receiverPk; - return list; - }; + return i; + }; - // - // Decrypt batch - // + // + // Decrypt batch for user AES/RSA + // - /** - * Verfiy an item and decrypt its item key using RSA - * @param i [Object] The item to decrypt - * @param senderPubkey [String] A public key used to verify - */ - this.decryptItemKeyForUser = function(i, senderPubkey) { - // set rsa public key used to verify - rsa.init(senderPubkey); + /** + * Decrypt and verify a list of items using AES and RSA + * @param list [Array] The list of items to decrypt + * @param senderPubkeys [Array] A list of public keys used to verify + * @param receiverPrivkey [Array] The receiver's private key used to decrypt + */ + CryptoBatch.prototype.decryptListForUser = function(list, senderPubkeys, receiverPrivkey) { + var j; - // verify signature - if (!rsa.verify([i.iv, util.str2Base64(i.senderPk), i.encryptedKey, i.ciphertext], i.signature)) { - throw new Error('Verifying RSA signature failed!'); - } - // decrypt symmetric item key for user - i.key = rsa.decrypt(i.encryptedKey); + // verify and decrypt a list of items using RSA + this.decryptListKeysForUser(list, senderPubkeys, receiverPrivkey); - // delete ciphertext values - delete i.signature; - delete i.encryptedKey; - delete i.senderPk; + // decrypt a list of items + this.decryptList(list); - return i; - }; + // set plaintext as list item + for (j = 0; j < list.length; j++) { + list[j] = list[j].plaintext; + } - /** - * Decrypt and verify a list of item keys using RSA - * @param list [Array] The list of items to decrypt - * @param senderPubkeys [Array] A list of public keys used to verify - * @param receiverPrivkey [String] The receiver's private key used to decrypt - */ - this.decryptListKeysForUser = function(list, senderPubkeys, receiverPrivkey) { - var senderPk, - self = this; + return list; + }; - // set receiver private key - rsa.init(null, receiverPrivkey.privateKey); + /** + * Decrypt and verify a list of item keys using RSA + * @param list [Array] The list of items to decrypt + * @param senderPubkeys [Array] A list of public keys used to verify + * @param receiverPrivkey [String] The receiver's private key used to decrypt + */ + CryptoBatch.prototype.decryptListKeysForUser = function(list, senderPubkeys, receiverPrivkey) { + var self = this, + senderPk; - list.forEach(function(i) { - // fetch correct public key for verification - senderPk = null; - senderPk = _.findWhere(senderPubkeys, { - _id: i.senderPk - }); + // set receiver private key + self._rsa.init(null, receiverPrivkey.privateKey); - // decrypt item for user - self.decryptItemKeyForUser(i, senderPk.publicKey); - }); + list.forEach(function(i) { + // fetch correct public key for verification + senderPk = null; + senderPk = self.__.findWhere(senderPubkeys, { + _id: i.senderPk + }); - return list; - }; + // decrypt item for user + self.decryptItemKeyForUser(i, senderPk.publicKey); + }); - /** - * Decrypt a list of item keys using RSA and the encrypt them again using AES - * @param list [Array] The list of items to decrypt - * @param senderPubkeys [Array] A list of public keys used to verify - * @param receiverPrivkey [String] The receiver's private key used to decrypt - * @param symKey [String] The symmetric key used to re-encrypt the item key - */ - this.reencryptListKeysForUser = function(list, senderPubkeys, receiverPrivkey, symKey) { - // verify and decrypt item keys using RSA - this.decryptListKeysForUser(list, senderPubkeys, receiverPrivkey); + return list; + }; - list.forEach(function(i) { - // re-encrypt item key using aes - i.encryptedKey = aes.encrypt(i.key, symKey, i.iv); + /** + * Verfiy an item and decrypt its item key using RSA + * @param i [Object] The item to decrypt + * @param senderPubkey [String] A public key used to verify + */ + CryptoBatch.prototype.decryptItemKeyForUser = function(i, senderPubkey) { + var self = this; - delete i.key; - }); + // set rsa public key used to verify + self._rsa.init(senderPubkey); - return list; - }; + // verify signature + if (!self._rsa.verify([i.iv, self._util.str2Base64(i.senderPk), i.encryptedKey, i.ciphertext], i.signature)) { + throw new Error('Verifying RSA signature failed!'); + } + // decrypt symmetric item key for user + i.key = self._rsa.decrypt(i.encryptedKey); - /** - * Decrypt an item using AES - * @param i [Object] The item to decrypt - */ - this.decryptItem = function(i) { - // symmetrically decrypt JSON and parse to object literal - i.plaintext = JSON.parse(aes.decrypt(i.ciphertext, i.key, i.iv)); + // delete ciphertext values + delete i.signature; + delete i.encryptedKey; + delete i.senderPk; - // delete ciphertext values - delete i.ciphertext; + return i; + }; - return i; - }; + // + // Encrypt batch AES + // - /** - * Decrypt a list of items using AES - * @param i [Object] The item to decrypt - */ - this.decryptList = function(list) { - var self = this; + /** + * Encrypt an item using AES + * @param i [Object] The item to encrypt + */ + CryptoBatch.prototype.encryptItem = function(i) { + var self = this; - list.forEach(function(i) { - // decrypt item for user - self.decryptItem(i); - }); + // stringify to JSON before symmetric encryption + i.ciphertext = self._aes.encrypt(JSON.stringify(i.plaintext), i.key, i.iv); - return list; - }; + // delete plaintext values + delete i.plaintext; - /** - * Decrypt keys and items using AES - * @param list [Array] The list of items to decrypt - * @param symKey [String] The symmetric key used to re-encrypt the item key - */ - this.decryptKeysAndList = function(list, symKey) { - var self = this, - j; + return i; + }; - list.forEach(function(i) { - // decrypt item key - i.key = aes.decrypt(i.encryptedKey, symKey, i.iv); - // decrypt item for user - self.decryptItem(i); + /** + * Encrypt a list of items using AES + * @param i [Object] The item to encrypt + */ + CryptoBatch.prototype.encryptList = function(list) { + var self = this; - delete i.encryptedKey; - }); + list.forEach(function(i) { + // encrypt item + self.encryptItem(i); + }); - // set plaintext as list item - for (j = 0; j < list.length; j++) { - list[j] = list[j].plaintext; - } + return list; + }; - return list; - }; + /** + * Encrypt a list of items using AES and hash using HMAC + * @param i [Object] The item to encrypt + */ + CryptoBatch.prototype.authEncryptList = function(list) { + var self = this; - /** - * Decrypt and verify an item using AES and RSA - * @param i [Object] The item to decrypt - * @param senderPubkey [String] A public key used to verify - */ - this.decryptItemForUser = function(i, senderPubkey) { - // verfiy signature and decrypt item key - this.decryptItemKeyForUser(i, senderPubkey); + self.encryptList(list); - // symmetrically decrypt JSON and parse to object literal - this.decryptItem(i); + list.forEach(function(i) { + // calculate hmac of iv and ciphertext using key + i.hmac = self._aes.hmac([i.iv, i.ciphertext], i.key); - return i; - }; + // delete symmetric key on each item + delete i.key; + }); - /** - * Decrypt and verify a list of items using AES and RSA - * @param list [Array] The list of items to decrypt - * @param senderPubkeys [Array] A list of public keys used to verify - * @param receiverPrivkey [Array] The receiver's private key used to decrypt - */ - this.decryptListForUser = function(list, senderPubkeys, receiverPrivkey) { - var j; + return list; + }; - // verify and decrypt a list of items using RSA - this.decryptListKeysForUser(list, senderPubkeys, receiverPrivkey); + // + // Decrypt batch AES + // - // decrypt a list of items - this.decryptList(list); + /** + * Decrypt an item using AES + * @param i [Object] The item to decrypt + */ + CryptoBatch.prototype.decryptItem = function(i) { + var self = this; - // set plaintext as list item - for (j = 0; j < list.length; j++) { - list[j] = list[j].plaintext; - } + // symmetrically decrypt JSON and parse to object literal + i.plaintext = JSON.parse(self._aes.decrypt(i.ciphertext, i.key, i.iv)); - return list; - }; - }; + // delete ciphertext values + delete i.ciphertext; - if (typeof define !== 'undefined' && define.amd) { - // AMD - define(['cryptoLib/aes-cbc', 'cryptoLib/rsa', 'cryptoLib/util', 'underscore'], function(aes, rsa, util, _) { - return new CryptoBatch(aes, rsa, util, _); - }); - } else if (typeof module !== 'undefined' && module.exports) { - // node.js - module.exports = new CryptoBatch(require('./aes-cbc'), require('./rsa'), require('./util'), require('underscore')); - } + return i; + }; + + /** + * Decrypt a list of items using AES + * @param i [Object] The item to decrypt + */ + CryptoBatch.prototype.decryptList = function(list) { + var self = this; + + list.forEach(function(i) { + // decrypt item + self.decryptItem(i); + }); + + return list; + }; + + /** + * Encrypt a list of items using AES and verfiy using HMAC + * @param i [Object] The item to decrypt + */ + CryptoBatch.prototype.authDecryptList = function(list, keys) { + var self = this, + i, len, calculated, j; + + for (i = 0, len = list.length; i < len; i++) { + // validate presence of args + if (!list[i].hmac || !list[i].iv || !list[i].ciphertext || !keys[i]) { + throw new Error('Arguments for hmac verification missing!'); + } + + // verify hmac of each item + calculated = self._aes.hmac([list[i].iv, list[i].ciphertext], keys[i]); + if (list[i].hmac !== calculated) { + throw new Error('Hmac verification failed!'); + } + + // set key property for batch decryption + list[i].key = keys[i]; + } + + // decrypt lsit using aes + self.decryptList(list); + + // set plaintext as list item + for (j = 0; j < list.length; j++) { + list[j] = list[j].plaintext; + } + + return list; + }; + + // + // Reencrypt batch for user AES/RSA + // + + /** + * Decrypt a list of item keys using RSA and the encrypt them again using AES + * @param list [Array] The list of items to decrypt + * @param senderPubkeys [Array] A list of public keys used to verify + * @param receiverPrivkey [String] The receiver's private key used to decrypt + * @param symKey [String] The symmetric key used to re-encrypt the item key + */ + CryptoBatch.prototype.reencryptListKeysForUser = function(list, senderPubkeys, receiverPrivkey, symKey) { + var self = this; + + // verify and decrypt item keys using RSA + this.decryptListKeysForUser(list, senderPubkeys, receiverPrivkey); + + list.forEach(function(i) { + // re-encrypt item key using aes + i.encryptedKey = self._aes.encrypt(i.key, symKey, i.iv); + + delete i.key; + }); + + return list; + }; + + /** + * Decrypt keys and items using AES + * @param list [Array] The list of items to decrypt + * @param symKey [String] The symmetric key used to re-encrypt the item key + */ + CryptoBatch.prototype.decryptKeysAndList = function(list, symKey) { + var self = this, + j; + + list.forEach(function(i) { + // decrypt item key + i.key = self._aes.decrypt(i.encryptedKey, symKey, i.iv); + // decrypt item for user + self.decryptItem(i); + + delete i.encryptedKey; + }); + + // set plaintext as list item + for (j = 0; j < list.length; j++) { + list[j] = list[j].plaintext; + } + + return list; + }; + + if (typeof define !== 'undefined' && define.amd) { + // AMD + define(['cryptoLib/aes-cbc', 'cryptoLib/rsa', 'cryptoLib/util', 'underscore'], function(aes, rsa, util, _) { + return new CryptoBatch(aes, rsa, util, _); + }); + } else if (typeof module !== 'undefined' && module.exports) { + // node.js + module.exports = new CryptoBatch(require('./aes-cbc'), require('./rsa'), require('./util'), require('underscore')); + } })(); \ No newline at end of file diff --git a/src/js/crypto/crypto.js b/src/js/crypto/crypto.js index 499df2c..2cf8e90 100644 --- a/src/js/crypto/crypto.js +++ b/src/js/crypto/crypto.js @@ -126,59 +126,48 @@ define(function(require) { }); }; - // - // En/Decrypts single item - // - - self.aesEncrypt = function(plaintext, key, iv, callback) { - startWorker('/crypto/aes-worker.js', { - type: 'encrypt', - plaintext: plaintext, - key: key, - iv: iv - }, callback, function() { - return self.aesEncryptSync(plaintext, key, iv); - }); - }; - - self.aesDecrypt = function(ciphertext, key, iv, callback) { - startWorker('/crypto/aes-worker.js', { - type: 'decrypt', - ciphertext: ciphertext, - key: key, - iv: iv - }, callback, function() { - return self.aesDecryptSync(ciphertext, key, iv); - }); - }; - - self.aesEncryptSync = function(plaintext, key, iv) { - return aes.encrypt(plaintext, key, iv); - }; - - self.aesDecryptSync = function(ciphertext, key, iv) { - return aes.decrypt(ciphertext, key, iv); - }; - // // En/Decrypt a list of items with AES in a WebWorker thread // - self.aesEncryptList = function(list, callback) { - startWorker('/crypto/aes-batch-worker.js', { - type: 'encrypt', - list: list - }, callback, function() { - return cryptoBatch.encryptList(list); + self.symEncryptList = function(list, callback) { + var key, envelope, envelopes = []; + + // generate single secret key shared for all list items + key = util.random(self.keySize); + + // package objects into batchable envelope format + list.forEach(function(i) { + envelope = { + id: i.id, + plaintext: i, + key: key, + iv: util.random(self.ivSize) + }; + envelopes.push(envelope); + }); + + startWorker('/crypto/crypto-batch-worker.js', { + type: 'symEncrypt', + list: envelopes + }, function(err, encryptedList) { + // return generated secret key + callback(err, { + key: key, + list: encryptedList + }); + }, function() { + return cryptoBatch.authEncryptList(envelopes); }); }; - self.aesDecryptList = function(list, callback) { - startWorker('/crypto/aes-batch-worker.js', { - type: 'decrypt', - list: list + self.symDecryptList = function(list, keys, callback) { + startWorker('/crypto/crypto-batch-worker.js', { + type: 'symDecrypt', + list: list, + keys: keys }, callback, function() { - return cryptoBatch.decryptList(list); + return cryptoBatch.authDecryptList(list, keys); }); }; @@ -215,7 +204,7 @@ define(function(require) { }); startWorker('/crypto/crypto-batch-worker.js', { - type: 'encrypt', + type: 'asymEncrypt', list: envelopes, senderPrivkey: senderPrivkey, receiverPubkeys: receiverPubkeys @@ -239,7 +228,7 @@ define(function(require) { }; startWorker('/crypto/crypto-batch-worker.js', { - type: 'decrypt', + type: 'asymDecrypt', list: list, receiverPrivkey: receiverPrivkey, senderPubkeys: senderPubkeys diff --git a/test/unit/crypto-test.js b/test/unit/crypto-test.js index 8160bf1..e4ed3f9 100644 --- a/test/unit/crypto-test.js +++ b/test/unit/crypto-test.js @@ -56,22 +56,34 @@ define(['js/crypto/crypto', 'cryptoLib/util', 'test/test-data'], function(crypto }); }); - asyncTest("AES en/decrypt (Async/Worker)", 4, function() { - var secret = 'Big secret'; + asyncTest("AES/HMAC encrypt batch (Async/Worker)", 2, function() { + // generate test data + var collection; - var key = util.random(cryptoTest.keySize); - var iv = util.random(cryptoTest.ivSize); + collection = testData.getEmailCollection(10); + cryptoTest.symlist = collection.toJSON(); - crypto.aesEncrypt(secret, key, iv, function(err, ciphertext) { - ok(!err); - ok(ciphertext, 'Encrypt item'); + crypto.symEncryptList(cryptoTest.symlist, function(err, result) { + ok(!err && result.key && result.list && result.list[0].hmac, 'Encrypt list for user'); + equal(result.list.length, cryptoTest.symlist.length, 'Length of list'); + cryptoTest.symEncryptedList = result.list; + cryptoTest.symKey = result.key; - crypto.aesDecrypt(ciphertext, key, iv, function(err, decrypted) { - ok(!err); - equal(decrypted, secret, 'Decrypt item'); + start(); + }); + }); - start(); - }); + asyncTest("AES/HMAC decrypt batch (Async/Worker)", 3, function() { + var keys = []; + for (var i = 0; i < cryptoTest.symEncryptedList.length; i++) { + keys.push(cryptoTest.symKey); + } + crypto.symDecryptList(cryptoTest.symEncryptedList, keys, function(err, decryptedList) { + ok(!err && decryptedList, 'Decrypt list'); + equal(decryptedList.length, cryptoTest.symlist.length, 'Length of list'); + deepEqual(decryptedList, cryptoTest.symlist, 'Decrypted list is correct'); + + start(); }); }); diff --git a/test/unit/main.js b/test/unit/main.js index 0ec2add..fcca131 100644 --- a/test/unit/main.js +++ b/test/unit/main.js @@ -19,15 +19,18 @@ require(['../../src/require-config'], function() { }); function startTests() { - require(['test/unit/forge-test', - 'test/unit/aes-test', - 'test/unit/rsa-test', - 'test/unit/lawnchair-dao-test', - 'test/unit/keychain-dao-test', - 'test/unit/crypto-test', - 'test/unit/devicestorage-dao-test' - ], function() { - //Tests loaded, run tests - QUnit.start(); - }); + require( + [ + 'test/unit/forge-test', + 'test/unit/aes-test', + 'test/unit/rsa-test', + 'test/unit/lawnchair-dao-test', + 'test/unit/keychain-dao-test', + 'test/unit/crypto-test', + 'test/unit/devicestorage-dao-test' + ], function() { + //Tests loaded, run tests + QUnit.start(); + } + ); } \ No newline at end of file