From 2a5ab75fcac7a7cf90a5534541cd9717475bce48 Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Fri, 19 Jul 2019 16:33:35 +0200 Subject: [PATCH] Decrypt message with multiple keys in parallel Don't keep the entire message in memory. This also fixes an unhandled promise rejection when the input stream contains an error (e.g. an armor checksum mismatch). --- src/message.js | 10 +++++----- src/packet/sym_encrypted_integrity_protected.js | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/message.js b/src/message.js index e4208c85..30f4e2e6 100644 --- a/src/message.js +++ b/src/message.js @@ -115,22 +115,22 @@ Message.prototype.decrypt = async function(privateKeys, passwords, sessionKeys, const symEncryptedPacket = symEncryptedPacketlist[0]; let exception = null; - for (let i = 0; i < keyObjs.length; i++) { - if (!keyObjs[i] || !util.isUint8Array(keyObjs[i].data) || !util.isString(keyObjs[i].algorithm)) { + const decryptedPromise = Promise.all(keyObjs.map(async keyObj => { + if (!keyObj || !util.isUint8Array(keyObj.data) || !util.isString(keyObj.algorithm)) { throw new Error('Invalid session key for decryption.'); } try { - await symEncryptedPacket.decrypt(keyObjs[i].algorithm, keyObjs[i].data, streaming); - break; + await symEncryptedPacket.decrypt(keyObj.algorithm, keyObj.data, streaming); } catch (e) { util.print_debug_error(e); exception = e; } - } + })); // We don't await stream.cancel here because it only returns when the other copy is canceled too. stream.cancel(symEncryptedPacket.encrypted); // Don't keep copy of encrypted data in memory. symEncryptedPacket.encrypted = null; + await decryptedPromise; if (!symEncryptedPacket.packets || !symEncryptedPacket.packets.length) { throw exception || new Error('Decryption failed.'); diff --git a/src/packet/sym_encrypted_integrity_protected.js b/src/packet/sym_encrypted_integrity_protected.js index 71f5e1f7..68d20314 100644 --- a/src/packet/sym_encrypted_integrity_protected.js +++ b/src/packet/sym_encrypted_integrity_protected.js @@ -109,8 +109,8 @@ SymEncryptedIntegrityProtected.prototype.encrypt = async function (sessionKeyAlg * @async */ SymEncryptedIntegrityProtected.prototype.decrypt = async function (sessionKeyAlgorithm, key, streaming) { - if (!streaming) this.encrypted = await stream.readToEnd(this.encrypted); - const encrypted = stream.clone(this.encrypted); + let encrypted = stream.clone(this.encrypted); + if (!streaming) encrypted = await stream.readToEnd(encrypted); const decrypted = await crypto.cfb.decrypt(sessionKeyAlgorithm, key, encrypted, new Uint8Array(crypto.cipher[sessionKeyAlgorithm].blockSize)); // there must be a modification detection code packet as the