use std::fmt;
use super::SecurityMode;
use deku::prelude::*;
use rand::random;
#[derive(Clone, Debug, PartialEq, DekuRead, DekuWrite)]
#[deku(endian = "big")]
pub struct ServerGreeting {
#[deku(assert_eq = "[0u8; 12]")]
unused: [u8; 12],
mode: u32,
challenge: [u8; 16],
salt: [u8; 16],
count: u32,
#[deku(assert_eq = "[0u8; 12]")]
mbz: [u8; 12],
}
impl fmt::Display for ServerGreeting {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Greeting with Mode and Count: {}, {}",
self.mode, self.count
)
}
}
impl ServerGreeting {
pub fn new(modes: &[SecurityMode]) -> Self {
ServerGreeting {
unused: [0; 12],
mode: modes.iter().fold(0u32, |acc, mode| {
acc | <SecurityMode as Into<u32>>::into(*mode)
}),
challenge: Vec::from([0; 16])
.iter()
.map(|_| random())
.collect::<Vec<u8>>()
.try_into()
.unwrap(),
salt: Vec::from([0; 16])
.iter()
.map(|_| random())
.collect::<Vec<u8>>()
.try_into()
.unwrap(),
count: 1024,
mbz: [0; 12],
}
}
pub fn with_count(mut self, count: u32) -> Self {
self.count = count;
self
}
pub fn count(&self) -> u32 {
self.count
}
pub fn has_mode(&self, mode: SecurityMode) -> bool {
let greeting_mode: u32 = self.mode;
let mode_as_number: u32 = mode.into();
match mode {
SecurityMode::Reserved => greeting_mode | mode_as_number == mode_as_number,
_ => greeting_mode & mode_as_number == mode_as_number,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashSet;
const SERVER_GREETING_LENGTH_IN_BYTES: usize = 64;
#[test]
fn create_server_greeting_with_mode_reserved() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Reserved]);
assert_eq!(server_greeting.mode, 0);
}
#[test]
fn read_mode_reserved_in_reserved_greeting() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Reserved]);
assert!(server_greeting.has_mode(SecurityMode::Reserved));
}
#[test]
fn read_mode_reserved_in_non_reserved_greeting_and_fail() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Unauthenticated]);
assert!(!server_greeting.has_mode(SecurityMode::Reserved));
}
#[test]
fn create_server_greeting_with_mode_unauthenticated() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Unauthenticated]);
assert_eq!(server_greeting.mode, 1);
}
#[test]
fn read_mode_unauthenticated() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Unauthenticated]);
assert!(server_greeting.has_mode(SecurityMode::Unauthenticated));
}
#[test]
fn create_server_greeting_with_mode_auth() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Authenticated]);
assert_eq!(server_greeting.mode, 2);
}
#[test]
fn read_mode_auth() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Authenticated]);
assert!(server_greeting.has_mode(SecurityMode::Authenticated));
}
#[test]
fn create_server_greeting_with_mode_encrypted() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Encrypted]);
assert_eq!(server_greeting.mode, 4);
}
#[test]
fn read_mode_encrypted() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Encrypted]);
assert!(server_greeting.has_mode(SecurityMode::Encrypted));
}
#[test]
fn create_server_greeting_with_mode_mixed() {
let server_greeting = ServerGreeting::new(&[SecurityMode::EncryptedControlUnauthTest]);
assert_eq!(server_greeting.mode, 8);
}
#[test]
fn read_mode_mixed() {
let server_greeting = ServerGreeting::new(&[SecurityMode::EncryptedControlUnauthTest]);
assert!(server_greeting.has_mode(SecurityMode::EncryptedControlUnauthTest));
}
#[test]
fn create_server_greeting_with_modes_unauth_and_auth_and_encrypted_and_mixed() {
let server_greeting = ServerGreeting::new(&[
SecurityMode::Unauthenticated,
SecurityMode::Authenticated,
SecurityMode::Encrypted,
SecurityMode::EncryptedControlUnauthTest,
]);
assert_eq!(server_greeting.mode, 15);
}
#[test]
fn read_each_mode_from_unauth_and_auth_and_encrypted_and_mixed() {
let server_greeting = ServerGreeting::new(&[
SecurityMode::Unauthenticated,
SecurityMode::Authenticated,
SecurityMode::Encrypted,
SecurityMode::EncryptedControlUnauthTest,
]);
assert!(server_greeting.has_mode(SecurityMode::Unauthenticated));
assert!(server_greeting.has_mode(SecurityMode::Authenticated));
assert!(server_greeting.has_mode(SecurityMode::Encrypted));
assert!(server_greeting.has_mode(SecurityMode::EncryptedControlUnauthTest));
}
#[test]
fn read_mode_unauth_in_reserved_greeting_and_fail() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Reserved]);
assert!(!server_greeting.has_mode(SecurityMode::Unauthenticated));
}
#[test]
fn read_mode_auth_in_reserved_greeting_and_fail() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Reserved]);
assert!(!server_greeting.has_mode(SecurityMode::Authenticated));
}
#[test]
fn read_mode_encrypted_in_reserved_greeting_and_fail() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Reserved]);
assert!(!server_greeting.has_mode(SecurityMode::Encrypted));
}
#[test]
fn read_mode_mixed_in_reserved_greeting_and_fail() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Reserved]);
assert!(!server_greeting.has_mode(SecurityMode::EncryptedControlUnauthTest));
}
#[test]
fn unused_are_zeros() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Reserved]);
assert!(server_greeting.unused == [0; 12]);
}
#[test]
fn challenge_bytes_are_random() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Reserved]);
let challenge_bytes_unique = server_greeting.challenge.iter().collect::<HashSet<_>>();
assert!(challenge_bytes_unique.len() > 1);
}
#[test]
fn salt_bytes_are_random() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Reserved]);
let challenge_bytes_unique = server_greeting.salt.iter().collect::<HashSet<_>>();
assert!(challenge_bytes_unique.len() > 1);
}
#[test]
fn default_count_is_under_a_valid_range() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Reserved]);
assert!(server_greeting.count.ge(&1024) && server_greeting.count.le(&32768));
}
#[test]
fn use_custom_count_value() {
let count_value = 32769;
let server_greeting =
ServerGreeting::new(&[SecurityMode::Reserved]).with_count(count_value);
assert_eq!(server_greeting.count, count_value);
}
#[test]
fn mbz_are_zeros() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Reserved]);
assert!(server_greeting.mbz == [0; 12]);
}
#[test]
fn serialize_into_correct_length_of_bytes() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Unauthenticated]);
let encoded = server_greeting.to_bytes().unwrap();
assert_eq!(encoded.len(), SERVER_GREETING_LENGTH_IN_BYTES);
}
#[test]
fn deserialize_into_correct_struct() {
let server_greeting = ServerGreeting::new(&[SecurityMode::Unauthenticated]);
let encoded = server_greeting.to_bytes().unwrap();
let (_rest, val) = ServerGreeting::from_bytes((&encoded, 0)).unwrap();
assert_eq!(val, server_greeting);
}
}