integrated new crypto lib api into crypto.js

This commit is contained in:
Tankred Hase 2013-05-23 22:17:25 +02:00
parent 52fba1a462
commit 1e27297013
4 changed files with 93 additions and 34 deletions

View File

@ -2,6 +2,7 @@
'use strict';
// import web worker dependencies
importScripts('../../lib/underscore-1.4.4.min.js');
importScripts('../../lib/forge/forge.rsa.bundle.js');
importScripts('../app-config.js');
importScripts('./crypto-batch.js');
@ -20,18 +21,15 @@
aes = new cryptoLib.AesCBC(forge),
rsa = new cryptoLib.RSA(forge),
util = new cryptoLib.Util(),
batch = new cryptoLib.CryptoBatch(aes, rsa, util);
batch = new cryptoLib.CryptoBatch(aes, rsa, util, _);
// pass RSA keys to module
rsa.init(i.pubkeyPem, i.privkeyPem);
if (i.type === 'encrypt' && i.list) {
if (i.type === 'encrypt' && i.receiverPubkeys && i.senderPrivkey && i.list) {
// start encryption
output = batch.encryptListForUser(i.list);
output = batch.encryptListForUser(i.list, i.receiverPubkeys, i.senderPrivkey);
} else if (i.type === 'decrypt' && i.list) {
} else if (i.type === 'decrypt' && i.senderPubkeys && i.receiverPrivkey && i.list) {
// start decryption
output = batch.decryptListForUser(i.list);
output = batch.decryptListForUser(i.list, i.senderPubkeys, i.receiverPrivkey);
} else {
throw 'Not all arguments for web worker crypto are defined!';

View File

@ -4,11 +4,11 @@
/**
* Crypto batch library for processing large sets of data
*/
var CryptoBatch = function(aes, rsa, util) {
var CryptoBatch = function(aes, rsa, util, _) {
/**
* Encrypt a list of items using AES
* @list list [Array] The list of items to encrypt
* @param list [Array] The list of items to encrypt
*/
this.encryptList = function(list) {
list.forEach(function(i) {
@ -22,7 +22,7 @@
/**
* Decrypt a list of items using AES
* @list list [Array] The list of items to decrypt
* @param list [Array] The list of items to decrypt
*/
this.decryptList = function(list) {
list.forEach(function(i) {
@ -36,19 +36,33 @@
/**
* Encrypt and sign a list of items using AES and RSA
* @list list [Array] The list of items to encrypt
* @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) {
// encrypt list
this.encryptListForUser = function(list, receiverPubkeys, senderPrivkey) {
// encrypt list with aes
var encryptedList = this.encryptList(list);
// set sender private key
rsa.init(null, senderPrivkey.privateKey);
// encrypt keys for user
encryptedList.forEach(function(i) {
// fetch correct public key
var pk = _.findWhere(receiverPubkeys, {
_id: i.receiverPk
});
// set rsa public key used to encrypt
rsa.init(pk.publicKey);
// process new values
i.encryptedKey = rsa.encrypt(i.key);
i.signature = rsa.sign([i.iv, util.str2Base64(i.id), i.encryptedKey, i.ciphertext]);
i.senderPk = senderPrivkey._id;
// delete old ones
delete i.key;
delete i.receiverPk;
});
return encryptedList;
@ -56,22 +70,35 @@
/**
* Decrypt and verify a list of items using AES and RSA
* @list list [Array] The list of items to decrypt
* @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(encryptedList) {
this.decryptListForUser = function(encryptedList, senderPubkeys, receiverPrivkey) {
var j, self = this;
// set receiver private key
rsa.init(null, receiverPrivkey.privateKey);
// decrypt keys for user
encryptedList.forEach(function(i) {
// fetch correct public key
var pk = _.findWhere(senderPubkeys, {
_id: i.senderPk
});
// set rsa public key used to verify
rsa.init(pk.publicKey);
// verify signature
if (!rsa.verify([i.iv, util.str2Base64(i.id), i.encryptedKey, i.ciphertext], i.signature)) {
throw new Error('Verifying RSA signature failed!');
}
// precoess new values
// process new values
i.key = rsa.decrypt(i.encryptedKey);
// delete old values
delete i.signature;
delete i.encryptedKey;
delete i.senderPk;
});
// decrypt list

View File

@ -96,6 +96,8 @@ app.crypto.Crypto = function(window, util) {
}
};
// TODO: not required since key is synced before crypto init in keychain dao getUserKeyPair
/**
* Return a Public Key object containing the Public Key PEM
*/
@ -109,6 +111,8 @@ app.crypto.Crypto = function(window, util) {
};
};
// TODO: not required since key is synced before crypto init in keychain dao getUserKeyPair
/**
* Return a Private Key object containing the encrypted private key
*/
@ -123,6 +127,8 @@ app.crypto.Crypto = function(window, util) {
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';
@ -261,25 +267,37 @@ app.crypto.Crypto = function(window, util) {
// En/Decrypt something speficially using the user's secret key
//
this.encryptListForUser = function(list, recipientPubkey, callback) {
this.encryptListForUser = function(list, receiverPubkeys, callback) {
var envelope, envelopes = [],
self = this;
if (!receiverPubkeys || receiverPubkeys.length !== 1) {
callback({
errMsg: 'Encryption is currently implemented for only one receiver!'
});
return;
}
var keypair = rsa.exportKeys();
var senderPrivkey = {
_id: keypair._id,
privateKey: keypair.privkeyPem
};
// package objects into batchable envelope format
list.forEach(function(i) {
envelope = {
id: i.id,
plaintext: i,
key: util.random(self.keySize),
iv: util.random(self.ivSize)
iv: util.random(self.ivSize),
receiverPk: receiverPubkeys[0]._id
};
envelopes.push(envelope);
});
if (window.Worker) {
var keypair = rsa.exportKeys();
var worker = new Worker(app.config.workerPath + '/crypto/crypto-batch-worker.js');
worker.onmessage = function(e) {
callback(null, e.data);
@ -287,21 +305,32 @@ app.crypto.Crypto = function(window, util) {
worker.postMessage({
type: 'encrypt',
list: envelopes,
pubkeyPem: keypair.pubkeyPem,
privkeyPem: keypair.privkeyPem
senderPrivkey: senderPrivkey,
receiverPubkeys: receiverPubkeys
});
} else {
var batch = new cryptoLib.CryptoBatch(aes, rsa, util);
var encryptedList = batch.encryptListForUser(envelopes);
var batch = new cryptoLib.CryptoBatch(aes, rsa, util, _);
var encryptedList = batch.encryptListForUser(envelopes, receiverPubkeys, senderPrivkey);
callback(null, encryptedList);
}
};
this.decryptListForUser = function(list, recipientPubkey, callback) {
if (window.Worker) {
this.decryptListForUser = function(list, senderPubkeys, callback) {
if (!senderPubkeys || senderPubkeys < 1) {
callback({
errMsg: 'Sender public keys must be set!'
});
return;
}
var keypair = rsa.exportKeys();
var keypair = rsa.exportKeys();
var receiverPrivkey = {
_id: keypair._id,
privateKey: keypair.privkeyPem
};
if (window.Worker) {
var worker = new Worker(app.config.workerPath + '/crypto/crypto-batch-worker.js');
worker.onmessage = function(e) {
@ -310,13 +339,13 @@ app.crypto.Crypto = function(window, util) {
worker.postMessage({
type: 'decrypt',
list: list,
pubkeyPem: keypair.pubkeyPem,
privkeyPem: keypair.privkeyPem
receiverPrivkey: receiverPrivkey,
senderPubkeys: senderPubkeys
});
} else {
var batch = new cryptoLib.CryptoBatch(aes, rsa, util);
var decryptedList = batch.decryptListForUser(list);
var batch = new cryptoLib.CryptoBatch(aes, rsa, util, _);
var decryptedList = batch.decryptListForUser(list, senderPubkeys, receiverPrivkey);
callback(null, decryptedList);
}
};

View File

@ -98,7 +98,9 @@ asyncTest("AES/RSA encrypt batch for User (Async/Worker)", 2, function() {
collection = td.getEmailCollection(10);
crypto_test.list = collection.toJSON();
crypto_test.crypto.encryptListForUser(crypto_test.list, null, function(err, encryptedList) {
var receiverPubkeys = [crypto_test.crypto.getPublicKey()];
crypto_test.crypto.encryptListForUser(crypto_test.list, receiverPubkeys, function(err, encryptedList) {
ok(!err && encryptedList, 'Encrypt list for user');
equal(encryptedList.length, crypto_test.list.length, 'Length of list');
crypto_test.encryptedList = encryptedList;
@ -108,7 +110,10 @@ asyncTest("AES/RSA encrypt batch for User (Async/Worker)", 2, function() {
});
asyncTest("AES/RSA decrypt batch for User (Async/Worker)", 3, function() {
crypto_test.crypto.decryptListForUser(crypto_test.encryptedList, null, function(err, decryptedList) {
var senderPubkeys = [crypto_test.crypto.getPublicKey()];
crypto_test.crypto.decryptListForUser(crypto_test.encryptedList, senderPubkeys, function(err, decryptedList) {
ok(!err && decryptedList, 'Decrypt list');
equal(decryptedList.length, crypto_test.list.length, 'Length of list');
deepEqual(decryptedList, crypto_test.list, 'Decrypted list is correct');