diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/MessageMetadata.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/MessageMetadata.java index 7743d32e..8c18eadb 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/MessageMetadata.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/MessageMetadata.java @@ -698,6 +698,9 @@ public class MessageMetadata { * @return recipients */ public @Nonnull List getRecipients() { + if (recipients == null) { + return new ArrayList<>(); + } return new ArrayList<>(recipients); } 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 a820dca5..263871de 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 @@ -428,7 +428,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream { } // attempt decryption - if (decryptPKESKAndStream(subkeyIdentifier, decryptorFactory, pkesk)) { + if (decryptPKESKAndStream(esks, subkeyIdentifier, decryptorFactory, pkesk)) { return true; } } @@ -473,7 +473,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream { PBEDataDecryptorFactory decryptorFactory = ImplementationFactory.getInstance() .getPBEDataDecryptorFactory(passphrase); - if (decryptSKESKAndStream(skesk, decryptorFactory)) { + if (decryptSKESKAndStream(esks, skesk, decryptorFactory)) { return true; } } @@ -506,7 +506,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream { } PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(secretKey, protector); - if (decryptWithPrivateKey(privateKey, decryptionKeyId, pkesk)) { + if (decryptWithPrivateKey(esks, privateKey, decryptionKeyId, pkesk)) { return true; } } @@ -529,7 +529,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream { } PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(secretKey, protector); - if (decryptWithPrivateKey(privateKey, decryptionKeyId, pkesk)) { + if (decryptWithPrivateKey(esks, privateKey, decryptionKeyId, pkesk)) { return true; } } @@ -561,7 +561,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream { LOGGER.debug("Attempt decryption with key " + decryptionKeyId + " while interactively requesting its passphrase"); SecretKeyRingProtector protector = options.getSecretKeyProtector(decryptionKey); PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(secretKey, protector); - if (decryptWithPrivateKey(privateKey, decryptionKeyId, pkesk)) { + if (decryptWithPrivateKey(esks, privateKey, decryptionKeyId, pkesk)) { return true; } } @@ -576,13 +576,14 @@ public class OpenPgpMessageInputStream extends DecryptionStream { return false; } - private boolean decryptWithPrivateKey(PGPPrivateKey privateKey, + private boolean decryptWithPrivateKey(SortedESKs esks, + PGPPrivateKey privateKey, SubkeyIdentifier decryptionKeyId, PGPPublicKeyEncryptedData pkesk) throws PGPException, IOException { PublicKeyDataDecryptorFactory decryptorFactory = ImplementationFactory.getInstance() .getPublicKeyDataDecryptorFactory(privateKey); - return decryptPKESKAndStream(decryptionKeyId, decryptorFactory, pkesk); + return decryptPKESKAndStream(esks, decryptionKeyId, decryptorFactory, pkesk); } private static boolean hasUnsupportedS2KSpecifier(PGPSecretKey secretKey, SubkeyIdentifier decryptionKeyId) { @@ -597,17 +598,23 @@ public class OpenPgpMessageInputStream extends DecryptionStream { return false; } - private boolean decryptSKESKAndStream(PGPPBEEncryptedData skesk, PBEDataDecryptorFactory decryptorFactory) + private boolean decryptSKESKAndStream(SortedESKs esks, + PGPPBEEncryptedData symEsk, + PBEDataDecryptorFactory decryptorFactory) throws IOException, UnacceptableAlgorithmException { try { - InputStream decrypted = skesk.getDataStream(decryptorFactory); - SessionKey sessionKey = new SessionKey(skesk.getSessionKey(decryptorFactory)); + InputStream decrypted = symEsk.getDataStream(decryptorFactory); + SessionKey sessionKey = new SessionKey(symEsk.getSessionKey(decryptorFactory)); throwIfUnacceptable(sessionKey.getAlgorithm()); MessageMetadata.EncryptedData encryptedData = new MessageMetadata.EncryptedData( sessionKey.getAlgorithm(), metadata.depth + 1); encryptedData.sessionKey = sessionKey; + encryptedData.recipients = new ArrayList<>(); + for (PGPPublicKeyEncryptedData pkesk : esks.pkesks) { + encryptedData.recipients.add(pkesk.getKeyID()); + } LOGGER.debug("Successfully decrypted data with passphrase"); - IntegrityProtectedInputStream integrityProtected = new IntegrityProtectedInputStream(decrypted, skesk, options); + IntegrityProtectedInputStream integrityProtected = new IntegrityProtectedInputStream(decrypted, symEsk, options); nestedInputStream = new OpenPgpMessageInputStream(integrityProtected, options, encryptedData, policy); return true; } catch (UnacceptableAlgorithmException e) { @@ -618,23 +625,28 @@ public class OpenPgpMessageInputStream extends DecryptionStream { return false; } - private boolean decryptPKESKAndStream(SubkeyIdentifier decryptionKeyId, + private boolean decryptPKESKAndStream(SortedESKs esks, + SubkeyIdentifier decryptionKeyId, PublicKeyDataDecryptorFactory decryptorFactory, - PGPPublicKeyEncryptedData pkesk) + PGPPublicKeyEncryptedData asymEsk) throws IOException, UnacceptableAlgorithmException { try { - InputStream decrypted = pkesk.getDataStream(decryptorFactory); - SessionKey sessionKey = new SessionKey(pkesk.getSessionKey(decryptorFactory)); + InputStream decrypted = asymEsk.getDataStream(decryptorFactory); + SessionKey sessionKey = new SessionKey(asymEsk.getSessionKey(decryptorFactory)); throwIfUnacceptable(sessionKey.getAlgorithm()); MessageMetadata.EncryptedData encryptedData = new MessageMetadata.EncryptedData( - SymmetricKeyAlgorithm.requireFromId(pkesk.getSymmetricAlgorithm(decryptorFactory)), + SymmetricKeyAlgorithm.requireFromId(asymEsk.getSymmetricAlgorithm(decryptorFactory)), metadata.depth + 1); encryptedData.decryptionKey = decryptionKeyId; encryptedData.sessionKey = sessionKey; + encryptedData.recipients = new ArrayList<>(); + for (PGPPublicKeyEncryptedData pkesk : esks.pkesks) { + encryptedData.recipients.add(pkesk.getKeyID()); + } LOGGER.debug("Successfully decrypted data with key " + decryptionKeyId); - IntegrityProtectedInputStream integrityProtected = new IntegrityProtectedInputStream(decrypted, pkesk, options); + IntegrityProtectedInputStream integrityProtected = new IntegrityProtectedInputStream(decrypted, asymEsk, options); nestedInputStream = new OpenPgpMessageInputStream(integrityProtected, options, encryptedData, policy); return true; } catch (UnacceptableAlgorithmException e) { diff --git a/pgpainless-core/src/test/java/org/pgpainless/example/DecryptOrVerify.java b/pgpainless-core/src/test/java/org/pgpainless/example/DecryptOrVerify.java index 2e6c982f..c35b3572 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/example/DecryptOrVerify.java +++ b/pgpainless-core/src/test/java/org/pgpainless/example/DecryptOrVerify.java @@ -170,6 +170,7 @@ public class DecryptOrVerify { // The metadata object contains information about the message MessageMetadata metadata = decryptionStream.getMetadata(); assertTrue(metadata.isEncrypted()); // message was encrypted + assertTrue(metadata.isEncryptedFor(secretKey)); assertFalse(metadata.isVerifiedSigned()); // We did not do any signature verification // The output stream now contains the decrypted message @@ -202,6 +203,7 @@ public class DecryptOrVerify { // metadata with information on the message, like signatures MessageMetadata metadata = decryptionStream.getMetadata(); assertTrue(metadata.isEncrypted()); // messages was in fact encrypted + assertTrue(metadata.isEncryptedFor(certificate)); assertTrue(metadata.isVerifiedSigned()); // the signatures were actually correct assertTrue(metadata.isVerifiedSignedBy(certificate)); // the signatures could be verified using the certificate @@ -233,6 +235,7 @@ public class DecryptOrVerify { // Get the metadata object for information about the message MessageMetadata metadata = verificationStream.getMetadata(); assertTrue(metadata.isVerifiedSigned()); // signatures were verified successfully + assertTrue(metadata.isVerifiedSignedBy(certificate)); // The output stream we piped to now contains the message assertEquals(PLAINTEXT, out.toString()); }