diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c01e66e..bfb5e07 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -56,6 +56,27 @@ The syntax follows what is available in [MyST-parser].
---
+#### Including files
+
+It is advisable to [include external files](https://myst-parser.readthedocs.io/en/latest/syntax/code_and_apis.html#including-code-from-files) with data, instead of using a code block to display the data.
+
+---
+**NOTE**: The reason for this is, that `codespell` is used to check for common spelling mistakes and output from other programs may contain text, that will trigger it to flag it as an error.
+
+To work around this issue, `codespell` is configured to ignore example files, so that not entire chapter files have to be ignored.
+
+---
+
+Use the `{literalcode}` directive to include files:
+
+````
+
+```{literalinclude} examples/my-example.txt
+:language: text
+```
+
+````
+
#### Cross-referencing
There are a few guidelines when it comes to cross-referencing, which work around oddities with [sphinx] and [MyST-parser]:
diff --git a/book/.codespellrc b/book/.codespellrc
index 3fe0661..0ca6c79 100644
--- a/book/.codespellrc
+++ b/book/.codespellrc
@@ -2,4 +2,4 @@
# SPDX-License-Identifier: CC0-1.0
[codespell]
-skip = ./build,./input,./source/diag/*.svg
+skip = ./build,./input,./source/diag/*.svg,./source/examples/*
diff --git a/book/source/10-encryption.md b/book/source/10-encryption.md
index 2b48280..87adc37 100644
--- a/book/source/10-encryption.md
+++ b/book/source/10-encryption.md
@@ -8,44 +8,176 @@ SPDX-License-Identifier: CC-BY-SA-4.0
[Encryption](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#section-2.1) is one of the core facilities of OpenPGP. It provides confidentiality.
+For an in-depth, packet-level view of encrypted data in OpenPGP, see {ref}`zoom_enc`.
+
+## Terminology
+
+| Term | Description |
+|------|-------------|
+| SEIPD Packet | *Symmetrically Encrypted, Integrity Protected Data* packet; contains the encrypted message payload |
+| SKESK Packet | *Symmetric-Key-Encrypted Session-Key* packet; contains or provides a passphrase-encrypted Session-Key |
+| PKESK Packet | *Public-Key-Encrypted Session-Key* packet; contains a session-key encrypted using an asymmetric public-key |
+| Session-Key | Symmetric encryption key, which is either used directly as - or to derive - the Message-Key |
+| Message-Key | Symmetric encryption key used to encrypt the contents of the SEIPD packet |
+
## High-Level overview of the message encryption process
-Core concept:
+Encryption in OpenPGP is performed in two distinct steps:
-- The plaintext is encrypted with a symmetric "session key."
-- The "session key" itself is stored in encrypted form, possibly multiple times:
- - The session key is encrypted to the encryption keys of each intended recipient of the message.
- - Alternatively, or additionally, the session key may be encrypted using a passphrase (this mode of operation doesn't require any OpenPGP certificates.)
+1. The plaintext is encrypted based on a (secret) symmetric key, the [*session key*](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-confidentiality-via-encrypt). The (potentially large) ciphertext only needs to be stored once, even if it is sent to multiple recipients. All recipients get access to the same shared session key to decrypt the message.
+2. For each recipient of the message, a packet that contains the session key is generated.
+ - Usually, the session key is encrypted to a public encryption component key of the recipient.
+ - Alternatively - or additionally - the session key may also be encrypted using a passphrase. This is a specialized and less commonly used mode of operation that doesn't require OpenPGP certificates.
-## Generations of encryption
+```{note}
+Above, "plaintext" either means a *Literal Data* packet, *Compressed Data* packet or a *signed message*.
+A *signed message* on the other hand is a packet sequence that either resembles an *inline-signed message* (a *Literal Data* packet sandwhiched between one or more *One-Pass-Signature* and their respective *Signature* packets), or a *prefixed-signed* message (one or more *Signature* packets followed by a single *Literal Data* packet).
+```
+
+## History of encryption mechanisms in OpenPGP
+
+OpenPGP's encryption mechanisms have evolved over time. The RFC shows an [overview of encryption mechanisms](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#section-10.3.2.1), and how they may be combined.
+
+Two generations of encryption mechanisms are currently relevant in OpenPGP, and will co-exist for the foreseeable future. The main difference between these lies in the symmetric part of the encryption mechanism, represented by versions 1 and 2 of the *Symmetrically Encrypted and Integrity Protected Data* packets (abbreviated as "SEIPD"), as they make use of different techniques to provide non-malleability. More on these below.
+
+Older, legacy encryption mechanisms exist in OpenPGP. However, those must not be used for encryption anymore. Messages encrypted using these legacy mechanisms may still be decrypted, although with caution. For more information see the [decryption](decryption_chapter) chapter.
+
+SEIPD packets are typically used in combination with two mechanisms that provide *session keys*:
+
+- [Public-Key Encrypted Session Key](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-public-key-encrypted-sessio) (PKESK) packets and
+- [Symmetric-Key Encrypted Session Key](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#skesk) (SKESK) packets.
+
+The typical combination of mechanisms for encryption in OpenPGP is a [hybrid cryptosystem](hybrid_cryptosystems), consisting of one or more [Public-Key Encrypted Session Key](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-public-key-encrypted-sessio) packets (PKESK), followed by a [Symmetrically Encrypted Integrity Protected Data* (SEIPD) packet. In this combination, an asymmetric cryptographic mechanism is used to protect a *session key* inside PKESK packets, which is used to protect the plaintext using symmetric-key encryption in a SEIPD packet.
+
+## Encapsulating session keys: PKESK, SKESK
+
+"*ESK" (encrypted session-key) packets are a family of mechanisms for encapsulation of symmetric key material. There are two branches:
+
+- [PKESK](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-public-key-encrypted-sessio): Uses asymmetric OpenPGP key material to protect a session key, and
+- [SKESK](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-symmetric-key-encrypted-ses): Uses passphrases to protect the symmetric key material, instead of OpenPGP asymmetric key material (this is less commonly used).
+
+An arbitrary number of PKESKs and SKESKs can be used for the same message. It is also possible to mix those, resulting in a message which can be decrypted using either one of the designated OpenPGP keys or any of the passwords used to encrypt the message. This is useful to make a message available to a number of known recipients, with the option to provide the password to future recipients.
+
+### PKESK: Session key encrypted to an asymmetric OpenPGP key
+
+To encrypt an OpenPGP message for a recipient, the session-key is encrypted to the recipients public key. The resulting encrypted session key is packed into a PKESK packet, which holds essential metadata, like an identifier of the recipients encryption (sub)-key.
+
+This procedure is repeated for each recipient of the message, and all resulting PKESK packets are prepended to the SEIPD packet (see below) containing the actual message.
+
+Typically, the sender would also include themselves as a recipient, in order to be able to decrypt the sent message at a later point in time.
+
+### SKESK: Session key encrypted to a passphrase
+
+As an alternative (or augmentation) to PKESK packets, a message can also be encrypted to a symmetric passphrase. This is done using a SKESK packet, which basically uses an S2K mechanism to derive a symmetric key from a passphrase, which is then either used directly as the session-key, or more commonly, used as a key-encapsulation-key (KEK) to encrypt the session-key.
+
+Also see https://flowcrypt.com/docs/guide/send-and-receive/send-password-protected-emails.html
+
+As for protection of secret key material, it is important to chose appropriate S2K parameters when generating an SKESK packet.
+The specification currently recommends to use either *Iterated and Salted S2K* or *Argon2*.
+
+```{admonition} TODO:
+:class: warning
+
+Add further guidance for recommended S2K parameters, like iteration count or Argon2 configuration. Perhaps in a dedicated "S2K Parameters" section, which can be reused for the encryption chapter and when we talk about secret key encryption in TSKs.
+```
+
+## Symmetric encryption of data, SEIPD
+
+*Symmetrically Encrypted Integrity Protected Data* (SEIPD) packets represent the symmetric aspect of OpenPGP's encryption mechanism. The function of these packets is entirely independent of (asymmetric) OpenPGP keys.
+
+A SEIPD packet contains the actual payload: the ciphertext of the encrypted message. For a large encrypted message, the SEIPD packet will also be large.
+
+```{note}
+SEIPD packets are the successor to the [Symmetrically Encrypted Data](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-symmetrically-encrypted-dat) packet, which is obsolete.
+```
+
+Two versions of the SEIPD packet (differentiated by the version number) have been specified. Version 1, introduced in RFC4880, is used in OpenPGP v4 while SEIPD version 2 was introduced with OpenPGP v6. Both versions can be used with either OpenPGP v4 or v6 keys, although OpenPGP v4 keys need to announce support for SEIPD version 2 via the *Feature* signature subpacket.
+
+When decrypted, the data contained in a SEIPD packet forms an [OpenPGP message](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-openpgp-messages). That is, the decrypted data consists of a series of OpenPGP packets.
+
+In both versions of SEIPD, the decryptor must have obtained a *session key* in a previous step, before processing the SEIPD packet. Using this session key, the decryptor can decrypt the SEIPD packet and process the plaintext data that it contains.
+
+### v1 SEIPD, based on MDC
+
+The [version 1 SEIPD](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#version-one-seipd) mechanism is supported by all modern OpenPGP version 4 implementations. It was introduced in [RFC 4880](https://www.rfc-editor.org/rfc/rfc4880.html#section-5.13) as a replacement for the *SED* (Symmetrically Encrypted Data) packet. SEIPDv1 provides integrity protection of the ciphertext using a SHA-1 checksum of the plaintext as modification detection code.
+
+Version 1 SEIPD can only be combined with [version 3 PKESK](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#v3-pkesk) and/or [version 4 SKESK](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#v4-skesk) packets.
+
+In this version of the SEIPD packet, the session-key is used directly as message-key, meaning the payload is encrypted symmetrically using the session-key.
+
+When communicating with a mix of recipients, some of whose OpenPGP software only supports OpenPGP version 4, then this mechanism must be used.
+
+```{figure} drawio/SEIPDv1-PKESK.svg
+:name: fig-encryption-seipdv1-pkesk
+:alt: Depicts a dotted hexagon labeled "Plaintext", from which a curved arrow passes another dotted hexagon "Session Key" and finally points to a "SEIPDv1" packet. Two more curved arrows originate from the session key and pass Alice' and Bob's encryption key, ending in two PKESK packets.
+
+With SEIPDv1, the session-key is directly used as message-key to encrypt the payload
+```
(SEIPDv2)=
-### SEIPD w/ AEAD (v2)
+### v2 SEIPD, based on AEAD
-### SEIPD (v1)
+The [version 2 SEIPD](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#version-two-seipd) mechanism was introduced in OpenPGP version 6. Consequently, it can only be used for encryption when all recipients explicitly announce support for it using a *Feature* signature subpacket.
+It provides integrity protection of the ciphertext using *AEAD* (authenticated encryption with additional data).
+v2 SEIPD can only be combined with either [version 6 PKESK](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#v6-pkesk) and/or [version 6 SKESK](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#v6-skesk) packets.
+
+In version 2 SEIPD, the *session key* is transformed into a *message key*, based on a per-message salt value stored separately in the v2 SEIPD packet. The message key is then used in an AEAD scheme to encrypt the message payload.
+
+```{note}
+The session-key can use a different symmetric algorithm than the message-key.
+```
+
+```{figure} drawio/SEIPDv2-PKESK.svg
+:name: fig-encryption-seipdv2-pkesk
+:alt: TODO
+
+With SEIPDv2, the message-key is derived from the session-key in an extra step.
+```
+
+This additional step introduces key-separation into the protocol, which protects against certain attacks, such as an [OpenPGP SEIP downgrade attack](https://www.metzdowd.com/pipermail/cryptography/2015-October/026685.html).
+
+```{admonition} TODO
+:class: warning
+
+Explain, that with SEIPDv2, a session-key can essentially protect more than one message by reusing the same session-key and *ESK packets with a fresh, per-message salt.
+
+This might very well go into the advanced topics section though.
+```
## Advanced topics
-### Encrypt for multiple/single subkey per certificate?
+### Encrypt to multiple/single subkey per certificate?
+
+A recipients certificate may possibly contain more than one usable encryption subkey.
+This raises the question, should the message be encrypted for all of them?
+
+There is the argument, that a powerful attacker might have managed to add an attacker-controlled encryption subkey to the victims certificate.
+In this case, only encrypting to the "newest" encryption key would help uncovering such an attack, although a powerful attacker could just MitM any sent messages and just add a PKESK for the victim-controlled encryption keys to hide the fact that the sender used a different key.
+
+On the other hand, a user might have multiple encryption subkeys on purpose.
+Picture for example a scenario where the same certificate is used on multiple devices, but each devices has dedicated encryption subkeys to allow for smoother revocation in case of a lost device.
+In this scenario, it is important that the sender encrypts the message to all available encryption subkeys.
### "Negotiating" algorithms based on recipients preference subpackets
#### Prevent "downgrade" -> Policy
+Each implementation should define a "minimum" level of security when it comes to algorithms and key lengths.
+If the lowest common denominator of symmetric encryption algorithms preferred by a set of recipients provides too little security, the implementation should either use a configured fallback algorithm instead, or fail to produce a message at all.
+
### Implications of how a recipient cert is "addressed" (fingerprint/key-ID vs. user-ID) (preferences, expiration, revocation)
-### AEAD modes: GCM
+```{admonition} TODO
+:class: warning
+
+This has been described elsewhere already.
+See 9.7.3
+```
+
+### AEAD modes in v2 SEIPD: GCM
```{admonition} TODO
:class: warning
Produce text around discussion: https://mailarchive.ietf.org/arch/msg/openpgp/ZTYD5VJsG1k2jJBbn5zIAf5o7d4/
```
-
-## Zooming in: Packet structure
-
-### Encryption yields a 'wrapped' openpgp packet stream
-
-### SKESK
-
-Also see https://flowcrypt.com/docs/guide/send-and-receive/send-password-protected-emails.html
diff --git a/book/source/11-decryption.md b/book/source/11-decryption.md
index a3e39dd..030c1f0 100644
--- a/book/source/11-decryption.md
+++ b/book/source/11-decryption.md
@@ -6,6 +6,22 @@ SPDX-License-Identifier: CC-BY-SA-4.0
(decryption_chapter)=
# Decryption
+Message decryption is the process of taking an encrypted message and recovering its plaintext.
+This involves multiple steps.
+
+Implementations typically first process the PKESK and SKESK packets leading the SEIPD packet to identify \*ESK packets suitable for decryption.
+A PKESK packet is suitable, if it contains a recipient-keyID matching a decryption (sub-) key of the users certificate.
+Typically, all \*ESK packets leading a SEIPD packet contain the same *session-key* once decrypted.
+
+```{note}
+
+Anonymous-recipient PKESK packets contain a recipient-keyID of `0`, so if no suitable non-anonymous PKESK was found, any anonymous PKESKs are tried with any available decryption (sub-) keys (see [](decryption_anonymous_recipient)).
+```
+
+If no suitable PKESK packets were found, SKESK packets are tried next, meaning the user is typically prompted to enter a decryption passphrase.
+
+Once any of these methods succeeded, the resulting *session-key* is used to decrypt the SEIPD packet.
+
```{admonition} TODO
:class: warning
@@ -15,25 +31,190 @@ SPDX-License-Identifier: CC-BY-SA-4.0
- using revoked subkey?
```
-## SEIPD w/ AEAD (v2)
+## Password-protected session-key (SKESK)
+
+Decrypting a SKESK packet to recover the *session-key* is done by performing the encryption steps in reverse, based on a user-provided passphrase.
+
+In both version 4 and version 6 of the SKESK packet, the user is prompted to enter a passphrase, which is passed through the S2K function described by the SKESK packet.
+However, the subsequent steps of the procedure are different, as described in the following sections.
+
+### SKESK v4
+
+Here, the result of the S2K function is a symmetric key, which is either used to decrypt the encrypted session-key contained in the SKESK packet, or - less commonly - used as session-key directly (see [](decryption-skesk4-direct-method)).
+
+```{note}
+
+The "direct method" where the result of the S2K function is directly used as session key is only applicable if only one SKESK packet is present.
+```
+
+```{figure} drawio/SKESKv4-decryption.svg
+:name: fig-skeskv4-decryption
+:alt: Diagram depicting how the S2K function is used to derive key symmetric key from the user-provided passphrase. This key is then either used directly as session-key, or used to decrypt the encrypted session-key.
+
+Decrypting the session-key from a version 4 SKESK packet.
+```
+
+With version 4 SKESK packets, which are only used with version 1 SEIPD packets, the *session-key* is used as *message-key* without an intermediate derivation.
+
+(decryption-skesk4-direct-method)=
+#### Direct-Method
+
+In version 4 of the SKESK packet, the encrypted session-key is optional. A missing encrypted session-key signals the use of the "direct-method", which means, the result of passing the passphrase through the S2K function is directly used as the session-key/message-key.
+
+When the direct method is used, the symmetric cipher algorithm ID of the SKESK packet dictates the cipher algorithm used to decrypt the plaintext from the SEIPD packet.
+
+Otherwise, the cipher algorithm ID to decrypt the SEIPD packet was prefixed to the decrypted session key.
+
+Sanitizing this algorithm ID of the decrypted session-key acts as a very early quick check to verify that the used passphrase was correct. For further validation of the session-key, see [](decryption_seipd_quick_check).
+
+
+### SKESK v6
+
+With version 6 SKESK packets, the result of the passing the passphrase through the S2K function is used as *initial keying material* (IKM) to derive a symmetric *key encryption key* using HKDF as a key derivation function. The HKDF function doesn't use any salt in this step and the *info* parameter is assembled from parameters of the SKESK packet.
+
+In the next step, this symmetric key is used to decrypt the *session-key* using AEAD.
+The AEAD function uses information from the associated SEIPDv2 packet as *additional data*.
+The function is also salted using the SEIPDv2's salt.
+The *AEAD Auth Tag* of the SKESK packet is used as authentication tag.
+
+The result is the *session-key*.
+
+```{figure} drawio/SKESKv6-decryption.svg
+:name: fig-skeskv6-decryption
+:alt: Diagram depicting the complicated process of deriving the session-key from a SKESK version 6 packet.
+
+Decrypting the session-key from a version 6 SKESK packet.
+```
+
+## Key-protected session key (PKESK)
+
+More common than SKESK packets are PKESK packets which are used to protect the session-key using an encryption key of the recipient.
+
+### PKESK v3
+
+With version 3 PKESKs, the recipients secret encryption (sub-) key is directly used to decrypt the encrypted *session key*.
+The key ID of the subkey to be used is recorded in the PKESKs key-id field. A value of `0` indicates an anonymous recipient (see [](decryption_anonymous_recipient)).
+
+To detect, which symmetric cipher is used to decrypt the SEIPDv1 packet later on, each public key algorithm uses a slightly different encoding to unpack the symmetric algorithm tag from the decrypted session key. See the respective sections[^rsa-spec] [^elgamal-spec] [^ecdh-spec] [^x25519-spec] [^x448-spec] of the standard. Typically, the cipher algorithm ID is prefixed the the actual session key.
+
+[^rsa-spec]: [Algorithm-Specific Fields for RSA encryption](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-algorithm-specific-fields-f)
+[^elgamal-spec]: [Algorithm-Specific Fields for Elgamal encryption](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-algorithm-specific-fields-fo)
+[^ecdh-spec]: [Algorithm-Specific Fields for ECDH encryption](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-algorithm-specific-fields-for)
+[^x25519-spec]: [Algorithm-Specific Fields for X25519 encryption](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-algorithm-specific-fields-for-)
+[^x448-spec]: [Algorithm-Specific Fields for X448 encryption](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-algorithm-specific-fields-for-x)
+
+```{figure} drawio/PKESKv3-decryption.svg
+:name: fig-decryption-pkesk3
+:alt: Depicts, how the the secret-key component of the users encryption subkey is directly used to decrypt the encrypted session-key.
+
+Decrypting the session-key from a version 3 PKESK packet.
+```
+
+### PKESK v6
+
+The decryption of version 6 PKESK packets works quite similar to version 3.
+
+```{figure} drawio/PKESKv6-decryption.svg
+:name: fig-decryption-pkesk6
+:alt: Depicts, how the the secret-key component of the users encryption subkey is directly used to decrypt the encrypted session-key.
+
+Decrypting the session-key from a version 6 PKESK packet.
+```
+
+Contrary to the version 3 PKESK, the encrypted session-key within the version 6 PKESK does not contain the symmetric cipher algorithm used to decrypt the SEIPD packet.
+Instead, this cipher algorithm ID is encoded inside the SEIPDv2 packet directly.
## SEIPD (v1)
+Version 1 SEIPD packets MUST only be used with version 3 PKESK packets and/or version 4 SKESK packets.
+Any other combinations are not allowed and MUST result in a broken message.
+
+```{note}
+Since SEIPD version 1 is susceptible to downgrade attacks under certain scenarios, it is recommended to use SEIPD version 2 wherever possible.
+```
+
+To decrypt the contents of a version 1 SEIPD packet, the session-key obtained in the previous step is used.
+The cipher algorithm is either extracted from the decrypted session-key (the algorithm ID is typically prefixed to the decrypted session-key), or - in case of a SKESK packet using the direct-method - taken from the SKESKs cipher algorithm field.
+
+Once the cipher is initialized, the whole encrypted data from the SEIPD packet is decrypted.
+
+```{admonition} TODO
+:class: warning
+
+Describe the MDC which is used for modification detection.
+```
+
+```{figure} drawio/SEIPDv1-decryption.svg
+:name: fig-decryption-seipd1
+:alt: Depicts how the session-key is used directly to decrypt the contents of the SEIPD packet.
+
+The contents of the SEIPD packet are decrypted using the session-key as message-key.
+```
+
+
+## SEIPD w/ AEAD (v2)
+
+Preferred mode.
+Version 2 SEIPD packets MUST only be used with version 6 PKESK packets and/or version 6 SKESK packets.
+Any other combinations are not allowed and MUST result in a broken message.
+
+Once the session-key was obtained from a PKESK or SKESK, it is used to derive a *message-key* and an IV. This is done by passing the session-key through a salted HKDF function, where the salt is unique per message and obtained from the SEIPD packet.
+
+The result is split into the message key and first half of the IV.
+
+```{figure} drawio/SEIPDv2-decryption-mk-derivation.svg
+:name: fig-decryption-seipd2-mk-derivation
+:alt: Depicts how the session-key is fed into a salted HKDF to derive both the message-key and the first half of an IV.
+
+In a first step, a message-key and half of an IV is derived from the session-key.
+```
+
+Then, the contents of the SEIPDs encrypted data are split into chunks, which are processed sequentially. Each chunk is decrypted using AEAD with parameters from the SEIPD packet as *additional data*.
+For each chunk, the chunk index starting at `0` is passed into the function as second half of the IV.
+
+All decrypted plaintext blocks are appended to form the result of the decryption process.
+
+After all blocks have been processed, in a last AEAD step, the total number of plaintext octets gets appended to the *additional data* and the final AEAD auth tag from the SEIPD packet is processed.
+
+```{figure} drawio/SEIPDv2-decryption-chunks.svg
+:name: fig-decryption-seipd2-chunks
+:alt: Depicts, how the message-key and index-postfixed IV are used to decrypt each individual chunk of plaintext.
+
+Each chunk is decrypted using AEAD using the message-key and an IV with appended chunk index.
+```
+
+
## SED
Legacy mode, may be decrypted, but not produced.
## Advanced topics
-### Selecting decryption key
+(decryption_seipd_quick_check)=
+### Verify successful session-key decryption
-- Trying PKESKs until one works out
-- consider "smart" strategies
+SEIPDv1 packets might make use of a "quick check" mechanism to quickly verify that the correct session key was used without the need to decrypt the whole SEIPD packet.
+This check consists of 16 random bytes, followed a copy of the two last bytes, which are prefixed to the plaintext.
+During decrypting, these 2 bytes can be compared to the 15th and 16th random byte to detect use of the wrong session key.
-additional wrinkle: hidden intended decryption key (`gnupg --throw-keyid`)
-
-also see:
+Since the chance to accidentally end up with matching quick check bytes albeit the use of the wrong session key is 1:65536, some implementations validate further contents of the plaintext, such as the packet headers.
-https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#pkesk-notes
+The standard [warns against](https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-12.html#name-risks-of-a-quick-check-orac) using the quick check mechanism, as it introduces the risk of a decryption oracle. Instead, the use of SEIPDv2 is recommended, as the AEAD mechanism automatically detects use of the wrong session-key early on after the first chunk has been decrypted.
-> An implementation MAY accept or use a Key ID of all zeros, or an omitted key fingerprint, to hide the intended decryption key
\ No newline at end of file
+(decryption_anonymous_recipient)=
+### Anonymous recipients
+
+Having all recipients keys listed as part of the PKESK packets presents a metadata leakage. An observer can easily enumerate recipients of a message by comparing the PKESKs with certificates of potential recipients.
+
+To prevent this issue, the sender can decide to add individual recipients as anonymous recipients using a wildcard key-ID / fingerprint.
+This is done by creating a normal PKESK packet for the recipient, but setting the recipient key field to `0` (as well as omitting the version number of the key for v6 PKESKs).
+
+A recipient of such a message that does not find a PKESK addressed specifically to any of their keys, can then try to decrypt any anonymous PKESK packets using any of their encryption subkeys.
+
+To reduce the number of keys to try, the recipient can skip all secret keys which do not share the public-key algorithm stated in the PKESK packet.
+
+```{admonition} TODO
+:class: warning
+
+When did the decryption succeed? Describe quick check of the check sum and decryption of first few bytes of the SEIPD as test strategies.
+```
diff --git a/book/source/21-zoom_encyption.md b/book/source/21-zoom_encyption.md
index 79880f2..f48b73b 100644
--- a/book/source/21-zoom_encyption.md
+++ b/book/source/21-zoom_encyption.md
@@ -3,4 +3,112 @@ SPDX-FileCopyrightText: 2023 The "Notes on OpenPGP" project
SPDX-License-Identifier: CC-BY-SA-4.0
-->
+(zoom_enc)=
# Zooming in: Packet structure of encrypted data
+
+## SEIPD v2
+
+### Encrypt
+
+We encrypt a short message to Alice, using a public certificate version of {ref}`alice_priv`:
+
+```text
+$ echo "hello world" | sq encrypt --recipient-file alice.pub
+```
+
+This produces an ASCII armored encrypted message:
+
+```{literalinclude} examples/ascii_armored_encrypted_message.asc
+:language: text
+```
+
+### Inspect the packet dump of the encrypted message
+
+Inspecting the packets of this message, we see:
+
+```text
+$ sq packet dump --hex enc.pgp
+Public-Key Encrypted Session Key Packet, new CTB, 2 header bytes + 93 bytes
+ Version: 6
+ Recipient: C0A58384A438E5A14F73712426A4D45DBAEEF4A39E6B30B09D5513F978ACCA94
+ Pk algo: X25519
+
+ 00000000 c1 CTB
+ 00000001 5d length
+ 00000002 06 version
+ 00000003 21 recipient_len
+ 00000004 06 recipient_version
+ 00000005 c0 a5 83 84 a4 38 e5 a1 4f 73 71 recipient
+ 00000010 24 26 a4 d4 5d ba ee f4 a3 9e 6b 30 b0 9d 55 13
+ 00000020 f9 78 ac ca 94
+ 00000025 19 pk_algo
+ 00000026 31 61 a4 33 ba eb 03 ef ca 23 x25519_e
+ 00000030 01 d8 86 c1 0f 0c 23 cb 12 01 70 15 e0 01 0c 28
+ 00000040 87 1b 20 da a1 20
+ 00000046 18 x25519_esk_len
+ 00000047 12 9b 91 15 f6 1f 98 97 f5 x25519_esk
+ 00000050 d5 dd f1 19 d4 93 9a 06 7a ed b2 8d 99 01 2e
+
+Sym. Encrypted and Integrity Protected Data Packet, new CTB, 2 header bytes + 114 bytes
+ Version: 2
+ Symmetric algo: AES-128
+ AEAD algo: EAX
+ Chunk size: 4096
+ Salt: 9673F229E1386AD0464367096945493F4D42FE4D6129B06750B3C89F0F214093
+ No session key supplied
+
+ 00000000 d2 CTB
+ 00000001 72 length
+ 00000002 02 version
+ 00000003 07 sym_algo
+ 00000004 01 aead_algo
+ 00000005 06 chunk_size
+ 00000006 96 73 f2 29 e1 38 6a d0 46 43 salt
+ 00000010 67 09 69 45 49 3f 4d 42 fe 4d 61 29 b0 67 50 b3
+ 00000020 c8 9f 0f 21 40 93
+ 00000026 bb 77 fb 75 ef bc ba f9 75 48 .w.u....uH
+ 00000030 37 f8 eb 7e b0 44 a4 09 28 e1 ad 99 39 d0 72 23 7..~.D..(...9.r#
+ 00000040 c2 30 55 67 a6 35 e7 dc 9f 68 ea ad b4 c4 fa 71 .0Ug.5...h.....q
+ 00000050 7a 96 6b 12 22 b2 13 da 27 e3 91 d6 ad 9b 65 2d z.k."...'.....e-
+ 00000060 4d da 31 5b 69 13 8e 71 b0 12 2b a0 15 ce a0 96 M.1[i..q..+.....
+ 00000070 9d ea a4 20 ...
+```
+
+### Decrypt
+
+```text
+$ sq decrypt --dump-session-key --recipient-file alice.sec enc.pgp
+Session key: 8DDA27B9B000BD84D0A39DFF66780111
+Encrypted using AES-128
+Compressed using ZIP
+hello world
+```
+
+Inspecting the packets inside the SEIPD container:
+
+```text
+$ sq decrypt --dump --recipient-file alice.sec enc.pgp
+Public-Key Encrypted Session Key Packet, new CTB, 93 bytes
+ Version: 6
+ Recipient: C0A58384A438E5A14F73712426A4D45DBAEEF4A39E6B30B09D5513F978ACCA94
+ Pk algo: X25519
+
+Encrypted using AES-128
+Compressed using ZIP
+hello world
+Sym. Encrypted and Integrity Protected Data Packet, new CTB, 114 bytes
+│ Version: 2
+│ Symmetric algo: AES-128
+│ AEAD algo: EAX
+│ Chunk size: 4096
+│ Salt: 9673F229E1386AD0464367096945493F4D42FE4D6129B06750B3C89F0F214093
+│
+└── Compressed Data Packet, new CTB, 44 bytes
+ │ Algorithm: ZIP
+ │
+ ├── Literal Data Packet, new CTB, 18 bytes
+ │ Format: Binary data
+ │
+ └── Padding Packet, new CTB, 14 bytes
+ Unknown variant
+```
diff --git a/book/source/drawio/PKESKv3-decryption.drawio b/book/source/drawio/PKESKv3-decryption.drawio
new file mode 100644
index 0000000..b6e37fe
--- /dev/null
+++ b/book/source/drawio/PKESKv3-decryption.drawio
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/book/source/drawio/PKESKv3-decryption.svg b/book/source/drawio/PKESKv3-decryption.svg
new file mode 100644
index 0000000..da7e8d6
--- /dev/null
+++ b/book/source/drawio/PKESKv3-decryption.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/book/source/drawio/PKESKv6-decryption.drawio b/book/source/drawio/PKESKv6-decryption.drawio
new file mode 100644
index 0000000..26142f7
--- /dev/null
+++ b/book/source/drawio/PKESKv6-decryption.drawio
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/book/source/drawio/PKESKv6-decryption.svg b/book/source/drawio/PKESKv6-decryption.svg
new file mode 100644
index 0000000..0a0dd87
--- /dev/null
+++ b/book/source/drawio/PKESKv6-decryption.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/book/source/drawio/SEIPDv1-PKESK.drawio b/book/source/drawio/SEIPDv1-PKESK.drawio
new file mode 100644
index 0000000..ff0732b
--- /dev/null
+++ b/book/source/drawio/SEIPDv1-PKESK.drawio
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/book/source/drawio/SEIPDv1-PKESK.svg b/book/source/drawio/SEIPDv1-PKESK.svg
new file mode 100644
index 0000000..c8518d1
--- /dev/null
+++ b/book/source/drawio/SEIPDv1-PKESK.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/book/source/drawio/SEIPDv1-decryption.drawio b/book/source/drawio/SEIPDv1-decryption.drawio
new file mode 100644
index 0000000..adf2f4c
--- /dev/null
+++ b/book/source/drawio/SEIPDv1-decryption.drawio
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/book/source/drawio/SEIPDv1-decryption.svg b/book/source/drawio/SEIPDv1-decryption.svg
new file mode 100644
index 0000000..708593e
--- /dev/null
+++ b/book/source/drawio/SEIPDv1-decryption.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/book/source/drawio/SEIPDv2-PKESK.drawio b/book/source/drawio/SEIPDv2-PKESK.drawio
new file mode 100644
index 0000000..9a4a400
--- /dev/null
+++ b/book/source/drawio/SEIPDv2-PKESK.drawio
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/book/source/drawio/SEIPDv2-PKESK.svg b/book/source/drawio/SEIPDv2-PKESK.svg
new file mode 100644
index 0000000..33a2a52
--- /dev/null
+++ b/book/source/drawio/SEIPDv2-PKESK.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/book/source/drawio/SEIPDv2-decryption-chunks.drawio b/book/source/drawio/SEIPDv2-decryption-chunks.drawio
new file mode 100644
index 0000000..e38b132
--- /dev/null
+++ b/book/source/drawio/SEIPDv2-decryption-chunks.drawio
@@ -0,0 +1,257 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/book/source/drawio/SEIPDv2-decryption-chunks.svg b/book/source/drawio/SEIPDv2-decryption-chunks.svg
new file mode 100644
index 0000000..7376d21
--- /dev/null
+++ b/book/source/drawio/SEIPDv2-decryption-chunks.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/book/source/drawio/SEIPDv2-decryption-mk-derivation.drawio b/book/source/drawio/SEIPDv2-decryption-mk-derivation.drawio
new file mode 100644
index 0000000..24dfd8d
--- /dev/null
+++ b/book/source/drawio/SEIPDv2-decryption-mk-derivation.drawio
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/book/source/drawio/SEIPDv2-decryption-mk-derivation.svg b/book/source/drawio/SEIPDv2-decryption-mk-derivation.svg
new file mode 100644
index 0000000..0619eda
--- /dev/null
+++ b/book/source/drawio/SEIPDv2-decryption-mk-derivation.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/book/source/drawio/SKESKv4-decryption.drawio b/book/source/drawio/SKESKv4-decryption.drawio
new file mode 100644
index 0000000..d7c71b5
--- /dev/null
+++ b/book/source/drawio/SKESKv4-decryption.drawio
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/book/source/drawio/SKESKv4-decryption.svg b/book/source/drawio/SKESKv4-decryption.svg
new file mode 100644
index 0000000..c168a78
--- /dev/null
+++ b/book/source/drawio/SKESKv4-decryption.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/book/source/drawio/SKESKv6-decryption.drawio b/book/source/drawio/SKESKv6-decryption.drawio
new file mode 100644
index 0000000..a9ec75b
--- /dev/null
+++ b/book/source/drawio/SKESKv6-decryption.drawio
@@ -0,0 +1,220 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/book/source/drawio/SKESKv6-decryption.svg b/book/source/drawio/SKESKv6-decryption.svg
new file mode 100644
index 0000000..02e79a2
--- /dev/null
+++ b/book/source/drawio/SKESKv6-decryption.svg
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/book/source/examples/ascii_armored_encrypted_message.asc b/book/source/examples/ascii_armored_encrypted_message.asc
new file mode 100644
index 0000000..68bfa3f
--- /dev/null
+++ b/book/source/examples/ascii_armored_encrypted_message.asc
@@ -0,0 +1,9 @@
+-----BEGIN PGP MESSAGE-----
+
+wV0GIQbApYOEpDjloU9zcSQmpNRduu70o55rMLCdVRP5eKzKlBkxYaQzuusD78oj
+AdiGwQ8MI8sSAXAV4AEMKIcbINqhIBgSm5EV9h+Yl/XV3fEZ1JOaBnrtso2ZAS7S
+cgIHAQaWc/Ip4Thq0EZDZwlpRUk/TUL+TWEpsGdQs8ifDyFAk7t3+3XvvLr5dUg3
++Ot+sESkCSjhrZk50HIjwjBVZ6Y159yfaOqttMT6cXqWaxIishPaJ+OR1q2bZS1N
+2jFbaROOcbASK6AVzqCWneqkIA==
+=WFpq
+-----END PGP MESSAGE-----