Skip to content

Commit

Permalink
aes: autodetection support for AES-NI
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tarcieri committed Nov 30, 2020
1 parent 68c1756 commit 4d1dff8
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 44 deletions.
69 changes: 37 additions & 32 deletions .github/workflows/aes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ jobs:
- run: cargo build --release --target ${{ matrix.target }}
- run: cargo build --release --target ${{ matrix.target }} --features compact
- run: cargo build --release --target ${{ matrix.target }} --features ctr
- run: cargo build --release --target ${{ matrix.target }} --features compact,ctr
- run: cargo build --release --target ${{ matrix.target }} --features force-soft
- run: cargo build --release --target ${{ matrix.target }} --all-features

# Tests for the portable software backend
soft:
Expand Down Expand Up @@ -73,6 +74,7 @@ jobs:
- run: cargo test --release --target ${{ matrix.target }}
- run: cargo test --release --target ${{ matrix.target }} --features compact
- run: cargo test --release --target ${{ matrix.target }} --features ctr
- run: cargo test --release --target ${{ matrix.target }} --features force-soft
- run: cargo test --release --target ${{ matrix.target }} --all-features

# Tests for the AES-NI backend
Expand Down Expand Up @@ -111,37 +113,40 @@ jobs:
- run: cargo test --release --target ${{ matrix.target }}
- run: cargo test --release --target ${{ matrix.target }} --features compact
- run: cargo test --release --target ${{ matrix.target }} --features ctr
- run: cargo test --release --target ${{ matrix.target }} --features force-soft
- run: cargo test --release --target ${{ matrix.target }} --all-features

# Cross-compiled tests
cross:
strategy:
matrix:
include:
# ARM64
- target: aarch64-unknown-linux-gnu
rust: 1.41.0 # MSRV
- target: aarch64-unknown-linux-gnu
rust: stable

# PPC32
- target: powerpc-unknown-linux-gnu
rust: 1.41.0 # MSRV
- target: powerpc-unknown-linux-gnu
rust: stable

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- run: ${{ matrix.deps }}
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
profile: minimal
override: true
- run: cargo install cross
- run: cross test --release --target ${{ matrix.target }}
- run: cross test --release --target ${{ matrix.target }} --features compact
- run: cross test --release --target ${{ matrix.target }} --features ctr
- run: cross test --release --target ${{ matrix.target }} --features compact,ctr
# TODO(tarcieri): re-enable these after cpuid-bool v0.2.0 is published
# cross:
# strategy:
# matrix:
# include:
# # ARM64
# - target: aarch64-unknown-linux-gnu
# rust: 1.41.0 # MSRV
# - target: aarch64-unknown-linux-gnu
# rust: stable
#
# # PPC32
# - target: powerpc-unknown-linux-gnu
# rust: 1.41.0 # MSRV
# - target: powerpc-unknown-linux-gnu
# rust: stable
#
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v1
# - run: ${{ matrix.deps }}
# - uses: actions-rs/toolchain@v1
# with:
# toolchain: ${{ matrix.rust }}
# target: ${{ matrix.target }}
# profile: minimal
# override: true
# - run: cargo install cross
# - run: cross test --release --target ${{ matrix.target }}
# - run: cross test --release --target ${{ matrix.target }} --features compact
# - run: cross test --release --target ${{ matrix.target }} --features ctr
# - run: cargo test --release --target ${{ matrix.target }} --features force-soft
# - run: cargo test --release --target ${{ matrix.target }} --all-features
6 changes: 6 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ members = [
"twofish",
"threefish",
]

[patch.crates-io]
cpuid-bool = { git = "https://github.com/RustCrypto/utils" }
4 changes: 4 additions & 0 deletions aes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@ opaque-debug = "0.3"
[dev-dependencies]
cipher = { version = "=0.3.0-pre", features = ["dev"] }

[target.'cfg(any(target_arch = "x86_64", target_arch = "x86"))'.dependencies]
cpuid-bool = "0.2"

[features]
compact = [] # Reduce code size at the cost of performance
force-soft = [] # Disable support for AES hardware intrinsics

[package.metadata.docs.rs]
all-features = true
Expand Down
103 changes: 103 additions & 0 deletions aes/src/autodetect.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//! Autodetection support for hardware accelerated AES backends with fallback
//! to the fixsliced "soft" implementation.
use crate::{Block, ParBlocks};
use cipher::{
consts::{U16, U24, U32, U8},
generic_array::GenericArray,
BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher,
};

cpuid_bool::new!(aes_cpuid, "aes");

macro_rules! define_aes_impl {
(
$name:tt,
$module:tt,
$key_size:ty,
$doc:expr
) => {
#[doc=$doc]
#[derive(Clone)]
pub struct $name {
inner: $module::Inner,
token: aes_cpuid::InitToken
}

mod $module {
#[derive(Copy, Clone)]
pub(super) union Inner {
pub(super) ni: crate::ni::$name,
pub(super) soft: crate::soft::$name,
}
}

impl NewBlockCipher for $name {
type KeySize = $key_size;

#[inline]
fn new(key: &GenericArray<u8, $key_size>) -> Self {
let (token, aesni_present) = aes_cpuid::init_get();

let inner = if aesni_present {
$module::Inner { ni: crate::ni::$name::new(key) }
} else {
$module::Inner { soft: crate::soft::$name::new(key) }
};

Self { inner, token }
}
}

impl BlockCipher for $name {
type BlockSize = U16;
type ParBlocks = U8;
}

impl BlockEncrypt for $name {
#[inline]
fn encrypt_block(&self, block: &mut Block) {
if self.token.get() {
unsafe { self.inner.ni.encrypt_block(block) }
} else {
unsafe { self.inner.soft.encrypt_block(block) }
}
}

#[inline]
fn encrypt_par_blocks(&self, blocks: &mut ParBlocks) {
if self.token.get() {
unsafe { self.inner.ni.encrypt_par_blocks(blocks) }
} else {
unsafe { self.inner.soft.encrypt_par_blocks(blocks) }
}
}
}

impl BlockDecrypt for $name {
#[inline]
fn decrypt_block(&self, block: &mut Block) {
if self.token.get() {
unsafe { self.inner.ni.decrypt_block(block) }
} else {
unsafe { self.inner.soft.decrypt_block(block) }
}
}

#[inline]
fn decrypt_par_blocks(&self, blocks: &mut ParBlocks) {
if self.token.get() {
unsafe { self.inner.ni.decrypt_par_blocks(blocks) }
} else {
unsafe { self.inner.soft.decrypt_par_blocks(blocks) }
}
}
}

opaque_debug::implement!($name);
}
}

define_aes_impl!(Aes128, aes128, U16, "AES-128 block cipher instance");
define_aes_impl!(Aes192, aes192, U24, "AES-192 block cipher instance");
define_aes_impl!(Aes256, aes256, U32, "AES-256 block cipher instance");
17 changes: 6 additions & 11 deletions aes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,16 @@ use cfg_if::cfg_if;

cfg_if! {
if #[cfg(all(
target_feature = "aes",
target_feature = "sse2",
any(target_arch = "x86_64", target_arch = "x86"),
not(feature = "force-soft")
))] {
mod ni;
pub use ni::{Aes128, Aes192, Aes256};
mod autodetect;
mod soft;

#[cfg(feature = "ctr")]
cfg_if! {
if #[cfg(target_feature = "ssse3")] {
pub use ni::{Aes128Ctr, Aes192Ctr, Aes256Ctr};
} else {
compile_error!("Please enable the +ssse3 target feature to use `ctr` with AES-NI")
}
}
pub use autodetect::{Aes128, Aes192, Aes256};

// TODO(tarcieri): AES-CTR
} else {
mod soft;
pub use soft::{Aes128, Aes192, Aes256};
Expand Down
3 changes: 3 additions & 0 deletions aes/src/soft/ctr.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
//! AES in counter mode (a.k.a. AES-CTR)
// TODO(tarcieri): fix AES-CTR autodetection
#![allow(dead_code)]

use super::{Aes128, Aes192, Aes256};

/// AES-128 in CTR mode
Expand Down
2 changes: 1 addition & 1 deletion aes/src/soft/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ macro_rules! define_aes_impl {
$doc:expr
) => {
#[doc=$doc]
#[derive(Clone)]
#[derive(Copy, Clone)]
pub struct $name {
keys: $fixslice_keys,
}
Expand Down

0 comments on commit 4d1dff8

Please sign in to comment.