use des::cipher::{BlockEncrypt, KeyInit};
use des::Des;
use rand::Rng;
pub struct VncAuth {
password: Option<String>,
}
impl VncAuth {
pub fn new(password: Option<String>) -> Self {
Self { password }
}
#[allow(clippy::unused_self)] pub fn generate_challenge(&self) -> [u8; 16] {
let mut rng = rand::thread_rng();
let mut challenge = [0u8; 16];
rng.fill(&mut challenge);
challenge
}
pub fn verify_response(&self, response: &[u8], challenge: &[u8; 16]) -> bool {
if let Some(ref password) = self.password {
let expected = self.encrypt_challenge(challenge, password);
response == expected.as_slice()
} else {
false
}
}
#[allow(clippy::unused_self)] fn encrypt_challenge(&self, challenge: &[u8; 16], password: &str) -> Vec<u8> {
let mut key = [0u8; 8];
let pw_bytes = password.as_bytes();
for (i, &byte) in pw_bytes.iter().take(8).enumerate() {
key[i] = reverse_bits(byte);
}
let cipher = Des::new_from_slice(&key).expect("8-byte key");
let mut encrypted = vec![0u8; 16];
let mut block1_bytes = [0u8; 8];
block1_bytes.copy_from_slice(&challenge[0..8]);
let mut block1 = block1_bytes.into();
cipher.encrypt_block(&mut block1);
encrypted[0..8].copy_from_slice(&block1);
let mut block2_bytes = [0u8; 8];
block2_bytes.copy_from_slice(&challenge[8..16]);
let mut block2 = block2_bytes.into();
cipher.encrypt_block(&mut block2);
encrypted[8..16].copy_from_slice(&block2);
encrypted
}
}
fn reverse_bits(byte: u8) -> u8 {
let mut result = 0u8;
for i in 0..8 {
if byte & (1 << i) != 0 {
result |= 1 << (7 - i);
}
}
result
}