added rsa module and tests

This commit is contained in:
Tankred Hase 2013-05-14 16:05:31 +02:00
parent ec14639d56
commit 6bbcd8cab7
6 changed files with 158 additions and 97 deletions

View File

@ -30,7 +30,6 @@ app.crypto.AesCBC = function(forge) {
* @param ciphertext [String] The base64 encoded ciphertext
* @param key [String] The base64 encoded key
* @param iv [String] The base64 encoded IV
* @param iv [String] The base64 encoded HMAC
* @return [String] The decrypted plaintext in UTF8
*/
this.decrypt = function(ciphertext, key, iv) {

94
src/js/crypto/rsa.js Normal file
View File

@ -0,0 +1,94 @@
/**
* A Wrapper for Forge's RSA encryption
*/
app.crypto.RSA = function(forge) {
'use strict';
var publicKey = null,
privateKey = null;
/**
* Initializes the RSA module by passing the user's keypair
* The private key is option and required only for decryption
* and signing
*/
this.init = function(pubkeyPem, privkeyPem) {
publicKey = forge.pki.publicKeyFromPem(pubkeyPem);
if (privkeyPem) {
privateKey = forge.pki.privateKeyFromPem(privkeyPem);
}
};
/**
* Generate RSA keypair with the corresponding keysize
*/
this.generateKeypair = function(keySize, callback) {
forge.rsa.generateKeyPair({
bits: keySize,
workerScript: app.config.workerPath + '/../../lib/forge/prime.worker.js'
}, function(err, keypair) {
if (err || !keypair.publicKey || !keypair.privateKey) {
callback({
errMsg: 'RSA keygeneration failed!',
err: err
});
return;
}
publicKey = keypair.publicKey;
privateKey = keypair.privateKey;
callback();
});
};
/**
* Exports user's keypair as PEMs
*/
this.exportKeys = function() {
return {
pubkeyPem: forge.pki.publicKeyToPem(publicKey),
privkeyPem: forge.pki.privateKeyToPem(privateKey)
};
};
/**
* Encrypt a String using RSA with PKCS#1 v1.5 padding
* @param plaintext [String] The input string in UTF8
* @return [String] The base64 encoded ciphertext
*/
this.encrypt = function(plaintext) {
var ct = publicKey.encrypt(plaintext);
return forge.util.encode64(ct);
};
/**
* Decrypt a String using RSA with PKCS#1 v1.5 padding
* @param ciphertext [String] The base64 encoded ciphertext
* @return [String] The decrypted plaintext in UTF8
*/
this.decrypt = function(ciphertext) {
// parse base64 input to utf8
var ctUtf8 = forge.util.decode64(ciphertext);
return privateKey.decrypt(ctUtf8);
};
this.sign = function(input) {
var sha = forge.md.sha256.create();
sha.update(input);
var sig = privateKey.sign(sha);
return forge.util.encode64(sig);
};
this.verify = function(input, sig) {
// parse base64 signature to utf8
var sigUtf8 = forge.util.decode64(sig);
var sha = forge.md.sha256.create();
sha.update(input);
return publicKey.verify(sha.digest().getBytes(), sigUtf8);
};
};

View File

@ -1,17 +1,11 @@
module("AES Crypto");
var aes_test = {
keySize: 128
keySize: 128,
util: new app.crypto.Util(window, uuid),
test_message: new TestData().generateBigString(1000)
};
test("Init", 1, function() {
// init dependencies
aes_test.util = new app.crypto.Util(window, uuid);
ok(aes_test.util, 'Util');
// generate test data
aes_test.test_message = new TestData().generateBigString(1000);
});
test("CBC mode", 4, function() {
var aes = new app.crypto.AesCBC(forge);

View File

@ -1,6 +1,6 @@
module("Forge Crypto");
var rsa_test = {
var forge_rsa_test = {
keySize: 1024,
test_message: '06a9214036b8a15b512e03d534120006'
};
@ -13,15 +13,15 @@ var forge_aes_test = {
test("SHA-1 Hash", 1, function() {
var sha1 = forge.md.sha1.create();
sha1.update(forge_aes_test.test_message);
var digest = sha1.digest().getBytes();
ok(digest);
var digest = sha1.digest().toHex();
ok(digest, digest);
});
test("SHA-256 Hash", 1, function() {
rsa_test.md = forge.md.sha256.create();
rsa_test.md.update(forge_aes_test.test_message);
var digest = rsa_test.md.digest().getBytes();
ok(digest);
forge_rsa_test.md = forge.md.sha256.create();
forge_rsa_test.md.update(forge_aes_test.test_message);
var digest = forge_rsa_test.md.digest().toHex();
ok(digest, digest);
});
test("HMAC SHA-256", 1, function() {
@ -34,85 +34,7 @@ test("HMAC SHA-256", 1, function() {
hmac.start('sha256', key);
hmac.update(iv);
hmac.update(forge_aes_test.test_message);
var result = hmac.digest().toHex();
var digest = hmac.digest().toHex();
ok(result);
});
test("PBKDF2", 1, function() {
var util = new app.crypto.Util(window, uuid);
var salt = util.base642Str("vbhmLjC+Ub6MSbhS6/CkOwxB25wvwRkSLP2DzDtYb+4=");
var expect = '5223bd44b0523090b21e9d38a749b090';
var dk = forge.pkcs5.pbkdf2('password', salt, 1000, 16);
equal(expect, forge.util.bytesToHex(dk));
});
asyncTest("RSA Generate Keypair", 1, function() {
forge.rsa.generateKeyPair({
bits: rsa_test.keySize,
workerScript: app.config.workerPath + '/../lib/forge/prime.worker.js'
}, function(err, keypair) {
ok(!err && keypair);
rsa_test.keypair = keypair;
start();
});
});
test("RSA Encrypt", 1, function() {
rsa_test.ct = rsa_test.keypair.publicKey.encrypt(rsa_test.test_message);
ok(rsa_test.ct);
});
test("RSA Decrypt", 1, function() {
var pt = rsa_test.keypair.privateKey.decrypt(rsa_test.ct);
equal(rsa_test.test_message, pt);
});
test("RSA Sign", 1, function() {
var sha = forge.md.sha256.create();
sha.update(forge_aes_test.test_message);
rsa_test.sig = rsa_test.keypair.privateKey.sign(sha);
ok(rsa_test.sig);
});
test("RSA Verify", 1, function() {
var res = rsa_test.keypair.publicKey.verify(rsa_test.md.digest().getBytes(), rsa_test.sig);
ok(res);
});
test("AES-128-CBC Encrypt", 1, function() {
var util = new app.crypto.Util(window, uuid);
forge_aes_test.key = util.base642Str(util.random(forge_aes_test.keySize));
forge_aes_test.iv = util.base642Str(util.random(forge_aes_test.keySize));
var input = forge_aes_test.test_message;
// encrypt
var enCipher = forge.aes.createEncryptionCipher(forge_aes_test.key);
enCipher.start(forge_aes_test.iv);
enCipher.update(forge.util.createBuffer(input));
enCipher.finish();
forge_aes_test.ct = enCipher.output.getBytes();
ok(forge_aes_test.ct);
});
test("AES-128-CBC Decrypt", 1, function() {
var input = forge_aes_test.test_message;
// decrypt
var deCipher = forge.aes.createDecryptionCipher(forge_aes_test.key);
deCipher.start(forge_aes_test.iv);
deCipher.update(forge.util.createBuffer(forge_aes_test.ct));
deCipher.finish();
equal(input, deCipher.output, 'En/Decrypt length: ' + input.length);
ok(digest, digest);
});

View File

@ -42,6 +42,7 @@
<script src="../js/crypto/util.js"></script>
<script src="../js/crypto/pbkdf2.js"></script>
<script src="../js/crypto/aes-cbc.js"></script>
<script src="../js/crypto/rsa.js"></script>
<script src="../js/crypto/nacl-crypto.js"></script>
<script src="../js/crypto/crypto.js"></script>
@ -56,6 +57,7 @@
<script src="util-test.js"></script>
<script src="forge-test.js"></script>
<script src="aes-test.js"></script>
<script src="rsa-test.js"></script>
<script src="nacl-crypto-test.js"></script>
<script src="crypto-test.js"></script>
<script src="localstorage-dao-test.js"></script>

50
test/unit/rsa-test.js Normal file
View File

@ -0,0 +1,50 @@
module("RSA Crypto");
var rsa_test = {
keySize: 1024,
rsa: new app.crypto.RSA(forge),
test_message: '06a9214036b8a15b512e03d534120006'
};
asyncTest("Generate keypair", 1, function() {
rsa_test.rsa.generateKeypair(rsa_test.keySize, function(err) {
ok(!err);
start();
});
});
test("Export keys", 2, function() {
rsa_test.keypair = rsa_test.rsa.exportKeys();
ok(rsa_test.keypair.pubkeyPem.indexOf('-----BEGIN PUBLIC KEY-----') === 0, rsa_test.keypair.pubkeyPem);
ok(rsa_test.keypair.privkeyPem.indexOf('-----BEGIN RSA PRIVATE KEY-----') === 0, rsa_test.keypair.privkeyPem);
});
test("Init", 2, function() {
rsa_test.rsa.init(rsa_test.keypair.pubkeyPem, rsa_test.keypair.privkeyPem);
var exported = rsa_test.rsa.exportKeys();
ok(exported.pubkeyPem.indexOf('-----BEGIN PUBLIC KEY-----') === 0);
ok(exported.privkeyPem.indexOf('-----BEGIN RSA PRIVATE KEY-----') === 0);
});
test("Encrypt", 1, function() {
rsa_test.ct = rsa_test.rsa.encrypt(rsa_test.test_message);
ok(rsa_test.ct);
});
test("Decrypt", 1, function() {
var pt = rsa_test.rsa.decrypt(rsa_test.ct);
equal(pt, rsa_test.test_message);
});
test("Sign", 1, function() {
rsa_test.sig = rsa_test.rsa.sign(rsa_test.test_message);
ok(rsa_test.sig);
});
test("Verify", 1, function() {
var res = rsa_test.rsa.verify(rsa_test.test_message, rsa_test.sig);
ok(res);
});