feat(sqlcipher): decrypt SQLCipher pages into the reader's stream - #10
Merged
Conversation
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.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
…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.)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
maindid not have, this is the only one whosecontent was neither already landed nor superseded.
What it adds
core/src/sqlcipher.rs— decrypts SQLCipher pages into the reader's streamcore/tests/sqlcipher_oracle.rs— Tier-2 oracle testdocs/decisions/0010-sqlcipher-decryption.md— the rationaletests/data/README.md.gitattributesmarking the fixture trees-text(see below)Evidence
Merged current
maininto the branch first — zero conflicts — and ran thesuite against the merge result, not the branch in isolation:
Local run on the pinned toolchain (cargo 1.96.0, matching
rust-toolchain.toml).CI is the independent check.
On the
.gitattributescommitProphylactic, 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.autocrlfdefaults to true on GitHub runners.Release
No version edit in this PR.
feat:lets release-plz compute the bump and openits own release PR on merge.