Encryption Methodology
A technical reference for the encryption protocols and at-rest protections used by Loqa, including their current deployment boundaries.
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.
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.
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.
via Ratchet session
via Ratchet session
via Ratchet session
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.
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.
AES-256-GCM key
with per-file key
to storage
pairwise shared secret
via Ratchet sessions
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.
HMAC-SHA256("loqa-email-enc" ‖ 0x01)HMAC-SHA256("loqa-email-hmac" ‖ 0x01)HMAC-SHA256("loqa-file:{id}")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.