Concept
Messages and envelopes
A HexaEight message is an opaque text blob that one identity sends to another. The SDK calls this blob an envelope. This page describes what an envelope contains, what travels in cleartext at the wire level, and what fields are available inside the encrypted payload.
What an envelope is
From the application's perspective, an envelope is a string that the SDK produces from a plaintext body and that another SDK can turn back into that body. Applications do not need to inspect the envelope; they pass it to whatever transport delivers it to the recipient (HTTP, message queue, file, ntfy).
// Producing an envelope
string envelope = await client.EncryptEnvelopeAsync(
recipient: "[email protected]",
body: "hello alice");
// Decoding an envelope
var msg = await client.DecryptEnvelopeAsync(envelope);
Console.WriteLine($"From {msg.Sender}: {msg.Body}"); What travels in cleartext, what is encrypted
An envelope has two parts:
- A short cleartext header at the start, containing the sender's opaque cryptographic identifier and a time-window number (called a KGT — a 15-minute window used for key derivation). The recipient needs both to know which decryption key to fetch.
- The encrypted payload, which contains the actual message body and any optional fields the sender added.
The cleartext header tells the receiving SDK which key to ask the platform for. It does not reveal the sender's email address or hostname directly — the identifier is opaque. It does not reveal the body in any form.
The encrypted payload
Inside the encrypted payload, the SDK places a JSON object with the following fields:
| Field | Always present? | Set by | Purpose |
|---|---|---|---|
Sender | Yes | The platform, at encryption time | The cryptographically verified sender name. The receiver trusts this. |
Body | Yes | The application | The actual message content. |
SessionId | If a session is used | The application | Identifies an ongoing conversation. See sessioned envelopes. |
FinalRecipient | Optional | The application | Used in relay scenarios. The sender is asking the recipient to forward to this final party. |
OriginalSender | Set by relay agents | The relay agent | "This message came from this original party, forwarded by me." |
ProtectionHash | Auto-populated | The SDK | A hash of the sending application's binary. Used by app-level authorization rules. |
Two envelope variants
HexaEight envelopes come in two variants:
- Standard envelopes — used when sender and receiver have not established a session. The wire header includes the sender's identifier and a KGT. Each side fetches their key from the platform on receipt.
- Sessioned envelopes — used when two parties have agreed on a session ID out of band. The wire header is a session hash; both sides pin the shared key locally up front and subsequent envelopes in that session skip the per-message key fetch. Sessioned envelopes are smaller and faster for ongoing conversations.
See How-to: Use sessioned envelopes for the practical steps.
What the SDK does on every encrypt and decrypt
- Encrypt: the SDK fetches the appropriate shared key from the platform (or reuses a cached one), serialises the body and any optional fields into a JSON payload, encrypts the payload, and produces the wire envelope.
- Decrypt: the SDK parses the wire header, fetches the
receiving key for that sender (or reuses a cached one), decrypts the
payload, extracts the
SenderandBodyfields, runs authorisation if enabled, and returns the result.
All of this is transparent to your code — you call
EncryptEnvelopeAsync and get back a string, or call
DecryptEnvelopeAsync and get back a DecryptedEnvelope
object.
See also
- Identity model Concept
- The authorization model Concept
- Encrypt a message How-to
- Decrypt a message How-to
- Wire format specification Reference