diff --git a/src/alipay.rs b/src/alipay.rs index aff192f..525c7dd 100644 --- a/src/alipay.rs +++ b/src/alipay.rs @@ -1,7 +1,9 @@ // src/alipay.rs — 支付宝 RSA2 签名与请求封装 -use rsa::pkcs8::{DecodePrivateKey, EncodePrivateKey, LineEnding}; +use rsa::pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, LineEnding}; +use rsa::signature::Signer; +use rsa::RsaPublicKey; use rsa::{Pkcs1v15Sign, RsaPrivateKey}; -use sha2::Sha256; +use sha2::{Digest, Sha256}; use std::collections::BTreeMap; use std::env; @@ -62,12 +64,30 @@ fn urlencoding(s: &str) -> String { /// 使用 RSA2 (SHA256) 对内容签名 pub fn rsa2_sign(content: &str, private_key_pem: &str) -> Result { // 解析 PKCS8 格式的私钥 - let private_key = RsaPrivateKey::from_pkcs8_pem(private_key_pem) - .map_err(|e| format!("私钥解析失败: {}", e))?; + // 支持两种格式: + // 1. PEM 格式字符串 (-----BEGIN PRIVATE KEY-----...) + // 2. Base64 编码的 PEM 字符串 (用于环境变量配置) + let private_key = match RsaPrivateKey::from_pkcs8_pem(private_key_pem) { + Ok(key) => key, + Err(_) => { + // 尝试作为 base64 编码的 PEM 解码 + 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 signing_input = content.as_bytes(); + let signing_input = Sha256::digest(content.as_bytes()); let signature = private_key - .sign(Pkcs1v15Sign::new::(), signing_input) + .sign(Pkcs1v15Sign::new::(), &signing_input) .map_err(|e| format!("签名失败: {}", e))?; Ok(base64::Engine::encode( @@ -78,18 +98,17 @@ pub fn rsa2_sign(content: &str, private_key_pem: &str) -> Result /// 验证 RSA2 签名 pub fn rsa2_verify(content: &str, sign: &str, public_key_pem: &str) -> Result { - use rsa::pkcs8::DecodePublicKey; - - let public_key = rsa::RsaPublicKey::from_public_key_pem(public_key_pem) + let public_key = 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::(), - content.as_bytes(), + &hashed_content, &sig_bytes, ) .is_ok()) diff --git a/src/handlers/payment.rs b/src/handlers/payment.rs index 5ad894d..969b524 100644 --- a/src/handlers/payment.rs +++ b/src/handlers/payment.rs @@ -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 { - let private_key = - RsaPrivateKey::from_pkcs8_pem(private_key_pem).map_err(|e| format!("私钥解析失败: {}", e))?; - let signature = private_key.sign(Pkcs1v15Sign::new::(), 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::(), &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 { /// 验证 RSA2 签名 fn rsa2_verify(content: &str, sign: &str, public_key_pem: &str) -> Result { 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::(), content.as_bytes(), &sig_bytes) + .verify(Pkcs1v15Sign::new::(), &hashed_content, &sig_bytes) .is_ok()) }