This document explains how KENI encrypts your data, where the keys live, what our server can and cannot see, and the deliberate trade-offs we made. We wrote it for people who actually read whitepapers — concise, no marketing.
1. Threat model
We assume the network is hostile and our infrastructure is assumed-breached. The goal is: even an attacker with full read access to our database, plus traffic capture between client and server, cannot read your 1:1 message text. (Group messages and the media you send in 1:1 are server-readable by design — see §5.)
We do not defend against malware on your own device, a compromised peer (your friend's phone), or a lawful subpoena against our compliance archive (see §5). If your threat model requires defending against state-level actors with subpoena power, Signal is the right answer — KENI made a different choice and we'll explain it honestly.
2. Key generation
On first install the client generates two key pairs on-device:
- Identity key: X25519, used for long-term peer identification. Public half uploaded to the server; private half lives device-locally in iOS Keychain (kSecAttrAccessibleAfterFirstUnlock, iCloud sync disabled) or Android EncryptedSharedPreferences (allowBackup excluded). It is never replicated to iCloud or Google cloud backup.
- Prekey: X25519, rotated. Used for asynchronous session setup so a peer who's offline can still receive your first message.
Private keys are never transmitted to our servers. The optional passphrase backup (§4) is the only way private keys leave the device, and that copy is encrypted with a key derived from a passphrase we never see.
3. Per-room session
When two users start a 1-on-1 chat:
- Client A fetches B's identity public key from server.
- Both clients run X25519 ECDH locally to derive a 32-byte shared secret.
- The shared secret seeds the initial ratchet root key. Each message is sealed with AES-256-GCM under a fresh 12-byte nonce; ciphertext, nonce and ratchet header are transmitted.
- Group chats default to server-side encryption with a compliance copy (see §5). An end-to-end group mode using the Sender Keys protocol (a rotating per-sender key distributed over each member's pairwise session) is available to every group; a new group starts server-readable and its owner switches the mode on.
1:1 sessions run a simplified Signal Double Ratchet. A fresh ephemeral X25519 key is generated at every DH ratchet step, and each message carries a ratchet header next to its ciphertext. That gives forward secrecy — message keys from before a ratchet step cannot be re-derived — and break-in recovery: once a peer's new ratchet public key arrives, future message keys are independent of any key leaked earlier.
The boundary, stated plainly. This is a simplified ratchet, not a line-for-line Signal implementation. And messages sent before the ratchet shipped carry no ratchet header — they are still decrypted over the original static-X25519-ECDH path, so forward secrecy does not apply retroactively to that history.
Several devices on one account are handled per-device, not per-account. Each device publishes its own key and is delivered its own copy of a message. The distribution query returns approved devices only, so a device that has not been approved is handed nothing it could decrypt — the gate fails closed, not open. Your first device approves itself; every device after it starts pending and must be approved from one you have already approved. The safety number you compare with a contact covers their whole approved device set, so a device appearing on their account shows up as a change in that number rather than as a silent addition.
4. Identity backup (zero knowledge)
Losing your phone shouldn't lose your message history. Users can opt into a passphrase-backed key escrow:
- User types a passphrase (≥ 8 chars), entered only on-device.
- Client generates a random 16-byte salt.
- Client runs PBKDF2-SHA256, 600,000 iterations, salt + passphrase → 256-bit KEK. Backups written before this count was raised record their own iteration value and are read back at it.
- Client encrypts { identity_priv, identity_pub, prekey_priv, prekey_pub } as JSON with AES-256-GCM under KEK, fresh nonce.
- Client uploads { version, salt, ciphertext } to server.
Server stores opaque ciphertext. Without the passphrase we can't derive the KEK; without the KEK we can't decrypt. Lost passphrase = permanently lost backup. We will not "reset" your identity for you because we can't.
5. Compliance archive (be aware)
1:1 message text is end-to-end encrypted only — no compliance copy, nothing we can decrypt, not even us. Group messages keep a compliance copy encrypted with KENI's platform public key (group chats are server-readable by design; an end-to-end group mode is available and is switched on per group by its owner). The group compliance copy exists for two reasons:
- Lawful disclosure orders. Without it, we cannot comply with a subpoena even if legally required. Some apps choose not to comply by design — that's a defensible position; we made a different one.
- CSAM detection. Images are hashed with Microsoft PhotoDNA against the known-CSAM corpus before delivery (see /safety). This requires the server to see image bytes briefly.
The platform private key is held in HSM-grade storage. Access is gated on multi-party authorization with logged justification. We do not mine the archive for product analytics, advertising, or training data. If this trade-off doesn't fit your threat model, please use Signal — we won't be offended.
6. AI features (what leaves your device)
AI features (the KENI assistant, intent routing, summarization) are not E2EE. The cloud LLM has to read your prompt to answer. What we do:
- PII auto-scrub before egress: regex-based replacement of phone numbers, emails, credit cards, national IDs, IPs with placeholders; restored in the LLM response.
- One-time consent dialog the first time you open any AI surface. Revocable in Settings → Privacy, which disables all AI features.
- Optional local mode: download a small GGUF model (Qwen2.5 or Llama 3.2, from ~280MB) to run it on-device; switch STT to Whisper for fully offline transcription. Neither path sends audio or prompts to anyone.
7. TURN / WebRTC media
Voice/video uses WebRTC. Signaling goes through our WS gateway (the SDPs themselves are not message content). Media flows peer-to-peer when NAT allows; behind symmetric NAT we relay through our own coturn server (turn.hikeni.com). The relay sees encrypted SRTP packets — it cannot decrypt media. Each session uses HMAC-SHA1 short-term TURN credentials (24h TTL) signed by the gateway with a server-only secret; users never see permanent TURN passwords.
8. What we deliberately did NOT do
- No analytics SDKs that profile users (no Mixpanel, no Amplitude). Crash reporting via Firebase Crashlytics only, scoped to stack traces.
- No third-party ad SDKs. No IDFA / GAID collection.
- No contact list upload. Contact discovery hashes phone numbers client-side (SHA-256 over E.164) and uploads only the hash list; we never see your raw contacts.
- No background location. Live-location is an explicit per-room opt-in with auto-expiry.
9. Open issues & roadmap
- Regaining multi-device access when no approved device is left. Approval has to come from a device you already approved (§3), so if the only one is lost or wiped there is nothing left to approve from, and recovery falls back to the passphrase-encrypted identity backup (§4). Identity keys are deliberately not auto-synced through iCloud Keychain — that choice is what makes this the recovery path, and it is the trade-off we owe you the clearest warning about.
- NCMEC ESP registration pending; until live, CSAM matches are
queued in
ncmec_reportswith status=pending_retry. - Compliance-archive third-party audit. We're a small team
and haven't done one yet. The code (
backend/handlers/ecdh.go,handlers/moderation.go) is the source of truth in the meantime.
10. Contact
Found a bug in our crypto? Want to argue with a trade-off above? Email safety@hikeni.com. We read every report and reply within 5 working days.