mirror of
https://github.com/moparisthebest/mail
synced 2024-11-22 08:52:15 -05:00
started refacroting crypto
This commit is contained in:
parent
1b95066e12
commit
c9c53598e8
@ -5,44 +5,71 @@
|
|||||||
app.crypto.Crypto = function(window, util) {
|
app.crypto.Crypto = function(window, util) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var symmetricUserKey = null, // the user's secret key used to encrypt item-keys
|
var keypair = null, // the user's keys used to encrypt item-keys
|
||||||
keyId = null, // the key ID linking the user's key set
|
aes = new app.crypto.AesCBC(forge), // use AES-CBC mode by default
|
||||||
aes = new app.crypto.AesCBC(forge); // use AES-CBC mode by default
|
rsa = new app.crypto.RSA(forge, util); // use RSA for asym. crypto
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
this.init = function(emailAddress, password, keySize, ivSize, callback) {
|
this.init = function(args, callback) {
|
||||||
this.emailAddress = emailAddress;
|
var self = this;
|
||||||
this.keySize = keySize;
|
|
||||||
this.ivSize = ivSize;
|
this.emailAddress = args.emailAddress;
|
||||||
|
this.keySize = args.keySize;
|
||||||
|
this.ivSize = args.keySize;
|
||||||
|
|
||||||
// derive PBKDF2 from password in web worker thread
|
// derive PBKDF2 from password in web worker thread
|
||||||
this.deriveKey(password, keySize, function(pbkdf2) {
|
this.deriveKey(args.password, args.keySize, function(pbkdf2) {
|
||||||
|
|
||||||
// fetch user's encrypted secret key from keychain/storage
|
// fetch user's encrypted secret key from keychain/storage
|
||||||
var keyStore = new app.dao.LocalStorageDAO(window);
|
var keyStore = new app.dao.LocalStorageDAO(window);
|
||||||
var storageId = emailAddress + '_encryptedSymmetricKey';
|
var storageId = args.emailAddress + '_encryptedKeypair';
|
||||||
var storedKey = keyStore.read(storageId);
|
var storedKeypair = keyStore.read(storageId);
|
||||||
|
|
||||||
// check if key exists
|
// check if key exists
|
||||||
if (!storedKey) {
|
if (!storedKeypair) {
|
||||||
// generate key, encrypt and persist if none exists
|
// generate keys, encrypt and persist if none exists
|
||||||
symmetricUserKey = util.random(keySize);
|
generateKeypair(keyStore, storageId, pbkdf2);
|
||||||
var iv = util.random(ivSize);
|
|
||||||
var key = aes.encrypt(symmetricUserKey, pbkdf2, iv);
|
|
||||||
storedKey = {
|
|
||||||
_id: util.UUID(),
|
|
||||||
userId: emailAddress,
|
|
||||||
encryptedKey: key,
|
|
||||||
keyIV: iv
|
|
||||||
};
|
|
||||||
keyStore.persist(storageId, storedKey);
|
|
||||||
} else {
|
} else {
|
||||||
// decrypt key
|
// decrypt key
|
||||||
|
decryptKeypair(storedKeypair, pbkdf2);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
function generateKeypair(keyStore, storageId, pbkdf2) {
|
||||||
|
// generate RSA keypair in web worker
|
||||||
|
rsa.generateKeypair(rsa_test.keySize, function(err) {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
keypair = rsa.exportKeys();
|
||||||
|
|
||||||
|
// encrypt keypair
|
||||||
|
var iv = util.random(self.ivSize);
|
||||||
|
var encryptedKeys = aes.encrypt(JSON.stringify(keypair), pbkdf2, iv);
|
||||||
|
|
||||||
|
// store encrypted keypair
|
||||||
|
var newStoredKeypair = {
|
||||||
|
_id: keypair._id,
|
||||||
|
userId: args.emailAddress,
|
||||||
|
encryptedKeys: encryptedKeys,
|
||||||
|
keyIV: iv
|
||||||
|
};
|
||||||
|
keyStore.persist(storageId, newStoredKeypair);
|
||||||
|
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function decryptKeypair(storedKeypair, pbkdf2) {
|
||||||
try {
|
try {
|
||||||
symmetricUserKey = aes.decrypt(storedKey.encryptedKey, pbkdf2, storedKey.keyIV);
|
var keypairJson = aes.decrypt(storedKeypair.encryptedKeys, pbkdf2, storedKeypair.keyIV);
|
||||||
|
keypair = JSON.parse(keypairJson);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
callback({
|
callback({
|
||||||
errMsg: 'Wrong password!'
|
errMsg: 'Wrong password!'
|
||||||
@ -50,11 +77,8 @@ app.crypto.Crypto = function(window, util) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
keyId = storedKey._id;
|
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
});
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,18 +110,6 @@ app.crypto.Crypto = function(window, util) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Derive an asymmetric keypait from the user's secret
|
|
||||||
*/
|
|
||||||
this.deriveKeyPair = function(naclCrypto, callback) {
|
|
||||||
naclCrypto.generateKeypair(symmetricUserKey, function(keys) {
|
|
||||||
if (keyId) {
|
|
||||||
keys.id = keyId;
|
|
||||||
}
|
|
||||||
callback(keys);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// En/Decrypts single item
|
// En/Decrypts single item
|
||||||
//
|
//
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
/**
|
/**
|
||||||
* A Wrapper for Forge's RSA encryption
|
* A Wrapper for Forge's RSA encryption
|
||||||
*/
|
*/
|
||||||
app.crypto.RSA = function(forge) {
|
app.crypto.RSA = function(forge, util) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var utl = forge.util;
|
var utl = forge.util;
|
||||||
|
|
||||||
var publicKey = null,
|
var keypair = null;
|
||||||
privateKey = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the RSA module by passing the user's keypair
|
* Initializes the RSA module by passing the user's keypair
|
||||||
* The private key is option and required only for decryption
|
* The private key is option and required only for decryption
|
||||||
* and signing
|
* and signing
|
||||||
*/
|
*/
|
||||||
this.init = function(pubkeyPem, privkeyPem) {
|
this.init = function(pubkeyPem, privkeyPem, keyId) {
|
||||||
publicKey = forge.pki.publicKeyFromPem(pubkeyPem);
|
keypair.publicKey = forge.pki.publicKeyFromPem(pubkeyPem);
|
||||||
if (privkeyPem) {
|
if (privkeyPem) {
|
||||||
privateKey = forge.pki.privateKeyFromPem(privkeyPem);
|
keypair.privateKey = forge.pki.privateKeyFromPem(privkeyPem);
|
||||||
}
|
}
|
||||||
|
keypair._id = keyId;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,8 +28,8 @@ app.crypto.RSA = function(forge) {
|
|||||||
forge.rsa.generateKeyPair({
|
forge.rsa.generateKeyPair({
|
||||||
bits: keySize,
|
bits: keySize,
|
||||||
workerScript: app.config.workerPath + '/../../lib/forge/prime.worker.js'
|
workerScript: app.config.workerPath + '/../../lib/forge/prime.worker.js'
|
||||||
}, function(err, keypair) {
|
}, function(err, newKeypair) {
|
||||||
if (err || !keypair.publicKey || !keypair.privateKey) {
|
if (err || !newKeypair || !newKeypair.publicKey || !newKeypair.privateKey) {
|
||||||
callback({
|
callback({
|
||||||
errMsg: 'RSA keygeneration failed!',
|
errMsg: 'RSA keygeneration failed!',
|
||||||
err: err
|
err: err
|
||||||
@ -37,8 +37,9 @@ app.crypto.RSA = function(forge) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
publicKey = keypair.publicKey;
|
keypair = newKeypair;
|
||||||
privateKey = keypair.privateKey;
|
// generate unique keypair ID
|
||||||
|
keypair._id = util.UUID();
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
@ -49,8 +50,9 @@ app.crypto.RSA = function(forge) {
|
|||||||
*/
|
*/
|
||||||
this.exportKeys = function() {
|
this.exportKeys = function() {
|
||||||
return {
|
return {
|
||||||
pubkeyPem: forge.pki.publicKeyToPem(publicKey),
|
_id: keypair._id,
|
||||||
privkeyPem: forge.pki.privateKeyToPem(privateKey)
|
pubkeyPem: forge.pki.publicKeyToPem(keypair.publicKey),
|
||||||
|
privkeyPem: forge.pki.privateKeyToPem(keypair.privateKey)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -61,7 +63,7 @@ app.crypto.RSA = function(forge) {
|
|||||||
*/
|
*/
|
||||||
this.encrypt = function(plaintext) {
|
this.encrypt = function(plaintext) {
|
||||||
// encode plaintext to utf8 and encrypt
|
// encode plaintext to utf8 and encrypt
|
||||||
var ct = publicKey.encrypt(utl.encodeUtf8(plaintext));
|
var ct = keypair.publicKey.encrypt(utl.encodeUtf8(plaintext));
|
||||||
// encode ciphtext to base64
|
// encode ciphtext to base64
|
||||||
return utl.encode64(ct);
|
return utl.encode64(ct);
|
||||||
};
|
};
|
||||||
@ -75,7 +77,7 @@ app.crypto.RSA = function(forge) {
|
|||||||
// decode base64 ciphertext to utf8
|
// decode base64 ciphertext to utf8
|
||||||
var ctUtf8 = utl.decode64(ciphertext);
|
var ctUtf8 = utl.decode64(ciphertext);
|
||||||
// decrypt and decode to utf16
|
// decrypt and decode to utf16
|
||||||
return utl.decodeUtf8(privateKey.decrypt(ctUtf8));
|
return utl.decodeUtf8(keypair.privateKey.decrypt(ctUtf8));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -91,7 +93,7 @@ app.crypto.RSA = function(forge) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// encode signature to base64
|
// encode signature to base64
|
||||||
return utl.encode64(privateKey.sign(sha));
|
return utl.encode64(keypair.privateKey.sign(sha));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -110,7 +112,7 @@ app.crypto.RSA = function(forge) {
|
|||||||
sha.update(utl.decode64(i));
|
sha.update(utl.decode64(i));
|
||||||
});
|
});
|
||||||
|
|
||||||
return publicKey.verify(sha.digest().getBytes(), sigUtf8);
|
return keypair.publicKey.verify(sha.digest().getBytes(), sigUtf8);
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
@ -13,7 +13,11 @@ asyncTest("Init", 2, function() {
|
|||||||
crypto_test.crypto = new app.crypto.Crypto(window, crypto_test.util);
|
crypto_test.crypto = new app.crypto.Crypto(window, crypto_test.util);
|
||||||
ok(crypto_test.crypto, 'Crypto');
|
ok(crypto_test.crypto, 'Crypto');
|
||||||
|
|
||||||
crypto_test.crypto.init(crypto_test.user, crypto_test.password, crypto_test.keySize, crypto_test.ivSize, function() {
|
crypto_test.crypto.init({
|
||||||
|
emailAddress: crypto_test.user,
|
||||||
|
password: crypto_test.password,
|
||||||
|
keySize: crypto_test.keySize
|
||||||
|
}, function() {
|
||||||
ok(true, 'Init crypto');
|
ok(true, 'Init crypto');
|
||||||
|
|
||||||
start();
|
start();
|
||||||
|
@ -2,7 +2,7 @@ module("RSA Crypto");
|
|||||||
|
|
||||||
var rsa_test = {
|
var rsa_test = {
|
||||||
keySize: 1024,
|
keySize: 1024,
|
||||||
rsa: new app.crypto.RSA(forge),
|
rsa: new app.crypto.RSA(forge, new app.crypto.Util(window, uuid)),
|
||||||
test_message: '06a9214036b8a15b512e03d534120006'
|
test_message: '06a9214036b8a15b512e03d534120006'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user