use crate::error::TigerError;
use base64::engine::general_purpose::STANDARD as BASE64;
use base64::Engine;
use rsa::pkcs1v15::{SigningKey, VerifyingKey, Signature};
use rsa::{RsaPrivateKey, RsaPublicKey};
use rsa::pkcs8::DecodePublicKey;
use sha1::Sha1;
use signature::{Signer, SignatureEncoding, Verifier};
pub fn load_private_key(key_str: &str) -> Result<RsaPrivateKey, TigerError> {
if key_str.is_empty() {
return Err(TigerError::Auth("私钥不能为空".to_string()));
}
if let Ok(key) = <RsaPrivateKey as rsa::pkcs1::DecodeRsaPrivateKey>::from_pkcs1_pem(key_str) {
return Ok(key);
}
if let Ok(key) = <RsaPrivateKey as rsa::pkcs8::DecodePrivateKey>::from_pkcs8_pem(key_str) {
return Ok(key);
}
if let Ok(der_bytes) = BASE64.decode(key_str.trim()) {
if let Ok(key) =
<RsaPrivateKey as rsa::pkcs1::DecodeRsaPrivateKey>::from_pkcs1_der(&der_bytes)
{
return Ok(key);
}
if let Ok(key) =
<RsaPrivateKey as rsa::pkcs8::DecodePrivateKey>::from_pkcs8_der(&der_bytes)
{
return Ok(key);
}
}
Err(TigerError::Auth(
"无法解析私钥:不是有效的 PKCS#1、PKCS#8 PEM 或 Base64 格式".to_string(),
))
}
pub fn sign_with_rsa(private_key_str: &str, content: &str) -> Result<String, TigerError> {
let private_key = load_private_key(private_key_str)?;
let signing_key = SigningKey::<Sha1>::new(private_key);
let signature = signing_key
.sign(content.as_bytes());
Ok(BASE64.encode(signature.to_bytes()))
}
pub fn verify_with_rsa(public_key_str: &str, content: &str, signature_b64: &str) -> Result<bool, TigerError> {
if public_key_str.is_empty() {
return Err(TigerError::Auth("public key must not be empty".to_string()));
}
if signature_b64.is_empty() {
return Err(TigerError::Auth("signature must not be empty".to_string()));
}
let der_bytes = BASE64.decode(public_key_str.trim())
.map_err(|e| TigerError::Auth(format!("failed to decode public key base64: {}", e)))?;
let public_key = RsaPublicKey::from_public_key_der(&der_bytes)
.map_err(|e| TigerError::Auth(format!("failed to parse public key: {}", e)))?;
let sig_bytes = BASE64.decode(signature_b64.trim())
.map_err(|e| TigerError::Auth(format!("failed to decode signature base64: {}", e)))?;
let verifying_key = VerifyingKey::<Sha1>::new(public_key);
let signature = Signature::try_from(sig_bytes.as_slice())
.map_err(|e| TigerError::Auth(format!("invalid signature format: {}", e)))?;
verifying_key.verify(content.as_bytes(), &signature)
.map_err(|e| TigerError::Auth(format!("response signature verification failed: {}", e)))?;
Ok(true)
}
#[path = "signer_test.rs"]
#[cfg(test)]
mod signer_test;