Storage and key releaseTechnical referenceBrowse
Reference

Local storage

Durable conversation and operational stores are encrypted. Temporary media and in-memory plaintext require separate lifecycle controls. The interesting question is under which key, released by what, because a phone must keep receiving messages and ringing while its owner's history stays sealed.

Released beta
On this page

Two key domains

Two independent key domains

Operational key

Device-only Keychain. Available after the first device unlock.

Operational store

Identity and ratchet state, contacts, routing capabilities, push state and ciphertext queues.

Supports background delivery and incoming calls.

History key

A separate random key, released by the selected history-protection factors.

Protected history

Transcripts, attachment keys, contact notes and call-log attribution.

Passphrase modes wrap this key in an Argon2id-derived envelope.

History protection covers its own data domain. Locking it does not also revoke every operational key. Device unlock, biometrics and passphrase modes have different release policies, described below.

The operational store (identity and ratchet state, contacts, capabilities, delivery and call-recovery state, push tokens) is AES-256-GCM sealed under a key in the device-only Keychain that becomes available once the phone has been unlocked since boot. It is excluded from backups and never synced. It stays available in the background so that encrypted delivery and calls keep working, and so a locked phone can name the contact who is ringing.

The protected history, including transcripts, attachment keys, contact notes, and the who of the call log, is sealed under a separate random 256-bit key whose release policy the user chooses. Per-chat filenames are derived with a salted HMAC, so even the list of files names no contact. Any history-bearing plaintext that must sit next to ratchet state for crash safety gets a second envelope under the history key, so the operational file is never a bypass.

The four history modes

ModeKey release policyPasscode alone?Lockout
Device unlockKeychain, when unlocked, this device onlyYesNormal iOS recovery semantics
Face ID onlyKeychain, when passcode set, this device only + current biometric setNo fallbackChanging enrolment invalidates access
Auris passphraseArgon2id/AES-GCM envelope behind an application-password Keychain policyNoA forgotten passphrase is unrecoverable
Face ID + passphraseThe envelope plus current biometricsNoEither factor missing is unrecoverable

A mode change re-wraps the one history key; it does not re-encrypt every chat, and the target item is authenticated and read back before the old item is retired. There is deliberately no account recovery, cloud escrow, recovery question, plaintext fallback, or replacement-key path once protected files exist. The one recovery action, "Erase inaccessible history", is destructive and confirmed explicitly. Passphrase modes exist for a lost, stolen or forensically examined phone whose passcode an attacker knows or can guess.

The passphrase envelope

Passphrase modes derive a 32-byte wrapping key with Argon2id v1.3 from the canonically normalised passphrase and a fresh 16-byte salt (64 MiB of memory, three passes, one lane) and AES-256-GCM-seal the random history key under it. Domain, policy mode, format, algorithm, parameters and salt are all authenticated, and the envelope is exactly 95 bytes: the parser accepts only that exact shape and parameter set before invoking Argon2, so an edited resource field cannot request attacker-chosen memory. The parameter profile is not RFC 9106's byte-identical second recommended profile (which uses four lanes); it is the one-lane variant the app has always used, recorded in the envelope and release-tested.

The Argon2 implementation is the tagged upstream reference source, compiled in-tree and byte-identical to the release archive, with the official known-answer vector included in the hosted test suite. This is a test capability, not evidence that every archive reran it. One implementation detail worth stating because it was once misdocumented: on Apple platforms the reference code's internal secure-wipe takes its volatile-function-pointer memset path inside an optimisation-disabled function, not memset_s; the Swift-owned password and key buffers are wiped with memset_s directly.

Attachments on the device

Durable attachments are AES-256-GCM sealed under each attachment's own random key, which lives inside protected history; the ciphertext is padded to the same authenticated size buckets as uploads, so an examiner learns a bucket class and file timing, not exact content length. Playback and image decoding receive a short-lived plaintext materialisation under complete file protection and backup exclusion, whose filename binds the blob id and a hash of the key, so reusing an id under a different key is intended not to reuse an older plaintext materialisation. Every asynchronous plaintext-producing task carries an owner-and-generation token: a hardened lock invalidates the generation, waits for active file work, purges the exact materialisation root, and refuses stale tasks even after a later unlock. A force-kill can defer the scrub until next launch, which removes the residue before any encrypted state opens.

A peer-controlled attachment announcement passes one parser before anything reaches persisted state or a filesystem path: kind is photo or voice, blob ids are bounded hex, keys are exactly 32 bytes, numeric metadata is finite and bounded. A persisted path is a hint only. Each read resolves a canonical location from the validated descriptor, and symlinks at either the attachment root or a target are refused.

Locking

A hardened lock (the app-lock timer, backgrounding in a protected mode, protected data becoming unavailable) advances an in-memory key epoch and invalidates the store-load generation, so decrypt or key-derivation work admitted before the lock cannot later re-cache the key or install a decrypted snapshot. In-memory transcripts, drafts, the decoded photo cache and materialised media are purged; playback and recording stop; full-screen media dismisses; preview-bearing notifications are removed. Messages that arrive while history is locked do not advance the live ratchet and are not acknowledged to the server; the ciphertext is redelivered after unlock.

What deletion does

Deleting one message, clearing one chat, deleting a contact with its chat, or clearing all history each proves an authenticated current-store mutation before reporting success, and retires unreferenced media afterwards; a failed physical delete is retried after the next save, and launch reconciliation removes orphans. This is logical deletion from the active store: not a promise about wear-levelled flash or filesystem snapshots underneath, and not remote unsend. Ordinary chat clearing retains the shared history key for the chats that remain. Uninstalling the app removes its container, but iOS may retain Keychain items across reinstall; the app's own reset is the documented erasure path.

What a seized device yields

  • Before first unlock: the configured operational key class and file protection are intended to deny normal access. This is an operating-system protection boundary, not a claim that every forensic technique yields no information.
  • After first unlock, then locked: operational state is intentionally available to the app for background work. If an attacker can extract and open it, the exposed identity and session state can enable impersonation and traffic decryption within the compromised state’s scope. History remains governed by its separate key-release mode; protection depends on the factors, OS state and extraction capability. Device-unlock mode can also permit caller names in iOS Recents; hardened history modes stop new entries there.
  • Unlocked and in the attacker's hands: whatever the current factors release. No app survives a live, controlled endpoint, and Auris does not claim to.

Retiring the after-first-unlock residual (generic-only notifications, unattributed rings, no sends while locked) is a designed opt-in full-lockdown mode, not the default, because those costs are unusable as defaults. Swift cannot promise deterministic erasure of every secret copy in memory; a live memory compromise remains outside the claims.

The plain-language version is protecting your history in the guide.

Reviewed · Review scope and versions