crypto\aes_256_gcm/
win.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use super::*;
5use crate::win::*;
6use std::sync::LazyLock;
7use windows::Win32::Security::Cryptography::BCRYPT_ALG_HANDLE;
8use windows::Win32::Security::Cryptography::BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO;
9use windows::Win32::Security::Cryptography::BCRYPT_KEY_HANDLE;
10use windows::Win32::Security::Cryptography::BCRYPT_OPEN_ALGORITHM_PROVIDER_FLAGS;
11use zerocopy::IntoBytes;
12
13static AES_256_GCM: LazyLock<Result<AlgHandle, Aes256GcmError>> = LazyLock::new(|| {
14    const CHAINING_MODE: &[u16] = wchar::wchz!("ChainingModeGCM");
15    let mut handle = BCRYPT_ALG_HANDLE::default();
16
17    // SAFETY: Errors are handled before the handle is used, and the handle is closed on drop.
18    unsafe {
19        let handle = windows::Win32::Security::Cryptography::BCryptOpenAlgorithmProvider(
20            &mut handle,
21            windows::Win32::Security::Cryptography::BCRYPT_AES_ALGORITHM,
22            None,
23            BCRYPT_OPEN_ALGORITHM_PROVIDER_FLAGS(0),
24        )
25        .ok()
26        .map(|()| AlgHandle(handle))
27        .map_err(|e| err(e, "open algorithm provider"))?;
28
29        windows::Win32::Security::Cryptography::BCryptSetProperty(
30            handle.0.into(),
31            windows::Win32::Security::Cryptography::BCRYPT_CHAINING_MODE,
32            CHAINING_MODE.as_bytes(),
33            0,
34        )
35        .ok()
36        .map_err(|e| err(e, "setting GCM Property"))?;
37
38        Ok(handle)
39    }
40});
41
42fn err(err: windows_result::Error, op: &'static str) -> Aes256GcmError {
43    Aes256GcmError(crate::BackendError(err, op))
44}
45
46pub struct Aes256GcmInner {
47    key: KeyHandle,
48}
49
50pub struct Aes256GcmEncCtxInner<'a> {
51    key: &'a KeyHandle,
52}
53
54pub struct Aes256GcmDecCtxInner<'a> {
55    key: &'a KeyHandle,
56}
57
58impl Aes256GcmInner {
59    pub fn new(key: &[u8; KEY_LEN]) -> Result<Self, Aes256GcmError> {
60        let mut handle = BCRYPT_KEY_HANDLE::default();
61        // SAFETY: the algorithm handle is valid.
62        let key = unsafe {
63            windows::Win32::Security::Cryptography::BCryptImportKey(
64                AES_256_GCM.as_ref().map_err(|e| e.clone())?.0,
65                None,
66                windows::Win32::Security::Cryptography::BCRYPT_KEY_DATA_BLOB,
67                &mut handle,
68                None,
69                KeyBlob32::new(key).as_bytes(),
70                0,
71            )
72        }
73        .ok()
74        .map(|()| KeyHandle(handle))
75        .map_err(|e| err(e, "importing key"))?;
76
77        Ok(Aes256GcmInner { key })
78    }
79
80    pub fn enc_ctx(&self) -> Result<Aes256GcmEncCtxInner<'_>, Aes256GcmError> {
81        Ok(Aes256GcmEncCtxInner { key: &self.key })
82    }
83
84    pub fn dec_ctx(&self) -> Result<Aes256GcmDecCtxInner<'_>, Aes256GcmError> {
85        Ok(Aes256GcmDecCtxInner { key: &self.key })
86    }
87}
88
89impl Aes256GcmEncCtxInner<'_> {
90    pub fn cipher(
91        &mut self,
92        iv: &[u8],
93        data: &[u8],
94        tag: &mut [u8],
95    ) -> Result<Vec<u8>, Aes256GcmError> {
96        let mut crypted_len = 0;
97        let mut iv_buffer = iv.to_vec();
98        let mut nonce_buffer = iv.to_vec();
99        let mut crypted_data = vec![0; data.len()];
100
101        let mut auth_mode = BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO {
102            cbSize: size_of::<BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO>() as u32,
103            dwInfoVersion: windows::Win32::Security::Cryptography::BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION,
104            pbNonce: nonce_buffer.as_mut_ptr(),
105            cbNonce: nonce_buffer.len() as u32,
106            pbTag: tag.as_mut_ptr(),
107            cbTag: tag.len() as u32,
108            ..Default::default()
109        };
110
111        // SAFETY: key and buffers are valid for the duration of the call
112        unsafe {
113            windows::Win32::Security::Cryptography::BCryptEncrypt(
114                self.key.0,
115                Some(data),
116                Some(std::ptr::from_mut(&mut auth_mode).cast()),
117                Some(&mut iv_buffer),
118                Some(&mut crypted_data),
119                &mut crypted_len,
120                windows::Win32::Security::Cryptography::BCRYPT_FLAGS(0),
121            )
122            .ok()
123            .map_err(|e| err(e, "encrypt"))
124        }?;
125        assert_eq!(crypted_len as usize, data.len());
126        Ok(crypted_data)
127    }
128}
129
130impl Aes256GcmDecCtxInner<'_> {
131    pub fn cipher(
132        &mut self,
133        iv: &[u8],
134        data: &[u8],
135        tag: &[u8],
136    ) -> Result<Vec<u8>, Aes256GcmError> {
137        let mut crypted_len = 0;
138        let mut iv_buffer = iv.to_vec();
139        let mut nonce_buffer = iv.to_vec();
140        let mut crypted_data = vec![0; data.len()];
141        let mut tag_buffer = tag.to_vec();
142
143        let mut auth_mode = BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO {
144            cbSize: size_of::<BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO>() as u32,
145            dwInfoVersion: windows::Win32::Security::Cryptography::BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION,
146            pbNonce: nonce_buffer.as_mut_ptr(),
147            cbNonce: nonce_buffer.len() as u32,
148            pbTag: tag_buffer.as_mut_ptr(),
149            cbTag: tag_buffer.len() as u32,
150            ..Default::default()
151        };
152
153        // SAFETY: key and buffers are valid for the duration of the call
154        unsafe {
155            windows::Win32::Security::Cryptography::BCryptDecrypt(
156                self.key.0,
157                Some(data),
158                Some(std::ptr::from_mut(&mut auth_mode).cast()),
159                Some(&mut iv_buffer),
160                Some(&mut crypted_data),
161                &mut crypted_len,
162                windows::Win32::Security::Cryptography::BCRYPT_FLAGS(0),
163            )
164            .ok()
165            .map_err(|e| err(e, "decrypt"))
166        }?;
167        assert_eq!(crypted_len as usize, data.len());
168        Ok(crypted_data)
169    }
170}