win_crypto_ng/helpers/
mod.rs1use crate::property::Property;
2use crate::{Error, Result};
3use std::mem::MaybeUninit;
4use std::ptr::{null, null_mut};
5use winapi::shared::bcrypt::*;
6use winapi::shared::ntdef::{LPCWSTR, PUCHAR, ULONG, VOID};
7
8mod bytes;
9pub use bytes::{AsBytes, FromBytes, Pod};
10mod blob;
11pub use blob::{Blob, BlobLayout};
12mod windows_string;
13pub use windows_string::WindowsString;
14
15pub trait Handle: Send {
16 fn as_ptr(&self) -> BCRYPT_HANDLE;
17 fn as_mut_ptr(&mut self) -> *mut BCRYPT_HANDLE;
18
19 fn set_property<T: Property>(&self, value: &T::Value) -> Result<()> {
20 let property = WindowsString::from(T::IDENTIFIER);
21 unsafe {
22 Error::check(BCryptSetProperty(
23 self.as_ptr(),
24 property.as_ptr(),
25 value as *const _ as PUCHAR,
26 std::mem::size_of_val(value) as ULONG,
27 0,
28 ))
29 }
30 }
31
32 fn get_property<T: Property>(&self) -> Result<T::Value>
33 where
34 T::Value: Sized,
35 {
36 let property = WindowsString::from(T::IDENTIFIER);
37 let mut size = get_property_size(self.as_ptr(), property.as_ptr())?;
39 assert_eq!(
40 size as usize,
41 std::mem::size_of::<T::Value>(),
42 "CNG property needs to allocate extra data in sized get_property variant"
43 );
44
45 let mut result = MaybeUninit::<T::Value>::uninit();
48
49 unsafe {
50 Error::check(BCryptGetProperty(
51 self.as_ptr(),
52 property.as_ptr(),
53 result.as_mut_ptr() as *mut _,
54 size,
55 &mut size,
56 0,
57 ))?;
58 }
59 assert_eq!(size as usize, std::mem::size_of::<T::Value>());
62
63 Ok(unsafe { result.assume_init() })
64 }
65
66 fn get_property_unsized<T: Property>(&self) -> Result<Box<T::Value>> {
67 let property = WindowsString::from(T::IDENTIFIER);
68
69 let mut size = get_property_size(self.as_ptr(), property.as_ptr())?;
70 let mut result = vec![0u8; size as usize].into_boxed_slice();
71
72 unsafe {
73 Error::check(BCryptGetProperty(
74 self.as_ptr(),
75 property.as_ptr(),
76 result.as_mut_ptr(),
77 size,
78 &mut size,
79 0,
80 ))?;
81 }
82 assert_eq!(size as usize, result.len());
85
86 Ok(FromBytes::from_boxed(result))
87 }
88}
89
90fn get_property_size(handle: BCRYPT_HANDLE, prop: LPCWSTR) -> Result<ULONG> {
91 let mut size: ULONG = 0;
92 unsafe {
93 Error::check(BCryptGetProperty(handle, prop, null_mut(), 0, &mut size, 0))?;
94 }
95 Ok(size)
96}
97
98pub struct AlgoHandle {
99 handle: BCRYPT_ALG_HANDLE,
100}
101
102unsafe impl Send for AlgoHandle {}
103
104impl AlgoHandle {
105 pub fn open(id: &str) -> Result<Self> {
106 let mut handle = null_mut::<VOID>();
107 unsafe {
108 let id_str = WindowsString::from(id);
109 Error::check(BCryptOpenAlgorithmProvider(
110 &mut handle,
111 id_str.as_ptr(),
112 null(),
113 0,
114 ))
115 .map(|_| Self { handle })
116 }
117 }
118}
119
120impl Drop for AlgoHandle {
121 fn drop(&mut self) {
122 if !self.handle.is_null() {
123 unsafe {
124 BCryptCloseAlgorithmProvider(self.handle, 0);
125 }
126 }
127 }
128}
129
130impl Handle for AlgoHandle {
131 fn as_ptr(&self) -> BCRYPT_ALG_HANDLE {
132 self.handle
133 }
134
135 fn as_mut_ptr(&mut self) -> *mut BCRYPT_ALG_HANDLE {
136 &mut self.handle
137 }
138}
139
140pub struct KeyHandle {
142 pub(crate) handle: BCRYPT_KEY_HANDLE,
143}
144
145unsafe impl Send for KeyHandle {}
146
147impl KeyHandle {
148 pub fn new() -> Self {
149 Self { handle: null_mut() }
150 }
151}
152
153impl Drop for KeyHandle {
154 fn drop(&mut self) {
155 if !self.handle.is_null() {
156 unsafe {
157 BCryptDestroyKey(self.handle);
158 }
159 }
160 }
161}
162
163impl Default for KeyHandle {
164 fn default() -> Self {
165 KeyHandle::new()
166 }
167}
168
169impl Handle for KeyHandle {
170 fn as_ptr(&self) -> BCRYPT_KEY_HANDLE {
171 self.handle
172 }
173
174 fn as_mut_ptr(&mut self) -> *mut BCRYPT_KEY_HANDLE {
175 &mut self.handle
176 }
177}
178
179#[cfg(test)]
180pub(crate) fn assert_send<T: Send>() {}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185
186 #[test]
187 fn send() {
188 assert_send::<AlgoHandle>();
189 assert_send::<KeyHandle>();
190 }
191}