use rsa::{BoxedUint, RsaPrivateKey, RsaPublicKey, traits::PublicKeyParts};
use sha2::{Digest as _, Sha256};
pub use rsa::{Pkcs1v15Sign as Pkcs1v15, Pss};
use crate::Digest;
pub trait SignatureScheme: rsa::traits::SignatureScheme {
fn new<D: Digest>() -> Self;
}
impl SignatureScheme for Pkcs1v15 {
fn new<D: Digest>() -> Self {
Self::new::<D>()
}
}
impl SignatureScheme for Pss {
fn new<D: Digest>() -> Self {
Self::new::<D>()
}
}
pub struct RsaVerifyingKey(pub RsaPublicKey);
pub struct RsaSigningKey(pub RsaPrivateKey);
impl RsaVerifyingKey {
pub fn modulus(&self) -> Vec<u8> {
self.0.n_bytes().to_vec()
}
pub fn exponent(&self) -> Vec<u8> {
self.0.e_bytes().to_vec()
}
pub fn from_parameters(modulus: &[u8], exponent: &[u8]) -> Option<Self> {
let modulus = BoxedUint::from_be_slice_vartime(modulus);
let exponent = BoxedUint::from_be_slice_vartime(exponent);
let key = RsaPublicKey::new(modulus, exponent).ok()?;
Some(Self(key))
}
pub fn verifies<S: SignatureScheme, D: Digest>(
&self,
signature: &[u8],
message: &[u8],
) -> bool {
let hash = D::digest(message);
let scheme = S::new::<D>();
self.0.verify(scheme, &hash, signature).is_ok()
}
pub fn key_id(&self) -> Vec<u8> {
let modulus = self.modulus();
let exponent = self.exponent();
let digest = Sha256::new()
.chain_update(modulus)
.chain_update(exponent)
.finalize();
digest.to_vec()
}
}
impl RsaSigningKey {
pub fn sign<S: SignatureScheme, D: Digest>(&self, message: &[u8]) -> Vec<u8> {
let digest = D::digest(message);
let scheme = S::new::<D>();
self.0
.sign_with_rng(&mut rand::rng(), scheme, digest.as_slice())
.expect("RSA signing with valid parameters should not fail")
}
pub fn verifying_key(&self) -> RsaVerifyingKey {
RsaVerifyingKey(self.0.to_public_key())
}
}