Merge pull request #664 from bkerler/mfdes_test

HF MFDES updates. New aid create, aid delete and format card command. Auth fixed. Improved logging.
This commit is contained in:
Iceman 2020-04-10 06:32:27 +02:00 committed by GitHub
commit 652bf0c94b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 891 additions and 228 deletions

View file

@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased]
- Updates `hf mfdes` functions, improved logging and added new commands (@bkerler)
- Updated 'legic.lua' and 'legic_clone.lua' script - works with current command set (@Pizza_4u)
- Rewrote `hf mfdes` functions and added apdu debugging (@bkerler)
- Add Mifare Desfire GetDFNames and improve HF MFDES Enum output (@bkerler)

View file

@ -16,6 +16,7 @@
#include "commonutil.h"
#include "util.h"
#include "mifare.h"
#include "ticks.h"
#define MAX_APPLICATION_COUNT 28
#define MAX_FILE_COUNT 16
@ -137,7 +138,7 @@ void MifareDesfireGetInformation() {
memcpy(payload.uid, card.uid, sizeof(payload.uid));
LED_A_ON();
uint8_t cmd[] = {GET_VERSION, 0x00, 0x00, 0x00};
uint8_t cmd[] = {0x90, GET_VERSION, 0x00, 0x00, 0x00};
size_t cmd_len = sizeof(cmd);
len = DesfireAPDU(cmd, cmd_len, resp);
@ -152,7 +153,7 @@ void MifareDesfireGetInformation() {
memcpy(payload.versionHW, resp + 1, sizeof(payload.versionHW));
// ADDITION_FRAME 1
cmd[0] = ADDITIONAL_FRAME;
cmd[1] = ADDITIONAL_FRAME;
len = DesfireAPDU(cmd, cmd_len, resp);
if (!len) {
print_result("ERROR <--: ", resp, len);
@ -246,9 +247,15 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
else if (arg1 == 1)
Desfire_des_key_new(keybytes, key);
cmd[0] = AUTHENTICATE;
cmd[1] = arg2; //keynumber
len = DesfireAPDU(cmd, 2, resp);
cmd[0] = 0x90;
cmd[1] = AUTHENTICATE;
cmd[2] = 0x0;
cmd[3] = 0x0;
cmd[4] = 0x1;
cmd[5] = arg2; //keynumber
cmd[6] = 0x0;
len = DesfireAPDU(cmd, 7, resp);
if (!len) {
if (DBGLEVEL >= DBG_ERROR) {
DbpString("Authentication failed. Card timeout.");
@ -257,14 +264,13 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
return;
}
if (resp[2] == 0xaf) {
} else {
if (resp[2] == (uint8_t)0xaf) {
DbpString("Authentication failed. Invalid key number.");
OnError(3);
return;
}
memcpy(encRndB, resp + 3, 8);
memcpy(encRndB, resp + 1, 8);
if (arg1 == 2)
tdes_dec(&decRndB, &encRndB, key->data);
else if (arg1 == 1)
@ -275,6 +281,11 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
// This should be random
uint8_t decRndA[8] = {0x00};
uint32_t value = prng_successor(GetTickCount(), 32);
num_to_bytes(value, 4, &decRndA[0]);
value = prng_successor(GetTickCount(), 32);
num_to_bytes(value, 4, &decRndA[4]);
memcpy(RndA, decRndA, 8);
uint8_t encRndA[8] = {0x00};
@ -297,10 +308,14 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
memcpy(both + 8, encRndB, 8);
cmd[0] = ADDITIONAL_FRAME;
memcpy(cmd + 1, both, 16);
len = DesfireAPDU(cmd, 17, resp);
cmd[0] = 0x90;
cmd[1] = ADDITIONAL_FRAME;
cmd[2] = 0x00;
cmd[3] = 0x00;
cmd[4] = 0x10;
memcpy(cmd + 5, both, 16);
cmd[16 + 5] = 0x0;
len = DesfireAPDU(cmd, 5 + 16 + 1, resp);
if (!len) {
if (DBGLEVEL >= DBG_ERROR) {
DbpString("Authentication failed. Card timeout.");
@ -309,14 +324,14 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
return;
}
if (resp[2] == 0x00) {
if (resp[len - 3] == 0x00) {
struct desfire_key sessionKey = {0};
desfirekey_t skey = &sessionKey;
Desfire_session_key_new(RndA, RndB, key, skey);
//print_result("SESSION : ", skey->data, 8);
memcpy(encRndA, resp + 3, 8);
memcpy(encRndA, resp + 1, 8);
if (arg1 == 2)
tdes_dec(&encRndA, &encRndA, key->data);
@ -326,19 +341,20 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
rol(decRndA, 8);
for (int x = 0; x < 8; x++) {
if (decRndA[x] != encRndA[x]) {
DbpString("Authentication failed. Cannot varify PICC.");
DbpString("Authentication failed. Cannot verify PICC.");
OnError(4);
return;
}
}
//Change the selected key to a new value.
/*
/*
// Current key is a 3DES key, change it to a DES key
if (arg1 == 2) {
cmd[0] = CHANGE_KEY;
cmd[1] = arg2;
cmd[0] = 0x90;
cmd[1] = CHANGE_KEY;
cmd[2] = arg2;
uint8_t newKey[16] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77};
@ -367,20 +383,21 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
buff3[x] = buff3[x] ^ buff2[x];
}
tdes_dec(&buff3, &buff3, skey->data);
memcpy(cmd+18,buff3,8);
memcpy(cmd+19,buff3,8);
// The command always times out on the first attempt, this will retry until a response
// is recieved.
len = 0;
while(!len) {
len = DesfireAPDU(cmd,26,resp);
len = DesfireAPDU(cmd,27,resp);
}
} else {
// Current key is a DES key, change it to a 3DES key
if (arg1 == 1) {
cmd[0] = CHANGE_KEY;
cmd[1] = arg2;
cmd[0] = 0x90;
cmd[1] = CHANGE_KEY;
cmd[2] = arg2;
uint8_t newKey[16] = {0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f};
@ -397,31 +414,31 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
memcpy(buff3 + 1, &second, 1);
des_dec(&buff1, &buff1, skey->data);
memcpy(cmd+2,buff1,8);
memcpy(cmd+3,buff1,8);
for (int x = 0; x < 8; x++) {
buff2[x] = buff2[x] ^ buff1[x];
}
des_dec(&buff2, &buff2, skey->data);
memcpy(cmd+10,buff2,8);
memcpy(cmd+11,buff2,8);
for (int x = 0; x < 8; x++) {
buff3[x] = buff3[x] ^ buff2[x];
}
des_dec(&buff3, &buff3, skey->data);
memcpy(cmd+18,buff3,8);
memcpy(cmd+19,buff3,8);
// The command always times out on the first attempt, this will retry until a response
// is recieved.
len = 0;
while(!len) {
len = DesfireAPDU(cmd,26,resp);
len = DesfireAPDU(cmd,27,resp);
}
}
}
*/
OnSuccess();
//OnSuccess();
if (arg1 == 2)
reply_old(CMD_ACK, 1, 0, 0, skey->data, 16);
else if (arg1 == 1)
@ -433,11 +450,139 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
}
}
break;
case 2:
case 2: {
//SendDesfireCommand(AUTHENTICATE_ISO, &arg2, resp);
uint8_t keybytes[16];
uint8_t RndA[8] = {0x00};
uint8_t RndB[8] = {0x00};
if (arg1 == 2) {
if (datain[1] == 0xff) {
memcpy(keybytes, PICC_MASTER_KEY16, 16);
} else {
memcpy(keybytes, datain + 1, datalen);
}
} else {
if (arg1 == 1) {
if (datain[1] == 0xff) {
uint8_t null_key_data8[8] = {0x00};
memcpy(keybytes, null_key_data8, 8);
} else {
memcpy(keybytes, datain + 1, datalen);
}
}
}
struct desfire_key defaultkey = {0};
desfirekey_t key = &defaultkey;
if (arg1 == 2)
Desfire_3des_key_new_with_version(keybytes, key);
else if (arg1 == 1)
Desfire_des_key_new(keybytes, key);
cmd[0] = AUTHENTICATE;
cmd[1] = arg2; //keynumber
len = DesfireAPDU(cmd, 2, resp);
if (!len) {
if (DBGLEVEL >= DBG_ERROR) {
DbpString("Authentication failed. Card timeout.");
}
OnError(3);
return;
}
if (resp[2] == (uint8_t)0xaf) {
DbpString("Authentication failed. Invalid key number.");
OnError(3);
return;
}
memcpy(encRndB, resp + 2, 8);
if (arg1 == 2)
tdes_dec(&decRndB, &encRndB, key->data);
else if (arg1 == 1)
des_dec(&decRndB, &encRndB, key->data);
memcpy(RndB, decRndB, 8);
rol(decRndB, 8);
// This should be random
uint8_t decRndA[8] = {0x00};
uint32_t value = prng_successor(GetTickCount(), 32);
num_to_bytes(value, 4, &decRndA[0]);
value = prng_successor(GetTickCount(), 32);
num_to_bytes(value, 4, &decRndA[4]);
memcpy(RndA, decRndA, 8);
uint8_t encRndA[8] = {0x00};
if (arg1 == 2)
tdes_dec(&encRndA, &decRndA, key->data);
else if (arg1 == 1)
des_dec(&encRndA, &decRndA, key->data);
memcpy(both, encRndA, 8);
for (int x = 0; x < 8; x++) {
decRndB[x] = decRndB[x] ^ encRndA[x];
}
if (arg1 == 2)
tdes_dec(&encRndB, &decRndB, key->data);
else if (arg1 == 1)
des_dec(&encRndB, &decRndB, key->data);
memcpy(both + 8, encRndB, 8);
cmd[0] = ADDITIONAL_FRAME;
memcpy(cmd + 1, both, 16);
len = DesfireAPDU(cmd, 1 + 16, resp);
if (!len) {
if (DBGLEVEL >= DBG_ERROR) {
DbpString("Authentication failed. Card timeout.");
}
OnError(3);
return;
}
if (resp[1] == 0x00) {
struct desfire_key sessionKey = {0};
desfirekey_t skey = &sessionKey;
Desfire_session_key_new(RndA, RndB, key, skey);
//print_result("SESSION : ", skey->data, 8);
memcpy(encRndA, resp + 2, 8);
if (arg1 == 2)
tdes_dec(&encRndA, &encRndA, key->data);
else if (arg1 == 1)
des_dec(&encRndA, &encRndA, key->data);
rol(decRndA, 8);
for (int x = 0; x < 8; x++) {
if (decRndA[x] != encRndA[x]) {
DbpString("Authentication failed. Cannot verify PICC.");
OnError(4);
return;
}
}
//OnSuccess();
if (arg1 == 2)
reply_old(CMD_ACK, 1, 0, 0, skey->data, 16);
else if (arg1 == 1)
reply_old(CMD_ACK, 1, 0, 0, skey->data, 8);
} else {
DbpString("Authentication failed.");
OnError(6);
return;
}
}
break;
case 3: {
//defaultkey
uint8_t keybytes[16] = {0x00};
if (datain[1] == 0xff) {
@ -454,13 +599,14 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
uint8_t IV[16] = {0x00};
mbedtls_aes_init(&ctx);
cmd[0] = AUTHENTICATE_AES;
cmd[1] = 0x0;
cmd[0] = 0x90;
cmd[1] = AUTHENTICATE_AES;
cmd[2] = 0x0;
cmd[3] = 0x1;
cmd[4] = arg2; //keynumber
cmd[5] = 0x0;
len = DesfireAPDU(cmd, 6, resp);
cmd[3] = 0x0;
cmd[4] = 0x1;
cmd[5] = arg2; //keynumber
cmd[6] = 0x0;
len = DesfireAPDU(cmd, 7, resp);
if (!len) {
if (DBGLEVEL >= DBG_ERROR) {
DbpString("Authentication failed. Card timeout.");
@ -482,6 +628,14 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, 16, IV, encRndB, decRndB);
rol(decRndB, 16);
uint8_t nonce[16] = {0x00};
uint32_t val = prng_successor(GetTickCount(), 32);
num_to_bytes(val, 4, &nonce[0]);
val = prng_successor(GetTickCount(), 32);
num_to_bytes(val, 4, &nonce[4]);
val = prng_successor(GetTickCount(), 32);
num_to_bytes(val, 4, &nonce[8]);
val = prng_successor(GetTickCount(), 32);
num_to_bytes(val, 4, &nonce[12]);
memcpy(both, nonce, 16);
memcpy(both + 16, decRndB, 16);
uint8_t encBoth[32] = {0x00};
@ -494,14 +648,15 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
}
mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, 32, IV, both, encBoth);
cmd[0] = ADDITIONAL_FRAME;
cmd[1] = 0x00;
cmd[0] = 0x90;
cmd[1] = ADDITIONAL_FRAME;
cmd[2] = 0x00;
cmd[3] = 0x20;
memcpy(cmd + 4, encBoth, 32);
cmd[36]=0x0;
cmd[3] = 0x00;
cmd[4] = 0x20;
memcpy(cmd + 5, encBoth, 32);
cmd[32 + 5] = 0x0;
len = DesfireAPDU(cmd, 37, resp); // 4 + 32 + 1 == 37
len = DesfireAPDU(cmd, 5 + 32 + 1, resp);
if (!len) {
if (DBGLEVEL >= DBG_ERROR) {
DbpString("Authentication failed. Card timeout.");
@ -526,7 +681,7 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
}
}
OnSuccess();
//OnSuccess();
reply_mix(CMD_ACK, 1, len, 0, resp, len);
}
@ -570,7 +725,7 @@ int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout) {
// CreateAPDU
size_t CreateAPDU(uint8_t *datain, size_t len, uint8_t *dataout) {
size_t cmdlen = MIN(len + 4, PM3_CMD_DATA_SIZE - 1);
size_t cmdlen = MIN(len + 3, PM3_CMD_DATA_SIZE - 1);
uint8_t cmd[cmdlen];
memset(cmd, 0, cmdlen);
@ -580,10 +735,10 @@ size_t CreateAPDU(uint8_t *datain, size_t len, uint8_t *dataout) {
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("pcb_blocknum %d == %d ", pcb_blocknum, cmd[0]);
cmd[1] = 0x90; // CID: 0x00 //TODO: allow multiple selected cards
//cmd[1] = 0x90; // CID: 0x00 //TODO: allow multiple selected cards
memcpy(cmd + 2, datain, len);
AddCrc14A(cmd, len + 2);
memcpy(cmd + 1, datain, len);
AddCrc14A(cmd, len + 1);
/*
hf 14a apdu -sk 90 60 00 00 00

View file

@ -697,7 +697,7 @@ int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData) {
int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData) {
int len;
uint8_t data[17] = {MFDES_AUTHENTICATION_FRAME};
uint8_t data[17] = {MFDES_ADDITIONAL_FRAME};
memcpy(data + 1, key, 16);
uint8_t receivedAnswer[MAX_FRAME_SIZE] = {0x00};

View file

@ -819,7 +819,7 @@ void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
case MFDES_GET_KEY_VERSION:
snprintf(exp, size, "GET KEY VERSION");
break;
case MFDES_AUTHENTICATION_FRAME:
case MFDES_ADDITIONAL_FRAME:
snprintf(exp, size, "AUTH FRAME / NEXT FRAME");
break;
default:

File diff suppressed because it is too large Load diff

View file

@ -17,7 +17,7 @@ int CmdHFMFDes(const char *Cmd);
char *getCardSizeStr(uint8_t fsize);
char *getProtocolStr(uint8_t id);
char *getVersionStr(uint8_t major, uint8_t minor);
void getKeySettings(uint8_t *aid);
int getKeySettings(uint8_t *aid);
// Ev1 card limits
#define MAX_NUM_KEYS 0x0F
@ -28,55 +28,6 @@ void getKeySettings(uint8_t *aid);
#define NOT_YET_AUTHENTICATED 0xFF
// status- and error codes |
#define OPERATION_OK 0x00 // Successful operation
#define NO_CHANGES 0x0C // No changes done to backup files
// ,CommitTransaction/
// AbortTransaction not necessary
#define OUT_OF_EEPROM_ERROR 0x0E // Insufficient NV-Memory to
// complete command
#define ILLEGAL_COMMAND_CODE 0x1C // Command code not supported
#define INTEGRITY_ERROR 0x1E // CRC or MAC does not match data
// Padding bytes not valid
#define NO_SUCH_KEY 0x40 // Invalid key number specified
#define LENGTH_ERROR 0x7E // Length of command string invalid
#define PERMISSION_DENIED 0x9D // Current configuration status
// does not allow the requested
// command
#define PARAMETER_ERROR 0x9E // Value of the parameter(s) inval.
#define APPLICATION_NOT_FOUND 0xA0 // Requested AID not present on PIC
#define APPL_INTEGRITY_ERROR 0xA1 // [1] // Unrecoverable error within app-
// lication, app will be disabled
#define AUTHENTICATION_ERROR 0xAE // Current authentication status
// does not allow the requested
// command
#define ADDITIONAL_FRAME 0xAF // Additional data frame is
// expected to be sent
#define BOUNDARY_ERROR 0xBE // Attempt to read/write data from/
// to beyond the file's/record's
// limits. Attempt to exceed the
// limits of a value file.
#define PICC_INTEGRITY_ERROR 0xC1 // [1] // Unrecoverable error within PICC
// ,PICC will be disabled
#define COMMAND_ABORTED 0xCA // Previous Command was not fully
// completed Not all Frames were
// requested or provided by PCD
#define PICC_DISABLED_ERROR 0xCD // [1] // PICC was disabled by an unrecoverable error
#define COUNT_ERROR 0xCE // Number of Applications limited
// to 28, no additional
// CreateApplication possible
#define DUPLICATE_ERROR 0xDE // Creation of file/application
// failed because file/application
// with same number already exists
#define EEPROM_ERROR 0xEE // [1] // Could not complete NV-write
// operation due to loss of power,
// internal backup/rollback
// mechanism activated
#define FILE_NOT_FOUND_ERROR 0xF0 // Specified file number does not
// exist
#define FILE_INTEGRITY_ERROR 0xF1 // [1] // Unrecoverable error within file,
// file will be disabled
//
// [1] These errors are not expected to appear during normal operation
#endif

View file

@ -350,21 +350,18 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
// MIFARE DESFire command set:
#define MFDES_GET_VERSION 0x60
#define MFDES_AUTHENTICATE 0x0A // AUTHENTICATE_NATIVE
#define MFDES_AUTHENTICATE_ISO 0x1A // AUTHENTICATE_STANDARD
#define MFDES_AUTHENTICATE_AES 0xAA
#define MFDES_CREATE_APPLICATION 0xCA
#define MFDES_DELETE_APPLICATION 0xDA
#define MFDES_CREDIT 0x0C
#define MFDES_LIMITED_CREDIT 0x1C
#define MFDES_DEBIT 0xDC
#define MFDES_WRITE_RECORD 0x3B
#define MFDES_READSIG 0x3C
#define MFDES_WRITE_DATA 0x3D
#define MFDES_GET_KEY_SETTINGS 0x45
#define MFDES_CHANGE_KEY_SETTINGS 0x54
#define MFDES_SELECT_APPLICATION 0x5A
@ -376,18 +373,36 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define MFDES_GET_FREE_MEMORY 0x6E
#define MFDES_GET_DF_NAMES 0x6D
#define MFDES_GET_FILE_IDS 0x6F
#define MFDES_ABORT_TRANSACTION 0xA7
#define MFDES_AUTHENTICATION_FRAME 0xAF
#define MFDES_ADDITIONAL_FRAME 0xAF
#define MFDES_ADDITIONAL_FRAME_RESP 0x91AF
#define MFDES_SUCCESS_FRAME_RESP 0x9100
#define MFDES_EAUTH_RESP 0x91AE
#define MFDES_ENO_SUCH_KEY_RESP 0x9140
#define MFDES_READ_RECORDS 0xBB
#define MFDES_READ_DATA 0xBD
#define MFDES_ABORT_TRANSACTION 0xA7
// MIFARE DESFire status set:
#define MFDES_OPERATION_OK 0x00
#define MFDES_NO_CHANGES 0x0C
#define MFDES_ADDITIONAL_FRAME 0xAF
#define MFDES_E_OUT_OF_EEPROM 0x0E
#define MFDES_E_ILLEGAL_COMMAND_CODE 0x1C
#define MFDES_E_INTEGRITY_ERROR 0x1E
#define MFDES_E_NO_SUCH_KEY 0x40
#define MFDES_E_LENGTH 0x7E
#define MFDES_E_PERMISSION_DENIED 0x9D
#define MFDES_E_PARAMETER_ERROR 0x9E
#define MFDES_E_APPLICATION_NOT_FOUND 0xA0
#define MFDES_E_APPL_INTEGRITY 0xA1
#define MFDES_E_AUTHENTIFICATION_ERROR 0xAE
#define MFDES_E_BOUNDARY 0xBE
#define MFDES_E_PICC_INTEGRITY 0xC1
#define MFDES_E_COMMAND_ABORTED 0xCA
#define MFDES_E_PICC_DISABLED 0xCD
#define MFDES_E_COUNT 0xCE
#define MFDES_E_DUPLICATE 0xDE
#define MFDES_E_EEPROM 0xEE
#define MFDES_E_FILE_NOT_FOUND 0xF0
#define MFDES_E_FILE_INTEGRITY 0xF1
#define MFDES_SIGNATURE 0x90
#define MFDES_CREATE_CYCLIC_RECORD_FILE 0xC0
#define MFDES_CREATE_LINEAR_RECORD_FILE 0xC1