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}