Skip to content

Commit

Permalink
[XTS] Integrate ciphertext stealing
Browse files Browse the repository at this point in the history
  • Loading branch information
zer0x64 committed Nov 24, 2024
1 parent b7126d9 commit aac14b2
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 70 deletions.
2 changes: 1 addition & 1 deletion xts/benches/aes.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![feature(test)]
extern crate test;

use aes::{ Aes128, Aes256 };
use aes::{Aes128, Aes256};

cipher::block_encryptor_bench!(
KeyIv: xts::Encryptor<Aes128>,
Expand Down
62 changes: 53 additions & 9 deletions xts/src/decrypt.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use core::{fmt, ops::Add};

use crate::xts_core::{precompute_iv, Xts};
use crate::xts_core::{precompute_iv, Stealer, Xts};
use crate::{Error, Result};
use cipher::{
array::ArraySize,
crypto_common::{BlockSizes, IvSizeUser},
inout::InOut,
typenum::Sum,
AlgorithmName, Block, BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt,
BlockCipherEncrypt, BlockModeDecBackend, BlockModeDecClosure, BlockModeDecrypt, BlockSizeUser,
Iv, IvState, Key, KeyInit, KeyIvInit, KeySizeUser, ParBlocks, ParBlocksSizeUser,
InOutBuf, Iv, IvState, Key, KeyInit, KeyIvInit, KeySizeUser, ParBlocks, ParBlocksSizeUser,
};

#[cfg(feature = "zeroize")]
Expand Down Expand Up @@ -87,6 +88,34 @@ where
pub fn reset_iv(&mut self, iv: &Block<Self>) {
self.iv = precompute_iv(&self.tweaker, iv)
}

/// Decrypt `inout` buffer.
pub fn decrypt_inout(&mut self, mut buf: InOutBuf<'_, '_, u8>) -> Result<()> {
if buf.len() < C::BlockSize::USIZE {
return Err(Error);
};

{
let (blocks, _) = buf.reborrow().into_chunks();
self.decrypt_blocks_inout(blocks);
}

self.ciphertext_stealing(buf.get_out());

Ok(())
}

/// Decrypt data in-place.
fn decrypt(&mut self, buf: &mut [u8]) -> Result<()> {
self.decrypt_inout(buf.into())
}

/// Decrypt data buffer-to-buffer.
fn decrypt_b2b(&mut self, in_buf: &[u8], out_buf: &mut [u8]) -> Result<()> {
InOutBuf::new(in_buf, out_buf)
.map_err(|_| Error)
.and_then(|buf| self.decrypt_inout(buf))
}
}

impl<BS, C, T> BlockSizeUser for SplitDecryptor<C, T>
Expand All @@ -95,7 +124,7 @@ where
C: BlockCipherDecrypt<BlockSize = BS>,
T: BlockCipherEncrypt<BlockSize = BS>,
{
type BlockSize = C::BlockSize;
type BlockSize = BS;
}

impl<BS, C, T> BlockModeDecrypt for SplitDecryptor<C, T>
Expand Down Expand Up @@ -147,13 +176,33 @@ where
}
}

impl<BS, C, T> Stealer for SplitDecryptor<C, T>
where
BS: BlockSizes,
C: BlockCipherDecrypt<BlockSize = BS>,
T: BlockCipherEncrypt<BlockSize = BS>,
{
fn process_block(&self, block: &mut Block<Self>) {
self.cipher.decrypt_block(block);
}

fn get_iv_mut(&mut self) -> &mut Block<Self> {
&mut self.iv
}

#[inline(always)]
fn is_decrypt() -> bool {
false
}
}

impl<BS, C, T> IvSizeUser for SplitDecryptor<C, T>
where
BS: BlockSizes,
C: BlockCipherDecrypt<BlockSize = BS>,
T: BlockCipherEncrypt<BlockSize = BS>,
{
type IvSize = C::BlockSize;
type IvSize = BS;
}

impl<BS, C, T> IvState for SplitDecryptor<C, T>
Expand Down Expand Up @@ -290,9 +339,4 @@ where
fn get_iv_mut(&mut self) -> &mut Block<Self> {
self.iv
}

#[inline(always)]
fn is_decrypt() -> bool {
true
}
}
67 changes: 56 additions & 11 deletions xts/src/encrypt.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::xts_core::{precompute_iv, Xts};
use crate::xts_core::{precompute_iv, Stealer, Xts};
use crate::{Error, Result};

use cipher::InOutBuf;
use cipher::{
array::ArraySize, crypto_common::BlockSizes, typenum::Sum, AlgorithmName,
Block, BlockCipherEncBackend, BlockCipherEncClosure, BlockCipherEncrypt, BlockModeEncBackend,
array::ArraySize, crypto_common::BlockSizes, typenum::Sum, AlgorithmName, Block,
BlockCipherEncBackend, BlockCipherEncClosure, BlockCipherEncrypt, BlockModeEncBackend,
BlockModeEncClosure, BlockModeEncrypt, BlockSizeUser, InOut, Iv, IvSizeUser, IvState, Key,
KeyInit, KeyIvInit, KeySizeUser, ParBlocks, ParBlocksSizeUser,
};
Expand Down Expand Up @@ -85,6 +87,34 @@ where
pub fn reset_iv(&mut self, iv: &Block<Self>) {
self.iv = precompute_iv(&self.tweaker, iv)
}

/// Encrypt `inout` buffer.
pub fn encrypt_inout(&mut self, mut buf: InOutBuf<'_, '_, u8>) -> Result<()> {
if buf.len() < C::BlockSize::USIZE {
return Err(Error);
};

{
let (blocks, _) = buf.reborrow().into_chunks();
self.encrypt_blocks_inout(blocks);
}

self.ciphertext_stealing(buf.get_out());

Ok(())
}

/// Encrypt data in-place.
fn encrypt(&mut self, buf: &mut [u8]) -> Result<()> {
self.encrypt_inout(buf.into())
}

/// Encrypt data buffer-to-buffer.
fn encrypt_b2b(&mut self, in_buf: &[u8], out_buf: &mut [u8]) -> Result<()> {
InOutBuf::new(in_buf, out_buf)
.map_err(|_| Error)
.and_then(|buf| self.encrypt_inout(buf))
}
}

impl<BS, C, T> BlockSizeUser for SplitEncryptor<C, T>
Expand All @@ -93,7 +123,7 @@ where
C: BlockCipherEncrypt<BlockSize = BS>,
T: BlockCipherEncrypt<BlockSize = BS>,
{
type BlockSize = C::BlockSize;
type BlockSize = BS;
}

impl<BS, C, T> IvSizeUser for SplitEncryptor<C, T>
Expand Down Expand Up @@ -165,6 +195,26 @@ where
}
}

impl<BS, C, T> Stealer for SplitEncryptor<C, T>
where
BS: BlockSizes,
C: BlockCipherEncrypt<BlockSize = BS>,
T: BlockCipherEncrypt<BlockSize = BS>,
{
fn process_block(&self, block: &mut Block<Self>) {
self.cipher.encrypt_block(block);
}

fn get_iv_mut(&mut self) -> &mut Block<Self> {
&mut self.iv
}

#[inline(always)]
fn is_decrypt() -> bool {
false
}
}

impl<BS, C, T> AlgorithmName for SplitEncryptor<C, T>
where
BS: BlockSizes,
Expand Down Expand Up @@ -192,7 +242,7 @@ where
}

impl<C, T> Drop for SplitEncryptor<C, T>
where
where
C: BlockCipherEncrypt,
T: BlockCipherEncrypt,
{
Expand Down Expand Up @@ -280,11 +330,6 @@ where
}

fn get_iv_mut(&mut self) -> &mut Block<Self> {
self.iv
}

#[inline(always)]
fn is_decrypt() -> bool {
false
&mut self.iv
}
}
60 changes: 12 additions & 48 deletions xts/src/xts_core.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use cipher::typenum::Unsigned;
use cipher::BlockCipherDecrypt;
use cipher::{
crypto_common::BlockSizes, Array, Block, BlockCipherEncrypt, BlockSizeUser, InOut, InOutBuf,
ParBlocks, ParBlocksSizeUser,
Expand Down Expand Up @@ -31,9 +32,6 @@ pub trait Xts: ParBlocksSizeUser + BlockSizeUser {
/// Gets the IV reference.
fn get_iv_mut(&mut self) -> &mut Array<u8, Self::BlockSize>;

/// There is a slight difference regarding the tweak during decryption
fn is_decrypt() -> bool;

//Unused but keeping for now just in case
fn _process(&self, mut block: InOut<'_, '_, Block<Self>>) {
let mut b = block.clone_in();
Expand Down Expand Up @@ -122,51 +120,17 @@ pub trait Xts: ParBlocksSizeUser + BlockSizeUser {
}
}

pub trait XtsMode: Xts {
fn process_all_in_place(&mut self, buffer: &mut [u8]) -> Result<()> {
let block_size = Self::block_size();
let par_blocks_size = Self::ParBlocksSize::USIZE;

if buffer.len() < block_size {
return Err(Error);
}

let need_stealing = buffer.len() % Self::block_size() == 0;

let (buffer, remaining_buffer) = if need_stealing {
buffer.split_at_mut((buffer.len() / block_size - 1) * block_size)
} else {
(buffer, [0u8; 0].as_mut_slice())
};

// Split buffer into blocks
let mut blocks = buffer
.chunks_exact_mut(block_size)
.map(|b| <&mut Block<Self>>::try_from(b).unwrap());

// Can't figure out how to get parblocks in place here, commenting for now
// if par_blocks_size > 1 {
// let mut blocks: alloc::vec::Vec<&mut Block<Self>> = blocks.collect();
pub(crate) trait Stealer: BlockSizeUser {
/// Encrypt/Decrypt the block
fn process_block(&self, block: &mut Block<Self>);

// let mut par_blocks = blocks.chunks_exact_mut(par_blocks_size);
// for b in par_blocks {
// let mut b = <&mut ParBlocks<Self>>::try_from(*b).unwrap();
// }

// self.process_tail_blocks_inplace(tail);
// } else {
for b in blocks {
self.process_block_inplace(b);
}
//}

if need_stealing {
self.ciphertext_stealing(remaining_buffer);
};
/// Gets the IV reference.
fn get_iv_mut(&mut self) -> &mut Array<u8, Self::BlockSize>;

Ok(())
}
/// There is a slight difference regarding the tweak during decryption
fn is_decrypt() -> bool;

/// Perform the ciphertext stealing phase
fn ciphertext_stealing(&mut self, buffer: &mut [u8]) {
let remaining_bytes = buffer.len() - Self::block_size();

Expand All @@ -185,7 +149,7 @@ pub trait XtsMode: Xts {
carry
};

self.process_inplace(second_to_last_block);
self.process_block(second_to_last_block);

{
let iv = self.get_iv_mut();
Expand All @@ -195,7 +159,7 @@ pub trait XtsMode: Xts {
}
} else {
// Process normally
self.process_block_inplace(second_to_last_block);
self.process_block(second_to_last_block);
}

// We first swap the remaining bytes with the previous block's
Expand All @@ -209,6 +173,6 @@ pub trait XtsMode: Xts {
let second_to_last_block: &mut Block<Self> = (&mut buffer[0..Self::block_size()])
.try_into()
.expect("Not a full block on second to last block!");
self.process_block_inplace(second_to_last_block);
self.process_block(second_to_last_block);
}
}
2 changes: 1 addition & 1 deletion xts/tests/aes.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use aes::*;
use xts::{Decryptor, Encryptor};
use cipher::{block_mode_dec_test, block_mode_enc_test};
use xts::{Decryptor, Encryptor};

#[test]
fn manual_test() {
Expand Down

0 comments on commit aac14b2

Please sign in to comment.