fix: 修复支付宝 RSA 签名失败问题
- 支持 base64 编码的 PEM 格式私钥(用于 systemd 环境变量) - RSA 签名/验证前需先用 Sha256::digest() 哈希输入 - 添加 Digest trait 导入
This commit is contained in:
@@ -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<String, String> {
|
||||
// 解析 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::<Sha256>(), signing_input)
|
||||
.sign(Pkcs1v15Sign::new::<Sha256>(), &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<String, String>
|
||||
|
||||
/// 验证 RSA2 签名
|
||||
pub fn rsa2_verify(content: &str, sign: &str, public_key_pem: &str) -> Result<bool, String> {
|
||||
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::<Sha256>(),
|
||||
content.as_bytes(),
|
||||
&hashed_content,
|
||||
&sig_bytes,
|
||||
)
|
||||
.is_ok())
|
||||
|
||||
Reference in New Issue
Block a user