fix: 修复支付宝 RSA 签名失败问题

- 支持 base64 编码的 PEM 格式私钥(用于 systemd 环境变量)
- RSA 签名/验证前需先用 Sha256::digest() 哈希输入
- 添加 Digest trait 导入
This commit is contained in:
2026-04-27 13:53:18 +08:00
parent 580e68b58c
commit 00fea53a4c
2 changed files with 51 additions and 16 deletions

View File

@@ -2,10 +2,10 @@
use actix_web::{get, post, web, HttpRequest, HttpResponse};
use chrono::Utc;
use rsa::pkcs8::DecodePrivateKey;
use rsa::signature::Signer;
use rsa::signature::{Signer, Verifier};
use rsa::{Pkcs1v15Sign, RsaPrivateKey};
use serde::Deserialize;
use sha2::Sha256;
use sha2::{Digest, Sha256};
use sqlx::postgres::PgPool;
use std::collections::BTreeMap;
use tracing::info;
@@ -87,9 +87,23 @@ fn urlencoding(s: &str) -> String {
/// RSA2 (SHA256) 签名
fn rsa2_sign(content: &str, private_key_pem: &str) -> Result<String, String> {
let private_key =
RsaPrivateKey::from_pkcs8_pem(private_key_pem).map_err(|e| format!("私钥解析失败: {}", e))?;
let signature = private_key.sign(Pkcs1v15Sign::new::<Sha256>(), content.as_bytes())
let private_key = match RsaPrivateKey::from_pkcs8_pem(private_key_pem) {
Ok(key) => key,
Err(_) => {
let decoded = base64::Engine::decode(
&base64::engine::general_purpose::STANDARD,
private_key_pem,
)
.map_err(|e| format!("Base64 解码失败: {}", e))?;
let pem_str = String::from_utf8(decoded)
.map_err(|e| format!("PEM 字符串格式错误: {}", e))?;
RsaPrivateKey::from_pkcs8_pem(&pem_str)
.map_err(|e| format!("私钥解析失败: {}", e))?
}
};
let hashed_content = Sha256::digest(content.as_bytes());
let signature = private_key
.sign(Pkcs1v15Sign::new::<Sha256>(), &hashed_content)
.map_err(|e| format!("签名失败: {}", e))?;
Ok(base64::Engine::encode(
&base64::engine::general_purpose::STANDARD,
@@ -100,13 +114,15 @@ fn rsa2_sign(content: &str, private_key_pem: &str) -> Result<String, String> {
/// 验证 RSA2 签名
fn rsa2_verify(content: &str, sign: &str, public_key_pem: &str) -> Result<bool, String> {
use rsa::pkcs8::DecodePublicKey;
use rsa::signature::Verifier;
let public_key =
rsa::RsaPublicKey::from_public_key_pem(public_key_pem)
.map_err(|e| format!("支付宝公钥解析失败: {}", e))?;
let sig_bytes = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, sign)
.map_err(|e| format!("签名 Base64 解码失败: {}", e))?;
let hashed_content = Sha256::digest(content.as_bytes());
Ok(public_key
.verify(Pkcs1v15Sign::new::<Sha256>(), content.as_bytes(), &sig_bytes)
.verify(Pkcs1v15Sign::new::<Sha256>(), &hashed_content, &sig_bytes)
.is_ok())
}