From 0ab548cb905318645ef680a0ea93efdf3d89e2df Mon Sep 17 00:00:00 2001 From: larabr <7375870+larabr@users.noreply.github.com> Date: Tue, 2 Sep 2025 14:20:59 +0200 Subject: [PATCH] Fix zlib compression for data larger than 65KB Regression introduced in https://github.com/openpgpjs/openpgpjs/pull/1826 (v6.2.0) . Due to internal fflate lib changes, part of the compressed data ended up being discarded, leading to a corrupted compressed payload for the encrypted/signed message, which cannot be decompressed. Compression is disabled by default in openpgpjs. Hence, the issue affects only users who enabled zlib compression via e.g. `config.preferredCompressionAlgorithm = openpgp.enums.compression.zlib` and encrypted or signed data larger than 65KB. --- src/packet/compressed_data.js | 8 ++++++-- test/general/openpgp.js | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/packet/compressed_data.js b/src/packet/compressed_data.js index cdeddea0..fa7fddc2 100644 --- a/src/packet/compressed_data.js +++ b/src/packet/compressed_data.js @@ -151,8 +151,12 @@ function zlib(compressionStreamInstantiator, ZlibStreamedConstructor) { return streamFromAsync(() => streamReadToEnd(data).then(inputData => { return new Promise((resolve, reject) => { const zlibStream = new ZlibStreamedConstructor(); - zlibStream.ondata = processedData => { - resolve(processedData); + const processedChunks = []; + zlibStream.ondata = (processedData, final) => { + processedChunks.push(processedData); + if (final) { + resolve(util.concatUint8Array(processedChunks)); + } }; try { zlibStream.push(inputData, true); // only one chunk to push diff --git a/test/general/openpgp.js b/test/general/openpgp.js index 4558cb5c..d626522b 100644 --- a/test/general/openpgp.js +++ b/test/general/openpgp.js @@ -3698,6 +3698,26 @@ XfA3pqV4mTzF }); }); + it('should encrypt and decrypt with one password (larger message)', async function () { + const largerPlaintext = new Uint8Array(100_000); + const encOpt = modifyCompressionEncryptOptions({ + message: await openpgp.createMessage({ binary: largerPlaintext }), + passwords: password1 + }); + const decOpt = { + passwords: password1, + format: 'binary' + }; + return openpgp.encrypt(encOpt).then(async function (encrypted) { + decOpt.message = await openpgp.readMessage({ armoredMessage: encrypted }); + return openpgp.decrypt(decOpt); + }).then(function (decrypted) { + expect(util.equalsUint8Array(decrypted.data, largerPlaintext)).to.be.true; + expect(decrypted.signatures.length).to.equal(0); + verifyCompressionDecrypted(decrypted); + }); + }); + it('Streaming encrypt and decrypt small message roundtrip', async function() { const plaintext = []; let i = 0;