diff --git a/aes/Cargo.toml b/aes/Cargo.toml index d44c8d37e..cdbd595d2 100644 --- a/aes/Cargo.toml +++ b/aes/Cargo.toml @@ -31,7 +31,8 @@ level = "warn" check-cfg = [ 'cfg(aes_backend_soft, values("compact"))', 'cfg(aes_backend, values("soft"))', - 'cfg(cpubits, values("16", "32", "64"))' + 'cfg(cpubits, values("16", "32", "64"))', + 'cfg(__enable_aes_soft_backend)' ] [package.metadata.docs.rs] diff --git a/aes/build.rs b/aes/build.rs new file mode 100644 index 000000000..23b790e29 --- /dev/null +++ b/aes/build.rs @@ -0,0 +1,30 @@ +use std::collections::HashSet; + +fn main() { + let needs_soft = needs_soft(); + if needs_soft { + println!("cargo::rustc-cfg=__enable_aes_soft_backend"); + } +} + +/// Returns whether the soft backend is required. +/// +/// The soft backend may not be required if the target's features are +/// sufficient for one of the accelerated backends and the user did not +/// explicitly opt into the soft backend. +fn needs_soft() -> bool { + if std::env::var("CARGO_CFG_AES_BACKEND").is_ok_and(|value| value == "soft") { + return true; + } + + let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").expect("missing target_arch"); + let target_features = std::env::var("CARGO_CFG_TARGET_FEATURE").unwrap_or_default(); + let target_features = target_features.split(',').collect::>(); + let miri = std::env::var("CARGO_CFG_MIRI").is_ok(); + + match &*target_arch { + "x86" | "x86_64" => !target_features.contains("aes"), + "aarch64" if !miri => !target_features.contains("aes"), + _ => true, + } +} diff --git a/aes/src/backends.rs b/aes/src/backends.rs index c6c1aaa68..05bc632b4 100644 --- a/aes/src/backends.rs +++ b/aes/src/backends.rs @@ -1,3 +1,4 @@ +#[cfg(__enable_aes_soft_backend)] pub(crate) mod soft; cpubits::cfg_if! { diff --git a/aes/src/hazmat.rs b/aes/src/hazmat.rs index 373340685..45e0c49b1 100644 --- a/aes/src/hazmat.rs +++ b/aes/src/hazmat.rs @@ -11,6 +11,7 @@ //! We do NOT recommend using it to implement any algorithm which has not //! received extensive peer review by cryptographers. +#[cfg(__enable_aes_soft_backend)] use crate::backends::soft::hazmat as soft; pub use crate::Block; @@ -42,6 +43,17 @@ macro_rules! if_intrinsics_available { }}; } +/// Execute the provided body if the soft backend is available. +macro_rules! if_soft_backend_available { + ($body:expr) => {{ + #[cfg(__enable_aes_soft_backend)] + if true { + $body; + return; + } + }}; +} + /// ⚠️ AES cipher (encrypt) round function. /// /// This API performs the following steps as described in FIPS 197 Appendix C: @@ -62,7 +74,11 @@ pub fn cipher_round(block: &mut Block, round_key: &Block) { intrinsics::cipher_round(block, round_key) } - soft::cipher_round(block, round_key); + if_soft_backend_available! { + soft::cipher_round(block, round_key) + } + + unreachable!(); } /// ⚠️ AES cipher (encrypt) round function: parallel version. @@ -79,7 +95,11 @@ pub fn cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { intrinsics::cipher_round_par(blocks, round_keys) } - soft::cipher_round_par(blocks, round_keys); + if_soft_backend_available! { + soft::cipher_round_par(blocks, round_keys) + } + + unreachable!(); } /// ⚠️ AES equivalent inverse cipher (decrypt) round function. @@ -102,7 +122,11 @@ pub fn equiv_inv_cipher_round(block: &mut Block, round_key: &Block) { intrinsics::equiv_inv_cipher_round(block, round_key) } - soft::equiv_inv_cipher_round(block, round_key); + if_soft_backend_available! { + soft::equiv_inv_cipher_round(block, round_key) + } + + unreachable!(); } /// ⚠️ AES equivalent inverse cipher (decrypt) round function: parallel version. @@ -119,7 +143,11 @@ pub fn equiv_inv_cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { intrinsics::equiv_inv_cipher_round_par(blocks, round_keys) } - soft::equiv_inv_cipher_round_par(blocks, round_keys); + if_soft_backend_available! { + soft::equiv_inv_cipher_round_par(blocks, round_keys) + } + + unreachable!(); } /// ⚠️ AES mix columns function. @@ -133,7 +161,11 @@ pub fn mix_columns(block: &mut Block) { intrinsics::mix_columns(block) } - soft::mix_columns(block); + if_soft_backend_available! { + soft::mix_columns(block) + } + + unreachable!(); } /// ⚠️ AES inverse mix columns function. @@ -149,5 +181,9 @@ pub fn inv_mix_columns(block: &mut Block) { intrinsics::inv_mix_columns(block) } - soft::inv_mix_columns(block); + if_soft_backend_available! { + soft::inv_mix_columns(block) + } + + unreachable!(); } diff --git a/aes/src/lib.rs b/aes/src/lib.rs index 2ee6820a3..79c4b5bcb 100644 --- a/aes/src/lib.rs +++ b/aes/src/lib.rs @@ -247,9 +247,15 @@ macro_rules! impl_key_init { } } - let soft = backends::soft::$soft_name::new(key); - let inner = Inner { soft }; - Self { inner, token } + cfg_if! { + if #[cfg(__enable_aes_soft_backend)] { + let soft = backends::soft::$soft_name::new(key); + let inner = Inner { soft }; + return Self { inner, token }; + } else { + unreachable!(); + } + } } } }; @@ -297,9 +303,15 @@ macro_rules! impl_encrypt { } } - // SAFETY: we access correct union variant - let backend = unsafe { &self.inner.soft }; - f.call(backend); + cfg_if! { + if #[cfg(__enable_aes_soft_backend)] { + // SAFETY: we access correct union variant + let backend = unsafe { &self.inner.soft }; + f.call(backend); + } else { + unreachable!(); + } + } } } }; @@ -347,9 +359,15 @@ macro_rules! impl_decrypt { } } - // SAFETY: we access correct union variant - let backend = unsafe { &self.inner.soft }; - f.call(backend); + cfg_if! { + if #[cfg(__enable_aes_soft_backend)] { + // SAFETY: we access correct union variant + let backend = unsafe { &self.inner.soft }; + f.call(backend); + } else { + unreachable!(); + } + } } } }; @@ -387,10 +405,16 @@ macro_rules! impl_from_enc { } } - // SAFETY: we access correct union variant - let soft = unsafe { enc.inner.soft }; - let inner = Inner { soft }; - Self { inner, token } + cfg_if! { + if #[cfg(__enable_aes_soft_backend)] { + // SAFETY: we access correct union variant + let soft = unsafe { enc.inner.soft }; + let inner = Inner { soft }; + Self { inner, token } + } else { + unreachable!(); + } + } } } @@ -457,6 +481,7 @@ macro_rules! define_aes_impl { pub(super) aes: backends::x86_aes::$name, #[cfg(all(target_arch = "aarch64", not(miri), not(aes_backend = "soft")))] pub(super) aes: backends::aarch64_aes::$name, + #[cfg(__enable_aes_soft_backend)] pub(super) soft: backends::soft::$name, } @@ -469,6 +494,7 @@ macro_rules! define_aes_impl { pub(super) aes: backends::x86_aes::$name_enc, #[cfg(all(target_arch = "aarch64", not(miri), not(aes_backend = "soft")))] pub(super) aes: backends::aarch64_aes::$name_enc, + #[cfg(__enable_aes_soft_backend)] pub(super) soft: backends::soft::$name, } @@ -481,6 +507,7 @@ macro_rules! define_aes_impl { pub(super) aes: backends::x86_aes::$name_dec, #[cfg(all(target_arch = "aarch64", not(miri), not(aes_backend = "soft")))] pub(super) aes: backends::aarch64_aes::$name_dec, + #[cfg(__enable_aes_soft_backend)] pub(super) soft: backends::soft::$name, } }