Skip to main content

wx_rust_open/util/crypto/
wx_open_crypt_utils.rs

1//! 开放平台(第三方平台)回调消息加解密工具。
2//!
3//! 对应 Java `me.chanjar.weixin.open.util.WxOpenCryptUtil`(继承
4//! `me.chanjar.weixin.common.util.crypto.WxCryptUtil`):
5//!
6//! - 回调推送消息解密(`decrypt_xml`/`decrypt_content`):SHA1 验签 +
7//!   AES-256-CBC 解密(同企业微信 AES-CBC 模式);
8//! - 回复消息加密(`encrypt`/`encrypt_context`)。
9//!
10//! 与 miniapp 的 `WxMaCryptUtils` 同一包装模式:从 `WxOpenConfigStorage`
11//! 取 componentToken/componentAesKey/componentAppId,aesKey 去掉全部空格
12//! (对齐 Java `StringUtils.remove(encodingAesKey, " ")`)。
13
14use wx_rust_common::util::crypto::{EncryptContext, WxCryptUtil};
15
16use crate::config::WxOpenConfigStorage;
17
18/// 开放平台(第三方平台)回调消息加解密工具。
19#[derive(Debug, Clone)]
20pub struct WxOpenCryptUtils {
21    inner: WxCryptUtil,
22}
23
24impl WxOpenCryptUtils {
25    /// 从配置存储构建加解密工具。
26    ///
27    /// # 参数
28    /// - `config`:开放平台配置存储(componentToken/componentAesKey/componentAppId)
29    pub fn new(config: &dyn WxOpenConfigStorage) -> Result<Self, String> {
30        // Java: StringUtils.remove(encodingAesKey, " ")——去除全部空格后 base64 解码
31        let aes_key = config
32            .component_aes_key()
33            .unwrap_or_default()
34            .replace(' ', "");
35        let inner = WxCryptUtil::new(
36            config.component_token().unwrap_or_default(),
37            aes_key,
38            config.component_app_id().unwrap_or_default(),
39        )?;
40        Ok(Self { inner })
41    }
42
43    /// 解密第三方平台推送的加密消息(xml 格式)。
44    ///
45    /// 对应 Java `WxCryptUtil.decryptXml(msgSignature, timestamp, nonce, encryptedXml)`。
46    pub fn decrypt_xml(
47        &self,
48        msg_signature: &str,
49        timestamp: &str,
50        nonce: &str,
51        encrypted_xml: &str,
52    ) -> Result<String, String> {
53        self.inner
54            .decrypt_xml(msg_signature, timestamp, nonce, encrypted_xml)
55    }
56
57    /// 验证签名后直接解密密文内容(对应 Java `decryptContent`)。
58    pub fn decrypt_content(
59        &self,
60        msg_signature: &str,
61        timestamp: &str,
62        nonce: &str,
63        cipher_text: &str,
64    ) -> Result<String, String> {
65        self.inner
66            .decrypt_content(msg_signature, timestamp, nonce, cipher_text)
67    }
68
69    /// 将待回复消息加密打包为带签名的 xml(对应 Java `encrypt`)。
70    pub fn encrypt(&self, plain_xml: &str) -> Result<String, String> {
71        self.inner.encrypt(plain_xml)
72    }
73
74    /// 将待回复消息加密打包,返回加密所需值对象(对应 Java `encryptContext`)。
75    pub fn encrypt_context(&self, plain_xml: &str) -> Result<EncryptContext, String> {
76        self.inner.encrypt_context(plain_xml)
77    }
78}