ncrypt 0.2.0

WIP rust bindings for the win32 ncrypt api
Documentation
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>()..];

        /* Layout:

        BCRYPT_RSAKEY_BLOB
        PublicExponent[cbPublicExp] // Big-endian.
        Modulus[cbModulus] // Big-endian.
        */

        let e = BigUint::from_bytes_be(&data[..exponent_size]);
        data = &data[exponent_size..];
        let n = BigUint::from_bytes_be(&data[..modulus_size]);

        // println!("Magic 0x{:X}", header.Magic);
        // println!("BitLength {}", header.BitLength);
        // println!("cbPublicExp 0x{:X}", header.cbPublicExp);
        // println!("cbModulus 0x{:X}", header.cbModulus);
        // println!("cbPrime1 0x{:X}", header.cbPrime1);
        // println!("cbPrime2 0x{:X}", header.cbPrime2);

        Ok(Self::PublicKey(Box::new(RsaPublicKey::new(n, e)?)))
    }
}