1use crate::random::Random;
2use aes::cipher::{
3 block_padding::{Pkcs7, UnpadError},
4 BlockDecryptMut, BlockEncryptMut, KeyInit,
5};
6use thiserror::Error;
7use tracing::debug;
8
9type EcbEncryptor = ecb::Encryptor<aes::Aes128>;
10type EcbDecryptor = ecb::Decryptor<aes::Aes128>;
11
12const KEY_SIZE: usize = 16;
13const DEFAULT_SEED: u32 = 7;
14
15#[derive(Debug, Error)]
16pub enum CryptoError {
17 #[error("Input cannot be empty")]
18 EmptyInput,
19
20 #[error("Decryption failed: {0}")]
21 DecryptionFailed(String),
22
23 #[error("UTF-8 conversion error")]
24 Utf8Error(#[from] std::string::FromUtf8Error),
25}
26#[derive(Clone, Debug)]
27pub struct Crypto {
28 key: [u8; KEY_SIZE],
29}
30
31impl Crypto {
32 pub fn new(seed: u32) -> Self {
33 let mut crypto = Self {
34 key: [0u8; KEY_SIZE],
35 };
36
37 crypto.set_key(seed);
38 crypto
39 }
40
41 pub fn set_key(&mut self, seed: u32) {
42 let mut key = [0u8; KEY_SIZE];
43
44 if seed == 0 {
45 for (i, byte) in key.iter_mut().enumerate() {
46 *byte = i as u8
47 }
48 } else {
49 let mut rng = Random::new(DEFAULT_SEED);
50 let new_seed = rng.next().wrapping_add(seed);
51 rng.set_seed(new_seed);
52
53 for byte in key.iter_mut() {
54 *byte = rng.next() as u8
55 }
56 }
57
58 debug!("Setting new encryption key: {:?}", hex::encode(key));
59 self.key = key;
60 }
61
62 pub fn encrypt(&self, plain_text: &str) -> Result<Vec<u8>, CryptoError> {
63 if plain_text.is_empty() {
64 return Err(CryptoError::EmptyInput);
65 }
66
67 let res = EcbEncryptor::new(&self.key.into())
68 .encrypt_padded_vec_mut::<Pkcs7>(plain_text.as_bytes());
69
70 Ok(res)
71 }
72
73 pub fn decrypt(&self, cipher_text: &[u8]) -> Result<String, CryptoError> {
74 if cipher_text.is_empty() {
75 return Err(CryptoError::EmptyInput);
76 }
77
78 let res = EcbDecryptor::new(&self.key.into())
79 .decrypt_padded_vec_mut::<Pkcs7>(cipher_text)
80 .map_err(|e: UnpadError| CryptoError::DecryptionFailed(e.to_string()))?;
81
82 String::from_utf8(res).map_err(CryptoError::from)
83 }
84
85 pub fn prepare_challenge_response(&mut self, key: &str) -> Result<String, CryptoError> {
86 let response_key = self.encrypt(key)?;
87 let response_str = hex::encode(&response_key);
88 let response_bytes = response_str.as_bytes();
89
90 let seed = ((response_bytes[0] as u32) << 8) | (response_bytes[1] as u32);
91 self.set_key(seed);
92
93 Ok(response_str)
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn test_key() {
103 let crypto = Crypto::new(0);
104
105 assert_eq!(crypto.key.len(), KEY_SIZE);
106 assert_eq!(
107 &crypto.key as &[u8],
108 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
109 );
110
111 let crypto = Crypto::new(1337);
112
113 assert_eq!(crypto.key.len(), KEY_SIZE);
114 assert_eq!(
115 &crypto.key as &[u8],
116 [251, 135, 22, 197, 214, 181, 148, 115, 149, 93, 40, 78, 123, 141, 60, 108]
117 );
118 }
119
120 #[test]
121 fn test_encrypt_decrypt() {
122 let crypto = Crypto::new(1337);
123
124 let plain_text = "hello world".to_string();
125 let cipher_text = crypto.encrypt(&plain_text).expect("Failed to encrypt");
126 let decrypted_text = crypto.decrypt(&cipher_text).expect("Failed to decrypt");
127
128 assert_eq!(plain_text, decrypted_text);
129 }
130}