mirror of
https://gitlab.com/fabinfra/fabaccess/nfc_rs.git
synced 2025-03-12 23:01:43 +01:00
100 lines
2.7 KiB
Rust
100 lines
2.7 KiB
Rust
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<CipherKey> {
|
|
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> {
|
|
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::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 {
|
|
key.len() == get_key_size(cipher)
|
|
}
|
|
|
|
/// 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()
|
|
}
|