mirror of
https://github.com/moparisthebest/mail
synced 2025-02-26 07:41:48 -05:00
crypto error handling cleanup
This commit is contained in:
parent
d1290e7a9f
commit
628cb0ddd9
@ -1,69 +1,91 @@
|
|||||||
(function() {
|
(function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Wrapper for Forge's AES-CBC encryption
|
* A Wrapper for Forge's AES-CBC encryption
|
||||||
*/
|
*/
|
||||||
var AesCBC = function(forge) {
|
var AesCBC = function(forge) {
|
||||||
|
this._forge = forge;
|
||||||
|
};
|
||||||
|
|
||||||
var utl = forge.util;
|
/**
|
||||||
|
* Encrypt a String using AES-CBC-Pkcs7 using the provided keysize (e.g. 128, 256)
|
||||||
|
* @param plaintext [String] The input string in UTF-16
|
||||||
|
* @param key [String] The base64 encoded key
|
||||||
|
* @param iv [String] The base64 encoded IV
|
||||||
|
* @return [String] The base64 encoded ciphertext
|
||||||
|
*/
|
||||||
|
AesCBC.prototype.encrypt = function(plaintext, key, iv) {
|
||||||
|
// validate args
|
||||||
|
if (!plaintext || !key || !iv) {
|
||||||
|
throw new Error("Missing args for encryption!");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
// decode args to utf8 and encrypt
|
||||||
* Encrypt a String using AES-CBC-Pkcs7 using the provided keysize (e.g. 128, 256)
|
var cipher = this._forge.aes.createEncryptionCipher(this._forge.util.decode64(key));
|
||||||
* @param plaintext [String] The input string in UTF-16
|
cipher.start(this._forge.util.decode64(iv));
|
||||||
* @param key [String] The base64 encoded key
|
cipher.update(this._forge.util.createBuffer(this._forge.util.encodeUtf8(plaintext)));
|
||||||
* @param iv [String] The base64 encoded IV
|
cipher.finish();
|
||||||
* @return [String] The base64 encoded ciphertext
|
|
||||||
*/
|
|
||||||
this.encrypt = function(plaintext, key, iv) {
|
|
||||||
// validate args
|
|
||||||
if (!plaintext || !key || !iv) {
|
|
||||||
throw new Error("Missing args for encryption!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// decode args to utf8 and encrypt
|
// encode to base64
|
||||||
var cipher = forge.aes.createEncryptionCipher(utl.decode64(key));
|
return this._forge.util.encode64(cipher.output.getBytes());
|
||||||
cipher.start(utl.decode64(iv));
|
};
|
||||||
cipher.update(utl.createBuffer(utl.encodeUtf8(plaintext)));
|
|
||||||
cipher.finish();
|
|
||||||
|
|
||||||
// encode to base64
|
/**
|
||||||
return utl.encode64(cipher.output.getBytes());
|
* Decrypt a String using AES-CBC-Pkcs7 using the provided keysize (e.g. 128, 256)
|
||||||
};
|
* @param ciphertext [String] The base64 encoded ciphertext
|
||||||
|
* @param key [String] The base64 encoded key
|
||||||
|
* @param iv [String] The base64 encoded IV
|
||||||
|
* @return [String] The decrypted plaintext in UTF-16
|
||||||
|
*/
|
||||||
|
AesCBC.prototype.decrypt = function(ciphertext, key, iv) {
|
||||||
|
// validate args
|
||||||
|
if (!ciphertext || !key || !iv) {
|
||||||
|
throw new Error("Missing args for decryption!");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
// decode args input to utf8 decrypt
|
||||||
* Decrypt a String using AES-CBC-Pkcs7 using the provided keysize (e.g. 128, 256)
|
var cipher = this._forge.aes.createDecryptionCipher(this._forge.util.decode64(key));
|
||||||
* @param ciphertext [String] The base64 encoded ciphertext
|
cipher.start(this._forge.util.decode64(iv));
|
||||||
* @param key [String] The base64 encoded key
|
cipher.update(this._forge.util.createBuffer(this._forge.util.decode64(ciphertext)));
|
||||||
* @param iv [String] The base64 encoded IV
|
cipher.finish();
|
||||||
* @return [String] The decrypted plaintext in UTF-16
|
|
||||||
*/
|
|
||||||
this.decrypt = function(ciphertext, key, iv) {
|
|
||||||
// validate args
|
|
||||||
if (!ciphertext || !key || !iv) {
|
|
||||||
throw new Error("Missing args for decryption!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// decode args input to utf8 decrypt
|
// decode to utf16
|
||||||
var cipher = forge.aes.createDecryptionCipher(utl.decode64(key));
|
return this._forge.util.decodeUtf8(cipher.output.getBytes());
|
||||||
cipher.start(utl.decode64(iv));
|
};
|
||||||
cipher.update(utl.createBuffer(utl.decode64(ciphertext)));
|
|
||||||
cipher.finish();
|
|
||||||
|
|
||||||
// decode to utf16
|
/**
|
||||||
return utl.decodeUtf8(cipher.output.getBytes());
|
* Calculate a hmac using SHA-256 for a given input
|
||||||
};
|
* @param parts [Array] Array of Base64 encoded parts
|
||||||
|
* @param key [String] The base64 encoded key
|
||||||
|
* @return [String] The Base64 encoded hmac
|
||||||
|
*/
|
||||||
|
AesCBC.prototype.hmac = function(parts, key) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
};
|
// validate args
|
||||||
|
if (!parts || !key) {
|
||||||
|
throw new Error("Missing args for hmac processing!");
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof define !== 'undefined' && define.amd) {
|
var hmac = self._forge.hmac.create();
|
||||||
// AMD
|
hmac.start('sha256', self._forge.util.decode64(key));
|
||||||
define(['forge'], function(forge) {
|
parts.forEach(function(i) {
|
||||||
return new AesCBC(forge);
|
// decode base64 part and append to hmac msg
|
||||||
});
|
hmac.update(self._forge.util.decode64(i));
|
||||||
} else if (typeof module !== 'undefined' && module.exports) {
|
});
|
||||||
// node.js
|
|
||||||
module.exports = new AesCBC(require('node-forge'));
|
return self._forge.util.encode64(hmac.digest().getBytes());
|
||||||
}
|
};
|
||||||
|
|
||||||
|
if (typeof define !== 'undefined' && define.amd) {
|
||||||
|
// AMD
|
||||||
|
define(['forge'], function(forge) {
|
||||||
|
return new AesCBC(forge);
|
||||||
|
});
|
||||||
|
} else if (typeof module !== 'undefined' && module.exports) {
|
||||||
|
// node.js
|
||||||
|
module.exports = new AesCBC(require('node-forge'));
|
||||||
|
}
|
||||||
|
|
||||||
})();
|
})();
|
@ -17,27 +17,16 @@
|
|||||||
|
|
||||||
require(['cryptoLib/crypto-batch'], function(batch) {
|
require(['cryptoLib/crypto-batch'], function(batch) {
|
||||||
|
|
||||||
var i = e.data,
|
var output;
|
||||||
output = null;
|
|
||||||
|
|
||||||
if (i.type === 'encrypt' && i.receiverPubkeys && i.senderPrivkey && i.list) {
|
try {
|
||||||
// start encryption
|
output = doOperation(batch, e.data);
|
||||||
output = batch.encryptListForUser(i.list, i.receiverPubkeys, i.senderPrivkey);
|
} catch (e) {
|
||||||
|
output = {
|
||||||
} else if (i.type === 'decrypt' && i.senderPubkeys && i.receiverPrivkey && i.list) {
|
err: {
|
||||||
// start decryption
|
errMsg: (e.message) ? e.message : e
|
||||||
output = batch.decryptListForUser(i.list, i.senderPubkeys, i.receiverPrivkey);
|
}
|
||||||
|
};
|
||||||
} 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 {
|
|
||||||
throw 'Not all arguments for web worker crypto are defined!';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// pass output back to main thread
|
// pass output back to main thread
|
||||||
@ -47,4 +36,34 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function doOperation(batch, i) {
|
||||||
|
var output;
|
||||||
|
|
||||||
|
if (i.type === 'encrypt' && 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) {
|
||||||
|
// start decryption
|
||||||
|
output = batch.decryptListForUser(i.list, i.senderPubkeys, i.receiverPrivkey);
|
||||||
|
|
||||||
|
} 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 {
|
||||||
|
output = {
|
||||||
|
err: {
|
||||||
|
errMsg: 'Not all arguments for web worker crypto are defined!'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
}());
|
}());
|
@ -28,7 +28,7 @@
|
|||||||
// set sender's keypair id for later verification
|
// set sender's keypair id for later verification
|
||||||
i.senderPk = senderKeyId;
|
i.senderPk = senderKeyId;
|
||||||
// sign the bundle
|
// sign the bundle
|
||||||
i.signature = rsa.sign([i.iv, util.str2Base64(i.id), util.str2Base64(i.senderPk), i.encryptedKey, i.ciphertext]);
|
i.signature = rsa.sign([i.iv, util.str2Base64(i.senderPk), i.encryptedKey, i.ciphertext]);
|
||||||
|
|
||||||
// delete plaintext values
|
// delete plaintext values
|
||||||
delete i.plaintext;
|
delete i.plaintext;
|
||||||
@ -79,7 +79,7 @@
|
|||||||
rsa.init(senderPubkey);
|
rsa.init(senderPubkey);
|
||||||
|
|
||||||
// verify signature
|
// verify signature
|
||||||
if (!rsa.verify([i.iv, util.str2Base64(i.id), util.str2Base64(i.senderPk), i.encryptedKey, i.ciphertext], i.signature)) {
|
if (!rsa.verify([i.iv, util.str2Base64(i.senderPk), i.encryptedKey, i.ciphertext], i.signature)) {
|
||||||
throw new Error('Verifying RSA signature failed!');
|
throw new Error('Verifying RSA signature failed!');
|
||||||
}
|
}
|
||||||
// decrypt symmetric item key for user
|
// decrypt symmetric item key for user
|
||||||
|
@ -2,305 +2,322 @@
|
|||||||
* High level crypto api that invokes native crypto (if available) and
|
* High level crypto api that invokes native crypto (if available) and
|
||||||
* gracefully degrades to JS crypto (if unavailable)
|
* gracefully degrades to JS crypto (if unavailable)
|
||||||
*/
|
*/
|
||||||
define(['cryptoLib/util', 'cryptoLib/aes-cbc', 'cryptoLib/rsa', 'cryptoLib/crypto-batch',
|
define(function(require) {
|
||||||
'js/crypto/pbkdf2', 'js/app-config'
|
'use strict';
|
||||||
], function(util, aes, rsa, cryptoBatch, pbkdf2, app) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var self = {};
|
var util = require('cryptoLib/util'),
|
||||||
|
aes = require('cryptoLib/aes-cbc'),
|
||||||
|
rsa = require('cryptoLib/rsa'),
|
||||||
|
cryptoBatch = require('cryptoLib/crypto-batch'),
|
||||||
|
pbkdf2 = require('js/crypto/pbkdf2'),
|
||||||
|
app = require('js/app-config');
|
||||||
|
|
||||||
var passBasedKey;
|
var self = {},
|
||||||
|
passBasedKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the crypto modules by fetching the user's
|
* Initializes the crypto modules by fetching the user's
|
||||||
* encrypted secret key from storage and storing it in memory.
|
* encrypted secret key from storage and storing it in memory.
|
||||||
*/
|
*/
|
||||||
self.init = function(args, callback) {
|
self.init = function(args, callback) {
|
||||||
// valdiate input
|
// valdiate input
|
||||||
if (!args.emailAddress || !args.keySize || !args.rsaKeySize) {
|
if (!args.emailAddress || !args.keySize || !args.rsaKeySize) {
|
||||||
callback({
|
callback({
|
||||||
errMsg: 'Crypto init failed. Not all args set!'
|
errMsg: 'Crypto init failed. Not all args set!'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.emailAddress = args.emailAddress;
|
self.emailAddress = args.emailAddress;
|
||||||
self.keySize = args.keySize;
|
self.keySize = args.keySize;
|
||||||
self.ivSize = args.keySize;
|
self.ivSize = args.keySize;
|
||||||
self.rsaKeySize = args.rsaKeySize;
|
self.rsaKeySize = args.rsaKeySize;
|
||||||
|
|
||||||
// derive PBKDF2 from password in web worker thread
|
// derive PBKDF2 from password in web worker thread
|
||||||
self.deriveKey(args.password, self.keySize, function(err, derivedKey) {
|
self.deriveKey(args.password, self.keySize, function(err, derivedKey) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// remember pbkdf2 for later use
|
// remember pbkdf2 for later use
|
||||||
passBasedKey = derivedKey;
|
passBasedKey = derivedKey;
|
||||||
|
|
||||||
// check if key exists
|
// check if key exists
|
||||||
if (!args.storedKeypair) {
|
if (!args.storedKeypair) {
|
||||||
// generate keys, encrypt and persist if none exists
|
// generate keys, encrypt and persist if none exists
|
||||||
generateKeypair(derivedKey);
|
generateKeypair(derivedKey);
|
||||||
} else {
|
} else {
|
||||||
// decrypt key
|
// decrypt key
|
||||||
decryptKeypair(args.storedKeypair, derivedKey);
|
decryptKeypair(args.storedKeypair, derivedKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function generateKeypair(derivedKey) {
|
function generateKeypair(derivedKey) {
|
||||||
// generate RSA keypair in web worker
|
// generate RSA keypair in web worker
|
||||||
rsa.generateKeypair(self.rsaKeySize, function(err, generatedKeypair) {
|
rsa.generateKeypair(self.rsaKeySize, function(err, generatedKeypair) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// encrypt keypair
|
// encrypt keypair
|
||||||
var iv = util.random(self.ivSize);
|
var iv = util.random(self.ivSize);
|
||||||
var encryptedPrivateKey = aes.encrypt(generatedKeypair.privkeyPem, derivedKey, iv);
|
var encryptedPrivateKey = aes.encrypt(generatedKeypair.privkeyPem, derivedKey, iv);
|
||||||
|
|
||||||
// new encrypted keypair object
|
// new encrypted keypair object
|
||||||
var newKeypair = {
|
var newKeypair = {
|
||||||
publicKey: {
|
publicKey: {
|
||||||
_id: generatedKeypair._id,
|
_id: generatedKeypair._id,
|
||||||
userId: self.emailAddress,
|
userId: self.emailAddress,
|
||||||
publicKey: generatedKeypair.pubkeyPem
|
publicKey: generatedKeypair.pubkeyPem
|
||||||
},
|
},
|
||||||
privateKey: {
|
privateKey: {
|
||||||
_id: generatedKeypair._id,
|
_id: generatedKeypair._id,
|
||||||
userId: self.emailAddress,
|
userId: self.emailAddress,
|
||||||
encryptedKey: encryptedPrivateKey,
|
encryptedKey: encryptedPrivateKey,
|
||||||
iv: iv
|
iv: iv
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// return generated keypair for storage in keychain dao
|
// return generated keypair for storage in keychain dao
|
||||||
callback(null, newKeypair);
|
callback(null, newKeypair);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function decryptKeypair(storedKeypair, derivedKey) {
|
function decryptKeypair(storedKeypair, derivedKey) {
|
||||||
var decryptedPrivateKey;
|
var decryptedPrivateKey;
|
||||||
|
|
||||||
// validate input
|
// validate input
|
||||||
if (!storedKeypair || !storedKeypair.privateKey || !storedKeypair.privateKey.encryptedKey || !storedKeypair.privateKey.iv) {
|
if (!storedKeypair || !storedKeypair.privateKey || !storedKeypair.privateKey.encryptedKey || !storedKeypair.privateKey.iv) {
|
||||||
callback({
|
callback({
|
||||||
errMsg: 'Incomplete arguments for private key decryption!'
|
errMsg: 'Incomplete arguments for private key decryption!'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to decrypt with derivedKey
|
// try to decrypt with derivedKey
|
||||||
try {
|
try {
|
||||||
var prK = storedKeypair.privateKey;
|
var prK = storedKeypair.privateKey;
|
||||||
decryptedPrivateKey = aes.decrypt(prK.encryptedKey, derivedKey, prK.iv);
|
decryptedPrivateKey = aes.decrypt(prK.encryptedKey, derivedKey, prK.iv);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
callback({
|
callback({
|
||||||
errMsg: 'Wrong password!'
|
errMsg: 'Wrong password!'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// set rsa keys
|
// set rsa keys
|
||||||
rsa.init(storedKeypair.publicKey.publicKey, decryptedPrivateKey, storedKeypair.publicKey._id);
|
rsa.init(storedKeypair.publicKey.publicKey, decryptedPrivateKey, storedKeypair.publicKey._id);
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do PBKDF2 key derivation in a WebWorker thread
|
* Do PBKDF2 key derivation in a WebWorker thread
|
||||||
*/
|
*/
|
||||||
self.deriveKey = function(password, keySize, callback) {
|
self.deriveKey = function(password, keySize, callback) {
|
||||||
startWorker('/crypto/pbkdf2-worker.js', {
|
startWorker('/crypto/pbkdf2-worker.js', {
|
||||||
password: password,
|
password: password,
|
||||||
keySize: keySize
|
keySize: keySize
|
||||||
}, callback, function() {
|
}, callback, function() {
|
||||||
return pbkdf2.getKey(password, keySize);
|
return pbkdf2.getKey(password, keySize);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// En/Decrypts single item
|
// En/Decrypts single item
|
||||||
//
|
//
|
||||||
|
|
||||||
self.aesEncrypt = function(plaintext, key, iv, callback) {
|
self.aesEncrypt = function(plaintext, key, iv, callback) {
|
||||||
startWorker('/crypto/aes-worker.js', {
|
startWorker('/crypto/aes-worker.js', {
|
||||||
type: 'encrypt',
|
type: 'encrypt',
|
||||||
plaintext: plaintext,
|
plaintext: plaintext,
|
||||||
key: key,
|
key: key,
|
||||||
iv: iv
|
iv: iv
|
||||||
}, callback, function() {
|
}, callback, function() {
|
||||||
return self.aesEncryptSync(plaintext, key, iv);
|
return self.aesEncryptSync(plaintext, key, iv);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
self.aesDecrypt = function(ciphertext, key, iv, callback) {
|
self.aesDecrypt = function(ciphertext, key, iv, callback) {
|
||||||
startWorker('/crypto/aes-worker.js', {
|
startWorker('/crypto/aes-worker.js', {
|
||||||
type: 'decrypt',
|
type: 'decrypt',
|
||||||
ciphertext: ciphertext,
|
ciphertext: ciphertext,
|
||||||
key: key,
|
key: key,
|
||||||
iv: iv
|
iv: iv
|
||||||
}, callback, function() {
|
}, callback, function() {
|
||||||
return self.aesDecryptSync(ciphertext, key, iv);
|
return self.aesDecryptSync(ciphertext, key, iv);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
self.aesEncryptSync = function(plaintext, key, iv) {
|
self.aesEncryptSync = function(plaintext, key, iv) {
|
||||||
return aes.encrypt(plaintext, key, iv);
|
return aes.encrypt(plaintext, key, iv);
|
||||||
};
|
};
|
||||||
|
|
||||||
self.aesDecryptSync = function(ciphertext, key, iv) {
|
self.aesDecryptSync = function(ciphertext, key, iv) {
|
||||||
return aes.decrypt(ciphertext, key, iv);
|
return aes.decrypt(ciphertext, key, iv);
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// En/Decrypt a list of items with AES in a WebWorker thread
|
// En/Decrypt a list of items with AES in a WebWorker thread
|
||||||
//
|
//
|
||||||
|
|
||||||
self.aesEncryptList = function(list, callback) {
|
self.aesEncryptList = function(list, callback) {
|
||||||
startWorker('/crypto/aes-batch-worker.js', {
|
startWorker('/crypto/aes-batch-worker.js', {
|
||||||
type: 'encrypt',
|
type: 'encrypt',
|
||||||
list: list
|
list: list
|
||||||
}, callback, function() {
|
}, callback, function() {
|
||||||
return cryptoBatch.encryptList(list);
|
return cryptoBatch.encryptList(list);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
self.aesDecryptList = function(list, callback) {
|
self.aesDecryptList = function(list, callback) {
|
||||||
startWorker('/crypto/aes-batch-worker.js', {
|
startWorker('/crypto/aes-batch-worker.js', {
|
||||||
type: 'decrypt',
|
type: 'decrypt',
|
||||||
list: list
|
list: list
|
||||||
}, callback, function() {
|
}, callback, function() {
|
||||||
return cryptoBatch.decryptList(list);
|
return cryptoBatch.decryptList(list);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// En/Decrypt something speficially using the user's secret key
|
// En/Decrypt something speficially using the user's secret key
|
||||||
//
|
//
|
||||||
|
|
||||||
self.encryptListForUser = function(list, receiverPubkeys, callback) {
|
self.encryptListForUser = function(list, receiverPubkeys, callback) {
|
||||||
var envelope, envelopes = [];
|
var envelope, envelopes = [];
|
||||||
|
|
||||||
if (!receiverPubkeys || receiverPubkeys.length !== 1) {
|
if (!receiverPubkeys || receiverPubkeys.length !== 1) {
|
||||||
callback({
|
callback({
|
||||||
errMsg: 'Encryption is currently implemented for only one receiver!'
|
errMsg: 'Encryption is currently implemented for only one receiver!'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var keypair = rsa.exportKeys();
|
var keypair = rsa.exportKeys();
|
||||||
var senderPrivkey = {
|
var senderPrivkey = {
|
||||||
_id: keypair._id,
|
_id: keypair._id,
|
||||||
privateKey: keypair.privkeyPem
|
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
|
receiverPk: receiverPubkeys[0]._id
|
||||||
};
|
};
|
||||||
envelopes.push(envelope);
|
envelopes.push(envelope);
|
||||||
});
|
});
|
||||||
|
|
||||||
startWorker('/crypto/crypto-batch-worker.js', {
|
startWorker('/crypto/crypto-batch-worker.js', {
|
||||||
type: 'encrypt',
|
type: 'encrypt',
|
||||||
list: envelopes,
|
list: envelopes,
|
||||||
senderPrivkey: senderPrivkey,
|
senderPrivkey: senderPrivkey,
|
||||||
receiverPubkeys: receiverPubkeys
|
receiverPubkeys: receiverPubkeys
|
||||||
}, callback, function() {
|
}, callback, function() {
|
||||||
return cryptoBatch.encryptListForUser(envelopes, receiverPubkeys, senderPrivkey);
|
return cryptoBatch.encryptListForUser(envelopes, receiverPubkeys, senderPrivkey);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
self.decryptListForUser = function(list, senderPubkeys, callback) {
|
self.decryptListForUser = function(list, senderPubkeys, callback) {
|
||||||
if (!senderPubkeys || senderPubkeys < 1) {
|
if (!senderPubkeys || senderPubkeys < 1) {
|
||||||
callback({
|
callback({
|
||||||
errMsg: 'Sender public keys must be set!'
|
errMsg: 'Sender public keys must be set!'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var keypair = rsa.exportKeys();
|
var keypair = rsa.exportKeys();
|
||||||
var receiverPrivkey = {
|
var receiverPrivkey = {
|
||||||
_id: keypair._id,
|
_id: keypair._id,
|
||||||
privateKey: keypair.privkeyPem
|
privateKey: keypair.privkeyPem
|
||||||
};
|
};
|
||||||
|
|
||||||
startWorker('/crypto/crypto-batch-worker.js', {
|
startWorker('/crypto/crypto-batch-worker.js', {
|
||||||
type: 'decrypt',
|
type: 'decrypt',
|
||||||
list: list,
|
list: list,
|
||||||
receiverPrivkey: receiverPrivkey,
|
receiverPrivkey: receiverPrivkey,
|
||||||
senderPubkeys: senderPubkeys
|
senderPubkeys: senderPubkeys
|
||||||
}, callback, function() {
|
}, callback, function() {
|
||||||
return cryptoBatch.decryptListForUser(list, senderPubkeys, receiverPrivkey);
|
return cryptoBatch.decryptListForUser(list, senderPubkeys, receiverPrivkey);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Re-encrypt keys item and items seperately
|
// Re-encrypt keys item and items seperately
|
||||||
//
|
//
|
||||||
|
|
||||||
self.reencryptListKeysForUser = function(list, senderPubkeys, callback) {
|
self.reencryptListKeysForUser = function(list, senderPubkeys, callback) {
|
||||||
var keypair = rsa.exportKeys();
|
var keypair = rsa.exportKeys();
|
||||||
var receiverPrivkey = {
|
var receiverPrivkey = {
|
||||||
_id: keypair._id,
|
_id: keypair._id,
|
||||||
privateKey: keypair.privkeyPem
|
privateKey: keypair.privkeyPem
|
||||||
};
|
};
|
||||||
|
|
||||||
startWorker('/crypto/crypto-batch-worker.js', {
|
startWorker('/crypto/crypto-batch-worker.js', {
|
||||||
type: 'reencrypt',
|
type: 'reencrypt',
|
||||||
list: list,
|
list: list,
|
||||||
receiverPrivkey: receiverPrivkey,
|
receiverPrivkey: receiverPrivkey,
|
||||||
senderPubkeys: senderPubkeys,
|
senderPubkeys: senderPubkeys,
|
||||||
symKey: passBasedKey
|
symKey: passBasedKey
|
||||||
}, callback, function() {
|
}, callback, function() {
|
||||||
return cryptoBatch.reencryptListKeysForUser(list, senderPubkeys, receiverPrivkey, passBasedKey);
|
return cryptoBatch.reencryptListKeysForUser(list, senderPubkeys, receiverPrivkey, passBasedKey);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
self.decryptKeysAndList = function(list, callback) {
|
self.decryptKeysAndList = function(list, callback) {
|
||||||
startWorker('/crypto/crypto-batch-worker.js', {
|
startWorker('/crypto/crypto-batch-worker.js', {
|
||||||
type: 'decryptItems',
|
type: 'decryptItems',
|
||||||
list: list,
|
list: list,
|
||||||
symKey: passBasedKey
|
symKey: passBasedKey
|
||||||
}, callback, function() {
|
}, callback, function() {
|
||||||
return cryptoBatch.decryptKeysAndList(list, passBasedKey);
|
return cryptoBatch.decryptKeysAndList(list, passBasedKey);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// helper functions
|
// helper functions
|
||||||
//
|
//
|
||||||
|
|
||||||
function startWorker(script, args, callback, noWorker) {
|
function startWorker(script, args, callback, noWorker) {
|
||||||
// check for WebWorker support
|
// check for WebWorker support
|
||||||
if (window.Worker) {
|
if (window.Worker) {
|
||||||
|
|
||||||
// init webworker thread
|
// init webworker thread
|
||||||
var worker = new Worker(app.config.workerPath + script);
|
var worker = new Worker(app.config.workerPath + script);
|
||||||
|
|
||||||
worker.onmessage = function(e) {
|
worker.onmessage = function(e) {
|
||||||
// return derived key from the worker
|
if (e.data.err) {
|
||||||
callback(null, e.data);
|
callback(e.data.err);
|
||||||
};
|
return;
|
||||||
|
}
|
||||||
|
// return result from the worker
|
||||||
|
callback(null, e.data);
|
||||||
|
};
|
||||||
|
|
||||||
// send data to the worker
|
// send data to the worker
|
||||||
worker.postMessage(args);
|
worker.postMessage(args);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// no WebWorker support... do synchronous call
|
// no WebWorker support... do synchronous call
|
||||||
var result = noWorker();
|
var result;
|
||||||
callback(null, result);
|
try {
|
||||||
}
|
result = noWorker();
|
||||||
}
|
} catch (e) {
|
||||||
|
callback({
|
||||||
|
errMsg: (e.message) ? e.message : e
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return self;
|
callback(null, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
});
|
});
|
@ -298,7 +298,7 @@ define(function(require) {
|
|||||||
|
|
||||||
/* message was not found in cache... fetch from imap server */
|
/* message was not found in cache... fetch from imap server */
|
||||||
|
|
||||||
function messageReady(err, gottenMessage) {
|
function bodyReady(err, gottenMessage) {
|
||||||
message = gottenMessage;
|
message = gottenMessage;
|
||||||
itemCounter++;
|
itemCounter++;
|
||||||
// remember how many items should be fetched before the callback fires
|
// remember how many items should be fetched before the callback fires
|
||||||
@ -311,10 +311,10 @@ define(function(require) {
|
|||||||
|
|
||||||
// decrypt Message body
|
// decrypt Message body
|
||||||
if (message.body.indexOf(PREFIX) !== -1 && message.body.indexOf(SUFFIX) !== -1) {
|
if (message.body.indexOf(PREFIX) !== -1 && message.body.indexOf(SUFFIX) !== -1) {
|
||||||
decryptMessageBody(message, function(err, ptMessage) {
|
decryptBody(message, function(err, ptMessage) {
|
||||||
message = ptMessage;
|
message = ptMessage;
|
||||||
// return decrypted message
|
// return decrypted message
|
||||||
callback(null, message);
|
callback(err, message);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -325,7 +325,7 @@ define(function(require) {
|
|||||||
//check();
|
//check();
|
||||||
}
|
}
|
||||||
|
|
||||||
function decryptMessageBody(email, callback) {
|
function decryptBody(email, callback) {
|
||||||
var ctMessageBase64, ctMessage, pubkeyIds;
|
var ctMessageBase64, ctMessage, pubkeyIds;
|
||||||
|
|
||||||
// parse email body for encrypted message block
|
// parse email body for encrypted message block
|
||||||
@ -390,7 +390,8 @@ define(function(require) {
|
|||||||
self._imapClient.getMessage({
|
self._imapClient.getMessage({
|
||||||
path: options.folder,
|
path: options.folder,
|
||||||
uid: options.uid,
|
uid: options.uid,
|
||||||
onMessage: messageReady,
|
onBody: bodyReady,
|
||||||
|
onEnd: bodyReady
|
||||||
/*onAttachment: attachmentReady*/
|
/*onAttachment: attachmentReady*/
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -272,7 +272,7 @@ define(function(require) {
|
|||||||
it('should parse message body without attachement', function(done) {
|
it('should parse message body without attachement', function(done) {
|
||||||
var uid = 415;
|
var uid = 415;
|
||||||
|
|
||||||
imapClientStub.getMessage.yieldsTo('onMessage', null, {
|
imapClientStub.getMessage.yieldsTo('onBody', null, {
|
||||||
uid: uid,
|
uid: uid,
|
||||||
body: ''
|
body: ''
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user