diff --git a/src/openpgp.js b/src/openpgp.js index 9478f548..5f6dc374 100644 --- a/src/openpgp.js +++ b/src/openpgp.js @@ -127,14 +127,14 @@ export function generateKey({ userIds=[], passphrase="", numBits=2048, keyExpira const revocationCertificate = key.getRevocationCertificate(); key.revocationSignatures = []; - return { + return convertStreams({ key: key, - privateKeyArmored: await convertStream(key.armor()), - publicKeyArmored: await convertStream(key.toPublic().armor()), + privateKeyArmored: key.armor(), + publicKeyArmored: key.toPublic().armor(), revocationCertificate: revocationCertificate - }; + }); }).catch(onError.bind(null, 'Error generating keypair')); } @@ -309,7 +309,7 @@ export function encrypt({ message, publicKeys, privateKeys, passwords, sessionKe if (privateKeys.length || signature) { // sign the message only if private keys or signature is specified if (detached) { const detachedSignature = await message.signDetached(privateKeys, signature, date, fromUserId); - result.signature = armor ? await convertStream(detachedSignature.armor(), asStream) : detachedSignature; + result.signature = armor ? detachedSignature.armor() : detachedSignature; } else { message = await message.sign(privateKeys, signature, date, fromUserId); } @@ -320,14 +320,13 @@ export function encrypt({ message, publicKeys, privateKeys, passwords, sessionKe }).then(async encrypted => { if (armor) { result.data = encrypted.message.armor(); - result.data = await convertStream(result.data, asStream); } else { result.message = encrypted.message; } if (returnSessionKey) { result.sessionKey = encrypted.sessionKey; } - return result; + return convertStreams(result, asStream, armor ? ['signature', 'data'] : []); }).catch(onError.bind(null, 'Error encrypting message')); } @@ -425,17 +424,16 @@ export function sign({ message, privateKeys, armor=true, asStream=message&&messa return Promise.resolve().then(async function() { if (detached) { const signature = await message.signDetached(privateKeys, undefined, date, fromUserId); - result.signature = armor ? await convertStream(signature.armor(), asStream) : signature; + result.signature = armor ? signature.armor() : signature; } else { message = await message.sign(privateKeys, undefined, date, fromUserId); if (armor) { result.data = message.armor(); - result.data = await convertStream(result.data, asStream); } else { result.message = message; } } - return result; + return convertStreams(result, asStream, armor ? ['signature', 'data'] : []); }).catch(onError.bind(null, 'Error signing cleartext message')); } @@ -596,9 +594,9 @@ function toArray(param) { /** * Convert data to or from Stream - * @param {Object} data the data to convert - * @param {Boolean} asStream whether to return a ReadableStream - * @returns {Object} the parse data in the respective format + * @param {Object} data the data to convert + * @param {Boolean} asStream (optional) whether to return a ReadableStream + * @returns {Object} the data in the respective format */ async function convertStream(data, asStream) { if (!asStream && util.isStream(data)) { @@ -615,6 +613,26 @@ async function convertStream(data, asStream) { return data; } +/** + * Convert object properties from Stream + * @param {Object} obj the data to convert + * @param {Boolean} asStream (optional) whether to return ReadableStreams + * @param {Boolean} keys (optional) which keys to return as streams, if possible + * @returns {Object} the data in the respective format + */ +async function convertStreams(obj, asStream, keys=[]) { + if (Object.prototype.isPrototypeOf(obj)) { + await Promise.all(Object.entries(obj).map(async ([key, value]) => { // recursively search all children + if (util.isStream(value) || keys.includes(key)) { + obj[key] = await convertStream(value, asStream); + } else { + await convertStreams(obj[key], asStream); + } + })); + } + return obj; +} + /** * Global error handler that logs the stack trace and rethrows a high lvl error message. diff --git a/test/general/brainpool.js b/test/general/brainpool.js index 5420183d..7120b96d 100644 --- a/test/general/brainpool.js +++ b/test/general/brainpool.js @@ -213,14 +213,14 @@ describe('Brainpool Cryptography', function () { function omnibus() { it('Omnibus BrainpoolP256r1 Test', function () { const options = { userIds: {name: "Hi", email: "hi@hel.lo"}, curve: "brainpoolP256r1" }; - return openpgp.generateKey(options).then(async function (firstKey) { - const hi = (await openpgp.key.readArmored(firstKey.privateKeyArmored)).keys[0]; - const pubHi = (await openpgp.key.readArmored(firstKey.publicKeyArmored)).keys[0]; + return openpgp.generateKey(options).then(function (firstKey) { + const hi = firstKey.key; + const pubHi = hi.toPublic(); const options = { userIds: { name: "Bye", email: "bye@good.bye" }, curve: "brainpoolP256r1" }; - return openpgp.generateKey(options).then(async function (secondKey) { - const bye = (await openpgp.key.readArmored(secondKey.privateKeyArmored)).keys[0]; - const pubBye = (await openpgp.key.readArmored(secondKey.publicKeyArmored)).keys[0]; + return openpgp.generateKey(options).then(function (secondKey) { + const bye = secondKey.key; + const pubBye = bye.toPublic(); const testData = input.createSomeMessage(); const testData2 = input.createSomeMessage(); diff --git a/test/general/ecc_nist.js b/test/general/ecc_nist.js index 94053175..94cd9d60 100644 --- a/test/general/ecc_nist.js +++ b/test/general/ecc_nist.js @@ -241,14 +241,14 @@ describe('Elliptic Curve Cryptography', function () { const options = { userIds: {name: "Hi", email: "hi@hel.lo"}, curve: "p256" }; const testData = input.createSomeMessage(); const testData2 = input.createSomeMessage(); - return openpgp.generateKey(options).then(async function (firstKey) { - const hi = (await openpgp.key.readArmored(firstKey.privateKeyArmored)).keys[0]; - const pubHi = (await openpgp.key.readArmored(firstKey.publicKeyArmored)).keys[0]; + return openpgp.generateKey(options).then(function (firstKey) { + const hi = firstKey.key; + const pubHi = hi.toPublic(); - const options = { userIds: { name: "Bye", email: "bye@good.bye" }, curve: "brainpoolP256r1" }; - return openpgp.generateKey(options).then(async function (secondKey) { - const bye = (await openpgp.key.readArmored(secondKey.privateKeyArmored)).keys[0]; - const pubBye = (await openpgp.key.readArmored(secondKey.publicKeyArmored)).keys[0]; + const options = { userIds: { name: "Bye", email: "bye@good.bye" }, curve: "p256" }; + return openpgp.generateKey(options).then(function (secondKey) { + const bye = secondKey.key; + const pubBye = bye.toPublic(); return Promise.all([ // Signing message diff --git a/test/general/key.js b/test/general/key.js index cfb035f9..48eff2b3 100644 --- a/test/general/key.js +++ b/test/general/key.js @@ -1837,8 +1837,8 @@ VYGdb3eNlV8CfoEC const opt = {numBits: 512, userIds: userId, passphrase: 'passphrase'}; if (openpgp.util.getWebCryptoAll()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys const key = (await openpgp.generateKey(opt)).key; - const armor1 = await openpgp.stream.readToEnd(key.armor()); - const armor2 = await openpgp.stream.readToEnd(key.armor()); + const armor1 = key.armor(); + const armor2 = key.armor(); expect(armor1).to.equal(armor2); expect(await key.decrypt('passphrase')).to.be.true; expect(key.isDecrypted()).to.be.true; @@ -1848,7 +1848,7 @@ VYGdb3eNlV8CfoEC expect(key.isDecrypted()).to.be.false; expect(await key.decrypt('new_passphrase')).to.be.true; expect(key.isDecrypted()).to.be.true; - const armor3 = await openpgp.stream.readToEnd(key.armor()); + const armor3 = key.armor(); expect(armor3).to.not.equal(armor1); }); diff --git a/test/general/openpgp.js b/test/general/openpgp.js index 261eca48..8de4cede 100644 --- a/test/general/openpgp.js +++ b/test/general/openpgp.js @@ -1712,15 +1712,16 @@ describe('OpenPGP.js public api tests', function() { message, privateKeys: privateKey_1337.keys, detached: true, - date: past + date: past, + armor: false }; const verifyOpt = { message, publicKeys: publicKey_1337.keys, date: past }; - return openpgp.sign(signOpt).then(async function (signed) { - verifyOpt.signature = await openpgp.signature.readArmored(signed.signature); + return openpgp.sign(signOpt).then(function (signed) { + verifyOpt.signature = signed.signature; return openpgp.verify(verifyOpt).then(function (verified) { expect(+verified.signatures[0].signature.packets[0].created).to.equal(+past); expect(verified.data).to.equal(openpgp.util.removeTrailingSpaces(plaintext)); diff --git a/test/general/x25519.js b/test/general/x25519.js index 67257adb..6f0c1e8f 100644 --- a/test/general/x25519.js +++ b/test/general/x25519.js @@ -212,6 +212,7 @@ describe('X25519 Cryptography', function () { expect(result.signatures[0].valid).to.be.true; }); + // TODO export, then reimport key and validate function omnibus() { it('Omnibus Ed25519/Curve25519 Test', function () { const options = { @@ -222,14 +223,12 @@ describe('X25519 Cryptography', function () { expect(firstKey).to.exist; expect(firstKey.privateKeyArmored).to.exist; expect(firstKey.publicKeyArmored).to.exist; + expect(firstKey.key).to.exist; + expect(firstKey.key.primaryKey).to.exist; + expect(firstKey.key.subKeys).to.have.length(1); + expect(firstKey.key.subKeys[0].keyPacket).to.exist; - const hi = (await openpgp.key.readArmored(firstKey.privateKeyArmored)).keys[0]; - const pubHi = (await openpgp.key.readArmored(firstKey.publicKeyArmored)).keys[0]; - expect(hi).to.exist; - expect(hi.primaryKey).to.exist; - expect(hi.subKeys).to.have.length(1); - expect(hi.subKeys[0].subKey).to.exist; - + const hi = firstKey.key; const primaryKey = hi.primaryKey; const subKey = hi.subKeys[0]; expect(hi.getAlgorithmInfo().curve).to.equal('ed25519'); @@ -243,7 +242,7 @@ describe('X25519 Cryptography', function () { primaryKey, { userId: user.userId, key: primaryKey } )).to.eventually.be.true; await expect(user.verifyCertificate( - primaryKey, user.selfCertifications[0], [pubHi] + primaryKey, user.selfCertifications[0], [hi.toPublic()] )).to.eventually.equal(openpgp.enums.keyStatus.valid); const options = { @@ -251,8 +250,7 @@ describe('X25519 Cryptography', function () { curve: "curve25519" }; return openpgp.generateKey(options).then(async function (secondKey) { - const bye = (await openpgp.key.readArmored(secondKey.privateKeyArmored)).keys[0]; - const pubBye = (await openpgp.key.readArmored(secondKey.publicKeyArmored)).keys[0]; + const bye = secondKey.key; expect(bye.getAlgorithmInfo().curve).to.equal('ed25519'); expect(bye.getAlgorithmInfo().algorithm).to.equal('eddsa'); expect(bye.subKeys[0].getAlgorithmInfo().curve).to.equal('curve25519'); @@ -264,14 +262,14 @@ describe('X25519 Cryptography', function () { bye.primaryKey, { userId: user.userId, key: bye.primaryKey } )).to.eventually.be.true; await expect(user.verifyCertificate( - bye.primaryKey, user.selfCertifications[0], [pubBye] + bye.primaryKey, user.selfCertifications[0], [bye.toPublic()] )).to.eventually.equal(openpgp.enums.keyStatus.valid); return Promise.all([ // Hi trusts Bye! - pubBye.signPrimaryUser([hi]).then(trustedBye => { + bye.toPublic().signPrimaryUser([hi]).then(trustedBye => { expect(trustedBye.users[0].otherCertifications[0].verify( - primaryKey, { userId: user.userId, key: pubBye.primaryKey } + primaryKey, { userId: user.userId, key: bye.toPublic().primaryKey } )).to.eventually.be.true; }), // Signing message @@ -282,12 +280,12 @@ describe('X25519 Cryptography', function () { // Verifying signed message return Promise.all([ openpgp.verify( - { message: msg, publicKeys: pubHi } + { message: msg, publicKeys: hi.toPublic() } ).then(output => expect(output.signatures[0].valid).to.be.true), // Verifying detached signature openpgp.verify( { message: openpgp.message.fromText('Hi, this is me, Hi!'), - publicKeys: pubHi, + publicKeys: hi.toPublic(), signature: await openpgp.signature.readArmored(signed.data) } ).then(output => expect(output.signatures[0].valid).to.be.true) ]); @@ -295,7 +293,7 @@ describe('X25519 Cryptography', function () { // Encrypting and signing openpgp.encrypt( { message: openpgp.message.fromText('Hi, Hi wrote this but only Bye can read it!'), - publicKeys: [pubBye], + publicKeys: [bye.toPublic()], privateKeys: [hi] } ).then(async encrypted => { const msg = await openpgp.message.readArmored(encrypted.data); @@ -303,7 +301,7 @@ describe('X25519 Cryptography', function () { return openpgp.decrypt( { message: msg, privateKeys: bye, - publicKeys: [pubHi] } + publicKeys: [hi.toPublic()] } ).then(output => { expect(output.data).to.equal('Hi, Hi wrote this but only Bye can read it!'); expect(output.signatures[0].valid).to.be.true;