Skip to main content

aes/
autodetect.rs

1//! Autodetection support for hardware accelerated AES backends with fallback
2//! to the fixsliced "soft" implementation.
3
4use crate::soft;
5use cipher::{
6    AlgorithmName, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncClosure,
7    BlockCipherEncrypt, BlockSizeUser, Key, KeyInit, KeySizeUser,
8    consts::{U16, U24, U32},
9};
10use core::fmt;
11use core::mem::ManuallyDrop;
12
13#[cfg(target_arch = "aarch64")]
14use crate::armv8 as arch;
15
16#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
17use crate::x86 as arch;
18
19macro_rules! define_aes_impl {
20    (
21        name = $name:ident,
22        name_enc = $name_enc:ident,
23        name_dec = $name_dec:ident,
24        module = $module:tt,
25        key_size = $key_size:ty,
26        doc = $doc:expr,
27    ) => {
28        mod $module {
29            use super::{arch, soft};
30            use core::mem::ManuallyDrop;
31
32            pub(super) union Inner {
33                pub(super) arch: ManuallyDrop<arch::$name>,
34                pub(super) soft: ManuallyDrop<soft::$name>,
35            }
36
37            pub(super) union InnerEnc {
38                pub(super) arch: ManuallyDrop<arch::$name_enc>,
39                pub(super) soft: ManuallyDrop<soft::$name_enc>,
40            }
41
42            pub(super) union InnerDec {
43                pub(super) arch: ManuallyDrop<arch::$name_dec>,
44                pub(super) soft: ManuallyDrop<soft::$name_dec>,
45            }
46        }
47
48        #[doc=$doc]
49        #[doc = "block cipher"]
50        pub struct $name {
51            inner: $module::Inner,
52            token: arch::features::aes::InitToken,
53        }
54
55        impl KeySizeUser for $name {
56            type KeySize = $key_size;
57        }
58        impl From<$name_enc> for $name {
59            #[inline]
60            fn from(enc: $name_enc) -> $name {
61                Self::from(&enc)
62            }
63        }
64
65        impl From<&$name_enc> for $name {
66            fn from(enc: &$name_enc) -> $name {
67                use core::ops::Deref;
68                let inner = if enc.token.get() {
69                    $module::Inner {
70                        arch: ManuallyDrop::new(unsafe { enc.inner.arch.deref().into() }),
71                    }
72                } else {
73                    $module::Inner {
74                        soft: ManuallyDrop::new(unsafe { enc.inner.soft.deref().into() }),
75                    }
76                };
77
78                Self {
79                    inner,
80                    token: enc.token,
81                }
82            }
83        }
84
85        impl KeyInit for $name {
86            #[inline]
87            fn new(key: &Key<Self>) -> Self {
88                let (token, aes_features) = arch::features::aes::init_get();
89
90                let inner = if aes_features {
91                    $module::Inner {
92                        arch: ManuallyDrop::new(arch::$name::new(key)),
93                    }
94                } else {
95                    $module::Inner {
96                        soft: ManuallyDrop::new(soft::$name::new(key)),
97                    }
98                };
99
100                Self { inner, token }
101            }
102        }
103
104        impl Clone for $name {
105            fn clone(&self) -> Self {
106                let inner = if self.token.get() {
107                    $module::Inner {
108                        arch: unsafe { self.inner.arch.clone() },
109                    }
110                } else {
111                    $module::Inner {
112                        soft: unsafe { self.inner.soft.clone() },
113                    }
114                };
115
116                Self {
117                    inner,
118                    token: self.token,
119                }
120            }
121        }
122
123        impl BlockSizeUser for $name {
124            type BlockSize = U16;
125        }
126
127        impl BlockCipherEncrypt for $name {
128            fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure<BlockSize = U16>) {
129                if self.token.get() {
130                    unsafe { &self.inner.arch }.encrypt_with_backend(f)
131                } else {
132                    unsafe { &self.inner.soft }.encrypt_with_backend(f)
133                }
134            }
135        }
136
137        impl BlockCipherDecrypt for $name {
138            fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure<BlockSize = U16>) {
139                if self.token.get() {
140                    unsafe { &self.inner.arch }.decrypt_with_backend(f)
141                } else {
142                    unsafe { &self.inner.soft }.decrypt_with_backend(f)
143                }
144            }
145        }
146
147        impl fmt::Debug for $name {
148            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
149                f.write_str(concat!(stringify!($name), " { .. }"))
150            }
151        }
152
153        impl AlgorithmName for $name {
154            fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
155                f.write_str(stringify!($name))
156            }
157        }
158
159        impl Drop for $name {
160            #[inline]
161            fn drop(&mut self) {
162                if self.token.get() {
163                    unsafe { ManuallyDrop::drop(&mut self.inner.arch) };
164                } else {
165                    unsafe { ManuallyDrop::drop(&mut self.inner.soft) };
166                };
167            }
168        }
169
170        #[cfg(feature = "zeroize")]
171        impl zeroize::ZeroizeOnDrop for $name {}
172
173        #[doc=$doc]
174        #[doc = "block cipher (encrypt-only)"]
175        pub struct $name_enc {
176            inner: $module::InnerEnc,
177            token: arch::features::aes::InitToken,
178        }
179
180        impl KeySizeUser for $name_enc {
181            type KeySize = $key_size;
182        }
183
184        impl KeyInit for $name_enc {
185            #[inline]
186            fn new(key: &Key<Self>) -> Self {
187                let (token, aes_features) = arch::features::aes::init_get();
188
189                let inner = if aes_features {
190                    $module::InnerEnc {
191                        arch: ManuallyDrop::new(arch::$name_enc::new(key)),
192                    }
193                } else {
194                    $module::InnerEnc {
195                        soft: ManuallyDrop::new(soft::$name_enc::new(key)),
196                    }
197                };
198
199                Self { inner, token }
200            }
201        }
202
203        impl Clone for $name_enc {
204            fn clone(&self) -> Self {
205                let inner = if self.token.get() {
206                    $module::InnerEnc {
207                        arch: unsafe { self.inner.arch.clone() },
208                    }
209                } else {
210                    $module::InnerEnc {
211                        soft: unsafe { self.inner.soft.clone() },
212                    }
213                };
214
215                Self {
216                    inner,
217                    token: self.token,
218                }
219            }
220        }
221
222        impl BlockSizeUser for $name_enc {
223            type BlockSize = U16;
224        }
225
226        impl BlockCipherEncrypt for $name_enc {
227            fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure<BlockSize = U16>) {
228                if self.token.get() {
229                    unsafe { &self.inner.arch }.encrypt_with_backend(f)
230                } else {
231                    unsafe { &self.inner.soft }.encrypt_with_backend(f)
232                }
233            }
234        }
235
236        impl fmt::Debug for $name_enc {
237            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
238                f.write_str(concat!(stringify!($name_enc), " { .. }"))
239            }
240        }
241
242        impl AlgorithmName for $name_enc {
243            fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
244                f.write_str(stringify!($name_enc))
245            }
246        }
247
248        impl Drop for $name_enc {
249            #[inline]
250            fn drop(&mut self) {
251                if self.token.get() {
252                    unsafe { ManuallyDrop::drop(&mut self.inner.arch) };
253                } else {
254                    unsafe { ManuallyDrop::drop(&mut self.inner.soft) };
255                };
256            }
257        }
258
259        #[cfg(feature = "zeroize")]
260        impl zeroize::ZeroizeOnDrop for $name_enc {}
261
262        #[doc=$doc]
263        #[doc = "block cipher (decrypt-only)"]
264        pub struct $name_dec {
265            inner: $module::InnerDec,
266            token: arch::features::aes::InitToken,
267        }
268
269        impl KeySizeUser for $name_dec {
270            type KeySize = $key_size;
271        }
272
273        impl From<$name_enc> for $name_dec {
274            #[inline]
275            fn from(enc: $name_enc) -> $name_dec {
276                Self::from(&enc)
277            }
278        }
279
280        impl From<&$name_enc> for $name_dec {
281            fn from(enc: &$name_enc) -> $name_dec {
282                use core::ops::Deref;
283                let inner = if enc.token.get() {
284                    $module::InnerDec {
285                        arch: ManuallyDrop::new(unsafe { enc.inner.arch.deref().into() }),
286                    }
287                } else {
288                    $module::InnerDec {
289                        soft: ManuallyDrop::new(unsafe { enc.inner.soft.deref().into() }),
290                    }
291                };
292
293                Self {
294                    inner,
295                    token: enc.token,
296                }
297            }
298        }
299
300        impl KeyInit for $name_dec {
301            #[inline]
302            fn new(key: &Key<Self>) -> Self {
303                let (token, aes_features) = arch::features::aes::init_get();
304
305                let inner = if aes_features {
306                    $module::InnerDec {
307                        arch: ManuallyDrop::new(arch::$name_dec::new(key)),
308                    }
309                } else {
310                    $module::InnerDec {
311                        soft: ManuallyDrop::new(soft::$name_dec::new(key)),
312                    }
313                };
314
315                Self { inner, token }
316            }
317        }
318
319        impl Clone for $name_dec {
320            fn clone(&self) -> Self {
321                let inner = if self.token.get() {
322                    $module::InnerDec {
323                        arch: unsafe { self.inner.arch.clone() },
324                    }
325                } else {
326                    $module::InnerDec {
327                        soft: unsafe { self.inner.soft.clone() },
328                    }
329                };
330
331                Self {
332                    inner,
333                    token: self.token,
334                }
335            }
336        }
337
338        impl BlockSizeUser for $name_dec {
339            type BlockSize = U16;
340        }
341
342        impl BlockCipherDecrypt for $name_dec {
343            fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure<BlockSize = U16>) {
344                if self.token.get() {
345                    unsafe { &self.inner.arch }.decrypt_with_backend(f)
346                } else {
347                    unsafe { &self.inner.soft }.decrypt_with_backend(f)
348                }
349            }
350        }
351
352        impl fmt::Debug for $name_dec {
353            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
354                f.write_str(concat!(stringify!($name_dec), " { .. }"))
355            }
356        }
357
358        impl AlgorithmName for $name_dec {
359            fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
360                f.write_str(stringify!($name_dec))
361            }
362        }
363
364        impl Drop for $name_dec {
365            #[inline]
366            fn drop(&mut self) {
367                if self.token.get() {
368                    unsafe { ManuallyDrop::drop(&mut self.inner.arch) };
369                } else {
370                    unsafe { ManuallyDrop::drop(&mut self.inner.soft) };
371                };
372            }
373        }
374
375        #[cfg(feature = "zeroize")]
376        impl zeroize::ZeroizeOnDrop for $name_dec {}
377    };
378}
379
380define_aes_impl!(
381    name = Aes128,
382    name_enc = Aes128Enc,
383    name_dec = Aes128Dec,
384    module = aes128,
385    key_size = U16,
386    doc = "AES-128",
387);
388define_aes_impl!(
389    name = Aes192,
390    name_enc = Aes192Enc,
391    name_dec = Aes192Dec,
392    module = aes192,
393    key_size = U24,
394    doc = "AES-192",
395);
396define_aes_impl!(
397    name = Aes256,
398    name_enc = Aes256Enc,
399    name_dec = Aes256Dec,
400    module = aes256,
401    key_size = U32,
402    doc = "AES-256",
403);