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}