diff --git a/src/openpgp.js b/src/openpgp.js index ec5ee0a8..3fa9ef14 100644 --- a/src/openpgp.js +++ b/src/openpgp.js @@ -26,7 +26,7 @@ import * as messageLib from './message.js'; import * as cleartext from './cleartext.js'; import * as key from './key.js'; -import armor from './encoding/armor.js'; +import armorLib from './encoding/armor.js'; import enums from './enums.js'; import config from './config/config.js'; import util from './util'; @@ -133,31 +133,35 @@ export function generateKey({ userIds=[], passphrase, numBits=2048, unlocked=fal * @param {Key|Array} privateKeys (optional) private keys for signing. If omitted message will not be signed * @param {String|Array} passwords (optional) array of passwords or a single password to encrypt the message * @param {String} filename (optional) a filename for the literal data packet - * @param {Boolean} packets (optional) if the return value should be a Packetlist - * @return {Promise} encrypted ASCII armored message, or Packetlist if 'packets' is true + * @param {Boolean} armor (optional) if the return value should be ascii armored or the message object + * @return {Promise} encrypted ASCII armored message, or Message if 'armor' is true * @static */ -export function encrypt({ data, publicKeys, privateKeys, passwords, filename, packets }) { +export function encrypt({ data, publicKeys, privateKeys, passwords, filename, armor=true }) { checkData(data); publicKeys = toArray(publicKeys); privateKeys = toArray(privateKeys); passwords = toArray(passwords); if (asyncProxy) { // use web worker if available - return asyncProxy.delegate('encrypt', { data, publicKeys, privateKeys, passwords, filename, packets }); + return asyncProxy.delegate('encrypt', { data, publicKeys, privateKeys, passwords, filename, armor }); } return execute(() => { - let msg = createMessage(data, filename); + let message = createMessage(data, filename); if (privateKeys) { // sign the message only if private keys are specified - msg = msg.sign(privateKeys); + message = message.sign(privateKeys); } - msg = msg.encrypt(publicKeys, passwords); + message = message.encrypt(publicKeys, passwords); - if(packets) { - return getPackets(msg); - } else { - return getAsciiArmored(msg); + if(armor) { + return { + data: armorLib.encode(enums.armor.message, message.packets.write()) + }; } + return { + message: message + }; + }, 'Error encrypting message'); } @@ -387,30 +391,6 @@ function createMessage(data, filename) { return msg; } -/** - * Get the Packetlist from a message object. - * @param {Message} message the message object - * @return {Object} an object contating keys and data - */ -function getPackets(message) { - const dataIndex = message.packets.indexOfTag(enums.packet.symmetricallyEncrypted, enums.packet.symEncryptedIntegrityProtected)[0]; - return { - keys: message.packets.slice(0, dataIndex).write(), - data: message.packets.slice(dataIndex, message.packets.length).write() - }; -} - -/** - * Get the ascii armored message. - * @param {Message} message the message object - * @return {Object} an object containt data - */ -function getAsciiArmored(message) { - return { - data: armor.encode(enums.armor.message, message.packets.write()) - }; -} - /** * Parse the message given a certain format. * @param {Message} message the message object to be parse diff --git a/src/worker/async_proxy.js b/src/worker/async_proxy.js index 3dcc1f2d..f22a6477 100644 --- a/src/worker/async_proxy.js +++ b/src/worker/async_proxy.js @@ -29,6 +29,7 @@ import crypto from '../crypto'; import packet from '../packet'; import * as key from '../key.js'; +import * as message from '../message.js'; import type_keyid from '../type/keyid.js'; const INITIAL_RANDOM_SEED = 50000, // random bytes seeded to worker @@ -154,19 +155,33 @@ function clonePackets(options) { } function parseClonedPackets(data) { - if (data.key) { // parse cloned generated key - const packetlist = packet.List.fromStructuredClone(data.key); - data.key = new key.Key(packetlist); + if (data.key) { + data.key = packetlistCloneToKey(data.key); } - if (data.signatures) { // parse cloned signatures - data.signatures = data.signatures.map(sig => { - sig.keyid = type_keyid.fromClone(sig.keyid); - return sig; - }); + if (data.message) { + data.message = packetlistCloneToMessage(data.message); + } + if (data.signatures) { + data.signatures = data.signatures.map(packetlistCloneToSignature); } return data; } +function packetlistCloneToKey(clone) { + const packetlist = packet.List.fromStructuredClone(clone); + return new key.Key(packetlist); +} + +function packetlistCloneToMessage(clone) { + const packetlist = packet.List.fromStructuredClone(clone.packets); + return new message.Message(packetlist); +} + +function packetlistCloneToSignature(clone) { + clone.keyid = type_keyid.fromClone(clone.keyid); + return clone; +} + AsyncProxy.prototype.decryptKey = function(privateKey, password) { var self = this; diff --git a/src/worker/worker.js b/src/worker/worker.js index 18b861c7..a79e8ba5 100644 --- a/src/worker/worker.js +++ b/src/worker/worker.js @@ -131,8 +131,7 @@ function parseClonedPackets(options, method) { if(options.privateKey) { options.privateKey = packetlistCloneToKey(options.privateKey); } - // parse message depending on method - if (options.message && method === 'verify') { + if (options.message && method === 'verify') { // verify supports only CleartextMessage options.message = packetlistCloneToCleartextMessage(options.message); } else if (options.message) { options.message = packetlistCloneToMessage(options.message); @@ -140,19 +139,19 @@ function parseClonedPackets(options, method) { return options; } -function packetlistCloneToKey(packetlistClone) { - var packetlist = window.openpgp.packet.List.fromStructuredClone(packetlistClone); +function packetlistCloneToKey(clone) { + var packetlist = window.openpgp.packet.List.fromStructuredClone(clone); return new window.openpgp.key.Key(packetlist); } -function packetlistCloneToMessage(message) { - var packetlist = window.openpgp.packet.List.fromStructuredClone(message.packets); +function packetlistCloneToMessage(clone) { + var packetlist = window.openpgp.packet.List.fromStructuredClone(clone.packets); return new window.openpgp.message.Message(packetlist); } -function packetlistCloneToCleartextMessage(message) { - var packetlist = window.openpgp.packet.List.fromStructuredClone(message.packets); - return new window.openpgp.cleartext.CleartextMessage(message.text, packetlist); +function packetlistCloneToCleartextMessage(clone) { + var packetlist = window.openpgp.packet.List.fromStructuredClone(clone.packets); + return new window.openpgp.cleartext.CleartextMessage(clone.text, packetlist); } function clonePackets(data) { diff --git a/test/general/openpgp.js b/test/general/openpgp.js index 427a97dd..9f7a9c99 100644 --- a/test/general/openpgp.js +++ b/test/general/openpgp.js @@ -354,17 +354,6 @@ describe('OpenPGP.js public api tests', function() { expect(privateKey.keys[0].decrypt(passphrase)).to.be.true; }); - function testHelper(encOpt, decOpt) { - return openpgp.encrypt(encOpt).then(function(encrypted) { - expect(encrypted.data).to.exist; - var msg = openpgp.message.readArmored(encrypted.data); - expect(msg).to.exist; - - decOpt.message = msg; - return openpgp.decrypt(decOpt); - }); - } - describe('without Worker', tests); describe('with Worker', function() { before(function() { @@ -387,7 +376,10 @@ describe('OpenPGP.js public api tests', function() { var decOpt = { privateKey: privateKey.keys[0] }; - testHelper(encOpt, decOpt).catch(function(error) { + openpgp.encrypt(encOpt).then(function(encrypted) { + decOpt.message = openpgp.message.readArmored(encrypted.data); + return openpgp.decrypt(decOpt); + }).catch(function(error) { expect(error.message).to.match(/not decrypted/); done(); }); @@ -406,7 +398,10 @@ describe('OpenPGP.js public api tests', function() { var decOpt = { privateKey: privateKey.keys[0] }; - testHelper(encOpt, decOpt).then(function(decrypted) { + openpgp.encrypt(encOpt).then(function(encrypted) { + decOpt.message = openpgp.message.readArmored(encrypted.data); + return openpgp.decrypt(decOpt); + }).then(function(decrypted) { expect(decrypted.data).to.equal(plaintext); expect(decrypted.signatures).to.not.exist; done(); @@ -423,7 +418,10 @@ describe('OpenPGP.js public api tests', function() { privateKey: privateKey.keys[0], publicKeys: publicKey.keys }; - testHelper(encOpt, decOpt).then(function(decrypted) { + openpgp.encrypt(encOpt).then(function(encrypted) { + decOpt.message = openpgp.message.readArmored(encrypted.data); + return openpgp.decrypt(decOpt); + }).then(function(decrypted) { expect(decrypted.data).to.equal(plaintext); expect(decrypted.signatures[0].valid).to.be.true; done(); @@ -452,7 +450,10 @@ describe('OpenPGP.js public api tests', function() { privateKey: privateKey.keys[0], publicKeys: openpgp.key.readArmored(wrong_pubkey).keys }; - testHelper(encOpt, decOpt).then(function(decrypted) { + openpgp.encrypt(encOpt).then(function(encrypted) { + decOpt.message = openpgp.message.readArmored(encrypted.data); + return openpgp.decrypt(decOpt); + }).then(function(decrypted) { expect(decrypted.data).to.equal(plaintext); expect(decrypted.signatures[0].valid).to.be.null; done(); @@ -468,13 +469,16 @@ describe('OpenPGP.js public api tests', function() { var decOpt = { password: password1 }; - testHelper(encOpt, decOpt).then(function(decrypted) { + openpgp.encrypt(encOpt).then(function(encrypted) { + decOpt.message = openpgp.message.readArmored(encrypted.data); + return openpgp.decrypt(decOpt); + }).then(function(decrypted) { expect(decrypted.data).to.equal(plaintext); done(); }); }); - it('should encrypt and decrypt with two password2', function(done) { + it('should encrypt and decrypt with two passwords', function(done) { var encOpt = { data: plaintext, passwords: [password1, password2] @@ -482,7 +486,63 @@ describe('OpenPGP.js public api tests', function() { var decOpt = { password: password2 }; - testHelper(encOpt, decOpt).then(function(decrypted) { + openpgp.encrypt(encOpt).then(function(encrypted) { + decOpt.message = openpgp.message.readArmored(encrypted.data); + return openpgp.decrypt(decOpt); + }).then(function(decrypted) { + expect(decrypted.data).to.equal(plaintext); + done(); + }); + }); + + it('should encrypt and decrypt with password and not ascii armor', function(done) { + var encOpt = { + data: plaintext, + passwords: password1, + armor: false + }; + var decOpt = { + password: password1 + }; + openpgp.encrypt(encOpt).then(function(encrypted) { + decOpt.message = encrypted.message; + return openpgp.decrypt(decOpt); + }).then(function(decrypted) { + expect(decrypted.data).to.equal(plaintext); + done(); + }); + }); + + it('should encrypt and decrypt with one session key', function(done) { + var encOpt = { + data: plaintext, + passwords: password1 + }; + var decOpt = { + sessionKey: password1 + }; + openpgp.encrypt(encOpt).then(function(encrypted) { + decOpt.message = openpgp.message.readArmored(encrypted.data); + return openpgp.decrypt(decOpt); + }).then(function(decrypted) { + expect(decrypted.data).to.equal(plaintext); + done(); + }); + }); + + it('should encrypt and decrypt with two session keys and not ascii armor', function(done) { + var encOpt = { + data: plaintext, + passwords: [password1, password2], + armor: false + }; + var decOpt = { + sessionKey: password2 + }; + openpgp.encrypt(encOpt).then(function(encrypted) { + decOpt.message = encrypted.message; + return openpgp.decrypt(decOpt); + }).then(function(decrypted) { expect(decrypted.data).to.equal(plaintext); done(); });