myph-v2~ rust shellcode loader with evasive capabilities |
| git clone https://github.com/djnnvx/myph-v2.git |
| log | files | refs | archive | README |
chacha20_cipher.rs (5676B)
1 use super::Encryptor; 2 use chacha20::cipher::{KeyIvInit, StreamCipher}; 3 use chacha20::ChaCha20; 4 use rand::Rng; 5 use sha2::{Digest, Sha256}; 6 7 /// ChaCha20 stream cipher implementation 8 pub struct ChaCha20Encryptor { 9 key: [u8; 32], 10 } 11 12 impl ChaCha20Encryptor { 13 /// Creates a new ChaCha20 encryptor with the given key 14 /// Uses SHA-256 to derive a proper 32-byte key from the input 15 pub fn new(key: &str) -> Self { 16 let mut hasher = Sha256::new(); 17 hasher.update(key.as_bytes()); 18 let hash = hasher.finalize(); 19 20 // Use full 32 bytes of SHA-256 hash for ChaCha20 key 21 let mut key_bytes = [0u8; 32]; 22 key_bytes.copy_from_slice(&hash[..32]); 23 24 println!( 25 "[ChaCha20] Derived key from input (SHA-256): {:02x?}", 26 &key_bytes[..8] 27 ); 28 29 Self { key: key_bytes } 30 } 31 } 32 33 impl Encryptor for ChaCha20Encryptor { 34 fn encrypt(&self, data: &[u8]) -> Result<Vec<u8>, String> { 35 // Generate random nonce (12 bytes for ChaCha20) 36 let mut rng = rand::thread_rng(); 37 let mut nonce = [0u8; 12]; 38 rng.fill(&mut nonce); 39 40 println!( 41 "[ChaCha20] Generated random nonce for encryption: {:02x?}", 42 &nonce 43 ); 44 45 let mut cipher = ChaCha20::new(&self.key.into(), &nonce.into()); 46 let mut buffer = data.to_vec(); 47 cipher.apply_keystream(&mut buffer); 48 49 // Prepend nonce to ciphertext 50 let mut result = nonce.to_vec(); 51 result.extend_from_slice(&buffer); 52 53 Ok(result) 54 } 55 56 fn decrypt(&self, data: &[u8]) -> Result<Vec<u8>, String> { 57 if data.len() < 12 { 58 return Err("Ciphertext too short to contain nonce".to_string()); 59 } 60 61 // Extract nonce from beginning of data 62 let nonce: [u8; 12] = data[..12].try_into().unwrap(); 63 let ciphertext = &data[12..]; 64 65 println!("[ChaCha20] Extracted nonce for decryption: {:02x?}", &nonce); 66 67 // ChaCha20 is symmetric - same operation for decrypt 68 let mut cipher = ChaCha20::new(&self.key.into(), &nonce.into()); 69 let mut buffer = ciphertext.to_vec(); 70 cipher.apply_keystream(&mut buffer); 71 72 Ok(buffer) 73 } 74 75 fn key_size(&self) -> usize { 76 32 // ChaCha20 uses 32-byte keys 77 } 78 79 fn algorithm_name(&self) -> &'static str { 80 "ChaCha20" 81 } 82 83 fn uses_iv(&self) -> bool { 84 true // Uses nonce 85 } 86 87 fn generate_decrypt_code(&self) -> &'static str { 88 r#"/// Decrypts ChaCha20 encrypted data using the provided key 89 /// 90 /// Returns `Ok(Vec<u8>)` with decrypted data if successful, otherwise returns an error. 91 pub fn decrypt_chacha20(data: &[u8], key: &[u8]) -> Result<Vec<u8>, String> { 92 use chacha20::cipher::{KeyIvInit, StreamCipher}; 93 use chacha20::ChaCha20; 94 95 if data.len() < 12 { 96 return Err("Ciphertext too short to contain nonce".to_string()); 97 } 98 99 if key.len() != 32 { 100 return Err("Key must be 32 bytes for ChaCha20".to_string()); 101 } 102 103 let nonce: [u8; 12] = data[..12].try_into().unwrap(); 104 let ciphertext = &data[12..]; 105 106 let key_array: [u8; 32] = key.try_into().map_err(|_| "Invalid key length".to_string())?; 107 108 let mut cipher = ChaCha20::new(&key_array.into(), &nonce.into()); 109 let mut buffer = ciphertext.to_vec(); 110 cipher.apply_keystream(&mut buffer); 111 112 Ok(buffer) 113 }"# 114 } 115 116 fn required_dependencies(&self) -> Vec<(&'static str, &'static str)> { 117 vec![("chacha20", "0.9")] 118 } 119 } 120 121 #[cfg(test)] 122 mod tests { 123 use super::*; 124 125 #[test] 126 fn test_chacha20_encrypt_decrypt() { 127 let encryptor = ChaCha20Encryptor::new("my-secret-key-123"); 128 let plaintext = b"Hello, World!"; 129 130 let encrypted = encryptor.encrypt(plaintext).unwrap(); 131 assert_ne!(encrypted, plaintext); 132 133 let decrypted = encryptor.decrypt(&encrypted).unwrap(); 134 assert_eq!(decrypted, plaintext); 135 } 136 137 #[test] 138 fn test_chacha20_different_keys() { 139 let encryptor1 = ChaCha20Encryptor::new("key1"); 140 let encryptor2 = ChaCha20Encryptor::new("key2"); 141 let plaintext = b"Test data"; 142 143 let encrypted1 = encryptor1.encrypt(plaintext).unwrap(); 144 let encrypted2 = encryptor2.encrypt(plaintext).unwrap(); 145 146 assert_ne!(encrypted1, encrypted2); 147 } 148 149 #[test] 150 fn test_chacha20_empty_data() { 151 let encryptor = ChaCha20Encryptor::new("key"); 152 let empty: &[u8] = &[]; 153 154 let encrypted = encryptor.encrypt(empty).unwrap(); 155 // Encrypted data includes 12-byte nonce 156 assert_eq!(encrypted.len(), 12); 157 158 let decrypted = encryptor.decrypt(&encrypted).unwrap(); 159 assert_eq!(decrypted.len(), 0); 160 } 161 162 #[test] 163 fn test_chacha20_long_data() { 164 let encryptor = ChaCha20Encryptor::new("secret-key"); 165 let plaintext = b"This is a much longer message that tests the stream cipher capabilities"; 166 167 let encrypted = encryptor.encrypt(plaintext).unwrap(); 168 assert_ne!(encrypted, plaintext); 169 // Encrypted data includes 12-byte nonce + ciphertext 170 assert_eq!(encrypted.len(), plaintext.len() + 12); 171 172 let decrypted = encryptor.decrypt(&encrypted).unwrap(); 173 assert_eq!(decrypted, plaintext); 174 } 175 176 #[test] 177 fn test_chacha20_binary_data() { 178 let encryptor = ChaCha20Encryptor::new("key"); 179 let plaintext: Vec<u8> = (0..=255).collect(); 180 181 let encrypted = encryptor.encrypt(&plaintext).unwrap(); 182 assert_ne!(encrypted, plaintext); 183 184 let decrypted = encryptor.decrypt(&encrypted).unwrap(); 185 assert_eq!(decrypted, plaintext); 186 } 187 }