Skip to content

Commit a5220ab

Browse files
committed
aes_gcm: Split x86-64 integrated implementation into its own module.
``` git difftool HEAD^1:src/aead/aes_gcm.rs \ src/aead/aes_gcm/aeshwclmulmovbe.rs ```
1 parent 2a6a4ec commit a5220ab

File tree

2 files changed

+159
-113
lines changed

2 files changed

+159
-113
lines changed

src/aead/aes_gcm.rs

Lines changed: 7 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2015-2016 Brian Smith.
1+
// Copyright 2015-2025 Brian Smith.
22
//
33
// Permission to use, copy, modify, and/or distribute this software for any
44
// purpose with or without fee is hereby granted, provided that the above
@@ -25,9 +25,6 @@ use crate::{
2525
};
2626
use core::ops::RangeFrom;
2727

28-
#[cfg(target_arch = "x86_64")]
29-
use aes::EncryptCtr32 as _;
30-
3128
#[cfg(any(
3229
all(target_arch = "aarch64", target_endian = "little"),
3330
all(target_arch = "arm", target_endian = "little"),
@@ -36,6 +33,8 @@ use aes::EncryptCtr32 as _;
3633
))]
3734
use cpu::GetFeature as _;
3835

36+
mod aeshwclmulmovbe;
37+
3938
#[derive(Clone)]
4039
pub(super) struct Key(DynKey);
4140

@@ -178,47 +177,7 @@ pub(super) fn seal(
178177
match key {
179178
#[cfg(target_arch = "x86_64")]
180179
DynKey::AesHwClMulAvxMovbe(Combo { aes_key, gcm_key }) => {
181-
use crate::c;
182-
let mut auth = gcm::Context::new(gcm_key, aad, in_out.len())?;
183-
let (htable, xi) = auth.inner();
184-
prefixed_extern! {
185-
// `HTable` and `Xi` should be 128-bit aligned. TODO: Can we shrink `HTable`? The
186-
// assembly says it needs just nine values in that array.
187-
fn aesni_gcm_encrypt(
188-
input: *const u8,
189-
output: *mut u8,
190-
len: c::size_t,
191-
key: &aes::AES_KEY,
192-
ivec: &mut Counter,
193-
Htable: &gcm::HTable,
194-
Xi: &mut gcm::Xi) -> c::size_t;
195-
}
196-
let processed = unsafe {
197-
aesni_gcm_encrypt(
198-
in_out.as_ptr(),
199-
in_out.as_mut_ptr(),
200-
in_out.len(),
201-
aes_key.inner_less_safe(),
202-
&mut ctr,
203-
htable,
204-
xi,
205-
)
206-
};
207-
208-
let ramaining = match in_out.get_mut(processed..) {
209-
Some(remaining) => remaining,
210-
None => {
211-
// This can't happen. If it did, then the assembly already
212-
// caused a buffer overflow.
213-
unreachable!()
214-
}
215-
};
216-
let (mut whole, remainder) = slice::as_chunks_mut(ramaining);
217-
aes_key.ctr32_encrypt_within(whole.as_flattened_mut().into(), &mut ctr);
218-
auth.update_blocks(whole.as_ref());
219-
let remainder = OverlappingPartialBlock::new(remainder.into())
220-
.unwrap_or_else(|InputTooLongError { .. }| unreachable!());
221-
seal_finish(aes_key, auth, remainder, ctr, tag_iv)
180+
aeshwclmulmovbe::seal(aes_key, gcm_key, ctr, tag_iv, aad, in_out)
222181
}
223182

224183
#[cfg(all(target_arch = "aarch64", target_endian = "little"))]
@@ -344,86 +303,21 @@ pub(super) fn open(
344303
in_out_slice: &mut [u8],
345304
src: RangeFrom<usize>,
346305
) -> Result<Tag, error::Unspecified> {
347-
#[cfg(any(
348-
all(target_arch = "aarch64", target_endian = "little"),
349-
target_arch = "x86_64"
350-
))]
351-
let in_out = Overlapping::new(in_out_slice, src.clone()).map_err(error::erase::<IndexError>)?;
352-
353306
let mut ctr = Counter::one(nonce);
354307
let tag_iv = ctr.increment();
355308

356309
match key {
357310
#[cfg(target_arch = "x86_64")]
358311
DynKey::AesHwClMulAvxMovbe(Combo { aes_key, gcm_key }) => {
359-
use crate::c;
360-
361-
prefixed_extern! {
362-
// `HTable` and `Xi` should be 128-bit aligned. TODO: Can we shrink `HTable`? The
363-
// assembly says it needs just nine values in that array.
364-
fn aesni_gcm_decrypt(
365-
input: *const u8,
366-
output: *mut u8,
367-
len: c::size_t,
368-
key: &aes::AES_KEY,
369-
ivec: &mut Counter,
370-
Htable: &gcm::HTable,
371-
Xi: &mut gcm::Xi) -> c::size_t;
372-
}
373-
374-
let mut auth = gcm::Context::new(gcm_key, aad, in_out.len())?;
375-
let processed = in_out.with_input_output_len(|input, output, len| {
376-
let (htable, xi) = auth.inner();
377-
unsafe {
378-
aesni_gcm_decrypt(
379-
input,
380-
output,
381-
len,
382-
aes_key.inner_less_safe(),
383-
&mut ctr,
384-
htable,
385-
xi,
386-
)
387-
}
388-
});
389-
let in_out_slice = in_out_slice.get_mut(processed..).unwrap_or_else(|| {
390-
// This can't happen. If it did, then the assembly already
391-
// caused a buffer overflow.
392-
unreachable!()
393-
});
394-
// Authenticate any remaining whole blocks.
395-
let in_out = Overlapping::new(in_out_slice, src.clone()).unwrap_or_else(
396-
|IndexError { .. }| {
397-
// This can't happen. If it did, then the assembly already
398-
// overwrote part of the remaining input.
399-
unreachable!()
400-
},
401-
);
402-
let (whole, _) = slice::as_chunks(in_out.input());
403-
auth.update_blocks(whole);
404-
405-
let whole_len = whole.as_flattened().len();
406-
407-
// Decrypt any remaining whole blocks.
408-
let whole = Overlapping::new(&mut in_out_slice[..(src.start + whole_len)], src.clone())
409-
.map_err(error::erase::<IndexError>)?;
410-
aes_key.ctr32_encrypt_within(whole, &mut ctr);
411-
412-
let in_out_slice = match in_out_slice.get_mut(whole_len..) {
413-
Some(partial) => partial,
414-
None => unreachable!(),
415-
};
416-
let in_out = Overlapping::new(in_out_slice, src)
417-
.unwrap_or_else(|IndexError { .. }| unreachable!());
418-
let in_out = OverlappingPartialBlock::new(in_out)
419-
.unwrap_or_else(|InputTooLongError { .. }| unreachable!());
420-
open_finish(aes_key, auth, in_out, ctr, tag_iv)
312+
aeshwclmulmovbe::open(aes_key, gcm_key, ctr, tag_iv, aad, in_out_slice, src)
421313
}
422314

423315
#[cfg(all(target_arch = "aarch64", target_endian = "little"))]
424316
DynKey::AesHwClMul(Combo { aes_key, gcm_key }) => {
425317
use crate::bits::BitLength;
426318

319+
let in_out =
320+
Overlapping::new(in_out_slice, src.clone()).map_err(error::erase::<IndexError>)?;
427321
let mut auth = gcm::Context::new(gcm_key, aad, in_out.len())?;
428322
let remainder_len = in_out.len() % BLOCK_LEN;
429323
let whole_len = in_out.len() - remainder_len;

src/aead/aes_gcm/aeshwclmulmovbe.rs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// Copyright 2015-2025 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 AUTHOR DISCLAIMS ALL WARRANTIES
8+
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9+
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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(target_arch = "x86_64")]
16+
17+
use super::{
18+
super::overlapping::IndexError,
19+
aes::{self, Counter, EncryptCtr32, Overlapping, OverlappingPartialBlock},
20+
gcm, Aad, Tag,
21+
};
22+
use crate::{
23+
c,
24+
error::{self, InputTooLongError},
25+
polyfill::slice,
26+
};
27+
use core::ops::RangeFrom;
28+
29+
pub(super) fn seal(
30+
aes_key: &aes::hw::Key,
31+
gcm_key: &gcm::clmulavxmovbe::Key,
32+
mut ctr: Counter,
33+
tag_iv: aes::Iv,
34+
aad: Aad<&[u8]>,
35+
in_out: &mut [u8],
36+
) -> Result<Tag, error::Unspecified> {
37+
prefixed_extern! {
38+
// `HTable` and `Xi` should be 128-bit aligned. TODO: Can we shrink `HTable`? The
39+
// assembly says it needs just nine values in that array.
40+
fn aesni_gcm_encrypt(
41+
input: *const u8,
42+
output: *mut u8,
43+
len: c::size_t,
44+
key: &aes::AES_KEY,
45+
ivec: &mut Counter,
46+
Htable: &gcm::HTable,
47+
Xi: &mut gcm::Xi) -> c::size_t;
48+
}
49+
50+
let mut auth = gcm::Context::new(gcm_key, aad, in_out.len())?;
51+
let (htable, xi) = auth.inner();
52+
53+
let processed = unsafe {
54+
aesni_gcm_encrypt(
55+
in_out.as_ptr(),
56+
in_out.as_mut_ptr(),
57+
in_out.len(),
58+
aes_key.inner_less_safe(),
59+
&mut ctr,
60+
htable,
61+
xi,
62+
)
63+
};
64+
65+
let ramaining = match in_out.get_mut(processed..) {
66+
Some(remaining) => remaining,
67+
None => {
68+
// This can't happen. If it did, then the assembly already
69+
// caused a buffer overflow.
70+
unreachable!()
71+
}
72+
};
73+
let (mut whole, remainder) = slice::as_chunks_mut(ramaining);
74+
aes_key.ctr32_encrypt_within(whole.as_flattened_mut().into(), &mut ctr);
75+
auth.update_blocks(whole.as_ref());
76+
let remainder = OverlappingPartialBlock::new(remainder.into())
77+
.unwrap_or_else(|InputTooLongError { .. }| unreachable!());
78+
79+
super::seal_finish(aes_key, auth, remainder, ctr, tag_iv)
80+
}
81+
82+
pub(super) fn open(
83+
aes_key: &aes::hw::Key,
84+
gcm_key: &gcm::clmulavxmovbe::Key,
85+
mut ctr: Counter,
86+
tag_iv: aes::Iv,
87+
aad: Aad<&[u8]>,
88+
in_out_slice: &mut [u8],
89+
src: RangeFrom<usize>,
90+
) -> Result<Tag, error::Unspecified> {
91+
prefixed_extern! {
92+
// `HTable` and `Xi` should be 128-bit aligned. TODO: Can we shrink `HTable`? The
93+
// assembly says it needs just nine values in that array.
94+
fn aesni_gcm_decrypt(
95+
input: *const u8,
96+
output: *mut u8,
97+
len: c::size_t,
98+
key: &aes::AES_KEY,
99+
ivec: &mut Counter,
100+
Htable: &gcm::HTable,
101+
Xi: &mut gcm::Xi) -> c::size_t;
102+
}
103+
104+
let in_out = Overlapping::new(in_out_slice, src.clone()).map_err(error::erase::<IndexError>)?;
105+
let mut auth = gcm::Context::new(gcm_key, aad, in_out.len())?;
106+
let processed = in_out.with_input_output_len(|input, output, len| {
107+
let (htable, xi) = auth.inner();
108+
unsafe {
109+
aesni_gcm_decrypt(
110+
input,
111+
output,
112+
len,
113+
aes_key.inner_less_safe(),
114+
&mut ctr,
115+
htable,
116+
xi,
117+
)
118+
}
119+
});
120+
let in_out_slice = in_out_slice.get_mut(processed..).unwrap_or_else(|| {
121+
// This can't happen. If it did, then the assembly already
122+
// caused a buffer overflow.
123+
unreachable!()
124+
});
125+
// Authenticate any remaining whole blocks.
126+
let in_out =
127+
Overlapping::new(in_out_slice, src.clone()).unwrap_or_else(|IndexError { .. }| {
128+
// This can't happen. If it did, then the assembly already
129+
// overwrote part of the remaining input.
130+
unreachable!()
131+
});
132+
let (whole, _) = slice::as_chunks(in_out.input());
133+
auth.update_blocks(whole);
134+
135+
let whole_len = whole.as_flattened().len();
136+
137+
// Decrypt any remaining whole blocks.
138+
let whole = Overlapping::new(&mut in_out_slice[..(src.start + whole_len)], src.clone())
139+
.map_err(error::erase::<IndexError>)?;
140+
aes_key.ctr32_encrypt_within(whole, &mut ctr);
141+
142+
let in_out_slice = match in_out_slice.get_mut(whole_len..) {
143+
Some(partial) => partial,
144+
None => unreachable!(),
145+
};
146+
let in_out =
147+
Overlapping::new(in_out_slice, src).unwrap_or_else(|IndexError { .. }| unreachable!());
148+
let in_out = OverlappingPartialBlock::new(in_out)
149+
.unwrap_or_else(|InputTooLongError { .. }| unreachable!());
150+
151+
super::open_finish(aes_key, auth, in_out, ctr, tag_iv)
152+
}

0 commit comments

Comments
 (0)