Skip to content

feat(picky-crypto): add the RustCrypto backend - #559

Open
Benoît Cortier (CBenoit) wants to merge 5 commits into
cbenoit-picky-crypto-testsuitefrom
cbenoit-picky-crypto-rustcrypto
Open

Benoît Cortier (CBenoit) wants to merge 5 commits into
cbenoit-picky-crypto-testsuitefrom
cbenoit-picky-crypto-rustcrypto

Conversation

@CBenoit

@CBenoit Benoît Cortier (CBenoit) commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

Implementing the picky-crypto contract needs at least one software backend. RustCrypto covers every contract algorithm except the key-based KDFs and FFDH, and it includes the legacy algorithms NTLM, Kerberos and legacy PKCS#12 need.

Add the picky-crypto-rustcrypto crate (publish = false). It is a thin adapter: each entry maps the contract's arguments to RustCrypto calls, checks algorithm-fixed lengths and constant bytes, and maps library errors to the contract's error set. Library capabilities the adapter relies on are cited at their locked versions in code comments. fips() is always false. Library zeroize features are enabled, and adapter-held secret copies and returned buffers use zeroizing storage. No secret-holding type implements Debug.

Algorithm families are features, with nothing enabled by default. A build without features yields an empty provider, and each feature only adds entries:

  • digest: SHA-1, SHA-2 and SHA3-384/512 hashes, HMAC and PBKDF2
  • aes: AES-CBC
  • aead: AES-GCM
  • key-wrap: AES-KW
  • rsa: PKCS#1 v1.5 signature verification (MD5, SHA-1, SHA-2, SHA3-384/512), PKCS#1 v1.5 and OAEP encryption, private-key loading, 2048/3072/4096-bit generation
  • nist-ec: ECDSA and ECDH on P-256, P-384 and P-521, private-key loading and generation
  • curve25519: Ed25519 verification, loading and generation; X25519 ephemeral and static agreement
  • legacy: MD4, MD5, RC4, 3DES-EDE3-CBC and RC2-CBC
  • all: every family (64 entries)

A secure-random entry comes with aead, rsa, nist-ec or curve25519. Key-based KDFs and FFDH are not provided; other providers supply them.

Where the library falls short of the contract, the adapter uses library functions only:

  • RSA key generation expands a 256-bit OS seed with ChaCha20, because the library's generator interface cannot report a randomness failure.
  • Ephemeral X25519 fills its scalar from the OS generator, because the library's ephemeral type panics on randomness failure.
  • Ed25519 verification rejects non-canonical public-key encodings, which the library accepts (ZIP-215), by comparing the library's recompression with the input.
  • RSA keys beyond the library's size or exponent limits return Unsupported.

RSA signing and decryption are blinded, and ECDSA signing mixes OS randomness into the RFC 6979 nonce.
picky-crypto-rustcrypto/deny.toml bans ed25519-dalek's legacy_compatibility feature over the workspace, because it would weaken the Ed25519 S range check through feature unification.

CONTRACT.md clarifications motivated by this backend:

  • §4: library key-validation failures map to InvalidKey, except when the library only rejects a well-formed key for its size or parameters, which maps to Unsupported.
  • §7 and §12: handling RSA private keys with non-distinct primes (p = q) is implementation-defined, per call, and has no conformance vector.

The picky-crypto-conformance runner gains a rustcrypto feature that registers this provider with all. CI runs it, together with a depth-2 cargo-hack clippy powerset over the backend's features and the cargo-deny feature ban.

The separate fix(picky) commit makes an Ed25519 SignatureEncoding::to_vec call explicit, so workspace clippy passes when ed25519/alloc is unified in. It duplicates a standalone fix against master and drops out when this branch is rebased after that fix lands.

Stacked on #556; merge after it.

Size: backend source +1544 (about 180 of it inline adapter tests), manifests and runner +78, documentation +89/−8, CI +29/−2, Cargo.lock +69 (md4 0.11.0, rc4 0.2.0 and this crate), picky +2/−2.

Open question: rsa is the prerelease 0.10.0-rc.18, which the workspace already locks.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Contract inconsistencies, ECDSA nonce handling, PBKDF2 error mapping, and the prohibited intent-file addition remain unresolved.

5 open findings
What changed in this PR

Adds a feature-gated RustCrypto implementation of the picky-crypto provider contract and integrates it with conformance testing and CI.

Changes:

  • Implements 64 cryptographic provider entries across eight feature families.
  • Clarifies contract error handling and malformed RSA-key behavior.
  • Adds conformance, feature-powerset, documentation, and dependency-policy checks.
File Description
.github/​workflows/​ci.yml Adds backend conformance and CI checks.
Cargo.lock Locks backend dependencies.
Cargo.toml Registers the backend workspace crate.
picky/​src/​signature.rs Disambiguates signature encoding.
picky-crypto/​CONTRACT.md Revises error and RSA-key rules.
picky-crypto-conformance/​Cargo.toml Adds the optional backend feature.
picky-crypto-conformance/​tests/​main.rs Registers the RustCrypto provider.
picky-crypto-rustcrypto/​AGENTS.md Adds backend maintenance guidance.
picky-crypto-rustcrypto/​Cargo.toml Defines features and dependencies.
picky-crypto-rustcrypto/​INTENT.md Adds backend intent and invariants.
picky-crypto-rustcrypto/​README.md Documents features and capabilities.
picky-crypto-rustcrypto/​deny.toml Bans weakened Ed25519 compatibility.
picky-crypto-rustcrypto/​src/​aead.rs Implements AES-GCM.
picky-crypto-rustcrypto/​src/​cbc.rs Implements CBC ciphers.
picky-crypto-rustcrypto/​src/​curve25519.rs Implements Ed25519 and X25519.
picky-crypto-rustcrypto/​src/​ec.rs Implements NIST EC operations.
picky-crypto-rustcrypto/​src/​hash.rs Implements digest entries.
picky-crypto-rustcrypto/​src/​key_wrap.rs Implements AES-KW.
picky-crypto-rustcrypto/​src/​lib.rs Assembles feature-selected entries.
picky-crypto-rustcrypto/​src/​mac.rs Implements HMAC.
picky-crypto-rustcrypto/​src/​pbkdf2.rs Implements PBKDF2.
picky-crypto-rustcrypto/​src/​random.rs Implements secure randomness.
picky-crypto-rustcrypto/​src/​rc4.rs Implements RC4.
picky-crypto-rustcrypto/​src/​rsa.rs Implements RSA operations and keys.
picky-crypto-rustcrypto/​src/​util.rs Adds zeroizing buffer and length helpers.

🧠 Review effort: Balanced


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread picky-crypto-rustcrypto/src/ec.rs Outdated
Comment thread picky-crypto-rustcrypto/src/pbkdf2.rs Outdated
Comment thread picky-crypto-rustcrypto/INTENT.md
Comment thread picky-crypto-rustcrypto/README.md Outdated
Comment thread picky-crypto/CONTRACT.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The new contract wording misclassifies non-key library validation failures as InvalidKey.

1 open finding
4 resolved since last review

🧠 Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The broad cryptographic and key-handling surface warrants final human security review despite comprehensive conformance coverage.

0 open findings

1 resolved since last review

🧠 Review effort: Balanced

@CBenoit
Benoît Cortier (CBenoit) force-pushed the cbenoit-picky-crypto-rustcrypto branch 5 times, most recently from 969bab0 to aed983a Compare October 13, 2026 07:01
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Ed25519 signatures gain an inherent to_vec when the ed25519 crate's alloc feature is enabled anywhere in the build, which leaves the trait import unused and fails clippy with warnings denied. Calling the trait method by path compiles the same with and without that feature.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
ECDSA signing now mixes operating-system randomness into the RFC 6979 nonce, as the contract requires for ECDSA nonces. PBKDF2 reports an output allocation failure as unsupported only above the must-support output length.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The section 4 rule on library validation failures covers key validation only; non-key inputs keep the errors the section 4 table assigns.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Conformance outcome sets for RSA private keys with inconsistent or non-distinct components are exact per test input: a signature verifies under (n, e) or the call returns InvalidKey, and decrypting a ciphertext with valid padding returns the expected plaintext or InvalidKey, never VerificationFailed.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@CBenoit
Benoît Cortier (CBenoit) force-pushed the cbenoit-picky-crypto-rustcrypto branch from aed983a to 6482c34 Compare October 13, 2026 08:14

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants