Skip to content

Commit ca62f3f

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 c5016a7 commit ca62f3f

File tree

6 files changed

+145
-7
lines changed

6 files changed

+145
-7
lines changed

.github/workflows/aes.yml

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ env:
1717
RUSTFLAGS: "-Dwarnings"
1818

1919
jobs:
20+
# Builds for no_std platforms
2021
build:
2122
runs-on: ubuntu-latest
2223
strategy:
@@ -36,7 +37,9 @@ jobs:
3637
profile: minimal
3738
override: true
3839
- run: cargo build --release --target ${{ matrix.target }}
39-
- run: cargo build --release --target ${{ matrix.target }} --all-features
40+
- run: cargo build --release --target ${{ matrix.target }} --features compact
41+
- run: cargo build --release --target ${{ matrix.target }} --features ctr
42+
- run: cargo build --release --target ${{ matrix.target }} --features compact,ctr
4043

4144
# Tests for the portable software backend
4245
soft:
@@ -68,6 +71,7 @@ jobs:
6871
- run: ${{ matrix.deps }}
6972
- run: cargo check --target ${{ matrix.target }} --all-features
7073
- run: cargo test --release --target ${{ matrix.target }}
74+
- run: cargo test --release --target ${{ matrix.target }} --features autodetect
7175
- run: cargo test --release --target ${{ matrix.target }} --features compact
7276
- run: cargo test --release --target ${{ matrix.target }} --features ctr
7377
- run: cargo test --release --target ${{ matrix.target }} --all-features
@@ -99,13 +103,17 @@ jobs:
99103
- uses: actions/checkout@v1
100104
- uses: actions-rs/toolchain@v1
101105
with:
102-
profile: minimal
103106
toolchain: ${{ matrix.rust }}
107+
target: ${{ matrix.target }}
108+
profile: minimal
109+
override: true
104110
- run: ${{ matrix.deps }}
105-
- run: cargo check --all-features
106-
- run: cargo test --no-default-features
107-
- run: cargo test
108-
- run: cargo test --all-features
111+
- run: cargo check --target ${{ matrix.target }} --all-features
112+
- run: cargo test --release --target ${{ matrix.target }}
113+
- run: cargo test --release --target ${{ matrix.target }} --features autodetect
114+
- run: cargo test --release --target ${{ matrix.target }} --features compact
115+
- run: cargo test --release --target ${{ matrix.target }} --features ctr
116+
- run: cargo test --release --target ${{ matrix.target }} --all-features
109117

110118
# Cross-compiled tests
111119
cross:
@@ -137,3 +145,5 @@ jobs:
137145
- run: cargo install cross
138146
- run: cross test --release --target ${{ matrix.target }}
139147
- run: cross test --release --target ${{ matrix.target }} --features compact
148+
- run: cross test --release --target ${{ matrix.target }} --features ctr
149+
- run: cross test --release --target ${{ matrix.target }} --features compact,ctr

Cargo.lock

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

aes/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ categories = ["cryptography", "no-std"]
1717
[dependencies]
1818
cfg-if = "1"
1919
cipher = "=0.3.0-pre"
20+
cpuid-bool = { version = "0.1", optional = true }
2021
ctr = { version = "=0.7.0-pre", optional = true }
2122
opaque-debug = "0.3"
2223

2324
[dev-dependencies]
2425
cipher = { version = "=0.3.0-pre", features = ["dev"] }
2526

2627
[features]
28+
autodetect = ["cpuid-bool"] # Detect hardware AES and fallback to "soft" if unavailable
2729
compact = [] # Reduce code size at the cost of performance
2830

2931
[package.metadata.docs.rs]

aes/src/autodetect.rs

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

aes/src/lib.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,17 @@ cfg_if! {
6868
any(target_arch = "x86_64", target_arch = "x86"),
6969
))] {
7070
mod ni;
71-
pub use ni::{Aes128, Aes192, Aes256};
71+
72+
cfg_if! {
73+
if #[cfg(feature = "autodetect")] {
74+
mod autodetect;
75+
mod soft;
76+
77+
pub use autodetect::{Aes128, Aes192, Aes256};
78+
} else {
79+
pub use ni::{Aes128, Aes192, Aes256};
80+
}
81+
}
7282

7383
#[cfg(feature = "ctr")]
7484
cfg_if! {

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

0 commit comments

Comments
 (0)