1
0
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:
Tankred Hase 2013-08-30 16:05:33 +02:00
parent d1290e7a9f
commit 628cb0ddd9
6 changed files with 399 additions and 340 deletions

View File

@ -5,8 +5,8 @@
* 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) * Encrypt a String using AES-CBC-Pkcs7 using the provided keysize (e.g. 128, 256)
@ -15,20 +15,20 @@
* @param iv [String] The base64 encoded IV * @param iv [String] The base64 encoded IV
* @return [String] The base64 encoded ciphertext * @return [String] The base64 encoded ciphertext
*/ */
this.encrypt = function(plaintext, key, iv) { AesCBC.prototype.encrypt = function(plaintext, key, iv) {
// validate args // validate args
if (!plaintext || !key || !iv) { if (!plaintext || !key || !iv) {
throw new Error("Missing args for encryption!"); throw new Error("Missing args for encryption!");
} }
// decode args to utf8 and encrypt // decode args to utf8 and encrypt
var cipher = forge.aes.createEncryptionCipher(utl.decode64(key)); var cipher = this._forge.aes.createEncryptionCipher(this._forge.util.decode64(key));
cipher.start(utl.decode64(iv)); cipher.start(this._forge.util.decode64(iv));
cipher.update(utl.createBuffer(utl.encodeUtf8(plaintext))); cipher.update(this._forge.util.createBuffer(this._forge.util.encodeUtf8(plaintext)));
cipher.finish(); cipher.finish();
// encode to base64 // encode to base64
return utl.encode64(cipher.output.getBytes()); return this._forge.util.encode64(cipher.output.getBytes());
}; };
/** /**
@ -38,22 +38,44 @@
* @param iv [String] The base64 encoded IV * @param iv [String] The base64 encoded IV
* @return [String] The decrypted plaintext in UTF-16 * @return [String] The decrypted plaintext in UTF-16
*/ */
this.decrypt = function(ciphertext, key, iv) { AesCBC.prototype.decrypt = function(ciphertext, key, iv) {
// validate args // validate args
if (!ciphertext || !key || !iv) { if (!ciphertext || !key || !iv) {
throw new Error("Missing args for decryption!"); throw new Error("Missing args for decryption!");
} }
// decode args input to utf8 decrypt // decode args input to utf8 decrypt
var cipher = forge.aes.createDecryptionCipher(utl.decode64(key)); var cipher = this._forge.aes.createDecryptionCipher(this._forge.util.decode64(key));
cipher.start(utl.decode64(iv)); cipher.start(this._forge.util.decode64(iv));
cipher.update(utl.createBuffer(utl.decode64(ciphertext))); cipher.update(this._forge.util.createBuffer(this._forge.util.decode64(ciphertext)));
cipher.finish(); cipher.finish();
// decode to utf16 // decode to utf16
return utl.decodeUtf8(cipher.output.getBytes()); return this._forge.util.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!");
}
var hmac = self._forge.hmac.create();
hmac.start('sha256', self._forge.util.decode64(key));
parts.forEach(function(i) {
// decode base64 part and append to hmac msg
hmac.update(self._forge.util.decode64(i));
});
return self._forge.util.encode64(hmac.digest().getBytes());
}; };
if (typeof define !== 'undefined' && define.amd) { if (typeof define !== 'undefined' && define.amd) {

View File

@ -17,8 +17,27 @@
require(['cryptoLib/crypto-batch'], function(batch) { require(['cryptoLib/crypto-batch'], function(batch) {
var i = e.data, var output;
output = null;
try {
output = doOperation(batch, e.data);
} catch (e) {
output = {
err: {
errMsg: (e.message) ? e.message : e
}
};
}
// pass output back to main thread
self.postMessage(output);
});
});
};
function doOperation(batch, i) {
var output;
if (i.type === 'encrypt' && i.receiverPubkeys && i.senderPrivkey && i.list) { if (i.type === 'encrypt' && i.receiverPubkeys && i.senderPrivkey && i.list) {
// start encryption // start encryption
@ -37,14 +56,14 @@
output = batch.decryptKeysAndList(i.list, i.symKey); output = batch.decryptKeysAndList(i.list, i.symKey);
} else { } else {
throw 'Not all arguments for web worker crypto are defined!'; output = {
err: {
errMsg: 'Not all arguments for web worker crypto are defined!'
}
};
} }
// pass output back to main thread return output;
self.postMessage(output); }
});
});
};
}()); }());

View File

@ -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

View File

@ -2,14 +2,18 @@
* 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'
], function(util, aes, rsa, cryptoBatch, pbkdf2, app) {
'use strict'; '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
@ -288,7 +292,11 @@ define(['cryptoLib/util', 'cryptoLib/aes-cbc', 'cryptoLib/rsa', 'cryptoLib/crypt
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(e.data.err);
return;
}
// return result from the worker
callback(null, e.data); callback(null, e.data);
}; };
@ -297,7 +305,16 @@ define(['cryptoLib/util', 'cryptoLib/aes-cbc', 'cryptoLib/rsa', 'cryptoLib/crypt
} else { } else {
// no WebWorker support... do synchronous call // no WebWorker support... do synchronous call
var result = noWorker(); var result;
try {
result = noWorker();
} catch (e) {
callback({
errMsg: (e.message) ? e.message : e
});
return;
}
callback(null, result); callback(null, result);
} }
} }

View File

@ -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*/
}); });
}; };

View File

@ -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: ''
}); });