use ::rsa::pkcs1::DecodeRsaPrivateKey;
use ::rsa::traits::{PrivateKeyParts, PublicKeyParts};
use ::rsa::{BigUint, RsaPrivateKey};
use crate::{CryptoError, Result};
pub fn private_decrypt_raw(der: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>> {
let key = RsaPrivateKey::from_pkcs1_der(der)
.map_err(|e| CryptoError::Rsa(format!("parse RSAPrivateKey DER: {e}")))?;
let modulus_bytes = key.size();
let c = BigUint::from_bytes_be(ciphertext);
if &c >= key.n() {
return Err(CryptoError::Rsa(
"ciphertext is not less than the modulus".into(),
));
}
let m = c.modpow(key.d(), key.n());
let raw = m.to_bytes_be();
if raw.len() > modulus_bytes {
return Err(CryptoError::Rsa("plaintext exceeds modulus size".into()));
}
let mut out = vec![0u8; modulus_bytes - raw.len()];
out.extend_from_slice(&raw);
Ok(out)
}
pub fn private_key_modulus_len(der: &[u8]) -> Result<usize> {
let key = RsaPrivateKey::from_pkcs1_der(der)
.map_err(|e| CryptoError::Rsa(format!("parse RSAPrivateKey DER: {e}")))?;
Ok(key.size())
}
#[cfg(test)]
mod tests {
use super::*;
use ::rsa::pkcs1::EncodeRsaPrivateKey;
fn public_encrypt_raw(key: &RsaPrivateKey, block: &[u8]) -> Vec<u8> {
let m = BigUint::from_bytes_be(block);
let c = m.modpow(key.e(), key.n());
let raw = c.to_bytes_be();
let mut out = vec![0u8; key.size() - raw.len()];
out.extend_from_slice(&raw);
out
}
fn pkcs1_v15_block(modulus_bytes: usize, payload: &[u8]) -> Vec<u8> {
let pad_len = modulus_bytes - payload.len() - 3;
let mut block = Vec::with_capacity(modulus_bytes);
block.push(0x00);
block.push(0x02);
block.extend(std::iter::repeat_n(0xFFu8, pad_len)); block.push(0x00);
block.extend_from_slice(payload);
block
}
#[test]
fn raw_decrypt_round_trips_a_padded_block() {
let mut rng = rand::thread_rng();
let key = RsaPrivateKey::new(&mut rng, 1024).expect("keygen");
let der = key.to_pkcs1_der().expect("der").as_bytes().to_vec();
let payload = [0xABu8; 16];
let block = pkcs1_v15_block(key.size(), &payload);
let wrapped = public_encrypt_raw(&key, &block);
let recovered = private_decrypt_raw(&der, &wrapped).unwrap();
assert_eq!(recovered, block);
assert_eq!(recovered.len(), key.size());
assert_eq!(recovered[recovered.len() - 17], 0x00);
assert_eq!(&recovered[recovered.len() - 16..], &payload);
}
#[test]
fn rejects_ciphertext_at_or_above_modulus() {
let mut rng = rand::thread_rng();
let key = RsaPrivateKey::new(&mut rng, 1024).expect("keygen");
let der = key.to_pkcs1_der().expect("der").as_bytes().to_vec();
let n_bytes = key.n().to_bytes_be();
assert!(private_decrypt_raw(&der, &n_bytes).is_err());
}
#[test]
fn rejects_malformed_der() {
assert!(private_decrypt_raw(b"not a der key", &[0u8; 128]).is_err());
}
}