bc-java
bc-java copied to clipboard
Decryption of OpenPGP messages without encrypted session key packets
According to RFC4880, a valid OpenPGP message may not necessarily include an encrypted session key:
OpenPGP Message :- Encrypted Message [...]
Encrypted Data :- Symmetrically Encrypted Data Packet |
Symmetrically Encrypted Integrity Protected Data Packet
Encrypted Message :- Encrypted Data | ESK Sequence, Encrypted Data.
(Substitution: OpenPGP Message -> Encrypted Message -> Encrypted Data)
I noticed, that BCs PGPObjectFactory cannot properly parse encrypted data packets if there are no encrypted session key packets (fixed in 5d9a45839a9d129cae0eee6f5dbae7ff40165a91).
With that resolved, I noticed that it is not possible to decrypt a message without any encrypted session keys using a session key, since the current implementation requires at least one PKESK/SKESK (Public/Symmetric Key Encrypted Session Key) packet.
As a solution I added the PGPSessionKeyEncryptedData object which allows decryption using a PGPSessionKey.
The user can add this manually to a PGPEncryptedDataList by calling pgpEncryptedDataList.addSessionKeyDecryptionMethod(PGPSessionKey sessionKey).
With these patches in place, messages without encrypted session keys can be decrypted :partying_face:!
Perhaps we want to remove the session key decryption on PGPPBEEncryptedData/PublicKeyEncryptedData introduced in https://github.com/bcgit/bc-java/pull/1030 in favor of this for a cleaner API?
I added isIntegrityProtected() to PGPEncryptedDataList.
Before, it was not possible to determine whether a PGPEncryptedDataList was integrity-protected if the list of methods was empty.
The PGPEncryptedDataList is probably the better place for this method anyways.
Okay I've done a bit of work on this now. How's the following look:
PGPSessionKeyEncryptedData sessionKeyEncData = encryptedData.extractSessionKeyEncryptedData();
SessionKeyDataDecryptorFactory decryptorFactory = new BcSessionKeyDataDecryptorFactory(sessionKey);
InputStream decrypted = sessionKeyEncData.getDataStream(decryptorFactory);
Really the data list is already carrying the session key encrypted data, there's no need to pass the session key in twice (actually sometimes there may be very good reasons for not doing so).
I like your proposal better than my solution :+1:.
Should be appearing in github shortly. I've deprecated the old methods and marked them for later removal.