use crate::property::Property;
use crate::{Error, Result};
use std::mem::MaybeUninit;
use std::ptr::{null, null_mut};
use winapi::shared::bcrypt::*;
use winapi::shared::ntdef::{LPCWSTR, PUCHAR, ULONG, VOID};
mod bytes;
pub use bytes::{AsBytes, FromBytes, Pod};
mod blob;
pub use blob::{Blob, BlobLayout};
mod windows_string;
pub use windows_string::WindowsString;
pub trait Handle: Send {
fn as_ptr(&self) -> BCRYPT_HANDLE;
fn as_mut_ptr(&mut self) -> *mut BCRYPT_HANDLE;
fn set_property<T: Property>(&self, value: &T::Value) -> Result<()> {
let property = WindowsString::from(T::IDENTIFIER);
unsafe {
Error::check(BCryptSetProperty(
self.as_ptr(),
property.as_ptr(),
value as *const _ as PUCHAR,
std::mem::size_of_val(value) as ULONG,
0,
))
}
}
fn get_property<T: Property>(&self) -> Result<T::Value>
where
T::Value: Sized,
{
let property = WindowsString::from(T::IDENTIFIER);
let mut size = get_property_size(self.as_ptr(), property.as_ptr())?;
assert_eq!(
size as usize,
std::mem::size_of::<T::Value>(),
"CNG property needs to allocate extra data in sized get_property variant"
);
let mut result = MaybeUninit::<T::Value>::uninit();
unsafe {
Error::check(BCryptGetProperty(
self.as_ptr(),
property.as_ptr(),
result.as_mut_ptr() as *mut _,
size,
&mut size,
0,
))?;
}
assert_eq!(size as usize, std::mem::size_of::<T::Value>());
Ok(unsafe { result.assume_init() })
}
fn get_property_unsized<T: Property>(&self) -> Result<Box<T::Value>> {
let property = WindowsString::from(T::IDENTIFIER);
let mut size = get_property_size(self.as_ptr(), property.as_ptr())?;
let mut result = vec![0u8; size as usize].into_boxed_slice();
unsafe {
Error::check(BCryptGetProperty(
self.as_ptr(),
property.as_ptr(),
result.as_mut_ptr(),
size,
&mut size,
0,
))?;
}
assert_eq!(size as usize, result.len());
Ok(FromBytes::from_boxed(result))
}
}
fn get_property_size(handle: BCRYPT_HANDLE, prop: LPCWSTR) -> Result<ULONG> {
let mut size: ULONG = 0;
unsafe {
Error::check(BCryptGetProperty(handle, prop, null_mut(), 0, &mut size, 0))?;
}
Ok(size)
}
pub struct AlgoHandle {
handle: BCRYPT_ALG_HANDLE,
}
unsafe impl Send for AlgoHandle {}
impl AlgoHandle {
pub fn open(id: &str) -> Result<Self> {
let mut handle = null_mut::<VOID>();
unsafe {
let id_str = WindowsString::from(id);
Error::check(BCryptOpenAlgorithmProvider(
&mut handle,
id_str.as_ptr(),
null(),
0,
))
.map(|_| Self { handle })
}
}
}
impl Drop for AlgoHandle {
fn drop(&mut self) {
if !self.handle.is_null() {
unsafe {
BCryptCloseAlgorithmProvider(self.handle, 0);
}
}
}
}
impl Handle for AlgoHandle {
fn as_ptr(&self) -> BCRYPT_ALG_HANDLE {
self.handle
}
fn as_mut_ptr(&mut self) -> *mut BCRYPT_ALG_HANDLE {
&mut self.handle
}
}
pub struct KeyHandle {
pub(crate) handle: BCRYPT_KEY_HANDLE,
}
unsafe impl Send for KeyHandle {}
impl KeyHandle {
pub fn new() -> Self {
Self { handle: null_mut() }
}
}
impl Drop for KeyHandle {
fn drop(&mut self) {
if !self.handle.is_null() {
unsafe {
BCryptDestroyKey(self.handle);
}
}
}
}
impl Default for KeyHandle {
fn default() -> Self {
KeyHandle::new()
}
}
impl Handle for KeyHandle {
fn as_ptr(&self) -> BCRYPT_KEY_HANDLE {
self.handle
}
fn as_mut_ptr(&mut self) -> *mut BCRYPT_KEY_HANDLE {
&mut self.handle
}
}
#[cfg(test)]
pub(crate) fn assert_send<T: Send>() {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn send() {
assert_send::<AlgoHandle>();
assert_send::<KeyHandle>();
}
}