Skip to main content

encryption/
manager.rs

1// Copyright (c) 2026 erik <erik@erik.xyz> — https://erik.xyz
2
3//! 门面(Manager):注册表 + 默认标识的组合,业务层的常用入口。
4//!
5//! 对应 PHP 版的 `EncryptionManager`、`AsymmetricCryptoManager`、`HashingManager`、
6//! `KeyDerivationManager`、`PasswordBasedKdfManager`。每个门面提供「用默认算法」与
7//! 「显式指定 `*_with(identifier, ...)`」两组方法。
8//!
9//! 八个门面(本文件的六个 + `asymmetric` 子模块的两个)结构完全同构:都是
10//! `Registry<Box<dyn 能力>>` 加一个默认标识,默认方法一律转发给 `*_with`。
11//! 因此它们统一由 `manager_facade!` 宏生成——调用点只声明门面名、能力 trait、
12//! 错误消息里的能力名,以及一张「默认方法 → `*_with` 方法」的转发表;
13//! 加一个门面是加一段声明,不是把几十行样板再抄一遍。
14
15use crate::error::{Error, Result};
16
17/// 校验并设置默认标识。
18fn check_default(registry_has: bool, kind: &'static str, identifier: &str) -> Result<()> {
19    if registry_has {
20        Ok(())
21    } else {
22        Err(Error::UnknownIdentifier {
23            kind,
24            identifier: identifier.to_string(),
25        })
26    }
27}
28
29// 门面生成宏——上面八个门面共同的形状:
30//
31//   struct 名 { registry: Registry<Box<dyn 能力>>, default_identifier: String }
32//   new / registry / registry_mut / default_identifier / set_default_identifier
33//   x(&self, ...)          → x_with(&self.default_identifier, ...)
34//   x_with(&self, id, ...) → registry.get(id)?.x(...)
35//
36// 三处 Rust 细节决定了它的写法:
37//
38// - `macro_rules!` 是**文本作用域**:`mod asymmetric;` 里的调用得写在本定义之后,
39//   这就是下面 mod 声明跟在宏后面的原因,不是排版随意。
40// - 宏体在**展开处**解析路径,参数里的类型在**调用处**解析;所以宏体一律写
41//   `$crate::...`,调用点一律写 `crate::...`,谁都不依赖调用方模块里的 `use`。
42// - `concat_idents!` 不稳定,`x` 与 `x_with` 的名字只能成对显式传入(`x with x_with`)。
43macro_rules! manager_facade {
44    (
45        $(#[$struct_doc:meta])*
46        $name:ident, $capability:path, $kind:literal,
47        $(
48            $(#[$method_doc:meta])*
49            $method:ident with $with:ident ( $($arg:ident: $ty:ty),* $(,)? )
50                -> $ret:ty
51        ),* $(,)?
52    ) => {
53        $(#[$struct_doc])*
54        #[derive(Debug)]
55        pub struct $name {
56            registry: $crate::registry::Registry<Box<dyn $capability>>,
57            default_identifier: String,
58        }
59
60        impl $name {
61            /// `default_identifier` 必须已注册,否则返回
62            /// [`crate::error::Error::UnknownIdentifier`]。
63            pub fn new(
64                registry: $crate::registry::Registry<Box<dyn $capability>>,
65                default_identifier: impl Into<String>,
66            ) -> $crate::error::Result<Self> {
67                let default_identifier = default_identifier.into();
68                $crate::manager::check_default(
69                    registry.has(&default_identifier),
70                    $kind,
71                    &default_identifier,
72                )?;
73                Ok(Self {
74                    registry,
75                    default_identifier,
76                })
77            }
78
79            $(
80                $(#[$method_doc])*
81                pub fn $method(&self, $($arg: $ty),*) -> $ret {
82                    self.$with(&self.default_identifier $(, $arg)*)
83                }
84
85                pub fn $with(&self, identifier: &str $(, $arg: $ty)*) -> $ret {
86                    self.registry.get(identifier)?.$method($($arg),*)
87                }
88            )*
89
90            pub fn registry(&self) -> &$crate::registry::Registry<Box<dyn $capability>> {
91                &self.registry
92            }
93
94            pub fn registry_mut(
95                &mut self,
96            ) -> &mut $crate::registry::Registry<Box<dyn $capability>> {
97                &mut self.registry
98            }
99
100            pub fn default_identifier(&self) -> &str {
101                &self.default_identifier
102            }
103
104            pub fn set_default_identifier(
105                &mut self,
106                identifier: impl Into<String>,
107            ) -> $crate::error::Result<()> {
108                let identifier = identifier.into();
109                $crate::manager::check_default(
110                    self.registry.has(&identifier),
111                    $kind,
112                    &identifier,
113                )?;
114                self.default_identifier = identifier;
115                Ok(())
116            }
117        }
118    };
119}
120
121mod asymmetric;
122pub use asymmetric::{KeyAgreementManager, SignatureManager};
123
124manager_facade! {
125    /// 对称加密门面。
126    EncryptionManager, crate::contract::SymmetricCipher, "symmetric cipher",
127    encrypt with encrypt_with(plaintext: &[u8])
128        -> crate::error::Result<Vec<u8>>,
129    decrypt with decrypt_with(ciphertext: &[u8])
130        -> crate::error::Result<Vec<u8>>,
131}
132
133manager_facade! {
134    /// 非对称加密门面。
135    AsymmetricCryptoManager, crate::contract::AsymmetricCipher, "asymmetric cipher",
136    /// 返回十六进制密文。
137    encrypt with encrypt_with(plaintext: &[u8], public_key_hex: &str)
138        -> crate::error::Result<String>,
139    decrypt with decrypt_with(ciphertext_hex: &str, private_key_hex: &str)
140        -> crate::error::Result<Vec<u8>>,
141}
142
143manager_facade! {
144    /// 哈希门面。
145    HashingManager, crate::contract::Hasher, "hasher",
146    digest with digest_with(data: &[u8])
147        -> crate::error::Result<Vec<u8>>,
148    digest_hex with digest_hex_with(data: &[u8])
149        -> crate::error::Result<String>,
150}
151
152manager_facade! {
153    /// 密钥派生(HKDF)门面。
154    KeyDerivationManager, crate::contract::KeyDerivation, "key derivation",
155    derive with derive_with(ikm: &[u8], salt: &[u8], length: usize, info: &[u8])
156        -> crate::error::Result<Vec<u8>>,
157}
158
159manager_facade! {
160    /// 口令派生(PBKDF2)门面。
161    PasswordBasedKdfManager, crate::contract::PasswordBasedKdf, "password-based kdf",
162    derive_from_password with derive_from_password_with(
163        password: &[u8], salt: &[u8], length: usize
164    ) -> crate::error::Result<Vec<u8>>,
165}
166
167manager_facade! {
168    /// 密钥封装(KEM)门面。
169    KeyEncapsulationManager, crate::contract::KeyEncapsulation, "key encapsulation",
170    /// 生成密钥对,返回 `(公钥 hex, 私钥 hex)`。
171    generate with generate_with()
172        -> crate::error::Result<(String, String)>,
173    /// 用公钥封装,返回 `(密文 hex, 共享密钥 hex)`。
174    encapsulate with encapsulate_with(public_key_hex: &str)
175        -> crate::error::Result<(String, String)>,
176    /// 用私钥解封装,返回共享密钥 hex(非法密文按隐式拒绝语义不报错)。
177    decapsulate with decapsulate_with(ciphertext_hex: &str, private_key_hex: &str)
178        -> crate::error::Result<String>,
179}
180
181#[cfg(test)]
182mod tests {
183    use super::*;
184    use crate::contract::{
185        AsymmetricCipher, Hasher, KeyAgreement, KeyDerivation, KeyEncapsulation, PasswordBasedKdf,
186        Signer, SymmetricCipher,
187    };
188    use crate::registry::Registry;
189
190    /// 八个门面的 `kind` 文案全部钉死:空注册表 + 未注册的默认标识必然报错,
191    /// 改宏时若动到文案(或漏传 `$kind`),这里先红。
192    ///
193    /// 注册表自己的 kind 故意取 "unused":断言只可能由 `check_default` 收到的
194    /// 文案满足,不会与 `Registry::new` 的参数巧合通过。
195    #[test]
196    fn unknown_default_kind_is_pinned_for_every_facade() {
197        fn unknown(kind: &'static str) -> Error {
198            Error::UnknownIdentifier {
199                kind,
200                identifier: "missing".to_string(),
201            }
202        }
203
204        assert_eq!(
205            EncryptionManager::new(
206                Registry::<Box<dyn SymmetricCipher>>::new("unused"),
207                "missing"
208            )
209            .unwrap_err(),
210            unknown("symmetric cipher")
211        );
212        assert_eq!(
213            AsymmetricCryptoManager::new(
214                Registry::<Box<dyn AsymmetricCipher>>::new("unused"),
215                "missing"
216            )
217            .unwrap_err(),
218            unknown("asymmetric cipher")
219        );
220        assert_eq!(
221            HashingManager::new(Registry::<Box<dyn Hasher>>::new("unused"), "missing").unwrap_err(),
222            unknown("hasher")
223        );
224        assert_eq!(
225            KeyDerivationManager::new(Registry::<Box<dyn KeyDerivation>>::new("unused"), "missing")
226                .unwrap_err(),
227            unknown("key derivation")
228        );
229        assert_eq!(
230            PasswordBasedKdfManager::new(
231                Registry::<Box<dyn PasswordBasedKdf>>::new("unused"),
232                "missing"
233            )
234            .unwrap_err(),
235            unknown("password-based kdf")
236        );
237        assert_eq!(
238            KeyEncapsulationManager::new(
239                Registry::<Box<dyn KeyEncapsulation>>::new("unused"),
240                "missing"
241            )
242            .unwrap_err(),
243            unknown("key encapsulation")
244        );
245        assert_eq!(
246            SignatureManager::new(Registry::<Box<dyn Signer>>::new("unused"), "missing")
247                .unwrap_err(),
248            unknown("signer")
249        );
250        assert_eq!(
251            KeyAgreementManager::new(Registry::<Box<dyn KeyAgreement>>::new("unused"), "missing")
252                .unwrap_err(),
253            unknown("key agreement")
254        );
255    }
256}