Example: OpenPGP Recipient Identity Disclosure

This example uses the Legion of the Bouncy Castle Java cryptography APIs to perform OpenPGP operations; the APIs are distributed with the example source code.

OpenPGP is a data encryption standard. It is most often used to ensure the end-to-end confidentiality and integrity of email communication, but it can also be used offline and to encrypt and sign files.

RFC 4880 defines the format of OpenPGP messages. In a typical usage scenario, encrypted messages contain two "packets":

  1. a randomly-generated session key, encrypted with the recipient's public key;
  2. the sender's message, encrypted under the session key using a symmetric cipher.

Although OpenPGP provides message confidentiality and integrity, it does not necessarily provide recipient confidentiality because the first of these packets contains the recipient's key ID — the final 64 bits of the SHA-1 hash of their public key — which may be used to corroborate the recipient's identity with a resource that maps public keys to identities, such as an OpenPGP key server.

In this example, two principals attempt to communicate securely using OpenPGP while concealing their identities from a passive attacker with the ability to read messages sent over the communication medium. A sender is chosen randomly from a pool of six principals (Alice, Bob, Charlie, Dan, Elvis and Fred), and a recipient is chosen from the remaining five; their identities are both marked as secret. The sender greets the recipient (with the message "Hello, [NAME]"), encrypts the greeting with the recipient's public key, and sends the encrypted message over an insecure medium, where it is monitored by the attacker. Two pieces of information are observable by the attacker: the header of the first packet in the encrypted message, and the length (in bytes) of the entire encrypted message. Thus, the question we want to answer is "how much information does an attacker learn about the principals' identities by observing these two features of the encrypted traffic?".

Because the two principals are selected uniformly, there are ≈4.9 bits of secret information in this scenario (≈2.6 bits from the sender's identity and ≈2.3 bits from the recipient's identity). LeakWatch reveals that, due to the presence of the recipient's key ID in the first packet, there is a leakage of ≈2.52 bits about the secret information: there is complete leakage of the recipient's identity, and a further leakage of ≈0.2 bits of the sender's identity, because the attacker also knows that the sender is not the recipient.

Some OpenPGP implementations mitigate this leakage of the recipient's identity; e.g., GnuPG features a -R option that replaces the key ID in the first packet with null bytes. By patching the Bouncy Castle OpenPGP API to do the same (which can be mimicked by uncommenting line 56 of RecipientKeyIDTest.java), the leakage decreases to ≈1.86 bits; the recipient's identity is no longer leaked completely via the key ID in the first packet, but because the attacker knows the format of the plaintext message, the length of the second packet still reveals some information about the recipient's identity (because the sender's encrypted message will be longer when greeting a recipient with a longer name).