66use rustls:: crypto:: cipher:: NONCE_LEN ;
77use rustls:: Error ;
88use windows:: core:: Owned ;
9+ use windows:: Win32 :: Foundation :: NTSTATUS ;
910use windows:: Win32 :: Security :: Cryptography :: {
10- BCryptDecrypt , BCryptEncrypt , BCryptGenerateSymmetricKey , BCRYPT_AES_GCM_ALG_HANDLE ,
11- BCRYPT_ALG_HANDLE , BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO ,
12- BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION , BCRYPT_CHACHA20_POLY1305_ALG_HANDLE ,
13- BCRYPT_FLAGS , BCRYPT_KEY_HANDLE ,
11+ BCryptGenerateSymmetricKey , BCRYPT_AES_GCM_ALG_HANDLE , BCRYPT_ALG_HANDLE ,
12+ BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO , BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION ,
13+ BCRYPT_CHACHA20_POLY1305_ALG_HANDLE , BCRYPT_FLAGS , BCRYPT_KEY_HANDLE ,
1414} ;
1515
1616/// The tag length is 16 bytes for all supported ciphers.
1717pub ( crate ) const TAG_LEN : usize = 16 ;
1818
19+ type BcryptInPlaceFn = unsafe fn (
20+ BCRYPT_KEY_HANDLE ,
21+ * mut u8 ,
22+ u32 ,
23+ * mut BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO ,
24+ * mut u32 ,
25+ BCRYPT_FLAGS ,
26+ ) -> NTSTATUS ;
27+
28+ const _: BcryptInPlaceFn = bcrypt_encrypt_in_place;
29+ const _: BcryptInPlaceFn = bcrypt_decrypt_in_place;
30+
31+ #[ link( name = "bcrypt" ) ]
32+ extern "system" {
33+ #[ link_name = "BCryptEncrypt" ]
34+ fn bcrypt_encrypt_raw (
35+ hkey : BCRYPT_KEY_HANDLE ,
36+ pbinput : * const u8 ,
37+ cbinput : u32 ,
38+ ppaddinginfo : * const core:: ffi:: c_void ,
39+ pbiv : * mut u8 ,
40+ cbiv : u32 ,
41+ pboutput : * mut u8 ,
42+ cboutput : u32 ,
43+ pcbresult : * mut u32 ,
44+ dwflags : BCRYPT_FLAGS ,
45+ ) -> NTSTATUS ;
46+
47+ #[ link_name = "BCryptDecrypt" ]
48+ fn bcrypt_decrypt_raw (
49+ hkey : BCRYPT_KEY_HANDLE ,
50+ pbinput : * const u8 ,
51+ cbinput : u32 ,
52+ ppaddinginfo : * const core:: ffi:: c_void ,
53+ pbiv : * mut u8 ,
54+ cbiv : u32 ,
55+ pboutput : * mut u8 ,
56+ cboutput : u32 ,
57+ pcbresult : * mut u32 ,
58+ dwflags : BCRYPT_FLAGS ,
59+ ) -> NTSTATUS ;
60+ }
61+
62+ unsafe fn bcrypt_encrypt_in_place (
63+ hkey : BCRYPT_KEY_HANDLE ,
64+ buffer : * mut u8 ,
65+ len : u32 ,
66+ info : * mut BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO ,
67+ pcbresult : * mut u32 ,
68+ dwflags : BCRYPT_FLAGS ,
69+ ) -> NTSTATUS {
70+ unsafe {
71+ bcrypt_encrypt_raw (
72+ hkey,
73+ buffer as * const u8 ,
74+ len,
75+ info as * const core:: ffi:: c_void ,
76+ std:: ptr:: null_mut ( ) ,
77+ 0 ,
78+ buffer,
79+ len,
80+ pcbresult,
81+ dwflags,
82+ )
83+ }
84+ }
85+
86+ unsafe fn bcrypt_decrypt_in_place (
87+ hkey : BCRYPT_KEY_HANDLE ,
88+ buffer : * mut u8 ,
89+ len : u32 ,
90+ info : * mut BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO ,
91+ pcbresult : * mut u32 ,
92+ dwflags : BCRYPT_FLAGS ,
93+ ) -> NTSTATUS {
94+ unsafe {
95+ bcrypt_decrypt_raw (
96+ hkey,
97+ buffer as * const u8 ,
98+ len,
99+ info as * const core:: ffi:: c_void ,
100+ std:: ptr:: null_mut ( ) ,
101+ 0 ,
102+ buffer,
103+ len,
104+ pcbresult,
105+ dwflags,
106+ )
107+ }
108+ }
109+
19110#[ derive( Debug , Clone , Copy ) ]
20111pub ( crate ) struct Algorithm {
21112 handle : BCRYPT_ALG_HANDLE ,
@@ -101,7 +192,7 @@ impl AeadKey {
101192 let mut tag = [ 0u8 ; TAG_LEN ] ;
102193
103194 // https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_authenticated_cipher_mode_info
104- let info = BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO {
195+ let mut info = BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO {
105196 cbSize : core:: mem:: size_of :: < BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO > ( ) as u32 ,
106197 dwInfoVersion : BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION ,
107198 pbNonce : nonce. as_ptr ( ) . cast_mut ( ) ,
@@ -114,16 +205,16 @@ impl AeadKey {
114205 } ;
115206
116207 unsafe {
117- // SAFETY: CNG supports in-place encryption, so the input and output buffers can be the same.
208+ // SAFETY: CNG supports in-place encryption, and the raw helper accepts one buffer pointer
209+ // so Rust does not materialize overlapping input and output slice references.
118210 let mut size = 0u32 ;
119- let input = std :: slice :: from_raw_parts ( data. as_ptr ( ) . cast ( ) , data . len ( ) ) ;
211+ let len = data. len ( ) . try_into ( ) . unwrap ( ) ;
120212
121- BCryptEncrypt (
213+ bcrypt_encrypt_in_place (
122214 * self . handle ,
123- Some ( input) ,
124- Some ( std:: ptr:: from_ref ( & info) as * mut _ ) ,
125- None ,
126- Some ( data) ,
215+ data. as_mut_ptr ( ) ,
216+ len,
217+ std:: ptr:: from_mut ( & mut info) ,
127218 & mut size,
128219 BCRYPT_FLAGS :: default ( ) ,
129220 )
@@ -147,7 +238,7 @@ impl AeadKey {
147238 let ( ciphertext, tag) = data. split_at_mut ( payload_len - TAG_LEN ) ;
148239
149240 // https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_authenticated_cipher_mode_info
150- let info = BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO {
241+ let mut info = BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO {
151242 cbSize : core:: mem:: size_of :: < BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO > ( ) as u32 ,
152243 dwInfoVersion : BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION ,
153244 pbNonce : nonce. as_ptr ( ) . cast_mut ( ) ,
@@ -162,16 +253,15 @@ impl AeadKey {
162253 let mut size = 0u32 ;
163254
164255 unsafe {
165- // SAFETY: CNG supports in-place decryption, so the input and output buffers can be the same.
166-
167- let input = std :: slice :: from_raw_parts ( ciphertext. as_ptr ( ) . cast ( ) , ciphertext . len ( ) ) ;
256+ // SAFETY: CNG supports in-place decryption, and the raw helper accepts one buffer pointer
257+ // so Rust does not materialize overlapping input and output slice references.
258+ let len = ciphertext. len ( ) . try_into ( ) . unwrap ( ) ;
168259
169- BCryptDecrypt (
260+ bcrypt_decrypt_in_place (
170261 * self . handle ,
171- Some ( input) ,
172- Some ( std:: ptr:: from_ref ( & info) as * mut _ ) ,
173- None ,
174- Some ( ciphertext) ,
262+ ciphertext. as_mut_ptr ( ) ,
263+ len,
264+ std:: ptr:: from_mut ( & mut info) ,
175265 & mut size,
176266 BCRYPT_FLAGS :: default ( ) ,
177267 )
0 commit comments