Current deployment scope. Loqa rolls encryption out by conversation and content type. Treat the in-product encryption status as authoritative for eligible content. Some attachments, calls, server channels, bots, integrations, and feature-generated content remain server-processed. The protocol descriptions below explain protections used on covered paths; they are not a claim that every Loqa feature is end-to-end encrypted.

01Encryption at a Glance

The table summarizes the protocols available to covered paths. Actual coverage depends on the conversation, content type, client version, and the encryption status shown in the app.

Surface Protocol Cipher Forward Secrecy Post-Compromise Security
E2EE-marked 1 : 1 content X3DH + Double Ratchet AES-256-GCM Protocol-dependent Protocol-dependent
E2EE-marked group content Per-msg key + Ratchet wrap AES-256-GCM Protocol-dependent Protocol-dependent
E2EE server channels (experimental) MLS (RFC 9420) AES-256-GCM Protocol target Protocol target
Eligible encrypted attachments Per-file key wrapping AES-256-GCM Path-dependent Path-dependent
PII (Emails) Server-side envelope AES-256-GCM + HMAC N/A N/A
Passwords Argon2id (PHC winner) N/A N/A
Stored Files Server-managed encryption AES-256-GCM + HKDF N/A N/A

02Direct Message Encryption

Eligible 1:1 DM content uses a Signal-style protocol with two phases: X3DH for initial key agreement and the Double Ratchet for ongoing encryption. Feature-specific content can follow a different path, so the app's encryption status remains the coverage authority.

X3DH Key Agreement

When Alice first messages Bob, the Extended Triple Diffie-Hellman (X3DH) protocol establishes a shared secret without requiring Bob to be online.

Alice (Initiator)
Identity Key (IKA)
Ephemeral Key (EKA)
DH1 IKA ↔ SPKB
DH2 EKA ↔ IKB
DH3 EKA ↔ SPKB
DH4 EKA ↔ OPKB
Shared Secret = HKDF(DH1 ‖ DH2 ‖ DH3 ‖ DH4)
Bob (Responder)
Identity Key (IKB)
Signed PreKey (SPKB)
One-Time PreKey (OPKB)

Curve

X25519 (Curve25519) with automatic P-256 ECDH fallback for browsers that don't yet support X25519 in WebCrypto.

KDF

HKDF-SHA256 with the info label loqa-x3dh. The raw DH outputs are concatenated and passed through HKDF to derive the initial root key.

Signed PreKey

Bob's signed prekey is authenticated by signing the raw public key bytes with his identity key, preventing key substitution attacks.

One-Time PreKeys

Uploaded in batches of 100, replenished when fewer than 30 remain. Each is consumed once to provide an additional layer of key separation.

Double Ratchet Protocol

After X3DH establishes the shared secret, covered message content uses the Double Ratchet — a combination of a symmetric chain ratchet and a DH ratchet designed to provide forward secrecy and post-compromise security.

Root Key (RK)
↓ DH Ratchet (on reply)
Send Chain Key (CKs)
↓ HMAC-SHA256
Message Key (MK1)
Message Key (MK2)
↓ ...
Recv Chain Key (CKr)
↓ HMAC-SHA256
Message Key (MK1)
Message Key (MK2)
↓ ...

Chain KDF

Each chain key is advanced using HMAC-SHA256 with two constant inputs: 0x01 produces the message key, 0x02 produces the next chain key. Message keys are used once and discarded.

DH Ratchet

When a reply is sent, a new DH key pair is generated. The new DH output is combined with the root key via HKDF to derive a fresh root key and chain key — providing post-compromise security.

Out-of-Order Messages

Up to 256 skipped message keys are cached per session, enabling decryption of out-of-order messages without breaking the ratchet state.

Multi-Device

Each device maintains its own ratchet session. Messages are encrypted for all of the recipient's devices, with per-device ciphertext carried in the message header.

03Group DM Encryption

Covered group-DM content uses a per-message random key architecture. Each covered message gets a fresh AES-256-GCM key, which is then wrapped individually for each participant using their ratchet session.

1
Generate random per-message AES-256 key
2
Encrypt plaintext → ciphertext + nonce
3
Wrap key for Recipient A
via Ratchet session
Wrap key for Recipient B
via Ratchet session
Wrap key for Recipient C
via Ratchet session
4
Send: ciphertext + nonce + { A: wrappedKey, B: wrappedKey, C: wrappedKey }

Ratchet-Wrapped Keys

Each recipient's copy of the message key is encrypted using their active Double Ratchet session — inheriting the same forward secrecy and post-compromise security as 1:1 DMs. The wrapped key format is a JSON object containing the ratchet header, ciphertext, and nonce.

Legacy Fallback

If no ratchet session can be established for a recipient (e.g., they haven't uploaded prekeys), the key is wrapped using static ECDH with ciphertext:nonce format. This path will be phased out as all clients upgrade.

04Server Channel Encryption (MLS)

For experimental server channels that opt into E2EE, Loqa includes a Messaging Layer Security (MLS) implementation based on RFC 9420 via an OpenMLS WASM module. The production membership, recovery, and multi-device lifecycle is still being hardened; do not treat ordinary server channels as E2EE.

Ratchet Tree (Binary)
Group Secret
Interior
Interior
Member A
Member B
Member C
Member D
Each member holds only their leaf private key. Interior secrets are derived from child DH outputs. Adding or removing a member updates only the path from the affected leaf to the root — O(log n) cost.

Server Role

For a correctly covered MLS payload, the Loqa server acts as a Delivery Service that stores opaque encrypted bytes and fans them out to group members. This statement does not apply to non-E2EE channels or content that bypasses the covered path.

KeyPackages

Each client pre-uploads KeyPackages (minimum 10, replenished in batches of 20) so other members can add them to groups asynchronously.

Epochs

The MLS design advances the group epoch on membership changes and discards prior epoch keys. Production lifecycle enforcement remains experimental while membership and recovery hardening continues.

Commits

Membership changes are applied via MLS Commit messages, which atomically update the ratchet tree and derive new application secrets.

Federation

The experimental federation path includes signed endpoints for relaying MLS KeyPackages, Commits, and Welcomes between instances. Cross-instance lifecycle behavior must be validated before a federated channel is represented as production E2EE. See the Federation Whitepaper §7 for protocol details.

05File Encryption

On attachment paths explicitly covered by E2EE, the client encrypts file bytes before upload and wraps the file key for recipients. Other attachment paths use server-managed encryption at rest and are accessible to the service for delivery, moderation, or feature processing.

Generate random per-file
AES-256-GCM key
Encrypt file bytes
with per-file key
Upload ciphertext
to storage
Key wrapping varies by channel type:
1:1 DM
Wrap file key with
pairwise shared secret
Group DM
Wrap file key per-recipient
via Ratchet sessions
MLS Channel
MLS-encrypt file key + nonce
as a group message

Key Wrapping (DM)

The per-file key is exported to raw bytes, then encrypted with the pairwise AES-256-GCM shared secret using a fresh 12-byte nonce. The wrapped key and wrap nonce are sent as metadata alongside the message.

Server-Managed File Encryption

For non-E2EE server channels, the backend encrypts files at rest using AES-256-GCM with per-file keys derived from the server master key via HMAC-SHA256 (loqa-file:{fileId}). Files are stored as nonce (12 bytes) ‖ ciphertext.

06PII & At-Rest Protection

Loqa applies field-level encryption to selected sensitive database fields, including account email fields. Other personal data needed to operate the service can be stored in readable form under access controls. Domain-separated sub-keys isolate supported encryption uses.

Master PII Key (32 bytes)
HMAC-SHA256("loqa-email-enc" ‖ 0x01)
Email Encryption Key
AES-256-GCM encrypt/decrypt
HMAC-SHA256("loqa-email-hmac" ‖ 0x01)
Email Blind Index Key
HMAC-SHA256 deterministic lookup
HMAC-SHA256("loqa-file:{id}")
Per-File Encryption Key
AES-256-GCM for stored files

Email Encryption

The primary account table encrypts email addresses with AES-256-GCM using a derived sub-key and a random 12-byte nonce; the ciphertext and nonce are stored base64-encoded. Verification, delivery, and retry infrastructure necessarily processes the address, so this database-at-rest protection is not a claim that plaintext never exists anywhere in the service path.

Blind Index Lookup

Emails are normalized (lowercase + trim), then hashed with HMAC-SHA256 using an isolated sub-key. This deterministic blind index enables login and deduplication queries without revealing the actual address.

Password Hashing

Argon2id — the Password Hashing Competition winner — protects all user passwords and OAuth2 client secrets. Each hash uses a unique random salt via OsRng. API tokens and webhook secrets use SHA-256 with constant-time verification.

Key Isolation

The master key is never used directly. All operations use domain-separated sub-keys derived via HMAC-SHA256 (equivalent to HKDF-Expand). Compromising one key domain does not affect the others.

07Key Storage & Lifecycle

Protocol private keys are generated and used on-device via the Web Crypto API and IndexedDB. Public key material is uploaded for key agreement, and Loqa may store client-encrypted recovery material. Recovery and multi-device flows remain subject to the deployment scope above.

🔑

Identity Key Pair

Non-extractable X25519 key pair stored in IndexedDB (loqa_e2ee/keypairs). Generated once on first login; public key uploaded to the server.

🔄

Ratchet Sessions

Per-(peer, device) session state stored in loqa_e2ee/ratchet_sessions. Contains root key, chain keys, ratchet key JWK, and up to 256 skipped message keys.

✍️

Signed PreKeys

Stored in loqa_e2ee/signed_prekeys. Public key is signed by the identity key and uploaded to the server. Private JWK stays local for X3DH responder operations.

🎟️

One-Time PreKeys

Batched in loqa_e2ee/otp_prekeys (100 at a time, replenished at 30). Each public key is uploaded; private JWK stays local and is consumed on first use.

🌲

MLS Group State

Persisted in a separate loqa-mls IndexedDB. Tracks group epoch and identity initialization state. WASM manages in-memory tree state.

📱

Device Identity

Each device generates a unique ID stored in loqa_e2ee/device_info. This allows per-device ratchet sessions and multi-device message delivery.

08Reproducible Audit Scope

🔬

For security researchers: Cryptographic primitives, key storage, content routing, recovery, native media, and server-side handling all influence the effective boundary. Review the current repository and release configuration together; an isolated primitive does not prove end-to-end coverage for a feature.

Report security findings through the security contact.

Questions About Our Encryption?

We welcome review from security researchers, cryptographers, and enterprise security teams. We're happy to provide additional technical detail or discuss integration requirements.