How PGP works: hybrid encryption, signatures and packets

Updated November 2026

PGP does not encrypt your message with your recipient’s public key directly. It makes a fresh random key for each message, encrypts the message with that key using fast symmetric encryption, and then encrypts only that small key with the recipient’s public key. This page walks through that idea and the other steps around it.

Two kinds of encryption

Symmetric encryption uses one key to lock and unlock, like a house key. It is very fast and works on data of any size. OpenPGP software today uses AES for it. The catch: the sender and the recipient both need the same key, and you cannot safely send it over the same channel as the message.

Public-key encryption uses a pair of keys. Anyone can use your public key to encrypt something for you, but only your private key can decrypt it. That solves the key-sharing problem, because you can publish the public key anywhere. But public-key operations are slow, and they can only handle small amounts of data. Current keys typically use Curve25519 (X25519) for this. Older keys use RSA.

PGP combines the two. This is called hybrid encryption.

Hybrid encryption step by step

RFC 9580, the OpenPGP standard, describes what happens when you encrypt a message to Bob:

  1. The software generates a random session key, used for this one message only.
  2. It encrypts the message with the session key, using a symmetric cipher such as AES.
  3. It encrypts the session key with Bob’s public key.
  4. It sends both: the encrypted session key first, then the encrypted message.

Bob’s software reverses this. His private key decrypts the session key, and the session key decrypts the message.

Session key random, used once Your message plain text or file Encrypt session key with Bob’s public key Encrypt message with session key (AES) OpenPGP message Encrypted session key Encrypted message Bob reverses the steps: his private key opens the session key, and the session key opens the message.
Hybrid encryption: the slow public-key step only ever handles the small session key.

This design has a useful side effect: one message can have many recipients. Say you send a 10 MB file to three people. The file is encrypted once, about 10 MB, and the session key is encrypted three times, once with each recipient’s public key. With the Curve25519 keys GnuPG makes, each encrypted session key takes about 100 bytes, so three recipients add about 300 bytes, not another 20 MB.

Encrypting with only a passphrase (gpg --symmetric) works in a similar way. The session key is protected with a key derived from the passphrase, not with a public key.

Hashes and signatures

A hash function turns any amount of data into a short fixed-size value, like a very strong checksum. SHA2-256, the hash every RFC 9580 program must support, always gives 256 bits. Change one letter of the input and the hash changes completely. Finding two inputs with the same hash is meant to be impossible in practice.

To sign, your software hashes the data and then signs the hash with your private key. To verify, the recipient’s software hashes the data it received and checks the signature against that hash using your public key. If even one byte changed, verification fails. A good signature shows two things: the data has not changed, and it was signed by whoever holds the private key. Whether that key really belongs to the person it names is a separate question, covered in Key signatures.

Ed25519 is the signature algorithm every RFC 9580 program must support. MD5, which PGP 2.x used, and SHA-1 must no longer be used to make signatures.

Signing and encrypting together

When you sign and encrypt, the signature goes on the inside. The software signs the plain message, may compress the result, and then encrypts everything. Only the recipient can see the signature, and it still checks out after decryption. It also means an eavesdropper cannot tell from the outside who signed the message.

Inside a message: packets

An OpenPGP message is a sequence of packets, each with a type number and a length. Keys, signatures and messages are all built from packets. You can look at them with gpg --list-packets. Here is a short signed-and-encrypted message made with GnuPG (output shortened):

gpg --list-packets message.asc

:pubkey enc packet: version 3, algo 18, keyid EBD243B6F125D26C
:encrypted data packet:
	mdc_method: 2
:compressed packet: algo=2
:onepass_sig packet: keyid F2C9F13D0062B815
:literal data packet:
	mode b (62), created 1793775997, name="msg.txt",
	raw data: 14 bytes
:signature packet: algo 22, keyid F2C9F13D0062B815
	digest algo 10, begin of digest 7d e6
The packets in the example, from outside to inside
Packet (type number)What it holds
Public-Key Encrypted Session Key (1)The session key, encrypted to one recipient’s key. There is one per recipient.
Symmetrically Encrypted and Integrity Protected Data (18)Everything below, encrypted with the session key, plus a check that detects tampering.
Compressed Data (8)The inner packets, compressed (here with ZLIB).
One-Pass Signature (4)Tells the reader a signature follows, so it can hash the data as it reads it, in one pass.
Literal Data (11)The actual 14-byte message, with a file name and date.
Signature (2)The signature over the literal data.

A public key file has its own packets: Public Key (6), User ID (13), Signature (2) for each self-signature and certification, and Public Subkey (14).

Compression

Encrypted data looks random and does not compress, so compression, when it happens at all, comes before encryption. The standard defines ZIP, ZLIB and BZip2, and requires only that programs handle uncompressed data. Compression is optional. RFC 9580 also warns that a malicious message could be built to expand without limit, so programs should cap how many layers of compression they will unpack.

ASCII armor

Packets are binary. Email and web forms handle plain text better, so OpenPGP can wrap binary data in ASCII armor: base64 text, in lines of at most 76 characters, between header lines such as these:

-----BEGIN PGP MESSAGE-----

hF4D69JDtvEl0mwSAQdAXUJjpoK3a9U4ZGtgGGAPZUA4sZiGlqsGiNyzCrwv7kcw
…
=6gOV
-----END PGP MESSAGE-----

The other headers are PUBLIC KEY BLOCK, PRIVATE KEY BLOCK and SIGNATURE. The short line starting with = is an optional CRC24 checksum. RFC 9580 now says programs should not add it, and must not add it for the new version 6 formats. In GnuPG, --armor (or -a) produces armored output. Without it you get binary.

A cleartext signature (gpg --clearsign) leaves the text readable above an armored signature. Trailing spaces are ignored and line endings are normalized before signing, and any line that starts with a dash gets “- ” in front of it. That is why the method suits plain text but not files where whitespace matters, such as patches.

Keys, subkeys and fingerprints

What people call a “public key” is really a bundle, an OpenPGP certificate. It holds a primary key (used for signing and certifying), one or more user IDs, self-signatures that tie them together, and usually subkeys for other jobs. Since version 2.3, GnuPG by default makes an Ed25519 primary key marked [SC] (sign, certify) and a Curve25519 subkey marked [E] (encrypt). Since 2.4.3, new keys expire after three years unless you choose otherwise.

The fingerprint is a hash of the primary public key. For the common version 4 keys it is a 160-bit SHA-1 hash, shown as 40 hex digits, and the 64-bit key ID is its last 16 digits. Version 6 keys from RFC 9580 use SHA2-256, which gives a 256-bit fingerprint, and their key ID is its first 64 bits. More in Keys.

Your private key is stored encrypted with a key derived from your passphrase. RFC 9580 adds Argon2 for this, a method designed to make guessing passphrases slow and memory-hungry.

What changed since PGP 2.x

The old FAQ’s appendix described PGP 2.x as three parts: RSA, IDEA and MD5. The design is the same today. The parts have changed:

JobPGP 2.x (1990s)RFC 9580 (2024)
Public-key algorithmRSAX25519 and Ed25519 required; new RSA keys must be at least 3072 bits
Symmetric cipherIDEAAES-128 required, AES-256 recommended; IDEA must not be used to encrypt
HashMD5SHA2-256 required; MD5 and SHA-1 must not be used for new signatures
Tamper detectionNone in the old encrypted-data packet (type 9)Integrity-protected packet (type 18); version 2 uses authenticated encryption (OCB required)
FingerprintMD5 (version 3 keys)SHA-1 (version 4), SHA2-256 (version 6)

Not every program uses every part of RFC 9580 yet. OpenPGP standards explains where implementations differ.

Sources