Skip to content

fix(sphragis): redact SharedSecret's Debug and retrofit SealError location - #33

Merged
forkwright merged 4 commits into
mainfrom
fix/25-redact-shared-secret
Aug 15, 2026
Merged

forkwright merged 4 commits into
mainfrom
fix/25-redact-shared-secret

Conversation

@forkwright

Copy link
Copy Markdown
Owner

Summary

  • SharedSecret was a bare pub type SharedSecret = Zeroizing<[u8; 32]> alias, so it inherited [u8; 32]'s derived Debug{:?} printed the live X-Wing shared secret. Zeroizing protects memory on drop, not the value while it is alive. Replaced with a newtype carrying a manual, redacting Debug ("SharedSecret([REDACTED])"), matching DecapsulationKey's existing pattern. Zeroize-on-drop is unchanged (the newtype still wraps Zeroizing). An as_slice() accessor preserves every existing call site (derive_wrap_key, the KAT assertions) — no behavior change beyond the Debug surface.
  • Finishes the #[snafu(implicit)] location retrofit onto SealError that Return typed entropy failures instead of panicking in cryptographic operations #16/fix(sphragis): return typed entropy failures instead of panicking #28 started: every remaining variant (WrongLength, InvalidMlKem, HkdfExpand, AeadSeal, AeadOpen, UnsupportedVersion, Serialization, EnvelopeTooLarge, TrailingData) now carries a location, and every construction site that built the enum directly (map_err closures, a bare return Err(..)) now goes through its context selector (.context() / .build() / .fail()) so the field actually populates.

Tests

  • New shared_secret_debug_is_redacted (tests/known_answer_vectors.rs): formats a real SharedSecret obtained from encapsulate(), asserts the output contains "REDACTED" and does not contain the hex-encoded secret bytes. This is the mandatory negative-case fixture — a type-compiles check would prove nothing.
  • Extended wrong_length_ek_and_ct_rejected to capture one SealError::WrongLength and assert location.file.ends_with("hybrid.rs"), mirroring the pattern tests/entropy_failure.rs already uses for SealError::Entropy.
  • All existing KAT / round-trip / negative tests are unchanged in behavior; SealError construction now goes through context selectors instead of struct literals, but every variant's fields (other than the new location) are identical.

Notes

Closes #25
Closes #26

forkwright added 4 commits August 15, 2026 18:31
…ation

SharedSecret was a bare `pub type SharedSecret = Zeroizing<[u8; 32]>`
alias, so it inherited [u8; 32]'s derived Debug: `{:?}` printed the live
X-Wing shared secret. Zeroizing protects memory on drop, not the value
while it is alive. Replace the alias with a newtype carrying a manual,
redacting Debug ("SharedSecret([REDACTED])"), matching
DecapsulationKey's existing pattern; zeroize-on-drop is unchanged since
the newtype still wraps Zeroizing. An as_slice() accessor preserves
every existing call site (derive_wrap_key, the KAT assertions).

Also finishes the SealError location retrofit #16/#28 started: every
variant now carries a snafu implicit location field, and every
construction site that built the enum directly (map_err closures, a
bare return Err) now goes through its context selector so the field
actually populates.

Part of #25
Part of #26
…ants

snafu's `.context()` requires the context selector's associated `Source`
type to equal the original Result's error type — that only holds for a
variant that actually declares a `source` field (like `Entropy`, wrapping
`rand_core::Error`). `HkdfExpand`, `AeadSeal`, `AeadOpen`, `InvalidMlKem`,
and `WrongLength` carry no `source` field, so `.context()` failed to
type-check for all of them (CI: E0271, Source == NoneError / InvalidLength
/ TryFromSliceError / etc.). Switch those call sites to
`.map_err(|_| XSnafu { .. }.build())`, matching the pattern already used
for `Serialization`. The implicit `location` field still populates
correctly through `.build()`.

Part of #25
Part of #26
EncapsulationKey is intentionally not Debug (it holds key-derived
material). unwrap_err() requires T: Debug even on the Err path, so it
does not compile. Match on a reference to the Result instead, mirroring
tests/entropy_failure.rs's existing pattern for the same reason.

Part of #26
The let-else panic! branch trips the crate's deny(clippy::panic) under
-D warnings. entropy_failure.rs already expects this lint for the same
reason (an unmatched variant IS the test failure); apply the same
expect here.

Part of #26
@forkwright
forkwright merged commit 11216eb into main Aug 15, 2026
12 checks passed
@forkwright
forkwright deleted the fix/25-redact-shared-secret branch August 15, 2026 23:46
forkwright pushed a commit that referenced this pull request Aug 16, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.2.0](v0.1.2...v0.2.0)
(2026-08-16)


### ⚠ BREAKING CHANGES

* **sphragis:** make deterministic encapsulation private
([#31](#31))

### Features

* **sphragis:** define revocation as key rotation, not re-wrapping
([#34](#34))
([37ba8e3](37ba8e3))
* **sphragis:** narrow the public API to the envelope profile, define
the adapter seam
([#32](#32))
([d0a0bb8](d0a0bb8))


### Bug Fixes

* **sphragis:** bind the KAT gate to a machine-readable crypto
provenance lock
([#27](#27))
([65e3433](65e3433))
* **sphragis:** bound and fully consume untrusted CBOR before accepting
a wrapped key ([#24](#24))
([d165e5b](d165e5b))
* **sphragis:** make deterministic encapsulation private
([#31](#31))
([cf48668](cf48668))
* **sphragis:** redact SharedSecret's Debug and retrofit SealError
location ([#33](#33))
([11216eb](11216eb))
* **sphragis:** return typed entropy failures instead of panicking
([#28](#28))
([2ff3a08](2ff3a08))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

Retrofit #[snafu(implicit)] location onto SealError's remaining variants SharedSecret's derived Debug prints the raw X-Wing shared secret

1 participant