Hi everyone,
I’m a developer and researcher looking for a way to make local message history safer.
Currently, even with E2EE, local data usually sits in a database that becomes “unlocked” while the app is open. This makes it vulnerable to specialized forensic tools (like Cellebrite/GrayKey) if a device is seized while the app is “hot.”
The Concept: Blind Indexing (SSE)
Instead of a single “master key” that decrypts everything in RAM, we use Searchable Symmetric Encryption (SSE): How it works: Searchable fields are hashed with hardware-backed “peppers” (Secure Enclave/StrongBox). The Benefit: SQLite can search and retrieve “Alice,” but the database engine never sees the plaintext name. An attacker with a database dump sees only useless random tokens. Performance: We use a “Lease Token” model to ensure hardware-gated encryption doesn’t lag the UI.
Why I’m asking here:
I’d love your feedback:
Is forensic resilience against device seizure a priority for your threat model?
How difficult would it be to interface a “blinded” storage trait into the current Rust core?
I’d appreciate any technical critiques or thoughts on the best way to make this a reality for the ecosystem! Also if you are a developer / researcher interested in collaborating please let me know.
People seem to want to hide the existence of data, resisting suspicion and social coercion, not forensics.
Searchable symmetric encryption - Wikipedia seems like it might be more useful for, say, complying with the GDPR while using a US cloud provider. But maybe I am not understanding, the concept is new to me. So I cannot answer your second question; apologies.
Thank you Ian, looks like there is indeed a need for this. I will start working on it and come up with a framework and a plan so that other people can also contribute .
For some background, we already have password protection using SQLCipher and have deprecated it because of way too many problems with it.
We implemented this as an experiment, but it has limitations:
We store blobs (images, files and other media) in a blob directory rather than inside the database. It is not encrypted even when the database is encrypted.
iOS has special handling for SQLite files, allowing to keep them locked when the process is suspended. Encrypted with SQLCipher databases are not recognized and result in 0xdead10cc error. We have stopped this experiment on iOS because of this: disable creation of new encrypted accounts, fade out existing ones · Issue #2010 · deltachat/deltachat-ios · GitHub
Signal works around this by not encrypting the header of the database, just literally skipping encryption of the first N bytes.
Opening the database is just slow because of key derivation function. This is a problem if you have multiple profiles.
This is all not even considering the UI questions: we just stored the key in the OS “keychain”, not asking the user to ever type the password.
Currently password encryption database feature is marked as “deprecated at unknown future date”. We keep it around for Ubuntu Touch client because Ubuntu Touch does not support disk encryption or filesystem encryption. This is better than nothing even when the blobdir is not encrypted, but for every other operating system (Android, Linux, Windows, macOS, FreeBSD, iOS) we recommend that users use their OS features to encrypt all the application files. As soon as Ubuntu Touch has proper FS encryption, we would really like to deprecate SQLCipher for real and go back to plain SQLite.
In short, I think this is not a feature that apps should implement, but an OS should implement. Otherwise it greatly multiplies the effort: every application will need to integrate with iOS, Android, GNOME/KDE/whatever, macOS, Windows etc. interfaces to access keychains (“secure enclaves”)
The answer is likely “no”. There is much lower hanging fruit, such as encrypting the backups. Users uploading their backups to Google Drive is easier to solve and likely has more impact. As for “forensic resilience”, we have not even thought about it being a problem that we should solve in the app before.
Storage it Delta Chat is basically using rusqlite, an Rust interface to SQLite, with vendored SQLCipher. Next to the database each profile (called “account” in the core for historical reasons) stores blob directory with unencrypted blobs named after the contents BLAKE3 hash for deduplication.
For me this technology also looks like something that is more interesting for protecting the servers which are much easier to access than phones. The phones you can likely protect by locking down the USB or rebooting them like GrapheneOS does, and at the same time it is more likely that user will be forced to unlock the phone regardless of the technical measures.
As for the issues linked by @ian, I would not interpret them as user asking for protection against so-called forensic tools. Most of them are asking for encrypted backups or local “password protection” for the app on a shared device (which is better solved by e.g. private space feature, multiple profiles with filesystem encryption like on Ubuntu etc.).
I could not find anything about “lease token” in relation to “searchable symmetric encryption”, what does this mean?
Thanks so much for the reality check on my last post! The info about the issues with SQLCipher and the iOS 0xdead10ccerror was exactly what I needed to hear. It’s clear that a “lock everything” approach is a headache for stability and performance.
Based on your feedback, and the references on the other posts I’ve refined the idea. Instead of trying to reinvent the whole storage layer, I want to focus on a few specific, modular pieces that solve the biggest risks without breaking the app’s “snappiness” or background features.
1. Let’s start with Encrypted Backups You guys mentioned this is the “low-hanging fruit,” and I totally agree. Right now, if a user moves a backup through Google Drive or iCloud, it’s all out in the open. I’m looking at building a simple AES-256-GCM wrapper for the backup exports. It’s a clear win for privacy and doesn’t mess with the local database at all.
2. “Blinding” sensitive info (instead of full encryption) To deal with the “device seizure” worry without the SQLCipher baggage, what if we only obfuscated the high-risk stuff? For example, using hardware-backed hashes (Secure Enclave/StrongBox) for contact names. The database stays as plain SQLite (so the OS is happy), but the names aren’t readable in a raw dump.
3. Memory “Lease” for keys I’m also looking at a “lease” model—basically, the app gets the decryption key from the phone’s hardware only when it’s active, and we wipe it from RAM after a period of inactivity. It’s a way to protect “hot” data without needing a separate password every five seconds.
My goal is to keep this lightweight. I don’t want to repeat the SQLCipher experiment if it was a nightmare to maintain. I’m going to start by looking into the backup encryption first since that seems to be what users are actually asking for.
Does this feel like a more realistic direction for the core? I’d love to hear if anyone has thoughts on the best way to handle the key derivation for backups (I was thinking Argon2id).
rPGP crate that we use supports streaming encryption and decryption with AEAD modes of the latest standard of OpenPGP. Mandatory to implement AEAD mode is OCB, so encrypted backup format should likely be an OpenPGP binary message with an SKESK packet (with Argon2 which is also supported) followed by SEIPD v2 in OCB mode. We already have a function to export backups into streams, this is used both when exporting into files and when exporting over the network when “Add second device” procedure is used:
Contact names does not sound to me like the most sensitive info, it is going to be leaked in the message contents when contacts refer to each other and quote messages.
I’m also still not sure what is the scenario when the memory is dumped from the device, but the database cannot be accessed. Is it true that Cellebrite UFED and similar devices can sometimes access and dump the memory, but not the filesystem encryption keys?
Maybe protecting the OpenPGP keys so identity key (primary key) and encryption/decryption subkey is not leaked is the most interesting thing. The key can even be moved out of the database, it is currently generated once and never changes. This will at least to allow to protect against impersonation and decryption of future incoming messages.