use crate::error::ChallengeResponseError;
use crate::sec::{crc16, CRC_RESIDUAL_OK};
use aes::cipher::{Block, BlockCipherDecrypt, KeyInit};
use aes::Aes128;
use rand::{Rng, RngExt};
use std;
#[repr(C)]
#[repr(packed)]
#[derive(Default)]
pub struct Otp {
pub uid: [u8; 6],
pub use_counter: u16,
pub timestamp: [u8; 3],
pub session_counter: u8,
pub random_number: u16,
pub crc: u16,
}
#[derive(Debug)]
pub struct Aes128Key(pub [u8; 16]);
impl Drop for Aes128Key {
fn drop(&mut self) {
for i in self.0.iter_mut() {
*i = 0;
}
}
}
impl Aes128Key {
pub fn from_slice(s: &[u8]) -> Self {
let mut key = Aes128Key([0; 16]);
(&mut key.0).clone_from_slice(s);
key
}
pub fn generate<R: Rng>(mut rng: R) -> Self {
let mut key = Aes128Key([0; 16]);
for i in key.0.iter_mut() {
*i = rng.random()
}
key
}
}
#[derive(Debug)]
pub struct Aes128Block {
pub block: Block<Aes128>,
}
impl Drop for Aes128Block {
fn drop(&mut self) {
for i in self.block.iter_mut() {
*i = 0;
}
}
}
impl std::ops::Deref for Aes128Block {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.block
}
}
impl Aes128Block {
pub fn check(&self, key: &Aes128Key, challenge: &[u8]) -> Result<Otp, ChallengeResponseError> {
let aes_dec = Aes128::new(&key.0.into());
let mut tmp = Otp::default();
{
let tmp_slice = unsafe { std::slice::from_raw_parts_mut(&mut tmp as *mut Otp as *mut u8, 16) };
let mut block_copy = self.block.clone();
aes_dec.decrypt_block(&mut block_copy);
tmp_slice.copy_from_slice(&block_copy);
if crc16(tmp_slice) != CRC_RESIDUAL_OK {
return Err(ChallengeResponseError::WrongCRC);
}
}
for i in 0..6 {
tmp.uid[i] ^= challenge[i]
}
Ok(tmp)
}
}