use num_bigint::traits::ModInverse;
use num_bigint::BigUint;
use rand::{CryptoRng, Rng};
use rsa::padding::PaddingScheme;
use rsa::{PublicKey, RSAPrivateKey, RSAPublicKey};
use try_from::TryInto;
use crate::crypto::HashAlgorithm;
use crate::errors::Result;
use crate::types::{Mpi, PlainSecretParams, PublicParams};
pub fn decrypt(priv_key: &RSAPrivateKey, mpis: &[Mpi], _fingerprint: &[u8]) -> Result<Vec<u8>> {
ensure_eq!(mpis.len(), 1, "invalid input");
let mpi = &mpis[0];
let m = priv_key.decrypt(PaddingScheme::PKCS1v15, mpi.as_bytes())?;
Ok(m)
}
pub fn encrypt<R: CryptoRng + Rng>(
rng: &mut R,
n: &[u8],
e: &[u8],
plaintext: &[u8],
) -> Result<Vec<Vec<u8>>> {
let key = RSAPublicKey::new(BigUint::from_bytes_be(n), BigUint::from_bytes_be(e))?;
let data = key.encrypt(rng, PaddingScheme::PKCS1v15, plaintext)?;
Ok(vec![data])
}
pub fn generate_key<R: Rng + CryptoRng>(
rng: &mut R,
bit_size: usize,
) -> Result<(PublicParams, PlainSecretParams)> {
let key = RSAPrivateKey::new(rng, bit_size)?;
let p = &key.primes()[0];
let q = &key.primes()[1];
let u = p
.clone()
.mod_inverse(q)
.expect("invalid prime")
.to_biguint()
.expect("invalid prime");
Ok((
PublicParams::RSA {
n: key.n().into(),
e: key.e().into(),
},
PlainSecretParams::RSA {
d: key.d().into(),
p: p.into(),
q: q.into(),
u: u.into(),
},
))
}
pub fn verify(n: &[u8], e: &[u8], hash: HashAlgorithm, hashed: &[u8], sig: &[u8]) -> Result<()> {
let key = RSAPublicKey::new(BigUint::from_bytes_be(n), BigUint::from_bytes_be(e))?;
let rsa_hash: Option<rsa::hash::Hashes> = hash.try_into().ok();
key.verify(PaddingScheme::PKCS1v15, rsa_hash.as_ref(), &hashed[..], sig)
.map_err(Into::into)
}
pub fn sign(key: &RSAPrivateKey, hash: HashAlgorithm, digest: &[u8]) -> Result<Vec<Vec<u8>>> {
let rsa_hash: Option<rsa::hash::Hashes> = hash.try_into().ok();
let sig = key.sign(PaddingScheme::PKCS1v15, rsa_hash.as_ref(), digest)?;
Ok(vec![sig])
}