mirror of
https://gitlab.com/fabinfra/fabaccess/nfc_rs.git
synced 2025-03-13 15:21:43 +01:00
95 lines
2.6 KiB
Rust
95 lines
2.6 KiB
Rust
|
use crate::crypto::cipher_type::CipherType;
|
||
|
use crate::crypto::cipher_type::CipherType::*;
|
||
|
use crate::crypto::cipher::{aes, tdes, tdes_2k, tdes_3k};
|
||
|
use crate::error::Error;
|
||
|
use crate::error::Result;
|
||
|
|
||
|
use simple_error::simple_error;
|
||
|
|
||
|
#[derive(Debug, Clone)]
|
||
|
struct CipherKey {
|
||
|
/// Key as Array
|
||
|
key: Box<[u8]>,
|
||
|
|
||
|
/// CipherType of Key
|
||
|
cipher: CipherType,
|
||
|
|
||
|
/// KeyVersion of Key
|
||
|
key_version: u8
|
||
|
}
|
||
|
|
||
|
impl CipherKey {
|
||
|
pub fn new(key: &[u8], cipher: CipherType, key_version: u8) -> Result<CipherKey> {
|
||
|
if cipher == AES && key_version < 0x10 {
|
||
|
return Err(Error::Boxed(Box::new(simple_error!("KeyVersion is to low for AES Key (Minimum = 0x10)"))))
|
||
|
}
|
||
|
|
||
|
if !check_key(key, cipher.clone()) {
|
||
|
return Err(Error::Boxed(Box::new(simple_error!("Key is not valid for CipherType"))))
|
||
|
}
|
||
|
|
||
|
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> {
|
||
|
CipherKey::new(&*hex::decode(key)?, cipher, key_version)
|
||
|
}
|
||
|
|
||
|
pub fn new_empty(cipher: CipherType) -> Result<CipherKey> {
|
||
|
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::KEY_LEN,
|
||
|
TDES2K => tdes_2k::KEY_LEN,
|
||
|
TDES3K => tdes_3k::KEY_LEN,
|
||
|
AES => aes::KEY_LEN
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// 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()
|
||
|
}
|