2013-04-02 09:02:57 -04:00
|
|
|
/**
|
|
|
|
* High level crypto api that invokes native crypto (if available) and
|
|
|
|
* gracefully degrades to JS crypto (if unavailable)
|
|
|
|
*/
|
2013-08-30 10:05:33 -04:00
|
|
|
define(function(require) {
|
|
|
|
'use strict';
|
|
|
|
|
2014-06-05 09:26:19 -04:00
|
|
|
var aes = require('js/crypto/aes-gcm'),
|
2013-08-30 10:05:33 -04:00
|
|
|
pbkdf2 = require('js/crypto/pbkdf2'),
|
2014-06-18 11:09:04 -04:00
|
|
|
config = require('js/app-config').config,
|
|
|
|
axe = require('axe');
|
2013-08-30 10:05:33 -04:00
|
|
|
|
2014-06-05 09:26:19 -04:00
|
|
|
var PBKDF2_WORKER = '/crypto/pbkdf2-worker.js';
|
2013-08-30 10:05:33 -04:00
|
|
|
|
2014-06-05 09:26:19 -04:00
|
|
|
var Crypto = function() {};
|
2013-09-26 07:26:57 -04:00
|
|
|
|
2013-08-30 10:05:33 -04:00
|
|
|
/**
|
2014-06-05 09:26:19 -04:00
|
|
|
* Encrypt plaintext using AES-GCM.
|
|
|
|
* @param {String} plaintext The input string in UTF-16
|
|
|
|
* @param {String} key The base64 encoded key
|
|
|
|
* @param {String} iv The base64 encoded IV
|
|
|
|
* @param {Function} callback(error, ciphertext)
|
|
|
|
* @return {String} The base64 encoded ciphertext
|
2013-08-30 10:05:33 -04:00
|
|
|
*/
|
2014-06-05 09:26:19 -04:00
|
|
|
Crypto.prototype.encrypt = function(plaintext, key, iv, callback) {
|
|
|
|
var ct;
|
2013-09-26 07:26:57 -04:00
|
|
|
|
2014-06-05 09:26:19 -04:00
|
|
|
try {
|
|
|
|
ct = aes.encrypt(plaintext, key, iv);
|
|
|
|
} catch (err) {
|
|
|
|
callback(err);
|
2013-08-30 10:05:33 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-06-05 09:26:19 -04:00
|
|
|
callback(null, ct);
|
|
|
|
};
|
2013-08-30 10:05:33 -04:00
|
|
|
|
2014-06-05 09:26:19 -04:00
|
|
|
/**
|
|
|
|
* Decrypt ciphertext suing AES-GCM
|
|
|
|
* @param {String} ciphertext The base64 encoded ciphertext
|
|
|
|
* @param {String} key The base64 encoded key
|
|
|
|
* @param {String} iv The base64 encoded IV
|
|
|
|
* @param {Function} callback(error, plaintext)
|
|
|
|
* @return {String} The decrypted plaintext in UTF-16
|
|
|
|
*/
|
|
|
|
Crypto.prototype.decrypt = function(ciphertext, key, iv, callback) {
|
|
|
|
var pt;
|
2013-08-30 10:05:33 -04:00
|
|
|
|
2014-06-05 09:26:19 -04:00
|
|
|
try {
|
|
|
|
pt = aes.decrypt(ciphertext, key, iv);
|
|
|
|
} catch (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
2013-08-30 10:05:33 -04:00
|
|
|
}
|
|
|
|
|
2014-06-05 09:26:19 -04:00
|
|
|
callback(null, pt);
|
2013-08-30 10:05:33 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Do PBKDF2 key derivation in a WebWorker thread
|
|
|
|
*/
|
2013-10-09 10:40:36 -04:00
|
|
|
Crypto.prototype.deriveKey = function(password, salt, keySize, callback) {
|
2013-08-31 10:29:18 -04:00
|
|
|
startWorker({
|
|
|
|
script: PBKDF2_WORKER,
|
|
|
|
args: {
|
|
|
|
password: password,
|
2013-10-09 10:40:36 -04:00
|
|
|
salt: salt,
|
2013-08-31 10:29:18 -04:00
|
|
|
keySize: keySize
|
|
|
|
},
|
|
|
|
callback: callback,
|
|
|
|
noWorker: function() {
|
2013-10-09 10:40:36 -04:00
|
|
|
return pbkdf2.getKey(password, salt, keySize);
|
2013-08-31 10:29:18 -04:00
|
|
|
}
|
2013-08-30 10:05:33 -04:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
//
|
|
|
|
// helper functions
|
|
|
|
//
|
|
|
|
|
2013-08-31 10:29:18 -04:00
|
|
|
function startWorker(options) {
|
2013-08-30 10:05:33 -04:00
|
|
|
// check for WebWorker support
|
|
|
|
if (window.Worker) {
|
|
|
|
// init webworker thread
|
2013-09-15 09:17:28 -04:00
|
|
|
var worker = new Worker(config.workerPath + options.script);
|
2013-08-30 10:05:33 -04:00
|
|
|
worker.onmessage = function(e) {
|
|
|
|
if (e.data.err) {
|
2013-08-31 10:29:18 -04:00
|
|
|
options.callback(e.data.err);
|
2013-08-30 10:05:33 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// return result from the worker
|
2013-08-31 10:29:18 -04:00
|
|
|
options.callback(null, e.data);
|
2013-08-30 10:05:33 -04:00
|
|
|
};
|
2013-09-20 12:42:47 -04:00
|
|
|
worker.onerror = function(e) {
|
2014-06-18 11:09:04 -04:00
|
|
|
// show error message in logger
|
|
|
|
axe.error('Error handling web worker: Line ' + e.lineno + ' in ' + e.filename + ': ' + e.message);
|
2013-09-20 12:42:47 -04:00
|
|
|
// return error
|
|
|
|
options.callback({
|
|
|
|
errMsg: (e.message) ? e.message : e
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
};
|
2013-08-30 10:05:33 -04:00
|
|
|
// send data to the worker
|
2013-08-31 10:29:18 -04:00
|
|
|
worker.postMessage(options.args);
|
|
|
|
return;
|
|
|
|
}
|
2013-08-30 10:05:33 -04:00
|
|
|
|
2013-08-31 10:29:18 -04:00
|
|
|
// no WebWorker support... do synchronous call
|
|
|
|
var result;
|
|
|
|
try {
|
|
|
|
result = options.noWorker();
|
|
|
|
} catch (e) {
|
|
|
|
// return error
|
|
|
|
options.callback({
|
|
|
|
errMsg: (e.message) ? e.message : e
|
|
|
|
});
|
|
|
|
return;
|
2013-08-30 10:05:33 -04:00
|
|
|
}
|
2013-08-31 10:29:18 -04:00
|
|
|
options.callback(null, result);
|
2013-08-30 10:05:33 -04:00
|
|
|
}
|
|
|
|
|
2013-09-26 07:26:57 -04:00
|
|
|
return Crypto;
|
2013-06-10 11:57:33 -04:00
|
|
|
});
|