fix: 修复支付宝 RSA2 签名问题
- 支持 base64 编码的 PEM 格式私钥(systemd 环境变量) - 使用 Digest + Pkcs1v15Sign::new() 进行签名(自动哈希) - 修复 rsa2_sign 和 rsa2_verify 函数实现
This commit is contained in:
@@ -1,8 +1,9 @@
|
|||||||
// src/alipay.rs — 支付宝 RSA2 签名与请求封装
|
// src/alipay.rs — 支付宝 RSA2 签名与请求封装
|
||||||
|
use rsa::pkcs1v15::{Pkcs1v15Sign, SigningKey, VerifyingKey};
|
||||||
use rsa::pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, LineEnding};
|
use rsa::pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, LineEnding};
|
||||||
use rsa::signature::Signer;
|
use rsa::signature::{Signer, Verifier};
|
||||||
|
use rsa::RsaPrivateKey;
|
||||||
use rsa::RsaPublicKey;
|
use rsa::RsaPublicKey;
|
||||||
use rsa::{Pkcs1v15Sign, RsaPrivateKey};
|
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
@@ -76,42 +77,37 @@ pub fn rsa2_sign(content: &str, private_key_pem: &str) -> Result<String, String>
|
|||||||
private_key_pem,
|
private_key_pem,
|
||||||
)
|
)
|
||||||
.map_err(|e| format!("Base64 解码失败: {}", e))?;
|
.map_err(|e| format!("Base64 解码失败: {}", e))?;
|
||||||
|
|
||||||
let pem_str = String::from_utf8(decoded)
|
let pem_str = String::from_utf8(decoded)
|
||||||
.map_err(|e| format!("PEM 字符串格式错误: {}", e))?;
|
.map_err(|e| format!("PEM 字符串格式错误: {}", e))?;
|
||||||
|
|
||||||
RsaPrivateKey::from_pkcs8_pem(&pem_str)
|
RsaPrivateKey::from_pkcs8_pem(&pem_str)
|
||||||
.map_err(|e| format!("私钥解析失败: {}", e))?
|
.map_err(|e| format!("私钥解析失败: {}", e))?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let signing_input = Sha256::digest(content.as_bytes());
|
let signing_key = SigningKey::<Sha256>::new(private_key);
|
||||||
let signature = private_key
|
let signature = signing_key.sign(content.as_bytes());
|
||||||
.sign(Pkcs1v15Sign::new::<Sha256>(), &signing_input)
|
|
||||||
.map_err(|e| format!("签名失败: {}", e))?;
|
|
||||||
|
|
||||||
Ok(base64::Engine::encode(
|
Ok(base64::Engine::encode(
|
||||||
&base64::engine::general_purpose::STANDARD,
|
&base64::engine::general_purpose::STANDARD,
|
||||||
&signature,
|
signature.to_bytes().as_ref(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 验证 RSA2 签名
|
/// 验证 RSA2 签名
|
||||||
pub fn rsa2_verify(content: &str, sign: &str, public_key_pem: &str) -> Result<bool, String> {
|
pub fn rsa2_verify(content: &str, sign: &str, public_key_pem: &str) -> Result<bool, String> {
|
||||||
|
use sha2::Digest;
|
||||||
let public_key = RsaPublicKey::from_public_key_pem(public_key_pem)
|
let public_key = RsaPublicKey::from_public_key_pem(public_key_pem)
|
||||||
.map_err(|e| format!("支付宝公钥解析失败: {}", e))?;
|
.map_err(|e| format!("支付宝公钥解析失败: {}", e))?;
|
||||||
|
|
||||||
let sig_bytes = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, sign)
|
let sig_bytes = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, sign)
|
||||||
.map_err(|e| format!("签名 Base64 解码失败: {}", e))?;
|
.map_err(|e| format!("签名 Base64 解码失败: {}", e))?;
|
||||||
|
|
||||||
let hashed_content = Sha256::digest(content.as_bytes());
|
let hashed = Sha256::digest(content.as_bytes());
|
||||||
Ok(public_key
|
public_key
|
||||||
.verify(
|
.verify(rsa::Pkcs1v15Sign::new::<Sha256>(), &hashed, &sig_bytes)
|
||||||
Pkcs1v15Sign::new::<Sha256>(),
|
.map_err(|e| format!("签名验证失败: {}", e))?;
|
||||||
&hashed_content,
|
Ok(true)
|
||||||
&sig_bytes,
|
|
||||||
)
|
|
||||||
.is_ok())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 构建支付宝请求 URL(含签名)
|
/// 构建支付宝请求 URL(含签名)
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
// handlers/payment.rs — 支付相关处理器(接入支付宝)
|
// handlers/payment.rs — 支付相关处理器(接入支付宝)
|
||||||
use actix_web::{get, post, web, HttpRequest, HttpResponse};
|
use actix_web::{get, post, web, HttpRequest, HttpResponse};
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
use rsa::pkcs1v15::{Pkcs1v15Sign, SigningKey, VerifyingKey};
|
||||||
use rsa::pkcs8::DecodePrivateKey;
|
use rsa::pkcs8::DecodePrivateKey;
|
||||||
use rsa::signature::{Signer, Verifier};
|
use rsa::signature::{SignatureEncoding, Signer, Verifier};
|
||||||
use rsa::{Pkcs1v15Sign, RsaPrivateKey};
|
use rsa::RsaPrivateKey;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
use sqlx::postgres::PgPool;
|
use sqlx::postgres::PgPool;
|
||||||
@@ -101,29 +102,30 @@ fn rsa2_sign(content: &str, private_key_pem: &str) -> Result<String, String> {
|
|||||||
.map_err(|e| format!("私钥解析失败: {}", e))?
|
.map_err(|e| format!("私钥解析失败: {}", e))?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let hashed_content = Sha256::digest(content.as_bytes());
|
let signing_key = SigningKey::<Sha256>::new(private_key);
|
||||||
let signature = private_key
|
let signature = signing_key.sign(content.as_bytes());
|
||||||
.sign(Pkcs1v15Sign::new::<Sha256>(), &hashed_content)
|
|
||||||
.map_err(|e| format!("签名失败: {}", e))?;
|
|
||||||
Ok(base64::Engine::encode(
|
Ok(base64::Engine::encode(
|
||||||
&base64::engine::general_purpose::STANDARD,
|
&base64::engine::general_purpose::STANDARD,
|
||||||
&signature,
|
signature.to_bytes().as_ref(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 验证 RSA2 签名
|
/// 验证 RSA2 签名
|
||||||
|
#[allow(dead_code)]
|
||||||
fn rsa2_verify(content: &str, sign: &str, public_key_pem: &str) -> Result<bool, String> {
|
fn rsa2_verify(content: &str, sign: &str, public_key_pem: &str) -> Result<bool, String> {
|
||||||
use rsa::pkcs8::DecodePublicKey;
|
use rsa::pkcs8::DecodePublicKey;
|
||||||
use rsa::signature::Verifier;
|
use rsa::RsaPublicKey;
|
||||||
|
use sha2::Digest;
|
||||||
let public_key =
|
let public_key =
|
||||||
rsa::RsaPublicKey::from_public_key_pem(public_key_pem)
|
RsaPublicKey::from_public_key_pem(public_key_pem)
|
||||||
.map_err(|e| format!("支付宝公钥解析失败: {}", e))?;
|
.map_err(|e| format!("支付宝公钥解析失败: {}", e))?;
|
||||||
let sig_bytes = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, sign)
|
let sig_bytes = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, sign)
|
||||||
.map_err(|e| format!("签名 Base64 解码失败: {}", e))?;
|
.map_err(|e| format!("签名 Base64 解码失败: {}", e))?;
|
||||||
let hashed_content = Sha256::digest(content.as_bytes());
|
let hashed = Sha256::digest(content.as_bytes());
|
||||||
Ok(public_key
|
public_key
|
||||||
.verify(Pkcs1v15Sign::new::<Sha256>(), &hashed_content, &sig_bytes)
|
.verify(rsa::Pkcs1v15Sign::new::<Sha256>(), &hashed, &sig_bytes)
|
||||||
.is_ok())
|
.map_err(|e| format!("签名验证失败: {}", e))?;
|
||||||
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== Helper: 调用 alipay.trade.page.pay =====
|
// ===== Helper: 调用 alipay.trade.page.pay =====
|
||||||
|
|||||||
Reference in New Issue
Block a user