#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod ni;
mod soft;
use crate::secret::Secret;
use crate::Error;
use core::fmt;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Backend {
Software,
AesNi,
}
impl Backend {
pub fn detect() -> Backend {
if Backend::AesNi.is_available() {
Backend::AesNi
} else {
Backend::Software
}
}
pub fn is_available(self) -> bool {
match self {
Backend::Software => true,
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Backend::AesNi => ni::available(),
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
Backend::AesNi => false,
}
}
pub fn is_constant_time(self) -> bool {
matches!(self, Backend::AesNi)
}
pub fn constant_time() -> Result<Backend, Error> {
if Backend::AesNi.is_available() {
Ok(Backend::AesNi)
} else {
Err(Error::BackendUnavailable)
}
}
}
#[derive(Clone, Copy)]
pub(crate) enum KeyRef<'a> {
K128(&'a [u8; 16]),
K192(&'a [u8; 24]),
K256(&'a [u8; 32]),
}
impl<'a> KeyRef<'a> {
fn from_slice(key: &'a [u8]) -> Result<Self, Error> {
if let Ok(k) = key.try_into() {
return Ok(KeyRef::K128(k));
}
if let Ok(k) = key.try_into() {
return Ok(KeyRef::K192(k));
}
if let Ok(k) = key.try_into() {
return Ok(KeyRef::K256(k));
}
Err(Error::InvalidKeyLength(key.len()))
}
pub(crate) fn as_bytes(&self) -> &'a [u8] {
match *self {
KeyRef::K128(k) => k,
KeyRef::K192(k) => k,
KeyRef::K256(k) => k,
}
}
pub(crate) fn words(&self) -> usize {
match self {
KeyRef::K128(_) => 4,
KeyRef::K192(_) => 6,
KeyRef::K256(_) => 8,
}
}
pub(crate) fn rounds(&self) -> usize {
match self {
KeyRef::K128(_) => 10,
KeyRef::K192(_) => 12,
KeyRef::K256(_) => 14,
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum AesKey {
Aes128(Secret<[u8; 16]>),
Aes192(Secret<[u8; 24]>),
Aes256(Secret<[u8; 32]>),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum KeySize {
Aes128,
Aes192,
Aes256,
}
impl KeySize {
pub fn len(self) -> usize {
match self {
KeySize::Aes128 => 16,
KeySize::Aes192 => 24,
KeySize::Aes256 => 32,
}
}
pub fn is_empty(self) -> bool {
false
}
}
impl AesKey {
pub fn generate(size: KeySize) -> Result<Self, Error> {
Ok(match size {
KeySize::Aes128 => AesKey::Aes128(Secret::new(crate::random::bytes()?)),
KeySize::Aes192 => AesKey::Aes192(Secret::new(crate::random::bytes()?)),
KeySize::Aes256 => AesKey::Aes256(Secret::new(crate::random::bytes()?)),
})
}
pub fn size(&self) -> KeySize {
match self {
AesKey::Aes128(_) => KeySize::Aes128,
AesKey::Aes192(_) => KeySize::Aes192,
AesKey::Aes256(_) => KeySize::Aes256,
}
}
pub fn expose_secret(&self) -> &[u8] {
self.key_ref().as_bytes()
}
pub fn clone_secret(&self) -> Self {
match self {
AesKey::Aes128(k) => AesKey::Aes128(k.clone_secret()),
AesKey::Aes192(k) => AesKey::Aes192(k.clone_secret()),
AesKey::Aes256(k) => AesKey::Aes256(k.clone_secret()),
}
}
fn key_ref(&self) -> KeyRef<'_> {
match self {
AesKey::Aes128(k) => KeyRef::K128(k.expose_secret()),
AesKey::Aes192(k) => KeyRef::K192(k.expose_secret()),
AesKey::Aes256(k) => KeyRef::K256(k.expose_secret()),
}
}
}
impl TryFrom<&[u8]> for AesKey {
type Error = Error;
fn try_from(key: &[u8]) -> Result<Self, Error> {
Ok(match KeyRef::from_slice(key)? {
KeyRef::K128(k) => AesKey::Aes128(Secret::new(*k)),
KeyRef::K192(k) => AesKey::Aes192(Secret::new(*k)),
KeyRef::K256(k) => AesKey::Aes256(Secret::new(*k)),
})
}
}
#[derive(Clone)]
enum Inner {
Soft(soft::KeySchedule),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Ni(ni::KeySchedule),
}
impl Inner {
fn auto(key: KeyRef<'_>) -> Self {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
if let Some(ks) = ni::KeySchedule::new(key) {
return Inner::Ni(ks);
}
Inner::Soft(soft::KeySchedule::new(key))
}
fn new(key: KeyRef<'_>, backend: Backend) -> Result<Self, Error> {
match backend {
Backend::Software => Ok(Inner::Soft(soft::KeySchedule::new(key))),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Backend::AesNi => ni::KeySchedule::new(key).map(Inner::Ni).ok_or(Error::BackendUnavailable),
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
Backend::AesNi => Err(Error::BackendUnavailable),
}
}
fn backend(&self) -> Backend {
match self {
Inner::Soft(_) => Backend::Software,
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Inner::Ni(_) => Backend::AesNi,
}
}
fn rounds(&self) -> usize {
match self {
Inner::Soft(ks) => ks.nr,
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Inner::Ni(ks) => ks.rounds(),
}
}
#[inline]
fn encrypt(&self, block: &mut Block) {
match self {
Inner::Soft(ks) => soft::encrypt(ks, block),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Inner::Ni(ks) => ks.encrypt(block),
}
}
#[inline]
fn decrypt(&self, block: &mut Block) {
match self {
Inner::Soft(ks) => soft::decrypt(ks, block),
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Inner::Ni(ks) => ks.decrypt(block),
}
}
}
pub const BLOCK_SIZE: usize = 16;
pub type Block = [u8; BLOCK_SIZE];
pub trait BlockCipher {
fn encrypt_block(&self, block: &mut Block);
fn decrypt_block(&self, block: &mut Block);
fn encrypt_blocks(&self, blocks: &mut [Block]) {
for block in blocks {
self.encrypt_block(block);
}
}
fn decrypt_blocks(&self, blocks: &mut [Block]) {
for block in blocks {
self.decrypt_block(block);
}
}
}
macro_rules! fixed_key_aes {
($name:ident, $variant:ident, $bits:expr, $len:expr) => {
#[doc = concat!("AES with a ", stringify!($bits), "-bit key.")]
#[derive(Clone)]
pub struct $name {
inner: Inner,
}
impl $name {
#[doc = concat!("The key size in octets (", stringify!($len), ").")]
pub const KEY_SIZE: usize = $len;
pub fn new(key: &[u8; $len]) -> Self {
$name { inner: Inner::auto(KeyRef::$variant(key)) }
}
#[doc = concat!(stringify!($len), " octets long.")]
pub fn from_slice(key: &[u8]) -> Result<Self, Error> {
let key: &[u8; $len] = key.try_into().map_err(|_| Error::InvalidKeyLength(key.len()))?;
Ok(Self::new(key))
}
pub fn with_backend(key: &[u8; $len], backend: Backend) -> Result<Self, Error> {
Ok($name { inner: Inner::new(KeyRef::$variant(key), backend)? })
}
pub fn backend(&self) -> Backend {
self.inner.backend()
}
}
impl BlockCipher for $name {
fn encrypt_block(&self, block: &mut Block) {
self.inner.encrypt(block);
}
fn decrypt_block(&self, block: &mut Block) {
self.inner.decrypt(block);
}
}
impl fmt::Debug for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(concat!(stringify!($name), " { .. }"))
}
}
};
}
fixed_key_aes!(Aes128, K128, 128, 16);
fixed_key_aes!(Aes192, K192, 192, 24);
fixed_key_aes!(Aes256, K256, 256, 32);
#[derive(Clone)]
pub struct Aes {
inner: Inner,
}
impl Aes {
pub fn new(key: &[u8]) -> Result<Self, Error> {
Ok(Aes { inner: Inner::auto(KeyRef::from_slice(key)?) })
}
pub fn from_key(key: &AesKey) -> Self {
Aes { inner: Inner::auto(key.key_ref()) }
}
pub fn with_backend(key: &[u8], backend: Backend) -> Result<Self, Error> {
Ok(Aes { inner: Inner::new(KeyRef::from_slice(key)?, backend)? })
}
pub fn key_size(&self) -> usize {
match self.rounds() {
10 => 16,
12 => 24,
_ => 32,
}
}
pub fn rounds(&self) -> usize {
self.inner.rounds()
}
pub fn backend(&self) -> Backend {
self.inner.backend()
}
}
impl BlockCipher for Aes {
fn encrypt_block(&self, block: &mut Block) {
self.inner.encrypt(block);
}
fn decrypt_block(&self, block: &mut Block) {
self.inner.decrypt(block);
}
}
impl fmt::Debug for Aes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Aes{} {{ .. }}", self.key_size().saturating_mul(8))
}
}
impl<T: BlockCipher + ?Sized> BlockCipher for &T {
fn encrypt_block(&self, block: &mut Block) {
(**self).encrypt_block(block)
}
fn decrypt_block(&self, block: &mut Block) {
(**self).decrypt_block(block)
}
}