This commit is contained in:
Kai Jan Kriegel 2022-01-10 21:30:36 +01:00
parent d76554741b
commit 26277f067b
6 changed files with 80 additions and 77 deletions

View File

@ -2,7 +2,7 @@
name = "desfire"
version = "0.1.0"
authors = ["Kai Jan Kriegel <kai@kjkriegel.de>"]
edition = "2018"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "Library for interfacing with Mifare Desfire cards."
repository = "https://gitlab.com/fabinfra/fabaccess/nfc_rs"

View File

@ -12,9 +12,11 @@ pub struct CipherKey {
pub key: Box<[u8]>, //TODO: Decide if this should be pub
/// CipherType of Key
#[allow(dead_code)]
cipher: CipherType,
/// KeyVersion of Key
#[allow(dead_code)]
key_version: u8,
}

View File

@ -1,4 +1,4 @@
use crate::error::{Error, Result};
use crate::error::Result;
use simple_error::simple_error;
/// Extracts the the last `n` bytes of a slice. n being the blocksize.

View File

@ -1,41 +1,42 @@
#[allow(dead_code)]
#[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,
AuthenticateIso = 0x1A,
AuthenticateAes = 0xAA,
ChangeKeySettings = 0x54,
SetConfiguration = 0x5C,
ChangeKey = 0xC4,
GetKeyVersion = 0x64,
CreateApplication = 0xCA,
DeleteApplication = 0xDA,
GetApplicationIds = 0x6A,
FreeMemory = 0x6E,
GetDfNames = 0x6D,
GetKeySettings = 0x45,
SelectApplication = 0x5A,
FormatPicc = 0xFC,
GetVersion = 0x60,
GetCardUid = 0x51,
GetFileIds = 0x6F,
GetFileSettings = 0xF5,
ChangeFileSettings = 0x5F,
CreateStddatafile = 0xCD,
CreateBackupdatafile = 0xCB,
CreateValueFile = 0xCC,
CreateLinearRecordFile = 0xC1,
CreateCyclicRecordFile = 0xC0,
DeleteFile = 0xDF,
GetIsoFileIds = 0x61,
ReadData = 0xBD,
WriteData = 0x3D,
GetValue = 0x6C,
Credit = 0x0C,
Debit = 0xDC,
LimitedCredit = 0x1C,
WriteRecord = 0x3B,
ReadRecords = 0xBB,
ClearRecordFile = 0xEB,
CommitTransaction = 0xC7,
AbortTransaction = 0xA7,
Continue = 0xAF,
}

View File

@ -1,68 +1,69 @@
#[allow(dead_code)]
#[repr(u16)]
pub enum APDUStatusCodes {
/// Successful operation
OPERATION_OK = 0x9000,
OperationOk = 0x9000,
/// No changes done to backup files, CommitTransaction / AbortTransaction not necessary
NO_CHANGES = 0x900C,
NoChanges = 0x900C,
/// Insufficient NV-Memory to complete command
OUT_OF_EEPROM_ERROR = 0x900E,
OutOfEepromError = 0x900E,
/// Command code not supported
ILLEGAL_COMMAND_CODE = 0x901C,
IllegalCommandCode = 0x901C,
/// CRC or MAC does not match data Padding bytes not valid
INTEGRITY_ERROR = 0x901E,
IntegrityError = 0x901E,
/// Invalid key number specified
NO_SUCH_KEY = 0x9040,
NoSuchKey = 0x9040,
/// Invalid key number specified
LENGTH_ERROR = 0x907E,
LengthError = 0x907E,
/// Current configuration / status does not allow the requested command
PERMISSION_DENIED = 0x909D,
PermissionDenied = 0x909D,
/// Value of the parameter(s) invalid
PARAMETER_ERROR = 0x909E,
ParameterError = 0x909E,
/// Requested AID not present on PICC
APPLICATION_NOT_FOUND = 0x90A0,
ApplicationNotFound = 0x90A0,
/// Unrecoverable error within application, application will be disabled
APPL_INTEGRITY_ERROR = 0x90A1,
ApplIntegrityError = 0x90A1,
/// Current authentication status does not allow the requested command
AUTHENTICATION_ERROR = 0x90AE,
AuthenticationError = 0x90AE,
/// Additional data frame is expected to be sent
ADDITIONAL_FRAME = 0x90AF,
AdditionalFrame = 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,
BoundaryError = 0x90BE,
/// Unrecoverable error within PICC, PICC will be disabled
PICC_INTEGRITY_ERROR = 0x90C1,
PiccIntegrityError = 0x90C1,
/// Previous Command was not fully completed Not all Frames were requested or provided by the PCD
COMMAND_ABORTED = 0x90CA,
CommandAborted = 0x90CA,
/// PICC was disabled by an unrecoverable error
PICC_DISABLED_ERROR = 0x90CD,
PiccDisabledError = 0x90CD,
/// Number of Applications limited to 28, no additional CreateApplication possible
COUNT_ERROR = 0x90CE,
CountError = 0x90CE,
/// Creation of file/application failed because file/application with same number already exists
DUPLICATE_ERROR = 0x90DE,
DuplicateError = 0x90DE,
/// Could not complete NV-write operation due to loss of power, internal backup/rollback mechanism activated
EEPROM_ERROR = 0x90EE,
EepromError = 0x90EE,
/// Specified file number does not exist
FILE_NOT_FOUND = 0x90F0,
FileNotFound = 0x90F0,
/// Unrecoverable error within file, file will be disabled
FILE_INTEGRITY_ERROR = 0x90F1,
FileIntegrityError = 0x90F1,
}

View File

@ -9,7 +9,6 @@ use crate::error::{Result, Error};
use crate::error::Error::{InvalidApplicationID, InvalidKeyID, InvalidFileID, NumKeys, InvalidKeyVersion};
use crate::crypto::util::expand_to_blocksize;
use crate::desfire::{FileCommunication, ChangeMasterKeySettings, CreateDeleteFile, FileDirectoryAccess, ChangeMasterKey, ChangeApplicationKey, CryptoOperationsType, FileIdentifiers};
use crate::iso7816_4::apduresponse::APDUResponse;
use num_traits::FromPrimitive;
pub struct Desfire {
@ -33,7 +32,7 @@ impl Desfire {
let cmd_select_app = APDUCommand {
case: IsoCase::Case4Short,
cla: 0x90,
ins: APDUInstructions::SELECT_APPLICATION as u8,
ins: APDUInstructions::SelectApplication as u8,
data: Option::from(aid.to_le_bytes()[..3].to_vec()), //FIXME: Which byteorder?
..Default::default()
};
@ -57,7 +56,7 @@ impl Desfire {
let cmd_challenge_request = APDUCommand {
case: IsoCase::Case4Short,
cla: 0x90,
ins: APDUInstructions::AUTHENTICATE_ISO as u8,
ins: APDUInstructions::AuthenticateIso as u8,
data: Option::from(vec!(key_id)),
..Default::default()
};
@ -97,7 +96,7 @@ impl Desfire {
let cmd_challenge_response = APDUCommand {
case: IsoCase::Case4Short,
cla: 0x90,
ins: APDUInstructions::CONTINUE as u8,
ins: APDUInstructions::Continue as u8,
data: Some(rnd_ab_enc.clone()),
..Default::default()
};
@ -144,7 +143,7 @@ impl Desfire {
let cmd_challenge_request = APDUCommand {
case: IsoCase::Case4Short,
cla: 0x90,
ins: APDUInstructions::AUTHENTICATE_AES as u8,
ins: APDUInstructions::AuthenticateAes as u8,
data: Option::from(vec!(key_id)),
..Default::default()
};
@ -162,7 +161,7 @@ impl Desfire {
let rnd_b_enc = rnd_b_response_body.as_slice();
println!("RND_B_ENC: {:x?}", rnd_b_enc);
let mut rnd_b = AES::decrypt(rnd_b_enc, key, vec![0 as u8; 16].as_slice()).unwrap();
let rnd_b = AES::decrypt(rnd_b_enc, key, vec![0 as u8; 16].as_slice()).unwrap();
println!("RND_B: {:x?}", rnd_b);
// auth_iv = rnd_b.clone();
@ -187,7 +186,7 @@ impl Desfire {
let cmd_challenge_response = APDUCommand {
case: IsoCase::Case4Short,
cla: 0x90,
ins: APDUInstructions::CONTINUE as u8,
ins: APDUInstructions::Continue as u8,
data: Some(rnd_ab_enc.clone()),
..Default::default()
};
@ -231,7 +230,7 @@ impl Desfire {
let cmd_format = APDUCommand {
case: IsoCase::Case2Short,
cla: 0x90,
ins: APDUInstructions::FORMAT_PICC as u8,
ins: APDUInstructions::FormatPicc as u8,
..Default::default()
};
@ -255,7 +254,7 @@ impl Desfire {
let cmd_create_application = APDUCommand {
case: IsoCase::Case4Short,
cla: 0x90,
ins: APDUInstructions::CREATE_APPLICATION as u8,
ins: APDUInstructions::CreateApplication as u8,
data: Option::from(data), //FIXME: Which byteorder?
..Default::default()
};
@ -312,7 +311,7 @@ impl Desfire {
let cmd_change_key = APDUCommand {
case: IsoCase::Case4Short,
cla: 0x90,
ins: APDUInstructions::CHANGE_KEY as u8,
ins: APDUInstructions::ChangeKey as u8,
data: Option::from(data), //FIXME: Which byteorder?
..Default::default()
};
@ -381,7 +380,7 @@ impl Desfire {
let cmd_change_key = APDUCommand {
case: IsoCase::Case4Short,
cla: 0x90,
ins: APDUInstructions::CHANGE_KEY as u8,
ins: APDUInstructions::ChangeKey as u8,
data: Option::from(data), //FIXME: Which byteorder?
..Default::default()
};
@ -407,7 +406,7 @@ impl Desfire {
let cmd_create_file_standard = APDUCommand {
case: IsoCase::Case4Short,
cla: 0x90,
ins: APDUInstructions::CREATE_STDDATAFILE as u8,
ins: APDUInstructions::CreateStddatafile as u8,
data: Option::from(data),
..Default::default()
};
@ -455,7 +454,7 @@ impl Desfire {
let cmd_write_data = APDUCommand {
case: IsoCase::Case4Short,
cla: 0x90,
ins: APDUInstructions::WRITE_DATA as u8,
ins: APDUInstructions::WriteData as u8,
data: Option::from(write_buffer),
..Default::default()
};
@ -500,7 +499,7 @@ impl Desfire {
let cmd_read_data = APDUCommand {
case: IsoCase::Case4Short,
cla: 0x90,
ins: APDUInstructions::READ_DATA as u8,
ins: APDUInstructions::ReadData as u8,
data: Option::from(send_buffer),
..Default::default()
};
@ -509,7 +508,7 @@ impl Desfire {
let response = self.card.transmit(cmd_read_data).unwrap();
println!("RESPONSE: {}", response);
response.check().or_else(|e| return Err(e));
response.check().or_else(|e| return Err(e))?;
// println!("RESPONSE_DATA: {:x?}, WITHOUT_CMAC: {:x?}", response.body.as_ref().unwrap(), response.body.as_ref().unwrap()[..bytes_toread].to_vec());
read_buffer.append(&mut response.body.unwrap()[..bytes_toread].to_vec());