<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Searchable-Encryption on MongrelDB</title><link>https://www.mongreldb.com/articles/tags/searchable-encryption/</link><description>Recent content in Searchable-Encryption on MongrelDB</description><image><title>MongrelDB</title><url>https://www.mongreldb.com/assets/og-mongreldb.png</url><link>https://www.mongreldb.com/assets/og-mongreldb.png</link></image><generator>Hugo</generator><language>en-US</language><lastBuildDate>Sun, 02 Aug 2026 12:00:00 -0500</lastBuildDate><atom:link href="https://www.mongreldb.com/articles/tags/searchable-encryption/index.xml" rel="self" type="application/rss+xml"/><item><title>Encryption at Rest Without Paying the SQLite SEE Tax</title><link>https://www.mongreldb.com/articles/2026/07/encryption-at-rest-without-paying-the-sqlite-see-tax/</link><pubDate>Mon, 13 Jul 2026 09:00:00 -0500</pubDate><guid>https://www.mongreldb.com/articles/2026/07/encryption-at-rest-without-paying-the-sqlite-see-tax/</guid><description>SQLite SEE is the official paid reference for SQLite encryption. Here is MongrelDB&amp;#39;s open-source AES-GCM design, key hierarchy, WAL coverage, and search tradeoff.</description><content:encoded><![CDATA[<p>Encryption at rest is easy to describe badly, because saying &ldquo;the database is encrypted&rdquo; takes six words while proving which files are covered, where keys come from, what happens during rotation, and what metadata remains visible takes several pages; SQLite SEE is the official paid answer for teams that need to preserve SQLite&rsquo;s file format and API surface, while MongrelDB had a different constraint, which was to keep encryption inside an open-source engine whose WAL, sorted runs, result cache, searchable columns, and external key-management path all needed one documented trust model.</p>
<p>If SQLite compatibility is non-negotiable, MongrelDB is not an SEE replacement. It does not open SQLite files and it does not implement SQLite&rsquo;s API. The <a href="https://www.mongreldb.com/sqlite-see-alternative/">SQLite SEE alternatives guide</a> starts with that dividing line, because comparing ciphers before comparing compatibility is how migration projects get approved for the wrong reason.</p>
<h2 id="the-bytes-that-actually-get-encrypted">The bytes that actually get encrypted</h2>
<p>MongrelDB stores immutable sorted runs in its own <code>.sr</code> format. Page payloads in encrypted runs use AES-256-GCM, so confidentiality and authentication travel together; changing ciphertext or its authentication tag causes open or read to fail rather than producing plausible corrupted plaintext.</p>
<p>Encrypted tables also protect WAL frames with AES-256-GCM, because leaving the newest writes in a plaintext log would make page encryption mostly theatre. Persistent result-cache entries are encrypted as well. Structural run headers, schema, manifest data, and index files are not blanket-encrypted, so the storage directory still reveals some metadata; the documentation names that boundary rather than claiming the directory is an opaque blob.</p>
<p>Per-column page statistics need special handling. Cleartext min and max values would leak useful information even if every row payload were encrypted, so encrypted-column statistics travel in an authenticated per-run envelope and are decrypted when the run opens, preserving page pruning without publishing those bounds in the cleartext directory.</p>
<h2 id="the-key-hierarchy">The key hierarchy</h2>
<p>A human passphrase first goes through Argon2id with a random salt, then HKDF derives the database key-encryption material. Every sorted run receives its own random 256-bit data-encryption key, and that DEK is wrapped by the database key rather than stored as usable plaintext. Columns marked as searchable derive separate per-column keys, while WAL, cache, checkpoint, and metadata domains use separate derivation contexts.</p>
<p>Applications that already have high-entropy key material can skip the human-passphrase work factor and open with a raw key derived through HKDF. Production operators can also use HashiCorp Vault Transit: MongrelDB generates a random database root key, asks Vault to wrap it, and stores only provider identity plus Vault ciphertext in the database metadata.</p>
<p>KMS rotation rewraps the stable database root key rather than rewriting every page. The rotation has a durable journal and can resume after a crash, which sounds like implementation trivia until the first maintenance window is interrupted halfway through; key management is mostly failure recovery wearing a cryptography badge.</p>
<p>All in-memory key values use zeroizing wrappers. If a required passphrase, raw key, or KMS is unavailable, open fails closed. If the only copy of the passphrase or root key is lost, the data is lost too, because a recovery back door would also be a decryption back door.</p>
<h2 id="searchable-encryption-is-a-separate-trade">Searchable encryption is a separate trade</h2>
<p>Ordinary page encryption lets a trusted process decrypt pages and evaluate general SQL. It does not make an index searchable by an untrusted operator without revealing anything. MongrelDB&rsquo;s <code>ENCRYPTED_INDEXABLE</code> flag adds derived query material for the narrower case where selected equality or range filters must avoid a full decrypt-first scan.</p>
<p>Equality tokens use a keyed HMAC construction, so the same plaintext in one column produces the same index token. That enables exact lookup, but repeated values remain repeated tokens and frequency remains visible. Range tokens preserve enough order to resolve a bounded interval, which means order leaks by design. The <a href="https://www.mongreldb.com/searchable-encrypted-database/">searchable encrypted database guide</a> covers that leakage directly; there is no honest version of searchable range encryption where the index learns nothing about order.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-rust" data-lang="rust"><span style="display:flex;"><span>ColumnDef {
</span></span><span style="display:flex;"><span>    id: <span style="color:#ae81ff">2</span>,
</span></span><span style="display:flex;"><span>    name: <span style="color:#e6db74">&#34;account_id&#34;</span>.into(),
</span></span><span style="display:flex;"><span>    ty: <span style="color:#a6e22e">TypeId</span>::Bytes,
</span></span><span style="display:flex;"><span>    flags: <span style="color:#a6e22e">ColumnFlags</span>::empty()
</span></span><span style="display:flex;"><span>        .with(ColumnFlags::<span style="color:#66d9ef">ENCRYPTED_INDEXABLE</span>),
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The page stores the encrypted value and the index stores its derived token. Use that flag only for columns with a real indexed-query requirement, because ordinary encrypted columns reveal less.</p>
<h2 id="what-it-costs">What it costs</h2>
<p>The current documentation deliberately does not publish one universal encryption-overhead percentage. AES acceleration, page size, cache warmth, transaction size, storage device, fsync policy, and query shape all change the result, and a number measured on one workstation becomes marketing fiction as soon as it loses those qualifiers.</p>
<p>The repository includes a page-encryption benchmark command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>cargo bench -p mongreldb-core --bench page_encryption
</span></span></code></pre></div><p>Run it on deployment-class hardware, then repeat the application&rsquo;s real write and scan workload with encryption enabled. Small synchronous transactions usually expose fixed crypto and durability costs more clearly than large sequential batches, while warm reads can hide much of the page-decryption path behind cache reuse.</p>
<h2 id="the-comparison-that-actually-matters">The comparison that actually matters</h2>
<p>SEE is the conservative choice when the product is already SQLite and official compatibility is worth the license. SQLCipher and other maintained SQLite codecs belong on the shortlist when open-source availability and SQLite compatibility both matter. MongrelDB belongs on a different shortlist, for applications willing to change engines because they also need columnar scans, DataFusion SQL, vector and sparse retrieval, searchable equality or range columns, or one WAL covering operational and analytical data.</p>
<p>The cipher name does not decide that architecture. File compatibility, key operations, failure recovery, metadata leakage, backups, and the queries the application must still answer decide it, the same way they did when encrypted storage meant an encrypted filesystem and a handwritten key file, only now there are more layers available to get subtly wrong.</p>
]]></content:encoded></item></channel></rss>