diff --git a/src/js/crypto/crypto.js b/src/js/crypto/crypto.js index 60b0fec..ffc0114 100644 --- a/src/js/crypto/crypto.js +++ b/src/js/crypto/crypto.js @@ -7,9 +7,6 @@ app.crypto.Crypto = function(window, util) { var aes = new cryptoLib.AesCBC(forge); // use AES-CBC mode by default var rsa = new cryptoLib.RSA(forge, util); // use RSA for asym. crypto - var keyStore = new app.dao.LocalStorageDAO(window); - - var storageId; // storage id for the encrypted keypair in local storage /** * Initializes the crypto modules by fetching the user's @@ -26,35 +23,28 @@ app.crypto.Crypto = function(window, util) { return; } - this.emailAddress = args.emailAddress; - this.keySize = args.keySize; - this.ivSize = args.keySize; - this.rsaKeySize = args.rsaKeySize; - - storageId = self.emailAddress + '_encryptedKeypair'; + self.emailAddress = args.emailAddress; + self.keySize = args.keySize; + self.ivSize = args.keySize; + self.rsaKeySize = args.rsaKeySize; // derive PBKDF2 from password in web worker thread - this.deriveKey(args.password, self.keySize, function(pbkdf2) { - - // TODO: rm keystore logix and check args.storedKeypair - - // fetch user's encrypted secret key from keychain/storage - var storedKeypair = keyStore.read(storageId); + self.deriveKey(args.password, self.keySize, function(pbkdf2) { // check if key exists - if (!storedKeypair) { + if (!args.storedKeypair) { // generate keys, encrypt and persist if none exists generateKeypair(pbkdf2); } else { // decrypt key - decryptKeypair(storedKeypair, pbkdf2); + decryptKeypair(args.storedKeypair, pbkdf2); } }); function generateKeypair(pbkdf2) { // generate RSA keypair in web worker - rsa.generateKeypair(self.rsaKeySize, function(err, keypair) { + rsa.generateKeypair(self.rsaKeySize, function(err, generatedKeypair) { if (err) { callback(err); return; @@ -62,28 +52,43 @@ app.crypto.Crypto = function(window, util) { // encrypt keypair var iv = util.random(self.ivSize); - var encryptedKeys = aes.encrypt(JSON.stringify(keypair), pbkdf2, iv); + var encryptedPrivateKey = aes.encrypt(generatedKeypair.privkeyPem, pbkdf2, iv); - // store encrypted keypair - var newStoredKeypair = { - _id: keypair._id, - userId: self.emailAddress, - encryptedKey: encryptedKeys, - iv: iv + // new encrypted keypair object + var newKeypair = { + publicKey: { + _id: generatedKeypair._id, + userId: self.emailAddress, + publicKey: generatedKeypair.pubkeyPem + }, + privateKey: { + _id: generatedKeypair._id, + userId: self.emailAddress, + encryptedKey: encryptedPrivateKey, + iv: iv + } }; - keyStore.persist(storageId, newStoredKeypair); - // TODO: return generated keypair for storage in keychain dao - callback(); + // return generated keypair for storage in keychain dao + callback(null, newKeypair); }); } function decryptKeypair(storedKeypair, pbkdf2) { - var keypairJson, keypair; + var decryptedPrivateKey; + + // validate input + if (!storedKeypair || !storedKeypair.privateKey || !storedKeypair.privateKey.encryptedKey || !storedKeypair.privateKey.iv) { + callback({ + errMsg: 'Incomplete arguments for private key decryption!' + }); + return; + } + // try to decrypt with pbkdf2 try { - keypairJson = aes.decrypt(storedKeypair.encryptedKey, pbkdf2, storedKeypair.iv); - keypair = JSON.parse(keypairJson); + var prK = storedKeypair.privateKey; + decryptedPrivateKey = aes.decrypt(prK.encryptedKey, pbkdf2, prK.iv); } catch (ex) { callback({ errMsg: 'Wrong password!' @@ -91,56 +96,12 @@ app.crypto.Crypto = function(window, util) { return; } // set rsa keys - rsa.init(keypair.pubkeyPem, keypair.privkeyPem, keypair._id); + rsa.init(storedKeypair.publicKey.publicKey, decryptedPrivateKey, storedKeypair.publicKey._id); callback(); } }; - // TODO: not required since key is synced before crypto init in keychain dao getUserKeyPair - - /** - * Return a Public Key object containing the Public Key PEM - */ - this.getPublicKey = function() { - var keypair = rsa.exportKeys(); - - return { - _id: keypair._id, - userId: this.emailAddress, - publicKey: keypair.pubkeyPem - }; - }; - - // TODO: not required since key is synced before crypto init in keychain dao getUserKeyPair - - /** - * Return a Private Key object containing the encrypted private key - */ - this.getEncryptedPrivateKey = function(emailAddress) { - if (!emailAddress && !storageId) { - throw new Error('Emailaddress needs to be set or crypto needs to be initiated!'); - } - - var strgId = (storageId) ? storageId : emailAddress + '_encryptedKeypair'; - var storedKeypair = keyStore.read(strgId); - - return storedKeypair; - }; - - // TODO: not required since key is synced before crypto init in keychain dao getUserKeyPair - - this.putEncryptedPrivateKey = function(privkey) { - var strgId = (storageId) ? storageId : privkey.userId + '_encryptedKeypair'; - - // validate private key object - if (!strgId || !privkey || !privkey._id || !privkey.userId || !privkey.encryptedKey || !privkey.iv) { - throw new Error('Invalid encrypted private key object... will not store!'); - } - - return keyStore.persist(strgId, privkey); - }; - /** * Do PBKDF2 key derivation in a WebWorker thread */ diff --git a/test/unit/crypto-test.js b/test/unit/crypto-test.js index fa70a3a..489e423 100644 --- a/test/unit/crypto-test.js +++ b/test/unit/crypto-test.js @@ -8,41 +8,42 @@ var crypto_test = { rsaKeySize: 1024 }; -asyncTest("Init", 2, function() { +asyncTest("Init without keypair", 4, function() { // init dependencies crypto_test.util = new cryptoLib.Util(window, uuid); crypto_test.crypto = new app.crypto.Crypto(window, crypto_test.util); ok(crypto_test.crypto, 'Crypto'); + // test without passing keys crypto_test.crypto.init({ emailAddress: crypto_test.user, password: crypto_test.password, keySize: crypto_test.keySize, rsaKeySize: crypto_test.rsaKeySize - }, function(err) { - ok(!err, 'Init crypto'); + }, function(err, generatedKeypair) { + ok(!err && generatedKeypair, 'Init crypto without keypair input'); + var pk = generatedKeypair.publicKey; + ok(pk._id && pk.userId, 'Key ID: ' + pk._id); + ok(pk.publicKey.indexOf('-----BEGIN PUBLIC KEY-----') === 0, pk.publicKey); + crypto_test.generatedKeypair = generatedKeypair; start(); }); }); -test("Get Public Key PEM", 2, function() { - var pk = crypto_test.crypto.getPublicKey(); - ok(pk._id && pk.userId, 'Key ID: ' + pk._id); - ok(pk.publicKey.indexOf('-----BEGIN PUBLIC KEY-----') === 0, pk.publicKey); -}); +asyncTest("Init with keypair", 1, function() { + // test with passing keypair + crypto_test.crypto.init({ + emailAddress: crypto_test.user, + password: crypto_test.password, + keySize: crypto_test.keySize, + rsaKeySize: crypto_test.rsaKeySize, + storedKeypair: crypto_test.generatedKeypair + }, function(err, generatedKeypair) { + ok(!err, 'Init crypto with keypair input'); -test("Get Encrypted Private Key", 2, function() { - var prk = crypto_test.crypto.getEncryptedPrivateKey(); - ok(prk._id && prk.userId, 'Key ID: ' + prk._id); - ok(prk.encryptedKey, prk.encryptedKey); - - crypto_test.prk = prk; -}); - -test("Put Encrypted Private Key", 1, function() { - crypto_test.crypto.putEncryptedPrivateKey(crypto_test.prk); - ok(true); + start(); + }); }); asyncTest("PBKDF2 (Async/Worker)", 1, function() { @@ -98,7 +99,7 @@ asyncTest("AES/RSA encrypt batch for User (Async/Worker)", 2, function() { collection = td.getEmailCollection(10); crypto_test.list = collection.toJSON(); - var receiverPubkeys = [crypto_test.crypto.getPublicKey()]; + var receiverPubkeys = [crypto_test.generatedKeypair.publicKey]; crypto_test.crypto.encryptListForUser(crypto_test.list, receiverPubkeys, function(err, encryptedList) { ok(!err && encryptedList, 'Encrypt list for user'); @@ -111,7 +112,7 @@ asyncTest("AES/RSA encrypt batch for User (Async/Worker)", 2, function() { asyncTest("AES/RSA decrypt batch for User (Async/Worker)", 3, function() { - var senderPubkeys = [crypto_test.crypto.getPublicKey()]; + var senderPubkeys = [crypto_test.generatedKeypair.publicKey]; crypto_test.crypto.decryptListForUser(crypto_test.encryptedList, senderPubkeys, function(err, decryptedList) { ok(!err && decryptedList, 'Decrypt list'); diff --git a/test/unit/devicestorage-test.js b/test/unit/devicestorage-test.js index 1ea796c..a740bf3 100644 --- a/test/unit/devicestorage-test.js +++ b/test/unit/devicestorage-test.js @@ -25,8 +25,9 @@ asyncTest("Init", 3, function() { password: devicestorage_test.password, keySize: devicestorage_test.keySize, rsaKeySize: devicestorage_test.rsaKeySize - }, function(err) { - ok(!err, 'Init crypto'); + }, function(err, generatedKeypair) { + ok(!err && generatedKeypair, 'Init crypto'); + devicestorage_test.generatedKeypair = generatedKeypair; // clear db before tests devicestorage_test.jsonDao.clear(function(err) { @@ -39,7 +40,7 @@ asyncTest("Init", 3, function() { }); asyncTest("Encrypt list for user", 2, function() { - var receiverPubkeys = [devicestorage_test.crypto.getPublicKey()]; + var receiverPubkeys = [devicestorage_test.generatedKeypair.publicKey]; devicestorage_test.crypto.encryptListForUser(devicestorage_test.list, receiverPubkeys, function(err, encryptedList) { ok(!err); @@ -60,7 +61,7 @@ asyncTest("Store encrypted list", 1, function() { asyncTest("List items", 3, function() { - var senderPubkeys = [devicestorage_test.crypto.getPublicKey()]; + var senderPubkeys = [devicestorage_test.generatedKeypair.publicKey]; var offset = 2, num = 6; diff --git a/test/unit/index.html b/test/unit/index.html index ebabd62..beca018 100644 --- a/test/unit/index.html +++ b/test/unit/index.html @@ -57,11 +57,11 @@ - - + +