mirror of
https://gitlab.com/fabinfra/fabaccess/nfc_rs.git
synced 2025-03-12 06:41:46 +01:00
added basic desfire support
This commit is contained in:
parent
8c112d519d
commit
ad3437c263
41
src/desfire/apduinstructions.rs
Normal file
41
src/desfire/apduinstructions.rs
Normal file
@ -0,0 +1,41 @@
|
||||
#[repr(u8)]
|
||||
pub enum APDUInstructions {
|
||||
AUTHENTICATE_ISO = 0x1A,
|
||||
AUTHENTICATE_AES = 0xAA,
|
||||
CHANGE_KEY_SETTINGS = 0x54,
|
||||
SET_CONFIGURATION = 0x5C,
|
||||
CHANGE_KEY = 0xC4,
|
||||
GET_KEY_VERSION = 0x64,
|
||||
CREATE_APPLICATION = 0xCA,
|
||||
DELETE_APPLICATION = 0xDA,
|
||||
GET_APPLICATION_IDS = 0x6A,
|
||||
FREE_MEMORY = 0x6E,
|
||||
GET_DF_NAMES = 0x6D,
|
||||
GET_KEY_SETTINGS = 0x45,
|
||||
SELECT_APPLICATION = 0x5A,
|
||||
FORMAT_PICC = 0xFC,
|
||||
GET_VERSION = 0x60,
|
||||
GET_CARD_UID = 0x51,
|
||||
GET_FILE_IDS = 0x6F,
|
||||
GET_FILE_SETTINGS = 0xF5,
|
||||
CHANGE_FILE_SETTINGS = 0x5F,
|
||||
CREATE_STDDATAFILE = 0xCD,
|
||||
CREATE_BACKUPDATAFILE = 0xCB,
|
||||
CREATE_VALUE_FILE = 0xCC,
|
||||
CREATE_LINEAR_RECORD_FILE = 0xC1,
|
||||
CREATE_CYCLIC_RECORD_FILE = 0xC0,
|
||||
DELETE_FILE = 0xDF,
|
||||
GET_ISO_FILE_IDS = 0x61,
|
||||
READ_DATA = 0xBD,
|
||||
WRITE_DATA = 0x3D,
|
||||
GET_VALUE = 0x6C,
|
||||
CREDIT = 0x0C,
|
||||
DEBIT = 0xDC,
|
||||
LIMITED_CREDIT = 0x1C,
|
||||
WRITE_RECORD = 0x3B,
|
||||
READ_RECORDS = 0xBB,
|
||||
CLEAR_RECORD_FILE = 0xEB,
|
||||
COMMIT_TRANSACTION = 0xC7,
|
||||
ABORT_TRANSACTION = 0xA7,
|
||||
CONTINUE = 0xAF,
|
||||
}
|
68
src/desfire/apdustatuscodes.rs
Normal file
68
src/desfire/apdustatuscodes.rs
Normal file
@ -0,0 +1,68 @@
|
||||
#[repr(u16)]
|
||||
pub enum APDUStatusCodes {
|
||||
/// Successful operation
|
||||
OPERATION_OK = 0x9000,
|
||||
|
||||
/// No changes done to backup files, CommitTransaction / AbortTransaction not necessary
|
||||
NO_CHANGES = 0x900C,
|
||||
|
||||
/// Insufficient NV-Memory to complete command
|
||||
OUT_OF_EEPROM_ERROR = 0x900E,
|
||||
|
||||
/// Command code not supported
|
||||
ILLEGAL_COMMAND_CODE = 0x901C,
|
||||
|
||||
/// CRC or MAC does not match data Padding bytes not valid
|
||||
INTEGRITY_ERROR = 0x901E,
|
||||
|
||||
/// Invalid key number specified
|
||||
NO_SUCH_KEY = 0x9040,
|
||||
|
||||
/// Invalid key number specified
|
||||
LENGTH_ERROR = 0x907E,
|
||||
|
||||
/// Current configuration / status does not allow the requested command
|
||||
PERMISSION_DENIED = 0x909D,
|
||||
|
||||
/// Value of the parameter(s) invalid
|
||||
PARAMETER_ERROR = 0x909E,
|
||||
|
||||
/// Requested AID not present on PICC
|
||||
APPLICATION_NOT_FOUND = 0x90A0,
|
||||
|
||||
/// Unrecoverable error within application, application will be disabled
|
||||
APPL_INTEGRITY_ERROR = 0x90A1,
|
||||
|
||||
/// Current authentication status does not allow the requested command
|
||||
AUTHENTICATION_ERROR = 0x90AE,
|
||||
|
||||
/// Additional data frame is expected to be sent
|
||||
ADDITIONAL_FRAME = 0x90AF,
|
||||
|
||||
/// Attempt to read/write data from/to beyond the file\'s/record\'s limits. Attempt to exceed the limits of a value file.
|
||||
BOUNDARY_ERROR = 0x90BE,
|
||||
|
||||
/// Unrecoverable error within PICC, PICC will be disabled
|
||||
PICC_INTEGRITY_ERROR = 0x90C1,
|
||||
|
||||
/// Previous Command was not fully completed Not all Frames were requested or provided by the PCD
|
||||
COMMAND_ABORTED = 0x90CA,
|
||||
|
||||
/// PICC was disabled by an unrecoverable error
|
||||
PICC_DISABLED_ERROR = 0x90CD,
|
||||
|
||||
/// Number of Applications limited to 28, no additional CreateApplication possible
|
||||
COUNT_ERROR = 0x90CE,
|
||||
|
||||
/// Creation of file/application failed because file/application with same number already exists
|
||||
DUPLICATE_ERROR = 0x90DE,
|
||||
|
||||
/// Could not complete NV-write operation due to loss of power, internal backup/rollback mechanism activated
|
||||
EEPROM_ERROR = 0x90EE,
|
||||
|
||||
/// Specified file number does not exist
|
||||
FILE_NOT_FOUND = 0x90F0,
|
||||
|
||||
/// Unrecoverable error within file, file will be disabled
|
||||
FILE_INTEGRITY_ERROR = 0x90F1,
|
||||
}
|
388
src/desfire/desfire.rs
Normal file
388
src/desfire/desfire.rs
Normal file
@ -0,0 +1,388 @@
|
||||
use crate::{Card, error};
|
||||
use crate::iso7816_4::apducommand::{APDUCommand, IsoCase};
|
||||
use crate::desfire::apduinstructions::APDUInstructions;
|
||||
use crate::crypto::cipher::tdes::Tdes;
|
||||
use crate::crypto::cipher::aes::AES;
|
||||
use crate::crypto::cipher::Cipher;
|
||||
use crate::crypto::util;
|
||||
use crate::error::{Result, Error};
|
||||
use crate::error::Error::{InvalidApplicationID, InvalidKeyID, InvalidFileID};
|
||||
use crate::crypto::util::expand_to_blocksize;
|
||||
use crate::desfire::FileCommunication;
|
||||
use crate::iso7816_4::apduresponse::APDUResponse;
|
||||
|
||||
pub struct Desfire {
|
||||
card: Box<dyn Card>,
|
||||
session_key: Vec<u8>,
|
||||
cbc_iv: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Desfire {
|
||||
// Desfire commands
|
||||
|
||||
/// <summary>
|
||||
/// Select Application by ApplicationID (AID)
|
||||
/// </summary>
|
||||
/// <param name="aid">3 Byte AID</param>
|
||||
pub fn select_application(&self, aid: u32) -> Result<()> {
|
||||
if aid > 0xFFFFFF {
|
||||
return Err(InvalidApplicationID);
|
||||
}
|
||||
|
||||
let cmd_select_app = APDUCommand {
|
||||
case: IsoCase::Case4Short,
|
||||
cla: 0x90,
|
||||
ins: APDUInstructions::SELECT_APPLICATION as u8,
|
||||
data: Option::from(aid.to_le_bytes()[..3].to_vec()), //FIXME: Which byteorder?
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response = self.card.transmit(cmd_select_app).unwrap();
|
||||
|
||||
response.check().map_err(|e| e)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Authenticate to PICC, with ISO Authenticate for DES Key
|
||||
/// </summary>
|
||||
/// <param name="key_id">0x01 - 0x0D</param>
|
||||
/// <param name="key">Array of 8/16 Bytes</param>
|
||||
/// <param name="rndA">!!! WARNING For Testing only !!!</param>
|
||||
pub fn authenticate_iso_des(&mut self, key_id: u8, key: &[u8], rnd_a: Option<[u8; 8]>) -> Result<()> {
|
||||
if key_id > 0x0E {
|
||||
return Err(InvalidKeyID);
|
||||
}
|
||||
|
||||
let cmd_challenge_request = APDUCommand {
|
||||
case: IsoCase::Case4Short,
|
||||
cla: 0x90,
|
||||
ins: APDUInstructions::AUTHENTICATE_ISO as u8,
|
||||
data: Option::from(vec!(key_id)),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response = self.card.transmit(cmd_challenge_request).unwrap();
|
||||
|
||||
match response.check() {
|
||||
Ok(_) => {}
|
||||
Err(e) => { return Err(e); }
|
||||
}
|
||||
|
||||
let rnd_b_enc = response.body.as_slice();
|
||||
|
||||
let mut rnd_b = Tdes::decrypt(rnd_b_enc, key, vec![0 as u8; 8].as_slice()).unwrap();
|
||||
|
||||
rnd_b.rotate_left(1);
|
||||
|
||||
let rnd_b_rl = rnd_b.as_slice();
|
||||
|
||||
let rnd_a = match rnd_a {
|
||||
None => { rand::random() }
|
||||
Some(i) => { i }
|
||||
};
|
||||
|
||||
let rnd_ab = [&rnd_a, rnd_b_rl].concat();
|
||||
|
||||
let rnd_ab_enc = Tdes::encrypt(rnd_ab.as_slice(), key, rnd_b_enc).unwrap();
|
||||
|
||||
let cmd_challenge_response = APDUCommand {
|
||||
case: IsoCase::Case4Short,
|
||||
cla: 0x90,
|
||||
ins: APDUInstructions::CONTINUE as u8,
|
||||
data: Some(rnd_ab_enc),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response = self.card.transmit(cmd_challenge_response).unwrap();
|
||||
|
||||
match response.check() {
|
||||
Ok(_) => {}
|
||||
Err(e) => { return Err(e); }
|
||||
}
|
||||
|
||||
let mut rnd_a_rot_from_card = Tdes::decrypt(response.body.as_slice(), key, rnd_b.as_slice()).unwrap();
|
||||
rnd_a_rot_from_card.rotate_right(1);
|
||||
let rnd_a_from_card = rnd_a_rot_from_card.as_slice();
|
||||
|
||||
if rnd_a != rnd_a_from_card {
|
||||
return Err(Error::InvalidPICCChallenge);
|
||||
}
|
||||
|
||||
self.session_key = generate_session_key_des(&rnd_a, rnd_b.as_slice()).unwrap();
|
||||
|
||||
self.cbc_iv = vec![0 as u8; 8];
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Format PICC
|
||||
/// Need Authentication for PICC / Application 0x000000
|
||||
/// </summary>
|
||||
fn format_picc(&self) -> Result<()> {
|
||||
let cmd_format = APDUCommand {
|
||||
case: IsoCase::Case2Short,
|
||||
cla: 0x90,
|
||||
ins: APDUInstructions::FORMAT_PICC as u8,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response = self.card.transmit(cmd_format).unwrap();
|
||||
|
||||
response.check()
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create Application for ApplicationID
|
||||
/// </summary>
|
||||
/// <param name="aid">3 Byte ID</param>
|
||||
fn create_application(&self, aid: u32, keysetting1: u8, keysetting2: u8) -> Result<()> {
|
||||
if aid > 0xFFFFFF {
|
||||
return Err(InvalidApplicationID);
|
||||
}
|
||||
|
||||
let mut data = aid.to_le_bytes()[..3].to_vec();
|
||||
data.push(keysetting1);
|
||||
data.push(keysetting2);
|
||||
let cmd_create_application = APDUCommand {
|
||||
case: IsoCase::Case4Short,
|
||||
cla: 0x90,
|
||||
ins: APDUInstructions::CREATE_APPLICATION as u8,
|
||||
data: Option::from(data), //FIXME: Which byteorder?
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response = self.card.transmit(cmd_create_application).unwrap();
|
||||
|
||||
response.check()
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change AES key, the same as Authenticated
|
||||
/// </summary>
|
||||
/// <param name="key_id">0x01 - 0x0D</param>
|
||||
/// <param name="new_key">Array of 16 Bytes</param>
|
||||
/// <param name="key_version">Version of Key(min. 0x10)</param>
|
||||
fn change_key_aes(&mut self, key_id: u8, new_key: &[u8], key_version: u8) -> Result<()> {
|
||||
if key_id >= 0x0E {
|
||||
return Err(InvalidKeyID);
|
||||
}
|
||||
|
||||
let header = vec![0xC4, key_id];
|
||||
let key_and_version: Vec<u8> = [new_key, &[key_version]].concat();
|
||||
let mut command = vec![];
|
||||
|
||||
command.extend(&header);
|
||||
command.extend(&key_and_version);
|
||||
|
||||
let crc = crate::crypto::crc::crc32::calculate(command.as_slice());
|
||||
|
||||
let mut plaintext: Vec<u8> = vec![];
|
||||
plaintext.extend(key_and_version);
|
||||
plaintext.extend(crc);
|
||||
|
||||
let plaintext_pad = expand_to_blocksize(plaintext.as_mut_slice(), 16)?;
|
||||
|
||||
let cryptogram = AES::encrypt(plaintext_pad, self.session_key.as_slice(), self.cbc_iv.as_slice())?;
|
||||
|
||||
self.cbc_iv = util::extract_last_block(cryptogram.as_slice(), 16)?.to_vec();
|
||||
|
||||
let mut data: Vec<u8> = vec![key_id];
|
||||
data.extend(cryptogram);
|
||||
|
||||
let cmd_change_key = APDUCommand {
|
||||
case: IsoCase::Case4Short,
|
||||
cla: 0x90,
|
||||
ins: APDUInstructions::CHANGE_KEY as u8,
|
||||
data: Option::from(data), //FIXME: Which byteorder?
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response = self.card.transmit(cmd_change_key).unwrap();
|
||||
|
||||
response.check()
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change AES key, other than Authenticated
|
||||
/// </summary>
|
||||
/// <param name="key_id">0x01 - 0x0D</param>
|
||||
/// <param name="new_key">Array of 16 Bytes</param>
|
||||
/// <param name="old_key">Array of 16 Bytes</param>
|
||||
/// <param name="key_version">Version of Key(min. 0x10)</param>
|
||||
fn change_other_key_aes(&mut self, key_id: u8, new_key: &[u8], old_key: &[u8], key_version: u8) -> Result<()> {
|
||||
if key_id >= 0x0E {
|
||||
return Err(InvalidKeyID);
|
||||
}
|
||||
|
||||
let header = vec![0xC4, key_id];
|
||||
|
||||
let key_xor : Vec<u8> = new_key.iter().zip(old_key.iter()).map(|(&x1, &x2)| x1 ^ x2).collect();
|
||||
|
||||
let key_and_version: Vec<u8> = [key_xor, vec![key_version]].concat();
|
||||
let mut command = vec![];
|
||||
|
||||
command.extend(&header);
|
||||
command.extend(&key_and_version);
|
||||
|
||||
let crc = crate::crypto::crc::crc32::calculate(command.as_slice());
|
||||
|
||||
let mut plaintext: Vec<u8> = vec![];
|
||||
plaintext.extend(key_and_version);
|
||||
plaintext.extend(crc);
|
||||
|
||||
let plaintext_pad = expand_to_blocksize(plaintext.as_mut_slice(), 16)?;
|
||||
|
||||
let cryptogram = AES::encrypt(plaintext_pad, self.session_key.as_slice(), self.cbc_iv.as_slice())?;
|
||||
|
||||
self.cbc_iv = util::extract_last_block(cryptogram.as_slice(), 16)?.to_vec();
|
||||
|
||||
let mut data: Vec<u8> = vec![key_id];
|
||||
data.extend(cryptogram);
|
||||
|
||||
let cmd_change_key = APDUCommand {
|
||||
case: IsoCase::Case4Short,
|
||||
cla: 0x90,
|
||||
ins: APDUInstructions::CHANGE_KEY as u8,
|
||||
data: Option::from(data), //FIXME: Which byteorder?
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response = self.card.transmit(cmd_change_key).unwrap();
|
||||
|
||||
response.check()
|
||||
}
|
||||
|
||||
fn create_file_standard(&self, file_id: u8, communication: FileCommunication, access_rights: u16, size: u32) -> Result<()>{
|
||||
if file_id >= 0x20 {
|
||||
return Err(InvalidFileID)
|
||||
}
|
||||
|
||||
let access_rights = access_rights.to_le_bytes().to_vec();
|
||||
let size = size.to_le_bytes()[..3].to_vec();
|
||||
let mut data = vec![file_id, communication as u8];
|
||||
data.extend(&access_rights);
|
||||
data.extend(&size);
|
||||
|
||||
let cmd_create_file_standard = APDUCommand {
|
||||
case: IsoCase::Case4Short,
|
||||
cla: 0x90,
|
||||
ins: APDUInstructions::CREATE_STDDATAFILE as u8,
|
||||
data: Option::from(data),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response = self.card.transmit(cmd_create_file_standard).unwrap();
|
||||
|
||||
response.check()
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write Data to File
|
||||
/// </summary>
|
||||
/// <param name="file_id">ID of File (0x00 - 0x20)</param>
|
||||
/// <param name="offset">Offset for File</param>
|
||||
/// <param name="data">Data to write</param>
|
||||
fn write_data(&self, file_id: u8, offset: u32, data: &[u8]) -> Result<()> {
|
||||
if file_id >= 0x20 {
|
||||
return Err(InvalidFileID)
|
||||
}
|
||||
|
||||
const MAX_BYTES_PER_TRANSACTION: usize = 47;
|
||||
let mut bytes_writen: usize = 0;
|
||||
let length: usize = data.len();
|
||||
|
||||
let mut ret: Result<()> = Err(error::Error::Simple(simple_error::simple_error!("Error while writing data to card"))); //TODO: Replace with better error
|
||||
|
||||
while bytes_writen != data.len() {
|
||||
let bytes_towrite = match length - bytes_writen < MAX_BYTES_PER_TRANSACTION {
|
||||
true => { length - bytes_writen }
|
||||
false => { MAX_BYTES_PER_TRANSACTION }
|
||||
};
|
||||
|
||||
let mut write_buffer = vec![file_id];
|
||||
write_buffer.append(&mut offset.to_le_bytes()[..3].to_vec());
|
||||
write_buffer.append(&mut bytes_towrite.to_le_bytes()[..3].to_vec());
|
||||
write_buffer.append(&mut data[bytes_writen..bytes_writen + bytes_towrite].to_vec());
|
||||
bytes_writen += bytes_towrite;
|
||||
|
||||
let cmd_write_data = APDUCommand {
|
||||
case: IsoCase::Case4Short,
|
||||
cla: 0x90,
|
||||
ins: APDUInstructions::WRITE_DATA as u8,
|
||||
data: Option::from(write_buffer),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response = self.card.transmit(cmd_write_data).unwrap();
|
||||
|
||||
ret = response.check();
|
||||
};
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read Data from File
|
||||
/// </summary>
|
||||
/// <param name="file_id">ID of File (0x00 - 0x20)</param>
|
||||
/// <param name="offset">Offset for File</param>
|
||||
/// <param name="length">Lenght of Data</param>
|
||||
fn read_data(&self, file_id: u8, offset: u32, length: usize) -> Result<Vec<u8>> {
|
||||
if file_id >= 0x20 {
|
||||
return Err(InvalidFileID)
|
||||
}
|
||||
|
||||
const MAX_BYTES_PER_TRANSACTION: usize = 47;
|
||||
let mut bytes_read: usize = 0;
|
||||
|
||||
let mut read_buffer: Vec<u8> = vec![];
|
||||
|
||||
while bytes_read != length {
|
||||
let bytes_toread = match length - bytes_read < MAX_BYTES_PER_TRANSACTION {
|
||||
true => { length - bytes_read }
|
||||
false => { MAX_BYTES_PER_TRANSACTION }
|
||||
};
|
||||
|
||||
let mut send_buffer = vec![file_id];
|
||||
send_buffer.append(&mut offset.to_le_bytes()[..3].to_vec());
|
||||
send_buffer.append(&mut bytes_toread.to_le_bytes()[..3].to_vec());
|
||||
bytes_read += bytes_toread;
|
||||
|
||||
let cmd_read_data = APDUCommand {
|
||||
case: IsoCase::Case4Short,
|
||||
cla: 0x90,
|
||||
ins: APDUInstructions::READ_DATA as u8,
|
||||
data: Option::from(send_buffer),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response = self.card.transmit(cmd_read_data).unwrap();
|
||||
|
||||
response.check().or_else(|e| return Err(e));
|
||||
|
||||
read_buffer.append(&mut response.body()[..bytes_toread].to_vec());
|
||||
};
|
||||
|
||||
return Ok(read_buffer)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Generates SessionKey for DES Authentification
|
||||
/// </summary>
|
||||
/// <returns>8Byte SessionKey</returns>
|
||||
fn generate_session_key_des(rnd_a: &[u8], rnd_b: &[u8]) -> Option<Vec<u8>> {
|
||||
Some([&rnd_a[..4], &rnd_b[5..8]].concat())
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates SessionKey for AES Authentification
|
||||
/// </summary>
|
||||
/// <returns>16Byte SessionKey</returns>
|
||||
fn generate_session_key_aes(rnd_a: &[u8], rnd_b: &[u8]) -> Option<Vec<u8>> {
|
||||
//FIXME: Check math
|
||||
Some([&rnd_a[..4], &rnd_b[5..8], &rnd_a[5..8], &rnd_b[..4]].concat())
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
/// <summary>
|
||||
/// hold the Access Rights for changing application keys (Change Key command)
|
||||
/// </summary>
|
||||
#[repr(u8)]
|
||||
pub enum ChangeApplicationKey {
|
||||
/// <summary>
|
||||
/// Application master key authentication is necessary to change any key (default)
|
||||
/// </summary>
|
||||
MASTERKEY = 0x00,
|
||||
/// <summary>
|
||||
/// Authentication with the key to be changed (same Key#) is necessary to change a key
|
||||
/// </summary>
|
||||
SAMEKEY = 0x0E,
|
||||
/// <summary>
|
||||
/// All keys (except application master key, see Bit 0) within this application are frozen
|
||||
/// </summary>
|
||||
ALLKEYS = 0x0F,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// codes whether the application master key is changeable
|
||||
/// </summary>
|
||||
#[repr(u8)]
|
||||
pub enum ChangeMasterKey {
|
||||
/// <summary>
|
||||
/// Application master key is not changeable anymore (frozen)
|
||||
/// </summary>
|
||||
FROZEN = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// Application master key is changeable (authentication with the current application master key necessary, default)
|
||||
/// </summary>
|
||||
CHANGEABLE = 0x01,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// codes whether a change of the application master key settings is allowed
|
||||
/// </summary>
|
||||
#[repr(u8)]
|
||||
pub enum ChangeMasterKeySettings {
|
||||
|
||||
/// <summary>
|
||||
/// configuration not changeable anymore (frozen)
|
||||
/// </summary>
|
||||
FROZEN = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// this configuration is changeable if authenticated with the application master key (default)
|
||||
/// </summary>
|
||||
WITHMASTERKEY = 0x08
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// codes whether application master key authentication is needed before “Create File” / “Delete File”
|
||||
/// </summary>
|
||||
#[repr(u8)]
|
||||
pub enum CreateDeleteFile {
|
||||
/// <summary>
|
||||
/// “Create File”/ “Delete File”is permitted only with application master key authentication
|
||||
/// </summary>
|
||||
ONLYMASTERKEY = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// “Create File”/ “Delete File”is permitted also without application master key authentication (default)
|
||||
/// </summary>
|
||||
NOKEY = 0x04,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Crypto method of the application
|
||||
/// </summary>
|
||||
#[repr(u8)]
|
||||
pub enum CryptoOperationsType {
|
||||
TDES = 0x00,
|
||||
TKTDES = 0x40,
|
||||
AES = 0x80,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum FileAccessRights {
|
||||
FREE = 0x0E,
|
||||
NEVER = 0x0F
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum FileCommunication {
|
||||
/// <summary>
|
||||
/// "Plain communication"
|
||||
/// </summary>
|
||||
PLAIN = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// Plain communication secured by DES/3DES MACing
|
||||
/// </summary>
|
||||
MAC = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// Fully DES/3DES enciphered communication
|
||||
/// </summary>
|
||||
ENCRYPT = 0x03
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// codes whether application master key authentication is needed for file directory access
|
||||
/// </summary>
|
||||
#[repr(u8)]
|
||||
pub enum FileDirectoryAccess {
|
||||
/// <summary>
|
||||
/// Successful application master key authentication is required for executing the “Get FID List”, “Get File Settings”and “Get Key Settings”commands
|
||||
/// </summary>
|
||||
ONLYMASTERKEY = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// “Get FID List”, “Get File Settings” and “Get Key Settings” commands succeed independentlyof a preceding application master key authentication (default)
|
||||
/// </summary>
|
||||
NOKEY = 0x02,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates use of 2 byte ISO/IEC 7816-4 File Identifies for files within the Application
|
||||
/// </summary>
|
||||
#[repr(u8)]
|
||||
pub enum FileIdentifies {
|
||||
NOTUSED = 0x00,
|
||||
USED = 0x20
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum FileTypes {
|
||||
/// <summary>
|
||||
/// Standard Data File
|
||||
/// </summary>
|
||||
STANDARD = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// Backup Data Files
|
||||
/// </summary>
|
||||
BACKUP = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// Value Files with Backup
|
||||
/// </summary>
|
||||
VALUE = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// Linear Record Files with Backup
|
||||
/// </summary>
|
||||
LINEARRECORD = 0x03,
|
||||
|
||||
/// <summary>
|
||||
/// Cyclic Record Files with Backup
|
||||
/// </summary>
|
||||
CYCLICRECORD = 0x04
|
||||
}
|
||||
|
||||
mod apduinstructions;
|
||||
mod apdustatuscodes;
|
||||
mod desfire;
|
Loading…
x
Reference in New Issue
Block a user