diff --git a/unshell-cli/src/main.rs b/unshell-cli/src/main.rs index 5c47fda..1b9cb76 100644 --- a/unshell-cli/src/main.rs +++ b/unshell-cli/src/main.rs @@ -1,82 +1,8 @@ use std::io::{Write, stdin, stdout}; -use unshell_crypt::{ - aes::{decrypt_aes, decrypt_aes_lines, encrypt_aes, encrypt_aes_lines}, - base62::Base62, - fill, hash, -}; use unshell_lib::Announcement; -use unshell_obfuscate::format_obs; - fn main() -> Result<(), Box> { - // let aaa = unshell_lib::crypt::aes::decrypt_aes( - // "611dcb046fcb11c3a0cf6d27ac7c8452e0120c2675d067a0dd857d9cd3d9df21140f1e2a715083a48180907eb90b87a6", //_1c82a871dda0f4372eb8e0dbba34c8de", - // "abc123abc", - // )?; - - let key = "abc123abc"; - - println!( - "{}", - encrypt_aes_lines("Verylongstringthat1", &key, unshell_crypt::STATIC_IV) - ); - println!( - "{}", - encrypt_aes_lines("Verylongstringthat12", &key, unshell_crypt::STATIC_IV) - ); - println!( - "{}", - encrypt_aes_lines("Verylongstringthat123", &key, unshell_crypt::STATIC_IV) - ); - println!( - "{}", - encrypt_aes_lines("Verylongstringthat1234", &key, unshell_crypt::STATIC_IV) - ); - println!( - "{}", - encrypt_aes_lines("Verylongstringthat12345", &key, unshell_crypt::STATIC_IV) - ); - - // let e = Base62::encode_full(data, &key); - // let e = "_Nl8MlCFOyM4egPSXfo0wE4tfA0vOfBSZCx1TpKzjhI2qfahTrwh4JE1pJpcBttQqz_"; - - // let mut buf = [0u8; 256]; - // _L1IuRLMW8tZN68RerKcbltQl675Yeq930NbcxsEfYYf_ - // _L1IuRLMW8tZN68RerKcblyGtqOCLeLuBu3ormgklt3J_ - // _L1IuRLMW8tZN68RerKcblKi37HPcZRonvwFUS5SZc0C_ - // _L1IuRLMW8tZN68RerKcblya0Yw6TrFQxruqpemtv3K2_ - - // fill(&mut buf); - - // for byte in buf.iter() { - // print!("{}, ", byte); - // } - - // src/main.rs:13 - // _SqF7lDRCyatsM4hnUTNAOq_ - // - // _Nl8MlCFOyM4egPSXfo0wE4tfA0vOfBSZCx1TpKzjhI2qfahTrwh4JE1pJpcBttQqz_ - // unshell-lib-0.0.0/src/module/manager.rs:52 - - // println!("Key: {}", String::from_utf8_lossy(&key)); - - // let encoded = Base62::decode_full(&e, &key).unwrap(); - // let plaintext = decrypt_aes_lines(&data, &key, unshell_crypt::STATIC_IV); - - // let base = Base62::new(&hash("TEST_KEY".as_bytes()), 0); - - // let encoded = base.encode("123 1234 12342 1235e2".as_bytes()); - - // println!("Base62: {}", plaintext); - - // let base = Base62::new(&hash("TEST_KEY".as_bytes()), 0); - - // let decoded = base.decode(&encoded).unwrap(); - // println!("Decoded: {}", String::from_utf8(decoded).unwrap()); - - // Ok(()) - let mut serverruntime = unshell_lib::server::ListenerRuntime::new(); loop { diff --git a/unshell-crypt/src/aes.rs b/unshell-crypt/src/aes.rs index 0a1002c..e8decc9 100644 --- a/unshell-crypt/src/aes.rs +++ b/unshell-crypt/src/aes.rs @@ -9,45 +9,74 @@ fn pkcs7_padded_length(input_len: usize) -> usize { } pub fn encrypt_aes(plaintext: &str, key_str: &str, iv: [u8; 16]) -> String { + let plaintext = plaintext.as_bytes(); + // Hash the env key to get a 32-byte (256-bit) AES key let key = hash(key_str.as_bytes()); - let plaintext = plaintext.as_bytes(); + // Generate a psudo-random salt byte based on the plaintext + // I hope this does not break the encryption. + let mut salt = 0; + + for byte in plaintext { + salt ^= byte; + } + + let mut key_salted = key.clone(); + + // Salt the key by XORing the salt byte with all the key bytes. + // This ensures that the "hash" generated from the plaintext will + // make the encrypted result extremely different. + for i in 0..32 { + key_salted[i] ^= salt; + } let buf_len = pkcs7_padded_length(plaintext.len()); let mut buf = vec![0u8; buf_len]; let pt_len = plaintext.len(); buf[..pt_len].copy_from_slice(&plaintext); - let ct = cbc::Encryptor::::new(&key.into(), &iv.into()) - .encrypt_padded_mut::(&mut buf, pt_len) - .unwrap(); - Base62::encode_full(ct, &key) + let mut ct = cbc::Encryptor::::new(&key_salted.into(), &iv.into()) + .encrypt_padded_mut::(&mut buf, pt_len) + .unwrap() + .to_vec(); + + // Add the salt byte to the key byte, + ct.insert(0, salt); + + // Encode result in base62 + Base62::encode_full(&ct, &key) } pub fn encrypt_aes_lines(plaintext: &str, key_str: &str, iv: [u8; 16]) -> String { format!("_{}_", encrypt_aes(plaintext, key_str, iv)) } -pub fn decrypt_aes(input: &str, key_str: &str, iv: [u8; 16]) -> String { +pub fn decrypt_aes(input: &str, key_str: &str, iv: [u8; 16]) -> Result { // Hash the env key to get a 32-byte (256-bit) AES key - let key = hash(key_str.as_bytes()); + let mut key = hash(key_str.as_bytes()); - let cipher_bytes = Base62::decode_full(input, &key).unwrap(); + let mut cipher_bytes = Base62::decode_full(input, &key).unwrap(); + + let salt = cipher_bytes.remove(0); + + // XOR the salt bytes with the key bytes + // This replicates + for i in 0..32 { + key[i] ^= salt; + } // Create buffer for result let buf_len = cipher_bytes.len(); let mut buf: Vec = vec![0; buf_len]; buf[..cipher_bytes.len()].copy_from_slice(&cipher_bytes); - if let Ok(pt) = cbc::Decryptor::::new(&key.into(), &iv.into()) + let pt = cbc::Decryptor::::new(&key.into(), &iv.into()) .decrypt_padded_mut::(&mut buf) - { - String::from_utf8_lossy(pt).to_string() - } else { - "".to_string() - } + .map_err(|_| "decryption failed".to_string())?; + + Ok(String::from_utf8_lossy(pt).to_string()) } pub fn decrypt_aes_lines(input: &str, key_str: &str, iv: [u8; 16]) -> String { @@ -57,14 +86,17 @@ pub fn decrypt_aes_lines(input: &str, key_str: &str, iv: [u8; 16]) -> String { for aes_block in Regex::new(r"_([0-9a-zA-Z]*?)_").unwrap().find_iter(&input) { let range = aes_block.range(); let aes_block = aes_block.as_str()[1..(aes_block.len() - 1)].to_string(); - let decrypted_block = decrypt_aes(&aes_block, key_str, iv); - let range = (range.start + total_offset as usize)..(range.end + total_offset as usize); + if let Ok(decrypted_block) = decrypt_aes(&aes_block, key_str, iv) { + let range = (range.start + total_offset as usize)..(range.end + total_offset as usize); - // Offset range by the difference between the decrypted block length and the original range length - total_offset += decrypted_block.len().clone() - (range.end - range.start); + // Offset range by the difference between the decrypted block length and the original range length + total_offset += decrypted_block.len().clone() - (range.end - range.start); - decrypted_result.replace_range(range, &decrypted_block); + decrypted_result.replace_range(range, &decrypted_block); + } else { + continue; + } } decrypted_result diff --git a/unshell-crypt/src/base62.rs b/unshell-crypt/src/base62.rs index fdacaf0..eda55f4 100644 --- a/unshell-crypt/src/base62.rs +++ b/unshell-crypt/src/base62.rs @@ -123,13 +123,15 @@ impl Base62 { let base = Base62::new(&key, length % 255); let encoded = base.encode(data); + // For the case that the encoded length is not equal to the predicted length + // The nonce must be derived from this length, so this needs to be ensured + // + // Re-encode with the correct length if encoded.len() != length { let len = encoded.len(); let base = Base62::new(&key, len % 255); let encoded = base.encode(data); - println!("Fallback"); - assert_eq!(encoded.len(), len); encoded @@ -141,8 +143,6 @@ impl Base62 { let base = Base62::new(&key, data.len() % 255); base.decode(data) } - - // pub fn encode_full } // Helper: Check if big integer (as bytes) is zero