OpenPGP Message Format
Extracted elements (31)
A new random session key is generated for each encrypted message and encrypted separately to each recipient's public key. This hybrid encryption model limits exposure: compromise of one recipient's private key only reveals messages addressed to that recipient, not a long-term symmetric key.
The vagueness of OpenPGP signature semantics (0x10–0x13 certification levels) is intentional, not a flaw. Because OpenPGP places final authority for validity upon the receiver, one signer's casual act may be more rigorous than another authority's positive act.
PGP 2.6.x only accepts Version 3 signatures and only uses old-format packet headers. Software that must interoperate with PGP 2.6.x MUST use old format packets and may only generate Version 3 signatures. The One-Pass Signature packet (Tag 4) does not interoperate with PGP 2.6.x or earlier.
A Subkey Binding Signature (0x18) that binds a signing subkey MUST have an Embedded Signature subpacket containing a 0x19 Primary Key Binding Signature made by that signing subkey.
An implementation SHOULD ignore any Signature subpacket of a type it does not recognize. If an unrecognized subpacket has the critical bit (bit 7 of type octet) set, the evaluator SHOULD consider the signature to be in error.
DSA signatures MUST use hashes that are equal in size to the number of bits of q. If the hash output is larger, the leftmost bits equal to q's bit size are used.
Implementations SHOULD accept V3 signatures and SHOULD generate V4 signatures. V4 is the preferred format due to its extensible subpacket structure.
Implementations SHOULD compress the message after applying the signature but before encryption.
Implementations SHOULD NOT assume that Key IDs are unique; Key IDs are only eight octets and collisions are possible.
Implementations SHOULD use salted or iterated-and-salted S2K specifiers, as simple S2K specifiers are more vulnerable to dictionary attacks.
Packets with a tag greater than or equal to 16 MUST use new format packets, since old format packet tags are only four bits wide.
The Signature Creation Time subpacket MUST be present in the hashed area of a signature.
When a Symmetric-Key ESK packet uses an encrypted session key, the S2K specifier MUST use a salt value (Salted or Iterated-Salted S2K), because an all-zero IV is used for the session key decryption.
When multiple PKESKs are formed with one session key, the implementation MUST make a new PKCS#1 EME-PKCS1-v1_5 encoding for each recipient key.
A Public-Key Encrypted Session Key (PKESK) packet (Tag 1) holds a session key encrypted to one recipient's public key. Its body contains: version (1 octet, currently 3), Key ID (8 octets), public-key algorithm (1 octet), and the encrypted session key MPI(s).
Key flags (signature subpacket type 27) are N-octet flag fields indicating key capabilities: 0x01 certify, 0x02 sign data, 0x04 encrypt communications, 0x08 encrypt storage, 0x10 split key, 0x20 authentication, 0x80 group key. Implementations MUST NOT assume a fixed size.
Packet tags identify packet types. Defined tags include: 1 (Public-Key ESK), 2 (Signature), 3 (Symmetric-Key ESK), 4 (One-Pass Signature), 5 (Secret-Key), 6 (Public-Key), 7 (Secret-Subkey), 8 (Compressed Data), 9 (Symmetrically Encrypted Data), 11 (Literal Data), 13 (User ID), 14 (Public-Subkey), 17 (User Attribute), 18 (Sym. Encrypted Integrity Protected Data), 19 (MDC). Tag 0 is reserved and MUST NOT be used.
Signature types (0x00–0x50) encode the meaning of a Signature packet. Key types include: 0x10–0x13 (User ID certifications of increasing rigor), 0x18 (Subkey Binding), 0x19 (Primary Key Binding), 0x20 (Key Revocation), 0x28 (Subkey Revocation), 0x30 (Certification Revocation), 0x50 (Third-Party Confirmation).
String-to-Key (S2K) specifiers convert passphrases to symmetric keys. Three types are defined: Simple S2K (0x00, hash only), Salted S2K (0x01, 8-octet salt + hash), and Iterated and Salted S2K (0x03, salt + hash with repeated hashing). Values 100–110 are private/experimental.
The One-Pass Signature packet (Tag 4) precedes signed data and contains: version (1 octet, currently 3), signature type, hash algorithm, public-key algorithm, signing Key ID (8 octets), and a nesting flag. Multiple one-pass signatures bracket the message data such that Signature packets appear in reverse order.
The Sym. Encrypted Integrity Protected Data Packet (Tag 18) wraps encrypted content with a Modification Detection Code. It supersedes the bare Symmetrically Encrypted Data Packet (Tag 9) by prepending an encrypted MDC packet to detect tampering.
IANA maintains registries for OpenPGP: Public-Key Algorithm IDs (Section 9.1), Symmetric-Key Algorithm IDs (Section 9.2), Compression Algorithm IDs (Section 9.3), Hash Algorithm IDs (Section 9.4), S2K Specifier Types (Section 10.1), Packet Tags (Section 10.2), Signature Subpacket Types (Section 10.2.2), and User Attribute Types (Section 10.2.1).
Key IDs are only 64 bits and are not guaranteed unique; an attacker may create a key with the same Key ID as a target key. Implementations relying on Key ID alone for key lookup without verifying fingerprints are vulnerable to Key ID substitution attacks.
The Symmetrically Encrypted Data Packet (Tag 9) provides no integrity protection and is vulnerable to modification. Implementations SHOULD use the Sym. Encrypted Integrity Protected Data Packet (Tag 18) with a Modification Detection Code (Tag 19) instead, to detect ciphertext tampering.
Key revocation states are encoded in the Reason for Revocation subpacket (type 29): code 0 (unspecified), 1 (superseded), 2 (compromised), 3 (retired), 32 (User ID no longer valid). A compromised key makes all prior signatures suspect, whereas superseded/retired keys leave old signatures valid.
A packet header begins with a Packet Tag octet where bit 7 is always 1, bit 6 distinguishes new (1) from old (0) format. Old format encodes the tag in bits 5-2 and the length-type in bits 1-0; new format encodes the tag in bits 5-0.
A Signature subpacket header uses the same length encoding as new-format packets (1, 2, or 5 octets) but cannot use Partial Body Lengths. The length includes the type octet. Bit 7 of the type octet is the 'critical' flag.
Iterated and Salted S2K (type 0x03) encodes: one octet type (0x03), one octet hash algorithm, 8-octet salt, one octet coded count where count = (16 + (c & 15)) << ((c >> 4) + 6). The count is total octets to hash, not an iteration count.
Multiprecision integers (MPIs) consist of a two-octet bit-length scalar followed by the integer octets in big-endian order. Unused bits in the most significant octet MUST be zero. The total size is ((MPI.length + 7) / 8) + 2 octets.
New format packet lengths use a variable-length encoding: one-octet (0–191), two-octet (192–8383, decoded as ((first-192)<<8)+second+192), five-octet (first octet = 255, followed by four-octet scalar), or partial body (224–254, length = 1 << (octet & 0x1F)).
The Version 4 Signature packet body contains: version (1 octet), signature type (1), public-key algorithm (1), hash algorithm (1), two-octet hashed subpacket length, hashed subpackets, two-octet unhashed subpacket length, unhashed subpackets, left 16 bits of hash (2 octets), then the signature MPI(s).