Skip to content

Security hardening, GCP provider, native CLI binaries + differential coverage#34

Merged
systemslibrarian merged 7 commits into
mainfrom
security-hardening-and-gcp-provider
Jul 11, 2026
Merged

Security hardening, GCP provider, native CLI binaries + differential coverage#34
systemslibrarian merged 7 commits into
mainfrom
security-hardening-and-gcp-provider

Conversation

@systemslibrarian

@systemslibrarian systemslibrarian commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Four logical commits from a hardening + developer-experience session on the encryption engine. No change to the frozen .pqfe v2 / PQKF v1 / .sig v1 formats. 537 .NET tests + 13 Rust tests green; zero warnings.

1. feat: Google Cloud KMS envelope-key provider

PostQuantum.FileEncryption.Gcp completes the AWS / Azure / GCP trio over IContentKeyProvider. CEK generated locally, wrapped with bound AAD, unwrapped only against the configured CryptoKey, fail-closed on tamper/foreign-key/AAD-mismatch. CRC32C verified both ways (RFC 3720 check value). Wired into solution, tests, and release pipeline.

2. fix: security review (8 bugs, all adversarially verified)

PQKF option/limit validation at the boundary (no more silently-unopenable key files); corrupt ML-KEM-768 keys fail closed as library exceptions instead of raw platform/BouncyCastle throws; signature verification validates structure before hashing and evaluates both halves independently; cancellation honored before the KDF; LocalKek taxonomy; pqfe refuses to overwrite output without --force.

3. docs: positioning + trust artifacts

Threat-model-in-one-table + "verify it yourself" README sections; test-vectors/ committed as verifiable binaries with pinned hashes (drift-guarded); docs/CRYPTO-AGILITY.md; corrected KNOWN-GAPS reader-leniency ledger + durability/DecryptAtomicAsync entries.

4. feat: native CLI binaries + differential coverage

Standalone single-file pqfe binaries (linux-x64/win-x64/osx-arm64) attached to each release with SHA-256 + provenance, no .NET runtime needed. A Rust round-trip property test sweeps the framing matrix (chunk × length boundaries, per-byte tamper, truncation) and the cross-implementation CI harness now randomizes payload sizes each run.

🤖 Generated with Claude Code

systemslibrarian and others added 4 commits July 10, 2026 19:24
…ryption.Gcp)

Completes the AWS KMS / Azure Key Vault / Google Cloud KMS trio over the
IContentKeyProvider seam. GcpKmsContentKeyProvider generates the per-file
content key locally (Cloud KMS has no server-side data-key generation),
wraps it with Cloud KMS Encrypt bound to library-specific AAD, and unwraps
against only the configured CryptoKey — a tampered, foreign-key, or
AAD-mismatched blob fails closed with PqDecryptionException while operational
failures propagate as the SDK's own exceptions. The CRC32C integrity fields
are populated on every request and verified on every response (the .NET SDK
does not do this itself), pinned by the RFC 3720 check value.

Ships entirely around the frozen .pqfe v2 format via the existing provider
seam. Wired into the solution, test project, and release pipeline (pack,
SBOM, NuGet push). Unit-tested against an in-process fake reproducing the
service's binding and INVALID_ARGUMENT semantics.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n (security review)

An adversarial multi-zone review of the engine surfaced eight bugs that
weakened the fail-closed contract; all are fixed here with regression tests
and no change to the frozen .pqfe v2 / PQKF v1 / .sig v1 formats.

- PQKF ExportEncrypted validates options before writing, so an out-of-range
  option can no longer silently produce a key file the correct passphrase
  could never open; ImportEncrypted validates caller-supplied limits so a
  below-minimum limit is a configuration error, not a hostile-file rejection.
- A corrupt ML-KEM-768 recipient key (public half on encrypt, private half
  on decrypt) now fails closed as a library exception instead of leaking a
  raw platform/BouncyCastle exception, matching the mirror paths.
- Detached-signature verification validates the sidecar before hashing the
  content (per SIGNATURE-FORMAT.md ordering), and evaluates both signature
  components in independent guarded steps so one half throwing cannot skip
  the other.
- Cancellation is honored immediately before the password KDF, so a cancelled
  token no longer pays the full (up to gibibyte-scale) derivation cost first.
- LocalKekContentKeyProvider reports a malformed wrap as PqFormatException,
  keeping PqDecryptionException reserved for one generic auth-failure message.
- pqfe encrypt/decrypt refuse to overwrite an existing output without --force.
- DecryptAtomicAsync and the DI limits-overload document their boundaries.

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

Surface the library's differentiators (open, frozen-format, verifiable) and
close the transparency gaps the security review found.

- README: a threat-model-in-one-table section, a "verify it yourself" section
  (provenance, KAT reproduction, cross-implementation), a composable package
  table, and a zero-friction (no license key) install pitch.
- test-vectors/: the known-answer vectors committed as ready-to-use binaries
  with pinned SHA-256 sums and a 30-second verification walkthrough, guarded
  by VectorArtifactTests so a frozen artifact cannot drift.
- docs/CRYPTO-AGILITY.md: how the format versions, how existing ciphertext
  stays decryptable across a migration, and the harvest-now-decrypt-later
  reasoning, stated in one place.
- KNOWN-GAPS: correct the frozen-format reader-leniency entry (the KeySource-4
  body tolerates trailing bytes / extra blocks and aborts on unknown KemId),
  and record the directory-fsync durability boundary and DecryptAtomicAsync
  in-memory ceiling — all format-v3 candidates or documented limitations.
- SECURITY.md supported-versions refresh; KEY-MANAGEMENT / COOKBOOK / AUDIT-SCOPE
  / Hybrid README updated for the Gcp provider and the 55-recipient cap rationale.
- CHANGELOG [Unreleased] records the Gcp provider and the security fixes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two developer-experience additions for people building on post-quantum crypto.

- Native single-file `pqfe` binaries (linux-x64, win-x64, osx-arm64) are built
  natively per target in the release pipeline and attached to each release with
  a SHA-256 sum and a build-provenance attestation — usable with no .NET runtime.
- A Rust round-trip property test sweeps the framing matrix (chunk sizes ×
  lengths straddling one/two/three chunks, plus per-byte tamper and truncation
  at every length), catching encode/decode asymmetry the fixed KATs cannot. The
  cross-implementation CI harness now randomizes payload sizes each run, so the
  .NET <-> Rust agreement is exercised at fresh points continuously.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@systemslibrarian systemslibrarian changed the title Security hardening + Google Cloud KMS provider Security hardening, GCP provider, native CLI binaries + differential coverage Jul 10, 2026
systemslibrarian and others added 3 commits July 10, 2026 19:51
…ent row

Add a fair "versus general-purpose crypto toolkits" section to COMPARISON.md —
the broad BouncyCastle-wrapper libraries that expose ML-KEM/ML-DSA as
primitives. Framed as a scope/altitude difference (primitives vs a finished
fail-closed construction; no-footguns-by-omission; hybrid vs bare Kyber; a
verifiable format vs a library), not open-vs-closed, since several are also MIT.
Describes the category rather than naming specific packages, so it ages well.

Also corrects the at-a-glance table, which still called the recipient path
"experimental" — it is the shipped hybrid X25519 + ML-KEM-768 Hybrid package.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bump all nine lockstep packages to 1.6.0, promote the Gcp package's public API
from Unshipped to Shipped, and set PackageValidationBaselineVersion to the
previous release (1.5.0). Sweep every user-facing version reference: the root
README Status line, all `dotnet add package --version` snippets (root + package
READMEs), the supply-chain verify/download examples, and the ROADMAP-2.0
"NuGet package version" cell. Finalize the CHANGELOG [1.6.0] section and
compare-link footer. Historical references (audit-scope tag/commit, coverage
measured at v1.5.0) are left as the facts they are.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The new CLI overwrite guard (refuses to replace an existing output without
--force) broke the cross-implementation harness, which re-encrypts to the same
temp paths every loop iteration. Add --force to the two reused .NET CLI calls;
the other CI encrypt/decrypt calls write once to a fresh temp dir and are
unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@systemslibrarian
systemslibrarian merged commit 3f814ae into main Jul 11, 2026
10 checks passed
@systemslibrarian
systemslibrarian deleted the security-hardening-and-gcp-provider branch July 11, 2026 00:13
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