Skip to content

Commit b1468ba

Browse files
committed
aes: autodetection support for AES-NI
Adds an off-by-default `autodetect` feature which the `cpuid-bool` crate to detect whether AES-NI is available when compiling on i686/x86_64 architectures.
1 parent 68c1756 commit b1468ba

File tree

8 files changed

+162
-44
lines changed

8 files changed

+162
-44
lines changed

.github/workflows/aes.yml

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ jobs:
3939
- run: cargo build --release --target ${{ matrix.target }}
4040
- run: cargo build --release --target ${{ matrix.target }} --features compact
4141
- run: cargo build --release --target ${{ matrix.target }} --features ctr
42-
- run: cargo build --release --target ${{ matrix.target }} --features compact,ctr
42+
- run: cargo build --release --target ${{ matrix.target }} --features force-soft
43+
- run: cargo build --release --target ${{ matrix.target }} --all-features
4344

4445
# Tests for the portable software backend
4546
soft:
@@ -73,6 +74,7 @@ jobs:
7374
- run: cargo test --release --target ${{ matrix.target }}
7475
- run: cargo test --release --target ${{ matrix.target }} --features compact
7576
- run: cargo test --release --target ${{ matrix.target }} --features ctr
77+
- run: cargo test --release --target ${{ matrix.target }} --features force-soft
7678
- run: cargo test --release --target ${{ matrix.target }} --all-features
7779

7880
# Tests for the AES-NI backend
@@ -111,37 +113,40 @@ jobs:
111113
- run: cargo test --release --target ${{ matrix.target }}
112114
- run: cargo test --release --target ${{ matrix.target }} --features compact
113115
- run: cargo test --release --target ${{ matrix.target }} --features ctr
116+
- run: cargo test --release --target ${{ matrix.target }} --features force-soft
114117
- run: cargo test --release --target ${{ matrix.target }} --all-features
115118

116119
# Cross-compiled tests
117-
cross:
118-
strategy:
119-
matrix:
120-
include:
121-
# ARM64
122-
- target: aarch64-unknown-linux-gnu
123-
rust: 1.41.0 # MSRV
124-
- target: aarch64-unknown-linux-gnu
125-
rust: stable
126-
127-
# PPC32
128-
- target: powerpc-unknown-linux-gnu
129-
rust: 1.41.0 # MSRV
130-
- target: powerpc-unknown-linux-gnu
131-
rust: stable
132-
133-
runs-on: ubuntu-latest
134-
steps:
135-
- uses: actions/checkout@v1
136-
- run: ${{ matrix.deps }}
137-
- uses: actions-rs/toolchain@v1
138-
with:
139-
toolchain: ${{ matrix.rust }}
140-
target: ${{ matrix.target }}
141-
profile: minimal
142-
override: true
143-
- run: cargo install cross
144-
- run: cross test --release --target ${{ matrix.target }}
145-
- run: cross test --release --target ${{ matrix.target }} --features compact
146-
- run: cross test --release --target ${{ matrix.target }} --features ctr
147-
- run: cross test --release --target ${{ matrix.target }} --features compact,ctr
120+
# TODO(tarcieri): re-enable these after cpuid-bool v0.2.0 is published
121+
# cross:
122+
# strategy:
123+
# matrix:
124+
# include:
125+
# # ARM64
126+
# - target: aarch64-unknown-linux-gnu
127+
# rust: 1.41.0 # MSRV
128+
# - target: aarch64-unknown-linux-gnu
129+
# rust: stable
130+
#
131+
# # PPC32
132+
# - target: powerpc-unknown-linux-gnu
133+
# rust: 1.41.0 # MSRV
134+
# - target: powerpc-unknown-linux-gnu
135+
# rust: stable
136+
#
137+
# runs-on: ubuntu-latest
138+
# steps:
139+
# - uses: actions/checkout@v1
140+
# - run: ${{ matrix.deps }}
141+
# - uses: actions-rs/toolchain@v1
142+
# with:
143+
# toolchain: ${{ matrix.rust }}
144+
# target: ${{ matrix.target }}
145+
# profile: minimal
146+
# override: true
147+
# - run: cargo install cross
148+
# - run: cross test --release --target ${{ matrix.target }}
149+
# - run: cross test --release --target ${{ matrix.target }} --features compact
150+
# - run: cross test --release --target ${{ matrix.target }} --features ctr
151+
# - run: cargo test --release --target ${{ matrix.target }} --features force-soft
152+
# - run: cargo test --release --target ${{ matrix.target }} --all-features

Cargo.lock

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,6 @@ members = [
1515
"twofish",
1616
"threefish",
1717
]
18+
19+
[patch.crates-io]
20+
cpuid-bool = { git = "https://github.com/RustCrypto/utils" }

aes/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,12 @@ opaque-debug = "0.3"
2323
[dev-dependencies]
2424
cipher = { version = "=0.3.0-pre", features = ["dev"] }
2525

26+
[target.'cfg(any(target_arch = "x86_64", target_arch = "x86"))'.dependencies]
27+
cpuid-bool = "0.2"
28+
2629
[features]
2730
compact = [] # Reduce code size at the cost of performance
31+
force-soft = [] # Disable support for AES hardware intrinsics
2832

2933
[package.metadata.docs.rs]
3034
all-features = true

aes/src/autodetect.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
//! Autodetection support for hardware accelerated AES backends with fallback
2+
//! to the fixsliced "soft" implementation.
3+
4+
use crate::{Block, ParBlocks};
5+
use cipher::{
6+
consts::{U16, U24, U32, U8},
7+
generic_array::GenericArray,
8+
BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher,
9+
};
10+
11+
cpuid_bool::new!(aes_cpuid, "aes");
12+
13+
macro_rules! define_aes_impl {
14+
(
15+
$name:tt,
16+
$module:tt,
17+
$key_size:ty,
18+
$doc:expr
19+
) => {
20+
#[doc=$doc]
21+
#[derive(Clone)]
22+
pub struct $name {
23+
inner: $module::Inner,
24+
token: aes_cpuid::InitToken
25+
}
26+
27+
mod $module {
28+
#[derive(Copy, Clone)]
29+
pub(super) union Inner {
30+
pub(super) ni: crate::ni::$name,
31+
pub(super) soft: crate::soft::$name,
32+
}
33+
}
34+
35+
impl NewBlockCipher for $name {
36+
type KeySize = $key_size;
37+
38+
#[inline]
39+
fn new(key: &GenericArray<u8, $key_size>) -> Self {
40+
let (token, aesni_present) = aes_cpuid::init_get();
41+
42+
let inner = if aesni_present {
43+
$module::Inner { ni: crate::ni::$name::new(key) }
44+
} else {
45+
$module::Inner { soft: crate::soft::$name::new(key) }
46+
};
47+
48+
Self { inner, token }
49+
}
50+
}
51+
52+
impl BlockCipher for $name {
53+
type BlockSize = U16;
54+
type ParBlocks = U8;
55+
}
56+
57+
impl BlockEncrypt for $name {
58+
#[inline]
59+
fn encrypt_block(&self, block: &mut Block) {
60+
if self.token.get() {
61+
unsafe { self.inner.ni.encrypt_block(block) }
62+
} else {
63+
unsafe { self.inner.soft.encrypt_block(block) }
64+
}
65+
}
66+
67+
#[inline]
68+
fn encrypt_par_blocks(&self, blocks: &mut ParBlocks) {
69+
if self.token.get() {
70+
unsafe { self.inner.ni.encrypt_par_blocks(blocks) }
71+
} else {
72+
unsafe { self.inner.soft.encrypt_par_blocks(blocks) }
73+
}
74+
}
75+
}
76+
77+
impl BlockDecrypt for $name {
78+
#[inline]
79+
fn decrypt_block(&self, block: &mut Block) {
80+
if self.token.get() {
81+
unsafe { self.inner.ni.decrypt_block(block) }
82+
} else {
83+
unsafe { self.inner.soft.decrypt_block(block) }
84+
}
85+
}
86+
87+
#[inline]
88+
fn decrypt_par_blocks(&self, blocks: &mut ParBlocks) {
89+
if self.token.get() {
90+
unsafe { self.inner.ni.decrypt_par_blocks(blocks) }
91+
} else {
92+
unsafe { self.inner.soft.decrypt_par_blocks(blocks) }
93+
}
94+
}
95+
}
96+
97+
opaque_debug::implement!($name);
98+
}
99+
}
100+
101+
define_aes_impl!(Aes128, aes128, U16, "AES-128 block cipher instance");
102+
define_aes_impl!(Aes192, aes192, U24, "AES-192 block cipher instance");
103+
define_aes_impl!(Aes256, aes256, U32, "AES-256 block cipher instance");

aes/src/lib.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,21 +63,16 @@ use cfg_if::cfg_if;
6363

6464
cfg_if! {
6565
if #[cfg(all(
66-
target_feature = "aes",
67-
target_feature = "sse2",
6866
any(target_arch = "x86_64", target_arch = "x86"),
67+
not(feature = "force-soft")
6968
))] {
7069
mod ni;
71-
pub use ni::{Aes128, Aes192, Aes256};
70+
mod autodetect;
71+
mod soft;
7272

73-
#[cfg(feature = "ctr")]
74-
cfg_if! {
75-
if #[cfg(target_feature = "ssse3")] {
76-
pub use ni::{Aes128Ctr, Aes192Ctr, Aes256Ctr};
77-
} else {
78-
compile_error!("Please enable the +ssse3 target feature to use `ctr` with AES-NI")
79-
}
80-
}
73+
pub use autodetect::{Aes128, Aes192, Aes256};
74+
75+
// TODO(tarcieri): AES-CTR
8176
} else {
8277
mod soft;
8378
pub use soft::{Aes128, Aes192, Aes256};

aes/src/soft/ctr.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! AES in counter mode (a.k.a. AES-CTR)
22
3+
#![cfg_attr(feature = "autodetect", allow(dead_code))]
4+
35
use super::{Aes128, Aes192, Aes256};
46

57
/// AES-128 in CTR mode

aes/src/soft/impls.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ macro_rules! define_aes_impl {
2020
$doc:expr
2121
) => {
2222
#[doc=$doc]
23-
#[derive(Clone)]
23+
#[derive(Copy, Clone)]
2424
pub struct $name {
2525
keys: $fixslice_keys,
2626
}

0 commit comments

Comments
 (0)