1 | // Copyright 2018-2024 Brian Smith. |
2 | // |
3 | // Permission to use, copy, modify, and/or distribute this software for any |
4 | // purpose with or without fee is hereby granted, provided that the above |
5 | // copyright notice and this permission notice appear in all copies. |
6 | // |
7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES |
8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY |
10 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
14 | |
15 | #![cfg (any( |
16 | all(target_arch = "aarch64" , target_endian = "little" ), |
17 | target_arch = "x86" , |
18 | target_arch = "x86_64" |
19 | ))] |
20 | |
21 | use super::{Block, Counter, EncryptBlock, EncryptCtr32, Iv, KeyBytes, Overlapping, AES_KEY}; |
22 | use crate::{cpu, error}; |
23 | use cfg_if::cfg_if; |
24 | |
25 | cfg_if! { |
26 | if #[cfg(all(target_arch = "aarch64" , target_endian = "little" ))] { |
27 | pub(in super::super) type RequiredCpuFeatures = cpu::arm::Aes; |
28 | pub(in super::super) type OptionalCpuFeatures = (); |
29 | } else if #[cfg(any(target_arch = "x86" , target_arch = "x86_64" ))] { |
30 | use cpu::intel::{Aes, Avx, Ssse3}; |
31 | // Some functions seem to have been written to require only SSE/SSE2 |
32 | // but there seem to be no SSSE3-less CPUs with AES-NI, and we don't |
33 | // have feature detection for SSE2. |
34 | pub(in super::super) type RequiredCpuFeatures = (Aes, Ssse3); |
35 | pub(in super::super) type OptionalCpuFeatures = Avx; |
36 | } |
37 | } |
38 | |
39 | #[derive (Clone)] |
40 | pub struct Key { |
41 | inner: AES_KEY, |
42 | } |
43 | |
44 | impl Key { |
45 | #[cfg (all(target_arch = "aarch64" , target_endian = "little" ))] |
46 | pub(in super::super) fn new( |
47 | bytes: KeyBytes<'_>, |
48 | _required_cpu_features: RequiredCpuFeatures, |
49 | _optional_cpu_features: Option<OptionalCpuFeatures>, |
50 | ) -> Result<Self, error::Unspecified> { |
51 | let inner = unsafe { set_encrypt_key!(aes_hw_set_encrypt_key, bytes) }?; |
52 | Ok(Self { inner }) |
53 | } |
54 | |
55 | #[cfg (any(target_arch = "x86" , target_arch = "x86_64" ))] |
56 | pub(in super::super) fn new( |
57 | bytes: KeyBytes<'_>, |
58 | (Aes { .. }, Ssse3 { .. }): RequiredCpuFeatures, |
59 | optional_cpu_features: Option<OptionalCpuFeatures>, |
60 | ) -> Result<Self, error::Unspecified> { |
61 | // Ssse3 is required, but upstream only uses this if there is also Avx; |
62 | // presumably the base version is faster on pre-AVX CPUs. |
63 | let inner = if let Some(Avx { .. }) = optional_cpu_features { |
64 | unsafe { set_encrypt_key!(aes_hw_set_encrypt_key_alt, bytes) }? |
65 | } else { |
66 | unsafe { set_encrypt_key!(aes_hw_set_encrypt_key_base, bytes) }? |
67 | }; |
68 | Ok(Self { inner }) |
69 | } |
70 | |
71 | #[cfg (any( |
72 | all(target_arch = "aarch64" , target_endian = "little" ), |
73 | target_arch = "x86_64" |
74 | ))] |
75 | #[must_use ] |
76 | pub(in super::super) fn inner_less_safe(&self) -> &AES_KEY { |
77 | &self.inner |
78 | } |
79 | } |
80 | |
81 | impl EncryptBlock for Key { |
82 | fn encrypt_block(&self, block: Block) -> Block { |
83 | super::encrypt_block_using_encrypt_iv_xor_block(self, block) |
84 | } |
85 | |
86 | fn encrypt_iv_xor_block(&self, iv: Iv, block: Block) -> Block { |
87 | super::encrypt_iv_xor_block_using_ctr32(self, iv, block) |
88 | } |
89 | } |
90 | |
91 | impl EncryptCtr32 for Key { |
92 | fn ctr32_encrypt_within(&self, in_out: Overlapping<'_>, ctr: &mut Counter) { |
93 | unsafe { ctr32_encrypt_blocks!(aes_hw_ctr32_encrypt_blocks, in_out, &self.inner, ctr) } |
94 | } |
95 | } |
96 | |