capycrypt/aes/encryptable.rs
1use crate::{
2 aes::aes_functions::{apply_pcks7_padding, remove_pcks7_padding, xor_blocks, AES},
3 sha3::{aux_functions::byte_utils::get_random_bytes, shake_functions::kmac_xof},
4 Message, OperationError, SecParam,
5};
6use rayon::prelude::*;
7
8pub trait AesEncryptable {
9 fn aes_encrypt_cbc(&mut self, key: &[u8]);
10 fn aes_decrypt_cbc(&mut self, key: &[u8]) -> Result<(), OperationError>;
11 fn aes_encrypt_ctr(&mut self, key: &[u8]);
12 fn aes_decrypt_ctr(&mut self, key: &[u8]) -> Result<(), OperationError>;
13}
14
15impl AesEncryptable for Message {
16 /// # Symmetric Encryption using AES in CBC Mode
17 /// Encrypts a [`Message`] using the AES algorithm in CBC (Cipher Block Chaining) mode.
18 /// For more information refer to: NIST Special Publication 800-38A.
19 /// ## Replaces:
20 /// * `Message.data` with the result of encryption.
21 /// * `Message.digest` with the keyed hash of plaintext.
22 /// * `Message.sym_nonce` with the initialization vector (IV).
23 /// SECURITY NOTE: ciphertext length == plaintext length
24 /// ## Algorithm:
25 /// * iv ← Random(16)
26 /// * (ke || ka) ← kmac_xof(iv || key, “”, 512, “AES”)
27 /// * C1 = encrypt_block(P1 ⊕ IV)
28 /// * Cj = encrypt_block(Pj ⊕ Cj-1) for j = 2 … n
29 /// Here:
30 /// - P: Represents plaintext blocks.
31 /// - C: Represents ciphertext blocks.
32 /// ## Arguments:
33 /// * `key: &Vec<u8>`: symmetric encryption key.
34 fn aes_encrypt_cbc(&mut self, key: &[u8]) {
35 let iv = get_random_bytes(16);
36 let mut ke_ka = iv.clone();
37 ke_ka.append(&mut key.to_owned());
38 let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", SecParam::D256);
39 let ke = &ke_ka[..key.len()].to_vec(); // Encryption Key
40 let ka = &ke_ka[key.len()..].to_vec(); // Authentication Key
41
42 self.digest = kmac_xof(ka, &self.msg, 512, "AES", SecParam::D256);
43 self.sym_nonce = Some(iv.clone());
44
45 let key_schedule = AES::new(ke);
46
47 apply_pcks7_padding(&mut self.msg);
48
49 for block_index in (0..self.msg.len()).step_by(16) {
50 xor_blocks(
51 &mut self.msg[block_index..],
52 self.sym_nonce.as_mut().unwrap(),
53 );
54 AES::encrypt_block(&mut self.msg, block_index, &key_schedule.round_key);
55 *self.sym_nonce.as_mut().unwrap() = self.msg[block_index..block_index + 16].to_vec();
56 }
57
58 self.sym_nonce = Some(iv);
59 }
60
61 /// # Symmetric Decryption using AES in CBC Mode
62 /// Decrypts a [`Message`] using the AES algorithm in CBC (Cipher Block Chaining) mode.
63 /// For more information refer to: NIST Special Publication 800-38A.
64 /// ## Replaces:
65 /// * `Message.data` with the result of decryption.
66 /// * `Message.op_result` with the result of verification against the keyed hash.
67 /// * `Message.sym_nonce` is used as the initialization vector (IV).
68 /// SECURITY NOTE: ciphertext length == plaintext length
69 /// ## Algorithm:
70 /// * iv ← Symmetric nonce (IV)
71 /// * (ke || ka) ← kmac_xof(iv || key, “”, 512, “AES”)
72 /// * P1 = decrypt_block(C1) ⊕ IV
73 /// * Pj = decrypt_block(Cj) ⊕ Cj-1 for j = 2 … n
74 /// Here:
75 /// - P: Represents plaintext blocks.
76 /// - C: Represents ciphertext blocks.
77 /// ## Arguments:
78 /// * `key: &Vec<u8>`: symmetric encryption key.
79 fn aes_decrypt_cbc(&mut self, key: &[u8]) -> Result<(), OperationError> {
80 let iv = self.sym_nonce.clone().unwrap();
81 let mut ke_ka = iv.clone();
82 ke_ka.append(&mut key.to_owned());
83 let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", SecParam::D256);
84 let ke = &ke_ka[..key.len()].to_vec(); // Encryption Key
85 let ka = &ke_ka[key.len()..].to_vec(); // Authentication Key
86
87 let key_schedule = AES::new(ke);
88
89 let msg_copy = self.msg.clone();
90
91 self.msg
92 .par_chunks_mut(16)
93 .enumerate()
94 .for_each(|(i, block)| {
95 let block_index = i * 16;
96 let xor_block = if block_index >= 16 {
97 &msg_copy[block_index - 16..block_index]
98 } else {
99 &iv // Use IV for the first block
100 };
101 // Decrypt the block in-place without using the output
102 AES::decrypt_block(block, 0, &key_schedule.round_key);
103 // XOR the decrypted block with the previous ciphertext block
104 xor_blocks(block, xor_block);
105 });
106
107 remove_pcks7_padding(&mut self.msg);
108
109 kmac_xof(ka, &self.msg, 512, "AES", SecParam::D256);
110 Ok(())
111 }
112
113 /// # Symmetric Encryption using AES in CTR Mode
114 /// Encrypts a [`Message`] using the AES algorithm in CTR (Counter) mode.
115 /// For more information, refer to NIST Special Publication 800-38A.
116 /// ## Replaces:
117 /// * `Message.data` with the result of encryption.
118 /// * `Message.digest` with the keyed hash of plaintext.
119 /// * `Message.sym_nonce` with the initialization vector (IV).
120 /// SECURITY NOTE: ciphertext length == plaintext length
121 /// ## Algorithm:
122 /// * iv ← Random(12)
123 /// * CTR ← u32 counter starting at 0
124 /// * (ke || ka) ← kmac_xof(iv || key, “”, 512, “AES”)
125 /// * C1 = P1 ⊕ encrypt_block(IV || CTR1)
126 /// * Cj = Pj ⊕ encrypt_block(IV || CTRj) for j = 2 … n
127 /// Here:
128 /// - P: Represents plaintext blocks.
129 /// - C: Represents ciphertext blocks.
130 /// ## Arguments:
131 /// * `key: &[u8]`: symmetric encryption key.
132 fn aes_encrypt_ctr(&mut self, key: &[u8]) {
133 let iv = get_random_bytes(12);
134 let counter = 0u32;
135 let counter_bytes = counter.to_be_bytes();
136
137 let mut ke_ka = iv.clone();
138 ke_ka.extend_from_slice(&counter_bytes);
139 ke_ka.extend_from_slice(key);
140 let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", SecParam::D256);
141
142 let (ke, ka) = ke_ka.split_at(key.len());
143
144 self.sym_nonce = Some(iv.clone());
145 self.digest = kmac_xof(ka, &self.msg, 512, "AES", SecParam::D256);
146
147 let key_schedule = AES::new(ke);
148
149 // Parallelize encryption for each block
150 self.msg
151 .par_chunks_mut(16)
152 .enumerate()
153 .for_each(|(i, block)| {
154 let mut temp = iv.clone();
155 let counter = i as u32;
156 temp.extend_from_slice(&counter.to_be_bytes());
157
158 AES::encrypt_block(&mut temp, 0, &key_schedule.round_key);
159
160 xor_blocks(block, &temp);
161 });
162 }
163 /// # Symmetric Decryption using AES in CTR Mode
164 /// Decrypts a [`Message`] using the AES algorithm in CTR (Counter) mode.
165 /// For more information, refer to NIST Special Publication 800-38A.
166 /// ## Replaces:
167 /// * `Message.data` with the result of decryption.
168 /// * `Message.digest` with the keyed hash of plaintext.
169 /// SECURITY NOTE: ciphertext length == plaintext length
170 /// ## Algorithm:
171 /// * iv ← Message.sym_nonce
172 /// * CTR ← u32 counter starting at 0
173 /// * (ke || ka) ← kmac_xof(iv || key, “”, 512, “AES”)
174 /// * P1 = C1 ⊕ encrypt_block(IV || CTR1)
175 /// * Pj = Cj ⊕ encrypt_block(IV || CTRj) for j = 2 … n
176 /// Here:
177 /// - P: Represents plaintext blocks.
178 /// - C: Represents ciphertext blocks.
179 /// ## Arguments:
180 /// * `key: &[u8]`: symmetric encryption key.
181 fn aes_decrypt_ctr(&mut self, key: &[u8]) -> Result<(), OperationError> {
182 let iv = self
183 .sym_nonce
184 .clone()
185 .ok_or(OperationError::SymNonceNotSet)?;
186 let counter = 0u32;
187 let counter_bytes = counter.to_be_bytes();
188
189 let mut ke_ka = iv.clone();
190 ke_ka.extend_from_slice(&counter_bytes);
191 ke_ka.extend_from_slice(key);
192 let ke_ka = kmac_xof(&ke_ka, &[], 512, "AES", SecParam::D256);
193
194 let (ke, ka) = ke_ka.split_at(key.len());
195
196 let key_schedule = AES::new(ke);
197
198 // Parallelize decryption for each block
199 self.msg
200 .par_chunks_mut(16)
201 .enumerate()
202 .for_each(|(i, block)| {
203 let mut temp = iv.clone();
204 let counter = i as u32;
205 temp.extend_from_slice(&counter.to_be_bytes());
206
207 AES::encrypt_block(&mut temp, 0, &key_schedule.round_key);
208
209 xor_blocks(block, &temp);
210 });
211
212 kmac_xof(ka, &self.msg, 512, "AES", SecParam::D256);
213 Ok(())
214 }
215}