Skip to content

pkcs1v15: retrofit deterministic implicit rejection for decryption#685

Open
EffortlessSteven wants to merge 5 commits intoRustCrypto:masterfrom
EffortlessSteven:pkcs1v15-implicit-rejection-retrofit
Open

pkcs1v15: retrofit deterministic implicit rejection for decryption#685
EffortlessSteven wants to merge 5 commits intoRustCrypto:masterfrom
EffortlessSteven:pkcs1v15-implicit-rejection-retrofit

Conversation

@EffortlessSteven
Copy link
Copy Markdown

PKCS#1 v1.5 decrypt currently leaks padding validity through Error::Decryption. This PR removes that distinguisher without changing the public decrypt API.

It keeps the existing trait surface and Result<Vec<u8>>, standardizes the outer public-invalid boundary so wrong-length ciphertexts and out-of-range ciphertext representatives still return Err(Error::Decryption), and changes only padding-invalid but otherwise public-valid ciphertexts to return the deterministic rejection symbol.

What changes

  • retrofit the existing PKCS#1 v1.5 decrypt seam in src/algorithms/pad.rs, src/algorithms/pkcs1v15.rs, and src/pkcs1v15.rs
  • add a modulus-width serializer plus local KDK / IRPRF / scan / selector helpers for deterministic implicit rejection
  • keep the public sha2 feature name for compatibility. SHA-256 is now an unconditional internal dependency for PKCS#1 v1.5 implicit rejection, while the sha2 feature continues to gate the SHA-2 reexport and PKCS#1 v1.5 signature OID impls
  • add checked-in Appendix B fixtures and a data-driven vector runner, plus focused regression coverage
  • update PKCS#1 v1.5 docs and changelog to describe the new semantics under the existing API

What does not change

  • no new public safe-decrypt API
  • no fixed-size decapsulation API
  • no public sha2 feature rename or removal
  • no docs.rs feature-policy change
  • no README cleanup
  • no broader PKCS#1 v1.5 policy patch
  • no crate-wide Marvin-closure claim
  • no static/formal verification project
  • no DH = SHA256(D) caching optimization

Evidence

  • Appendix B coverage: B.1 2048-bit, B.2 2049-bit, B.3 3072-bit, B.4 4096-bit
  • Focused regressions: wrong-length and c >= n ciphertexts still return Err(Error::Decryption); identical invalid ciphertexts remain deterministic; distinct invalid ciphertexts produce distinct rejection symbols; valid ciphertexts still decrypt normally; RsaPrivateKey::decrypt(...) and pkcs1v15::DecryptingKey agree on the shared path
  • Rust matrix: cargo test --test pkcs1v15_implicit_rejection --all-features; cargo test --lib --tests --all-features; cargo check --all-features; cargo check --no-default-features
  • Marvin: corrected 100k and 300k baseline/patched runs did not show a strong global separation signal. A focused patched-only 500k follow-up weakened the earlier valid_0 vs zero_byte_in_padding_48_4 suspicion. Current conclusion: supportive evidence, not closure.

Follow-up work

Phase-two follow-ups should stay separate from this retrofit:

  • fixed-size decapsulation API
  • broader PKCS#1 v1.5 deprecation/default-disable work
  • stronger static/formal verification

@EffortlessSteven EffortlessSteven force-pushed the pkcs1v15-implicit-rejection-retrofit branch from 8e622fd to 4a7234a Compare April 19, 2026 06:38
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