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}