Refactor crypto module

This commit is contained in:
Tankred Hase 2014-12-11 14:16:07 +01:00
parent f4fe1a36a6
commit 88a48ec540
2 changed files with 50 additions and 78 deletions

View File

@ -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,43 +66,33 @@ Crypto.prototype.deriveKey = function(password, salt, keySize, callback) {
// helper functions // helper functions
// //
function startWorker(options) { Crypto.prototype.startWorker = function(options) {
// check for WebWorker support return this._q(function(resolve, reject) {
if (window.Worker) { // check for WebWorker support
// init webworker thread if (window.Worker) {
var worker = new Worker(options.script); // init webworker thread
worker.onmessage = function(e) { var worker = new Worker(options.script);
if (e.data.err) { worker.onmessage = function(e) {
options.callback(e.data.err); // return result from the worker
return; if (e.data.err) {
} reject(e.data.err);
// return result from the worker } else {
options.callback(null, e.data); resolve(e.data);
}; }
worker.onerror = function(e) { };
// show error message in logger worker.onerror = function(e) {
axe.error('Error handling web worker: Line ' + e.lineno + ' in ' + e.filename + ': ' + e.message); // show error message in logger
// return error axe.error('Error handling web worker: Line ' + e.lineno + ' in ' + e.filename + ': ' + e.message);
options.callback({ // return error
errMsg: (e.message) ? e.message : e reject(e);
}); };
// send data to the worker
worker.postMessage(options.args);
return; return;
}; }
// send data to the worker
worker.postMessage(options.args);
return;
}
// 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);
}

View File

@ -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,16 +24,14 @@ 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();
});
}); });
}); });
}); });
@ -42,14 +40,11 @@ describe('Crypto unit tests', 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();
}); });
}); });
}); });
}); });