High Security Request Headers
Encryption types 8 and 9. Both are AES-256-GCM with a 64-byte header. They differ in one thing only: where the key comes from, and therefore what kind of server they address.
Which one do I use?
The choice is made for you by what you are talking to, not by a security preference — the two types are equally strong.
| Type 8 | Type 9 | |
|---|---|---|
| Destination | a RAIDA | a Content Server |
| Key located by | two coin selectors | a 5-byte session handle |
| Key material | AN_A || AN_B | the session key |
| Caller identified by | coin ownership | the session |
| Command coverage | the RAIDA command set | a narrower set — see below |
Why type 9 serves fewer commands
A Content Server holds no coin database. Commands whose whole purpose is to prove or transfer coin ownership — detect, pown, healing, locker, change, shard conversion — have nothing to verify against there, so they are not part of the type 9 command set. This is a property of what a Content Server is, not a gap waiting to be filled.
Coin authenticity numbers never appear on the type 9 wire at all. Possession of the session key is the authentication.
What they share
Both use a 64-byte request header and return a 32-byte response header. Both authenticate the header as well as the body: the GCM tag covers header bytes 0–47 as additional authenticated data, so no byte of the header can be altered in flight without the tag failing.
| Property | Type 8 | Type 9 |
|---|---|---|
| Cipher | AES-256-GCM | AES-256-GCM |
| Request AAD | header bytes 0–47 | header bytes 0–47 |
| Tag | bytes 48–63, full 16 | bytes 48–63, full 16 |
| Nonce | 12 bytes at 29–40 | 12 bytes at 26–37 |
| Body length at | 22–23, 16-bit | 22–25, 32-bit |
| Bytes 8–15 | reserved | MUST be zero |
| Client echo | forced zero | forced zero |
| Replay protection | none | a 64-bit counter |
One command family cannot use these types
The QMail Object Transfer commands (6/76–84) require encryption type 1 and reject types 8 and 9 with ERROR_UNSUPPORTED_PROTOCOL (219).
The reason is a byte-layout collision, not a security decision: those commands carry a 32-bit body length in header bytes 10–13, which the High Security types use for other fields. See the Object Transfer framing for the details. Every other RAIDA command family accepts type 8.
The two are not layout-compatible
Both headers are 64 bytes, and it is tempting to treat them as one format with a different key selector. They are not. The body length, the nonce and the counter all sit at different offsets, so a parser written for one will mis-read the other. Branch on byte 16 before reading any other field.
Header Version 2 is the layout that finally puts type 8 and type 9 on the same offsets. It is a new value of byte 0, not a revision of these two maps.
Key selectors are readable, and that is deliberate
The bytes that identify the key — the coin selectors under type 8, the session handle under type 9 — travel in the clear. They have to: the receiver must read them to work out which key to decrypt with, so encrypting them would be circular.
They are not unprotected. Because they fall inside the authenticated header range, altering any of them invalidates the GCM tag and the request is rejected. A selector is a lookup key, never a secret; the security rests on possession of the key it points at.
Type 8 — AES-256-GCM, keyed by two coins
Type 8 is authenticated encryption: the header is not merely a container, it is cryptographically bound to the body. Tampering with any byte of the first 48 header bytes invalidates the request.
| Bytes | Field | Requirement |
|---|---|---|
| 0–15 | as type 1 | Routing, command, coin type, reserved. |
| 16 | EN | MUST be 0x08. |
| 17 | DN A | Denomination of key coin A. |
| 18–21 | SN A | Serial number of key coin A, big-endian. |
| 22–23 | BL | Body length, 16-bit big-endian, including the terminator. Minimum 18. |
| 24 | DN B | Denomination of key coin B. |
| 25–28 | SN B | Serial number of key coin B, big-endian. |
| 29–40 | NO | 12-byte GCM nonce from a CSPRNG. The most significant bit of byte 29 MUST be 0 on requests. |
| 41–47 | RS | MUST be 0x00. These are inside the AAD, so they cannot be quietly repurposed later. |
| 48–63 | AT | The full 16-byte GCM tag. Truncation is forbidden. |
Key construction. For target RAIDA r, with AN_A and AN_B being the two key coins' authenticity numbers on that RAIDA:
K = AN_A || AN_B (32 bytes, A first, order MUST NOT change)
The key is a concatenation, not a hash
Do not hash the two authenticity numbers together. The key is the raw 32-byte concatenation AN_A || AN_B, in that order. Hashing the concatenation is a plausible-looking mistake that produces a completely different key and a tag that never verifies.
Encryption:
plaintext P = challenge[16] || command_data[N]
ciphertext C = AES-256-GCM-Encrypt(K, nonce, AAD = header[0..47], P)
body = C || 0x3E 0x3E
The request AAD is header bytes 0–47 — the whole header except the tag itself. The terminator is clear and is not authenticated.
Duplicate-key mode
If only one eligible key coin is available, key B may be the same coin as key A: identical selectors in the header, giving K = AN_A || AN_A. Servers accept this.
Be aware of what it costs: the cipher is still AES-256, but the key carries at most 128 bits of entropy. This is a deliberate client-side trade-off for wallets that hold a single usable key coin, and the client software already handles the choice. Deployments that require a genuine 256-bit security target should disable it and fail when no distinct second coin exists.
Type 8 has no replay protection
The GCM nonce makes each request unique, but the server does not remember nonces it has seen, so a captured type 8 request can be replayed. Type 9 addresses this with an explicit counter; type 8 does not have one. Its seven reserved bytes at 41–47 sit inside the AAD and would be the natural place to add one, but no such mechanism exists today.
Type 9 — AES-256-GCM, keyed by a session handle
Type 9 does not go to a RAIDA
Type 9 is Content Server traffic. A RAIDA rejects it, and that is by design: a RAIDA has no session table, so it has nothing to resolve a session handle against. It is documented here because it shares the same framing as the RAIDA types, not because a RAIDA will answer it.
Type 9 changes exactly one thing relative to type 8: how the key is located. Same cipher, same nonce discipline, same tag position, same AAD span, same 32-byte response frame. Where type 8 names two coins and the server derives a key from its coin database, type 9 names a session and the server looks the key up in its session table.
| Bytes | Field | Requirement |
|---|---|---|
| 2 | RI | The Content Server's published node_id — not a RAIDA index. A CS configured with a nonzero node ID rejects a mismatch as malformed; a CS with node ID 0 accepts any value and echoes it. |
| 8–15 | RS | MUST be zero. The Group 6 extended framing that overloads these bytes under type 1 is disabled under type 9; large-object paging moves into the command data instead. |
| 16 | EN | MUST be 0x09. |
| 17–21 | HD | The 5-byte session handle, copied verbatim. It is opaque — no integer interpretation, therefore no endianness. All-zero is reserved and means "this is a session-open request". |
| 22–25 | BL | 32-bit big-endian body length, including the terminator. Four bytes, not two — there is no 64 KB cap here. |
| 26–37 | NO | 12-byte GCM nonce. The most significant bit of byte 26 MUST be 0 on requests. |
| 38–45 | CT | 64-bit big-endian request counter. Zero for a session-open request; 1 or greater for an established session. Replays are refused with status 103. |
| 46–47 | RS | MUST be zero. Authenticated via the AAD. |
| 48–63 | AT | Full 16-byte GCM tag. |
Key lookup:
| Handle | Key | Meaning |
|---|---|---|
| All zero | K_rke, recomputed from the vault and the open context | Session-open request |
| Nonzero | K_sess, from the session table | Established-session command |
The handle is a lookup selector, never a secret. Possession of the GCM key is what authenticates the caller. Coin authenticity numbers never appear on this wire at all — which is the point, since a Content Server is not trusted to hold them.
Challenge: type 9 keeps the 16-byte challenge and validates it. After the GCM tag verifies, the server checks the CRC32 and answers with status 37 on a mismatch.
The RKE key ID is not the session handle
These are easy to confuse and are different things. The RKE key ID is a one-byte vault index used when deriving K_rke from RAIDA-held shares. The session handle is five opaque bytes that locate an already-established session key. Only the handle appears in the type 9 header.
The other type numbers
None of the remaining numbers are available to client software. A request carrying an unimplemented type is rejected with ERROR_INVALID_ENCRYPTION (34).
- Types 3 and 7 are reserved for traffic between servers. Client software cannot use them: the keys involved are held only by servers.
- Types 4 and 5 are an earlier AES-256 design, superseded by type 8. The client library does not support them and no live command accepts them. Do not build anything new on them.
- Type 6 has never been allocated. It is simply a gap in the numbering.