use crate::crypto::cipher::{aes, tdes, tdes_2k, tdes_3k, Cipher}; use crate::crypto::cipher_type::CipherType; use crate::crypto::cipher_type::CipherType::*; use crate::error::Result; use simple_error::simple_error; #[derive(Debug, Clone)] pub struct CipherKey { /// Key as Array pub key: Box<[u8]>, //TODO: Decide if this should be pub /// CipherType of Key #[allow(dead_code)] pub cipher: CipherType, /// KeyVersion of Key #[allow(dead_code)] pub key_version: u8, } impl CipherKey { pub fn new(key: &[u8], cipher: CipherType, key_version: u8) -> Result { if cipher == AES && key_version < 0x10 { return Err(simple_error!("KeyVersion is to low for AES Key (Minimum = 0x10)").into()); } if !check_key(key, cipher.clone()) { return Err(simple_error!("Key is not valid for CipherType").into()); } let mut key: Box<[u8]> = Box::from(key); if cipher == TDES || cipher == TDES2K || cipher == TDES3K { key = set_key_version(key.as_ref(), key_version); } Ok(CipherKey { cipher, key_version, key, }) } pub fn new_from_str(key: &str, cipher: CipherType, key_version: u8) -> Result { CipherKey::new(&*hex::decode(key)?, cipher, key_version) } pub fn new_empty(cipher: CipherType) -> Result { Ok(CipherKey { key: generate_empty_key(cipher.clone()), key_version: if cipher == AES { 0x10u8 } else { 0x00u8 }, cipher, }) } } /// Generate Empty Key for CipherType pub fn generate_empty_key(cipher: CipherType) -> Box<[u8]> { let size = get_key_size(cipher); vec![0u8; size].into_boxed_slice() } /// Get KeySize for CipherType pub fn get_key_size(cipher: CipherType) -> usize { match cipher { TDES => tdes::Tdes::KEY_SIZE, TDES2K => tdes_2k::Tdes2k::KEY_SIZE, TDES3K => tdes_3k::Tdes3k::KEY_SIZE, AES => aes::AES::KEY_SIZE, } } /// Check Key Slice pub fn check_key(key: &[u8], cipher: CipherType) -> bool { if key.len() != get_key_size(cipher) { false } else { true } } /// Set Key Version for DES/TDES Keys /// KeyVersion is stored in the LSBits of the first 8 Bytes /// Parity Bits are not used from DESFire Cars pub fn set_key_version(key: &[u8], version: u8) -> Box<[u8]> { let pow2 = [ 0x01u8, 0x02u8, 0x04u8, 0x08u8, 0x10u8, 0x20u8, 0x40u8, 0x80u8, ]; let mut new_key = key.to_vec(); for i in 0..8 { if (version & pow2[i]) > 0 { new_key[i] = (new_key[5] | 0x01u8) as u8; } else { new_key[i] = (new_key[5] & 0x7fu8) as u8; } } new_key.into_boxed_slice() }