KarpelesLab/purecrypto
GitHub: KarpelesLab/purecrypto
一个纯 Rust、无 C 依赖的 no_std 密码学工具包,从 constant-time 原语到后量子算法、X.509 和 TLS/DTLS/QUIC 协议栈提供完整的加密能力。
Stars: 1 | Forks: 0
# purecrypto
[](https://github.com/KarpelesLab/purecrypto/actions/workflows/ci.yml)
[](https://crates.io/crates/purecrypto)
[](https://docs.rs/purecrypto)
[](LICENSE)
一个**完全使用 Rust** 编写的密码学工具包,不依赖任何外部
代码。`purecrypto` 是从零开始构建的 —— 从 constant-time
原语开始,向上涵盖哈希、密码、大数运算、
经典和后量子非对称堆栈、ASN.1、X.509 和 TLS —— 并且
可通过三种方式使用:
- 作为 **Rust 库**,
- 作为 **C 库**(具有 C ABI 的 `cdylib`),以及
- 作为 **独立命令行工具**(`purecrypto`:哈希、随机数、密钥
生成(包括 PQ)、CSR、小型 CA、TLS / DTLS / QUIC 测试客户端
和服务器等)。
这是一个具有类似 OpenSSL 广度的**模块化**工具包 —— 但与单体
二进制依赖不同,每个算法和协议层都由 feature 控制(基于
`#![no_std]` 核心),因此应用程序只需编译其所需的部分。
## 文档
- **[安全策略](SECURITY.md)** — 如何报告漏洞;保证状态。
- **[验证与保证矩阵](docs/validation.md)** — 每个模块:测试
向量、互操作目标、模糊测试、负输入覆盖、constant-time
姿态、已知限制。
- **[推荐用法](docs/recommended-usage.md)** — 固执己见的*安全
路径*:受认可默认值 vs 仅兼容 vs hazmat。
- **[威胁模型](docs/threat-model.md)** — 防御什么和不防御什么。
- **[基准测试](docs/benchmarks.md)** — 真实的每种算法的数字 + 其背后的
constant-time 权衡。
## 设计原则
- **无外部代码。** 没有 C,没有从其他库中提取的汇编,也没有
第三方 crypto crate。一切都在这里用 Rust 实现。
- **默认 constant-time。** 依赖于秘密的值通过
[`ct`](src/ct) 层(无分支相等、选择、排序)流动,以便上层
避免计时侧信道。当算法本质上不是
constant-time(RSA 密钥生成、模逆)时,它仅用于
一次性/密钥生成路径,并已记录在案。
- **`no_std` 核心。** crate 是 `#![no_std]`;`alloc` 和 `std` 是可选的
特性(`std` 是默认项并暗示 `alloc`)。
- **经验证。** 只要标准发布了测试向量,我们就会运行它们 —— RFC
8439、RFC 8032、RFC 8448、FIPS 203/204/205 ACVP —— 并与 OpenSSL 3.5 交叉验证 X.509
/ TLS / PQC 堆栈。
## 布局
单个 crate,模块由 Cargo 特性控制:
| 层级 | 模块 | 状态 |
| ---------------- | ----------- | ------ |
| Constant-time | `ct` | 已实现 |
| 哈希 | `hash` | SHA-2, SHA-3 + Keccak-256, SHAKE/cSHAKE/KMAC/TupleHash/ParallelHash, TurboSHAKE/KangarooTwelve/MarsupilamiFourteen, BLAKE2b/2s (+keyed/X), BLAKE3, SM3, Whirlpool (ISO/IEC 10118-3), Streebog-256/512 (GOST R 34.11-2012), MD2/MD4/MD5/SHA-1/RIPEMD-160; HMAC + `Mac` trait (constant-time 验证, drop-zeroizing)。Ascon-Hash256/XOF128/CXOF128 位于 `ascon` 中 |
| 随机数 | `rng` | RngCore/CryptoRng, HMAC-DRBG (NIST SP 800-90A), OsRng (Unix + Windows) |
| 对称密码 | `cipher` | AES-128/192/256 (constant-time, 无表); SM4 (GB/T 32907, constant-time, 无表); CBC/CFB/OFB/CTR; GCM, CCM, ChaCha20-Poly1305, XChaCha20-Poly1305, AEGIS-128L/256, AES-GCM-SIV (RFC 8452) 和 AES-SIV (RFC 5297, 抗 nonce 误用) (AEAD); XTS (磁盘加密); AES-KW + AES-KWP (RFC 3394 / 5649); DES + 3-DES (EDE3 / EDE2) 配合 `Cbc64` 用于旧版互操作。Ascon-AEAD128 位于 `ascon` 中,AEZ v5 (健壮的 AE) 位于 `aez` 中 |
| MAC | `mac` | AES-CMAC (RFC 4493); GMAC (NIST SP 800-38D); UMAC-64 / UMAC-128 (RFC 4418); HMAC 位于 `hash` 中 |
| 大数 (CT) | `bignum` | `Uint` 和运行时确定大小的 `BoxedUint`,加宽乘法,Montgomery 模运算,modexp,Fermat & 扩展欧几里得逆元 |
| 非对称密钥 | `rsa` | RSA 密钥生成(编译时 + 运行时,512–65536 位),原始,PKCS#1 v1.5 加密/签名,OAEP 加密,PSS 签名/验证,PKCS#1 DER/PEM |
| 密钥派生 | `kdf` | PBKDF2, HKDF, scrypt (RFC 7914), Argon2id/2d/2i (RFC 9106), SP 800-108 KBKDF(计数器 + 反馈,HMAC/CMAC PRF)|
| 椭圆曲线 | `ec` | P-256/P-384/P-521/secp256k1 上的 ECDSA/ECDH(运行时多曲线)+ 快速常量泛型 P-256,X25519,Ed25519 (EdDSA, RFC 8032),X448 (RFC 7748),Ed448 (EdDSA, RFC 8032),SM2 签名 + 加密(GB/T 32918 / RFC 8998)|
| 素数阶群 | `ristretto255` | ristretto255 (RFC 9496),一个稳定的素数阶群 API;用于阈值/FROST 调用者的低级标量/点算术也通过 `hazmat-secp256k1` / `hazmat-edwards25519` / `hazmat-mldsa` 暴露(`hazmat-*` **不保证 semver**)|
| 后量子 KEM | `mlkem` | ML-KEM-512 / 768 / 1024 (FIPS 203),`no_std`/no-alloc;在 -768 上与 OpenSSL 互操作 |
| 后量子签名 | `mldsa` | ML-DSA-44/65/87 (FIPS 204);hedged + deterministic;FIPS 204 ACVP + OpenSSL 互操作 |
| 后量子签名 | `slhdsa` | SLH-DSA,全部 12 套 (FIPS 205, SHA-2/SHAKE × 128/192/256 × s/f);FIPS 205 ACVP + OpenSSL 互操作 |
| 有状态 HBS | `lms` | LMS / HSS (RFC 8554, NIST SP 800-208); LM-OTS W{1,2,4,8} × LMS H{5,10,15,20,25}; **有状态**推进密钥; RFC 8554 KATs |
| 有状态 HBS | `xmss` | XMSS / XMSS^MT (RFC 8391, NIST SP 800-208); **有状态**推进密钥; RFC 8391 / 参考 KATs |
| 轻量级 | `ascon` | Ascon (NIST SP 800-232): Ascon-AEAD128 + Ascon-Hash256 / XOF128 / CXOF128 基于一个 320 位排列 |
| Diffie-Hellman | `dh` | 基于 RFC 3526 MODP 群 (group14..group18) + RFC 4419 群交换的有限域 DH,用于 SSH / 旧版 TLS / IKE 互操作(新代码:使用 `ec` 中的 ECDH)|
| 统一密钥 | `key` | 对象安全的 `PrivateKey`/`PublicKey` 外观 —— `sign`/`decrypt`/`agree`,`verify`/`encrypt` —— 适用于每种非对称密钥,具有消耗时检查的参数(不支持的参数会显式失败)和通用 PKCS#8/SPKI 解码器(`AnyPrivateKey`/`AnyPublicKey`,它们本身也是外观密钥);通过 `StatefulSigner` 实现有状态 XMSS/LMS,通过 `Encapsulator`/`Decapsulator` 实现 KEM |
| ASN.1 / DER | `der` | DER 读取器/写入器,base64,PEM |
| X.509 | `x509` | 自签名 + CA 签发(RSA、ECDSA、Ed25519 和 Ed448),PKCS#10 CSR,解析,验证;PKIX SPKI;RFC 5280 nameConstraints 跨链执行;OpenSSL 互操作 |
| TLS | `tls` | TLS 1.2 和 1.3,DTLS 1.2 和 1.3 客户端 + 服务器(sans-I/O 核心 + 阻塞 `Stream`);x25519/secp256r1 + X25519MLKEM768 混合 (1.3); AES-GCM & ChaCha20-Poly1305; Ed25519/Ed448/ECDSA/RSA 认证; ALPN, record_size_limit (RFC 8449), TLS-Exporter (RFC 5705); 具有抗重放窗口的 PSK 会话恢复 + 0-RTT (early_data) (1.3); RFC 5077 会话票据 (1.2); mTLS / 客户端证书身份验证; HelloRetryRequest (客户端 + 服务器); 双向 KeyUpdate; RFC 8448 KATs; DTLS HelloVerifyRequest / cookie DoS 防护,握手分段 + 重组,64 位滑动窗口抗重放;DTLS 1.3 加密序列号 + ACK 驱动重传。 |
| HPKE | `hpke` | RFC 9180 混合公钥加密 — 4 KEMs × 3 KDFs × 3 AEADs + ExportOnly,全部四种模式 (Base/PSK/Auth/AuthPSK) |
| ECH | `ech` | draft-ietf-tls-esni-22 加密客户端 Hello — 客户端 + 服务器,retry_configs,HRR 确认信号,bit-shape GREASE |
| QUIC | `quic` | QUIC v1 (RFC 9000) + QUIC-TLS (RFC 9001) + 恢复 / 拥塞 (RFC 9002) + DATAGRAM 扩展 (RFC 9221),sans-I/O |
| 证书压缩 | `cert-compression` | RFC 8879 TLS 1.3 证书压缩(通过 `compcol` 兄弟 crate 实现 zlib)|
| 旧版 TLS | `tls-legacy` | ⚠️ **已弃用/不安全,默认关闭** — SSL 3.0 / TLS 1.0 / TLS 1.1 (RFC 8996) 使用 CBC MAC-then-encrypt 套件(`TLS_RSA_*` 静态 RSA + 基于 AES-CBC-SHA/SHA256 + 3DES 的 `TLS_ECDHE_RSA_*`),客户端 + 服务器。仅作为最后的互操作性手段(例如 VoIP 电话预配);需要降低 `Config::min_version`。包含 BEAST 1/n-1 分割 + constant-time CBC 解密,但 MD5/SHA-1 PRF、Lucky13 残留和 SSLv3 POODLE 仍然存在 —— 请勿用于现代对等点。 |
| C ABI | `ffi` | 哈希/HMAC + AES-CMAC + GMAC,KBKDF,R,AEAD(包括 AEGIS、Ascon)+ AES-KW,RSA,ECDSA,Ed25519,Ed448,X25519,X448,SM2,ML-KEM,ML-DSA,SLH-DSA,LMS/XMSS,X.509,TLS / DTLS / QUIC (sans-I/O);不透明句柄 + 调用者缓冲区;`include/purecrypto.h` |
| CLI | (binary) | `hash`/`dgst`, `mac`, `kdf`, `enc`, `rand`, `genpkey` (经典 + PQ), `pkey`, `pkeyutl`, `kem`, `kex`, `req`, `x509`, `ca`, `crl`, `s_client`, `s_server`, `s_dtls_client`, `s_dtls_server`, `q_client`, `q_server` |
## CLI + C-API 覆盖矩阵
以下每个功能区域都可以从 Rust 库、
`purecrypto` CLI 和 C ABI(`include/purecrypto.h`)调用。
| 区域 | CLI | C API |
| ------------------------------------- | ------------------------------------ | ------------------------------------------------------------------ |
| 哈希 (SHA-2/3, BLAKE2/3, SM3, Ascon, …) | `hash` | `pc_digest`, `pc_hash_*`, `pc_ascon_xof`/`pc_ascon_cxof` |
| HMAC (SHA-1, SHA-2, SHA-3, SM3, …) | `mac` | `pc_hmac` |
| AES-CMAC (RFC 4493) | `mac -alg cmac` | `pc_cmac` |
| GMAC (NIST SP 800-38D) | `mac -alg gmac -nonce …` | `pc_gmac` |
| KDFs (HKDF, PBKDF2, scrypt, Argon2) | `kdf hkdf\|pbkdf2\|scrypt\|argon2` | `pc_hkdf`, `pc_pbkdf2`, `pc_scrypt`, `pc_argon2` |
| KBKDF (SP 800-108, counter/feedback) | `kdf kbkdf` | `pc_kbkdf_counter`, `pc_kbkdf_feedback` |
| AEAD (AES-GCM/CCM, ChaCha20-Poly1305, XChaCha20-Poly1305, AES-GCM-SIV, AES-SIV, AEGIS-128L/256, Ascon-AEAD128) | `enc` | `pc_aead_encrypt`, `pc_aead_decrypt` |
| AES 密钥封装 (RFC 3394/5649) | `enc -alg AES-KW\|AES-KWP` | `pc_aes_kw_wrap/unwrap`, `pc_aes_kwp_wrap/unwrap` |
| 随机数 | `rand` | `pc_rand_bytes` |
| RSA 密钥生成 + PKCS#1 签名/验证 | `genpkey`, `req`, `x509`, `pkeyutl` | `pc_rsa_generate`, `pc_rsa_sign_pkcs1`, `pc_rsa_verify_pkcs1` |
| RSA-PSS 签名/验证 | `pkeyutl sign/verify -pkeyopt pss` | `pc_rsa_sign_pss`, `pc_rsa_verify_pss` |
| RSA-OAEP 加密/解密 | `pkeyutl encrypt/decrypt -pkeyopt oaep` | `pc_rsa_encrypt_oaep`, `pc_rsa_decrypt_oaep` |
| ECDSA 密钥生成 + 签名/验证 | `genpkey -alg EC`, `pkeyutl` | `pc_ec_generate`, `pc_ec_sign`, `pc_ec_verify` |
| Ed25519 签名/验证 | `genpkey -alg ED25519`, `pkeyutl` | `pc_ed25519_*` |
| Ed448 签名/验证 | `genpkey -alg ED448`, `pkeyutl` | `pc_ed448_*` |
| SM2 签名/验证 + 加密/解密 | `genpkey -alg SM2`, `pkeyutl` | `pc_sm2_*` |
| NIST 曲线上的 ECDH | `kex -alg ECDH-P{256,384,521}` | `pc_ecdh` |
| X25519 | `kex -alg X25519` | `pc_x25519`, `pc_x25519_public` |
| X448 | `kex -alg X448` | `pc_x448`, `pc_x448_public` |
| ML-KEM (FIPS 203) | `kem keygen\|encaps\|decaps` | `pc_mlkem_*` |
| ML-DSA (FIPS 204) | `pkeyutl sign/verify` (ML-DSA 密钥) | `pc_mldsa_*` |
| SLH-DSA (FIPS 205) | `pkeyutl sign/verify` (SLH-DSA 密钥) | `pc_slhdsa_*` |
| LMS / HSS (RFC 8554, 有状态) | `genpkey -alg LMS-…\|HSS-…`, `pkeyutl` | `pc_lms_*`, `pc_hss_*` |
| XMSS / XMSS^MT (RFC 8391, 有状态) | `genpkey -alg XMSS-…\|XMSSMT-…`, `pkeyutl` | `pc_xmss_*`, `pc_xmssmt_*` |
| CSR (PKCS#10) | `req` | `pc_csr_create_rsa`, `pc_csr_from_pem`, `pc_csr_verify_self_signed`|
| X.509 证书解析 + 验证 | `x509`, `ca` | `pc_cert_*`, `pc_ec_self_signed_pem` |
| CRL 解析 + 验证 | `crl` | `pc_crl_*` |
| TLS 1.2 / 1.3 客户端 + 服务器 | `s_client`, `s_server` | `pc_tls_cfg_*`, `pc_tls_*` (memory-BIO 风格) |
| DTLS 1.2 / 1.3 客户端 + 服务器 | `s_dtls_client`, `s_dtls_server` | `pc_tls_cfg_*` (`PC_DTLS_1_*` 选择器), `pc_dtls_next_timeout/on_timeout` |
| QUIC v1 客户端 + 服务器 | `q_client`, `q_server` | `pc_quic_cfg_*`, `pc_quic_*` (sans-I/O, datagram in/out + streams) |
对于 TLS/DTLS,C ABI 是 sans-I/O 的:调用者通过
`pc_tls_feed` / `pc_tls_pop` 传输网络字节,并通过 `pc_tls_send` /
`pc_tls_recv` 传输应用字节(镜像 OpenSSL 的 `BIO_s_mem`)。
## Cargo 特性
默认为 `std + cli`,并且大多数模块处于开启状态。少数是可选的:`quic`、`hpke`、
`ech`、`falcon`、`tls-legacy`、`ristretto255`、`ffi` C ABI,以及
`tokio` / `mio` I/O 适配器。禁用默认项以进行 `no_std` 构建并
仅重新启用您需要的:
```
# 纯 no_std,无 allocator:仅包含 `ct` 和适用的 primitives。
purecrypto = { version = "0.6", default-features = false }
# no_std 核心 + ML-KEM-768(无 alloc):
purecrypto = { version = "0.6", default-features = false, features = ["mlkem"] }
# 仅包含 PQ 签名的库:
purecrypto = { version = "0.6", default-features = false, features = ["mldsa", "slhdsa"] }
```
模块开关:`hash`、`cipher`、`mac`、`kdf`、`bignum`、`rng`、
`linux-getrandom`、`rsa`、`dh`、`der`、`ec`、`key`、`ristretto255`、`x509`、
`pkcs12`、`tls`、`dtls`、`tls-legacy`、`quic`、`mlkem`、`mldsa`、`slhdsa`、
`falcon`、`lms`、`xmss`、`ascon`、`aez`、`hpke`、`ech`、`cert-compression`、
`embedded-roots`、`ffi`、`cli`(加上 `tokio` / `mio` I/O 适配器)—— 外加
不稳定的 `hazmat-secp256k1` / `hazmat-edwards25519` / `hazmat-mldsa` 开关
(不保证 semver)。
每个模块仅引入其自身的依赖项。任何需要
堆的东西都需要 `alloc`(除了 `ct`、`hash`、`cipher` 和无 `alloc` 的
`mlkem` 核心外的大多数东西)。
## 构建
```
cargo build # default: std + CLI binary
cargo build --no-default-features # bare no_std
cargo build --no-default-features --features alloc # no_std + alloc
cargo test # full suite
cargo test --release -- --ignored # heavy KATs (SLH-DSA 's' sets, RSA keygen)
```
需要 Rust 1.88+(2024 版);MSRV 声明为 `rust-version =
"1.88"` 并在 CI 中强制执行。
## 命令行工具
`purecrypto` 二进制文件(默认构建;或者 `cargo build --features cli`)。
每个子命令在未指定 `-in` 时读取 `stdin`,并在未指定 `-out` 时写入
`stdout`,因此命令可以通过管道组合。
### `hash` — 消息摘要
```
purecrypto hash sha256 file.txt # one-shot digest
echo -n abc | purecrypto hash sha3-256 # any algorithm from the `hash` module
```
算法:`sha224`、`sha256`、`sha384`、`sha512`、`sha512-224`、`sha512-256`、
`sha3-224`、`sha3-256`、`sha3-384`、`sha3-512`、`keccak256`、`blake2b256`、
`blake2b384`、`blake2b512`、`blake2s256`、`blake3`、`m14`、`sm3`、`whirlpool`、
`streebog256`、`streebog512`、`sha1`、`md2`、`md5`、`ripemd160`。(XOF
`shake128`/`shake256` 以及 BLAKE2X/cSHAKE/KMAC 变体通过
Rust 库公开,而不是通过 CLI。)
### `rand` — 随机数
```
purecrypto rand 32 # 32 random bytes as hex
purecrypto rand 16 --binary # raw bytes to stdout
```
### `genpkey` — 密钥生成(经典和后量子)
```
# Classical
purecrypto genpkey -algorithm RSA -bits 2048 -out rsa.pem # also 3072, 4096
purecrypto genpkey -algorithm RSA -bits 8192 -out rsa8k.pem # any even size, 512..=65536
purecrypto genpkey -algorithm EC -curve P-256 -out ec.pem # or P-384, P-521, secp256k1
purecrypto genpkey -algorithm ED25519 -out ed.pem
# Post-quantum signatures (FIPS 204 / FIPS 205)
purecrypto genpkey -algorithm ML-DSA-44 -out mldsa44.pem
purecrypto genpkey -algorithm ML-DSA-65 -out mldsa65.pem
purecrypto genpkey -algorithm ML-DSA-87 -out mldsa87.pem
purecrypto genpkey -algorithm SLH-DSA-SHA2-128f -out slh128f.pem
purecrypto genpkey -algorithm SLH-DSA-SHAKE-256s -out slh256s.pem
# Post-quantum KEM (FIPS 203) — 所有三个安全级别
purecrypto genpkey -algorithm ML-KEM-512 -out mlkem512.pem
purecrypto genpkey -algorithm ML-KEM-768 -out mlkem768.pem
purecrypto genpkey -algorithm ML-KEM-1024 -out mlkem1024.pem
```
支持完整的 SLH-DSA 矩阵:
`SLH-DSA-{SHA2,SHAKE}-{128,192,256}{s,f}`(12 个参数集)。
输出格式:
- RSA → `-----BEGIN RSA PRIVATE KEY-----` (PKCS#1)
- EC → `-----BEGIN EC PRIVATE KEY-----` (SEC1)
- Ed25519 / ML-DSA / ML-KEM / SLH-DSA → `-----BEGIN PRIVATE KEY-----` (PKCS#8,
算法由嵌入的 OID 标识)
### `pkey` — 检查或转换密钥
```
purecrypto pkey -in key.pem -text # describe the key
purecrypto pkey -in key.pem -pubout # emit the SPKI public-key PEM
purecrypto pkey < key.pem # re-emit the private key (round-trip)
```
`pkey` 自动检测每种受支持的类型(RSA PKCS#1、EC SEC1 以及上述
PKCS#8 类型),并根据嵌入的 OID 为 PKCS#8 输入进行路由。
### `req` — PKCS#10 证书签名请求
```
purecrypto req -key leaf.pem -subj "/CN=leaf.example/O=Acme" \
-addext "subjectAltName=DNS:leaf.example,DNS:www.leaf.example" \
-out leaf.csr
purecrypto req -in leaf.csr -verify # check the CSR self-signature
```
### `x509` — 自签名证书和小型 CA
```
# 构建一个自签名 CA 证书
purecrypto x509 -new --ca -key ca.pem -subj "/CN=Internal CA" -out ca.crt
# 从 CSR 签发一个叶子证书
purecrypto x509 -req -in leaf.csr -CA ca.crt -CAkey ca.pem -out leaf.crt
# 检查证书
purecrypto x509 -in leaf.crt -text
```
### `s_client` — TLS 1.3 测试客户端
```
purecrypto s_client -connect example.com:443
purecrypto s_client -connect 127.0.0.1:8443 -CAfile ca.crt -servername leaf.example
purecrypto s_client -connect 127.0.0.1:8443 -insecure -quiet # skip cert verify, stdin → server
# 通过 ALPN 协商 HTTP/2(或回退至 http/1.1)
purecrypto s_client -connect example.com:443 -alpn h2,http/1.1
# 以 NSS SSLKEYLOGFILE 格式导出协商的密钥 — Wireshark 可以
# 随后解密捕获的 pcap。
purecrypto s_client -connect example.com:443 -keylogfile sslkeys.log
# 出示客户端证书(mTLS)。密钥可以是 Ed25519 (PKCS#8) 或
# ECDSA (SEC1)。
purecrypto s_client -connect server:443 -cert client.pem -key client.key
```
客户端首先提供 `X25519MLKEM768`(后量子混合),然后是 `x25519`
和 `secp256r1`;所有三个 TLS 1.3 密码套件
(`TLS_AES_128_GCM_SHA256`、`TLS_AES_256_GCM_SHA384`、
`TLS_CHACHA20_POLY1305_SHA256`);以及 Ed25519、Ed448、ECDSA 和 RSA 对等方签名。
### `s_server` — TLS 1.3 echo / `-www` 服务器
一次性测试服务器:它绑定并接受一个连接,执行
握手,交换数据,然后退出。
```
# 纯 TLS echo:
purecrypto s_server -cert server.pem -key server.key -accept 4433
# 为单个请求提供一个固定的 HTTP 响应(text/plain):
purecrypto s_server -cert server.pem -key server.key -accept 4433 -www
# 协商 ALPN,监听 8443 端口:
purecrypto s_server -cert server.pem -key server.key -accept 8443 -alpn h2,http/1.1
# mTLS:根据 `client-ca.pem` 中的 bundle 要求并验证客户端证书。
purecrypto s_server -cert server.pem -key server.key -accept 8443 \
-Verify client-ca.pem
```
### TLS 1.2
`s_client` / `s_server` 默认为 TLS 1.3。在任一端传递 `-tls1_2`
以强制使用 TLS 1.2。TLS 1.2 路径仅限 ECDHE-AEAD(AES-GCM 和
ChaCha20-Poly1305),并支持 mTLS 以及 RFC 5077 会话票据。
```
# 服务端(TLS 1.2)
purecrypto s_server -tls1_2 -accept 0.0.0.0:4443 -cert cert.pem -key key.pem
# 客户端(TLS 1.2)
purecrypto s_client -tls1_2 -connect example.com:443 -CAfile roots.pem
```
### DTLS — `s_dtls_client` / `s_dtls_server`
DTLS 通过 UDP 运 TLS 握手。既可以使用专用的
`s_dtls_client` / `s_dtls_server` 二进制文件,也可以向
`s_client` / `s_server` 传递 `-dtls1_2` / `-dtls1_3`。这两种形式是等效的。
```
# DTLS 1.2 echo
purecrypto s_dtls_server -dtls1_2 -accept 0.0.0.0:5684 -cert cert.pem -key key.pem
purecrypto s_dtls_client -dtls1_2 -connect localhost:5684
# DTLS 1.3 echo
purecrypto s_dtls_server -dtls1_3 -accept 0.0.0.0:5685 -cert cert.pem -key key.pem
purecrypto s_dtls_client -dtls1_3 -connect localhost:5685
# 通过带有版本标志的 s_client / s_server 实现等效操作
purecrypto s_server -dtls1_3 -accept 0.0.0.0:5685 -cert cert.pem -key key.pem
purecrypto s_client -dtls1_3 -connect localhost:5685
```
DTLS 服务器在分配任何按连接
状态之前,建立 HelloVerifyRequest cookie 交换 (1.2) 或
HelloRetryRequest cookie (1.3),并且一旦握手保护密钥
就位,双向都会安装 64 位滑动窗口重放
过滤器。默认记录大小为 1200 字节,以保持在常见路径 MTU 之下;使用
`-mtu` 覆盖。
### QUIC — `q_client` / `q_server`
基于 UDP 的 QUIC v1 (RFC 9000),由 TLS 1.3 密钥 (RFC 9001) 保护。既可以使用
专用二进制文件,也可以向 `s_client` / `s_server` 传递 `-quic` —— 这两种
形式是等效的。客户端驱动一个双向流
(stdin → server, reply → stdout);不可靠的 DATAGRAM 扩展
(RFC 9221) 可通过库 API 访问。
```
purecrypto q_server -accept 0.0.0.0:4434 -cert cert.pem -key key.pem -alpn h3
purecrypto q_client -connect localhost:4434 -alpn h3
```
### 实用手册
使用 EC 密钥的端到端 CA + 叶子节点:
```
purecrypto genpkey -algorithm EC -curve P-256 -out ca.pem
purecrypto x509 -new --ca -key ca.pem -subj "/CN=My CA" -out ca.crt
purecrypto genpkey -algorithm EC -curve P-256 -out leaf.pem
purecrypto req -key leaf.pem -subj "/CN=leaf.example" \
-addext "subjectAltName=DNS:leaf.example" -out leaf.csr
purecrypto x509 -req -in leaf.csr -CA ca.crt -CAkey ca.pem -out leaf.crt
```
后量子签名密钥及其公钥对应物:
```
purecrypto genpkey -algorithm ML-DSA-65 -out mldsa.pem
purecrypto pkey -in mldsa.pem -text # ML-DSA-65 private key
purecrypto pkey -in mldsa.pem -pubout > mldsa.pub.pem # PKIX SPKI
```
单主机上的双进程 mTLS 握手(向服务器提供客户端证书,
双方密钥均为 Ed25519):
```
# CA + 服务端证书 + 客户端证书
purecrypto genpkey -algorithm ED25519 -out ca.pem
purecrypto x509 -new --ca -key ca.pem -subj "/CN=Local CA" -out ca.crt
purecrypto genpkey -algorithm ED25519 -out server.pem
purecrypto req -key server.pem -subj "/CN=127.0.0.1" \
-addext "subjectAltName=DNS:127.0.0.1" -out server.csr
purecrypto x509 -req -in server.csr -CA ca.crt -CAkey ca.pem -out server.crt
purecrypto genpkey -algorithm ED25519 -out client.pem
purecrypto req -key client.pem -subj "/CN=alice" -out client.csr
purecrypto x509 -req -in client.csr -CA ca.crt -CAkey ca.pem -out client.crt
# 在一个终端中 — 服务端根据 ca.crt 要求并验证客户端证书:
purecrypto s_server -cert server.crt -key server.pem -accept 8443 -Verify ca.crt -www
# 在另一个终端中 — 客户端出示其证书 + 密钥:
purecrypto s_client -connect 127.0.0.1:8443 -CAfile ca.crt \
-cert client.crt -key client.pem -alpn http/1.1 \
-keylogfile keys.log
```
## 库用法
符合惯例的 Rust API —— 有关
完整参考,请参见 [docs.rs/purecrypto](https://docs.rs/purecrypto)。以下是一些常见模式:
```
use purecrypto::hash::{Digest, Sha256};
let d = Sha256::digest(b"abc");
use purecrypto::ec::Ed25519PrivateKey;
use purecrypto::rng::OsRng;
let sk = Ed25519PrivateKey::generate(&mut OsRng);
let sig = sk.sign(b"hello");
sk.public_key().verify(b"hello", &sig).unwrap();
use purecrypto::mldsa::MlDsa65PrivateKey;
let (sk, pk) = MlDsa65PrivateKey::generate(&mut OsRng);
let sig = sk.sign(&mut OsRng, b"hello", b"").unwrap();
assert!(pk.verify(&sig, b"hello", b""));
use purecrypto::mlkem::MlKem768DecapsKey;
let (dk, ek) = MlKem768DecapsKey::generate(&mut OsRng);
let (ct, ss_a) = ek.encapsulate(&mut OsRng);
let ss_b = dk.decapsulate(&ct);
assert_eq!(ss_a, ss_b);
```
### 版本和传输
`purecrypto` 提供了 TLS (TCP) 和 DTLS (UDP),每种各有两个协议
版本:
所有四个版本(TLS 1.2、TLS 1.3、DTLS 1.2、DTLS 1.3)和两种角色
(客户端、服务器)共享 **一个**公共 API:[`tls::Config`] +
[`tls::Connection`]。版本由
`Config::builder().versions(min, max).build()` 选择;角色在
连接构建时通过 `Connection::client(&cfg)` 或
`Connection::server(&cfg)` 选择。
- **TLS 1.2** 仅限 ECDHE-AEAD(AES-128/256-GCM、ChaCha20-Poly1305)—
没有静态 RSA,没有静态 DH,没有 CBC。通过构造实现前向保密。
包括 mTLS 和 RFC 5077 无状态会话票据。
- **TLS 1.3** 是完整的 RFC 8446,具有 PSK 恢复、0-RTT、
exporter、ALPN、mTLS 和降级检测。
- **DTLS 1.2** (RFC 6347) 通过 UDP 承载 TLS 1.2 握手,具有
HelloVerifyRequest cookie、握手分段/重组、
重放保护和重传。协商与 TLS 1.2 路径
支持的相同的 ECDHE-AEAD 套件 × 群 × 签名方案。
- **DTLS 1.3** (RFC 9147) 通过 UDP 承载 TLS 1.3 握手,具有
选择性 ACK 可靠性、加密序列号和
HelloRetryRequest cookie。协商与
TLS 1.3 路径相同的 TLS 1.3 套件、
群(包括 `X25519MLKEM768`)和签名方案。
### TLS 1.3
`tls` 模块是一个 sans-I/O TLS 1.3 实现,具有一个轻量级
`std::io::Read + Write` 适配器用于阻塞 TCP。完整的特性面,
按端配置:
```
// Client (TLS or DTLS, any version):
Config::builder()
.versions(ProtocolVersion::TLSv1_2, ProtocolVersion::TLSv1_3)
.roots(roots)
.server_name("example.com")
.alpn(vec![b"h2".to_vec(), b"http/1.1".to_vec()])
.record_size_limit(4096) // RFC 8449
.identity(client_chain, client_key) // mTLS (any SigningKey)
.build();
// Server (TLS or DTLS, any version):
Config::builder()
.tls_only() // shorthand for versions(TLSv1_2, TLSv1_3)
.identity(chain, SigningKey::Rsa(rsa) | SigningKey::Ecdsa(ec) | ...)
.alpn(...)
.ticket_key([0u8; 32]) // enables NewSessionTicket emission
.max_early_data(16384) // accept up to N bytes of 0-RTT
.client_auth(ClientAuth { roots, required: true }) // mTLS
.build();
// DTLS variant:
Config::builder()
.dtls() // shorthand for versions(DTLSv1_2, DTLSv1_3)
.identity(chain, key)
.cookie_secret([0u8; 32]) // amplification defense
.max_record_size(1200) // MTU ceiling
.build();
let mut conn = Connection::client(&cfg)?; // or Connection::server(&cfg)
```
握手完成后,双方将公开:
- `connection.alpn_selected()` — 协商的 ALPN 名称(如果有)。
- `connection.tls_exporter(label, context, out)` — RFC 8446 §7.5 / RFC 5705
应用层密钥材料。
- `connection.peer_certificates()` — 已验证的链(叶子节点在前)。
- (client) `connection.take_session()` — 移出一个从
服务器 NewSessionTicket 派生的 `ResumptionSession`;下次连接到
同一服务器时将其传递给
`Config::builder().resumption_session(...)`(TLS 1.3 PSK 或 TLS 1.2 RFC 5077 票据)。
- (client) `connection.write_early_data(&[u8])` — 在
`ServerHello` 到达之前发送早期流量密钥下的应用数据,仅在
启用了 0-RTT 的恢复连接上有效。
**0-RTT 重放警告。** RFC 8446 §8:0-RTT 数据可被主动
攻击者重放,因为服务器无法将早期字节绑定到唯一的
客户端-服务器握手实例。提供的 `ReplayWindow` 会阻止进程内
重复的绑定器,但跨进程/跨服务器的重放防御
是应用层面的。将通过 `write_early_data` 发送的所有数据标记为
幂等的(HEAD/GET、幂等 RPC 等),绝不能作为改变
状态的写入。
```
use purecrypto::tls::{Config, Connection, HandshakeStatus, RootCertStore};
// Use the embedded root bundle (feature `embedded-roots`, on by default):
// a curated first-party store built from the Mozilla root program and
// others, following CA/Browser Forum rules. Or start from
// `RootCertStore::new()` and add your own PEMs.
let roots = RootCertStore::with_embedded_roots();
let cfg = Config::builder()
.tls_only()
.roots(roots)
.server_name("example.com")
.alpn(vec![b"h2".to_vec(), b"http/1.1".to_vec()])
.build();
let mut conn = Connection::client(&cfg).unwrap();
// Drive the handshake: pop wire bytes from `conn`, send them, recv from
// the peer, feed them back. The sans-I/O surface is the same for TLS and
// DTLS — the only difference is "stream" vs "datagram" framing.
# fn _h(_: Connection) -> std::io::Result<()> { Ok(()) }
```
### 签名算法
X.509 链验证和 TLS 1.3 `CertificateVerify` 均通过
[`signature_registry`](src/signature_registry.rs) 模块进行分发。purecrypto 可以执行的每个签名
原语都作为一个注册表项出现;严格的白名单
[`SignaturePolicy`] 控制验证器将接受哪些项。
#### 注册表
| `id` (白名单键) | X.509 OID | TLS 1.3 方案 | 默认 `modern()` |
| --------------------------- | ------------------------------- | -------------- | ------------------ |
| `rsa-pkcs1-sha1` | `1.2.840.113549.1.1.5` | (无) | 可选 |
| `rsa-pkcs1-sha256` | `1.2.840.113549.1.1.11` | `0x0401` | |
| `rsa-pkcs1-sha384` | `1.2.840.113549.1.1.12` | `0x0501` | |
| `rsa-pkcs1-sha512` | `1.2.840.113549.1.1.13` | (无) | 可选 |
| `rsa-pss-rsae-sha256` | `1.2.840.113549.1.1.11` (RSAE) | `0x0804` | |
| `rsa-pss-rsae-sha384` | `1.2.840.113549.1.1.12` (RSAE) | `0x0805` | |
| `rsa-pss-rsae-sha512` | `1.2.840.113549.1.1.13` (RSAE) | `0x0806` | |
| `rsa-pss-pss-sha256` | `1.2.840.113549.1.1.10` (PSS 密钥) | (无) | 可选 |
| `ecdsa-with-sha256` | `1.2.840.10045.4.3.2` (任意曲线) | (无) | |
| `ecdsa-with-sha384` | `1.2.840.10045.4.3.3` (任意曲线) | (无) | |
| `ecdsa-with-sha512` | `1.2.840.10045.4.3.4` (任意曲线) | (无) | |
| `ecdsa-secp256r1-sha256` | (仅限 TLS — 严格曲线) | `0x0403` | |
| `ecdsa-secp384r1-sha384` | (仅限 TLS — 严格曲线) | `0x0503` | |
| `ecdsa-secp521r1-sha512` | (仅限 TLS — 严格曲线) | `0x0603` | |
| `ecdsa-secp256r1-sha384/512`, `ecdsa-secp384r1-sha256/512`, `ecdsa-secp521r1-sha256/384` | 交叉哈希,仅策略 | (无) | 可选 |
| `ecdsa-secp256k1-sha256/384/512` | secp256k1, 仅策略 | (无) | 可选 |
| `ed25519` | `1.3.101.112` | `0x0807` | |
| `ml-dsa-44` / `-65` / `-87` | `2.16.840.1.101.3.4.3.17/18/19` | `0x0904/05/06` | (NIST FIPS 204) |
| `slh-dsa-sha2-128s/128f/192s/192f/256s/256f`, `slh-dsa-shake-128s/128f/192s/192f/256s/256f` | `2.16.840.1.101.3.4.3.20..31` | (无) | 可选 (FIPS 205) |
匹配曲线/匹配哈希的 ECDSA 对(例如 P-256 + SHA-256)具有 IANA
TLS 方案代码;交叉哈希对和所有 secp256k1 条目可通过
以 OID 为键的 `ecdsa-with-shaN` 条目进行链分发(接受任何
受支持的曲线),并作为细粒度以策略为键的条目用于 TLS 选入。
ML-DSA 处于默认白名单中(现代 PQC 的未来)。SLH-DSA 的十二个
参数集已注册,但从未出现在默认白名单上:签名
为 7–50 KB,很少是 X.509 叶子的正确默认值。
#### 配置策略
```
use purecrypto::signature_registry::SignaturePolicy;
use purecrypto::tls::{Config, RootCertStore};
let roots = RootCertStore::new();
// Default — modern IANA-blessed set, RSA ≥ 2048 bits.
let cfg = Config::builder().roots(roots).build();
// Legacy interop: accept SHA-1 RSA and lower the RSA-bit floor to 1024.
let roots = RootCertStore::new();
let cfg = Config::builder()
.roots(roots)
.signature_policy(
SignaturePolicy::modern()
.permit("rsa-pkcs1-sha1")
.with_min_rsa_bits(1024),
)
.build();
// PQC-strict: only ML-DSA + Ed25519, refuse everything classical.
let roots = RootCertStore::new();
let cfg = Config::builder()
.roots(roots)
.signature_policy(
SignaturePolicy::empty()
.permit("ml-dsa-65")
.permit("ml-dsa-87")
.permit("ed25519"),
)
.build();
// SLH-DSA chains: opt in to a single set the application expects.
let roots = RootCertStore::new();
let cfg = Config::builder()
.roots(roots)
.signature_policy(SignaturePolicy::modern().permit("slh-dsa-sha2-128f"))
.build();
```
统一 [`Config`] 上的 `signature_policy` 适用于客户端和
服务器角色 —— 对于服务器,它控制 mTLS 下的客户端证书验证。该策略是一个严格的白名单:
向注册表添加条目并不会自动允许它 —— 调用者必须
显式添加 id。
## C 库
预构建的归档文件 —— `purecrypto` CLI、静态(`.a`/`.lib`)和共享
(`.so`/`.dylib`/`.dll`)C 库以及头文件 —— 附带在每个
适用于 Linux、
macOS 和 Windows 的 [GitHub 发布版](https://github.com/KarpelesLab/purecrypto/releases)中。
相同的代码可以通过 `ffi` 特性从 C 调用。因为该 crate 默认保持为
`rlib`(因此 `no_std` 构建不受影响),使用 `cargo rustc` 生成 C 库:
```
cargo rustc --lib --release --features ffi --crate-type cdylib # → target/release/libpurecrypto.so
cargo rustc --lib --release --features ffi --crate-type staticlib # → target/release/libpurecrypto.a
# Static link(独立自带):
cc app.c -I include target/release/libpurecrypto.a -lpthread -ldl -lm -o app
```
API 在 [`include/purecrypto.h`](include/purecrypto.h) 中声明:一次性
和流式哈希、HMAC、OS 随机性、RSA/ECDSA/Ed25519 密钥生成、
签名、验证和 PEM I/O,ML-KEM (FIPS 203) / ML-DSA (FIPS 204) /
SLH-DSA (FIPS 205) 密钥,X.509 解析/验证,以及 sans-I/O TLS /
DTLS 表面(`pc_tls_cfg_*`、`pc_tls_*`),包括用于已协商
密码套件和对等方 SNI 的握手后访问器。函数返回一个
`pc_status` 代码;可变长度输出使用输入/输出长度缓冲区;
有状态对象是由库释放的不透明句柄;panic 绝不会
跨越边界。
## 许可证
根据 [MIT 许可证](LICENSE) 授权。
标签:no_std, Rust, TLS/DTLS/QUIC, X.509, 可视化界面, 后量子加密, 密码学, 手动系统调用, 网络流量审计, 通知系统