From 4cbc4f0a64f460135294c9bf29a49fa8f2bde857 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sun, 30 May 2021 16:39:44 -0700 Subject: [PATCH] aes: soft `hazmat` backend The `hazmat` API provides access to the raw AES cipher round, equivalent inverse cipher round, mix columns, and inverse mix column operations. This commit wires up support in the "soft" backend (or more specifically, both the 32-bit and 64-bit fixsliced backends). It would benefit from a parallel API instead of what's currently provided, however that's left for future work. --- aes/Cargo.lock | 2 +- aes/src/soft/fixslice32.rs | 77 +++++++++++++++++++++++++++++-------- aes/src/soft/fixslice64.rs | 79 ++++++++++++++++++++++++++++++-------- aes/tests/hazmat.rs | 2 +- 4 files changed, 127 insertions(+), 33 deletions(-) diff --git a/aes/Cargo.lock b/aes/Cargo.lock index 70a22b1e..dd434991 100644 --- a/aes/Cargo.lock +++ b/aes/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "aes" -version = "0.7.2" +version = "0.7.3" dependencies = [ "cfg-if", "cipher", diff --git a/aes/src/soft/fixslice32.rs b/aes/src/soft/fixslice32.rs index bbd01091..1920b3b2 100644 --- a/aes/src/soft/fixslice32.rs +++ b/aes/src/soft/fixslice32.rs @@ -295,7 +295,7 @@ pub(crate) fn aes128_decrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[..8]); - inv_bitslice(&mut state, blocks); + inv_bitslice(&state, blocks); } /// Fully-fixsliced AES-128 encryption (the ShiftRows is completely omitted). @@ -352,7 +352,7 @@ pub(crate) fn aes128_encrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { sub_bytes(&mut state); add_round_key(&mut state, &rkeys[80..]); - inv_bitslice(&mut state, blocks); + inv_bitslice(&state, blocks); } /// Fully-fixsliced AES-192 decryption (the InvShiftRows is completely omitted). @@ -403,7 +403,7 @@ pub(crate) fn aes192_decrypt(rkeys: &FixsliceKeys192, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[..8]); - inv_bitslice(&mut state, blocks); + inv_bitslice(&state, blocks); } /// Fully-fixsliced AES-192 encryption (the ShiftRows is completely omitted). @@ -454,7 +454,7 @@ pub(crate) fn aes192_encrypt(rkeys: &FixsliceKeys192, blocks: &mut [Block]) { sub_bytes(&mut state); add_round_key(&mut state, &rkeys[96..]); - inv_bitslice(&mut state, blocks); + inv_bitslice(&state, blocks); } /// Fully-fixsliced AES-256 decryption (the InvShiftRows is completely omitted). @@ -511,7 +511,7 @@ pub(crate) fn aes256_decrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[..8]); - inv_bitslice(&mut state, blocks); + inv_bitslice(&state, blocks); } /// Fully-fixsliced AES-256 encryption (the ShiftRows is completely omitted). @@ -568,7 +568,7 @@ pub(crate) fn aes256_encrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { sub_bytes(&mut state); add_round_key(&mut state, &rkeys[112..]); - inv_bitslice(&mut state, blocks); + inv_bitslice(&state, blocks); } /// Note that the 4 bitwise NOT (^= 0xffffffff) are accounted for here so that it is a true @@ -1234,7 +1234,7 @@ fn bitslice(output: &mut [u32], input0: &[u8], input1: &[u8]) { } /// Un-bitslice a 256-bit internal state into two 128-bit blocks of output. -fn inv_bitslice(input: &mut [u32], output: &mut [Block]) { +fn inv_bitslice(input: &[u32], output: &mut [Block]) { debug_assert_eq!(input.len(), 8); debug_assert_eq!(output.len(), 2); @@ -1380,29 +1380,76 @@ fn rotate_rows_and_columns_2_2(x: u32) -> u32 { /// the AES round function gated under the `hazmat` crate feature. #[cfg(feature = "hazmat")] pub(crate) mod hazmat { + use super::{ + add_round_key, bitslice, inv_bitslice, inv_mix_columns_0, inv_shift_rows_1, inv_sub_bytes, + mix_columns_0, shift_rows_1, sub_bytes, sub_bytes_nots, State, + }; use crate::Block; /// AES cipher (encrypt) round function. #[inline] - pub(crate) fn cipher_round(_block: &mut Block, _round_key: &Block) { - todo!(); + pub(crate) fn cipher_round(block: &mut Block, round_key: &Block) { + let mut rkeys = [0u32; 8]; + let mut state = State::default(); + + // TODO(tarcieri): parallel operation + bitslice(&mut rkeys, &round_key, &round_key); + bitslice(&mut state, &block, &block); + sub_bytes(&mut state); + sub_bytes_nots(&mut state); + shift_rows_1(&mut state); + mix_columns_0(&mut state); + add_round_key(&mut state, &rkeys); + + let mut out = [Block::default(); 2]; + inv_bitslice(&state, &mut out); + block.copy_from_slice(&out[0]); } /// AES cipher (encrypt) round function. #[inline] - pub(crate) fn equiv_inv_cipher_round(_block: &mut Block, _round_key: &Block) { - todo!(); + pub(crate) fn equiv_inv_cipher_round(block: &mut Block, round_key: &Block) { + let mut rkeys = [0u32; 8]; + let mut state = State::default(); + + // TODO(tarcieri): parallel operation + bitslice(&mut rkeys, &round_key, &round_key); + bitslice(&mut state, &block, &block); + + sub_bytes_nots(&mut state); + inv_sub_bytes(&mut state); + inv_shift_rows_1(&mut state); + inv_mix_columns_0(&mut state); + add_round_key(&mut state, &rkeys); + + let mut out = [Block::default(); 2]; + inv_bitslice(&state, &mut out); + block.copy_from_slice(&out[0]); } /// AES mix columns function. #[inline] - pub(crate) fn mix_columns(_block: &mut Block) { - todo!(); + pub(crate) fn mix_columns(block: &mut Block) { + let mut state = State::default(); + bitslice(&mut state, &block, &block); + + mix_columns_0(&mut state); + + let mut out = [Block::default(); 2]; + inv_bitslice(&state, &mut out); + block.copy_from_slice(&out[0]); } /// AES inverse mix columns function. #[inline] - pub(crate) fn inv_mix_columns(_block: &mut Block) { - todo!(); + pub(crate) fn inv_mix_columns(block: &mut Block) { + let mut state = State::default(); + bitslice(&mut state, &block, &block); + + inv_mix_columns_0(&mut state); + + let mut out = [Block::default(); 2]; + inv_bitslice(&state, &mut out); + block.copy_from_slice(&out[0]); } } diff --git a/aes/src/soft/fixslice64.rs b/aes/src/soft/fixslice64.rs index 993c5529..c810e134 100644 --- a/aes/src/soft/fixslice64.rs +++ b/aes/src/soft/fixslice64.rs @@ -317,7 +317,7 @@ pub(crate) fn aes128_decrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[..8]); - inv_bitslice(&mut state, blocks); + inv_bitslice(&state, blocks); } /// Fully-fixsliced AES-128 encryption (the ShiftRows is completely omitted). @@ -374,7 +374,7 @@ pub(crate) fn aes128_encrypt(rkeys: &FixsliceKeys128, blocks: &mut [Block]) { sub_bytes(&mut state); add_round_key(&mut state, &rkeys[80..]); - inv_bitslice(&mut state, blocks); + inv_bitslice(&state, blocks); } /// Fully-fixsliced AES-192 decryption (the InvShiftRows is completely omitted). @@ -425,7 +425,7 @@ pub(crate) fn aes192_decrypt(rkeys: &FixsliceKeys192, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[..8]); - inv_bitslice(&mut state, blocks); + inv_bitslice(&state, blocks); } /// Fully-fixsliced AES-192 encryption (the ShiftRows is completely omitted). @@ -476,7 +476,7 @@ pub(crate) fn aes192_encrypt(rkeys: &FixsliceKeys192, blocks: &mut [Block]) { sub_bytes(&mut state); add_round_key(&mut state, &rkeys[96..]); - inv_bitslice(&mut state, blocks); + inv_bitslice(&state, blocks); } /// Fully-fixsliced AES-256 decryption (the InvShiftRows is completely omitted). @@ -533,7 +533,7 @@ pub(crate) fn aes256_decrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { add_round_key(&mut state, &rkeys[..8]); - inv_bitslice(&mut state, blocks); + inv_bitslice(&state, blocks); } /// Fully-fixsliced AES-256 encryption (the ShiftRows is completely omitted). @@ -590,7 +590,7 @@ pub(crate) fn aes256_encrypt(rkeys: &FixsliceKeys256, blocks: &mut [Block]) { sub_bytes(&mut state); add_round_key(&mut state, &rkeys[112..]); - inv_bitslice(&mut state, blocks); + inv_bitslice(&state, blocks); } /// Note that the 4 bitwise NOT (^= 0xffffffffffffffff) are accounted for here so that it is a true @@ -1132,7 +1132,7 @@ fn delta_swap_2(a: &mut u64, b: &mut u64, shift: u32, mask: u64) { } /// Applies ShiftRows once on an AES state (or key). -#[cfg(not(feature = "compact"))] +#[cfg(any(not(feature = "compact"), feature = "hazmat"))] #[inline] fn shift_rows_1(state: &mut [u64]) { debug_assert_eq!(state.len(), 8); @@ -1274,7 +1274,7 @@ fn bitslice(output: &mut [u64], input0: &[u8], input1: &[u8], input2: &[u8], inp } /// Un-bitslice a 512-bit internal state into four 128-bit blocks of output. -fn inv_bitslice(input: &mut [u64], output: &mut [Block]) { +fn inv_bitslice(input: &[u64], output: &mut [Block]) { debug_assert_eq!(input.len(), 8); debug_assert_eq!(output.len(), 4); @@ -1434,29 +1434,76 @@ fn rotate_rows_and_columns_2_2(x: u64) -> u64 { /// the AES round function gated under the `hazmat` crate feature. #[cfg(feature = "hazmat")] pub(crate) mod hazmat { + use super::{ + add_round_key, bitslice, inv_bitslice, inv_mix_columns_0, inv_shift_rows_1, inv_sub_bytes, + mix_columns_0, shift_rows_1, sub_bytes, sub_bytes_nots, State, + }; use crate::Block; /// AES cipher (encrypt) round function. #[inline] - pub(crate) fn cipher_round(_block: &mut Block, _round_key: &Block) { - todo!(); + pub(crate) fn cipher_round(block: &mut Block, round_key: &Block) { + let mut rkeys = [0u64; 8]; + let mut state = State::default(); + + // TODO(tarcieri): parallel operation + bitslice(&mut rkeys, &round_key, &round_key, &round_key, &round_key); + bitslice(&mut state, &block, &block, &block, &block); + sub_bytes(&mut state); + sub_bytes_nots(&mut state); + shift_rows_1(&mut state); + mix_columns_0(&mut state); + add_round_key(&mut state, &rkeys); + + let mut out = [Block::default(); 4]; + inv_bitslice(&state, &mut out); + block.copy_from_slice(&out[0]); } /// AES cipher (encrypt) round function. #[inline] - pub(crate) fn equiv_inv_cipher_round(_block: &mut Block, _round_key: &Block) { - todo!(); + pub(crate) fn equiv_inv_cipher_round(block: &mut Block, round_key: &Block) { + let mut rkeys = [0u64; 8]; + let mut state = State::default(); + + // TODO(tarcieri): parallel operation + bitslice(&mut rkeys, &round_key, &round_key, &round_key, &round_key); + bitslice(&mut state, &block, &block, &block, &block); + + sub_bytes_nots(&mut state); + inv_sub_bytes(&mut state); + inv_shift_rows_1(&mut state); + inv_mix_columns_0(&mut state); + add_round_key(&mut state, &rkeys); + + let mut out = [Block::default(); 4]; + inv_bitslice(&state, &mut out); + block.copy_from_slice(&out[0]); } /// AES mix columns function. #[inline] - pub(crate) fn mix_columns(_block: &mut Block) { - todo!(); + pub(crate) fn mix_columns(block: &mut Block) { + let mut state = State::default(); + bitslice(&mut state, &block, &block, &block, &block); + + mix_columns_0(&mut state); + + let mut out = [Block::default(); 4]; + inv_bitslice(&state, &mut out); + block.copy_from_slice(&out[0]); } /// AES inverse mix columns function. #[inline] - pub(crate) fn inv_mix_columns(_block: &mut Block) { - todo!(); + pub(crate) fn inv_mix_columns(block: &mut Block) { + let mut state = State::default(); + bitslice(&mut state, &block, &block, &block, &block); + + inv_mix_columns_0(&mut state); + + let mut out = [Block::default(); 4]; + inv_bitslice(&state, &mut out); + block.copy_from_slice(&out[0]); } } diff --git a/aes/tests/hazmat.rs b/aes/tests/hazmat.rs index e39ec089..75b93a06 100644 --- a/aes/tests/hazmat.rs +++ b/aes/tests/hazmat.rs @@ -1,7 +1,7 @@ //! Tests for low-level "hazmat" AES functions. // TODO(tarcieri): support for using the hazmat functions with the `soft` backend -#![cfg(all(feature = "hazmat", not(feature = "force-soft")))] +#![cfg(feature = "hazmat")] use aes::Block; use hex_literal::hex;