The Identity Block
Thirty-two bytes at the head of a request body that say who is calling. This is not a header, and it is not universal — the QMail command family uses it, and other command families do not.
A note on naming
This used to be called the "48-byte modern authenticated preamble"
That name caused more confusion than any other term in this documentation, in four separate ways:
- It is not a preamble. It does not precede the body; it is the beginning of the body, inside the encryption.
- "48 bytes" collided with an unrelated 48-byte structure elsewhere in the protocol, and both were described on the same documentation page.
- "Modern" meant nothing. It had been applied to three different generations of design.
- "Authenticated" was not always true. Whether the identity is actually checked depends on the command — see below.
The 48 in the old name came from counting the 16-byte challenge along with the 32-byte identity structure. The challenge belongs to the protocol layer and is present on every request regardless of whether an identity follows it, so this page counts the identity block as 32 bytes and treats the challenge separately.
Layout
Body offsets 0–47 of a decrypted QMail request. The challenge is shown for orientation; the identity block itself is bytes 16–47.
| Body bytes | Size | Field | Meaning |
|---|---|---|---|
| 0–15 | 16 | Challenge | 12 random bytes plus their CRC32. Protocol layer, not part of the identity. Present on every request. |
| 16–23 | 8 | Session ID | HV=1 QMail: eight zeros; RAIDAs SHOULD reject nonzero. HV=2 AUTH_COIN: eight zeros. HV=2 AUTH_SESSION (Content Server): 5-byte session handle, left-aligned, last three bytes zero, MUST equal header LOC A. See below. |
| 24–25 | 2 | Coin type | CloudCoin is 0x0006. |
| 26 | 1 | Denomination | Denomination of the identity coin. |
| 27–30 | 4 | Serial number | Serial number of the identity coin, big-endian. |
| 31 | 1 | Reserved | Formerly a device ID. No longer used; the server ignores it. |
| 32–47 | 16 | Authenticity Number | AUTH_COIN: the identity coin's AN on the RAIDA being addressed. AUTH_SESSION: MUST be sixteen zeros. |
The identity coin is not the key coin
The coin named here — the one whose AN proves who you are — is generally a different coin from the one named in the request header, whose AN encrypts the packet. Two coins, two roles, two places in the request. Confusing them produces requests that decrypt correctly and then fail authorisation, or vice versa.
How the server verifies it — and when it does not
Where the identity is checked, the server looks up the coin by denomination and serial number in its own database and compares the stored AN against the one in the block. A mismatch returns ERROR_INVALID_AN (200); an unknown coin returns ERROR_INVALID_SN_OR_DENOMINATION (40).
But this is a per-command behaviour, not a property of the structure:
| Command | Identity AN verified? |
|---|---|
| 70 upload | Yes |
| 71 tell | Yes — and the sender named inside the payload must match the verified identity |
| 72 ping, 73 peek | Yes |
| 85 subscribe | Yes — the identity coin is the vendor |
| device link commands | Yes — each device authenticates with its own coin |
| 74 download | No. See below. |
Download does not authenticate its identity coin
The download handler never looks the coin up and never compares the AN. The AN in the block is still consumed — it is used as key material by the encryption layer — but no authorisation decision is made from it. Access is gated by an ACL sidecar instead.
This has a practical diagnostic consequence. If a client builds a download request with a zero AN in the identity block — a common bug when an encryption-state structure is aliased unsafely — the server cannot derive the right key, fails to decrypt the body, never reaches the handler, and returns ERROR_INVALID_ENCRYPTION (34). The error points at encryption, but the cause is the identity block.
Two ways to count the offsets
Server and client code count this structure from different origins, which is worth knowing before you compare them:
| Counts from | Calls it | Session ID at | |
|---|---|---|---|
| Server | the start of the decrypted body, challenge included | 48 bytes | offset 16 |
| Client | the start of the identity structure it writes | 32 bytes | offset 0 |
The same bytes, sixteen apart. The client's packet builder prepends the challenge separately, so the client library never sees the challenge as part of "the preamble" while the server always does. When reading either codebase, check which origin is in use before trusting an offset.
DRD does not use this layout
There are currently two identity conventions in the protocol
This page documents the QMail identity block. The DRD command family (group 16) does something different: it places the caller's denomination, serial number and AN inline at the start of its command payload, immediately after the challenge, with no session field, no coin type and no reserved byte.
The verification logic is equivalent — DRD looks the coin up and compares the AN, just as QMail does — but the fields sit at different offsets and are reached by different code. A client cannot reuse its QMail identity builder for DRD.
DRD is pre-production and this is expected to change. Converging DRD onto the shared identity block is under consideration; the window for doing that without a wire break closes when DRD ships. Until it is decided, treat DRD's identity layout as documented on the DRD command pages, not here.
Other command families — authentication, locker, change, RKE — place their coin data directly in their command payloads in whatever shape the command needs. They do not have an identity block at all. Do not assume this structure exists in a request unless the command's own page says so.
Session ID versus coin
Bytes 16–23 are the dual identity slot. A RAIDA authenticates by coin ownership (serial + AN). A standalone Content Server has no coin database, so it authenticates once at SESSION_OPEN and then the caller presents a session handle in this slot — the same 32-byte block, never both a coin and a session.
| Envelope | Bytes 16–23 | Coin fields 24–47 |
|---|---|---|
| HV=1 QMail (live) | MUST be eight zeros. RAIDAs SHOULD reject nonzero so a session-mode body cannot be replayed at a RAIDA. | Filled. This is today's wire. |
| HV=2 AUTH_COIN (RAIDA content) | MUST be eight zeros. | Filled. Server compares AN to the coin page. |
| HV=2 AUTH_SESSION (Content Server) | 5-byte handle from SESSION_OPEN, left-aligned, last three bytes zero. MUST equal header LOC A. | Coin type, denomination, serial, AN, reserved MUST be zero. Authenticity numbers MUST NOT appear. |
The handle in this block is a lookup name, the same five bytes as header LOC A under EN 9. Possession of K_sess is the authentication. The handle is not the RKE key_id (that 1-byte vault-family id lives in the SESSION_OPEN context, not here). Layout: Header Version 2 — Sessions.
HV=1 type 9 is a different header, not this field
Transitional Content Server type 9 carries the session handle in the request header (HV=1 offsets). HV=2 keeps that handle in the header and copies it into this identity slot so QMail command payloads stay one shape on RAIDA and CS. Do not treat a nonzero HV=1 session_id as type 9.