Skip to main content

encryption/asymmetric/
mod.rs

1// Copyright (c) 2026 erik <erik@erik.xyz> — https://erik.xyz
2
3//! 非对称实现:RSA-OAEP 加密,以及 ECDSA / Ed25519 签名与 ECDH / X25519 密钥协商。
4//!
5//! - [`rsa`]:RSA-OAEP(SHA-256,RFC 8017),实现 [`crate::contract::AsymmetricCipher`];
6//! - [`ecdsa`]:ECDSA P-256(SHA-256)/ P-384(SHA-384)/ secp256k1(SHA-256),
7//!   实现 [`crate::contract::Signer`];
8//! - [`ed25519`]:Ed25519(RFC 8032),实现 [`crate::contract::Signer`];
9//! - [`ecdh`]:P-256 / P-384 / secp256k1 的静态 ECDH,实现 [`crate::contract::KeyAgreement`];
10//! - [`x25519`]:X25519(RFC 7748),实现 [`crate::contract::KeyAgreement`]。
11//!
12//! 各模块的十六进制长度约定见模块文档;密钥生成一律使用系统 CSPRNG。
13
14pub mod ecdh;
15pub mod ecdsa;
16pub mod ed25519;
17pub mod rsa;
18pub mod x25519;
19
20pub use rsa::{RsaOaepSha256Cipher, RsaOaepSha256Service};
21
22/// 非对称密钥对(十六进制):私钥与公钥的具体格式随算法(见各模块文档)。
23///
24/// `Debug` 打码:私钥永远不打印(与 [`crate::key::Key`] 同款遮蔽)。本库
25/// 「Debug 遮蔽」的安全默认值对密钥材质一律生效,密钥生成接口的返回值也不例外。
26#[derive(Clone, PartialEq, Eq)]
27pub struct KeyPairHex {
28    pub private_key_hex: String,
29    pub public_key_hex: String,
30}
31
32impl std::fmt::Debug for KeyPairHex {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        f.debug_struct("KeyPairHex")
35            .field("private_key_hex", &"***")
36            .field("public_key_hex", &self.public_key_hex)
37            .finish()
38    }
39}
40
41impl KeyPairHex {
42    /// 公钥(hex),可安全写日志。
43    pub fn public_only(&self) -> &str {
44        &self.public_key_hex
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    /// 私钥不得出现在 `Debug` 输出里——这是 README 声明的安全默认值,
53    /// 也是 `Key<N>` 已做到的遮蔽。所有 `generate_key_pair_hex()` 返回本类型。
54    #[test]
55    fn debug_redacts_the_private_key() {
56        let pair = KeyPairHex {
57            private_key_hex: "deadbeef".repeat(8),
58            public_key_hex: "cafebabe".repeat(8),
59        };
60        let text = format!("{pair:?}");
61        assert!(!text.contains("deadbeef"), "私钥泄漏进 Debug: {text}");
62        assert!(text.contains("cafebabe"), "公钥应照常打印: {text}");
63        assert!(text.contains("***"));
64    }
65
66    /// `Debug` 遮蔽不改变值语义:比较与克隆照旧。
67    #[test]
68    fn debug_redaction_keeps_value_semantics() {
69        let pair = KeyPairHex {
70            private_key_hex: "aa".repeat(32),
71            public_key_hex: "bb".repeat(33),
72        };
73        assert_eq!(pair.clone(), pair);
74        assert_eq!(pair.public_only(), pair.public_key_hex);
75    }
76}