use std::mem::{size_of, MaybeUninit};
use rsa::{BigUint, RsaPrivateKey, RsaPublicKey};
use windows_sys::Win32::Security::Cryptography::{BCRYPT_RSAKEY_BLOB, BCRYPT_RSAPUBLIC_MAGIC};
use crate::ParseError;
#[allow(dead_code)]
pub enum RsaKeyBlob {
PublicKey(Box<RsaPublicKey>),
PrivateKey(Box<RsaPrivateKey>),
}
impl RsaKeyBlob {
pub fn parse_public_key(data: &[u8]) -> Result<Box<RsaPublicKey>, ParseError> {
if let Self::PublicKey(pubkey) = Self::parse(data)? {
Ok(pubkey)
} else {
Err(ParseError::UnexpectedType)
}
}
pub fn parse(mut data: &[u8]) -> Result<Self, ParseError> {
if data.len() < size_of::<BCRYPT_RSAKEY_BLOB>() {
return Err(ParseError::TooSmall);
}
let header: BCRYPT_RSAKEY_BLOB = unsafe {
let mut header = MaybeUninit::uninit();
std::ptr::copy(
data.as_ptr(),
header.as_mut_ptr() as *mut u8,
size_of::<BCRYPT_RSAKEY_BLOB>(),
);
header.assume_init()
};
if header.Magic != BCRYPT_RSAPUBLIC_MAGIC {
todo!("magic 0x{:X} not yet implemented", header.Magic);
}
let exponent_size = header.cbPublicExp as usize;
let modulus_size = header.cbModulus as usize;
let expected = size_of::<BCRYPT_RSAKEY_BLOB>() + exponent_size + modulus_size;
if data.len() != expected {
return Err(ParseError::SizeMismatch {
expected,
actual: data.len(),
});
}
data = &data[size_of::<BCRYPT_RSAKEY_BLOB>()..];
let e = BigUint::from_bytes_be(&data[..exponent_size]);
data = &data[exponent_size..];
let n = BigUint::from_bytes_be(&data[..modulus_size]);
Ok(Self::PublicKey(Box::new(RsaPublicKey::new(n, e)?)))
}
}