diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.java index 07098269..b9ead7e7 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.java @@ -649,6 +649,9 @@ public class OpenPgpMessageInputStream extends DecryptionStream { for (PGPPublicKeyEncryptedData pkesk : esks.pkesks) { encryptedData.recipients.add(pkesk.getKeyID()); } + for (PGPPublicKeyEncryptedData pkesk : esks.anonPkesks) { + encryptedData.recipients.add(pkesk.getKeyID()); + } LOGGER.debug("Successfully decrypted data with key " + decryptionKeyId); IntegrityProtectedInputStream integrityProtected = new IntegrityProtectedInputStream(decrypted, asymEsk, options); diff --git a/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/HiddenRecipientEncryptionTest.java b/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/HiddenRecipientEncryptionTest.java new file mode 100644 index 00000000..1cb0d3cb --- /dev/null +++ b/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/HiddenRecipientEncryptionTest.java @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.encryption_signing; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPPublicKeyRing; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.bouncycastle.util.io.Streams; +import org.junit.jupiter.api.Test; +import org.pgpainless.PGPainless; +import org.pgpainless.decryption_verification.ConsumerOptions; +import org.pgpainless.decryption_verification.DecryptionStream; +import org.pgpainless.decryption_verification.MessageMetadata; +import org.pgpainless.key.SubkeyIdentifier; + +/** + * Test encryption with anonymous recipients. + */ +public class HiddenRecipientEncryptionTest { + + @Test + public void testAnonymousRecipientRoundtrip() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException { + PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() + .modernKeyRing("Alice "); + PGPPublicKeyRing certificate = PGPainless.extractCertificate(secretKeys); + + String msg = "Hello, World!\n"; + + ByteArrayOutputStream ciphertextOut = new ByteArrayOutputStream(); + EncryptionStream encryptionStream = PGPainless.encryptAndOrSign() + .onOutputStream(ciphertextOut) + .withOptions(ProducerOptions.encrypt( + EncryptionOptions.get() + .addHiddenRecipient(certificate) + )); + encryptionStream.write(msg.getBytes(StandardCharsets.UTF_8)); + encryptionStream.close(); + EncryptionResult result = encryptionStream.getResult(); + SubkeyIdentifier actualEncryptionKey = result.getRecipients().iterator().next(); + + byte[] ciphertext = ciphertextOut.toByteArray(); + + ByteArrayInputStream ciphertextIn = new ByteArrayInputStream(ciphertext); + DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() + .onInputStream(ciphertextIn) + .withOptions(ConsumerOptions.get() + .addDecryptionKey(secretKeys)); + + ByteArrayOutputStream plaintextOut = new ByteArrayOutputStream(); + Streams.pipeAll(decryptionStream, plaintextOut); + + decryptionStream.close(); + MessageMetadata metadata = decryptionStream.getMetadata(); + + assertEquals(msg, plaintextOut.toString()); + assertTrue(metadata.getRecipientKeyIds().contains(0L)); + assertEquals(actualEncryptionKey, metadata.getDecryptionKey()); + } +}