mirror of
https://github.com/moparisthebest/mail
synced 2024-11-22 17:02:17 -05:00
Refactor crypto module
This commit is contained in:
parent
f4fe1a36a6
commit
88a48ec540
@ -13,27 +13,22 @@ var aes = require('crypto-lib').aes,
|
|||||||
* 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)
|
||||||
*/
|
*/
|
||||||
function Crypto() {}
|
function Crypto($q) {
|
||||||
|
this._q = $q;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypt plaintext using AES-GCM.
|
* Encrypt plaintext using AES-GCM.
|
||||||
* @param {String} plaintext The input string in UTF-16
|
* @param {String} plaintext The input string in UTF-16
|
||||||
* @param {String} key The base64 encoded key
|
* @param {String} key The base64 encoded key
|
||||||
* @param {String} iv The base64 encoded IV
|
* @param {String} iv The base64 encoded IV
|
||||||
* @param {Function} callback(error, ciphertext)
|
|
||||||
* @return {String} The base64 encoded ciphertext
|
* @return {String} The base64 encoded ciphertext
|
||||||
*/
|
*/
|
||||||
Crypto.prototype.encrypt = function(plaintext, key, iv, callback) {
|
Crypto.prototype.encrypt = function(plaintext, key, iv) {
|
||||||
var ct;
|
return this._q(function(resolve) {
|
||||||
|
var ct = aes.encrypt(plaintext, key, iv);
|
||||||
try {
|
resolve(ct);
|
||||||
ct = aes.encrypt(plaintext, key, iv);
|
});
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(null, ct);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,34 +36,26 @@ Crypto.prototype.encrypt = function(plaintext, key, iv, callback) {
|
|||||||
* @param {String} ciphertext The base64 encoded ciphertext
|
* @param {String} ciphertext The base64 encoded ciphertext
|
||||||
* @param {String} key The base64 encoded key
|
* @param {String} key The base64 encoded key
|
||||||
* @param {String} iv The base64 encoded IV
|
* @param {String} iv The base64 encoded IV
|
||||||
* @param {Function} callback(error, plaintext)
|
|
||||||
* @return {String} The decrypted plaintext in UTF-16
|
* @return {String} The decrypted plaintext in UTF-16
|
||||||
*/
|
*/
|
||||||
Crypto.prototype.decrypt = function(ciphertext, key, iv, callback) {
|
Crypto.prototype.decrypt = function(ciphertext, key, iv) {
|
||||||
var pt;
|
return this._q(function(resolve) {
|
||||||
|
var pt = aes.decrypt(ciphertext, key, iv);
|
||||||
try {
|
resolve(pt);
|
||||||
pt = aes.decrypt(ciphertext, key, iv);
|
});
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(null, pt);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do PBKDF2 key derivation in a WebWorker thread
|
* Do PBKDF2 key derivation in a WebWorker thread
|
||||||
*/
|
*/
|
||||||
Crypto.prototype.deriveKey = function(password, salt, keySize, callback) {
|
Crypto.prototype.deriveKey = function(password, salt, keySize) {
|
||||||
startWorker({
|
return this.startWorker({
|
||||||
script: config.workerPath + '/pbkdf2-worker.min.js',
|
script: config.workerPath + '/pbkdf2-worker.min.js',
|
||||||
args: {
|
args: {
|
||||||
password: password,
|
password: password,
|
||||||
salt: salt,
|
salt: salt,
|
||||||
keySize: keySize
|
keySize: keySize
|
||||||
},
|
},
|
||||||
callback: callback,
|
|
||||||
noWorker: function() {
|
noWorker: function() {
|
||||||
return pbkdf2.getKey(password, salt, keySize);
|
return pbkdf2.getKey(password, salt, keySize);
|
||||||
}
|
}
|
||||||
@ -79,27 +66,25 @@ Crypto.prototype.deriveKey = function(password, salt, keySize, callback) {
|
|||||||
// helper functions
|
// helper functions
|
||||||
//
|
//
|
||||||
|
|
||||||
function startWorker(options) {
|
Crypto.prototype.startWorker = function(options) {
|
||||||
|
return this._q(function(resolve, reject) {
|
||||||
// check for WebWorker support
|
// check for WebWorker support
|
||||||
if (window.Worker) {
|
if (window.Worker) {
|
||||||
// init webworker thread
|
// init webworker thread
|
||||||
var worker = new Worker(options.script);
|
var worker = new Worker(options.script);
|
||||||
worker.onmessage = function(e) {
|
worker.onmessage = function(e) {
|
||||||
if (e.data.err) {
|
|
||||||
options.callback(e.data.err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// return result from the worker
|
// return result from the worker
|
||||||
options.callback(null, e.data);
|
if (e.data.err) {
|
||||||
|
reject(e.data.err);
|
||||||
|
} else {
|
||||||
|
resolve(e.data);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
worker.onerror = function(e) {
|
worker.onerror = function(e) {
|
||||||
// show error message in logger
|
// show error message in logger
|
||||||
axe.error('Error handling web worker: Line ' + e.lineno + ' in ' + e.filename + ': ' + e.message);
|
axe.error('Error handling web worker: Line ' + e.lineno + ' in ' + e.filename + ': ' + e.message);
|
||||||
// return error
|
// return error
|
||||||
options.callback({
|
reject(e);
|
||||||
errMsg: (e.message) ? e.message : e
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
// send data to the worker
|
// send data to the worker
|
||||||
worker.postMessage(options.args);
|
worker.postMessage(options.args);
|
||||||
@ -107,15 +92,7 @@ function startWorker(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// no WebWorker support... do synchronous call
|
// no WebWorker support... do synchronous call
|
||||||
var result;
|
var result = options.noWorker();
|
||||||
try {
|
resolve(result);
|
||||||
result = options.noWorker();
|
|
||||||
} catch (e) {
|
|
||||||
// return error
|
|
||||||
options.callback({
|
|
||||||
errMsg: (e.message) ? e.message : e
|
|
||||||
});
|
});
|
||||||
return;
|
};
|
||||||
}
|
|
||||||
options.callback(null, result);
|
|
||||||
}
|
|
@ -13,7 +13,7 @@ describe('Crypto unit tests', function() {
|
|||||||
ivSize = config.symIvSize;
|
ivSize = config.symIvSize;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
crypto = new Crypto();
|
crypto = new Crypto(qMock);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {});
|
afterEach(function() {});
|
||||||
@ -24,32 +24,27 @@ describe('Crypto unit tests', function() {
|
|||||||
var key = util.random(keySize);
|
var key = util.random(keySize);
|
||||||
var iv = util.random(ivSize);
|
var iv = util.random(ivSize);
|
||||||
|
|
||||||
crypto.encrypt(plaintext, key, iv, function(err, ciphertext) {
|
crypto.encrypt(plaintext, key, iv).then(function(ciphertext) {
|
||||||
expect(err).to.not.exist;
|
|
||||||
expect(ciphertext).to.exist;
|
expect(ciphertext).to.exist;
|
||||||
|
|
||||||
crypto.decrypt(ciphertext, key, iv, function(err, decrypted) {
|
return crypto.decrypt(ciphertext, key, iv);
|
||||||
expect(err).to.not.exist;
|
}).then(function(decrypted) {
|
||||||
expect(decrypted).to.equal(plaintext);
|
expect(decrypted).to.equal(plaintext);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
describe("PBKDF2 (Async/Worker)", function() {
|
describe("PBKDF2 (Async/Worker)", function() {
|
||||||
it('should work', function(done) {
|
it('should work', function(done) {
|
||||||
var salt = util.random(keySize);
|
var salt = util.random(keySize);
|
||||||
|
|
||||||
crypto.deriveKey(password, salt, keySize, function(err, key) {
|
crypto.deriveKey(password, salt, keySize).then(function(key) {
|
||||||
expect(err).to.not.exist;
|
|
||||||
expect(util.base642Str(key).length * 8).to.equal(keySize);
|
expect(util.base642Str(key).length * 8).to.equal(keySize);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
Loading…
Reference in New Issue
Block a user