1use aes::cipher::generic_array::GenericArray;
12use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit};
13use aes::Aes128;
14
15pub const KEY: [u8; 16] = [
17 0x5e, 0x9e, 0x4f, 0x00, 0x94, 0xef, 0x20, 0xab, 0x52, 0xe3, 0x5e, 0x73, 0x6a, 0xcb, 0x23, 0x24,
18];
19
20pub const BLOCK: usize = 16;
22
23#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25pub struct LengthError(pub usize);
26
27impl core::fmt::Display for LengthError {
28 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
29 write!(
30 f,
31 "enc: length {} is not a multiple of the {BLOCK}-byte AES block",
32 self.0
33 )
34 }
35}
36
37#[cfg(feature = "std")]
38impl std::error::Error for LengthError {}
39
40fn check(data: &[u8]) -> Result<(), LengthError> {
41 if data.len() % BLOCK != 0 {
42 return Err(LengthError(data.len()));
43 }
44 Ok(())
45}
46
47pub fn encrypt(data: &mut [u8]) -> Result<(), LengthError> {
49 check(data)?;
50 let cipher = Aes128::new(GenericArray::from_slice(&KEY));
51 for block in data.chunks_mut(BLOCK) {
52 cipher.encrypt_block(GenericArray::from_mut_slice(block));
53 }
54 Ok(())
55}
56
57pub fn decrypt(data: &mut [u8]) -> Result<(), LengthError> {
59 check(data)?;
60 let cipher = Aes128::new(GenericArray::from_slice(&KEY));
61 for block in data.chunks_mut(BLOCK) {
62 cipher.decrypt_block(GenericArray::from_mut_slice(block));
63 }
64 Ok(())
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn round_trips_and_rejects_partial_blocks() {
73 let mut data = [0u8; 32];
74 data[0] = 1;
75 let original = data;
76 encrypt(&mut data).unwrap();
77 assert_ne!(data, original);
78 let mut zeros = [0u8; 32];
80 encrypt(&mut zeros).unwrap();
81 assert_eq!(zeros[..16], zeros[16..]);
82 decrypt(&mut data).unwrap();
83 assert_eq!(data, original);
84 assert_eq!(encrypt(&mut [0u8; 15]), Err(LengthError(15)));
85 }
86}