2013-10-11 15:30:03 -04:00
|
|
|
/**
|
|
|
|
* High level crypto api that handles all calls to OpenPGP.js
|
|
|
|
*/
|
|
|
|
define(function(require) {
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
var openpgp = require('openpgp').openpgp,
|
2013-10-11 15:54:43 -04:00
|
|
|
util = require('openpgp').util;
|
2013-10-11 15:30:03 -04:00
|
|
|
|
|
|
|
var PGP = function() {
|
|
|
|
openpgp.init();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate a key pair for the user
|
|
|
|
*/
|
|
|
|
PGP.prototype.generateKeys = function(options, callback) {
|
2013-10-14 09:27:41 -04:00
|
|
|
var keys, userId;
|
2013-10-11 15:30:03 -04:00
|
|
|
|
2013-10-11 15:54:43 -04:00
|
|
|
if (!util.emailRegEx.test(options.emailAddress) || !options.keySize || typeof options.passphrase !== 'string') {
|
2013-10-11 15:30:03 -04:00
|
|
|
callback({
|
|
|
|
errMsg: 'Crypto init failed. Not all options set!'
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// generate keypair (keytype 1=RSA)
|
2013-10-11 21:19:01 -04:00
|
|
|
try {
|
2013-10-14 09:27:41 -04:00
|
|
|
userId = 'Whiteout User <' + options.emailAddress + '>';
|
|
|
|
keys = openpgp.generate_key_pair(1, options.keySize, userId, options.passphrase);
|
2013-10-11 21:19:01 -04:00
|
|
|
} catch (e) {
|
|
|
|
callback({
|
|
|
|
errMsg: 'Keygeneration failed!',
|
|
|
|
err: e
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
2013-10-11 15:30:03 -04:00
|
|
|
|
|
|
|
callback(null, {
|
2013-10-11 15:54:43 -04:00
|
|
|
keyId: util.hexstrdump(keys.privateKey.getKeyId()).toUpperCase(),
|
2013-10-11 15:30:03 -04:00
|
|
|
privateKeyArmored: keys.privateKeyArmored,
|
|
|
|
publicKeyArmored: keys.publicKeyArmored
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2013-11-06 10:20:49 -05:00
|
|
|
/**
|
|
|
|
* Show a user's fingerprint
|
|
|
|
*/
|
|
|
|
PGP.prototype.getFingerprint = function() {
|
|
|
|
var publicKey, privateKey;
|
|
|
|
|
|
|
|
privateKey = openpgp.keyring.exportPrivateKey(0);
|
|
|
|
if (privateKey && privateKey.keyId) {
|
|
|
|
publicKey = openpgp.keyring.getPublicKeysForKeyId(privateKey.keyId)[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!privateKey || !privateKey.keyId || !privateKey.armored || !publicKey || !publicKey.armored) {
|
|
|
|
console.error('Public key not available!');
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
|
|
|
return util.hexstrdump(publicKey.obj.getFingerprint()).toUpperCase();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Show a user's key id
|
|
|
|
*/
|
|
|
|
PGP.prototype.getKeyId = function() {
|
|
|
|
var privateKey = openpgp.keyring.exportPrivateKey(0);
|
|
|
|
if (!privateKey || !privateKey.keyId) {
|
|
|
|
console.error('Public key not available!');
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
|
|
|
return util.hexstrdump(privateKey.keyId).toUpperCase();
|
|
|
|
};
|
|
|
|
|
2013-10-11 15:30:03 -04:00
|
|
|
/**
|
|
|
|
* Import the user's key pair
|
|
|
|
*/
|
|
|
|
PGP.prototype.importKeys = function(options, callback) {
|
2013-10-11 15:54:43 -04:00
|
|
|
var publicKey, privateKey;
|
|
|
|
|
2013-10-11 15:30:03 -04:00
|
|
|
// check passphrase
|
|
|
|
if (typeof options.passphrase !== 'string' || !options.privateKeyArmored || !options.publicKeyArmored) {
|
|
|
|
callback({
|
|
|
|
errMsg: 'Importing keys failed. Not all options set!'
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-10-14 09:27:41 -04:00
|
|
|
// clear any keypair already in the keychain
|
|
|
|
openpgp.keyring.init();
|
2013-10-11 15:30:03 -04:00
|
|
|
// unlock and import private key
|
|
|
|
if (!openpgp.keyring.importPrivateKey(options.privateKeyArmored, options.passphrase)) {
|
2013-10-11 16:10:50 -04:00
|
|
|
openpgp.keyring.init();
|
2013-10-11 15:30:03 -04:00
|
|
|
callback({
|
|
|
|
errMsg: 'Incorrect passphrase!'
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// import public key
|
|
|
|
openpgp.keyring.importPublicKey(options.publicKeyArmored);
|
2013-10-11 15:54:43 -04:00
|
|
|
|
|
|
|
// check if keys have the same id
|
|
|
|
privateKey = openpgp.keyring.exportPrivateKey(0);
|
|
|
|
publicKey = openpgp.keyring.getPublicKeysForKeyId(privateKey.keyId)[0];
|
|
|
|
if (!privateKey || !privateKey.armored || !publicKey || !publicKey.armored || privateKey.keyId !== publicKey.keyId) {
|
|
|
|
// reset keyring
|
|
|
|
openpgp.keyring.init();
|
|
|
|
callback({
|
|
|
|
errMsg: 'Key IDs dont match!'
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-10-11 15:30:03 -04:00
|
|
|
callback();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Export the user's key pair
|
|
|
|
*/
|
|
|
|
PGP.prototype.exportKeys = function(callback) {
|
|
|
|
var publicKey, privateKey;
|
|
|
|
|
|
|
|
privateKey = openpgp.keyring.exportPrivateKey(0);
|
2013-10-11 16:10:50 -04:00
|
|
|
if (privateKey && privateKey.keyId) {
|
|
|
|
publicKey = openpgp.keyring.getPublicKeysForKeyId(privateKey.keyId)[0];
|
|
|
|
}
|
2013-10-11 15:30:03 -04:00
|
|
|
|
2013-10-11 16:10:50 -04:00
|
|
|
if (!privateKey || !privateKey.keyId || !privateKey.armored || !publicKey || !publicKey.armored) {
|
|
|
|
callback({
|
|
|
|
errMsg: 'Could not export keys!'
|
2013-10-11 15:30:03 -04:00
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-10-11 16:10:50 -04:00
|
|
|
callback(null, {
|
|
|
|
keyId: util.hexstrdump(privateKey.keyId).toUpperCase(),
|
|
|
|
privateKeyArmored: privateKey.armored,
|
|
|
|
publicKeyArmored: publicKey.armored
|
2013-10-11 15:30:03 -04:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Encrypt and sign a pgp message for a list of receivers
|
|
|
|
*/
|
2013-10-12 19:30:56 -04:00
|
|
|
PGP.prototype.encrypt = function(plaintext, receiverKeys, callback) {
|
2013-10-11 15:30:03 -04:00
|
|
|
var ct, i,
|
|
|
|
privateKey = openpgp.keyring.exportPrivateKey(0).obj;
|
|
|
|
|
2013-10-12 19:30:56 -04:00
|
|
|
for (i = 0; i < receiverKeys.length; i++) {
|
|
|
|
receiverKeys[i] = openpgp.read_publicKey(receiverKeys[i])[0];
|
2013-10-11 15:30:03 -04:00
|
|
|
}
|
|
|
|
|
2013-11-14 07:57:52 -05:00
|
|
|
// encrypt and sign the plaintext
|
|
|
|
try {
|
|
|
|
ct = openpgp.write_signed_and_encrypted_message(privateKey, receiverKeys, plaintext);
|
|
|
|
} catch (err) {
|
|
|
|
callback({
|
|
|
|
errMsg: 'Error encrypting plaintext!',
|
|
|
|
err: err
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
2013-10-11 15:30:03 -04:00
|
|
|
|
|
|
|
callback(null, ct);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Decrypt and verify a pgp message for a single sender
|
|
|
|
*/
|
2013-10-12 19:30:56 -04:00
|
|
|
PGP.prototype.decrypt = function(ciphertext, senderKey, callback) {
|
2013-11-14 07:57:52 -05:00
|
|
|
var privateKey, msg, keymat, sesskey, decrypted;
|
|
|
|
|
|
|
|
privateKey = openpgp.keyring.exportPrivateKey(0).obj;
|
2013-10-12 19:30:56 -04:00
|
|
|
senderKey = openpgp.read_publicKey(senderKey)[0];
|
2013-10-11 15:30:03 -04:00
|
|
|
|
2013-11-14 07:57:52 -05:00
|
|
|
try {
|
|
|
|
msg = openpgp.read_message(ciphertext)[0];
|
|
|
|
} catch (err) {
|
|
|
|
callback({
|
|
|
|
errMsg: 'Error decrypting PGP message!',
|
|
|
|
err: err
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
2013-10-11 15:30:03 -04:00
|
|
|
|
|
|
|
// Find the private (sub)key for the session key of the message
|
|
|
|
for (var i = 0; i < msg.sessionKeys.length; i++) {
|
|
|
|
if (privateKey.privateKeyPacket.publicKey.getKeyId() === msg.sessionKeys[i].keyId.bytes) {
|
|
|
|
keymat = {
|
|
|
|
key: privateKey,
|
|
|
|
keymaterial: privateKey.privateKeyPacket
|
|
|
|
};
|
|
|
|
sesskey = msg.sessionKeys[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for (var j = 0; j < privateKey.subKeys.length; j++) {
|
|
|
|
if (privateKey.subKeys[j].publicKey.getKeyId() === msg.sessionKeys[i].keyId.bytes) {
|
|
|
|
keymat = {
|
|
|
|
key: privateKey,
|
|
|
|
keymaterial: privateKey.subKeys[j]
|
|
|
|
};
|
|
|
|
sesskey = msg.sessionKeys[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-14 07:57:52 -05:00
|
|
|
if (!keymat) {
|
2013-10-11 15:30:03 -04:00
|
|
|
callback({
|
|
|
|
errMsg: 'No private key found!'
|
|
|
|
});
|
2013-11-14 07:57:52 -05:00
|
|
|
return;
|
2013-10-11 15:30:03 -04:00
|
|
|
}
|
2013-11-14 07:57:52 -05:00
|
|
|
|
|
|
|
// decrypt and verify ciphertext
|
|
|
|
try {
|
|
|
|
decrypted = msg.decryptAndVerifySignature(keymat, sesskey, senderKey);
|
|
|
|
} catch (err) {
|
|
|
|
callback({
|
|
|
|
errMsg: 'Error decrypting PGP message!',
|
|
|
|
err: err
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
callback(null, decrypted.text);
|
2013-10-11 15:30:03 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
return PGP;
|
|
|
|
});
|