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

cts/
lib.rs

1#![no_std]
2#![doc = include_str!("../README.md")]
3#![doc(
4    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
5    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
6)]
7#![cfg_attr(docsrs, feature(doc_cfg))]
8#![allow(clippy::unwrap_used, reason = "todo: convert to expect")]
9
10pub use cipher;
11
12pub use cipher::{KeyInit, KeyIvInit};
13
14mod cbc_cs1;
15mod cbc_cs2;
16mod cbc_cs3;
17mod ecb_cs1;
18mod ecb_cs2;
19mod ecb_cs3;
20
21pub use cbc_cs1::CbcCs1;
22pub use cbc_cs2::CbcCs2;
23pub use cbc_cs3::CbcCs3;
24pub use ecb_cs1::EcbCs1;
25pub use ecb_cs2::EcbCs2;
26pub use ecb_cs3::EcbCs3;
27
28use cipher::{
29    Block, BlockCipherDecBackend, BlockCipherEncBackend,
30    array::{Array, ArraySize},
31    inout::InOutBuf,
32    typenum::Unsigned,
33};
34
35/// Error which indicates that message is smaller than cipher's block size.
36#[derive(Copy, Clone, Debug)]
37pub struct Error;
38
39/// Encryption functionality of CTS modes.
40pub trait Encrypt: Sized {
41    /// Encrypt `inout` buffer.
42    ///
43    /// # Errors
44    /// If encryption failed.
45    fn encrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error>;
46
47    /// Encrypt data in-place.
48    ///
49    /// # Errors
50    /// If encryption failed.
51    fn encrypt(self, buf: &mut [u8]) -> Result<(), Error> {
52        self.encrypt_inout(buf.into())
53    }
54
55    /// Encrypt data buffer-to-buffer.
56    ///
57    /// # Errors
58    /// If encryption failed.
59    fn encrypt_b2b(self, in_buf: &[u8], out_buf: &mut [u8]) -> Result<(), Error> {
60        InOutBuf::new(in_buf, out_buf)
61            .map_err(|_| Error)
62            .and_then(|buf| self.encrypt_inout(buf))
63    }
64}
65
66/// Decryption functionality of CTS modes.
67pub trait Decrypt: Sized {
68    /// Decrypt `inout` buffer.
69    ///
70    /// # Errors
71    /// If decryption failed.
72    fn decrypt_inout(self, buf: InOutBuf<'_, '_, u8>) -> Result<(), Error>;
73
74    /// Decrypt data in-place.
75    ///
76    /// # Errors
77    /// If decryption failed.
78    fn decrypt(self, buf: &mut [u8]) -> Result<(), Error> {
79        self.decrypt_inout(buf.into())
80    }
81
82    /// Decrypt data buffer-to-buffer.
83    ///
84    /// # Errors
85    /// If decryption failed.
86    fn decrypt_b2b(self, in_buf: &[u8], out_buf: &mut [u8]) -> Result<(), Error> {
87        InOutBuf::new(in_buf, out_buf)
88            .map_err(|_| Error)
89            .and_then(|buf| self.decrypt_inout(buf))
90    }
91}
92
93fn ecb_enc<B: BlockCipherEncBackend>(cipher: &B, mut blocks: InOutBuf<'_, '_, Block<B>>) {
94    if B::ParBlocksSize::USIZE > 1 {
95        let (par_blocks, rem_blocks) = blocks.into_chunks();
96        blocks = rem_blocks;
97        for blocks in par_blocks {
98            cipher.encrypt_par_blocks(blocks);
99        }
100    }
101    for block in blocks {
102        cipher.encrypt_block(block);
103    }
104}
105
106fn ecb_dec<B: BlockCipherDecBackend>(cipher: &B, mut blocks: InOutBuf<'_, '_, Block<B>>) {
107    if B::ParBlocksSize::USIZE > 1 {
108        let (par_blocks, rem_blocks) = blocks.into_chunks();
109        blocks = rem_blocks;
110        for blocks in par_blocks {
111            cipher.decrypt_par_blocks(blocks);
112        }
113    }
114    for block in blocks {
115        cipher.decrypt_block(block);
116    }
117}
118
119fn cbc_enc<B: BlockCipherEncBackend>(
120    cipher: &B,
121    iv: &mut Block<B>,
122    mut blocks: InOutBuf<'_, '_, Block<B>>,
123) {
124    for mut block in blocks.reborrow() {
125        let mut t = block.clone_in();
126        xor(&mut t, iv);
127        cipher.encrypt_block_inplace(&mut t);
128        *iv = t.clone();
129        *block.get_out() = t;
130    }
131}
132
133fn cbc_dec<B: BlockCipherDecBackend>(
134    cipher: &B,
135    iv: &mut Block<B>,
136    mut blocks: InOutBuf<'_, '_, Block<B>>,
137) {
138    if B::ParBlocksSize::USIZE > 1 {
139        let (par_blocks, rem_blocks) = blocks.into_chunks();
140        blocks = rem_blocks;
141
142        for mut blocks in par_blocks {
143            let in_blocks = blocks.clone_in();
144            let mut t = blocks.clone_in();
145
146            cipher.decrypt_par_blocks_inplace(&mut t);
147            let n = t.len();
148            xor(&mut t[0], iv);
149            for i in 1..n {
150                xor(&mut t[i], &in_blocks[i - 1]);
151            }
152            *blocks.get_out() = t;
153            *iv = in_blocks[n - 1].clone();
154        }
155    }
156
157    for mut block in blocks {
158        let in_block = block.clone_in();
159        let mut t = block.clone_in();
160        cipher.decrypt_block_inplace(&mut t);
161        xor(&mut t, iv);
162        *block.get_out() = t;
163        *iv = in_block;
164    }
165}
166
167#[inline(always)]
168fn xor<N: ArraySize>(out: &mut Array<u8, N>, buf: &Array<u8, N>) {
169    for (a, b) in out.iter_mut().zip(buf) {
170        *a ^= *b;
171    }
172}