Improved DESFire support and added emulation

- Added DESFire emulator in armsrc/desfiresim.c with all major commands
- Fixed value operations (credit/debit/limited credit) to work correctly in MAC mode
- Removed value operations from EV1D40TransmitMAC array to match real card behavior
- Added auto-detection fallback for MAC mode compatibility with older cards
- Added emulator with 28 applications (kinda EV1 standard)
- Enhanced test suite with comprehensive value operation and multi-app testing
- Added emulator commands: sim, ereset, eload, eview, test
- Consolidated user documentation in doc/desfire.md with emulation guide
- Value file operations work on both emulator and real DESFire cards
- Proper limit checking and transaction commitment for value operations
- Support for all file types: Standard, Backup, Value, Linear/Cyclic Record
- Authentication with DES, 2TDEA/3DES, 3TDEA, and AES keys
- ISO file ID support and access rights enforcement
This commit is contained in:
Mistial Developer 2025-07-18 22:19:46 -04:00
commit 4bfdaf3376
No known key found for this signature in database
15 changed files with 4738 additions and 71 deletions

View file

@ -37,7 +37,7 @@ APP_CFLAGS = $(PLATFORM_DEFS) \
SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c lfadc.c SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c lfadc.c
SRC_HF = hfops.c SRC_HF = hfops.c
SRC_ISO15693 = iso15693.c iso15693tools.c SRC_ISO15693 = iso15693.c iso15693tools.c
SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c sam_common.c sam_mfc.c sam_seos.c SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c sam_common.c sam_mfc.c sam_seos.c desfiresim.c
#UNUSED: mifaresniff.c #UNUSED: mifaresniff.c
SRC_ISO14443b = iso14443b.c SRC_ISO14443b = iso14443b.c

View file

@ -55,6 +55,7 @@
#include "mifarecmd.h" #include "mifarecmd.h"
#include "mifaredesfire.h" #include "mifaredesfire.h"
#include "mifaresim.h" #include "mifaresim.h"
#include "desfiresim.h"
#include "emvsim.h" #include "emvsim.h"
#include "pcf7931.h" #include "pcf7931.h"
#include "Standalone/standalone.h" #include "Standalone/standalone.h"
@ -2130,6 +2131,55 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareSendCommand(packet->data.asBytes); MifareSendCommand(packet->data.asBytes);
break; break;
} }
case CMD_HF_DESFIRE_SIM_RESET: {
// Reset DESFire emulator to factory-fresh state
DesfireSimInit();
reply_ng(CMD_HF_DESFIRE_SIM_RESET, PM3_SUCCESS, NULL, 0);
break;
}
case CMD_HF_DESFIRE_EML_MEMCLR: {
DesfireEmlClear();
reply_ng(CMD_HF_DESFIRE_EML_MEMCLR, PM3_SUCCESS, NULL, 0);
break;
}
case CMD_HF_DESFIRE_EML_MEMSET: {
struct p {
uint32_t offset;
uint32_t length;
uint8_t data[PM3_CMD_DATA_SIZE - 8];
} *payload = (struct p *) packet->data.asBytes;
if (payload->length > PM3_CMD_DATA_SIZE - 8) {
reply_ng(CMD_HF_DESFIRE_EML_MEMSET, PM3_EMALLOC, NULL, 0);
return;
}
int res = DesfireEmlSet(payload->data, payload->offset, payload->length);
reply_ng(CMD_HF_DESFIRE_EML_MEMSET, res, NULL, 0);
break;
}
case CMD_HF_DESFIRE_EML_MEMGET: {
struct p {
uint32_t offset;
uint32_t length;
} *payload = (struct p *) packet->data.asBytes;
if (payload->length > PM3_CMD_DATA_SIZE) {
reply_ng(CMD_HF_DESFIRE_EML_MEMGET, PM3_EMALLOC, NULL, 0);
return;
}
uint8_t *buf = BigBuf_calloc(payload->length);
if (buf == NULL) {
reply_ng(CMD_HF_DESFIRE_EML_MEMGET, PM3_EMALLOC, NULL, 0);
return;
}
int res = DesfireEmlGet(buf, payload->offset, payload->length);
reply_ng(CMD_HF_DESFIRE_EML_MEMGET, res, buf, payload->length);
BigBuf_free_keep_EM();
break;
}
case CMD_HF_MIFARE_NACK_DETECT: { case CMD_HF_MIFARE_NACK_DETECT: {
DetectNACKbug(); DetectNACKbug();
break; break;

2243
armsrc/desfiresim.c Normal file

File diff suppressed because it is too large Load diff

270
armsrc/desfiresim.h Normal file
View file

@ -0,0 +1,270 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// DESFire emulation data structures and function prototypes
//-----------------------------------------------------------------------------
#ifndef __DESFIRESIM_H
#define __DESFIRESIM_H
#include "common.h"
#include "desfire.h"
#include "desfire_crypto.h"
// DESFire emulator memory layout (4KB BigBuf optimized for red team use)
#define DESFIRE_EMU_MEMORY_SIZE 4096
#define DESFIRE_CARD_HEADER_SIZE 32
#define DESFIRE_APP_DIR_SIZE 168 // 28 apps * 6 bytes each
#define DESFIRE_APP_DATA_SIZE 3896 // 4096 - 32 - 168 = 3896
#define DESFIRE_MAX_APPS 28 // EV1 standard limit
#define DESFIRE_MAX_FILES_PER_APP 16
#define DESFIRE_MAX_KEYS_PER_APP 14
#define DESFIRE_MAX_RESPONSE_SIZE 256 // Maximum response size for bounds checking
// Memory offsets
#define DESFIRE_CARD_HEADER_OFFSET 0x0000
#define DESFIRE_APP_DIR_OFFSET 0x0020
#define DESFIRE_APP_DATA_OFFSET 0x00C8 // 0x0020 + 168
// DESFire authentication constants
#define DESFIRE_NOT_YET_AUTHENTICATED 0xFF
// DESFire command constants (reuse existing from protocols.h where possible)
#ifndef MFDES_SELECT_APPLICATION
#define MFDES_SELECT_APPLICATION 0x5A
#endif
#ifndef MFDES_GET_APPLICATION_IDS
#define MFDES_GET_APPLICATION_IDS 0x6A
#endif
#ifndef MFDES_GET_FILE_IDS
#define MFDES_GET_FILE_IDS 0x6F
#endif
#define MFDES_GET_FILE_ISO_IDS 0x61
#define MFDES_AUTHENTICATE 0x0A
#define MFDES_AUTHENTICATE_3DES 0x1A
#define MFDES_AUTHENTICATE_AES 0xAA
#define MFDES_READ_DATA 0xBD
#define MFDES_WRITE_DATA 0x3D
#define MFDES_GET_FILE_SETTINGS 0xF5
#define MFDES_CREATE_APPLICATION 0xCA
#define MFDES_DELETE_APPLICATION 0xDA
#define MFDES_CREATE_STD_DATA_FILE 0xCD
#define MFDES_CREATE_BACKUP_DATA_FILE 0xCB
#define MFDES_CREATE_VALUE_FILE 0xCC
#define MFDES_CREATE_LINEAR_RECORD_FILE 0xC1
#define MFDES_CREATE_CYCLIC_RECORD_FILE 0xC0
#define MFDES_DELETE_FILE 0xDF
#define MFDES_GET_VALUE 0x6C
#define MFDES_CREDIT 0x0C
#define MFDES_DEBIT 0xDC
#define MFDES_LIMITED_CREDIT 0x1C
#define MFDES_WRITE_RECORD 0x3B
#define MFDES_READ_RECORDS 0xBB
#define MFDES_CLEAR_RECORD_FILE 0xEB
#define MFDES_COMMIT_TRANSACTION 0xC7
#define MFDES_ABORT_TRANSACTION 0xA7
#define MFDES_GET_KEY_SETTINGS 0x45
#define MFDES_GET_FREE_MEM 0x6E
#define MFDES_GET_DF_NAMES 0x6D
#define MFDES_GET_CARD_UID 0x51
#define MFDES_SET_CONFIGURATION 0x5C
#define MFDES_AUTHENTICATE_EV2_FIRST 0x71
#define MFDES_AUTHENTICATE_EV2_NONFIRST 0x77
#define MFDES_COMMIT_READER_ID 0xC8
// DESFire status codes
#define MFDES_OPERATION_OK 0x00
#define MFDES_AUTHENTICATION_ERROR 0xAE
#define MFDES_ADDITIONAL_FRAME 0xAF
#define MFDES_APPLICATION_NOT_FOUND 0xA0
#define MFDES_FILE_NOT_FOUND 0xF0
#define MFDES_PARAMETER_ERROR 0x9E
#define MFDES_COMMAND_ABORTED 0xCA
#define MFDES_DUPLICATE_ERROR 0x0E
// File types
typedef enum {
DESFIRE_FILE_TYPE_STANDARD = 0x00,
DESFIRE_FILE_TYPE_BACKUP = 0x01,
DESFIRE_FILE_TYPE_VALUE = 0x02,
DESFIRE_FILE_TYPE_LINEAR_RECORD = 0x03,
DESFIRE_FILE_TYPE_CYCLIC_RECORD = 0x04
} desfire_file_type_t;
// Authentication states
typedef enum {
DESFIRE_AUTH_NONE = 0,
DESFIRE_AUTH_CHALLENGE_SENT,
DESFIRE_AUTH_RESPONSE_RECEIVED,
DESFIRE_AUTH_AUTHENTICATED
} desfire_auth_state_t;
// DESFire card header (32 bytes at offset 0x0000)
typedef struct {
uint8_t version[8]; // DESFire version response
uint8_t uid[10]; // Card UID
uint8_t uidlen; // UID length
uint8_t num_apps; // Number of applications (max 2)
uint8_t master_key[16]; // Master key (up to AES-128)
uint8_t master_key_type; // Key type (0=DES, 1=3DES, 3=AES)
uint8_t key_settings; // Master key settings
uint8_t reserved[2]; // Reserved for future use
} PACKED desfire_card_t;
// Application directory entry (6 bytes each, max 2 entries)
typedef struct {
uint8_t aid[3]; // Application ID
uint16_t offset; // Offset in emulator memory
uint8_t auth_key; // Currently authenticated key (0xFF = none)
} PACKED desfire_app_dir_t;
// Application header in memory (8 bytes + variable data)
typedef struct {
uint8_t aid[3]; // Application ID
uint8_t key_settings; // Key settings
uint8_t num_keys; // Number of keys (1-14)
uint8_t num_files; // Number of files (0-16)
uint8_t auth_key; // Currently authenticated key
uint8_t reserved; // Reserved
// Followed by: keys array, file headers, file data
} PACKED desfire_app_t;
// File header (20 bytes - expanded for ISO support)
typedef struct {
uint8_t file_no; // File number (0-31)
uint8_t file_type; // File type (standard/backup/value/record)
uint8_t comm_settings; // Communication settings
uint8_t has_iso_id; // 1 if ISO file ID is present
uint16_t access_rights; // Access rights (4 nibbles)
uint16_t iso_file_id; // ISO file ID (if present)
union {
struct { // For standard/backup files
uint32_t size; // File size
} data;
struct { // For value files
int32_t lower_limit; // Lower limit
int32_t upper_limit; // Upper limit
int32_t value; // Current value
uint8_t limited_credit_enabled;
} value;
struct { // For record files
uint32_t record_size; // Size of one record
uint32_t max_records; // Maximum number of records
uint32_t current_records; // Current number of records
} record;
} settings;
uint16_t offset; // Offset to file data
} PACKED desfire_file_t;
// Enhanced runtime simulation state with full crypto support
typedef struct {
uint8_t selected_app[3]; // Currently selected AID (000000 = PICC level)
desfire_auth_state_t auth_state; // Authentication state
// Enhanced authentication context
struct desfire_tag *crypto_ctx; // Full DESFire crypto context
uint8_t auth_keyno; // Key number being authenticated
uint8_t auth_scheme; // Authentication scheme (DES/3DES/AES)
uint8_t current_auth_step; // Multi-step authentication tracking
// Challenge/response state for multi-step auth
uint8_t challenge[16]; // Current challenge data
uint8_t response[32]; // Response buffer for complex auth
uint8_t challenge_len; // Challenge length (8 for DES/3DES, 16 for AES)
uint8_t response_len; // Response length
// Session management
uint8_t session_active; // Boolean: is authenticated session active
uint8_t secure_channel; // Secure channel type (none/EV1/EV2/LRP)
uint8_t comm_mode; // Communication mode (plain/MAC/encrypted)
uint16_t cmd_counter; // Command counter for EV2/LRP
uint8_t transaction_id[4]; // Transaction identifier for EV2
uint8_t session_key[24]; // Session key storage
// Key management cache
uint8_t cached_key_type[DESFIRE_MAX_KEYS_PER_APP]; // Key types per app
uint8_t cached_key_data[DESFIRE_MAX_KEYS_PER_APP * 24]; // Key data cache
uint8_t cached_key_valid[DESFIRE_MAX_KEYS_PER_APP]; // Key validity flags
} desfire_sim_state_t;
// Function prototypes for DESFire emulation
// Memory management
void DesfireSimInit(void);
desfire_card_t *DesfireGetCard(void);
desfire_app_dir_t *DesfireGetAppDir(void);
desfire_app_t *DesfireFindApp(uint8_t *aid);
desfire_file_t *DesfireFindFile(desfire_app_t *app, uint8_t file_no);
// Command handlers
uint8_t HandleDesfireGetVersion(uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireSelectApp(uint8_t *aid, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireGetAppIDs(uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireGetFileIDs(uint8_t *response, uint8_t *response_len);
// Enhanced authentication handlers
uint8_t HandleDesfireAuthenticate(uint8_t keyno, uint8_t *data, uint8_t len, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireAuthenticateISO(uint8_t keyno, uint8_t *data, uint8_t len, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireAuthenticateAES(uint8_t keyno, uint8_t *data, uint8_t len, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireAdditionalFrame(uint8_t *data, uint8_t len, uint8_t *response, uint8_t *response_len);
// Authentication state management
void DesfireInitCryptoContext(void);
void DesfireClearSession(void);
bool DesfireIsAuthenticated(void);
uint8_t DesfireGetAuthKeyType(uint8_t *aid, uint8_t keyno);
void DesfireSetSessionKey(uint8_t *session_key, uint8_t key_type);
bool DesfireValidateMAC(uint8_t *data, uint8_t len, uint8_t *mac);
void DesfireCalculateMAC(uint8_t *data, uint8_t len, uint8_t *mac);
uint8_t HandleDesfireReadData(uint8_t file_no, uint32_t offset, uint32_t length, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireCreateApp(uint8_t *aid, uint8_t key_settings, uint8_t num_keys, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireDeleteApp(uint8_t *aid, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireCreateStdDataFile(uint8_t *data, uint8_t len, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireCreateBackupDataFile(uint8_t *data, uint8_t len, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireCreateValueFile(uint8_t *data, uint8_t len, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireCreateLinearRecordFile(uint8_t *data, uint8_t len, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireCreateCyclicRecordFile(uint8_t *data, uint8_t len, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireDeleteFile(uint8_t file_no, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireGetFileSettings(uint8_t file_no, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireWriteData(uint8_t file_no, uint32_t offset, uint32_t length, uint8_t *data, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireGetValue(uint8_t file_no, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireCredit(uint8_t file_no, int32_t value, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireDebit(uint8_t file_no, int32_t value, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireLimitedCredit(uint8_t file_no, int32_t value, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireWriteRecord(uint8_t file_no, uint32_t offset, uint32_t length, uint8_t *data, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireReadRecords(uint8_t file_no, uint32_t offset, uint32_t length, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireClearRecordFile(uint8_t file_no, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireGetKeySettings(uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireGetCardUID(uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireSetConfiguration(uint8_t option, uint8_t *data, uint8_t len, uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireGetDFNames(uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireGetFreeMem(uint8_t *response, uint8_t *response_len);
uint8_t HandleDesfireGetFileISOIDs(uint8_t *response, uint8_t *response_len);
// Utility functions
uint8_t DesfireGetCardVersion(void);
uint8_t DesfireGetKeySize(uint8_t key_type);
bool DesfireCheckAccess(desfire_file_t *file, uint8_t operation, uint8_t auth_key);
void DesfireGenerateChallenge(uint8_t *challenge, uint8_t len);
uint8_t DesfireGetKeyForAuth(uint8_t *aid, uint8_t keyno, uint8_t key_type, uint8_t *key_out);
// Global simulation state
extern desfire_sim_state_t g_desfire_state;
// DESFire emulator memory management functions
void DesfireEmlClear(void);
int DesfireEmlSet(const uint8_t *data, uint32_t offset, uint32_t length);
int DesfireEmlGet(uint8_t *data, uint32_t offset, uint32_t length);
#endif

View file

@ -37,6 +37,7 @@
#include "generator.h" #include "generator.h"
#include "desfire_crypto.h" // UL-C authentication helpers #include "desfire_crypto.h" // UL-C authentication helpers
#include "mifare.h" // for iso14a_polling_frame_t structure #include "mifare.h" // for iso14a_polling_frame_t structure
#include "desfiresim.h" // DESFire emulation
#define MAX_ISO14A_TIMEOUT 524288 #define MAX_ISO14A_TIMEOUT 524288
// this timeout is in MS // this timeout is in MS
@ -1203,6 +1204,470 @@ static void Simulate_reread_ulc_key(uint8_t *ulc_key) {
reverse_array(ulc_key + 8, 4); reverse_array(ulc_key + 8, 4);
reverse_array(ulc_key + 12, 4); reverse_array(ulc_key + 12, 4);
} }
//-----------------------------------------------------------------------------
// DESFire command dispatcher
//-----------------------------------------------------------------------------
uint8_t HandleDesfireCommand(uint8_t *cmd, uint8_t cmd_len, uint8_t *response, uint8_t *response_len) {
if (cmd_len < 1 || response == NULL || response_len == NULL) {
if (response != NULL && response_len != NULL) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
}
return MFDES_PARAMETER_ERROR;
}
// Check for ISO7816-wrapped commands (CLA=90 or 91, etc.)
if ((cmd[0] & 0xF0) == 0x90 && cmd_len >= 5) {
// ISO7816 wrapped command format: CLA INS P1 P2 [Lc Data] [Le]
uint8_t cla = cmd[0];
uint8_t ins = cmd[1];
uint8_t p1 = cmd[2];
uint8_t p2 = cmd[3];
uint8_t lc = 0;
uint8_t *data = NULL;
// Validate CLA - should be 0x90 for DESFire
if (cla != 0x90) {
response[0] = 0x6E; // Class not supported
response[1] = 0x00;
*response_len = 2;
return MFDES_COMMAND_ABORTED;
}
// Validate P1 - should be 0x00 for most DESFire commands
if (p1 != 0x00) {
response[0] = 0x6A; // Wrong P1-P2
response[1] = 0x86;
*response_len = 2;
return MFDES_PARAMETER_ERROR;
}
// Extract data length and pointer
if (cmd_len > 5) {
lc = cmd[4];
if (cmd_len >= 5 + lc) {
data = &cmd[5];
}
}
// Map ISO7816 INS to DESFire commands
uint8_t desfire_cmd;
switch (ins) {
case 0x5A: desfire_cmd = MFDES_SELECT_APPLICATION; break;
case 0x60: desfire_cmd = MFDES_GET_VERSION; break;
case 0x6A: desfire_cmd = MFDES_GET_APPLICATION_IDS; break;
case 0x6F: desfire_cmd = MFDES_GET_FILE_IDS; break;
case 0xF5: desfire_cmd = MFDES_GET_FILE_SETTINGS; break;
case 0x45: desfire_cmd = MFDES_GET_KEY_SETTINGS; break;
case 0xAA: desfire_cmd = MFDES_AUTHENTICATE_AES; break;
case 0x0A: desfire_cmd = MFDES_AUTHENTICATE; break;
case 0x1A: desfire_cmd = MFDES_AUTHENTICATE_3DES; break;
case 0xBD: desfire_cmd = MFDES_READ_DATA; break;
case 0x3D: desfire_cmd = MFDES_WRITE_DATA; break;
case 0xCA: desfire_cmd = MFDES_CREATE_APPLICATION; break;
case 0xDA: desfire_cmd = MFDES_DELETE_APPLICATION; break;
case 0xCD: desfire_cmd = MFDES_CREATE_STD_DATA_FILE; break;
case 0xCB: desfire_cmd = MFDES_CREATE_BACKUP_DATA_FILE; break;
case 0xCC: desfire_cmd = MFDES_CREATE_VALUE_FILE; break;
case 0xC1: desfire_cmd = MFDES_CREATE_LINEAR_RECORD_FILE; break;
case 0xC0: desfire_cmd = MFDES_CREATE_CYCLIC_RECORD_FILE; break;
case 0xDF: desfire_cmd = MFDES_DELETE_FILE; break;
case 0x6C: desfire_cmd = MFDES_GET_VALUE; break;
case 0x0C: desfire_cmd = MFDES_CREDIT; break;
case 0xDC: desfire_cmd = MFDES_DEBIT; break;
case 0x1C: desfire_cmd = MFDES_LIMITED_CREDIT; break;
case 0x3B: desfire_cmd = MFDES_WRITE_RECORD; break;
case 0xBB: desfire_cmd = MFDES_READ_RECORDS; break;
case 0xEB: desfire_cmd = MFDES_CLEAR_RECORD_FILE; break;
case 0x6E: desfire_cmd = MFDES_GET_FREE_MEM; break;
case 0x6D: desfire_cmd = MFDES_GET_DF_NAMES; break;
case 0x61: desfire_cmd = MFDES_GET_FILE_ISO_IDS; break;
case 0x51: desfire_cmd = MFDES_GET_CARD_UID; break;
case 0x5C: desfire_cmd = MFDES_SET_CONFIGURATION; break;
case 0x71: desfire_cmd = MFDES_AUTHENTICATE_EV2_FIRST; break;
case 0x77: desfire_cmd = MFDES_AUTHENTICATE_EV2_NONFIRST; break;
case 0xC8: desfire_cmd = MFDES_COMMIT_READER_ID; break;
case 0xAF: desfire_cmd = 0xAF; break; // Additional frame
default:
// Unknown ISO7816 command
response[0] = MFDES_COMMAND_ABORTED;
response[1] = 0x00; // SW2
*response_len = 2;
return MFDES_COMMAND_ABORTED;
}
// Handle the DESFire command
uint8_t status;
uint8_t desfire_response[DESFIRE_MAX_RESPONSE_SIZE];
uint8_t desfire_response_len = 0;
// Build native DESFire command
if (desfire_cmd == 0xAF) {
// Additional frame - just pass the data
if (data != NULL && lc > 0) {
status = HandleDesfireAuthenticate(0xFF, data, lc, desfire_response, &desfire_response_len);
} else {
status = MFDES_PARAMETER_ERROR;
}
} else if (desfire_cmd == MFDES_SELECT_APPLICATION && data != NULL && lc >= 3) {
status = HandleDesfireSelectApp(data, desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_GET_VERSION) {
status = HandleDesfireGetVersion(desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_GET_APPLICATION_IDS) {
status = HandleDesfireGetAppIDs(desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_GET_FILE_IDS) {
status = HandleDesfireGetFileIDs(desfire_response, &desfire_response_len);
} else if ((desfire_cmd == MFDES_AUTHENTICATE || desfire_cmd == MFDES_AUTHENTICATE_3DES ||
desfire_cmd == MFDES_AUTHENTICATE_AES) && lc >= 1) {
uint8_t keyno = (data != NULL && lc > 0) ? data[0] : p2;
uint8_t *auth_data = (lc > 1 && data != NULL) ? &data[1] : NULL;
uint8_t auth_len = (lc > 1) ? (lc - 1) : 0;
status = HandleDesfireAuthenticate(keyno, auth_data, auth_len, desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_READ_DATA && data != NULL && lc >= 7) {
uint8_t file_no = data[0];
uint32_t offset = (data[1] | (data[2] << 8) | (data[3] << 16));
uint32_t length = (data[4] | (data[5] << 8) | (data[6] << 16));
status = HandleDesfireReadData(file_no, offset, length, desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_WRITE_DATA && data != NULL && lc >= 7) {
uint8_t file_no = data[0];
uint32_t offset = (data[1] | (data[2] << 8) | (data[3] << 16));
uint32_t length = (data[4] | (data[5] << 8) | (data[6] << 16));
if (lc >= 7 + length) {
status = HandleDesfireWriteData(file_no, offset, length, &data[7], desfire_response, &desfire_response_len);
} else {
status = MFDES_PARAMETER_ERROR;
}
} else if (desfire_cmd == MFDES_CREATE_APPLICATION && data != NULL && lc >= 5) {
status = HandleDesfireCreateApp(data, data[3], data[4], desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_DELETE_APPLICATION && data != NULL && lc >= 3) {
status = HandleDesfireDeleteApp(data, desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_CREATE_STD_DATA_FILE && data != NULL && lc >= 7) {
status = HandleDesfireCreateStdDataFile(data, lc, desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_CREATE_BACKUP_DATA_FILE && data != NULL && lc >= 7) {
status = HandleDesfireCreateBackupDataFile(data, lc, desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_CREATE_VALUE_FILE && data != NULL && lc >= 17) {
status = HandleDesfireCreateValueFile(data, lc, desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_CREATE_LINEAR_RECORD_FILE && data != NULL && lc >= 10) {
status = HandleDesfireCreateLinearRecordFile(data, lc, desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_CREATE_CYCLIC_RECORD_FILE && data != NULL && lc >= 10) {
status = HandleDesfireCreateCyclicRecordFile(data, lc, desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_DELETE_FILE && data != NULL && lc >= 1) {
status = HandleDesfireDeleteFile(data[0], desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_GET_FILE_SETTINGS && data != NULL && lc >= 1) {
status = HandleDesfireGetFileSettings(data[0], desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_GET_KEY_SETTINGS) {
status = HandleDesfireGetKeySettings(desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_GET_VALUE && data != NULL && lc >= 1) {
status = HandleDesfireGetValue(data[0], desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_CREDIT && data != NULL && lc >= 5) {
uint8_t file_no = data[0];
int32_t value = (data[1] | (data[2] << 8) | (data[3] << 16) | (data[4] << 24));
status = HandleDesfireCredit(file_no, value, desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_DEBIT && data != NULL && lc >= 5) {
uint8_t file_no = data[0];
int32_t value = (data[1] | (data[2] << 8) | (data[3] << 16) | (data[4] << 24));
status = HandleDesfireDebit(file_no, value, desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_LIMITED_CREDIT && data != NULL && lc >= 5) {
uint8_t file_no = data[0];
int32_t value = (data[1] | (data[2] << 8) | (data[3] << 16) | (data[4] << 24));
status = HandleDesfireLimitedCredit(file_no, value, desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_WRITE_RECORD && data != NULL && lc >= 7) {
uint8_t file_no = data[0];
uint32_t offset = (data[1] | (data[2] << 8) | (data[3] << 16));
uint32_t length = (data[4] | (data[5] << 8) | (data[6] << 16));
if (lc >= 7 + length) {
status = HandleDesfireWriteRecord(file_no, offset, length, &data[7], desfire_response, &desfire_response_len);
} else {
status = MFDES_PARAMETER_ERROR;
}
} else if (desfire_cmd == MFDES_READ_RECORDS && data != NULL && lc >= 7) {
uint8_t file_no = data[0];
uint32_t offset = (data[1] | (data[2] << 8) | (data[3] << 16));
uint32_t length = (data[4] | (data[5] << 8) | (data[6] << 16));
status = HandleDesfireReadRecords(file_no, offset, length, desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_CLEAR_RECORD_FILE && data != NULL && lc >= 1) {
status = HandleDesfireClearRecordFile(data[0], desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_GET_FREE_MEM) {
status = HandleDesfireGetFreeMem(desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_GET_DF_NAMES) {
status = HandleDesfireGetDFNames(desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_GET_FILE_ISO_IDS) {
status = HandleDesfireGetFileISOIDs(desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_GET_CARD_UID) {
status = HandleDesfireGetCardUID(desfire_response, &desfire_response_len);
} else if (desfire_cmd == MFDES_SET_CONFIGURATION && data != NULL && lc >= 1) {
status = HandleDesfireSetConfiguration(data[0], (lc > 1) ? &data[1] : NULL, (lc > 1) ? lc - 1 : 0, desfire_response, &desfire_response_len);
} else {
status = MFDES_PARAMETER_ERROR;
}
// Format ISO7816 response
if (status == MFDES_OPERATION_OK || status == MFDES_ADDITIONAL_FRAME) {
// Copy response data
if (desfire_response_len > 0 && desfire_response_len <= DESFIRE_MAX_RESPONSE_SIZE - 2) {
memcpy(response, desfire_response, desfire_response_len);
*response_len = desfire_response_len;
}
// Add SW1 SW2 (90 00 for normal, 91 AF for additional frame)
if (status == MFDES_ADDITIONAL_FRAME) {
response[(*response_len)++] = 0x91;
response[(*response_len)++] = 0xAF;
} else {
response[(*response_len)++] = 0x91;
response[(*response_len)++] = 0x00;
}
} else {
// Error response with status code
response[0] = 0x91;
response[1] = status;
*response_len = 2;
}
return status;
}
// Native DESFire command handling
switch (cmd[0]) {
case MFDES_GET_VERSION:
return HandleDesfireGetVersion(response, response_len);
case MFDES_SELECT_APPLICATION:
if (cmd_len < 4) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
return HandleDesfireSelectApp(&cmd[1], response, response_len);
case MFDES_GET_APPLICATION_IDS:
return HandleDesfireGetAppIDs(response, response_len);
case MFDES_GET_FILE_IDS:
return HandleDesfireGetFileIDs(response, response_len);
case MFDES_AUTHENTICATE:
case MFDES_AUTHENTICATE_3DES:
case MFDES_AUTHENTICATE_AES:
if (cmd_len < 2) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
return HandleDesfireAuthenticate(cmd[1], &cmd[2], cmd_len - 2, response, response_len);
case MFDES_READ_DATA: {
if (cmd_len < 8) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
// Parse read data command: file_no, offset (3 bytes), length (3 bytes)
uint8_t file_no = cmd[1];
uint32_t offset = (cmd[2] | (cmd[3] << 8) | (cmd[4] << 16));
uint32_t length = (cmd[5] | (cmd[6] << 8) | (cmd[7] << 16));
return HandleDesfireReadData(file_no, offset, length, response, response_len);
}
case MFDES_CREATE_APPLICATION:
if (cmd_len < 6) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
// Parse create application command: AID (3 bytes), key_settings, num_keys
return HandleDesfireCreateApp(&cmd[1], cmd[4], cmd[5], response, response_len);
case MFDES_DELETE_APPLICATION:
if (cmd_len < 4) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
return HandleDesfireDeleteApp(&cmd[1], response, response_len);
case MFDES_WRITE_DATA: {
if (cmd_len < 8) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
uint8_t file_no = cmd[1];
uint32_t offset = (cmd[2] | (cmd[3] << 8) | (cmd[4] << 16));
uint32_t length = (cmd[5] | (cmd[6] << 8) | (cmd[7] << 16));
if (cmd_len < 8 + length) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
return HandleDesfireWriteData(file_no, offset, length, &cmd[8], response, response_len);
}
case MFDES_CREATE_STD_DATA_FILE:
if (cmd_len < 8) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
return HandleDesfireCreateStdDataFile(&cmd[1], cmd_len - 1, response, response_len);
case MFDES_CREATE_BACKUP_DATA_FILE:
if (cmd_len < 8) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
return HandleDesfireCreateBackupDataFile(&cmd[1], cmd_len - 1, response, response_len);
case MFDES_CREATE_VALUE_FILE:
if (cmd_len < 18) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
return HandleDesfireCreateValueFile(&cmd[1], cmd_len - 1, response, response_len);
case MFDES_CREATE_LINEAR_RECORD_FILE:
if (cmd_len < 11) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
return HandleDesfireCreateLinearRecordFile(&cmd[1], cmd_len - 1, response, response_len);
case MFDES_CREATE_CYCLIC_RECORD_FILE:
if (cmd_len < 11) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
return HandleDesfireCreateCyclicRecordFile(&cmd[1], cmd_len - 1, response, response_len);
case MFDES_DELETE_FILE:
if (cmd_len < 2) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
return HandleDesfireDeleteFile(cmd[1], response, response_len);
case MFDES_GET_FILE_SETTINGS:
if (cmd_len < 2) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
return HandleDesfireGetFileSettings(cmd[1], response, response_len);
case MFDES_GET_KEY_SETTINGS:
return HandleDesfireGetKeySettings(response, response_len);
case MFDES_GET_VALUE:
if (cmd_len < 2) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
return HandleDesfireGetValue(cmd[1], response, response_len);
case MFDES_CREDIT: {
if (cmd_len < 6) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
uint8_t file_no = cmd[1];
int32_t value = (cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24));
return HandleDesfireCredit(file_no, value, response, response_len);
}
case MFDES_DEBIT: {
if (cmd_len < 6) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
uint8_t file_no = cmd[1];
int32_t value = (cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24));
return HandleDesfireDebit(file_no, value, response, response_len);
}
case MFDES_LIMITED_CREDIT: {
if (cmd_len < 6) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
uint8_t file_no = cmd[1];
int32_t value = (cmd[2] | (cmd[3] << 8) | (cmd[4] << 16) | (cmd[5] << 24));
return HandleDesfireLimitedCredit(file_no, value, response, response_len);
}
case MFDES_WRITE_RECORD: {
if (cmd_len < 8) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
uint8_t file_no = cmd[1];
uint32_t offset = (cmd[2] | (cmd[3] << 8) | (cmd[4] << 16));
uint32_t length = (cmd[5] | (cmd[6] << 8) | (cmd[7] << 16));
if (cmd_len < 8 + length) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
return HandleDesfireWriteRecord(file_no, offset, length, &cmd[8], response, response_len);
}
case MFDES_READ_RECORDS: {
if (cmd_len < 8) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
uint8_t file_no = cmd[1];
uint32_t offset = (cmd[2] | (cmd[3] << 8) | (cmd[4] << 16));
uint32_t length = (cmd[5] | (cmd[6] << 8) | (cmd[7] << 16));
return HandleDesfireReadRecords(file_no, offset, length, response, response_len);
}
case MFDES_CLEAR_RECORD_FILE:
if (cmd_len < 2) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
return HandleDesfireClearRecordFile(cmd[1], response, response_len);
case MFDES_GET_FREE_MEM:
return HandleDesfireGetFreeMem(response, response_len);
case MFDES_GET_DF_NAMES:
return HandleDesfireGetDFNames(response, response_len);
case MFDES_GET_FILE_ISO_IDS:
return HandleDesfireGetFileISOIDs(response, response_len);
case MFDES_GET_CARD_UID:
return HandleDesfireGetCardUID(response, response_len);
case MFDES_SET_CONFIGURATION:
if (cmd_len < 2) {
response[0] = MFDES_PARAMETER_ERROR;
*response_len = 1;
return MFDES_PARAMETER_ERROR;
}
return HandleDesfireSetConfiguration(cmd[1], (cmd_len > 2) ? &cmd[2] : NULL, (cmd_len > 2) ? cmd_len - 2 : 0, response, response_len);
default:
// Unknown command
response[0] = MFDES_COMMAND_ABORTED;
*response_len = 1;
return MFDES_COMMAND_ABORTED;
}
}
bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
uint8_t *ats, size_t ats_len, tag_response_info_t **responses, uint8_t *ats, size_t ats_len, tag_response_info_t **responses,
uint32_t *cuid, uint8_t *pages, uint8_t *ulc_key) { uint32_t *cuid, uint8_t *pages, uint8_t *ulc_key) {
@ -1279,6 +1744,19 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
sak = 0x20; sak = 0x20;
memcpy(rATS, "\x06\x75\x77\x81\x02\x80\x00\x00", 8); memcpy(rATS, "\x06\x75\x77\x81\x02\x80\x00\x00", 8);
rATS_len = 8; // including CRC rATS_len = 8; // including CRC
// Initialize DESFire simulation
DesfireSimInit();
// Set version response from emulator memory card header
desfire_card_t *card = DesfireGetCard();
if (card != NULL && card->version[0] != 0x00) {
memcpy(rVERSION, card->version, 8);
} else {
// Default DESFire EV1 version (proper EV1 response)
memcpy(rVERSION, "\x04\x01\x01\x01\x00\x1A\x05\x91", 8);
}
AddCrc14A(rVERSION, sizeof(rVERSION) - 2);
break; break;
} }
case 4: { // ISO/IEC 14443-4 - javacard (JCOP) case 4: { // ISO/IEC 14443-4 - javacard (JCOP)
@ -1983,6 +2461,33 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin
p_response = &responses[RESP_INDEX_VERSION]; p_response = &responses[RESP_INDEX_VERSION];
} else if (receivedCmd[0] == MFDES_GET_VERSION && len == 4 && (tagType == 3)) { } else if (receivedCmd[0] == MFDES_GET_VERSION && len == 4 && (tagType == 3)) {
p_response = &responses[RESP_INDEX_VERSION]; p_response = &responses[RESP_INDEX_VERSION];
} else if (tagType == 3) { // DESFire emulation - handle all DESFire commands
uint8_t response_len = 0;
uint8_t status = HandleDesfireCommand(receivedCmd, len, dynamic_response_info.response, &response_len);
if (status == MFDES_OPERATION_OK) {
dynamic_response_info.response_n = response_len;
prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE);
p_response = &dynamic_response_info;
} else if (status == MFDES_ADDITIONAL_FRAME) {
// Authentication in progress - send challenge
dynamic_response_info.response_n = response_len;
prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE);
p_response = &dynamic_response_info;
} else {
// Error - DESFire sends error status in response, not NACK
// The error status is already in the response buffer
// Clear authentication state on certain errors
if (status == MFDES_AUTHENTICATION_ERROR || status == MFDES_APPLICATION_NOT_FOUND) {
// Reset authentication state on critical errors
// Note: g_desfire_state is already declared extern in desfiresim.h
g_desfire_state.auth_state = DESFIRE_AUTH_NONE;
g_desfire_state.auth_keyno = 0xFF;
}
dynamic_response_info.response_n = response_len;
prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE);
p_response = &dynamic_response_info;
}
} else if ((receivedCmd[0] == MIFARE_AUTH_KEYA || receivedCmd[0] == MIFARE_AUTH_KEYB) && len == 4 && tagType != 2 && tagType != 7 && tagType != 13) { // Received an authentication request } else if ((receivedCmd[0] == MIFARE_AUTH_KEYA || receivedCmd[0] == MIFARE_AUTH_KEYB) && len == 4 && tagType != 2 && tagType != 7 && tagType != 13) { // Received an authentication request
cardAUTHKEY = receivedCmd[0] - 0x60; cardAUTHKEY = receivedCmd[0] - 0x60;
cardAUTHSC = receivedCmd[1] / 4; // received block num cardAUTHSC = receivedCmd[1] / 4; // received block num
@ -2144,6 +2649,101 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin
dynamic_response_info.response[2] = 0x00; dynamic_response_info.response[2] = 0x00;
dynamic_response_info.response_n = 3; dynamic_response_info.response_n = 3;
} }
} else if (tagType == 3) {
// DESFire ISO14443-4 command handling
// Check for ISO 14443A-4 I-Block
if ((receivedCmd[0] & 0xC0) == 0x00 || (receivedCmd[0] & 0xC0) == 0x40) { // I-Block
uint8_t pcb = receivedCmd[0];
uint8_t block_num = pcb & 0x01;
uint8_t chain_bit = (pcb & 0x10) >> 4;
(void)chain_bit; // Mark as intentionally unused for now
// Extract the ISO7816 APDU from the I-Block
uint8_t apdu_offset = 1; // Skip PCB
if (pcb & 0x08) apdu_offset++; // Skip CID if present
if (pcb & 0x04) apdu_offset++; // Skip NAD if present
if (len > apdu_offset + 2) { // Must have at least PCB + APDU + CRC
uint8_t apdu_len = len - apdu_offset - 2; // Remove CRC
uint8_t response_len = 0;
uint8_t desfire_response[DESFIRE_MAX_RESPONSE_SIZE];
// Process the DESFire command
uint8_t status = HandleDesfireCommand(&receivedCmd[apdu_offset], apdu_len, desfire_response, &response_len);
// Build I-Block response
dynamic_response_info.response[0] = pcb & 0x0B; // Keep CID/NAD bits, clear chain bit
dynamic_response_info.response[0] |= block_num; // Echo block number
uint8_t resp_offset = 1;
if (pcb & 0x08) { // Echo CID if present
dynamic_response_info.response[resp_offset++] = receivedCmd[1];
}
// Copy DESFire response
if (response_len > 0) {
memcpy(&dynamic_response_info.response[resp_offset], desfire_response, response_len);
dynamic_response_info.response_n = resp_offset + response_len;
} else {
// Empty response with just status
dynamic_response_info.response[resp_offset] = 0x91;
dynamic_response_info.response[resp_offset + 1] = status;
dynamic_response_info.response_n = resp_offset + 2;
}
} else {
// Invalid I-Block
dynamic_response_info.response[0] = 0x92; // R-Block NACK
dynamic_response_info.response_n = 1;
}
} else if ((receivedCmd[0] & 0xC0) == 0xC0) { // S-Block
// Handle S-Block (DESELECT, WTX)
dynamic_response_info.response[0] = receivedCmd[0];
dynamic_response_info.response_n = 1;
} else if ((receivedCmd[0] & 0xC0) == 0x80) { // R-Block
// Handle R-Block (ACK/NAK)
dynamic_response_info.response[0] = receivedCmd[0];
dynamic_response_info.response_n = 1;
} else if ((receivedCmd[0] & 0xF0) != 0x90) {
// Not an ISO7816 wrapped command, might be native DESFire
// Native DESFire commands in I-Block: PCB + native command
uint8_t pcb = receivedCmd[0];
uint8_t apdu_offset = 1;
if (pcb & 0x08) apdu_offset++; // Skip CID if present
if (pcb & 0x04) apdu_offset++; // Skip NAD if present
if (len > apdu_offset + 2) { // Must have at least PCB + cmd + CRC
uint8_t cmd_len = len - apdu_offset - 2; // Remove CRC
uint8_t response_len = 0;
uint8_t desfire_response[DESFIRE_MAX_RESPONSE_SIZE];
// Process native DESFire command
uint8_t status = HandleDesfireCommand(&receivedCmd[apdu_offset], cmd_len, desfire_response, &response_len);
// Build I-Block response with native DESFire format
dynamic_response_info.response[0] = pcb & 0x0B; // Keep CID/NAD bits
dynamic_response_info.response[0] |= (pcb & 0x01); // Echo block number
uint8_t resp_offset = 1;
if (pcb & 0x08) { // Echo CID if present
dynamic_response_info.response[resp_offset++] = receivedCmd[1];
}
// For native DESFire, status byte comes first
dynamic_response_info.response[resp_offset++] = status;
// Then data if any
if (response_len > 0 && status == MFDES_OPERATION_OK) {
memcpy(&dynamic_response_info.response[resp_offset], desfire_response, response_len);
dynamic_response_info.response_n = resp_offset + response_len;
} else {
dynamic_response_info.response_n = resp_offset;
}
}
} else {
// Unknown format
dynamic_response_info.response[0] = 0x92; // R-Block NACK
dynamic_response_info.response_n = 1;
}
} else { } else {
// Check for ISO 14443A-4 compliant commands, look at left nibble // Check for ISO 14443A-4 compliant commands, look at left nibble

View file

@ -194,6 +194,9 @@ void DetectNACKbug(void);
bool GetIso14443aAnswerFromTag_Thinfilm(uint8_t *receivedResponse, uint16_t rec_maxlen, uint8_t *received_len); bool GetIso14443aAnswerFromTag_Thinfilm(uint8_t *receivedResponse, uint16_t rec_maxlen, uint8_t *received_len);
// DESFire emulation command dispatcher
uint8_t HandleDesfireCommand(uint8_t *cmd, uint8_t cmd_len, uint8_t *response, uint8_t *response_len);
extern iso14a_polling_parameters_t WUPA_POLLING_PARAMETERS; extern iso14a_polling_parameters_t WUPA_POLLING_PARAMETERS;
extern iso14a_polling_parameters_t REQA_POLLING_PARAMETERS; extern iso14a_polling_parameters_t REQA_POLLING_PARAMETERS;

View file

@ -647,6 +647,7 @@ SRCS = mifare/aiddesfire.c \
cmdhflto.c \ cmdhflto.c \
cmdhfmf.c \ cmdhfmf.c \
cmdhfmfdes.c \ cmdhfmfdes.c \
cmdhfmfdessim.c \
cmdhfmfhard.c \ cmdhfmfhard.c \
cmdhfmfu.c \ cmdhfmfu.c \
cmdhfmfp.c \ cmdhfmfp.c \

View file

@ -27,6 +27,7 @@
#include "cmdhf14a.h" #include "cmdhf14a.h"
#include "aes.h" #include "aes.h"
#include "crypto/libpcrypto.h" #include "crypto/libpcrypto.h"
#include "cmdhfmfdessim.h"
#include "protocols.h" #include "protocols.h"
#include "cmdtrace.h" #include "cmdtrace.h"
#include "cliparser.h" #include "cliparser.h"
@ -463,7 +464,7 @@ static void swap24(uint8_t *data) {
// default parameters // default parameters
static uint8_t defaultKeyNum = 0; static uint8_t defaultKeyNum = 0;
static DesfireCryptoAlgorithm defaultAlgoId = T_DES; static DesfireCryptoAlgorithm defaultAlgoId = T_3DES; // Real DESFire cards use 2TDEA by default
static uint8_t defaultKey[DESFIRE_MAX_KEY_SIZE] = {0}; static uint8_t defaultKey[DESFIRE_MAX_KEY_SIZE] = {0};
static int defaultKdfAlgo = MFDES_KDF_ALGO_NONE; static int defaultKdfAlgo = MFDES_KDF_ALGO_NONE;
static int defaultKdfInputLen = 0; static int defaultKdfInputLen = 0;
@ -604,8 +605,8 @@ static int CmdHF14ADesDefault(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -1511,8 +1512,8 @@ static int CmdHF14aDesDetect(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -1828,8 +1829,8 @@ static int CmdHF14aDesMAD(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -2002,8 +2003,8 @@ static int CmdHF14ADesSelectApp(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -2171,7 +2172,25 @@ static int CmdHF14ADesBruteApps(const char *Cmd) {
return res; return res;
} }
// TODO: We need to check the tag version, EV1 should stop after 26 apps are found // Get card version to check if it's EV1 (limited to 26 apps)
mfdes_info_res_t info;
int version_res = mfdes_get_info(&info);
bool is_ev1 = false;
if (version_res == PM3_SUCCESS) {
// Check if it's DESFire EV1 (version 1.x.x)
if (info.versionHW[1] == 0x01) {
is_ev1 = true;
PrintAndLogEx(INFO, "DESFire EV1 detected - will limit search to 26 applications");
}
}
// re-select PICC after getting version
res = DesfireSelectAIDHex(&dctx, 0x000000, false, 0);
if (res != PM3_SUCCESS) {
DropField();
PrintAndLogEx(FAILED, "Desfire PICC level select " _RED_("failed") " after version check.");
return res;
}
if (mad) { if (mad) {
idIncrement = 0x10; idIncrement = 0x10;
startAid[0] = 0xF0; startAid[0] = 0xF0;
@ -2192,12 +2211,19 @@ static int CmdHF14ADesBruteApps(const char *Cmd) {
PrintAndLogEx(INFO, "Bruteforce from " _YELLOW_("%06x") " to " _YELLOW_("%06x"), idStart, idEnd); PrintAndLogEx(INFO, "Bruteforce from " _YELLOW_("%06x") " to " _YELLOW_("%06x"), idStart, idEnd);
PrintAndLogEx(INFO, "Enumerating through all AIDs manually, this will take a while!"); PrintAndLogEx(INFO, "Enumerating through all AIDs manually, this will take a while!");
int app_count = 0;
for (uint32_t id = idStart; id <= idEnd && id >= idStart; id += idIncrement) { for (uint32_t id = idStart; id <= idEnd && id >= idStart; id += idIncrement) {
if (kbd_enter_pressed()) { if (kbd_enter_pressed()) {
break; break;
} }
// EV1 is limited to 26 applications
if (is_ev1 && app_count >= 26) {
PrintAndLogEx(INFO, "\nDESFire EV1 card limited to 26 applications - stopping search");
break;
}
float progress = ((id - idStart) / (idEnd - idStart)); float progress = ((id - idStart) / (idEnd - idStart));
PrintAndLogEx(INPLACE, "Progress " _YELLOW_("%0.1f") " %% current AID: %06X", progress, id); PrintAndLogEx(INPLACE, "Progress " _YELLOW_("%0.1f") " %% current AID: %06X", progress, id);
@ -2207,6 +2233,7 @@ static int CmdHF14ADesBruteApps(const char *Cmd) {
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
printf("\33[2K\r"); // clear current line before printing printf("\33[2K\r"); // clear current line before printing
PrintAndLogEx(SUCCESS, "Got new APPID " _GREEN_("%06X"), id); PrintAndLogEx(SUCCESS, "Got new APPID " _GREEN_("%06X"), id);
app_count++;
} }
} }
@ -2228,9 +2255,10 @@ static int CmdHF14ADesAuth(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfdes auth", CLIParserInit(&ctx, "hf mfdes auth",
"Select application on the card. It selects app if it is a valid one or returns an error.", "Select application on the card. It selects app if it is a valid one or returns an error.",
"hf mfdes auth -n 0 -t des -k 0000000000000000 --kdf none -> select PICC level and authenticate with key num=0, key type=des, key=00..00 and key derivation = none\n" "hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none -> select PICC level and authenticate with key num=0, key type=2tdea (default for factory cards), key=00..00\n"
"hf mfdes auth -n 0 -t aes -k 00000000000000000000000000000000 -> select PICC level and authenticate with key num=0, key type=aes, key=00..00 and key derivation = none\n" "hf mfdes auth -n 0 -t des -k 0000000000000000 --kdf none -> select PICC level and authenticate with key num=0, key type=des (single DES, rarely used), key=00..00\n"
"hf mfdes auth -n 0 -t des -k 0000000000000000 --save -> select PICC level and authenticate and in case of successful authentication - save channel parameters to defaults\n" "hf mfdes auth -n 0 -t aes -k 00000000000000000000000000000000 -> select PICC level and authenticate with key num=0, key type=aes, key=00..00\n"
"hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --save -> authenticate and save channel parameters to defaults\n"
"hf mfdes auth --aid 123456 -> select application 123456 and authenticate via parameters from `default` command"); "hf mfdes auth --aid 123456 -> select application 123456 and authenticate via parameters from `default` command");
void *argtable[] = { void *argtable[] = {
@ -2238,8 +2266,8 @@ static int CmdHF14ADesAuth(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -2606,8 +2634,8 @@ static int CmdHF14ADesCreateApp(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -2778,8 +2806,8 @@ static int CmdHF14ADesDeleteApp(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -2841,8 +2869,8 @@ static int CmdHF14ADesGetUID(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -2921,8 +2949,8 @@ static int CmdHF14ADesFormatPICC(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -2978,8 +3006,8 @@ static int CmdHF14ADesGetFreeMem(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -3040,8 +3068,8 @@ static int CmdHF14ADesChKeySettings(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -3113,8 +3141,8 @@ static int CmdHF14ADesGetKeyVersions(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number for authentication"), arg_int0("n", "keyno", "<dec>", "Key number for authentication"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -3215,8 +3243,8 @@ static int CmdHF14ADesGetKeySettings(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -3293,8 +3321,8 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -3365,8 +3393,8 @@ static int CmdHF14ADesGetAppNames(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -3437,8 +3465,8 @@ static int CmdHF14ADesGetFileIDs(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -3511,8 +3539,8 @@ static int CmdHF14ADesGetFileISOIDs(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -3584,8 +3612,8 @@ static int CmdHF14ADesGetFileSettings(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -3753,8 +3781,8 @@ static int CmdHF14ADesChFileSettings(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -3896,8 +3924,8 @@ static int CmdHF14ADesCreateFile(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -4034,8 +4062,8 @@ static int CmdHF14ADesCreateValueFile(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -4160,8 +4188,8 @@ static int CmdHF14ADesCreateRecordFile(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -4396,8 +4424,8 @@ static int CmdHF14ADesDeleteFile(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -4474,8 +4502,8 @@ static int CmdHF14ADesValueOperations(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -4646,8 +4674,8 @@ static int CmdHF14ADesClearRecordFile(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -5051,8 +5079,8 @@ static int CmdHF14ADesReadData(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -5222,8 +5250,8 @@ static int CmdHF14ADesWriteData(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -5561,8 +5589,8 @@ static int CmdHF14ADesLsFiles(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -5634,8 +5662,8 @@ static int CmdHF14ADesLsApp(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -5699,8 +5727,8 @@ static int CmdHF14ADesDump(const char *Cmd) {
arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("a", "apdu", "Show APDU requests and responses"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_int0("n", "keyno", "<dec>", "Key number"), arg_int0("n", "keyno", "<dec>", "Key number"),
arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Crypt algo"), arg_str0("t", "algo", "<DES|2TDEA|3TDEA|AES>", "Key type (default: 2TDEA for factory cards)"),
arg_str0("k", "key", "<hex>", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0("k", "key", "<hex>", "Key (hex): 8 bytes (DES), 16 bytes (2TDEA/AES), 24 bytes (3TDEA)"),
arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"), arg_str0(NULL, "kdf", "<none|AN10922|gallagher>", "Key Derivation Function (KDF)"),
arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"), arg_str0("i", "kdfi", "<hex>", "KDF input (1-31 hex bytes)"),
arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"), arg_str0("m", "cmode", "<plain|mac|encrypt>", "Communicaton mode"),
@ -5853,6 +5881,8 @@ static command_t CommandTable[] = {
{"write", CmdHF14ADesWriteData, IfPm3Iso14443a, "Write data to standard/backup/record/value file"}, {"write", CmdHF14ADesWriteData, IfPm3Iso14443a, "Write data to standard/backup/record/value file"},
{"value", CmdHF14ADesValueOperations, IfPm3Iso14443a, "Operations with value file (get/credit/limited credit/debit/clear)"}, {"value", CmdHF14ADesValueOperations, IfPm3Iso14443a, "Operations with value file (get/credit/limited credit/debit/clear)"},
{"clearrecfile", CmdHF14ADesClearRecordFile, IfPm3Iso14443a, "Clear record File"}, {"clearrecfile", CmdHF14ADesClearRecordFile, IfPm3Iso14443a, "Clear record File"},
{"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("Simulation") " --------------------"},
{"sim", CmdHFMFDesSim, IfPm3Iso14443a, "Simulate DESFire EV1 card"},
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("System") " -----------------------"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("System") " -----------------------"},
{"test", CmdHF14ADesTest, AlwaysAvailable, "Regression crypto tests"}, {"test", CmdHF14ADesTest, AlwaysAvailable, "Regression crypto tests"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}

1141
client/src/cmdhfmfdessim.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,26 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// DESFire simulation commands
//-----------------------------------------------------------------------------
#ifndef CMDHFMFDESSIM_H__
#define CMDHFMFDESSIM_H__
#include "common.h"
int CmdHFMFDesSim(const char *Cmd);
#endif

View file

@ -2240,6 +2240,20 @@ int DesfireValueFileOperations(DesfireContext_t *dctx, uint8_t fid, uint8_t oper
int res = DesfireCommand(dctx, operation, data, datalen, resp, &resplen, -1); int res = DesfireCommand(dctx, operation, data, datalen, resp, &resplen, -1);
// Auto-detection fallback: if MAC mode fails with length error, retry with plain mode
if ((res == 0x7E || res == -20) && dctx->commMode == DCMMACed) {
PrintAndLogEx(INFO, "MAC mode failed with length error, retrying with plain mode");
DesfireCommunicationMode original_mode = dctx->commMode;
dctx->commMode = DCMPlain;
memset(resp, 0, sizeof(resp));
resplen = 0;
res = DesfireCommand(dctx, operation, data, datalen, resp, &resplen, -1);
// Restore original mode for future commands
dctx->commMode = original_mode;
}
if (resplen == 4 && value) { if (resplen == 4 && value) {
*value = MemLeToUint4byte(resp); *value = MemLeToUint4byte(resp);
} }

View file

@ -219,9 +219,6 @@ static uint8_t DesfireGetCmdHeaderLen(uint8_t cmd) {
static const uint8_t EV1D40TransmitMAC[] = { static const uint8_t EV1D40TransmitMAC[] = {
MFDES_WRITE_DATA, MFDES_WRITE_DATA,
MFDES_CREDIT,
MFDES_LIMITED_CREDIT,
MFDES_DEBIT,
MFDES_WRITE_RECORD, MFDES_WRITE_RECORD,
MFDES_UPDATE_RECORD, MFDES_UPDATE_RECORD,
MFDES_COMMIT_READER_ID, MFDES_COMMIT_READER_ID,

View file

@ -23,8 +23,14 @@
- [How to create files](#how-to-create-files) - [How to create files](#how-to-create-files)
- [How to delete files](#how-to-delete-files) - [How to delete files](#how-to-delete-files)
- [How to read/write files](#how-to-readwrite-files) - [How to read/write files](#how-to-readwrite-files)
- [How to work with value files](#how-to-work-with-value-files)
- [How to work with transaction mac](#how-to-work-with-transaction-mac) - [How to work with transaction mac](#how-to-work-with-transaction-mac)
- [How to switch DESFire Light to LRP mode](#how-to-switch-desfire-light-to-lrp-mode) - [How to switch DESFire Light to LRP mode](#how-to-switch-desfire-light-to-lrp-mode)
- [How to get File ISO IDs](#how-to-get-file-iso-ids)
- [How to use DESFire emulation](#how-to-use-desfire-emulation)
- [Emulation limitations](#emulation-limitations)
- [Testing](#testing)
- [Real DESFire card notes](#real-desfire-card-notes)
## Documentation ## Documentation
@ -162,6 +168,29 @@ FCI sends from card to reader after selecting the application (df01 by default)
If it needs to have more space for FCI - just change the ID of one of the bigger files to 0x1f (and the current ID to something else) via SetConfiguration command. If it needs to have more space for FCI - just change the ID of one of the bigger files to 0x1f (and the current ID to something else) via SetConfiguration command.
### DESFire Light File Access Rights
Access rights are defined as 2 bytes (16 bits) per file:
- **Bits 15-12**: Read access condition
- **Bits 11-8**: Write access condition
- **Bits 7-4**: ReadWrite access condition
- **Bits 3-0**: Change access condition
Access condition values:
- **0x0 to 0x4**: Key number requiring authentication
- **0xE**: Free access (no authentication)
- **0xF**: No access allowed
Default file access rights:
| File | Type | Read | Write | RW | Change |
|------|------|------|-------|-------|--------|
| 0x1F | StandardData | 0xE | 0xF | 0x3 | 0x0 |
| 0x00 | StandardData | 0x1 | 0xF | 0x3 | 0x0 |
| 0x04 | StandardData | 0x1 | 0x2 | 0x3 | 0x0 |
| 0x03 | Value | 0x1 | 0x2 | 0x3 | 0x0 |
| 0x01 | CyclicRecord | 0x1 | 0x2 | 0x3 | 0x0 |
| 0x0F | TransactionMAC | 0x1 | 0xF | 0x1 | 0x0 |
## How to ## How to
@ -314,6 +343,33 @@ For more detailed samples look at the next howto.
`hf mfdes write --aid 123456 --fid 01 -d 01020304 --readerid 010203` write data to the file with CommitReaderID command before and CommitTransaction after write `hf mfdes write --aid 123456 --fid 01 -d 01020304 --readerid 010203` write data to the file with CommitReaderID command before and CommitTransaction after write
### How to work with value files
^[Top](#top)
Value files provide secure counter functionality with automatic transaction support.
*create value file:*
`hf mfdes createvaluefile --aid 123456 --fid 02 --lower 00000000 --upper 000003E8 --value 00000064 --rrights free --wrights free --rwrights free --chrights key0` - create value file with limits 0-1000, initial value 100
*value operations:*
`hf mfdes value --aid 123456 --fid 02 --op get -m plain` - read current value in plain mode
`hf mfdes value --aid 123456 --fid 02 --op get -m mac` - read current value in MAC mode
`hf mfdes value --aid 123456 --fid 02 --op credit -d 00000032 -m plain` - add 50 to value in plain mode
`hf mfdes value --aid 123456 --fid 02 --op credit -d 00000032 -m mac` - add 50 to value in MAC mode
`hf mfdes value --aid 123456 --fid 02 --op debit -d 00000014 -m mac` - subtract 20 from value in MAC mode
`hf mfdes value --aid 123456 --fid 02 --op limcredit -d 0000000A -m mac` - limited credit operation (if enabled)
*note on MAC mode:*
Value operations now work correctly in MAC mode on all DESFire variants. If you encounter issues with older cards, the system automatically falls back to plain mode for compatibility.
### How to work with transaction mac ### How to work with transaction mac
^[Top](#top) ^[Top](#top)
@ -389,3 +445,124 @@ Switch LRP mode on
`hf mfdes setconfig --appisoid df01 -t aes -s ev2 --param 05 --data 00000000010000000000` `hf mfdes setconfig --appisoid df01 -t aes -s ev2 --param 05 --data 00000000010000000000`
### How to get File ISO IDs
^[Top](#top)
DESFire EV1+ supports ISO file IDs that can be used for ISO 7816-4 compatible access.
`hf mfdes getfileisoids --aid 123456` -- Get ISO file IDs for a specific application
`hf mfdes getfileisoids --no-auth` -- Get ISO file IDs without authentication
### How to use DESFire emulation
^[Top](#top)
The DESFire emulator supports simulating DESFire EV1/EV2/EV3 cards with most features:
Start emulation:
`hf mfdes sim` -- Start emulation with default card
`hf mfdes sim -u 04112233445566` -- Start emulation with custom 7-byte UID
Reset emulator to factory state:
`hf mfdes sim ereset` -- Reset to factory DESFire card (2TDEA master key)
Load a card dump:
`hf mfdes sim eload -f mydump.bin` -- Load card data from binary file
`hf mfdes sim eload -j mydump.json` -- Load card data from JSON file
View emulator state:
`hf mfdes sim eview` -- Display current card structure
`hf mfdes sim eview --detailed` -- Display detailed card information
Test emulator functionality:
`hf mfdes sim test` -- Run comprehensive emulator tests
Example workflow:
```
# Reset emulator to factory state
hf mfdes sim ereset
# Start emulation
hf mfdes sim
# In another terminal, interact with the emulated card
hf mfdes info
hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none
hf mfdes createapp --aid 112233
hf mfdes selectapp --aid 112233
hf mfdes createfile --fid 01 --size 20 --isofid 1001
hf mfdes write --fid 01 -d 48656c6c6f20576f726c64
```
The emulator supports:
- All authentication modes (DES, 2TDEA/3DES, 3TDEA, AES)
- All file types (Standard, Backup, Value, Linear/Cyclic Record)
- Value file operations (get, credit, debit, limited credit) with proper limit checking
- Access rights enforcement
- ISO file IDs (EV1+ feature)
- GetCardUID with proper encryption
- SetConfiguration command
- GetDFNames for application enumeration
- Transaction MAC with CommitReaderID
- Automatic transaction commitment for value operations
### Emulation limitations
The DESFire emulator supports:
- Maximum 28 applications (EV1 standard limit)
- Up to 16 files per application
- Up to 14 keys per application
- 4KB total memory for data storage
## Testing
^[Top](#top)
### Built-in Tests
Run comprehensive DESFire tests with:
`./tools/pm3_tests.sh --desfire` - run DESFire-specific tests including emulator validation
`./tools/pm3_tests.sh --long` - run all tests including DESFire tests
`hf mfdes test` - run offline cryptographic and core protocol tests
`hf mfdes sim test` - run basic emulator functionality tests
`hf mfdes sim test --all` - run extended emulator validation with stress testing
### Manual Testing
Test value operations on both emulator and real cards:
```bash
# Test with emulator (requires two terminals)
# Terminal 1: Start emulator
hf mfdes sim ereset
hf mfdes sim
# Terminal 2: Test value operations with multiple applications
hf mfdes createapp --aid 123456 --ks1 0F --ks2 0E --numkeys 1
hf mfdes createapp --aid 789ABC --ks1 0F --ks2 0E --numkeys 1
hf mfdes getaids
hf mfdes selectapp --aid 123456
hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none
hf mfdes createvaluefile --fid 02 --lower 00000000 --upper 000003E8 --value 00000064 --rrights free --wrights free --rwrights free --chrights key0
hf mfdes value --fid 02 --op get -m plain
hf mfdes value --fid 02 --op credit -d 00000032 -m mac
hf mfdes value --fid 02 --op debit -d 00000014 -m mac
hf mfdes value --fid 02 --op get -m mac
# Test with real card (place DESFire card on reader)
# Same commands as above
```
### Real DESFire card notes
When working with real DESFire cards:
- Factory cards use 2TDEA (16-byte 3DES) as the default master key, not DES or AES
- The default master key is all zeros (16 bytes: 00000000000000000000000000000000)
- EV1 cards are limited to 26 applications maximum
- EV3 cards report version 03.xx.xx in hardware version field

View file

@ -758,6 +758,10 @@ typedef struct {
#define CMD_HF_DESFIRE_READER 0x072c #define CMD_HF_DESFIRE_READER 0x072c
#define CMD_HF_DESFIRE_INFO 0x072d #define CMD_HF_DESFIRE_INFO 0x072d
#define CMD_HF_DESFIRE_COMMAND 0x072e #define CMD_HF_DESFIRE_COMMAND 0x072e
#define CMD_HF_DESFIRE_SIM_RESET 0x072f
#define CMD_HF_DESFIRE_EML_MEMCLR 0x0750
#define CMD_HF_DESFIRE_EML_MEMSET 0x0751
#define CMD_HF_DESFIRE_EML_MEMGET 0x0752
#define CMD_HF_MIFARE_NACK_DETECT 0x0730 #define CMD_HF_MIFARE_NACK_DETECT 0x0730
#define CMD_HF_MIFARE_STATIC_NONCE 0x0731 #define CMD_HF_MIFARE_STATIC_NONCE 0x0731

View file

@ -11,6 +11,7 @@ RESOURCEPATH="./client/resources"
SLOWTESTS=false SLOWTESTS=false
OPENCLTESTS=false OPENCLTESTS=false
TESTDESFIRE=false
TESTALL=true TESTALL=true
TESTMFKEY=false TESTMFKEY=false
TESTSTATICNESTED=false TESTSTATICNESTED=false
@ -32,9 +33,10 @@ while (( "$#" )); do
case "$1" in case "$1" in
-h|--help) -h|--help)
echo """ echo """
Usage: $0 [--long] [--opencl] [--clientbin /path/to/proxmark3] [mfkey|nonce2key|mf_nonce_brute|staticnested|mfd_aes_brute|cryptorf|fpga_compress|bootrom|armsrc|client|recovery|common] Usage: $0 [--long] [--opencl] [--desfire] [--clientbin /path/to/proxmark3] [mfkey|nonce2key|mf_nonce_brute|staticnested|mfd_aes_brute|cryptorf|fpga_compress|bootrom|armsrc|client|recovery|common|desfire]
--long: Enable slow tests --long: Enable slow tests
--opencl: Enable tests requiring OpenCL (preferably a Nvidia GPU) --opencl: Enable tests requiring OpenCL (preferably a Nvidia GPU)
--desfire: Run comprehensive DESFire emulator vs real card tests
--clientbin ...: Specify path to proxmark3 binary to test --clientbin ...: Specify path to proxmark3 binary to test
If no target given, all targets will be tested If no target given, all targets will be tested
""" """
@ -48,6 +50,11 @@ Usage: $0 [--long] [--opencl] [--clientbin /path/to/proxmark3] [mfkey|nonce2key|
OPENCLTESTS=true OPENCLTESTS=true
shift shift
;; ;;
--desfire)
TESTDESFIRE=true
TESTALL=false
shift
;;
--clientbin) --clientbin)
if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
CLIENTBIN=$2 CLIENTBIN=$2
@ -122,6 +129,11 @@ Usage: $0 [--long] [--opencl] [--clientbin /path/to/proxmark3] [mfkey|nonce2key|
TESTCOMMON=true TESTCOMMON=true
shift shift
;; ;;
desfire)
TESTALL=false
TESTDESFIRE=true
shift
;;
-*|--*=) # unsupported flags -*|--*=) # unsupported flags
echo "Error: Unsupported flag $1" >&2 echo "Error: Unsupported flag $1" >&2
exit 1 exit 1
@ -578,8 +590,107 @@ while true; do
if ! CheckExecute "emv test" "$CLIENTBIN -c 'emv test'" "Tests \( ok"; then break; fi if ! CheckExecute "emv test" "$CLIENTBIN -c 'emv test'" "Tests \( ok"; then break; fi
if ! CheckExecute "hf cipurse test" "$CLIENTBIN -c 'hf cipurse test'" "Tests \( ok"; then break; fi if ! CheckExecute "hf cipurse test" "$CLIENTBIN -c 'hf cipurse test'" "Tests \( ok"; then break; fi
if ! CheckExecute "hf mfdes test" "$CLIENTBIN -c 'hf mfdes test'" "Tests \( ok"; then break; fi if ! CheckExecute "hf mfdes test" "$CLIENTBIN -c 'hf mfdes test'" "Tests \( ok"; then break; fi
if ! CheckExecute "hf mfdes sim test" "$CLIENTBIN -c 'hf mfdes sim test'" "Tests \( ok"; then break; fi
if ! CheckExecute "hf mfdes sim test --all" "$CLIENTBIN -c 'hf mfdes sim test --all'" "Tests \( ok"; then break; fi
# DESFire Real Card Validation Tests (requires real DESFire card on reader)
echo -e "\n${C_BLUE}DESFire Real Card Tests (place DESFire card on reader):${C_NC}"
read -p "Place a factory DESFire card on reader and press Enter (or Ctrl+C to skip)..."
if ! CheckExecute "hf mfdes info" "$CLIENTBIN -c 'hf mfdes info'" "Hardware.*version"; then
echo " Warning: DESFire card not detected, skipping real card tests"
else
if ! CheckExecute "hf mfdes factory auth" "$CLIENTBIN -c 'hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none'" "Authentication.*ok\|Authenticated"; then break; fi
if ! CheckExecute "hf mfdes getaids" "$CLIENTBIN -c 'hf mfdes getaids'" "000000"; then break; fi
if ! CheckExecute "hf mfdes getappnames" "$CLIENTBIN -c 'hf mfdes getappnames'" "Application"; then break; fi
if ! CheckExecute "hf mfdes getuid" "$CLIENTBIN -c 'hf mfdes getuid'" "UID"; then break; fi
if ! CheckExecute "hf mfdes freemem" "$CLIENTBIN -c 'hf mfdes freemem'" "free.*memory\|Free.*mem"; then break; fi
if ! CheckExecute "hf mfdes create test app" "$CLIENTBIN -c 'hf mfdes createapp --aid 112233 --ks 0F --numkeys 1'" "ok\|success"; then break; fi
if ! CheckExecute "hf mfdes select test app" "$CLIENTBIN -c 'hf mfdes selectapp --aid 112233'" "ok\|success"; then break; fi
if ! CheckExecute "hf mfdes auth test app" "$CLIENTBIN -c 'hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none'" "Authentication.*ok\|Authenticated"; then break; fi
if ! CheckExecute "hf mfdes create test file" "$CLIENTBIN -c 'hf mfdes createfile --aid 112233 --fid 01 --size 32'" "ok\|success"; then break; fi
if ! CheckExecute "hf mfdes write test data" "$CLIENTBIN -c 'hf mfdes write --aid 112233 --fid 01 --offset 0 -d 48656c6c6f20576f726c64'" "ok\|success"; then break; fi
if ! CheckExecute "hf mfdes read test data" "$CLIENTBIN -c 'hf mfdes read --aid 112233 --fid 01 --offset 0 --length 12'" "Hello.*World\|48.*65.*6c.*6c.*6f"; then break; fi
if ! CheckExecute "hf mfdes getfileids" "$CLIENTBIN -c 'hf mfdes getfileids --aid 112233'" "01"; then break; fi
if ! CheckExecute "hf mfdes getfilesettings" "$CLIENTBIN -c 'hf mfdes getfilesettings --aid 112233 --fid 01'" "File.*settings\|Size.*32"; then break; fi
if ! CheckExecute "hf mfdes cleanup test" "$CLIENTBIN -c 'hf mfdes selectapp --aid 000000 && hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none && hf mfdes deleteapp --aid 112233'" "ok\|success"; then break; fi
echo " Real card tests completed successfully!"
fi
if ! CheckExecute "hf waveshare load" "$CLIENTBIN -c 'hf waveshare load -m 6 -f tools/lena.bmp -s dither.bmp' && echo '34ff55fe7257876acf30dae00eb0e439 dither.bmp' | md5sum -c -" "dither.bmp: OK"; then break; fi if ! CheckExecute "hf waveshare load" "$CLIENTBIN -c 'hf waveshare load -m 6 -f tools/lena.bmp -s dither.bmp' && echo '34ff55fe7257876acf30dae00eb0e439 dither.bmp' | md5sum -c -" "dither.bmp: OK"; then break; fi
fi fi
# Dedicated DESFire emulator vs real card comparison tests
if $TESTDESFIRE; then
echo -e "\n${C_BLUE}Testing DESFire Emulator vs Real Card Validation:${C_NC}"
# Phase 1: Emulator tests
echo -e "\n${C_BLUE}Phase 1: Testing DESFire Emulator:${C_NC}"
if ! CheckExecute "desfire emulator reset" "$CLIENTBIN -c 'hf mfdes sim ereset'" "ok\|success\|Reset\|reset\|Resetting"; then break; fi
echo "Starting DESFire emulator (run 'hf mfdes sim' in another terminal)..."
read -p "Press Enter when emulator is running..."
if ! CheckExecute "emulator info test" "$CLIENTBIN -c 'hf mfdes info'" "DESFire\|Hardware.*version"; then break; fi
if ! CheckExecute "emulator auth test" "$CLIENTBIN -c 'hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none'" "Authentication.*ok\|Authenticated"; then break; fi
if ! CheckExecute "emulator getaids test" "$CLIENTBIN -c 'hf mfdes getaids'" "000000"; then break; fi
if ! CheckExecute "emulator app creation test" "$CLIENTBIN -c 'hf mfdes createapp --aid 123456 --ks1 0F --ks2 0E --numkeys 1'" "ok\|success"; then break; fi
if ! CheckExecute "emulator second app creation" "$CLIENTBIN -c 'hf mfdes createapp --aid 789ABC --ks1 0F --ks2 0E --numkeys 1'" "ok\|success"; then break; fi
if ! CheckExecute "emulator file creation test" "$CLIENTBIN -c 'hf mfdes selectapp --aid 123456 && hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none && hf mfdes createfile --fid 01 --size 16'" "ok\|success"; then break; fi
if ! CheckExecute "emulator write test" "$CLIENTBIN -c 'hf mfdes write --aid 123456 --fid 01 --offset 0 -d 48656c6c6f'" "ok\|success"; then break; fi
if ! CheckExecute "emulator read test" "$CLIENTBIN -c 'hf mfdes read --aid 123456 --fid 01 --offset 0 --length 5'" "Hello\|48.*65.*6c.*6c.*6f"; then break; fi
if ! CheckExecute "emulator multi-app test" "$CLIENTBIN -c 'hf mfdes getaids'" "123456.*789ABC\|789ABC.*123456"; then break; fi
if ! CheckExecute "emulator EV1+ getuid test" "$CLIENTBIN -c 'hf mfdes selectapp --aid 000000 && hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none && hf mfdes getuid'" "UID"; then break; fi
if ! CheckExecute "emulator EV1+ freemem test" "$CLIENTBIN -c 'hf mfdes freemem'" "free.*memory\|Free.*mem"; then break; fi
# Value file operation tests
echo " Testing value file operations..."
if ! CheckExecute "emulator value file creation" "$CLIENTBIN -c 'hf mfdes selectapp --aid 123456 && hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none && hf mfdes createvaluefile --fid 02 --lowlimit 0 --highlimit 1000 --value 100 --settings 0 --rrights 0 --wrights 0 --rwrights 0 --chrights 0'" "ok\|success"; then break; fi
if ! CheckExecute "emulator value get plain" "$CLIENTBIN -c 'hf mfdes value --aid 123456 --fid 02 --op get -m plain'" "Value.*100\|0x00000064"; then break; fi
if ! CheckExecute "emulator value get mac" "$CLIENTBIN -c 'hf mfdes value --aid 123456 --fid 02 --op get -m mac'" "Value.*100\|0x00000064"; then break; fi
if ! CheckExecute "emulator value credit plain" "$CLIENTBIN -c 'hf mfdes value --aid 123456 --fid 02 --op credit -d 00000032 -m plain'" "Value.*changed\|ok\|success"; then break; fi
if ! CheckExecute "emulator value get after credit" "$CLIENTBIN -c 'hf mfdes value --aid 123456 --fid 02 --op get -m plain'" "Value.*150\|0x00000096"; then break; fi
if ! CheckExecute "emulator value credit mac" "$CLIENTBIN -c 'hf mfdes value --aid 123456 --fid 02 --op credit -d 0000000A -m mac'" "Value.*changed\|ok\|success"; then break; fi
if ! CheckExecute "emulator value debit plain" "$CLIENTBIN -c 'hf mfdes value --aid 123456 --fid 02 --op debit -d 00000014 -m plain'" "Value.*changed\|ok\|success"; then break; fi
if ! CheckExecute "emulator value debit mac" "$CLIENTBIN -c 'hf mfdes value --aid 123456 --fid 02 --op debit -d 00000014 -m mac'" "Value.*changed\|ok\|success"; then break; fi
if ! CheckExecute "emulator value final check" "$CLIENTBIN -c 'hf mfdes value --aid 123456 --fid 02 --op get -m mac'" "Value.*132\|0x00000084"; then break; fi
if ! CheckExecute "emulator cleanup" "$CLIENTBIN -c 'hf mfdes selectapp --aid 000000 && hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none && hf mfdes deleteapp --aid 123456 && hf mfdes deleteapp --aid 789ABC'" "ok\|success"; then break; fi
echo " Emulator tests completed successfully!"
# Phase 2: Real card tests (if available)
echo -e "\n${C_BLUE}Phase 2: Testing Real DESFire Card (optional):${C_NC}"
echo "Place a factory DESFire card on reader for comparison tests..."
read -p "Press Enter to test real card (or Ctrl+C to skip)..."
if ! CheckExecute "real card info test" "$CLIENTBIN -c 'hf mfdes info'" "DESFire\|Hardware.*version"; then
echo " Real card not detected, skipping comparison tests"
else
echo " Real card detected, running comparison tests..."
if ! CheckExecute "real card auth test" "$CLIENTBIN -c 'hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none'" "Authentication.*ok\|Authenticated"; then break; fi
if ! CheckExecute "real card getaids test" "$CLIENTBIN -c 'hf mfdes getaids'" "000000"; then break; fi
if ! CheckExecute "real card app creation test" "$CLIENTBIN -c 'hf mfdes createapp --aid 123456 --ks1 0F --ks2 0E --numkeys 1'" "ok\|success"; then break; fi
if ! CheckExecute "real card second app creation" "$CLIENTBIN -c 'hf mfdes createapp --aid 789ABC --ks1 0F --ks2 0E --numkeys 1'" "ok\|success"; then break; fi
if ! CheckExecute "real card file creation test" "$CLIENTBIN -c 'hf mfdes selectapp --aid 123456 && hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none && hf mfdes createfile --fid 01 --size 16'" "ok\|success"; then break; fi
if ! CheckExecute "real card write test" "$CLIENTBIN -c 'hf mfdes write --aid 123456 --fid 01 --offset 0 -d 48656c6c6f'" "ok\|success"; then break; fi
if ! CheckExecute "real card read test" "$CLIENTBIN -c 'hf mfdes read --aid 123456 --fid 01 --offset 0 --length 5'" "Hello\|48.*65.*6c.*6c.*6f"; then break; fi
if ! CheckExecute "real card multi-app test" "$CLIENTBIN -c 'hf mfdes getaids'" "123456.*789ABC\|789ABC.*123456"; then break; fi
if ! CheckExecute "real card EV1+ getuid test" "$CLIENTBIN -c 'hf mfdes selectapp --aid 000000 && hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none && hf mfdes getuid'" "UID"; then break; fi
if ! CheckExecute "real card EV1+ freemem test" "$CLIENTBIN -c 'hf mfdes freemem'" "free.*memory\|Free.*mem"; then break; fi
# Value file operation tests on real card
echo " Testing value file operations on real card..."
if ! CheckExecute "real card value file creation" "$CLIENTBIN -c 'hf mfdes selectapp --aid 123456 && hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none && hf mfdes createvaluefile --fid 02 --lowlimit 0 --highlimit 1000 --value 100 --settings 0 --rrights 0 --wrights 0 --rwrights 0 --chrights 0'" "ok\|success"; then break; fi
if ! CheckExecute "real card value get plain" "$CLIENTBIN -c 'hf mfdes value --aid 123456 --fid 02 --op get -m plain'" "Value.*100\|0x00000064"; then break; fi
if ! CheckExecute "real card value get mac" "$CLIENTBIN -c 'hf mfdes value --aid 123456 --fid 02 --op get -m mac'" "Value.*100\|0x00000064"; then break; fi
if ! CheckExecute "real card value credit plain" "$CLIENTBIN -c 'hf mfdes value --aid 123456 --fid 02 --op credit -d 00000032 -m plain'" "Value.*changed\|ok\|success"; then break; fi
if ! CheckExecute "real card value get after credit" "$CLIENTBIN -c 'hf mfdes value --aid 123456 --fid 02 --op get -m plain'" "Value.*150\|0x00000096"; then break; fi
if ! CheckExecute "real card value credit mac" "$CLIENTBIN -c 'hf mfdes value --aid 123456 --fid 02 --op credit -d 0000000A -m mac'" "Value.*changed\|ok\|success"; then break; fi
if ! CheckExecute "real card value debit plain" "$CLIENTBIN -c 'hf mfdes value --aid 123456 --fid 02 --op debit -d 00000014 -m plain'" "Value.*changed\|ok\|success"; then break; fi
if ! CheckExecute "real card value debit mac" "$CLIENTBIN -c 'hf mfdes value --aid 123456 --fid 02 --op debit -d 00000014 -m mac'" "Value.*changed\|ok\|success"; then break; fi
if ! CheckExecute "real card value final check" "$CLIENTBIN -c 'hf mfdes value --aid 123456 --fid 02 --op get -m mac'" "Value.*132\|0x00000084"; then break; fi
if ! CheckExecute "real card cleanup" "$CLIENTBIN -c 'hf mfdes selectapp --aid 000000 && hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none && hf mfdes deleteapp --aid 123456 && hf mfdes deleteapp --aid 789ABC'" "ok\|success"; then break; fi
echo " Real card tests completed successfully!"
echo " Both emulator and real card behave identically!"
fi
echo -e "\n${C_GREEN}DESFire validation tests completed successfully!${C_NC}"
fi
echo -e "\n------------------------------------------------------------" echo -e "\n------------------------------------------------------------"
echo -e "Tests [ ${C_GREEN}OK${C_NC} ] ${C_OK}\n" echo -e "Tests [ ${C_GREEN}OK${C_NC} ] ${C_OK}\n"
exit 0 exit 0