OpenPGP Standard Overview Based on RFC 9508
OpenPGP ensures data confidentiality and integrity through public-key and/or symmetric encryption along with digital signatures. It defines formats for encoding and transmitting encrypted or signed messages, aswell as key and certificate material—though key storage and management fall outside its scope.
Core capabilities include:
- Confidentiality via encryption
- Authentication via digital signatures
- Data compression
- Base64 encoding for textual representation
Data Element Formats
Scalar Numbers
Scalars are unsigned integers stored in big-endian byte order. For example, the two-octet sequence [12 10] represents the decimal value 0x12 * 256 + 0x10 = 4624.
Multiprecision Integers (MPIs)
MPIs encode large unsigned integers used in cryptographic operations. Their structure is:
| length (2 octets, in bits) | value (variable octets) |
Examples:
[00 00]→ 0[00 01 01]→ 1 (1 bit long, value0x01)[00 09 01 FF]→ 511 (9 bits:0x01FF)
Rules:
- Unused high-order bits in the value field MUST be zero.
- Total size is
(length + 7) // 8 + 2octets. - MPIs can also encode fixed-length binary data like elliptic curve points.
Key IDs and Fingerprints
A Key ID is an 8-octet identifier derived from a key, not guaranteed unique. Fingerprints are longer hashes of key material and offer stronger uniqueness guarantees. Computation methods vary by key version.
Text Encoding
Text fields use UTF-8 unless otherwise specified.
Time Fields
Timestamps are 4-octet unsigned integers representing seconds since Unix epoch (1970-01-01 00:00:00 UTC).
Keyrings
A keyring is a collection of one or more keys, typically stored as a sequential list in a file or database.
String-to-Key (S2K) Specifiers
S2K converts a passphrase into a symmetric key for encrypting private key material or messages. Supported types:
| ID | Type | Size (octets) | Generate? | Notes |
|---|---|---|---|---|
| 0 | Simple S2K | 2 | No | Deprecated |
| 1 | Salted S2K | 10 | Conditional | Only for high-entropy input |
| 3 | Iterated and Salted S2K | 11 | Yes | Uses encoded iteration count |
| 4 | Argon2 | 20 | Yes | Recommended for new keys |
Simple S2K
Format: [0x00][hash_algo]. The passphrase is hashed directly. If the hash output is shorter than needed, it’s extended by hashing \x00 || passphrase, \x00\x00 || passphrase, etc., and concatenating results.
Salted S2K
Format: [0x01][hash_algo][8-octet salt]. Same extension logic as Simple S2K.
Iterated and Salted S2K
Format: [0x03][hash_algo][8-octet salt][count_octet].
The count_octet encodes an iteration count via:
int32_t count = ((16 + (c & 15)) << ((c >> 4) + 6));
The input to the hash is (salt || passphrase) repeated until reaching count bits (not iterations), then truncated to exactly count bits—but never less than one full salt || passphrase block.
Argon2
Format:
[0x04][16-octet salt][t][p][m]
t: number of passes (≥1)p: parallelism degree (≥1)m: memory exponent; actual memory =2^mKiB
Constraints:
m ∈ [3 + 2^{⌈log₂ p⌉}, 31]- Each passphrase SHOULD use a unique salt
- Output length is determined by the required key size
Recommended parameters:
t = 1,p = 4,m = 21(2 MiB memory), 128-bit salt, 256-bit output
Note: Argon2 is only permitted with AEAD-encrypted private keys.
Private Key Encryption
The first octet after public key material in a secret key packet indicates protection method:
| S2K Usage Octet | Mode | Encryption Parameters | Encryption Scheme | Generate? |
|---|---|---|---|---|
| 0 | Unprotected | — | v4: `secrets | |
| Cipher ID (1–252) | LegacyCFB | IV | CFB(MD5(passphrase), `secrets | |
| 253 | AEAD | len, cipher, AEAD mode, S2K len, S2K, nonce | AEAD(HKDF(S2K(passphrase), info), secrets, prefix) | Yes |
| 254 | CFB | len, cipher, S2K len, S2K, IV | CFB(S2K(passphrase), `secrets | |
| 255 | MalleableCFB | cipher, S2K, IV | CFB(S2K(passphrase), `secrets |
checksum= sum of all secret octets mod 65536 (2 octets)- Version 6 keys require explicit length fields for parameters
- Only rows marked "Generate? = Yes" may be used for new key generation
nonceserves as the AEAD initialization vector
In AEAD mode:
- Derivee base key via S2K(passphrase)
- Expand to final key using HKDF with context-specific
info - Encrypt secrets using AEAD with
packetprefixas associated data
Implementations MUST NOT generate keys using deprecated modes (Simple, LegacyCFB, MalleableCFB). Argon2 is strongly recommended for new AEAD-protected keys due to its memory-hard design.