Skip to main content
This is unreleased documentation for the main (development) branch of crypto-glue.

cts/
ecb_cs3.rs

1use core::marker::PhantomData;
2
3use crate::{Decrypt, Encrypt, Error, ecb_dec, ecb_enc};
4use cipher::{
5    Block, BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt, BlockCipherEncBackend,
6    BlockCipherEncClosure, BlockCipherEncrypt, BlockSizeUser, IvSizeUser,
7    array::ArraySize,
8    common::{InnerInit, InnerUser},
9    inout::InOutBuf,
10    typenum::Unsigned,
11};
12
13/// The ECB-CS-3 ciphertext stealing mode.
14#[derive(Debug)]
15pub struct EcbCs3<C: BlockSizeUser> {
16    cipher: C,
17}
18
19impl<C: BlockSizeUser> InnerUser for EcbCs3<C> {
20    type Inner = C;
21}
22
23impl<C: BlockSizeUser> IvSizeUser for EcbCs3<C> {
24    type IvSize = C::BlockSize;
25}
26
27impl<C: BlockSizeUser> InnerInit for EcbCs3<C> {
28    fn inner_init(cipher: Self::Inner) -> Self {
29        Self { cipher }
30    }
31}
32
33impl<C: BlockCipherEncrypt> Encrypt for EcbCs3<C> {
34    fn encrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error> {
35        if buf.len() < C::BlockSize::USIZE {
36            return Err(Error);
37        }
38        self.cipher.encrypt_with_backend(Closure {
39            buf,
40            _pd: PhantomData,
41        });
42        Ok(())
43    }
44}
45
46impl<C: BlockCipherDecrypt> Decrypt for EcbCs3<C> {
47    fn decrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error> {
48        if buf.len() < C::BlockSize::USIZE {
49            return Err(Error);
50        }
51        self.cipher.decrypt_with_backend(Closure {
52            buf,
53            _pd: PhantomData,
54        });
55        Ok(())
56    }
57}
58
59struct Closure<'a, BS: ArraySize> {
60    buf: InOutBuf<'a, 'a, u8>,
61    _pd: PhantomData<BS>,
62}
63
64impl<BS: ArraySize> BlockSizeUser for Closure<'_, BS> {
65    type BlockSize = BS;
66}
67
68impl<BS: ArraySize> BlockCipherEncClosure for Closure<'_, BS> {
69    fn call<B: BlockCipherEncBackend<BlockSize = BS>>(self, cipher: &B) {
70        let mut buf = self.buf;
71        let (mut blocks, mut tail) = buf.reborrow().into_chunks();
72
73        ecb_enc(cipher, blocks.reborrow());
74
75        if tail.is_empty() && blocks.len() > 1 {
76            let blocks = blocks.get_out();
77            let (last, rest) = blocks.split_last_mut().unwrap();
78            let (penultimate, _) = rest.split_last_mut().unwrap();
79            core::mem::swap(penultimate, last);
80        } else {
81            let last_block = blocks.get_out().last_mut().unwrap();
82
83            let n = tail.len();
84
85            let mut block = Block::<B>::default();
86            block[..n].copy_from_slice(tail.get_in());
87            block[n..].copy_from_slice(&last_block[n..]);
88            cipher.encrypt_block_inplace(&mut block);
89
90            tail.get_out().copy_from_slice(&last_block[..n]);
91            *last_block = block;
92        }
93    }
94}
95
96impl<BS: ArraySize> BlockCipherDecClosure for Closure<'_, BS> {
97    fn call<B: BlockCipherDecBackend<BlockSize = BS>>(self, cipher: &B) {
98        let mut buf = self.buf;
99        let (mut blocks, mut tail) = buf.reborrow().into_chunks();
100
101        ecb_dec(cipher, blocks.reborrow());
102
103        if tail.is_empty() && blocks.len() > 1 {
104            let blocks = blocks.get_out();
105            let (last, rest) = blocks.split_last_mut().unwrap();
106            let (penultimate, _) = rest.split_last_mut().unwrap();
107            core::mem::swap(penultimate, last);
108        } else {
109            let last_block = blocks.get_out().last_mut().unwrap();
110
111            let n = tail.len();
112            let mut block = Block::<B>::default();
113            block[..n].copy_from_slice(tail.get_in());
114            block[n..].copy_from_slice(&last_block[n..]);
115            tail.get_out().copy_from_slice(&last_block[..n]);
116
117            cipher.decrypt_block_inplace(&mut block);
118            *last_block = block;
119        }
120    }
121}