plain_aes/
lib.rs

1//! # plain-aes
2//!
3//! This crate implements Rijndael's cipher, in 128 bits and 192 bits modes respectively.
4//!
5//! ## Considerations
6//! * Within this crate, "block" or "block of data" refers specifically to a 16-byte sequence, as defined in the [FIPS 197 specification](https://csrc.nist.gov/pubs/fips/197/final).
7//! * For efficiency, most affine transformations and operations within GF(2^8) (e.g., polynomial multiplication) are implemented using pre-computed lookup tables.
8//! * While this crate is comprehensively tested, it should not be used in security-critical applications due to potential vulnerabilities. Modern CPUs offer hardware-accelerated AES, and some even have dedicated cryptographic coprocessors. These hardware features provide a more secure and performant solution for critical applications.
9//! ## Getting started
10//! 1. Run `cargo add plain-aes` or add `plain-aes` to your `Cargo.toml`.
11//! 2. Copy one of the examples included in [encrypt]/[decrypt], or refer to the tests folder in the Github repo to get started.
12pub use internal::KeyExpansionError;
13use internal::{decrypt_block, encrypt_block, ExpandedKey};
14/// This module encapsulates all internal operations for this crate.
15pub mod internal;
16/// A trait implemented by types that can be used as input for encryption or decryption operations.
17///
18/// This trait provides a unified interface for different data types, allowing you to pass them directly to the encryption/decryption algorithm without requiring additional logic.
19///
20/// For example, you could implement this trait on a file handle to encrypt or decrypt the contents of a file directly.
21///
22/// # Examples
23///
24/// ```
25/// use plain_aes::{encrypt, Encryptable, CipherVersion, ModeOfOperation};
26/// struct MyData {
27///     content: String,
28/// }
29///
30/// impl Encryptable for MyData {
31///     fn data(&self) -> Option<&[u8]> {
32///         Some(self.content.as_bytes())
33///     }
34/// }
35///
36/// let data = MyData { content: "example usage of Encryptable".to_string() };
37/// let encrypted_data = encrypt(data, CipherVersion::Aes128("This lib is cool".as_bytes(), ModeOfOperation::ECB));
38/// ```
39pub trait Encryptable {
40    /// Returns a dynamic slice containing the byte sequence of the content to be encrypted.
41    fn data(&self) -> Option<&[u8]>;
42}
43/// Mode of operation for AES.
44pub enum ModeOfOperation<'a> {
45    CBC(&'a [u8]),
46    ECB,
47}
48/// The cipher version to use, each cipher version encapsulates a key and [ModeOfOperation].
49pub enum CipherVersion<'a> {
50    Aes128(&'a [u8], ModeOfOperation<'a>),
51    Aes192(&'a [u8], ModeOfOperation<'a>),
52}
53/// An error produced during an encryption/decryption.
54#[derive(Debug, PartialEq)]
55pub enum OperationError {
56    /// The key expansion failed.
57    KeyExpansionFailed(KeyExpansionError),
58    /// The provided target had no data.
59    EmptyTarget,
60    /// The given target's data is less than the block size for AES, and thus cannot be fed to the encryption/decryption algorithm.
61    ///
62    /// For decryption, the target's data is most likely not a result of an AES encryption.
63    ///
64    /// For encryption, consider applying [pkcs5_padding] to the target's data before using [encrypt].
65    InvalidTargetSize,
66}
67impl<'a> CipherVersion<'a> {
68    /// Returns the expanded key size of each cipher version.
69    fn expanded_key_size(&self) -> usize {
70        match self {
71            CipherVersion::Aes128(_, _) => 176,
72            CipherVersion::Aes192(_, _) => 208,
73        }
74    }
75    /// Returns the given key, as a vector.
76    fn key(&self) -> Vec<u8> {
77        match self {
78            CipherVersion::Aes128(key, _) | CipherVersion::Aes192(key, _) => key.to_vec(),
79        }
80    }
81    /// Returns the mode of operation used.
82    fn mode_of_operation(&self) -> &ModeOfOperation {
83        match self {
84            CipherVersion::Aes128(_, mode) | CipherVersion::Aes192(_, mode) => mode,
85        }
86    }
87}
88impl Encryptable for &str {
89    fn data(&self) -> Option<&[u8]> {
90        if self.is_empty() {
91            return None;
92        };
93        Some(self.as_bytes())
94    }
95}
96
97impl Encryptable for &[u8] {
98    fn data(&self) -> Option<&[u8]> {
99        if self.len() < 1 {
100            return None;
101        }
102        Some(*self)
103    }
104}
105
106/// Additions the state and the round key as Galois fields GF(2^8) (XOR).
107fn add_round_key(state: &mut [u8], round_key: &[u8]) {
108    for i in 0..16 {
109        state[i] = state[i] ^ round_key[i]; // Addition in Galois fields is defined as the addition MOD 2 which is XOR
110    }
111}
112/// Applies PKCS#5 padding to blocks less than 16 bytes in length.
113pub fn pkcs5_padding(block: &[u8]) -> Vec<u8> {
114    let mut padded_block: Vec<u8> = Vec::new();
115    padded_block.extend(block);
116    for _ in 0..(16 - block.len()) {
117        padded_block.push((16 - block.len()) as u8);
118    }
119    padded_block
120}
121/// Removes PKCS#5 padding from a decrypted sequence.
122fn remove_pkcs5_padding(data: &mut Vec<u8>) {
123    let padding_byte = data[data.len() - 1];
124    if padding_byte >= 16 {
125        // We can only pad up to 15 bytes, since we're dealing with words.
126        return;
127    }
128    // Check if the padding is consistent.
129    for i in data.len() - (padding_byte as usize)..data.len() {
130        if data[i] != padding_byte {
131            // Padding unconsistent. No padding was applied.
132            return;
133        }
134    }
135    data.drain(data.len() - (padding_byte as usize)..);
136}
137/// Encrypts a data object using the specified cipher version.
138/// # Examples
139/// Encrypting a text message in AES-128-ECB mode of operation.
140/// ```
141/// use plain_aes::{encrypt, ModeOfOperation, CipherVersion};
142/// let message = "This is a super secret message";
143/// let key = "This lib is cool";
144/// let encrypted_message = encrypt(message, CipherVersion::Aes128(key.as_bytes(), ModeOfOperation::ECB)).unwrap();
145/// let expected_enrypted: &[u8] = &[
146///    0x11, 0x2B, 0xBD, 0x0D, 0x4C, 0x0C, 0xC5, 0x02, 0xB4, 0xC1, 0x38, 0xFD, 0x9A, 0x56,
147///    0xC1, 0xA8, 0x78, 0x61, 0xD9, 0xF5, 0x6B, 0x48, 0xCC, 0xC5, 0x48, 0x14, 0xF2, 0x8C,
148///    0x1A, 0x25, 0x11, 0xA3,
149/// ];
150/// assert!(expected_enrypted.iter().eq(encrypted_message.iter()))
151/// ```
152///
153/// Encrypting a text message in AES-192-CBC mode of operation.
154/// ```
155/// use plain_aes::{encrypt, ModeOfOperation, CipherVersion};
156/// let iv: [u8; 16] = [
157///    0x54, 0x68, 0x69, 0x73, 0x20, 0x6C, 0x69, 0x62, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6F,
158///    0x6F, 0x6C,
159/// ]; // You should not pass a fixed IV, this is for testing purposes.
160/// let message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultricies egestas nunc luctus congue. Pellentesque in vehicula lectus. Maecenas facilisis in tellus non accumsan. Cras at nisl eros. Donec efficitur dolor vitae odio cursus semper. Nulla facilisi. Nunc sit amet congue tellus. Ut sollicitudin odio ac odio malesuada, in sodales turpis pharetra.";
161/// let key = [0x54, 0x68, 0x69, 0x73, 0x20, 0x6C, 0x69, 0x62, 0x20, 0x63, 0x6F, 0x6F, 0x6C, 0x20, 0x79, 0x61, 0x64, 0x61, 0x20, 0x79, 0x61, 0x64, 0x61, 0x2E,]; // This lib cool yada yada.
162/// let encrypted_message = encrypt(message, CipherVersion::Aes192(&key[..], ModeOfOperation::CBC(&iv))).unwrap();
163/// let expected_enrypted: &[u8] = &[
164///     0x65,0xB9,0x79,0x89,0xFE,0x5F,0x15,0xC3,0x0A,0x33,0xAF,0xAD,0xE7,0xA1,0x60,0x14,0x86,0x91,0x85,0x57,0x82,0x51,0xC2,0x15,0x24,0x52,0x69,0x16,0x69,0x11,0x54,0x42,0xFE,0x45,0x0A,0x5E,0x87,0xC7,0x30,0x74,0x93,0xBD,0x24,0x3F,0xBB,0x21,0xD7,0xC9,0x22,0xAB,0x7D,0x0C,0xEA,0x4B,0x26,0x3B,0x97,0x7D,0x52,0x19,0x56,0x14,0x02,0x7A,0x70,0x70,0xC7,0x2D,0x1A,0x99,0xA6,0x65,0x89,0x34,0x9F,0x84,0xE3,0xC6,0x8B,0x06,0x8B,0x6A,0x2F,0xD8,0x71,0xFC,0x25,0xAF,0x6C,0x56,0x76,0xB5,0xF2,0x5B,0xD5,0x09,0xD2,0xE4,0x53,0xDB,0x6A,0x81,0xFE,0x42,0x7D,0xB6,0x77,0x0E,0x72,0xCB,0x90,0xDD,0x89,0xCA,0xA5,0x66,0x18,0x20,0xD3,0xD3,0x2D,0x56,0xA9,0x8D,0x25,0x8D,0x30,0x4A,0x1D,0x09,0x6E,0x90,0xFC,0x02,0x0E,0x4F,0x0C,0x04,0x46,0x7F,0x34,0xA6,0x4C,0xAA,0x5B,0xD1,0x05,0x67,0x7A,0xC4,0x52,0x1A,0x1C,0x29,0x6D,0x21,0xF8,0x88,0x6B,0x70,0x55,0xC2,0x00,0x94,0x5E,0x78,0x8F,0x53,0x05,0x50,0xB6,0xDF,0x2D,0x38,0x4D,0x76,0x0D,0x4E,0xC4,0xCB,0x1F,0xBA,0x46,0x65,0x95,0xBE,0xDC,0x89,0x83,0x78,0x25,0x2F,0xA1,0xA6,0x53,0x8D,0xAB,0x61,0xB4,0xF3,0x2B,0x6B,0x72,0x03,0xD7,0x54,0xFF,0xCB,0xA6,0xA1,0x26,0x97,0x84,0x43,0x26,0x49,0xDC,0x3E,0x14,0xCC,0x99,0x8F,0x30,0xE7,0xF6,0x11,0x40,0x87,0x9F,0xB2,0x65,0x40,0xB0,0x96,0x3D,0x6A,0x9D,0x89,0xC1,0x0F,0x25,0x4B,0x9F,0x26,0x5A,0x9F,0x52,0xC9,0x8D,0x72,0xE6,0x1F,0x0F,0xB8,0x2D,0x4F,0xA1,0x9F,0x29,0xEE,0xD2,0x61,0x61,0x6A,0x03,0xDF,0x33,0xB4,0xE8,0xA8,0x6F,0x73,0x87,0xAD,0xB4,0x93,0xB6,0xFA,0x76,0xCA,0x5C,0x38,0x01,0x0D,0x2B,0xC1,0x18,0xF5,0x4D,0x0F,0x84,0x08,0x94,0xCB,0xBE,0x91,0x7B,0x3D,0x5A,0xCD,0xE4,0x92,0x2B,0xD3,0xF4,0x02,0xB5,0x1B,0xEC,0x68,0xFB,0x72,0xAA,0x62,0x6B,0xA0,0xD2,0xF7,0xAB,0xF1,0x2E,0xCC,0xFB,0x38,0xBC,0xE0,0x83,0xB1,0x70,0xA5,0x94,0xF4,0xB3,0x92,0x2D,0x94,0xD2,0x5C,0x24,0x38,0x31,0xAB,0x59,0x29,0xE5,0x7A,0x98,0xF3,0x60,0x24,0x45,0xAD,0x55,0x57,0x5F,0x24,0x99,0xC0,0xD9,0x11,0xE1,0xEB,0x4C,0xDB,0xA4,0xCE,0x82,0xC2,
165/// ];
166/// assert!(expected_enrypted.iter().eq(encrypted_message.iter()))
167/// ```
168
169pub fn encrypt<T>(target: T, cipher_version: CipherVersion) -> Result<Vec<u8>, OperationError>
170where
171    T: Encryptable,
172{
173    match cipher_version.mode_of_operation() {
174        ModeOfOperation::CBC(iv) => {
175            match target.data() {
176                None => Err(OperationError::EmptyTarget),
177                Some(data) => {
178                    if data.len() < 16 {
179                        return Err(OperationError::InvalidTargetSize);
180                    }
181                    let mut cipher_data: Vec<u8> = Vec::new();
182                    let key_expansion = ExpandedKey::new(&cipher_version);
183                    if key_expansion.is_err() {
184                        return Err(OperationError::KeyExpansionFailed(
185                            key_expansion.unwrap_err(),
186                        ));
187                    }
188                    let expanded_key = key_expansion.unwrap();
189
190                    let block_num = data.len() / 16;
191                    let mut previous_encrypted_block: Option<[u8; 16]> = None;
192                    for i in 0..block_num {
193                        let block = &data[i * 16..(i + 1) * 16];
194                        let mut copied_block = block.to_vec(); // We must copy the current block because the initial data is not mutable, meaning the block cannot be mutated.
195                        let cipher_slice = copied_block.as_mut_slice();
196                        if let None = previous_encrypted_block {
197                            add_round_key(cipher_slice, *iv);
198                        } else {
199                            add_round_key(cipher_slice, &previous_encrypted_block.unwrap());
200                        }
201                        let encrypted_block = encrypt_block(cipher_slice, &expanded_key);
202                        previous_encrypted_block = Some(encrypted_block);
203                        cipher_data.extend(encrypted_block);
204                    }
205                    if data.len() % 16 != 0 {
206                        // There is remaining bytes less than 16 in length.
207                        let mut padded_vec = pkcs5_padding(&data[(block_num * 16)..]);
208                        let padded_block = padded_vec.as_mut_slice();
209                        add_round_key(padded_block, &previous_encrypted_block.unwrap());
210                        cipher_data.extend(encrypt_block(padded_block, &expanded_key));
211                    }
212                    Ok(cipher_data)
213                }
214            }
215        }
216        ModeOfOperation::ECB => match target.data() {
217            None => Err(OperationError::EmptyTarget),
218            Some(data) => {
219                if data.len() < 16 {
220                    return Err(OperationError::InvalidTargetSize);
221                }
222                let mut cipher_data: Vec<u8> = Vec::new();
223                let key_expansion = ExpandedKey::new(&cipher_version);
224                if key_expansion.is_err() {
225                    return Err(OperationError::KeyExpansionFailed(
226                        key_expansion.unwrap_err(),
227                    ));
228                }
229                let expanded_key = key_expansion.unwrap();
230
231                let block_num = data.len() / 16;
232                for i in 0..block_num {
233                    let block = &data[i * 16..(i + 1) * 16];
234                    let encrypted_block = encrypt_block(&block, &expanded_key);
235                    cipher_data.extend(encrypted_block);
236                }
237                if data.len() % 16 != 0 {
238                    // There is remaining bytes less than 16 in length.
239                    let padded_block = pkcs5_padding(&data[(block_num * 16)..]);
240                    cipher_data.extend(encrypt_block(&padded_block[..], &expanded_key));
241                }
242                Ok(cipher_data)
243            }
244        },
245    }
246}
247/// Decrypts a data object using the specified cipher version.
248/// # Examples
249/// Decrypting a byte sequence encrypted in AES-192-CBC mode of operation.
250/// ```
251/// use plain_aes::{decrypt, ModeOfOperation, CipherVersion};
252/// let iv: [u8; 16] = [
253///    0x54, 0x68, 0x69, 0x73, 0x20, 0x6C, 0x69, 0x62, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6F,
254///    0x6F, 0x6C,
255/// ]; // You should not pass a fixed IV, this is for testing purposes.
256/// let message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultricies egestas nunc luctus congue. Pellentesque in vehicula lectus. Maecenas facilisis in tellus non accumsan. Cras at nisl eros. Donec efficitur dolor vitae odio cursus semper. Nulla facilisi. Nunc sit amet congue tellus. Ut sollicitudin odio ac odio malesuada, in sodales turpis pharetra.";
257/// let key = [0x54, 0x68, 0x69, 0x73, 0x20, 0x6C, 0x69, 0x62, 0x20, 0x63, 0x6F, 0x6F, 0x6C, 0x20, 0x79, 0x61, 0x64, 0x61, 0x20, 0x79, 0x61, 0x64, 0x61, 0x2E,]; // This lib cool yada yada.
258/// let encrypted: &[u8] = &[
259///     0x65,0xB9,0x79,0x89,0xFE,0x5F,0x15,0xC3,0x0A,0x33,0xAF,0xAD,0xE7,0xA1,0x60,0x14,0x86,0x91,0x85,0x57,0x82,0x51,0xC2,0x15,0x24,0x52,0x69,0x16,0x69,0x11,0x54,0x42,0xFE,0x45,0x0A,0x5E,0x87,0xC7,0x30,0x74,0x93,0xBD,0x24,0x3F,0xBB,0x21,0xD7,0xC9,0x22,0xAB,0x7D,0x0C,0xEA,0x4B,0x26,0x3B,0x97,0x7D,0x52,0x19,0x56,0x14,0x02,0x7A,0x70,0x70,0xC7,0x2D,0x1A,0x99,0xA6,0x65,0x89,0x34,0x9F,0x84,0xE3,0xC6,0x8B,0x06,0x8B,0x6A,0x2F,0xD8,0x71,0xFC,0x25,0xAF,0x6C,0x56,0x76,0xB5,0xF2,0x5B,0xD5,0x09,0xD2,0xE4,0x53,0xDB,0x6A,0x81,0xFE,0x42,0x7D,0xB6,0x77,0x0E,0x72,0xCB,0x90,0xDD,0x89,0xCA,0xA5,0x66,0x18,0x20,0xD3,0xD3,0x2D,0x56,0xA9,0x8D,0x25,0x8D,0x30,0x4A,0x1D,0x09,0x6E,0x90,0xFC,0x02,0x0E,0x4F,0x0C,0x04,0x46,0x7F,0x34,0xA6,0x4C,0xAA,0x5B,0xD1,0x05,0x67,0x7A,0xC4,0x52,0x1A,0x1C,0x29,0x6D,0x21,0xF8,0x88,0x6B,0x70,0x55,0xC2,0x00,0x94,0x5E,0x78,0x8F,0x53,0x05,0x50,0xB6,0xDF,0x2D,0x38,0x4D,0x76,0x0D,0x4E,0xC4,0xCB,0x1F,0xBA,0x46,0x65,0x95,0xBE,0xDC,0x89,0x83,0x78,0x25,0x2F,0xA1,0xA6,0x53,0x8D,0xAB,0x61,0xB4,0xF3,0x2B,0x6B,0x72,0x03,0xD7,0x54,0xFF,0xCB,0xA6,0xA1,0x26,0x97,0x84,0x43,0x26,0x49,0xDC,0x3E,0x14,0xCC,0x99,0x8F,0x30,0xE7,0xF6,0x11,0x40,0x87,0x9F,0xB2,0x65,0x40,0xB0,0x96,0x3D,0x6A,0x9D,0x89,0xC1,0x0F,0x25,0x4B,0x9F,0x26,0x5A,0x9F,0x52,0xC9,0x8D,0x72,0xE6,0x1F,0x0F,0xB8,0x2D,0x4F,0xA1,0x9F,0x29,0xEE,0xD2,0x61,0x61,0x6A,0x03,0xDF,0x33,0xB4,0xE8,0xA8,0x6F,0x73,0x87,0xAD,0xB4,0x93,0xB6,0xFA,0x76,0xCA,0x5C,0x38,0x01,0x0D,0x2B,0xC1,0x18,0xF5,0x4D,0x0F,0x84,0x08,0x94,0xCB,0xBE,0x91,0x7B,0x3D,0x5A,0xCD,0xE4,0x92,0x2B,0xD3,0xF4,0x02,0xB5,0x1B,0xEC,0x68,0xFB,0x72,0xAA,0x62,0x6B,0xA0,0xD2,0xF7,0xAB,0xF1,0x2E,0xCC,0xFB,0x38,0xBC,0xE0,0x83,0xB1,0x70,0xA5,0x94,0xF4,0xB3,0x92,0x2D,0x94,0xD2,0x5C,0x24,0x38,0x31,0xAB,0x59,0x29,0xE5,0x7A,0x98,0xF3,0x60,0x24,0x45,0xAD,0x55,0x57,0x5F,0x24,0x99,0xC0,0xD9,0x11,0xE1,0xEB,0x4C,0xDB,0xA4,0xCE,0x82,0xC2,
260/// ];
261/// let decrypted_message = decrypt(encrypted, CipherVersion::Aes192(&key[..], ModeOfOperation::CBC(&iv))).unwrap();
262/// let expected_decrypted = message.as_bytes();
263/// assert!(expected_decrypted.iter().eq(decrypted_message.iter()))
264/// ```
265/// Decrypting a byte sequence encrypted in AES-128-ECB mode of operation.
266/// ```
267/// use plain_aes::{decrypt, ModeOfOperation, CipherVersion};
268/// let key = [
269///    0x54, 0x68, 0x69, 0x73, 0x20, 0x6C, 0x69, 0x62, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6F,
270///    0x6F, 0x6C,
271/// ]; // This lib is cool
272/// let message = "This is a super secret message";
273/// let encrypted: &[u8] = &[
274///    0x11, 0x2B, 0xBD, 0x0D, 0x4C, 0x0C, 0xC5, 0x02, 0xB4, 0xC1, 0x38, 0xFD, 0x9A, 0x56,
275///    0xC1, 0xA8, 0x78, 0x61, 0xD9, 0xF5, 0x6B, 0x48, 0xCC, 0xC5, 0x48, 0x14, 0xF2, 0x8C,
276///    0x1A, 0x25, 0x11, 0xA3,
277/// ];
278/// let decrypted_message = decrypt(encrypted, CipherVersion::Aes128(&key[..], ModeOfOperation::ECB)).unwrap();
279/// let expected_decrypted = message.as_bytes();
280/// assert!(expected_decrypted.iter().eq(decrypted_message.iter()))
281/// ```
282pub fn decrypt<T>(target: T, cipher_version: CipherVersion) -> Result<Vec<u8>, OperationError>
283where
284    T: Encryptable,
285{
286    match cipher_version.mode_of_operation() {
287        ModeOfOperation::CBC(iv) => match target.data() {
288            None => Err(OperationError::EmptyTarget),
289            Some(data) => {
290                if data.len() < 16 {
291                    return Err(OperationError::InvalidTargetSize);
292                }
293                let mut plain_data: Vec<u8> = Vec::new();
294                let key_expansion = ExpandedKey::new(&cipher_version);
295                if key_expansion.is_err() {
296                    return Err(OperationError::KeyExpansionFailed(
297                        key_expansion.unwrap_err(),
298                    ));
299                }
300                let expanded_key = key_expansion.unwrap();
301                let block_num: usize = data.len() / 16;
302                let mut previous_encrypted_block: Option<[u8; 16]> = None;
303                for i in 0..block_num {
304                    let block = &data[i * 16..(i + 1) * 16];
305                    let mut decrypted_block = decrypt_block(block, &expanded_key);
306                    if let None = previous_encrypted_block {
307                        add_round_key(&mut decrypted_block[..], *iv);
308                    } else {
309                        add_round_key(&mut decrypted_block[..], &previous_encrypted_block.unwrap());
310                    }
311                    let mut fixed_block: [u8; 16] = [0; 16];
312                    for i in 0..16 {
313                        fixed_block[i] = block[i];
314                    }
315                    previous_encrypted_block = Some(fixed_block);
316                    plain_data.extend(decrypted_block);
317                }
318                remove_pkcs5_padding(&mut plain_data);
319                Ok(plain_data)
320            }
321        },
322        ModeOfOperation::ECB => match target.data() {
323            None => Err(OperationError::EmptyTarget),
324            Some(data) => {
325                if data.len() < 16 {
326                    return Err(OperationError::InvalidTargetSize);
327                }
328                let mut plain_data: Vec<u8> = Vec::new();
329                let key_expansion = ExpandedKey::new(&cipher_version);
330                if key_expansion.is_err() {
331                    return Err(OperationError::KeyExpansionFailed(
332                        key_expansion.unwrap_err(),
333                    ));
334                }
335                let expanded_key = key_expansion.unwrap();
336                let block_num = data.len() / 16;
337                for i in 0..block_num {
338                    let block = &data[i * 16..(i + 1) * 16];
339                    let decrypted_block = decrypt_block(block, &expanded_key);
340                    plain_data.extend(decrypted_block);
341                }
342                // TO DO, alert user if data size is not 128 bits compliant (a block less than 16 bytes in size is left).
343                remove_pkcs5_padding(&mut plain_data);
344                Ok(plain_data)
345            }
346        },
347    }
348}
349
350#[cfg(test)]
351mod tests {
352    use super::*;
353
354    #[test]
355    fn pkcs5_padding_test() {
356        let block = [0x68, 0xe4, 0x48, 0xd5, 0xa9, 0xa4];
357        let expected_padded_block = [
358            0x68, 0xe4, 0x48, 0xd5, 0xa9, 0xa4, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
359            0x0a, 0x0a,
360        ];
361        let padded_block = pkcs5_padding(&block);
362        assert!(expected_padded_block.iter().eq(padded_block.iter()));
363    }
364    #[test]
365    fn remove_pkcs5_padding_test() {
366        let mut block = vec![
367            0x68, 0xe4, 0x48, 0xd5, 0xa9, 0xa4, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
368            0x0a, 0x0a,
369        ];
370        let expected_clean_block = [0x68, 0xe4, 0x48, 0xd5, 0xa9, 0xa4];
371        remove_pkcs5_padding(&mut block);
372        assert!(expected_clean_block.iter().eq(block.iter()));
373    }
374    #[test]
375    fn remove_pkcs5_padding_unconsistent_test() {
376        let mut block = vec![
377            0x68, 0xe4, 0x48, 0xd5, 0xa9, 0xa4, 0x68, 0xe4, 0x48, 0xd5, 0xa9, 0xa4, 0x6d, 0x0a,
378            0x0a, 0x0a,
379        ]; // We have what appears to be PKCS#5 padding, but unconsistent, should not mutate the block.
380        let original_block = block.clone();
381        remove_pkcs5_padding(&mut block);
382        assert!(original_block.iter().eq(block.iter()));
383    }
384}