Skip to content

feat(sqlcipher): decrypt SQLCipher pages into the reader's stream - #10

Merged
h4x0r merged 8 commits into
mainfrom
feat/sqlcipher-decryption
Aug 9, 2026
Merged

feat(sqlcipher): decrypt SQLCipher pages into the reader's stream#10
h4x0r merged 8 commits into
mainfrom
feat/sqlcipher-decryption

Conversation

@h4x0r

@h4x0r h4x0r commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Lands SQLCipher decryption, which has been sitting on an un-PR'd branch since
before the fleet CI migration. Rediscovered by a fleet-wide branch sweep: of 23
branches carrying commits main did not have, this is the only one whose
content was neither already landed nor superseded.

What it adds

  • core/src/sqlcipher.rs — decrypts SQLCipher pages into the reader's stream
  • core/tests/sqlcipher_oracle.rs — Tier-2 oracle test
  • docs/decisions/0010-sqlcipher-decryption.md — the rationale
  • Three fixtures (v3-compat, v4, raw-key) with provenance in tests/data/README.md
  • .gitattributes marking the fixture trees -text (see below)

Evidence

Merged current main into the branch first — zero conflicts — and ran the
suite against the merge result, not the branch in isolation:

cargo test --workspace --all-features --no-fail-fast
550 passed, 0 failed, 0 ignored, across 71 test targets, exit 0

Local run on the pinned toolchain (cargo 1.96.0, matching rust-toolchain.toml).
CI is the independent check.

On the .gitattributes commit

Prophylactic, and labelled as such rather than sold as a repair. The three
fixtures each carry a NUL at byte 100 / 135 / 1044 — inside git's 8000-byte
sniff window — so git already classifies them binary and nothing here is
corrupted today
. The gap is for the next fixture: git sniffs only the first
8000 bytes, so a compressed payload whose first NUL falls past that window is
classified as text and has its LF bytes rewritten on a Windows checkout,
where core.autocrlf defaults to true on GitHub runners.

Release

No version edit in this PR. feat: lets release-plz compute the bump and open
its own release PR on merge.

h4x0r and others added 6 commits July 28, 2026 23:52
Failing tests (API not yet implemented) that decrypt three real
SQLCipher-4.17-CLI-minted fixtures (v4 defaults, v3 compatibility, and
a raw 32-byte key) and read back the known rows through the native
reader. The engine-authored ciphertext is the independent oracle: our
RustCrypto decryptor must reproduce the plaintext OpenSSL produced.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ream

Add `sqlite_core::sqlcipher` and `Database::open_encrypted(bytes, key)`:
given a key, decrypt a SQLCipher database (PBKDF2 key derivation →
AES-256-CBC per-page decrypt → per-page HMAC authentication) into a
plaintext SQLite byte stream the existing reader consumes unchanged.

- RustCrypto only (pbkdf2/hmac/sha1/sha2/aes/cbc/cipher), never
  hand-rolled; all low-MSRV so sqlite-core stays on rust-version 1.80.
- Two typed key shapes (Passphrase / RawKey) — a raw key can never be
  silently PBKDF2-stretched as a passphrase (secure-by-design).
- Version auto-detected by page-1 HMAC verification across the shipped
  SQLCipher v4 (default) and v3-compatibility profiles.
- Fail loud: a wrong key/params is DecryptError::KeyOrParametersMismatch;
  a later page failing auth is PageAuthFailed(pgno). Panic-free on
  crafted/truncated input; no path emits plausible-but-wrong plaintext.

Tier-2 validated by core/tests/sqlcipher_oracle.rs against three real
SQLCipher-4.17-CLI fixtures (v4, v3-compat, raw key); the RustCrypto
decryptor reproduces the engine's plaintext, read back to known rows.
Provenance in tests/data/README.md; rationale in ADR 0010.

Gates: cargo test --workspace (548) + clippy -D warnings + fmt --check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lockFileMaintenance was enabled but not automerging, so refreshes opened PRs that
then aged - producing exactly the lock lag the setting exists to prevent. Lock lag
is the staleness that actually recurs in this fleet: a caret requirement that can
reach a newer version while the committed lock sits behind it. rangeStrategy does
not fix that; automerged lock maintenance does.

Enabled only because this repo has an MSRV job, per ADR-0018: automerge is gated on
the MSRV promise being protected by CI rather than by a reviewer noticing. Renovate
also waits for checks to pass before automerging, so a bump that raises the minimum
Rust version fails the MSRV job and cannot land. Repos without an MSRV job were
deliberately skipped in this sweep.

chore, not fix, so this does not cut a release: no crate code changed.

Verified: renovate.json parses as JSON and lockFileMaintenance.automerge is true.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`/target/` is anchored to the repository root, so it does not ignore the
build directories of nested cargo projects (fuzz/, bindings/python/).
Those artifacts were being picked up by `git add -A` and committed.

Unanchored `target/` matches at any depth, which is the intended behaviour.
The repo holds byte-exact fixtures and shipped no .gitattributes, so git's
text/binary autodetection was the only thing standing between the fixtures
and CRLF translation on a Windows checkout.

Prophylactic, not a repair: the three SQLCipher fixtures added here each
carry a NUL at byte 100 / 135 / 1044, inside git's 8000-byte sniff window,
so git already classifies them binary and nothing is currently corrupted.
The next fixture is not guaranteed that property -- a compressed payload
whose first NUL falls past 8000 bytes is classified as text and rewritten.
@socket-security

socket-security Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedcargo/​cbc@​0.1.210010093100100

View full report

h4x0r added 2 commits August 9, 2026 14:50
…r crypto deps

SQLCipher brings six third-party RustCrypto crates into the graph. New crates
entering the graph are a supply-chain decision, not the version-churn
bookkeeping that a cache refresh covers, so this takes the strongest mechanism
that applies before falling back to a weaker one.

Imported two more aggregate audit sets rather than exempting everything:

  [imports.zcash]  https://raw.githubusercontent.com/zcash/rust-ecosystem/...
  [imports.isrg]   https://raw.githubusercontent.com/divviup/libprio-rs/...

That is not paperwork. Exemptions drop 117 -> 103: SIXTEEN crates move from
"nobody read this" to genuinely audited, including hmac and inout -- two of the
six SQLCipher deps -- plus serde, sha2, subtle, getrandom, zlib-rs and others
that were exempted before this PR.

Four remain unaudited by us and by every imported set, and are exempted with a
note saying exactly that: aes 0.8.4, block-padding 0.3.3, cbc 0.1.2,
pbkdf2 0.12.2. The fleet rule forbids hand-rolled crypto and requires an
audited ecosystem crate, so these are the correct dependencies; the exemption
records that nobody has read these versions, which is true.

aes and pbkdf2 were already exempted, but at criteria safe-to-run -- enough
while they entered only through `zip` on dev/test paths. SQLCipher decryption
puts them on the SHIPPED path, so both are raised to safe-to-deploy. The gate
surfacing that change of exposure is the gate working.

No certify, no --accept-all.

Gate proven able to fail, with a well-formed mutation: re-pointing the cbc
exemption to a version that does not exist gives exit 255 and
`cbc:0.1.2 missing ["safe-to-deploy"]`; restoring it gives exit 0. (A first
attempt that deleted the block outright only proved the store formatter works
-- vet complained about blank lines, not about coverage.)
@h4x0r
h4x0r merged commit 41dfd7d into main Aug 9, 2026
25 checks passed
@h4x0r
h4x0r deleted the feat/sqlcipher-decryption branch August 9, 2026 14:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant