1
0
mirror of https://github.com/moparisthebest/mail synced 2024-11-26 02:42:17 -05:00

upgrade to openpgp.js v0.3.0

This commit is contained in:
Tankred Hase 2014-01-24 13:26:29 +01:00
parent 67127b8163
commit 6676e7bc01
5 changed files with 131 additions and 13686 deletions

View File

@ -4,12 +4,10 @@
define(function(require) { define(function(require) {
'use strict'; 'use strict';
var openpgp = require('openpgp').openpgp, var openpgp = require('openpgp'),
util = require('openpgp').util; util = require('openpgp').util;
var PGP = function() { var PGP = function() {};
openpgp.init();
};
/** /**
* Generate a key pair for the user * Generate a key pair for the user
@ -27,7 +25,7 @@ define(function(require) {
// generate keypair (keytype 1=RSA) // generate keypair (keytype 1=RSA)
try { try {
userId = 'Whiteout User <' + options.emailAddress + '>'; userId = 'Whiteout User <' + options.emailAddress + '>';
keys = openpgp.generate_key_pair(1, options.keySize, userId, options.passphrase); keys = openpgp.generateKeyPair(1, options.keySize, userId, options.passphrase);
} catch (e) { } catch (e) {
callback({ callback({
errMsg: 'Keygeneration failed!', errMsg: 'Keygeneration failed!',
@ -37,7 +35,7 @@ define(function(require) {
} }
callback(null, { callback(null, {
keyId: util.hexstrdump(keys.privateKey.getKeyId()).toUpperCase(), keyId: keys.key.getKeyPacket().getKeyId().toHex().toUpperCase(),
privateKeyArmored: keys.privateKeyArmored, privateKeyArmored: keys.privateKeyArmored,
publicKeyArmored: keys.publicKeyArmored publicKeyArmored: keys.publicKeyArmored
}); });
@ -46,48 +44,53 @@ define(function(require) {
/** /**
* Show a user's fingerprint * Show a user's fingerprint
*/ */
PGP.prototype.getFingerprint = function(publicKeyArmored) { PGP.prototype.getFingerprint = function(keyArmored) {
var publicKey, privateKey; function fingerprint(key) {
return util.hexstrdump(key.getKeyPacket().getFingerprint()).toUpperCase();
if (publicKeyArmored) {
// parse the optional public key parameter
publicKey = openpgp.read_publicKey(publicKeyArmored)[0];
return util.hexstrdump(publicKey.getFingerprint()).toUpperCase();
} }
privateKey = openpgp.keyring.exportPrivateKey(0); // process armored key input
if (privateKey && privateKey.keyId) { if (keyArmored) {
publicKey = openpgp.keyring.getPublicKeysForKeyId(privateKey.keyId)[0]; return fingerprint(openpgp.key.readArmored(keyArmored).keys[0]);
} }
if (!privateKey || !privateKey.keyId || !privateKey.armored || !publicKey || !publicKey.armored) { if (!this._publicKey) {
console.error('Public key not available!'); throw new Error('No public key set for fingerprint generation!');
return '';
} }
return util.hexstrdump(publicKey.obj.getFingerprint()).toUpperCase(); // get local fingerpring
return fingerprint(this._publicKey);
}; };
/** /**
* Show a user's key id * Show a user's key id
*/ */
PGP.prototype.getKeyId = function() { PGP.prototype.getKeyId = function() {
var privateKey = openpgp.keyring.exportPrivateKey(0); var pubKeyId, privKeyId;
if (!privateKey || !privateKey.keyId) {
console.error('Public key not available!'); // check keys
return ''; if (!this._privateKey || !this._publicKey) {
return;
} }
return util.hexstrdump(privateKey.keyId).toUpperCase(); pubKeyId = this._publicKey.getKeyPacket().getKeyId().toHex().toUpperCase();
privKeyId = this._privateKey.getKeyPacket().getKeyId().toHex().toUpperCase();
if (!pubKeyId || !privKeyId || pubKeyId !== privKeyId) {
console.error('Key IDs do not match!');
return;
}
return pubKeyId;
}; };
/** /**
* Import the user's key pair * Import the user's key pair
*/ */
PGP.prototype.importKeys = function(options, callback) { PGP.prototype.importKeys = function(options, callback) {
var publicKey, privateKey; var pubKeyId, privKeyId, self = this;
// check passphrase // check options
if (typeof options.passphrase !== 'string' || !options.privateKeyArmored || !options.publicKeyArmored) { if (typeof options.passphrase !== 'string' || !options.privateKeyArmored || !options.publicKeyArmored) {
callback({ callback({
errMsg: 'Importing keys failed. Not all options set!' errMsg: 'Importing keys failed. Not all options set!'
@ -95,25 +98,37 @@ define(function(require) {
return; return;
} }
// clear any keypair already in the keychain function resetKeys() {
openpgp.keyring.init(); self._publicKey = undefined;
// unlock and import private key self._privateKey = undefined;
if (!openpgp.keyring.importPrivateKey(options.privateKeyArmored, options.passphrase)) { }
openpgp.keyring.init();
// read armored keys
try {
this._publicKey = openpgp.key.readArmored(options.publicKeyArmored).keys[0];
this._privateKey = openpgp.key.readArmored(options.privateKeyArmored).keys[0];
} catch (e) {
resetKeys();
callback({
errMsg: 'Importing keys failed. Parsing error!'
});
return;
}
// decrypt private key with passphrase
if (!this._privateKey.decrypt(options.passphrase)) {
resetKeys();
callback({ callback({
errMsg: 'Incorrect passphrase!' errMsg: 'Incorrect passphrase!'
}); });
return; return;
} }
// import public key
openpgp.keyring.importPublicKey(options.publicKeyArmored);
// check if keys have the same id // check if keys have the same id
privateKey = openpgp.keyring.exportPrivateKey(0); pubKeyId = this._publicKey.getKeyPacket().getKeyId().toHex();
publicKey = openpgp.keyring.getPublicKeysForKeyId(privateKey.keyId)[0]; privKeyId = this._privateKey.getKeyPacket().getKeyId().toHex();
if (!privateKey || !privateKey.armored || !publicKey || !publicKey.armored || privateKey.keyId !== publicKey.keyId) { if (!pubKeyId || !privKeyId || pubKeyId !== privKeyId) {
// reset keyring resetKeys();
openpgp.keyring.init();
callback({ callback({
errMsg: 'Key IDs dont match!' errMsg: 'Key IDs dont match!'
}); });
@ -127,14 +142,7 @@ define(function(require) {
* Export the user's key pair * Export the user's key pair
*/ */
PGP.prototype.exportKeys = function(callback) { PGP.prototype.exportKeys = function(callback) {
var publicKey, privateKey; if (!this._publicKey || !this._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) {
callback({ callback({
errMsg: 'Could not export keys!' errMsg: 'Could not export keys!'
}); });
@ -142,26 +150,33 @@ define(function(require) {
} }
callback(null, { callback(null, {
keyId: util.hexstrdump(privateKey.keyId).toUpperCase(), keyId: this._publicKey.getKeyPacket().getKeyId().toHex().toUpperCase(),
privateKeyArmored: privateKey.armored, privateKeyArmored: this._privateKey.armor(),
publicKeyArmored: publicKey.armored publicKeyArmored: this._publicKey.armor()
}); });
}; };
/** /**
* Encrypt and sign a pgp message for a list of receivers * Encrypt and sign a pgp message for a list of receivers
*/ */
PGP.prototype.encrypt = function(plaintext, receiverKeys, callback) { PGP.prototype.encrypt = function(plaintext, publicKeysArmored, callback) {
var ct, i, var ciphertext, publicKeys = [];
privateKey = openpgp.keyring.exportPrivateKey(0).obj;
for (i = 0; i < receiverKeys.length; i++) { // check keys
receiverKeys[i] = openpgp.read_publicKey(receiverKeys[i])[0]; if (!this._privateKey || publicKeysArmored.length < 1) {
callback({
errMsg: 'Error encrypting. Keys must be set!'
});
return;
} }
try { try {
// parse armored public keys
publicKeysArmored.forEach(function(pubkeyArmored) {
publicKeys.push(openpgp.key.readArmored(pubkeyArmored).keys[0]);
});
// encrypt and sign the plaintext // encrypt and sign the plaintext
ct = openpgp.write_signed_and_encrypted_message(privateKey, receiverKeys, plaintext); ciphertext = openpgp.signAndEncryptMessage(publicKeys, this._privateKey, plaintext);
} catch (err) { } catch (err) {
callback({ callback({
errMsg: 'Error encrypting plaintext!', errMsg: 'Error encrypting plaintext!',
@ -170,65 +185,28 @@ define(function(require) {
return; return;
} }
callback(null, ct); callback(null, ciphertext);
}; };
/** /**
* Decrypt and verify a pgp message for a single sender * Decrypt and verify a pgp message for a single sender
*/ */
PGP.prototype.decrypt = function(ciphertext, senderKey, callback) { PGP.prototype.decrypt = function(ciphertext, publicKeyArmored, callback) {
var privateKey, publicKey, pubKeys, msg, keymat, sesskey, decrypted; var publicKey, message, decrypted, signaturesValid;
privateKey = openpgp.keyring.exportPrivateKey(0).obj; // check keys
publicKey = openpgp.read_publicKey(senderKey)[0]; if (!this._privateKey || !publicKeyArmored) {
pubKeys = [{
armored: senderKey,
obj: publicKey,
keyId: publicKey.getKeyId()
}];
try {
msg = openpgp.read_message(ciphertext)[0];
} catch (err) {
callback({ callback({
errMsg: 'Error reading PGP message!', errMsg: 'Error decrypting. Keys must be set!'
err: err
}); });
return; return;
} }
// Find the private (sub)key for the session key of the message // decrypt and verify pgp 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;
}
}
}
if (!keymat) {
callback({
errMsg: 'No private key found!'
});
return;
}
// decrypt and verify ciphertext
try { try {
decrypted = msg.decryptAndVerifySignature(keymat, sesskey, pubKeys); publicKey = openpgp.key.readArmored(publicKeyArmored).keys[0];
message = openpgp.message.readArmored(ciphertext);
decrypted = openpgp.decryptAndVerifyMessage(this._privateKey, [publicKey], message);
} catch (err) { } catch (err) {
callback({ callback({
errMsg: 'Error decrypting PGP message!', errMsg: 'Error decrypting PGP message!',
@ -237,14 +215,18 @@ define(function(require) {
return; return;
} }
// check if signatures are ok // check if signatures are valid
for (var k = 0; k < decrypted.validSignatures.length; k++) { signaturesValid = true;
if (!decrypted.validSignatures[k]) { decrypted.signatures.forEach(function(sig) {
callback({ if (!sig.valid) {
errMsg: 'Error verifying PGP signature!' signaturesValid = false;
});
return;
} }
});
if (!signaturesValid) {
callback({
errMsg: 'Verifying PGP signature failed!'
});
return;
} }
// return decrypted plaintext // return decrypted plaintext

File diff suppressed because it is too large Load Diff

6
src/lib/openpgp/openpgp.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -20,7 +20,7 @@
angularTouch: 'angular/angular-touch.min', angularTouch: 'angular/angular-touch.min',
moment: 'moment/moment.min', moment: 'moment/moment.min',
uuid: 'uuid/uuid', uuid: 'uuid/uuid',
openpgp: 'openpgp/openpgp', openpgp: 'openpgp/openpgp.min',
iscroll: 'iscroll/iscroll-min' iscroll: 'iscroll/iscroll-min'
}, },
shim: { shim: {
@ -35,9 +35,6 @@
exports: 'angular', exports: 'angular',
deps: ['angular'] deps: ['angular']
}, },
openpgp: {
exports: 'window'
},
iscroll: { iscroll: {
exports: 'IScroll' exports: 'IScroll'
}, },

View File

@ -10,33 +10,33 @@ define(function(require) {
passphrase = 'asdf', passphrase = 'asdf',
keySize = 512, keySize = 512,
keyId = 'F6F60E9B42CDFF4C', keyId = 'F6F60E9B42CDFF4C',
pubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\n' + pubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n' +
'Version: OpenPGP.js v.1.20131011\n' + 'Version: OpenPGP.js v0.3.0\r\n' +
'Comment: http://openpgpjs.org\n' + 'Comment: http://openpgpjs.org\r\n' +
'\n' + '\r\n' +
'xk0EUlhMvAEB/2MZtCUOAYvyLFjDp3OBMGn3Ev8FwjzyPbIF0JUw+L7y2XR5\n' + 'xk0EUlhMvAEB/2MZtCUOAYvyLFjDp3OBMGn3Ev8FwjzyPbIF0JUw+L7y2XR5\r\n' +
'RVGvbK88unV3cU/1tOYdNsXI6pSp/Ztjyv7vbBUAEQEAAc0pV2hpdGVvdXQg\n' + 'RVGvbK88unV3cU/1tOYdNsXI6pSp/Ztjyv7vbBUAEQEAAc0pV2hpdGVvdXQg\r\n' +
'VXNlciA8d2hpdGVvdXQudGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhM\n' + 'VXNlciA8d2hpdGVvdXQudGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhM\r\n' +
'vQkQ9vYOm0LN/0wAAAW4Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXq\n' + 'vQkQ9vYOm0LN/0wAAAW4Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXq\r\n' +
'IiN602mWrkd8jcEzLsW5IUNzVPLhrFIuKyBDTpLnC07Loce1\n' + 'IiN602mWrkd8jcEzLsW5IUNzVPLhrFIuKyBDTpLnC07Loce1\r\n' +
'=6XMW\n' + '=6XMW\r\n' +
'-----END PGP PUBLIC KEY BLOCK-----', '-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n',
privkey = '-----BEGIN PGP PRIVATE KEY BLOCK-----\n' + privkey = '-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n' +
'Version: OpenPGP.js v.1.20131011\n' + 'Version: OpenPGP.js v0.3.0\r\n' +
'Comment: http://openpgpjs.org\n' + 'Comment: http://openpgpjs.org\r\n' +
'\n' + '\r\n' +
'xcBeBFJYTLwBAf9jGbQlDgGL8ixYw6dzgTBp9xL/BcI88j2yBdCVMPi+8tl0\n' + 'xcBeBFJYTLwBAf9jGbQlDgGL8ixYw6dzgTBp9xL/BcI88j2yBdCVMPi+8tl0\r\n' +
'eUVRr2yvPLp1d3FP9bTmHTbFyOqUqf2bY8r+72wVABEBAAH+AwMIhNB4ivtv\n' + 'eUVRr2yvPLp1d3FP9bTmHTbFyOqUqf2bY8r+72wVABEBAAH+AwMIhNB4ivtv\r\n' +
'Y2xg6VeMcjjHxZayESHACV+nQx5Tx6ev6xzIF1Qh72fNPDppLhFSFOuTTMsU\n' + 'Y2xg6VeMcjjHxZayESHACV+nQx5Tx6ev6xzIF1Qh72fNPDppLhFSFOuTTMsU\r\n' +
'kTN4c+BVYt29spH+cA1jcDAxQ2ULrNAXo+hheOqhpedTs8aCbcLFkJAS16hk\n' + 'kTN4c+BVYt29spH+cA1jcDAxQ2ULrNAXo+hheOqhpedTs8aCbcLFkJAS16hk\r\n' +
'YSk4OnJgp/z24rVju1SHRSFbgundPzmNgXeX9e8IkviGhhQ11Wc5YwVkx03t\n' + 'YSk4OnJgp/z24rVju1SHRSFbgundPzmNgXeX9e8IkviGhhQ11Wc5YwVkx03t\r\n' +
'Z3MdDMF0jyhopbPIoBdyJB0dhvBh98w3JmwpYh9wjUA9MBHD1tvHpRmSZ3BM\n' + 'Z3MdDMF0jyhopbPIoBdyJB0dhvBh98w3JmwpYh9wjUA9MBHD1tvHpRmSZ3BM\r\n' +
'UCmATn2ZLWBRWiYqFbgDnL1GM80pV2hpdGVvdXQgVXNlciA8d2hpdGVvdXQu\n' + 'UCmATn2ZLWBRWiYqFbgDnL1GM80pV2hpdGVvdXQgVXNlciA8d2hpdGVvdXQu\r\n' +
'dGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhMvQkQ9vYOm0LN/0wAAAW4\n' + 'dGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhMvQkQ9vYOm0LN/0wAAAW4\r\n' +
'Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXqIiN602mWrkd8jcEzLsW5\n' + 'Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXqIiN602mWrkd8jcEzLsW5\r\n' +
'IUNzVPLhrFIuKyBDTpLnC07Loce1\n' + 'IUNzVPLhrFIuKyBDTpLnC07Loce1\r\n' +
'=ULta\n' + '=ULta\r\n' +
'-----END PGP PRIVATE KEY BLOCK-----'; '-----END PGP PRIVATE KEY BLOCK-----\r\n';
beforeEach(function() { beforeEach(function() {
pgp = new PGP(); pgp = new PGP();
@ -90,6 +90,7 @@ define(function(require) {
publicKeyArmored: pubkey publicKeyArmored: pubkey
}, function(err) { }, function(err) {
expect(err).to.exist; expect(err).to.exist;
expect(err.errMsg).to.equal('Incorrect passphrase!');
pgp.exportKeys(function(err, keys) { pgp.exportKeys(function(err, keys) {
expect(err).to.exist; expect(err).to.exist;
@ -109,15 +110,15 @@ define(function(require) {
pgp.exportKeys(function(err, keys) { pgp.exportKeys(function(err, keys) {
expect(err).to.not.exist; expect(err).to.not.exist;
expect(keys.keyId).to.equal(keyId); expect(keys.keyId).to.equal(keyId);
expect(keys.privateKeyArmored).to.equal(privkey); expect(keys.privateKeyArmored.replace(/\r/g, '')).to.equal(privkey.replace(/\r/g, ''));
expect(keys.publicKeyArmored).to.equal(pubkey); expect(keys.publicKeyArmored.replace(/\r/g, '')).to.equal(pubkey.replace(/\r/g, ''));
done(); done();
}); });
}); });
}); });
}); });
describe('Encryption', function() { describe('Encrypt/Sign/Decrypt/Verify', function() {
var message = 'asdfs\n\nThursday, Nov 21, 2013 7:38 PM asdf@example.com wrote:\n' + var message = 'asdfs\n\nThursday, Nov 21, 2013 7:38 PM asdf@example.com wrote:\n' +
'> asdf\n' + '> asdf\n' +
'> \n' + '> \n' +
@ -199,7 +200,7 @@ define(function(require) {
it('should work', function(done) { it('should work', function(done) {
pgp.decrypt(ciphertext, pubkey, function(err, pt) { pgp.decrypt(ciphertext, pubkey, function(err, pt) {
expect(err).to.not.exist; expect(err).to.not.exist;
expect(pt).to.equal(message.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n')); expect(pt).to.equal(message);
done(); done();
}); });
}); });