From fc4b04a8123406ee5cec5ffa627bf7ad35e1dd7e Mon Sep 17 00:00:00 2001 From: kdletters <61648117+kdletters@users.noreply.github.com> Date: Mon, 1 Jun 2026 22:20:29 +0800 Subject: [PATCH] fix: allow wechat message aes key trailing bits --- server-rs/crates/api-server/src/wechat_pay.rs | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/server-rs/crates/api-server/src/wechat_pay.rs b/server-rs/crates/api-server/src/wechat_pay.rs index 4b21f255..4fe51525 100644 --- a/server-rs/crates/api-server/src/wechat_pay.rs +++ b/server-rs/crates/api-server/src/wechat_pay.rs @@ -7,7 +7,12 @@ use axum::{ http::{HeaderMap, HeaderValue, StatusCode, header::CONTENT_TYPE}, response::{IntoResponse, Response}, }; -use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64_STANDARD}; +use base64::{ + Engine as _, alphabet, + engine::general_purpose::{ + GeneralPurpose, GeneralPurposeConfig, STANDARD as BASE64_STANDARD, + }, +}; use bytes::Bytes; use cbc::cipher::{BlockDecryptMut, KeyIvInit, block_padding::NoPadding}; use ring::{ @@ -53,6 +58,10 @@ const WECHAT_MINIPROGRAM_MESSAGE_ENCODING_AES_KEY_BYTES: usize = 43; const WECHAT_MINIPROGRAM_MESSAGE_AES_KEY_BYTES: usize = 32; const WECHAT_MINIPROGRAM_MESSAGE_RANDOM_BYTES: usize = 16; const WECHAT_MINIPROGRAM_MESSAGE_LENGTH_BYTES: usize = 4; +const WECHAT_MINIPROGRAM_MESSAGE_AES_KEY_BASE64: GeneralPurpose = GeneralPurpose::new( + &alphabet::STANDARD, + GeneralPurposeConfig::new().with_decode_allow_trailing_bits(true), +); #[derive(Clone, Debug)] pub enum WechatPayClient { @@ -1193,7 +1202,7 @@ fn decode_wechat_message_push_encoding_aes_key( ))); } let padded_key = format!("{encoding_aes_key}="); - let key = BASE64_STANDARD + let key = WECHAT_MINIPROGRAM_MESSAGE_AES_KEY_BASE64 .decode(padded_key.as_bytes()) .map_err(|error| { WechatPayError::InvalidConfig(format!( @@ -2176,6 +2185,18 @@ mod tests { } } + #[test] + fn decode_wechat_message_push_encoding_aes_key_allows_trailing_bits() { + let canonical_key = BASE64_STANDARD.encode([0u8; 32]); + let mut encoding_aes_key = canonical_key.trim_end_matches('=').to_string(); + encoding_aes_key.replace_range(encoding_aes_key.len() - 1.., "B"); + + let decoded = decode_wechat_message_push_encoding_aes_key(&encoding_aes_key) + .expect("wechat aes key with trailing bits should decode"); + + assert_eq!(decoded, vec![0u8; WECHAT_MINIPROGRAM_MESSAGE_AES_KEY_BYTES]); + } + #[test] fn wechat_message_push_signature_uses_sorted_sha1_parts() { let token = "token-1";