Skip to main content

rc5_block/
modes.rs

1use crate::{BlockCipher, Word};
2
3/// Modes of operation for a block cipher.
4///
5/// - **ECB**: Electronic Codebook mode.  
6/// - **CBC**: Cipher Block Chaining mode.  
7/// - **CTR**: Counter mode.
8///
9/// ECB mode of operation is less secure and is not recommended
10/// to use in production applications since it can be broken
11/// muc easily, special care should be kept while using this
12/// mode.
13pub enum OperationMode<W: Word, const N: usize> {
14    /// Electronic Codebook
15    ///
16    /// Encrypt/Decrypt each block independently Without any
17    /// additional security.
18    ECB,
19
20    /// Cipher Block Chaining
21    ///
22    /// Requires an initialization vector to add one stage
23    /// enhanced security.
24    CBC { iv: [W; N] },
25
26    /// Counter
27    ///
28    /// Requires a starting nonce + counter block, this way
29    /// it adds two stage complexity over encryption/decryption.
30    CTR { nonce_and_counter: [W; N] },
31}
32
33/// Encrypt a sequence of blocks in ECB mode.
34///
35/// # Parameters
36/// - `control_block`: the underlying block cipher instance.  
37/// - `input_blocks`: vector of full `[W; N]` plaintext blocks.
38///
39/// # Returns
40/// A vector of `[W; N]` ciphertext blocks.
41pub fn ecb_encrypt<C, W, const N: usize>(
42    control_block: &C,
43    input_blocks: Vec<[W; N]>,
44) -> Vec<[W; N]>
45where
46    C: BlockCipher<W, N>,
47    W: Word,
48{
49    input_blocks
50        .iter()
51        .map(|block| control_block.encrypt(*block))
52        .collect()
53}
54
55/// Decrypt a sequence of blocks in ECB mode.
56///
57/// # Parameters
58/// - `control_block`: the underlying block cipher instance.  
59/// - `input_blocks`: vector of full `[W; N]` ciphertext blocks.
60///
61/// # Returns
62/// A vector of `[W; N]` plaintext blocks.
63pub fn ecb_decrypt<C, W, const N: usize>(
64    control_block: &C,
65    input_blocks: Vec<[W; N]>,
66) -> Vec<[W; N]>
67where
68    C: BlockCipher<W, N>,
69    W: Word,
70{
71    input_blocks
72        .iter()
73        .map(|block| control_block.decrypt(*block))
74        .collect()
75}
76
77/// Encrypt in CBC mode.
78///
79/// # Parameters
80/// - `control_block`: the underlying block cipher instance.  
81/// - `iv`: Initialization Vector (`[W; N]`).  
82/// - `input_blocks`: vector of full `[W; N]` plaintext blocks.
83///
84/// # Returns
85/// A vector of `[W; N]` ciphertext blocks.
86pub fn cbc_encrypt<C, W, const N: usize>(
87    control_block: &C,
88    iv: [W; N],
89    input_blocks: Vec<[W; N]>,
90) -> Vec<[W; N]>
91where
92    C: BlockCipher<W, N>,
93    W: Word,
94{
95    let mut prev = iv;
96
97    input_blocks
98        .iter()
99        .map(|block| {
100            prev.iter_mut()
101                .enumerate()
102                .for_each(|(ix, word)| *word = *word ^ block[ix]);
103            let ct = control_block.encrypt(prev);
104            prev = ct;
105
106            ct
107        })
108        .collect()
109}
110
111/// Decrypt in CBC mode.
112///
113/// # Parameters
114/// - `control_block`: the underlying block cipher instance.  
115/// - `iv`: Initialization Vector (`[W; N]`).  
116/// - `input_blocks`: vector of full `[W; N]` ciphertext blocks.
117///
118/// # Returns
119/// A vector of `[W; N]` plaintext blocks.
120pub fn cbc_decrypt<C, W, const N: usize>(
121    control_block: &C,
122    iv: [W; N],
123    input_blocks: Vec<[W; N]>,
124) -> Vec<[W; N]>
125where
126    C: BlockCipher<W, N>,
127    W: Word,
128{
129    let mut prev = iv;
130
131    input_blocks
132        .iter()
133        .map(|block| {
134            let mut decrypted = control_block.decrypt(*block);
135            prev.iter_mut()
136                .enumerate()
137                .for_each(|(ix, word)| decrypted[ix] = decrypted[ix] ^ *word);
138
139            prev = *block;
140            decrypted
141        })
142        .collect()
143}
144
145/// Encrypt a byte stream in CTR mode (stream cipher).
146///
147/// # Parameters
148/// - `control_block`: the underlying block cipher instance.  
149/// - `nonce_and_counter`: initial counter block (`[W; N]`).  
150/// - `input_stream`: plaintext bytes to encrypt (any length).
151///
152/// # Returns
153/// A `Vec<u8>` ciphertext stream, same length as input.
154pub fn ctr_encrypt<C, W, const N: usize>(
155    control_block: &C,
156    mut nonce_and_counter: [W; N],
157    input_stream: &[u8],
158) -> Vec<u8>
159where
160    C: BlockCipher<W, N>,
161    W: Word,
162{
163    let mut ciphered_stream = vec![];
164
165    for input_chunk in input_stream.chunks(control_block.block_size()) {
166        let encrypted = control_block.encrypt(nonce_and_counter);
167        let key_stream = encrypted
168            .iter()
169            .flat_map(|word| word.to_bytes_slice())
170            .collect::<Vec<_>>();
171
172        for (ix, input) in input_chunk.iter().enumerate() {
173            ciphered_stream.push(*input ^ key_stream[ix]);
174        }
175        nonce_and_counter[N - 1] = nonce_and_counter[N - 1].wrapping_add(W::from_u8(1));
176    }
177    ciphered_stream
178}
179
180/// Decrypt a byte stream in CTR mode (identical to encryption).
181///
182/// # Parameters
183/// - `control_block`: the underlying block cipher instance.  
184/// - `nonce_and_counter`: same initial counter block used in encryption.  
185/// - `input_stream`: ciphertext bytes to decrypt (any length).
186///
187/// # Returns
188/// A `Vec<u8>` plaintext stream.
189pub fn ctr_decrypt<C, W, const N: usize>(
190    control_block: &C,
191    nonce_and_counter: [W; N],
192    input_blocks: &[u8],
193) -> Vec<u8>
194where
195    C: BlockCipher<W, N>,
196    W: Word,
197{
198    // Counter mode decryption is vice versa of counter mode encryption.
199    // A cipher text can be decrypted by reeating the encryption with same
200    // parameter configs.
201    ctr_encrypt(control_block, nonce_and_counter, input_blocks)
202}