Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ecbabc8
feat(picky-crypto): add the RustCrypto backend
CBenoit Oct 10, 2026
ad1b4cf
fix(picky-crypto): draw ECDSA nonces from the OS generator
CBenoit Oct 10, 2026
e12286f
docs(picky-crypto): limit the validation error rule to keys
CBenoit Oct 10, 2026
7d72ffc
docs(picky-crypto): state exact outcomes for inconsistent RSA keys
CBenoit Oct 13, 2026
4b8e8d0
test(picky-crypto): cover RSA key generation without extended runs
CBenoit Oct 13, 2026
a51fe8a
docs(picky-crypto): let size limits take precedence over structure
CBenoit Oct 13, 2026
c1f0550
fix(picky-crypto): refuse oversized RSA encodings before decoding
CBenoit Oct 13, 2026
f94434d
docs(picky-crypto): order bound, size-limit and structure checks
CBenoit Oct 13, 2026
a9cb15a
test(picky-crypto): control the RC2, RC4 and PBKDF2 range boundaries
CBenoit Oct 13, 2026
4beaaf1
fix(picky-crypto): bound PBKDF2 output before allocation
CBenoit Oct 13, 2026
4e96cab
fix(picky-crypto): refuse oversized cipher data before allocation
CBenoit Oct 13, 2026
ffbdfb6
docs(picky-crypto): allow boundary controls for hand-written inputs
CBenoit Oct 13, 2026
f058e49
test(picky-crypto): compare boundary control outputs across providers
CBenoit Oct 13, 2026
876c5bc
docs(picky-crypto): accept Unsupported outside the must-support set i…
CBenoit Oct 13, 2026
b34cc90
docs(picky-crypto): name capacity limits and padding-oracle handling
CBenoit Oct 13, 2026
57ea81b
docs(picky-crypto): drop dependency versions from the RustCrypto README
CBenoit Oct 13, 2026
80d11e3
test(picky-crypto): cover every boundary-control comparison
CBenoit Oct 13, 2026
ba98875
fix(picky-crypto): check the Ed25519 S range in the adapter
CBenoit Oct 14, 2026
3edb3e8
docs(picky-crypto): note best-effort wiping of RSA keygen seed copies
CBenoit Oct 14, 2026
cc9e494
docs(picky-crypto): mark untested properties in the RustCrypto backend
CBenoit Oct 14, 2026
2295b93
docs(picky-crypto): mark crate-wide untested secret-handling properties
CBenoit Oct 14, 2026
86e5e43
docs(picky-crypto): explain the ed25519-dalek feature ban
CBenoit Oct 14, 2026
2405421
style(picky-crypto): put each comment sentence on its own line
CBenoit Oct 14, 2026
5510962
docs(picky-crypto): state why the RustCrypto backend reports no FIPS
CBenoit Oct 14, 2026
ad66cc4
docs(picky-crypto): state outcome precedence and general RSA key cons…
CBenoit Oct 14, 2026
4a0b53b
docs(picky-crypto): describe RSA encoding caps as defense in depth
CBenoit Oct 14, 2026
488a027
test(picky-crypto): check base-key export and both PBKDF2 control len…
CBenoit Oct 14, 2026
52ea4bf
fix(picky-crypto): drop the RSA private-key encoding cap
CBenoit Oct 15, 2026
de28833
test(picky-crypto): check signing with keys from RSA decryption vectors
CBenoit Oct 15, 2026
001b5a9
feat(picky-crypto): add a random feature to the RustCrypto backend
CBenoit Oct 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -227,18 +227,45 @@ jobs:
run: cargo --locked xtask check-vectors

- name: Run conformance suite
run: cargo test --locked -p picky-crypto-conformance -- --show-output
run: cargo test --locked -p picky-crypto-conformance --features rustcrypto -- --show-output

- name: Install cargo-deny
run: cargo install --locked cargo-deny --version 0.20.2

- name: Check dependency allowlist
run: cargo deny --manifest-path picky-crypto/Cargo.toml --config picky-crypto/deny.toml check bans

picky-crypto-rustcrypto:
name: RustCrypto backend checks
needs: [formatting]
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v6
with:
submodules: true

- name: Install cargo-hack
run: cargo install --locked cargo-hack --version 0.6.45

- name: Check feature powerset
run: cargo hack clippy --locked --feature-powerset --depth 2 -p picky-crypto-rustcrypto --all-targets -- -D warnings

- name: Check documentation
run: cargo doc --locked -p picky-crypto-rustcrypto --no-deps --all-features
env:
RUSTDOCFLAGS: "-D warnings"

- name: Install cargo-deny
run: cargo install --locked cargo-deny --version 0.20.2

- name: Check banned features
run: cargo deny --manifest-path Cargo.toml --workspace --all-features --config picky-crypto-rustcrypto/deny.toml check bans

success:
name: Success
if: ${{ always() }}
needs: [formatting, lints, lints-wasm, tests, msrv, dotnet-tests, no-downgrade, picky-crypto-checks]
needs: [formatting, lints, lints-wasm, tests, msrv, dotnet-tests, no-downgrade, picky-crypto-checks, picky-crypto-rustcrypto]
runs-on: ubuntu-latest

steps:
Expand Down
69 changes: 69 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ members = [
"picky-crypto",
"picky-crypto-testsuite",
"picky-crypto-conformance",
"picky-crypto-rustcrypto",
"picky",
"picky-krb",
"picky-asn1",
Expand All @@ -17,6 +18,7 @@ members = [

default-members = [
"picky-crypto",
"picky-crypto-rustcrypto",
"picky",
"picky-krb",
"picky-asn1",
Expand Down
6 changes: 6 additions & 0 deletions picky-crypto-conformance/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ name = "conformance"
path = "tests/main.rs"
harness = true

[features]
rustcrypto = ["dep:picky-crypto-rustcrypto"]

[dependencies]
picky-crypto-rustcrypto = { path = "../picky-crypto-rustcrypto", features = ["all"], optional = true }

[dev-dependencies]
picky-crypto = { path = "../picky-crypto" }
picky-crypto-testsuite = { path = "../picky-crypto-testsuite" }
2 changes: 2 additions & 0 deletions picky-crypto-conformance/tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ fn empty() -> CryptoProvider {

providers! {
empty ("none") => empty(), Options::default();
#[cfg(feature = "rustcrypto")]
rustcrypto ("rustcrypto") => picky_crypto_rustcrypto::provider(), Options::default();
}

pairs! {
Expand Down
7 changes: 7 additions & 0 deletions picky-crypto-rustcrypto/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Backend maintenance

- Inline tests cover adapter logic only: argument mapping, length and constant-byte checks.
Do not retest behavior covered by the conformance suite or the library.
- Never modify `picky-crypto-testsuite` to make this backend pass.
Escalate a failing case with its cited source, vector identifier, expected outcome and native library behavior.
- Cite the source file or documentation page at the version locked in `Cargo.lock` when relying on a library capability, or mark it Unknown.
59 changes: 59 additions & 0 deletions picky-crypto-rustcrypto/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
[package]
name = "picky-crypto-rustcrypto"
version = "0.1.0"
edition = "2024"
publish = false
rust-version = "1.85"
authors = ["Devolutions Inc. <infos@devolutions.net>"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/Devolutions/picky-rs"
description = "RustCrypto backend for the picky cryptographic provider contract"
readme = "README.md"
keywords = ["cryptography", "provider", "crypto"]
categories = ["cryptography"]

[features]
digest = ["dep:sha1", "dep:sha2", "dep:sha3", "dep:hmac", "dep:pbkdf2", "dep:digest", "dep:crypto-common"]
aes = ["dep:aes", "dep:cbc", "dep:cipher"]
aead = ["dep:aes-gcm", "dep:aes", "dep:getrandom", "dep:crypto-common"]
key-wrap = ["dep:aes-kw", "dep:aes"]
rsa = ["dep:rsa", "dep:md-5", "dep:sha1", "dep:sha2", "dep:sha3", "dep:getrandom", "dep:chacha20", "dep:crypto-common"]
nist-ec = ["dep:p256", "dep:p384", "dep:p521", "dep:sha2", "dep:hmac", "dep:getrandom", "dep:crypto-common", "dep:sec1"]
curve25519 = ["dep:ed25519-dalek", "dep:ed25519", "dep:x25519-dalek", "dep:sha2", "dep:getrandom", "dep:crypto-common"]
legacy = ["dep:md4", "dep:md-5", "dep:rc4", "dep:des", "dep:rc2", "dep:cbc", "dep:cipher", "dep:digest"]
all = ["digest", "aes", "aead", "key-wrap", "rsa", "nist-ec", "curve25519", "legacy"]

[dependencies]
picky-crypto = { path = "../picky-crypto" }
zeroize = { version = "1.9", default-features = false, features = ["alloc"] }
crypto-common = { version = "0.2.2", optional = true, features = ["rand_core", "zeroize"] }
aes = { version = "0.9.2", optional = true, features = ["zeroize"] }
aes-gcm = { version = "0.11.1", optional = true, default-features = false, features = ["aes", "alloc", "rand_core", "zeroize"] }
aes-kw = { version = "0.3.1", optional = true, features = ["zeroize"] }
cbc = { version = "0.2.1", optional = true, default-features = false, features = ["zeroize"] }
cipher = { version = "0.5.2", optional = true, features = ["zeroize"] }
digest = { version = "0.11.3", optional = true, features = ["zeroize"] }
des = { version = "0.9.0", optional = true, features = ["zeroize"] }
rc2 = { version = "0.9.0", optional = true, features = ["zeroize"] }
rc4 = { version = "0.2.0", optional = true, features = ["zeroize"] }
md4 = { version = "0.11.0", optional = true, features = ["zeroize"] }
md-5 = { version = "0.11.0", optional = true, features = ["oid", "zeroize"] }
sha1 = { version = "0.11.0", optional = true, features = ["oid", "zeroize"] }
sha2 = { version = "0.11.0", optional = true, features = ["oid", "zeroize"] }
sha3 = { version = "0.12.0", optional = true, features = ["oid", "zeroize"] }
hmac = { version = "0.13.0", optional = true, features = ["zeroize"] }
pbkdf2 = { version = "0.13.0", optional = true, default-features = false, features = ["hmac"] }
rsa = { version = "=0.10.0-rc.18", optional = true }
chacha20 = { version = "0.10.2", optional = true, default-features = false, features = ["rng", "zeroize"] }
sec1 = { version = "0.8.1", optional = true, default-features = false, features = ["der", "zeroize"] }
p256 = { version = "0.14.0", optional = true, default-features = false, features = ["ecdsa", "ecdh", "pkcs8", "alloc", "precomputed-tables", "std"] }
p384 = { version = "0.14.0", optional = true, default-features = false, features = ["ecdsa", "ecdh", "pkcs8", "alloc", "precomputed-tables", "std"] }
p521 = { version = "0.14.0", optional = true, default-features = false, features = ["ecdsa", "ecdh", "pkcs8", "alloc", "precomputed-tables", "std"] }
ed25519-dalek = { version = "3.0.0", optional = true, default-features = false, features = ["alloc", "digest", "fast", "pkcs8", "rand_core", "zeroize"] }
ed25519 = { version = "3.0.0", optional = true, default-features = false, features = ["pkcs8", "zeroize"] }
x25519-dalek = { version = "3.0.0", optional = true, default-features = false, features = ["precomputed-tables", "static_secrets", "zeroize"] }
getrandom = { version = "0.4.3", optional = true, features = ["sys_rng"] }

[dev-dependencies]
# Test keys outside the library's checked constructors (small moduli, large exponents).
rsa = { version = "=0.10.0-rc.18", features = ["hazmat"] }
15 changes: 15 additions & 0 deletions picky-crypto-rustcrypto/INTENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# picky-crypto-rustcrypto
Comment thread
CBenoit marked this conversation as resolved.
Resolved

## Purpose

`picky-crypto` backend implemented on top of the RustCrypto crates.

It implements every algorithm of the contract that RustCrypto provides when the `all` feature is enabled, including legacy algorithms (MD4, MD5, RC4, 3DES, RC2) needed by NTLM, Kerberos and legacy PKCS#12.
No family is enabled by default; each feature adds a family of entries.

## Invariants

- A backend is a thin adapter.
Real logic in a backend means the contract doesn't fit that library, and that's a reason to revisit the contract.
- It passes the full `picky-crypto-testsuite` conformance suite.
- `fips()` always returns `false`.
Loading
Loading