KarpelesLab/purecrypto

GitHub: KarpelesLab/purecrypto

一个纯 Rust、无 C 依赖的 no_std 密码学工具包,从 constant-time 原语到后量子算法、X.509 和 TLS/DTLS/QUIC 协议栈提供完整的加密能力。

Stars: 1 | Forks: 0

# purecrypto [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](https://github.com/KarpelesLab/purecrypto/actions/workflows/ci.yml) [![crates.io](https://img.shields.io/crates/v/purecrypto.svg)](https://crates.io/crates/purecrypto) [![docs.rs](https://img.shields.io/docsrs/purecrypto)](https://docs.rs/purecrypto) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](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, 可视化界面, 后量子加密, 密码学, 手动系统调用, 网络流量审计, 通知系统