EffortlessMetrics/uselesskey-swarm
GitHub: EffortlessMetrics/uselesskey-swarm
一个 Rust 测试 fixture 工厂,用于在开发和 CI 中确定性生成加密密钥与证书的测试数据,避免将密钥文件提交到版本库。
Stars: 0 | Forks: 0
uselesskey
生成确定性的 auth、TLS、webhook、token 和测试 fixture,并提供仅包含元数据的审计回执。
`uselesskey` 是一个**测试 fixture 工厂**,而不是一个加密库。它生成确定性的 auth、TLS、webhook、token 和测试 fixture;默认将生成的原始材料排除在 git 之外;审计生成的内容;并明确界定证明边界。
## 从这里开始
首先选择你的任务;仓库的证明机制可以在你需要时通过链接找到。
| 我需要... | 从这里开始 | 复制此项 |
| --- | --- | --- |
| 编写 Rust 测试 | facade crate | `uselesskey = { version = "0.9.1", features = ["rsa"] }` |
| 测试 webhook 签名 | webhook profile | `uselesskey bundle --profile webhook --out target/uselesskey-webhook` |
| 测试 TLS 链 | TLS profile | `uselesskey bundle --profile tls --out target/uselesskey-tls` |
| 测试 OIDC/JWT 负面用例 | OIDC profile | `uselesskey bundle --profile oidc --out target/uselesskey-oidc` |
| 仅测试 token 的 Rust 代码 | facade token feature | `uselesskey = { version = "0.9.1", default-features = false, features = ["token"] }` |
| 安装 CI fixture | 已安装的 CLI bundle | `uselesskey bundle --profile scanner-safe --out target/uselesskey-bundle` |
| 测试负向验证器路径 | contract pack | `uselesskey bundle --profile oidc --out target/uselesskey-oidc` |
| 审查 bundle 证据 | verify + inspect + audit | `uselesskey inspect-bundle target/uselesskey-webhook` |
| 保持运行时材料可丢弃 | `target/` 输出 | `uselesskey audit-bundle target/uselesskey-webhook --ci --out target/uselesskey-webhook-audit` |
| 上传仅包含元数据的回执 | CI artifact 步骤 | `uses: actions/upload-artifact@v7` |
| 从 checkout 证明仓库的公开声明 | repo verification pack | `cargo xtask verification-pack --out target/uselesskey-verification` |
当你需要在此工作区之外使用 fixture bundle 时,请安装 CLI:
```
cargo install uselesskey-cli --version 0.9.1 --locked
uselesskey doctor
uselesskey profiles
uselesskey bundle --profile webhook --explain
```
生成、验证、检查和审计 webhook bundle:
```
uselesskey bundle --profile webhook --out target/uselesskey-webhook
uselesskey verify-bundle target/uselesskey-webhook
uselesskey inspect-bundle target/uselesskey-webhook
uselesskey audit-bundle target/uselesskey-webhook --ci --out target/uselesskey-webhook-audit
```
当审计是下游 CI 门禁的一部分时,请使用 `--ci --expect-profile
--policy strict --out `:
```
uselesskey audit-bundle target/uselesskey-webhook --ci --expect-profile webhook --policy strict --out target/uselesskey-webhook-audit
```
对于 GitHub Actions,请仅上传包含元数据的审计回执:
```
- name: Upload uselesskey audit receipts
uses: actions/upload-artifact@v7
if: always()
with:
name: uselesskey-webhook-audit
path: |
target/uselesskey-webhook-audit/bundle-audit.json
target/uselesskey-webhook-audit/bundle-audit.md
if-no-files-found: error
```
Rust 测试作者从 facade crate 开始:
```
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa"] }
```
然后在运行时生成确定性 fixture:
```
use uselesskey::{Factory, RsaFactoryExt, RsaSpec};
let fx = Factory::deterministic_from_str("test-seed");
let key = fx.rsa("issuer", RsaSpec::rs256());
let pkcs8_pem = key.private_key_pkcs8_pem();
```
审查者和维护者的证明是仓库本地的。从 checkout 中,公开声明可以被打包为仅包含元数据的证明 bundle:
```
cargo xtask verification-pack --out target/uselesskey-verification
```
这不能证明的内容:
- 生产密钥生成、密钥保管或机密管理;
- 生产 PKI、提供者兼容性或 webhook 传递语义;
- 提交生成的 secret 形状 payload 的权限;
- 下游验证器的正确性;
- 仓库的公开声明,除非你运行了仓库本地的证明命令。
任务路由请参阅 [docs/how-to/start-here.md](docs/how-to/start-here.md),验证/审计循环请参阅 [docs/how-to/verify-a-fixture-bundle.md](docs/how-to/verify-a-fixture-bundle.md),或者完整的证明索引请参阅 [docs/status/PUBLIC_CLAIMS.md](docs/status/PUBLIC_CLAIMS.md)。
对于下游形态的干净项目,请使用[外部示例索引](examples/external/README.md)。
## 为什么会有这个项目
`uselesskey` 是一个**测试 fixture 层**,而不是运行时加密服务。
当你需要真实的加密 fixture 但又不想提交 PEM/DER/JWK 文件时,请使用它。
它的存在是为了消除这种测试摩擦:
- 扫描器会检查 PR 中的每一次提交,而不仅仅是最终的差异
- 看起来像伪造的密钥仍然会触发策略、推送保护和审查摩擦
`uselesskey` 用一个 dev-dependency 和运行时生成取代了安全例外 + 路径忽略 + fixture 目录。
## 它解决了什么问题
如果没有这一层,团队通常会采用以下方法之一:
| 方法 | 问题 |
|----------|----------|
| 提交 PEM/DER 文件 | 触发扫描器和推送保护 |
| 在测试中临时生成密钥 | 重复的样板代码,RSA 速度慢,没有共享的确定性 |
| 直接使用原始加密 crate | 你仍然需要自己组装 PEM/DER/JWK/X.509 形状 |
| 直接使用 `rcgen` 或其他运行时 crate | 很有用,但并不以 fixture 的人体工程学、确定性或负面用例为中心 |
`uselesskey` 是专门为**测试工件**构建的。
## 你能得到什么
### Fixture 家族
- RSA (2048, 3072, 4096)
- ECDSA (P-256, P-384)
- Ed25519
- HMAC (HS256, HS384, HS512)
- OpenPGP (RSA 2048/3072, Ed25519)
- Token fixture(API key、bearer、OAuth access-token / JWT 形状)
- X.509 自签名证书和证书链
### 输出形状
- PKCS#8 PEM/DER
- SPKI PEM/DER
- OpenPGP armored 和二进制 keyblock
- JWK / JWKS
- 用于基于路径的 API 的临时文件
- X.509 叶子和链,以及负向变体
### 负面工件
- 损坏的 PEM
- 截断的 DER
- 不匹配的密钥对
- 过期/吊销/主机名不匹配/未知 CA 的证书
## 首先选择通道
从能保持测试语义且开销最小的通道开始。
| 我需要 | 推荐通道 | 原因 |
|----------|----------|----------|
| 仅需熵 / scanner 形状 | `uselesskey-entropy` 或 facade `features = ["entropy"]` | 确定性字节,没有密钥生成的负担 |
| 仅需 JWT / bearer / API-token 形状 | `uselesskey-token` 或 facade `features = ["token"]` | token 形状的 fixture,无需引入 RSA/X.509 |
| 有效的运行时加密语义 | 叶子 crate,如 `uselesskey-rsa`, `uselesskey-x509`, `uselesskey-ssh` | 真实的 PKCS#8/JWK/X.509/SSH fixture 行为 |
| 构建时物化的 fixture | `uselesskey-cli materialize` + `verify` | 干净的、仅限形状的 `OUT_DIR` / `include_bytes!` 工作流,RSA 物化作为显式 opt-in |
| 可重现的 fixture bundle + 交接 | `uselesskey-cli bundle` + `verify-bundle` + `inspect-bundle` + `export` | 确定性的、对扫描器安全的 fixture、manifest 和回执 bundle;无需提交真实 secret 的 Kubernetes/Vault payload 交接 |
功能选择请参阅 [docs/how-to/choose-features.md](docs/how-to/choose-features.md)。
在决定使用 entropy、token、semantic 还是物化的 fixture 工作流时,请使用 [docs/how-to/choose-lane.md](docs/how-to/choose-lane.md)。
当前的本地成本和咨询回执请参见 [docs/reference/dependency-economics.md](docs/reference/dependency-economics.md) 和 [docs/reference/audit-surface.md](docs/reference/audit-surface.md)。
## 选择最小的功能集
`uselesskey` facade 具有一个空的默认功能集。只需启用你需要的 fixture 家族。
常见的起点:
```
# 仅有 Entropy 的 fixtures
[dev-dependencies]
uselesskey = { version = "0.9.1", default-features = false, features = ["entropy"] }
```
```
# RSA fixtures
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa"] }
```
```
# 仅有 Token 的 fixtures,不引入 RSA/X.509
[dev-dependencies]
uselesskey = { version = "0.9.1", default-features = false, features = ["token"] }
```
```
# RSA + JWK/JWKS
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa", "jwk"] }
```
```
# X.509 fixtures
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["x509"] }
```
以下物化命令是仓库 checkout 示例。安装了
CLI 的用户可以运行相同的子命令,如 `uselesskey materialize ...` 和
`uselesskey verify ...`。
```
# Build-time 物化,仅限形状的通用 lane
cargo run -p uselesskey-cli -- materialize --manifest crates/materialize-shape-buildrs-example/uselesskey-fixtures.toml --out-dir target/tmp-fixtures
cargo run -p uselesskey-cli -- verify --manifest crates/materialize-shape-buildrs-example/uselesskey-fixtures.toml --out-dir target/tmp-fixtures
```
对于 `build.rs` 使用者:
```
# 通用的仅限形状的 Build-time 路径
[build-dependencies]
uselesskey-cli = { version = "0.9.1", default-features = false }
```
```
# 专用的 RSA PKCS#8 Build-time 路径
[build-dependencies]
uselesskey-cli = { version = "0.9.1", default-features = false, features = ["rsa-materialize"] }
```
为了方便,请使用 facade。仅当编译时最小化足够重要,足以证明更严格的 API 是合理的时候,才依赖叶子 crate。
如果你不确定从哪些 flag 开始,请从 [docs/how-to/choose-features.md](docs/how-to/choose-features.md) 开始。
对于下游 bot/reviewer 策略,请使用 [docs/how-to/downstream-fixture-policy.md](docs/how-to/downstream-fixture-policy.md)。
有关 crate 级别的支持合约(stable/incubating/experimental、受众和发布状态),请参阅 [docs/reference/support-matrix.md](docs/reference/support-matrix.md)。
## 快速开始
```
use uselesskey::{Factory, RsaFactoryExt, RsaSpec};
// Random mode: different keys every run
let fx = Factory::random();
// Deterministic mode: stable output for a seed string
let fx = Factory::deterministic_from_str("my-test-seed");
// Or use env-var seed with random fallback
let fx = Factory::deterministic_from_env("USELESSKEY_SEED")
.unwrap_or_else(|_| Factory::random());
let rsa = fx.rsa("issuer", RsaSpec::rs256());
let pkcs8_pem = rsa.private_key_pkcs8_pem();
let spki_der = rsa.public_key_spki_der();
```
核心形状始终是:
```
(mode, domain, label, spec, variant) -> artifact
```
这使得 fixture 在确定性模式下保持稳定,并且在两种模式下都可缓存。
## 常见代码片段的功能提醒
- `rsa` 用于 PEM/DER、临时文件和负向密钥示例
- `rsa` + `jwk` 用于 `public_jwk()` / `public_jwks()`
- `x509` 用于证书、rustls 和 tonic 示例
- `token` 仅用于 token 形状的 fixture
- `pgp` 用于 armored/二进制 OpenPGP fixture
## 依赖代码片段提醒
依赖代码片段:
- **快速开始 (RSA)**
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa"] }
- **仅限 Token**
[dev-dependencies]
uselesskey = { version = "0.9.1", default-features = false, features = ["token"] }
- **JWT/JWK**
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa", "jwk"] }
- **X.509 + rustls**
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["x509"] }
uselesskey-rustls = { version = "0.9.1", features = ["tls-config", "rustls-ring"] }
- **jsonwebtoken 适配器**
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa", "ecdsa", "ed25519", "hmac"] }
uselesskey-jsonwebtoken = { version = "0.9.1", features = ["all"] }
### JWK / JWKS
需要 `features = ["rsa", "jwk"]`。
```
use uselesskey::{Factory, RsaSpec, RsaFactoryExt};
let fx = Factory::random();
let rsa = fx.rsa("issuer", RsaSpec::rs256());
let jwk = rsa.public_jwk();
let jwks = rsa.public_jwks();
```
### 临时文件
```
use uselesskey::{Factory, RsaSpec, RsaFactoryExt};
let fx = Factory::random();
let rsa = fx.rsa("server", RsaSpec::rs256());
let keyfile = rsa.write_private_key_pkcs8_pem().unwrap();
assert!(keyfile.path().exists());
```
### X.509 证书
需要 `features = ["x509"]`。
用于简单 TLS 测试的自签名证书:
```
use uselesskey::{Factory, X509FactoryExt, X509Spec};
let fx = Factory::random();
let cert = fx.x509_self_signed("my-service", X509Spec::self_signed("test.example.com"));
let cert_pem = cert.cert_pem();
let key_pem = cert.private_key_pkcs8_pem();
```
三级链(root intermediate leaf):
```
use uselesskey::{Factory, X509FactoryExt, ChainSpec};
let fx = Factory::random();
let chain = fx.x509_chain("my-service", ChainSpec::new("test.example.com"));
// Standard TLS server chain: leaf + intermediate, no root
let chain_pem = chain.chain_pem();
// Individual artifacts for custom setups
let root_pem = chain.root_cert_pem();
let leaf_key = chain.leaf_private_key_pkcs8_pem();
```
### X.509 负面 fixture
这些用于错误路径测试,而不是验证逻辑。
```
use uselesskey::{Factory, X509FactoryExt, ChainSpec};
let fx = Factory::random();
let chain = fx.x509_chain("my-service", ChainSpec::new("test.example.com"));
// Expired leaf certificate
let expired = chain.expired_leaf();
// Hostname mismatch (SAN doesn't match expected hostname)
let wrong_host = chain.hostname_mismatch("wrong.example.com");
// Signed by an unknown CA (not in your trust store)
let unknown = chain.unknown_ca();
// Revoked leaf with CRL signed by the intermediate CA
let revoked = chain.revoked_leaf();
let crl_pem = revoked.crl_pem().expect("CRL present for revoked variant");
```
### 负面 fixture(密钥)
```
use uselesskey::{Factory, RsaSpec, RsaFactoryExt};
use uselesskey::negative::CorruptPem;
let fx = Factory::random();
let rsa = fx.rsa("issuer", RsaSpec::rs256());
let bad_pem = rsa.private_key_pkcs8_pem_corrupt(CorruptPem::BadBase64);
let truncated = rsa.private_key_pkcs8_der_truncated(32);
let mismatched_pub = rsa.mismatched_public_key_spki_der();
```
### Token fixture
Token fixture 是**工件形状**,而不是 auth 框架。它们的存在是为了让测试可以使用看起来真实的 token 值,而无需提交 blob。
```
use uselesskey::{Factory, TokenFactoryExt, TokenSpec};
let fx = Factory::random();
let api_key = fx.token("billing", TokenSpec::api_key());
let bearer = fx.token("gateway", TokenSpec::bearer());
let oauth = fx.token("issuer", TokenSpec::oauth_access_token());
assert!(api_key.value().starts_with("uk_test_"));
assert!(bearer.authorization_header().starts_with("Bearer "));
assert_eq!(oauth.value().split('.').count(), 3);
```
## 对扫描器安全的 bundle 和导出
`uselesskey-cli` bundle 工作流会生成一个确定性的 fixture 目录、一个 manifest 和每个工件的回执,下游测试可以验证、检查这些内容,并将其交接给 Kubernetes 或 Vault,而无需提交真实的 secret 材料。
```
# 生成 scanner 安全的 fixture bundle(默认 profile)
uselesskey bundle --profile scanner-safe --out target/uselesskey-bundle
# 根据记录的 manifest 和 receipts 验证 bundle
uselesskey verify-bundle target/uselesskey-bundle
# 打印人类可读的摘要,而不暴露 fixture payloads
uselesskey inspect-bundle target/uselesskey-bundle
# 从已验证的 bundle 渲染 Kubernetes / Vault payloads
uselesskey export k8s \
--bundle-dir target/uselesskey-bundle \
--name uselesskey-fixtures \
--namespace tests \
--out target/uselesskey-bundle/secret.yaml
uselesskey export vault-kv-json \
--bundle-dir target/uselesskey-bundle \
--out target/uselesskey-bundle/kv-v2.json
```
`oidc` profile 会生成一个 OIDC/JWKS contract pack,其中包含有效的 JWKS 和 JWT 形状的 fixture,以及重复的 `kid`、缺失的 `kid`、`alg: none` 和错误受众的负向变体:
```
uselesskey bundle --profile oidc --out target/uselesskey-oidc
```
有关参考 manifest、回执和 payload 形状,请参阅 [`examples/scanner-safe-bundle/README.md`](examples/scanner-safe-bundle/README.md)。有关 OIDC/JWT 验证器测试方案,请参阅 [`docs/how-to/test-oidc-jwks-validation.md`](docs/how-to/test-oidc-jwks-validation.md) 和 [`docs/how-to/test-jwt-negative-validation.md`](docs/how-to/test-jwt-negative-validation.md)。
有关对扫描器安全的、TLS、OIDC/JWKS 和 webhook profile 的任务优先列表,
请参阅 [`docs/contract-packs/README.md`](docs/contract-packs/README.md)。
## 适配器 crate
适配器 crate 是独立的包,而不是 facade feature。这使得集成版本控制变得明确,并避免了将 facade 与每个下游生态系统类型耦合在一起。
当你希望直接从 fixture 工件返回**原生第三方库类型**时,请使用它们。
### TLS 配置构建器 (`uselesskey-rustls`)
通过 `tls-config` feature,一步构建 rustls 配置:
```
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["x509"] }
uselesskey-rustls = { version = "0.9.1", features = ["tls-config", "rustls-ring"] }
```
### ring 签名密钥 (`uselesskey-ring`)
```
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa"] }
uselesskey-ring = { version = "0.9.1", features = ["all"] }
```
```
use uselesskey::{Factory, RsaFactoryExt, RsaSpec};
use uselesskey_ring::RingRsaKeyPairExt;
let fx = Factory::random();
let rsa = fx.rsa("signer", RsaSpec::rs256());
let ring_kp = rsa.rsa_key_pair_ring();
```
### RustCrypto 类型 (`uselesskey-rustcrypto`)
```
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa"] }
uselesskey-rustcrypto = { version = "0.9.1", features = ["all"] }
```
```
use uselesskey::{Factory, RsaFactoryExt, RsaSpec};
use uselesskey_rustcrypto::RustCryptoRsaExt;
let fx = Factory::random();
let rsa = fx.rsa("signer", RsaSpec::rs256());
let rsa_pk = rsa.rsa_private_key();
```
### aws-lc-rs 类型 (`uselesskey-aws-lc-rs`)
```
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["rsa"] }
uselesskey-aws-lc-rs = { version = "0.9.1", features = ["native", "all"] }
```
```
use uselesskey::{Factory, RsaFactoryExt, RsaSpec};
use uselesskey_aws_lc_rs::AwsLcRsRsaKeyPairExt;
let fx = Factory::random();
let rsa = fx.rsa("signer", RsaSpec::rs256());
let lc_kp = rsa.rsa_key_pair_aws_lc_rs();
```
### gRPC TLS (`uselesskey-tonic`)
```
[dev-dependencies]
uselesskey = { version = "0.9.1", features = ["x509"] }
uselesskey-tonic = "0.9.1"
```
```
use uselesskey::{ChainSpec, Factory, X509FactoryExt};
use uselesskey_tonic::{TonicClientTlsExt, TonicServerTlsExt};
let fx = Factory::random();
let chain = fx.x509_chain("grpc", ChainSpec::new("test.example.com"));
let server_tls = chain.server_tls_config_tonic();
let client_tls = chain.client_tls_config_tonic("test.example.com");
```
## 可运行示例
[`crates/uselesskey/examples/`](crates/uselesskey/examples/) 目录包含独立程序。由于 facade 的默认 feature 集是空的,请使用下面一个有效的 feature 集,通过 `cargo run -p uselesskey --example --features ""` 运行它们:
| 示例 | Feature(s) | 描述 |
|---------|------------|-------------|
| [adapter_jsonwebtoken](crates/uselesskey/examples/adapter_jsonwebtoken.rs) | `rsa,ecdsa,ed25519,hmac` | 使用 `jsonwebtoken` crate 集成对 JWT 进行签名和验证 |
| [adapter_rustls](crates/uselesskey/examples/adapter_rustls.rs) | `x509` | 将 X.509 fixture 转换为 rustls `ServerConfig` / `ClientConfig` |
| [basic_ecdsa](crates/uselesskey/examples/basic_ecdsa.rs) | `ecdsa,jwk` | 为 P-256 和 P-384 生成 PEM, DER, JWK 格式的 ECDSA 密钥对 |
| [basic_ed25519](crates/uselesskey/examples/basic_ed25519.rs) | `ed25519,jwk` | 生成 PEM, DER 和 JWK 格式的 Ed25519 密钥对 |
| [basic_hmac](crates/uselesskey/examples/basic_hmac.rs) | `hmac,jwk` | 为 HS256, HS384 和 HS512 生成 HMAC 密钥 |
| [basic_rsa](crates/uselesskey/examples/basic_rsa.rs) | `rsa,jwk` | 生成 PEM, DER 和 JWK 格式的 RSA 密钥对 |
| [basic_token](crates/uselesskey/examples/basic_token.rs) | `token` | 生成 API key、bearer token 和 OAuth access-token fixture |
| [basic_usage](crates/uselesskey/examples/basic_usage.rs) | `ecdsa,ed25519,rsa,jwk` | 多合一:RSA、ECDSA 和 Ed25519 fixture 生成 |
| [deterministic](crates/uselesskey/examples/deterministic.rs) | `rsa` | 从种子生成可重现的 fixture - 相同的种子总是产生相同的密钥 |
| [deterministic_mode](crates/uselesskey/examples/deterministic_mode.rs) | `rsa,ecdsa,ed25519` | 顺序无关的确定性派生保证 |
| [jwk_generation](crates/uselesskey/examples/jwk_generation.rs) | `ecdsa,ed25519,hmac,rsa,jwk` | 使用 `JwksBuilder` 跨密钥类型构建 JWK 和 JWKS |
| [jwk_jwks](crates/uselesskey/examples/jwk_jwks.rs) | `ecdsa,ed25519,hmac,rsa,jwk` | 来自多种密钥类型的 JWK 集合,支持元数据检查 |
| [jwks](crates/uselesskey/examples/jwks.rs) | `rsa,ecdsa,jwk` | 从 RSA 和 ECDSA 公钥构建 JWKS |
| [jwks_server_mock](crates/uselesskey/examples/jwks_server_mock.rs) | `rsa,ecdsa,ed25519,jwk` | 为模拟的 `/.well-known/jwks.json` endpoint 生成 JWKS 响应体 |
| [jwt_rs256_jwks](crates/uselesskey/examples/jwt_rs256_jwks.rs) | `rsa,jwk` | 提取 RSA 密钥对的 JWK/JWKS,用于 JWT 验证流程 |
| [jwt_signing](crates/uselesskey/examples/jwt_signing.rs) | `rsa,jwk` | 使用确定性的 RSA、ECDSA 和 HMAC 密钥进行 JWT 签名(ECDSA/HMAC 可选) |
| [negative_fixtures](crates/uselesskey/examples/negative_fixtures.rs) | `x509` | 用于错误路径测试的故意无效的证书和密钥 |
| [negative_payload_shapes](crates/uselesskey/examples/negative_payload_shapes.rs) | `rsa,jwk,token` | 用于验证器测试的、对扫描器安全的负向 JWK/JWKS 和 token 形状 |
| [tempfile_paths](crates/uselesskey/examples/tempfile_paths.rs) | `rsa,ed25519` | 将密钥 fixture 写入临时文件,用于基于路径的 API |
| [tempfiles](crates/uselesskey/examples/tempfiles.rs) | `x509` | 将 X.509 证书、密钥和身份 PEM 写入临时文件 |
| [tls_server](crates/uselesskey/examples/tls_server.rs) | `x509` | 用于 TLS 服务器测试的证书链生成 |
| [token_generation](crates/uselesskey/examples/token_generation.rs) | `token` | 用于测试的逼真 API key、bearer token 和 OAuth token |
| [x509_certificates](crates/uselesskey/examples/x509_certificates.rs) | `x509` | 自签名证书、证书链和负面 X.509 fixture |
## 工作区 Crate
`uselesskey` 是一个 **facade crate**,它从专注的实现 crate 中重新导出。
为了方便,可以依赖 facade,或者依赖单个 crate 以最大程度地减少编译时间。
### 实现 Crate
| Crate | 描述 |
|-------|-------------|
| [`uselesskey`](https://crates.io/crates/uselesskey) | 公共 facade — 在 feature flag 之后重新导出所有密钥类型和 trait |
| [`uselesskey-core`](https://crates.io/crates/uselesskey-core) | 工厂、确定性派生、缓存和负面 fixture 助手 |
| [`uselesskey-entropy`](https://crates.io/crates/uselesskey-entropy) | 用于扫描器安全和占位符测试的确定性高熵字节 fixture |
| [`uselesskey-rsa`](https://crates.io/crates/uselesskey-rsa) | RSA 2048/3072/4096 密钥对 (PKCS#8, SPKI, PEM, DER) |
| [`uselesskey-ecdsa`](https://crates.io/crates/uselesskey-ecdsa) | ECDSA P-256 / P-384 密钥对 |
| [`uselesskey-ed25519`](https://crates.io/crates/uselesskey-ed25519) | Ed25519 密钥对 |
| [`uselesskey-hmac`](https://crates.io/crates/uselesskey-hmac) | HMAC HS256/HS384/HS512 密钥 |
| [`uselesskey-ssh`](https://crates.io/crates/uselesskey-ssh) | 确定性的 OpenSSH 密钥和证书 fixture |
| [`uselesskey-pgp`](https://crates.io/crates/uselesskey-pgp) | OpenPGP 密钥 fixture(armored + 二进制 keyblock) |
| [`uselesskey-token`](https://crates.io/crates/uselesskey-token) | API key、bearer token 和 OAuth access-token fixture |
| [`uselesskey-webhook`](https://crates.io/crates/uselesskey-webhook) | 用于 GitHub、Stripe 和 Slack 签名测试的确定性 webhook fixture |
| [`uselesskey-jwk`](https://crates.io/crates/uselesskey-jwk) | 类型化的 JWK/JWKS 模型和构建器 |
| [`uselesskey-x509`](https://crates.io/crates/uselesskey-x509) | X.509 自签名证书和证书链 |
| [`uselesskey-cli`](https://crates.io/crates/uselesskey-cli) | 命令行 fixture 生成、打包和导出助手 |
| [`uselesskey-test-server`](https://crates.io/crates/uselesskey-test-server) | 确定性的 OIDC 发现和 JWKS HTTP 测试服务器 fixture |
| [`uselesskey-pkcs11-mock`](https://crates.io/crates/uselesskey-pkcs11-mock) | 用于 HSM/提供者集成测试的 PKCS#11 模拟提供者 fixture |
| [`uselesskey-webauthn`](https://crates.io/crates/uselesskey-webauthn) | 用于 passkey 测试的 WebAuthn 凭据和断言 fixture |
### 适配器 Crate
| Crate | 描述 |
|-------|-------------|
| [`uselesskey-axum`](https://crates.io/crates/uselesskey-axum) | `axum` auth 测试助手,带有确定性的 JWKS/OIDC 路由 |
| [`uselesskey-jsonwebtoken`](https://crates.io/crates/uselesskey-jsonwebtoken) | `jsonwebtoken` `EncodingKey` / `DecodingKey` |
| [`uselesskey-rustls`](https://crates.io/crates/uselesskey-rustls) | `rustls` `ServerConfig` / `ClientConfig` 构建器 |
| [`uselesskey-tonic`](https://crates.io/crates/uselesskey-tonic) | 用于 gRPC 的 `tonic::transport` TLS 身份 / 配置 |
| [`uselesskey-ring`](https://crates.io/crates/uselesskey-ring) | `ring` 0.17 原生签名密钥类型 |
| [`uselesskey-rustcrypto`](https://crates.io/crates/uselesskey-rustcrypto) | RustCrypto 原生类型(`rsa::RsaPrivateKey` 等) |
| [`uselesskey-aws-lc-rs`](https://crates.io/crates/uselesskey-aws-lc-rs) | `aws-lc-rs` 原生类型 |
## Feature Flag
`uselesskey` facade 默认不启用任何 feature。
按 feature 划分的扩展 trait:
- `rsa`: `RsaFactoryExt`
- `ecdsa`: `EcdsaFactoryExt`
- `ed25519`: `Ed25519FactoryExt`
- `hmac`: `HmacFactoryExt`
- `pgp`: `PgpFactoryExt`
- `token`: `TokenFactoryExt`
- `x509`: `X509FactoryExt`
对于输出系列的覆盖范围和依赖影响,请使用下面的矩阵。
## Feature 矩阵
### Facade feature(`uselesskey` crate)
| Feature | 扩展 Trait | 算法 / 输出 | 隐含 |
|---------|----------------|---------------------|---------|
| `rsa` | `RsaFactoryExt` | RSA 2048/3072/4096 — PKCS#8, SPKI, PEM, DER | — |
| `ecdsa` | `EcdsaFactoryExt` | P-256 (ES256), P-384 (ES384) — PKCS#8, SPKI | — |
| `ed25519` | `Ed25519FactoryExt` | Ed25519 — PKCS#8, SPKI | — |
| `hmac` | `HmacFactoryExt` | HS256, HS384, HS512 | — |
| `pgp` | `PgpFactoryExt` | OpenPGP RSA 2048/3072, Ed25519 — armored, binary | — |
| `token` | `TokenFactoryExt` | API key、bearer access token 和 OAuth access token | — |
| `x509` | `X509FactoryExt` | 自签名证书、证书链、负面证书 | `rsa` |
| `jwk` | — | 为所有启用的密钥类型提供 JWK/JWKS 输出 | — |
| `all-keys` | — | (bundle) | `rsa` `ecdsa` `ed25519` `hmac` `pgp` |
| `full` | — | (everything) | `all-keys` `token` `x509` `jwk` |
### 适配器 crate 的密钥类型支持
每个适配器 crate 都有针对特定算法的 feature flag(`rsa`, `ecdsa`, `ed25519`, `hmac`)以及一个方便的 `all` flag。
| 适配器 | RSA | ECDSA | Ed25519 | HMAC | X.509 / TLS | 额外 feature |
|---------|:---:|:-----:|:-------:|:----:|:-----------:|----------------|
| `uselesskey-jsonwebtoken` | ✓ | ✓ | ✓ | ✓ | — | — |
| `uselesskey-ring` | ✓ | ✓ | ✓ | — | — | — |
| `uselesskey-rustcrypto` | ✓ | ✓ | ✓ | ✓ | — | — |
| `uselesskey-aws-lc-rs` | ✓ | ✓ | ✓ | — | — | `native (enables aws-lc-rs dep)` |
| `uselesskey-rustls` | ✓ | ✓ | ✓ | — | ✓ | `tls-config, rustls-ring, rustls-aws-lc-rs` |
| `uselesskey-tonic` | — | — | — | — | ✓ | — |
## 为什么选择这个 crate
### 顺序无关的确定性
Fixture 派生自稳定的身份组件:
```
seed + (domain, label, spec, variant) -> derived seed -> artifact
```
添加新的 fixture 不会干扰现有的。测试顺序并不重要。
### 按身份缓存
RSA 密钥生成开销很大。基于 `(domain, label, spec, variant)` 的每个工厂缓存使得运行时生成成本足够低,足以取代提交的 fixture。
### 形状优先的输出
首先要求形状:PKCS#8, SPKI, PEM, DER, JWK, JWKS 或临时文件。
使用者要求的是工件形状;低级加密原语故意不作为默认输出。
### 第一类负面工件
损坏的 PEM、截断的 DER、不匹配的密钥、过期的证书、带有RL 的吊销叶子:这些正是团队否则需要手工制作并提交的工件。
`uselesskey` 使它们变得具有确定性、低成本且可随意丢弃。
## 何时不使用此 crate
- 生产密钥生成
- 运行时证书颁发机构行为
- 证书验证逻辑
- HSM / TPM / 硬件支持的密钥
- 以签名或验证 API 作为主要抽象
对于运行时证书生成,请直接使用 `rcgen`。对于验证,请使用 `rustls`、`x509-parser` 或实际负责验证的库。
## 生态系统
当你需要**不应存在于 git 历史记录中的真实测试 fixture** 时,请使用 `uselesskey`。
在以下情况寻求其他工具:
- 当你需要在以 fixture 为中心的工作流之外进行运行时证书生成时,请选择 `rcgen`
- 当你需要 TLS 运行时集成和验证时,请选择 `rustls`
- 当你需要解析/检查/验证工作时,请选择 `x509-parser`
## 社区
- [CHANGELOG](CHANGELOG.md) — 发布历史
- [CONTRIBUTING](CONTRIBUTING.md) — 如何构建、测试和添加新的密钥类型
- [SECURITY](SECURITY.md) — 安全策略(这是一个仅供测试的 crate)
- [CODE_OF_CONDUCT](CODE_OF_CONDUCT.md) — Contributor Covenant
- [SUPPORT](SUPPORT.md) — 如何获取帮助
## 稳定性和版本控制
**派生稳定性**
在同一个 `DerivationVersion` 中,给定 `(seed, domain, label, spec, variant)` 元组的工件是稳定的。
如果派生逻辑发生变化,将引入新的派生版本,而不是改变旧版本。
**Semver**
破坏性 API 更改在 `1.0` 之前会提升 minor 版本,之后则提升 major 版本。
**MSRV**
最低支持的 Rust 版本为 **1.95**(2024 edition)。
## 许可证
根据以下任一许可证授权:
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))
- MIT license ([LICENSE-MIT](LICENSE-MIT))
由你选择。标签:Rust, 加密测试数据, 可视化界面, 开发辅助, 文档结构分析, 测试夹具, 测试工具, 网络流量审计, 证书生成, 通知系统