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