1use aes::{
2 cipher::{consts::U16, generic_array::GenericArray, BlockCipherMut, NewBlockCipher},
3 Aes128,
4};
5#[cfg(feature = "backtrace")]
6use std::backtrace::Backtrace;
7use thiserror::Error;
8
9pub type CraftCipherResult<T> = Result<T, CipherError>;
10
11#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
12pub enum CipherComponent {
13 Key,
14 Iv,
15}
16
17#[derive(Debug, Error)]
18pub enum CipherError {
19 #[error("encryption is already enabled and cannot be enabled again")]
20 AlreadyEnabled {
21 #[cfg(feature = "backtrace")]
22 backtrace: Backtrace,
23 },
24 #[error("bad size '{size}' for '{component:?}'")]
25 BadSize {
26 size: usize,
27 component: CipherComponent,
28 #[cfg(feature = "backtrace")]
29 backtrace: Backtrace,
30 },
31}
32
33impl CipherError {
34 fn bad_size(component: CipherComponent, size: usize) -> Self {
35 CipherError::BadSize {
36 component,
37 size,
38 #[cfg(feature = "backtrace")]
39 backtrace: Backtrace::capture(),
40 }
41 }
42
43 fn already_enabled() -> Self {
44 CipherError::AlreadyEnabled {
45 #[cfg(feature = "backtrace")]
46 backtrace: Backtrace::capture(),
47 }
48 }
49}
50
51const BYTES_SIZE: usize = 16;
52
53pub struct CraftCipher {
54 iv: GenericArray<u8, U16>,
55 tmp: GenericArray<u8, U16>,
56 cipher: Aes128,
57}
58
59impl CraftCipher {
60 pub fn new(key: &[u8], iv: &[u8]) -> CraftCipherResult<Self> {
61 if iv.len() != BYTES_SIZE {
62 return Err(CipherError::bad_size(CipherComponent::Iv, iv.len()));
63 }
64
65 if key.len() != BYTES_SIZE {
66 return Err(CipherError::bad_size(CipherComponent::Key, key.len()));
67 }
68
69 let mut iv_out = [0u8; BYTES_SIZE];
70 iv_out.copy_from_slice(iv);
71
72 let mut key_out = [0u8; BYTES_SIZE];
73 key_out.copy_from_slice(key);
74
75 let tmp = [0u8; BYTES_SIZE];
76
77 Ok(Self {
78 iv: GenericArray::from(iv_out),
79 tmp: GenericArray::from(tmp),
80 cipher: Aes128::new(&GenericArray::from(key_out)),
81 })
82 }
83
84 pub fn encrypt(&mut self, data: &mut [u8]) {
85 unsafe { self.crypt(data, false) }
86 }
87
88 pub fn decrypt(&mut self, data: &mut [u8]) {
89 unsafe { self.crypt(data, true) }
90 }
91
92 unsafe fn crypt(&mut self, data: &mut [u8], decrypt: bool) {
93 let iv = &mut self.iv;
94 const IV_SIZE: usize = 16;
95 const IV_SIZE_MINUS_ONE: usize = IV_SIZE - 1;
96 let iv_ptr = iv.as_mut_ptr();
97 let iv_end_ptr = iv_ptr.offset(IV_SIZE_MINUS_ONE as isize);
98 let tmp_ptr = self.tmp.as_mut_ptr();
99 let tmp_offset_one_ptr = tmp_ptr.offset(1);
100 let cipher = &mut self.cipher;
101 let n = data.len();
102 let mut data_ptr = data.as_mut_ptr();
103 let data_end_ptr = data_ptr.offset(n as isize);
104
105 while data_ptr != data_end_ptr {
106 std::ptr::copy_nonoverlapping(iv_ptr, tmp_ptr, IV_SIZE);
107 cipher.encrypt_block(iv);
108 let orig = *data_ptr;
109 let updated = orig ^ *iv_ptr;
110 std::ptr::copy_nonoverlapping(tmp_offset_one_ptr, iv_ptr, IV_SIZE_MINUS_ONE);
111 if decrypt {
112 *iv_end_ptr = orig;
113 } else {
114 *iv_end_ptr = updated;
115 }
116 *data_ptr = updated;
117 data_ptr = data_ptr.offset(1);
118 }
119 }
120}
121
122pub(crate) fn setup_craft_cipher(
123 target: &mut Option<CraftCipher>,
124 key: &[u8],
125 iv: &[u8],
126) -> Result<(), CipherError> {
127 if target.is_some() {
128 Err(CipherError::already_enabled())
129 } else {
130 *target = Some(CraftCipher::new(key, iv)?);
131 Ok(())
132 }
133}