lanis_rs/utils/
crypt.rs

1use crate::utils::constants::URL;
2use crate::Error;
3use crate::Error::ServerSide;
4use aes::cipher::block_padding::{NoPadding, Pkcs7};
5use aes::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit};
6use md5::Md5;
7use rand::random;
8use regex::Regex;
9use reqwest::header::HeaderMap;
10use reqwest::Client;
11use rsa::pkcs8::{DecodePublicKey, EncodePrivateKey, EncodePublicKey};
12use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};
13use serde::de::DeserializeOwned;
14use serde::{Deserialize, Serialize};
15
16type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;
17type Aes256CbcEnc = cbc::Encryptor<aes::Aes256>;
18
19#[derive(Clone, Eq, PartialEq, Hash, Debug)]
20pub struct LanisKeyPair {
21    pub private_key: RsaPrivateKey,
22    pub public_key: RsaPublicKey,
23    /// Private key in PKCS#8 format
24    pub private_key_string: String,
25    /// Public key in PKCS#8 format
26    pub public_key_string: String,
27    /// Public key that's encoded and encrypted
28    pub public_key_lanis: String,
29}
30
31/// Takes key_size (in bits) and returns an RSA KeyPair
32pub async fn generate_lanis_key_pair(
33    key_size: usize,
34    client: &Client,
35) -> Result<LanisKeyPair, Error> {
36    let mut rng = rand::thread_rng();
37    match RsaPrivateKey::new(&mut rng, key_size) {
38        Ok(private_key) => {
39            let public_key = RsaPublicKey::from(&private_key);
40
41            let private_key_string = private_key.to_pkcs8_pem(Default::default());
42            let public_key_string = public_key.to_public_key_pem(Default::default());
43
44            if private_key_string.is_ok() && public_key_string.is_ok() {
45                let private_key_string = private_key_string.unwrap().to_string();
46                let public_key_string = public_key_string.unwrap();
47
48                match handshake(client, &public_key_string).await {
49                    Ok(public_key_lanis) => Ok(LanisKeyPair {
50                        private_key,
51                        public_key,
52                        private_key_string,
53                        public_key_string,
54                        public_key_lanis,
55                    }),
56                    Err(e) => Err(ServerSide(format!(
57                        "Handshake with lanis failed with error: '{}'",
58                        e
59                    ))),
60                }
61            } else {
62                Err(Error::Parsing(
63                    "Failed to convert private key and/or public key to pkcs8 pem!".to_string(),
64                ))
65            }
66        }
67        Err(e) => Err(Error::Crypto(format!(
68            "Failed to generate Private key!: {}",
69            e
70        ))),
71    }
72}
73
74async fn handshake(client: &Client, public_own_key: &String) -> Result<String, String> {
75    let mut rng = rand::thread_rng();
76    let public_key = get_public_key(&client).await?;
77
78    match public_key.encrypt(&mut rng, Pkcs1v15Encrypt, public_own_key.as_bytes()) {
79        Ok(encrypted_key) => {
80
81            let encrypted_key = base64::Engine::encode(&base64::engine::general_purpose::STANDARD, encrypted_key);
82
83            let mut headers = HeaderMap::new();
84            headers.insert("Accept", "*/*".parse().unwrap());
85            headers.insert("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8".parse().unwrap());
86            headers.insert("Sec-Fetch-Dest", "empty".parse().unwrap());
87            headers.insert("Sec-Fetch-Mode", "cors".parse().unwrap());
88            headers.insert("Sec-Fetch-Site", "same-origin".parse().unwrap());
89
90            match client.post(URL::AJAX).headers(headers).query(&[("f", "rsaHandshake"), ("s", "1111")]).form(&[("key", &encrypted_key)]).send().await {
91                Ok(response) => {
92                    #[derive(Debug, Deserialize)]
93                    struct ResponseData {
94                        challenge: String,
95                    }
96
97                    match serde_json::from_str::<ResponseData>(response.text().await.unwrap().as_str()) {
98                        Ok(data) => {
99                            match base64::Engine::decode(&base64::engine::general_purpose::STANDARD, &data.challenge) {
100                                Ok(challenge) => {
101                                    let result = decrypt_lanis_with_key(&challenge, public_own_key).await?;
102                                    let result_string = String::from_utf8_lossy(&result);
103                                    let result_string = result_string.trim();
104                                    if result_string == public_own_key.trim() {
105                                        Ok(encrypted_key)
106                                    } else {
107                                        Err(format!("Failed to perform challenge! Public Keys don't match!:\nOwn Public Key:\n{}\n\nResponse Public Key:\n{}", public_own_key, result_string))
108                                    }
109                                }
110                                Err(e) => {
111                                    Err(format!("Failed to decode challenge with error: '{}'", e))
112                                }
113                            }
114                        }
115                        Err(e) => {
116                            Err(format!("Failed to decode json with error: '{}'", e))
117                        }
118                    }
119                }
120                Err(e) =>  Err(format!("Failed to perform handshake with error: '{}'", e)),
121            }
122        }
123        Err(e) => {
124            Err(format!("Failed to encrypt with error: '{}'\nIs your public key to long? Maybe take a look at the documentation of the key 'key_pair' in struct 'Account'", e))
125        }
126    }
127}
128
129async fn get_public_key(client: &Client) -> Result<RsaPublicKey, String> {
130    let mut headers = HeaderMap::new();
131    headers.insert("Accept", "*/*".parse().unwrap());
132    headers.insert(
133        "Content-Type",
134        "application/x-www-form-urlencoded; charset=UTF-8"
135            .parse()
136            .unwrap(),
137    );
138    headers.insert("Sec-Fetch-Dest", "empty".parse().unwrap());
139    headers.insert("Sec-Fetch-Mode", "cors".parse().unwrap());
140    headers.insert("Sec-Fetch-Site", "same-origin".parse().unwrap());
141
142    match client
143        .post(URL::AJAX)
144        .headers(headers)
145        .query(&[("f", "rsaPublicKey")])
146        .send()
147        .await
148    {
149        Ok(response) => {
150            #[derive(Debug, Deserialize)]
151            // From the hearth
152            struct FuckYouLanis {
153                publickey: String,
154            }
155
156            let response_json = response.text().await.unwrap();
157            let json: FuckYouLanis = serde_json::from_str(&response_json).unwrap();
158            let public_key = json.publickey;
159            let public_key = RsaPublicKey::from_public_key_pem(&public_key).unwrap();
160
161            Ok(public_key)
162        }
163        Err(e) => Err(format!("Failed to get public key with error: {}", e)),
164    }
165}
166
167/// Encrypts data that can be sent to lanis
168pub async fn encrypt_lanis_data(data: &[u8], public_key: &String) -> String {
169    let salt = random::<[u8; 8]>();
170
171    const KEY_SIZE: usize = 256;
172    const IV_SIZE: usize = 128;
173
174    let mut output = [0; (KEY_SIZE + IV_SIZE) / 8];
175    evpkdf::evpkdf::<Md5>(public_key.as_bytes(), &salt, 1, &mut output);
176
177    let (key, iv) = output.split_at(KEY_SIZE / 8);
178
179    let key: [u8; 32] = key.try_into().unwrap();
180    let iv: [u8; 16] = iv.try_into().unwrap();
181
182    let encryptor = Aes256CbcEnc::new(&key.into(), &iv.into());
183
184    let encrypted = {
185        let salted = "Salted__".to_string();
186        let salted = salted.as_bytes();
187
188        let encrypted = encryptor.encrypt_padded_vec_mut::<Pkcs7>(&data);
189
190        let mut result: Vec<u8> = Vec::new();
191        result.extend(salted);
192        result.extend(salt);
193        result.extend(encrypted);
194
195        result
196    };
197
198    let result = base64::Engine::encode(&base64::engine::general_purpose::STANDARD, encrypted);
199
200    result
201}
202
203/// Allows to decrypt encoded text from raw lanis html
204pub async fn decrypt_lanis_encoded_tags(html_string: &str, key: &String) -> String {
205    let exp = Regex::new(r"<encoded>(.*?)</encoded>").unwrap();
206
207    let mut replaced_html = html_string.to_string();
208
209    for caps in exp.captures_iter(html_string) {
210        if let Some(encoded_content) = caps.get(1) {
211            let decrypted_content =
212                decrypt_lanis_string_with_key(encoded_content.as_str(), key).await;
213            let decrypted_string = decrypted_content.unwrap_or_default();
214            replaced_html = replaced_html.replacen(&caps[0], &decrypted_string, 1);
215        }
216    }
217
218    replaced_html.to_string()
219}
220
221/// Allows to decrypt string from lanis
222pub async fn decrypt_lanis_string_with_key(
223    data: &str,
224    public_key: &String,
225) -> Result<String, String> {
226    match base64::Engine::decode(&base64::engine::general_purpose::STANDARD, &data) {
227        Ok(data) => {
228            let result = decrypt_lanis_with_key(&data, &public_key).await?;
229            let result_string = String::from_utf8_lossy(&result);
230            let result_string = result_string.trim();
231            Ok(result_string.to_string())
232        }
233        Err(e) => Err(format!(
234            "Failed to decode base64 string with error: '{}'",
235            e
236        )),
237    }
238}
239
240/// Allows to decrypt raw bytes from lanis
241pub async fn decrypt_lanis_with_key(
242    data: &Vec<u8>,
243    public_key: &String,
244) -> Result<Vec<u8>, String> {
245    fn is_salted(encrypted_data: &Vec<u8>) -> bool {
246        match std::str::from_utf8(&encrypted_data[0..8]) {
247            Ok(s) => s == "Salted__",
248            Err(_) => false,
249        }
250    }
251
252    if !is_salted(&data) {
253        return Err("Data is not salted!".to_string());
254    }
255
256    let salt = &data[8..16];
257
258    const KEY_SIZE: usize = 256;
259    const IV_SIZE: usize = 128;
260
261    let mut output = [0; (KEY_SIZE + IV_SIZE) / 8];
262
263    evpkdf::evpkdf::<Md5>(public_key.as_bytes(), salt, 1, &mut output);
264
265    let (key, iv) = output.split_at(KEY_SIZE / 8);
266
267    let key: [u8; 32] = key.try_into().unwrap();
268    let iv: [u8; 16] = iv.try_into().unwrap();
269
270    let decryptor = Aes256CbcDec::new(&key.into(), &iv.into());
271
272    let result = decryptor
273        .decrypt_padded_vec_mut::<NoPadding>(&data[16..])
274        .unwrap();
275
276    Ok(result)
277}
278
279#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
280pub enum CryptorError {
281    /// Happens if serde_json fails to convert `T` into a [Vec<u8>]
282    Serialization(String),
283    /// Happens if serde_json fails to convert the decrypted data to `T`
284    Deserialization(String),
285    /// Happens if decryption fails
286    Decryption(String),
287}
288
289/// Allows to encrypt every type that implements Clone & Serialize. (as JSON)
290pub async fn encrypt_any<T: Clone + Serialize>(
291    data: &T,
292    key: &[u8; 32],
293) -> Result<Vec<u8>, CryptorError> {
294    let iv = [0; 16];
295
296    let serialized =
297        serde_json::to_vec(&data).map_err(|e| CryptorError::Serialization(e.to_string()))?;
298
299    let cipher = Aes256CbcEnc::new(&(*key).into(), &iv.into());
300    let result = cipher.encrypt_padded_vec_mut::<Pkcs7>(serialized.as_slice());
301
302    Ok(result)
303}
304
305/// Decrypts any previous encrypted type
306pub async fn decrypt_any<T: Clone + DeserializeOwned>(
307    data: &[u8],
308    key: &[u8; 32],
309) -> Result<T, CryptorError> {
310    let iv = [0; 16];
311
312    let decryptor = Aes256CbcDec::new(&(*key).into(), &iv.into());
313    let decrypted = decryptor
314        .decrypt_padded_vec_mut::<Pkcs7>(data)
315        .map_err(|e| CryptorError::Decryption(e.to_string()))?;
316
317    let result: T = serde_json::from_slice(&decrypted)
318        .map_err(|e| CryptorError::Deserialization(e.to_string()))?;
319    Ok(result)
320}
321