mirror of
https://github.com/moparisthebest/mail
synced 2024-12-22 15:28:49 -05:00
Implement and test crypto module
This commit is contained in:
parent
a7a562bef6
commit
18d1c39b0a
4
.gitignore
vendored
4
.gitignore
vendored
@ -8,7 +8,5 @@ dist/
|
|||||||
release/
|
release/
|
||||||
test/integration/src/
|
test/integration/src/
|
||||||
src/lib/*.js
|
src/lib/*.js
|
||||||
src/js/crypto/aes-cbc.js
|
src/js/crypto/aes-gcm.js
|
||||||
src/js/crypto/crypto-batch.js
|
|
||||||
src/js/crypto/rsa.js
|
|
||||||
src/js/crypto/util.js
|
src/js/crypto/util.js
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
"start": "grunt && grunt dev"
|
"start": "grunt && grunt dev"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"crypto-lib": "https://github.com/whiteout-io/crypto-lib/tarball/v0.1.1",
|
"crypto-lib": "https://github.com/whiteout-io/crypto-lib/tarball/v0.2.0",
|
||||||
"imap-client": "https://github.com/whiteout-io/imap-client/tarball/v0.3.3",
|
"imap-client": "https://github.com/whiteout-io/imap-client/tarball/v0.3.3",
|
||||||
"mailreader": "https://github.com/whiteout-io/mailreader/tarball/v0.3.3",
|
"mailreader": "https://github.com/whiteout-io/mailreader/tarball/v0.3.3",
|
||||||
"pgpmailer": "https://github.com/whiteout-io/pgpmailer/tarball/v0.3.4",
|
"pgpmailer": "https://github.com/whiteout-io/pgpmailer/tarball/v0.3.4",
|
||||||
|
@ -18,7 +18,7 @@ requirejs([
|
|||||||
'js/controller/read',
|
'js/controller/read',
|
||||||
'js/controller/write',
|
'js/controller/write',
|
||||||
'js/controller/navigation',
|
'js/controller/navigation',
|
||||||
'cryptoLib/util',
|
'js/crypto/util',
|
||||||
'js/util/error',
|
'js/util/error',
|
||||||
'fastclick',
|
'fastclick',
|
||||||
'angularSanitize',
|
'angularSanitize',
|
||||||
|
@ -2,7 +2,7 @@ define(function(require) {
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var _ = require('underscore'),
|
var _ = require('underscore'),
|
||||||
util = require('cryptoLib/util'),
|
util = require('js/crypto/util'),
|
||||||
config = require('js/app-config').config,
|
config = require('js/app-config').config,
|
||||||
outboxDb = 'email_OUTBOX';
|
outboxDb = 'email_OUTBOX';
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@ define(function(require) {
|
|||||||
var angular = require('angular'),
|
var angular = require('angular'),
|
||||||
_ = require('underscore'),
|
_ = require('underscore'),
|
||||||
appController = require('js/app-controller'),
|
appController = require('js/app-controller'),
|
||||||
aes = require('cryptoLib/aes-cbc'),
|
aes = require('js/crypto/aes-gcm'),
|
||||||
util = require('cryptoLib/util'),
|
util = require('js/crypto/util'),
|
||||||
str = require('js/app-config').string,
|
str = require('js/app-config').string,
|
||||||
crypto, emailDao, outbox, keychainDao;
|
crypto, emailDao, outbox, keychainDao;
|
||||||
|
|
||||||
|
@ -1,93 +0,0 @@
|
|||||||
(function() {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
// import web worker dependencies
|
|
||||||
importScripts('../../lib/require.js');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In the web worker thread context, 'this' and 'self' can be used as a global
|
|
||||||
* variable namespace similar to the 'window' object in the main thread
|
|
||||||
*/
|
|
||||||
self.onmessage = function(e) {
|
|
||||||
// fetch dependencies via require.js
|
|
||||||
require(['../../require-config'], function() {
|
|
||||||
require.config({
|
|
||||||
baseUrl: '../../lib'
|
|
||||||
});
|
|
||||||
|
|
||||||
require(['cryptoLib/crypto-batch'], function(batch) {
|
|
||||||
|
|
||||||
var output;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Asymmetric encryption
|
|
||||||
//
|
|
||||||
|
|
||||||
if (i.type === 'asymEncrypt' && i.receiverPubkeys && i.senderPrivkey && i.list) {
|
|
||||||
// start encryption
|
|
||||||
output = batch.encryptListForUser(i.list, i.receiverPubkeys, i.senderPrivkey);
|
|
||||||
|
|
||||||
} else if (i.type === 'asymDecrypt' && i.senderPubkeys && i.receiverPrivkey && i.list) {
|
|
||||||
// start decryption
|
|
||||||
output = batch.decryptListForUser(i.list, i.senderPubkeys, i.receiverPrivkey);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Symmetric encryption
|
|
||||||
//
|
|
||||||
else if (i.type === 'symEncrypt' && i.list) {
|
|
||||||
// start encryption
|
|
||||||
output = batch.authEncryptList(i.list);
|
|
||||||
|
|
||||||
} else if (i.type === 'symDecrypt' && i.list && i.keys) {
|
|
||||||
// start decryption
|
|
||||||
output = batch.authDecryptList(i.list, i.keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Reencryption of asymmetric items to symmetric items
|
|
||||||
//
|
|
||||||
else if (i.type === 'reencrypt' && i.senderPubkeys && i.receiverPrivkey && i.list && i.symKey) {
|
|
||||||
// start validation and re-encryption
|
|
||||||
output = batch.reencryptListKeysForUser(i.list, i.senderPubkeys, i.receiverPrivkey, i.symKey);
|
|
||||||
|
|
||||||
} else if (i.type === 'decryptItems' && i.symKey && i.list) {
|
|
||||||
// start decryption
|
|
||||||
output = batch.decryptKeysAndList(i.list, i.symKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Error
|
|
||||||
//
|
|
||||||
else {
|
|
||||||
output = {
|
|
||||||
err: {
|
|
||||||
errMsg: 'Not all arguments for web worker crypto are defined!'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
}());
|
|
@ -5,120 +5,54 @@
|
|||||||
define(function(require) {
|
define(function(require) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var util = require('cryptoLib/util'),
|
var aes = require('js/crypto/aes-gcm'),
|
||||||
aes = require('cryptoLib/aes-cbc'),
|
|
||||||
rsa = require('cryptoLib/rsa'),
|
|
||||||
cryptoBatch = require('cryptoLib/crypto-batch'),
|
|
||||||
pbkdf2 = require('js/crypto/pbkdf2'),
|
pbkdf2 = require('js/crypto/pbkdf2'),
|
||||||
config = require('js/app-config').config;
|
config = require('js/app-config').config;
|
||||||
|
|
||||||
var passBasedKey,
|
var PBKDF2_WORKER = '/crypto/pbkdf2-worker.js';
|
||||||
BATCH_WORKER = '/crypto/crypto-batch-worker.js',
|
|
||||||
PBKDF2_WORKER = '/crypto/pbkdf2-worker.js';
|
|
||||||
|
|
||||||
var Crypto = function() {
|
var Crypto = function() {};
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the crypto modules by fetching the user's
|
* Encrypt plaintext using AES-GCM.
|
||||||
* encrypted secret key from storage and storing it in memory.
|
* @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
|
||||||
*/
|
*/
|
||||||
Crypto.prototype.init = function(args, callback) {
|
Crypto.prototype.encrypt = function(plaintext, key, iv, callback) {
|
||||||
var self = this;
|
var ct;
|
||||||
|
|
||||||
// valdiate input
|
try {
|
||||||
if (!args.emailAddress || !args.keySize || !args.rsaKeySize || typeof args.password !== 'string' || !args.salt) {
|
ct = aes.encrypt(plaintext, key, iv);
|
||||||
callback({
|
} catch (err) {
|
||||||
errMsg: 'Crypto init failed. Not all args set!'
|
callback(err);
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.emailAddress = args.emailAddress;
|
callback(null, ct);
|
||||||
self.keySize = args.keySize;
|
};
|
||||||
self.ivSize = args.keySize;
|
|
||||||
self.rsaKeySize = args.rsaKeySize;
|
|
||||||
|
|
||||||
// derive PBKDF2 from password in web worker thread
|
/**
|
||||||
self.deriveKey(args.password, args.salt, self.keySize, function(err, derivedKey) {
|
* Decrypt ciphertext suing AES-GCM
|
||||||
if (err) {
|
* @param {String} ciphertext The base64 encoded ciphertext
|
||||||
callback(err);
|
* @param {String} key The base64 encoded key
|
||||||
return;
|
* @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;
|
||||||
|
|
||||||
// remember pbkdf2 for later use
|
try {
|
||||||
passBasedKey = derivedKey;
|
pt = aes.decrypt(ciphertext, key, iv);
|
||||||
|
} catch (err) {
|
||||||
// check if key exists
|
callback(err);
|
||||||
if (!args.storedKeypair) {
|
return;
|
||||||
// generate keys, encrypt and persist if none exists
|
|
||||||
generateKeypair(derivedKey);
|
|
||||||
} else {
|
|
||||||
// decrypt key
|
|
||||||
decryptKeypair(args.storedKeypair, derivedKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
function generateKeypair(derivedKey) {
|
|
||||||
// generate RSA keypair in web worker
|
|
||||||
rsa.generateKeypair(self.rsaKeySize, function(err, generatedKeypair) {
|
|
||||||
if (err) {
|
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// encrypt keypair
|
|
||||||
var iv = util.random(self.ivSize);
|
|
||||||
var encryptedPrivateKey = aes.encrypt(generatedKeypair.privkeyPem, derivedKey, iv);
|
|
||||||
|
|
||||||
// new encrypted keypair object
|
|
||||||
var newKeypair = {
|
|
||||||
publicKey: {
|
|
||||||
_id: generatedKeypair._id,
|
|
||||||
userId: self.emailAddress,
|
|
||||||
publicKey: generatedKeypair.pubkeyPem
|
|
||||||
},
|
|
||||||
privateKey: {
|
|
||||||
_id: generatedKeypair._id,
|
|
||||||
userId: self.emailAddress,
|
|
||||||
encryptedKey: encryptedPrivateKey,
|
|
||||||
iv: iv
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// return generated keypair for storage in keychain dao
|
|
||||||
callback(null, newKeypair);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function decryptKeypair(storedKeypair, derivedKey) {
|
callback(null, pt);
|
||||||
var decryptedPrivateKey;
|
|
||||||
|
|
||||||
// validate input
|
|
||||||
if (!storedKeypair || !storedKeypair.privateKey || !storedKeypair.privateKey.encryptedKey || !storedKeypair.privateKey.iv) {
|
|
||||||
callback({
|
|
||||||
errMsg: 'Incomplete arguments for private key decryption!'
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to decrypt with derivedKey
|
|
||||||
try {
|
|
||||||
var prK = storedKeypair.privateKey;
|
|
||||||
decryptedPrivateKey = aes.decrypt(prK.encryptedKey, derivedKey, prK.iv);
|
|
||||||
} catch (ex) {
|
|
||||||
callback({
|
|
||||||
errMsg: 'Wrong password!'
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// set rsa keys
|
|
||||||
rsa.init(storedKeypair.publicKey.publicKey, decryptedPrivateKey, storedKeypair.publicKey._id);
|
|
||||||
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -139,181 +73,6 @@ define(function(require) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
|
||||||
// En/Decrypt a list of items with AES in a WebWorker thread
|
|
||||||
//
|
|
||||||
|
|
||||||
Crypto.prototype.symEncryptList = function(list, callback) {
|
|
||||||
var self = this,
|
|
||||||
key, envelope, envelopes = [];
|
|
||||||
|
|
||||||
// generate single secret key shared for all list items
|
|
||||||
key = util.random(self.keySize);
|
|
||||||
|
|
||||||
// package objects into batchable envelope format
|
|
||||||
list.forEach(function(i) {
|
|
||||||
envelope = {
|
|
||||||
id: i.id,
|
|
||||||
plaintext: i,
|
|
||||||
key: key,
|
|
||||||
iv: util.random(self.ivSize)
|
|
||||||
};
|
|
||||||
envelopes.push(envelope);
|
|
||||||
});
|
|
||||||
|
|
||||||
startWorker({
|
|
||||||
script: BATCH_WORKER,
|
|
||||||
args: {
|
|
||||||
type: 'symEncrypt',
|
|
||||||
list: envelopes
|
|
||||||
},
|
|
||||||
callback: function(err, encryptedList) {
|
|
||||||
// return generated secret key
|
|
||||||
callback(err, {
|
|
||||||
key: key,
|
|
||||||
list: encryptedList
|
|
||||||
});
|
|
||||||
},
|
|
||||||
noWorker: function() {
|
|
||||||
return cryptoBatch.authEncryptList(envelopes);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Crypto.prototype.symDecryptList = function(list, keys, callback) {
|
|
||||||
startWorker({
|
|
||||||
script: BATCH_WORKER,
|
|
||||||
args: {
|
|
||||||
type: 'symDecrypt',
|
|
||||||
list: list,
|
|
||||||
keys: keys
|
|
||||||
},
|
|
||||||
callback: callback,
|
|
||||||
noWorker: function() {
|
|
||||||
return cryptoBatch.authDecryptList(list, keys);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// En/Decrypt something speficially using the user's secret key
|
|
||||||
//
|
|
||||||
|
|
||||||
Crypto.prototype.encryptListForUser = function(list, receiverPubkeys, callback) {
|
|
||||||
var self = this,
|
|
||||||
envelope, envelopes = [];
|
|
||||||
|
|
||||||
if (!receiverPubkeys || receiverPubkeys.length !== 1) {
|
|
||||||
callback({
|
|
||||||
errMsg: 'Encryption is currently implemented for only one receiver!'
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var keypair = rsa.exportKeys();
|
|
||||||
var senderPrivkey = {
|
|
||||||
_id: keypair._id,
|
|
||||||
privateKey: keypair.privkeyPem
|
|
||||||
};
|
|
||||||
|
|
||||||
// package objects into batchable envelope format
|
|
||||||
list.forEach(function(i) {
|
|
||||||
envelope = {
|
|
||||||
id: i.id,
|
|
||||||
plaintext: i,
|
|
||||||
key: util.random(self.keySize),
|
|
||||||
iv: util.random(self.ivSize),
|
|
||||||
receiverPk: receiverPubkeys[0]._id
|
|
||||||
};
|
|
||||||
envelopes.push(envelope);
|
|
||||||
});
|
|
||||||
|
|
||||||
startWorker({
|
|
||||||
script: BATCH_WORKER,
|
|
||||||
args: {
|
|
||||||
type: 'asymEncrypt',
|
|
||||||
list: envelopes,
|
|
||||||
senderPrivkey: senderPrivkey,
|
|
||||||
receiverPubkeys: receiverPubkeys
|
|
||||||
},
|
|
||||||
callback: callback,
|
|
||||||
noWorker: function() {
|
|
||||||
return cryptoBatch.encryptListForUser(envelopes, receiverPubkeys, senderPrivkey);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Crypto.prototype.decryptListForUser = function(list, senderPubkeys, callback) {
|
|
||||||
if (!senderPubkeys || senderPubkeys < 1) {
|
|
||||||
callback({
|
|
||||||
errMsg: 'Sender public keys must be set!'
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var keypair = rsa.exportKeys();
|
|
||||||
var receiverPrivkey = {
|
|
||||||
_id: keypair._id,
|
|
||||||
privateKey: keypair.privkeyPem
|
|
||||||
};
|
|
||||||
|
|
||||||
startWorker({
|
|
||||||
script: BATCH_WORKER,
|
|
||||||
args: {
|
|
||||||
type: 'asymDecrypt',
|
|
||||||
list: list,
|
|
||||||
receiverPrivkey: receiverPrivkey,
|
|
||||||
senderPubkeys: senderPubkeys
|
|
||||||
},
|
|
||||||
callback: callback,
|
|
||||||
noWorker: function() {
|
|
||||||
return cryptoBatch.decryptListForUser(list, senderPubkeys, receiverPrivkey);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Re-encrypt keys item and items seperately
|
|
||||||
//
|
|
||||||
|
|
||||||
Crypto.prototype.reencryptListKeysForUser = function(list, senderPubkeys, callback) {
|
|
||||||
var keypair = rsa.exportKeys();
|
|
||||||
var receiverPrivkey = {
|
|
||||||
_id: keypair._id,
|
|
||||||
privateKey: keypair.privkeyPem
|
|
||||||
};
|
|
||||||
|
|
||||||
startWorker({
|
|
||||||
script: BATCH_WORKER,
|
|
||||||
args: {
|
|
||||||
type: 'reencrypt',
|
|
||||||
list: list,
|
|
||||||
receiverPrivkey: receiverPrivkey,
|
|
||||||
senderPubkeys: senderPubkeys,
|
|
||||||
symKey: passBasedKey
|
|
||||||
},
|
|
||||||
callback: callback,
|
|
||||||
noWorker: function() {
|
|
||||||
return cryptoBatch.reencryptListKeysForUser(list, senderPubkeys, receiverPrivkey, passBasedKey);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Crypto.prototype.decryptKeysAndList = function(list, callback) {
|
|
||||||
startWorker({
|
|
||||||
script: BATCH_WORKER,
|
|
||||||
args: {
|
|
||||||
type: 'decryptItems',
|
|
||||||
list: list,
|
|
||||||
symKey: passBasedKey
|
|
||||||
},
|
|
||||||
callback: callback,
|
|
||||||
noWorker: function() {
|
|
||||||
return cryptoBatch.decryptKeysAndList(list, passBasedKey);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// helper functions
|
// helper functions
|
||||||
//
|
//
|
||||||
|
@ -1,23 +1,24 @@
|
|||||||
/**
|
/**
|
||||||
* A Wrapper for Forge's PBKDF2 function
|
* A Wrapper for Forge's PBKDF2 function
|
||||||
*/
|
*/
|
||||||
define(['node-forge'], function(forge) {
|
define(['forge'], function(forge) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var self = {};
|
var self = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PBKDF2-HMAC-SHA1 key derivation with a random salt and 1000 iterations
|
* PBKDF2-HMAC-SHA1 key derivation with a random salt and 1000 iterations
|
||||||
* @param password [String] The password in UTF8
|
* @param {String} password The password in UTF8
|
||||||
* @param salt [String] The base64 encoded salt
|
* @param {String} salt The base64 encoded salt
|
||||||
* @param keySize [Number] The key size in bits
|
* @param {String} keySize The key size in bits
|
||||||
* @return [String] The base64 encoded key
|
* @return {String} The base64 encoded key
|
||||||
*/
|
*/
|
||||||
self.getKey = function(password, salt, keySize) {
|
self.getKey = function(password, salt, keySize) {
|
||||||
var key = forge.pkcs5.pbkdf2(password, forge.util.decode64(salt), 1000, keySize / 8);
|
var saltUtf8 = forge.util.decode64(salt);
|
||||||
var keyBase64 = forge.util.encode64(key);
|
var md = forge.md.sha256.create();
|
||||||
|
var key = forge.pkcs5.pbkdf2(password, saltUtf8, 10000, keySize / 8, md);
|
||||||
|
|
||||||
return keyBase64;
|
return forge.util.encode64(key);
|
||||||
};
|
};
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
define(function(require) {
|
define(function(require) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var util = require('cryptoLib/util'),
|
var util = require('js/crypto/util'),
|
||||||
_ = require('underscore'),
|
_ = require('underscore'),
|
||||||
config = require('js/app-config').config,
|
config = require('js/app-config').config,
|
||||||
str = require('js/app-config').string;
|
str = require('js/app-config').string;
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
paths: {
|
paths: {
|
||||||
js: '../js',
|
js: '../js',
|
||||||
test: '../../test',
|
test: '../../test',
|
||||||
cryptoLib: '../js/crypto',
|
|
||||||
underscore: 'underscore/underscore-min',
|
underscore: 'underscore/underscore-min',
|
||||||
lawnchair: 'lawnchair/lawnchair-git',
|
lawnchair: 'lawnchair/lawnchair-git',
|
||||||
lawnchairSQL: 'lawnchair/lawnchair-adapter-webkit-sqlite-git',
|
lawnchairSQL: 'lawnchair/lawnchair-adapter-webkit-sqlite-git',
|
||||||
|
56
test/new-unit/crypto-test.js
Normal file
56
test/new-unit/crypto-test.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
define(function(require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var Crypto = require('js/crypto/crypto'),
|
||||||
|
util = require('js/crypto/util'),
|
||||||
|
expect = chai.expect;
|
||||||
|
|
||||||
|
describe('Crypto unit tests', function() {
|
||||||
|
var crypto;
|
||||||
|
|
||||||
|
var password = 'password',
|
||||||
|
keySize = 128,
|
||||||
|
ivSize = 128;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
crypto = new Crypto();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {});
|
||||||
|
|
||||||
|
describe('AES encrypt/decrypt', function() {
|
||||||
|
it('should work', function(done) {
|
||||||
|
var plaintext = 'Hello, World!';
|
||||||
|
var key = util.random(keySize);
|
||||||
|
var iv = util.random(ivSize);
|
||||||
|
|
||||||
|
crypto.encrypt(plaintext, key, iv, function(err, ciphertext) {
|
||||||
|
expect(err).to.not.exist;
|
||||||
|
expect(ciphertext).to.exist;
|
||||||
|
|
||||||
|
crypto.decrypt(ciphertext, key, iv, function(err, decrypted) {
|
||||||
|
expect(err).to.not.exist;
|
||||||
|
expect(decrypted).to.equal(plaintext);
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("PBKDF2 (Async/Worker)", function() {
|
||||||
|
it('should work', function(done) {
|
||||||
|
var salt = util.random(keySize);
|
||||||
|
|
||||||
|
crypto.deriveKey(password, salt, keySize, function(err, key) {
|
||||||
|
expect(err).to.not.exist;
|
||||||
|
expect(util.base642Str(key).length * 8).to.equal(keySize);
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
@ -33,6 +33,7 @@ function startTests() {
|
|||||||
'test/new-unit/email-dao-test',
|
'test/new-unit/email-dao-test',
|
||||||
'test/new-unit/app-controller-test',
|
'test/new-unit/app-controller-test',
|
||||||
'test/new-unit/pgp-test',
|
'test/new-unit/pgp-test',
|
||||||
|
'test/new-unit/crypto-test',
|
||||||
'test/new-unit/rest-dao-test',
|
'test/new-unit/rest-dao-test',
|
||||||
'test/new-unit/publickey-dao-test',
|
'test/new-unit/publickey-dao-test',
|
||||||
'test/new-unit/lawnchair-dao-test',
|
'test/new-unit/lawnchair-dao-test',
|
||||||
|
Loading…
Reference in New Issue
Block a user