mirror of
https://github.com/moparisthebest/mail
synced 2025-02-16 15:10:10 -05:00
integrated new crypto lib api into crypto.js
This commit is contained in:
parent
52fba1a462
commit
1e27297013
@ -2,6 +2,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// import web worker dependencies
|
// import web worker dependencies
|
||||||
|
importScripts('../../lib/underscore-1.4.4.min.js');
|
||||||
importScripts('../../lib/forge/forge.rsa.bundle.js');
|
importScripts('../../lib/forge/forge.rsa.bundle.js');
|
||||||
importScripts('../app-config.js');
|
importScripts('../app-config.js');
|
||||||
importScripts('./crypto-batch.js');
|
importScripts('./crypto-batch.js');
|
||||||
@ -20,18 +21,15 @@
|
|||||||
aes = new cryptoLib.AesCBC(forge),
|
aes = new cryptoLib.AesCBC(forge),
|
||||||
rsa = new cryptoLib.RSA(forge),
|
rsa = new cryptoLib.RSA(forge),
|
||||||
util = new cryptoLib.Util(),
|
util = new cryptoLib.Util(),
|
||||||
batch = new cryptoLib.CryptoBatch(aes, rsa, util);
|
batch = new cryptoLib.CryptoBatch(aes, rsa, util, _);
|
||||||
|
|
||||||
// pass RSA keys to module
|
if (i.type === 'encrypt' && i.receiverPubkeys && i.senderPrivkey && i.list) {
|
||||||
rsa.init(i.pubkeyPem, i.privkeyPem);
|
|
||||||
|
|
||||||
if (i.type === 'encrypt' && i.list) {
|
|
||||||
// start encryption
|
// 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
|
// start decryption
|
||||||
output = batch.decryptListForUser(i.list);
|
output = batch.decryptListForUser(i.list, i.senderPubkeys, i.receiverPrivkey);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw 'Not all arguments for web worker crypto are defined!';
|
throw 'Not all arguments for web worker crypto are defined!';
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
/**
|
/**
|
||||||
* Crypto batch library for processing large sets of data
|
* 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
|
* 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) {
|
this.encryptList = function(list) {
|
||||||
list.forEach(function(i) {
|
list.forEach(function(i) {
|
||||||
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypt a list of items using AES
|
* 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) {
|
this.decryptList = function(list) {
|
||||||
list.forEach(function(i) {
|
list.forEach(function(i) {
|
||||||
@ -36,19 +36,33 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypt and sign a list of items using AES and RSA
|
* 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) {
|
this.encryptListForUser = function(list, receiverPubkeys, senderPrivkey) {
|
||||||
// encrypt list
|
// encrypt list with aes
|
||||||
var encryptedList = this.encryptList(list);
|
var encryptedList = this.encryptList(list);
|
||||||
|
|
||||||
|
// set sender private key
|
||||||
|
rsa.init(null, senderPrivkey.privateKey);
|
||||||
|
|
||||||
// encrypt keys for user
|
// encrypt keys for user
|
||||||
encryptedList.forEach(function(i) {
|
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
|
// process new values
|
||||||
i.encryptedKey = rsa.encrypt(i.key);
|
i.encryptedKey = rsa.encrypt(i.key);
|
||||||
i.signature = rsa.sign([i.iv, util.str2Base64(i.id), i.encryptedKey, i.ciphertext]);
|
i.signature = rsa.sign([i.iv, util.str2Base64(i.id), i.encryptedKey, i.ciphertext]);
|
||||||
|
i.senderPk = senderPrivkey._id;
|
||||||
// delete old ones
|
// delete old ones
|
||||||
delete i.key;
|
delete i.key;
|
||||||
|
delete i.receiverPk;
|
||||||
});
|
});
|
||||||
|
|
||||||
return encryptedList;
|
return encryptedList;
|
||||||
@ -56,22 +70,35 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypt and verify a list of items using AES and RSA
|
* 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;
|
var j, self = this;
|
||||||
|
|
||||||
|
// set receiver private key
|
||||||
|
rsa.init(null, receiverPrivkey.privateKey);
|
||||||
|
|
||||||
// decrypt keys for user
|
// decrypt keys for user
|
||||||
encryptedList.forEach(function(i) {
|
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
|
// verify signature
|
||||||
if (!rsa.verify([i.iv, util.str2Base64(i.id), i.encryptedKey, i.ciphertext], i.signature)) {
|
if (!rsa.verify([i.iv, util.str2Base64(i.id), i.encryptedKey, i.ciphertext], i.signature)) {
|
||||||
throw new Error('Verifying RSA signature failed!');
|
throw new Error('Verifying RSA signature failed!');
|
||||||
}
|
}
|
||||||
// precoess new values
|
// process new values
|
||||||
i.key = rsa.decrypt(i.encryptedKey);
|
i.key = rsa.decrypt(i.encryptedKey);
|
||||||
// delete old values
|
// delete old values
|
||||||
delete i.signature;
|
delete i.signature;
|
||||||
delete i.encryptedKey;
|
delete i.encryptedKey;
|
||||||
|
delete i.senderPk;
|
||||||
});
|
});
|
||||||
|
|
||||||
// decrypt list
|
// decrypt list
|
||||||
|
@ -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
|
* 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
|
* Return a Private Key object containing the encrypted private key
|
||||||
*/
|
*/
|
||||||
@ -123,6 +127,8 @@ app.crypto.Crypto = function(window, util) {
|
|||||||
return storedKeypair;
|
return storedKeypair;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: not required since key is synced before crypto init in keychain dao getUserKeyPair
|
||||||
|
|
||||||
this.putEncryptedPrivateKey = function(privkey) {
|
this.putEncryptedPrivateKey = function(privkey) {
|
||||||
var strgId = (storageId) ? storageId : privkey.userId + '_encryptedKeypair';
|
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
|
// 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 = [],
|
var envelope, envelopes = [],
|
||||||
self = this;
|
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
|
// package objects into batchable envelope format
|
||||||
list.forEach(function(i) {
|
list.forEach(function(i) {
|
||||||
envelope = {
|
envelope = {
|
||||||
id: i.id,
|
id: i.id,
|
||||||
plaintext: i,
|
plaintext: i,
|
||||||
key: util.random(self.keySize),
|
key: util.random(self.keySize),
|
||||||
iv: util.random(self.ivSize)
|
iv: util.random(self.ivSize),
|
||||||
|
receiverPk: receiverPubkeys[0]._id
|
||||||
};
|
};
|
||||||
envelopes.push(envelope);
|
envelopes.push(envelope);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (window.Worker) {
|
if (window.Worker) {
|
||||||
|
|
||||||
var keypair = rsa.exportKeys();
|
|
||||||
|
|
||||||
var worker = new Worker(app.config.workerPath + '/crypto/crypto-batch-worker.js');
|
var worker = new Worker(app.config.workerPath + '/crypto/crypto-batch-worker.js');
|
||||||
worker.onmessage = function(e) {
|
worker.onmessage = function(e) {
|
||||||
callback(null, e.data);
|
callback(null, e.data);
|
||||||
@ -287,21 +305,32 @@ app.crypto.Crypto = function(window, util) {
|
|||||||
worker.postMessage({
|
worker.postMessage({
|
||||||
type: 'encrypt',
|
type: 'encrypt',
|
||||||
list: envelopes,
|
list: envelopes,
|
||||||
pubkeyPem: keypair.pubkeyPem,
|
senderPrivkey: senderPrivkey,
|
||||||
privkeyPem: keypair.privkeyPem
|
receiverPubkeys: receiverPubkeys
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
var batch = new cryptoLib.CryptoBatch(aes, rsa, util);
|
var batch = new cryptoLib.CryptoBatch(aes, rsa, util, _);
|
||||||
var encryptedList = batch.encryptListForUser(envelopes);
|
var encryptedList = batch.encryptListForUser(envelopes, receiverPubkeys, senderPrivkey);
|
||||||
callback(null, encryptedList);
|
callback(null, encryptedList);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.decryptListForUser = function(list, recipientPubkey, callback) {
|
this.decryptListForUser = function(list, senderPubkeys, callback) {
|
||||||
if (window.Worker) {
|
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');
|
var worker = new Worker(app.config.workerPath + '/crypto/crypto-batch-worker.js');
|
||||||
worker.onmessage = function(e) {
|
worker.onmessage = function(e) {
|
||||||
@ -310,13 +339,13 @@ app.crypto.Crypto = function(window, util) {
|
|||||||
worker.postMessage({
|
worker.postMessage({
|
||||||
type: 'decrypt',
|
type: 'decrypt',
|
||||||
list: list,
|
list: list,
|
||||||
pubkeyPem: keypair.pubkeyPem,
|
receiverPrivkey: receiverPrivkey,
|
||||||
privkeyPem: keypair.privkeyPem
|
senderPubkeys: senderPubkeys
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
var batch = new cryptoLib.CryptoBatch(aes, rsa, util);
|
var batch = new cryptoLib.CryptoBatch(aes, rsa, util, _);
|
||||||
var decryptedList = batch.decryptListForUser(list);
|
var decryptedList = batch.decryptListForUser(list, senderPubkeys, receiverPrivkey);
|
||||||
callback(null, decryptedList);
|
callback(null, decryptedList);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -98,7 +98,9 @@ asyncTest("AES/RSA encrypt batch for User (Async/Worker)", 2, function() {
|
|||||||
collection = td.getEmailCollection(10);
|
collection = td.getEmailCollection(10);
|
||||||
crypto_test.list = collection.toJSON();
|
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');
|
ok(!err && encryptedList, 'Encrypt list for user');
|
||||||
equal(encryptedList.length, crypto_test.list.length, 'Length of list');
|
equal(encryptedList.length, crypto_test.list.length, 'Length of list');
|
||||||
crypto_test.encryptedList = encryptedList;
|
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() {
|
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');
|
ok(!err && decryptedList, 'Decrypt list');
|
||||||
equal(decryptedList.length, crypto_test.list.length, 'Length of list');
|
equal(decryptedList.length, crypto_test.list.length, 'Length of list');
|
||||||
deepEqual(decryptedList, crypto_test.list, 'Decrypted list is correct');
|
deepEqual(decryptedList, crypto_test.list, 'Decrypted list is correct');
|
||||||
|
Loading…
Reference in New Issue
Block a user