mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
code fixes, better handling of card identification and outputs accordingly.
This commit is contained in:
parent
69732ef709
commit
8e74978855
2 changed files with 360 additions and 294 deletions
|
@ -38,12 +38,13 @@ uint8_t key_picc_data[16] = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
UNKNOWN = 0,
|
UNKNOWN = 0,
|
||||||
MF3ICD40,
|
DESFIRE_MF3ICD40,
|
||||||
EV1,
|
DESFIRE_EV1,
|
||||||
EV2,
|
DESFIRE_EV2,
|
||||||
EV3,
|
DESFIRE_EV3,
|
||||||
LIGHT,
|
DESFIRE_LIGHT,
|
||||||
} desfire_cardtype_t;
|
PLUS_EV1,
|
||||||
|
} nxp_cardtype_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t aid[3];
|
uint8_t aid[3];
|
||||||
|
@ -54,14 +55,65 @@ typedef struct {
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00};
|
The 7 MSBits (= n) code the storage size itself based on 2^n,
|
||||||
int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen, false);
|
the LSBit is set to '0' if the size is exactly 2^n
|
||||||
|
and set to '1' if the storage size is between 2^n and 2^(n+1).
|
||||||
|
For this version of DESFire the 7 MSBits are set to 0x0C (2^12 = 4096) and the LSBit is '0'.
|
||||||
|
*/
|
||||||
|
static char *getCardSizeStr(uint8_t fsize) {
|
||||||
|
|
||||||
if (!res && datalen > 1 && data[0] == 0x09) {
|
static char buf[40] = {0x00};
|
||||||
SLmode = 0;
|
char *retStr = buf;
|
||||||
|
|
||||||
|
uint16_t usize = 1 << ((fsize >> 1) + 1);
|
||||||
|
uint16_t lsize = 1 << (fsize >> 1);
|
||||||
|
|
||||||
|
// is LSB set?
|
||||||
|
if (fsize & 1)
|
||||||
|
sprintf(retStr, "0x%02X ( " _YELLOW_("%d - %d bytes") ")", fsize, usize, lsize);
|
||||||
|
else
|
||||||
|
sprintf(retStr, "0x%02X ( " _YELLOW_("%d bytes") ")", fsize, lsize);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *getProtocolStr(uint8_t id, bool hw) {
|
||||||
|
|
||||||
|
static char buf[50] = {0x00};
|
||||||
|
char *retStr = buf;
|
||||||
|
|
||||||
|
if (id == 0x04) {
|
||||||
|
sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3 MIFARE, 14443-4") ")", id);
|
||||||
|
} else if (id == 0x05) {
|
||||||
|
if (hw)
|
||||||
|
sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-2, 14443-3") ")", id);
|
||||||
|
else
|
||||||
|
sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") ")", id);
|
||||||
|
} else {
|
||||||
|
sprintf(retStr, "0x%02X ( " _YELLOW_("Unknown") ")", id);
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *getVersionStr(uint8_t major, uint8_t minor) {
|
||||||
|
|
||||||
|
static char buf[40] = {0x00};
|
||||||
|
char *retStr = buf;
|
||||||
|
|
||||||
|
if (major == 0x00)
|
||||||
|
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire MF3ICD40") ")", major, minor);
|
||||||
|
else if (major == 0x01 && minor == 0x00)
|
||||||
|
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV1") ")", major, minor);
|
||||||
|
else if (major == 0x12 && minor == 0x00)
|
||||||
|
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV2") ")", major, minor);
|
||||||
|
// else if (major == 0x13 && minor == 0x00)
|
||||||
|
// sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV3") ")", major, minor);
|
||||||
|
else if (major == 0x30 && minor == 0x00)
|
||||||
|
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire Light") ")", major, minor);
|
||||||
|
else
|
||||||
|
sprintf(retStr, "%x.%x ( " _YELLOW_("Unknown") ")", major, minor);
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
int DESFIRESendApdu(bool activate_field, bool leavefield_on, sAPDU apdu, uint8_t *result, int max_result_len, int *result_len, uint16_t *sw) {
|
int DESFIRESendApdu(bool activate_field, bool leavefield_on, sAPDU apdu, uint8_t *result, int max_result_len, int *result_len, uint16_t *sw) {
|
||||||
|
|
||||||
|
@ -107,7 +159,7 @@ int DESFIRESendApdu(bool activate_field, bool leavefield_on, sAPDU apdu, uint8_t
|
||||||
if (sw)
|
if (sw)
|
||||||
*sw = isw;
|
*sw = isw;
|
||||||
|
|
||||||
if (isw != 0x9000 && isw != status(MFDES_OPERATION_OK) && isw != status(MFDES_SIGNATURE) && isw != status(MFDES_ADDITIONAL_FRAME) && isw != status(MFDES_NO_CHANGES)) {
|
if (isw != 0x9000 && isw != status(MFDES_S_OPERATION_OK) && isw != status(MFDES_S_SIGNATURE) && isw != status(MFDES_S_ADDITIONAL_FRAME) && isw != status(MFDES_S_NO_CHANGES)) {
|
||||||
if (GetAPDULogging()) {
|
if (GetAPDULogging()) {
|
||||||
if (isw >> 8 == 0x61) {
|
if (isw >> 8 == 0x61) {
|
||||||
PrintAndLogEx(ERR, "APDU chaining len: 0x%02x -->", isw & 0xff);
|
PrintAndLogEx(ERR, "APDU chaining len: 0x%02x -->", isw & 0xff);
|
||||||
|
@ -240,15 +292,23 @@ static char *GetErrorString(int res, uint16_t *sw) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_len, uint16_t *sw, int splitbysize, bool readalldata) {
|
static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_len, uint16_t *sw, int splitbysize, bool readalldata) {
|
||||||
if (g_debugMode > 1) {
|
if (apdu == NULL) {
|
||||||
if (apdu == NULL) PrintAndLogEx(ERR, "APDU=NULL");
|
PrintAndLogEx(DEBUG, "APDU=NULL");
|
||||||
if (dest == NULL) PrintAndLogEx(ERR, "DEST=NULL");
|
return PM3_EINVARG;
|
||||||
if (sw == NULL) PrintAndLogEx(ERR, "SW=NULL");
|
}
|
||||||
if (recv_len == NULL) PrintAndLogEx(ERR, "RECV_LEN=NULL");
|
if (dest == NULL) {
|
||||||
|
PrintAndLogEx(DEBUG, "DEST=NULL");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (sw == NULL) {
|
||||||
|
PrintAndLogEx(DEBUG, "SW=NULL");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (recv_len == NULL) {
|
||||||
|
PrintAndLogEx(DEBUG, "RECV_LEN=NULL");
|
||||||
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
if (apdu == NULL || sw == NULL || recv_len == NULL) return PM3_EINVARG;
|
|
||||||
|
|
||||||
*sw = 0;
|
*sw = 0;
|
||||||
uint8_t data[255 * 5] = {0x00};
|
uint8_t data[255 * 5] = {0x00};
|
||||||
|
@ -257,7 +317,7 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_l
|
||||||
int i = 1;
|
int i = 1;
|
||||||
int res = DESFIRESendApdu(select, true, *apdu, data, sizeof(data), &resplen, sw);
|
int res = DESFIRESendApdu(select, true, *apdu, data, sizeof(data), &resplen, sw);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
if (g_debugMode > 1) GetErrorString(res, sw);
|
PrintAndLogEx(DEBUG, "%s", GetErrorString(res, sw));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
if (dest != NULL) {
|
if (dest != NULL) {
|
||||||
|
@ -276,6 +336,7 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_l
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (*sw == status(MFDES_ADDITIONAL_FRAME)) {
|
while (*sw == status(MFDES_ADDITIONAL_FRAME)) {
|
||||||
apdu->INS = MFDES_ADDITIONAL_FRAME; //0xAF
|
apdu->INS = MFDES_ADDITIONAL_FRAME; //0xAF
|
||||||
apdu->Lc = 0;
|
apdu->Lc = 0;
|
||||||
|
@ -284,9 +345,10 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_l
|
||||||
|
|
||||||
res = DESFIRESendApdu(false, true, *apdu, data, sizeof(data), &resplen, sw);
|
res = DESFIRESendApdu(false, true, *apdu, data, sizeof(data), &resplen, sw);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
if (g_debugMode > 1) GetErrorString(res, sw);
|
PrintAndLogEx(DEBUG, "%s", GetErrorString(res, sw));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dest != NULL) {
|
if (dest != NULL) {
|
||||||
if (splitbysize) {
|
if (splitbysize) {
|
||||||
memcpy(&dest[i * splitbysize], data, resplen);
|
memcpy(&dest[i * splitbysize], data, resplen);
|
||||||
|
@ -296,33 +358,33 @@ static int send_desfire_cmd(sAPDU *apdu, bool select, uint8_t *dest, int *recv_l
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pos += resplen;
|
pos += resplen;
|
||||||
|
|
||||||
if (*sw != status(MFDES_ADDITIONAL_FRAME)) break;
|
if (*sw != status(MFDES_ADDITIONAL_FRAME)) break;
|
||||||
}
|
}
|
||||||
if (splitbysize) *recv_len = i;
|
|
||||||
else {
|
*recv_len = (splitbysize) ? i : pos;
|
||||||
*recv_len = pos;
|
|
||||||
}
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static desfire_cardtype_t getCardType(uint8_t major, uint8_t minor) {
|
static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) {
|
||||||
|
|
||||||
if (major == 0x00)
|
if (major == 0x00)
|
||||||
return MF3ICD40;
|
return DESFIRE_MF3ICD40;
|
||||||
else if (major == 0x01 && minor == 0x00)
|
if (major == 0x01 && minor == 0x00)
|
||||||
return EV1;
|
return DESFIRE_EV1;
|
||||||
else if (major == 0x12 && minor == 0x00)
|
if (major == 0x12 && minor == 0x00)
|
||||||
return EV2;
|
return DESFIRE_EV2;
|
||||||
// else if (major == 0x13 && minor == 0x00)
|
// if (major == 0x13 && minor == 0x00)
|
||||||
// return EV3;
|
// return DESFIRE_EV3;
|
||||||
else if (major == 0x30 && minor == 0x00)
|
if (major == 0x30 && minor == 0x00)
|
||||||
return LIGHT;
|
return DESFIRE_LIGHT;
|
||||||
else
|
if (major == 0x11 && minor == 0x00 )
|
||||||
|
return PLUS_EV1;
|
||||||
|
|
||||||
return UNKNOWN;
|
return UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
//none, verified
|
// -- test if card supports 0x0A
|
||||||
static int test_desfire_authenticate() {
|
static int test_desfire_authenticate() {
|
||||||
uint8_t data[] = {0x00};
|
uint8_t data[] = {0x00};
|
||||||
sAPDU apdu = {0x90, MFDES_AUTHENTICATE, 0x00, 0x00, 0x01, data}; // 0x0A, KEY 0
|
sAPDU apdu = {0x90, MFDES_AUTHENTICATE, 0x00, 0x00, 0x01, data}; // 0x0A, KEY 0
|
||||||
|
@ -331,7 +393,7 @@ static int test_desfire_authenticate() {
|
||||||
return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, false);
|
return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// none, verified
|
// -- test if card supports 0x1A
|
||||||
static int test_desfire_authenticate_iso() {
|
static int test_desfire_authenticate_iso() {
|
||||||
uint8_t data[] = {0x00};
|
uint8_t data[] = {0x00};
|
||||||
sAPDU apdu = {0x90, MFDES_AUTHENTICATE_ISO, 0x00, 0x00, 0x01, data}; // 0x1A, KEY 0
|
sAPDU apdu = {0x90, MFDES_AUTHENTICATE_ISO, 0x00, 0x00, 0x01, data}; // 0x1A, KEY 0
|
||||||
|
@ -340,7 +402,7 @@ static int test_desfire_authenticate_iso() {
|
||||||
return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, false);
|
return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//none, verified
|
// -- test if card supports 0xAA
|
||||||
static int test_desfire_authenticate_aes() {
|
static int test_desfire_authenticate_aes() {
|
||||||
uint8_t data[] = {0x00};
|
uint8_t data[] = {0x00};
|
||||||
sAPDU apdu = {0x90, MFDES_AUTHENTICATE_AES, 0x00, 0x00, 0x01, data}; // 0xAA, KEY 0
|
sAPDU apdu = {0x90, MFDES_AUTHENTICATE_AES, 0x00, 0x00, 0x01, data}; // 0xAA, KEY 0
|
||||||
|
@ -349,37 +411,44 @@ static int test_desfire_authenticate_aes() {
|
||||||
return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, false);
|
return send_desfire_cmd(&apdu, false, NULL, &recv_len, &sw, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- FREE MEM, verified
|
// --- GET FREE MEM
|
||||||
static int desfire_print_freemem(uint32_t free_mem) {
|
static int desfire_print_freemem(uint32_t free_mem) {
|
||||||
PrintAndLogEx(SUCCESS, " Available free memory on card : " _GREEN_("%d bytes"), free_mem);
|
PrintAndLogEx(SUCCESS, " Available free memory on card : " _GREEN_("%d bytes"), free_mem);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// init / disconnect, verified
|
|
||||||
static int get_desfire_freemem(uint32_t *free_mem) {
|
static int get_desfire_freemem(uint32_t *free_mem) {
|
||||||
if (free_mem == NULL) return PM3_EINVARG;
|
if (free_mem == NULL) return PM3_EINVARG;
|
||||||
|
|
||||||
sAPDU apdu = {0x90, MFDES_GET_FREE_MEMORY, 0x00, 0x00, 0x00, NULL}; // 0x6E
|
sAPDU apdu = {0x90, MFDES_GET_FREE_MEMORY, 0x00, 0x00, 0x00, NULL}; // 0x6E
|
||||||
|
*free_mem = 0;
|
||||||
int recv_len = 0;
|
int recv_len = 0;
|
||||||
uint16_t sw = 0;
|
uint16_t sw = 0;
|
||||||
uint8_t fmem[4] = {0};
|
uint8_t fmem[4] = {0};
|
||||||
|
|
||||||
int res = send_desfire_cmd(&apdu, true, fmem, &recv_len, &sw, 0, true);
|
int res = send_desfire_cmd(&apdu, true, fmem, &recv_len, &sw, 0, true);
|
||||||
if (res == PM3_SUCCESS) {
|
|
||||||
|
if (res != PM3_SUCCESS )
|
||||||
|
return res;
|
||||||
|
|
||||||
|
if (sw != status(MFDES_S_OPERATION_OK))
|
||||||
|
return PM3_ESOFT;
|
||||||
|
|
||||||
*free_mem = le24toh(fmem);
|
*free_mem = le24toh(fmem);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
*free_mem = 0;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// --- GET SIGNATURE
|
||||||
|
static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t signature_len, nxp_cardtype_t card_type) {
|
||||||
|
|
||||||
// --- GET SIGNATURE, verified
|
if (uid == NULL) {
|
||||||
static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t signature_len, desfire_cardtype_t card_type) {
|
PrintAndLogEx(DEBUG, "UID=NULL");
|
||||||
if (g_debugMode > 1) {
|
return PM3_EINVARG;
|
||||||
if (uid == NULL) PrintAndLogEx(ERR, "UID=NULL");
|
}
|
||||||
if (signature == NULL) PrintAndLogEx(ERR, "SIGNATURE=NULL");
|
if (signature == NULL) {
|
||||||
|
PrintAndLogEx(DEBUG, "SIGNATURE=NULL");
|
||||||
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
if (uid == NULL || signature == NULL) return PM3_EINVARG;
|
|
||||||
// DESFire Ev3 - wanted
|
// DESFire Ev3 - wanted
|
||||||
// ref: MIFARE Desfire Originality Signature Validation
|
// ref: MIFARE Desfire Originality Signature Validation
|
||||||
|
|
||||||
|
@ -389,7 +458,7 @@ static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t sign
|
||||||
{"NTAG413DNA, DESFire EV1", "04BB5D514F7050025C7D0F397310360EEC91EAF792E96FC7E0F496CB4E669D414F877B7B27901FE67C2E3B33CD39D1C797715189AC951C2ADD"},
|
{"NTAG413DNA, DESFire EV1", "04BB5D514F7050025C7D0F397310360EEC91EAF792E96FC7E0F496CB4E669D414F877B7B27901FE67C2E3B33CD39D1C797715189AC951C2ADD"},
|
||||||
{"DESFire EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"},
|
{"DESFire EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"},
|
||||||
{"NTAG424DNA, NTAG424DNATT, DESFire Light EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B"},
|
{"NTAG424DNA, NTAG424DNATT, DESFire Light EV2", "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B"},
|
||||||
{"DESFire Light EV1", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"},
|
{"DESFire Light", "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"},
|
||||||
{"Mifare Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"}
|
{"Mifare Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -413,8 +482,8 @@ static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t sign
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
// PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
|
// PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
|
||||||
PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_desfire_public_keys[i].desc);
|
PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_desfire_public_keys[i].desc);
|
||||||
PrintAndLogEx(INFO, "IC signature public key value: %.32s", nxp_desfire_public_keys[i].value);
|
PrintAndLogEx(INFO, "IC signature public key value: %.32s", nxp_desfire_public_keys[i].value);
|
||||||
PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 16);
|
PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 16);
|
||||||
|
@ -429,35 +498,34 @@ static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t sign
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// init / disconnect, verified
|
|
||||||
static int get_desfire_signature(uint8_t *signature, size_t *signature_len) {
|
static int get_desfire_signature(uint8_t *signature, size_t *signature_len) {
|
||||||
if (g_debugMode > 1) {
|
|
||||||
if (signature == NULL) PrintAndLogEx(ERR, "SIGNATURE=NULL");
|
if (signature == NULL) {
|
||||||
if (signature_len == NULL) PrintAndLogEx(ERR, "SIGNATURE_LEN=NULL");
|
PrintAndLogEx(DEBUG, "SIGNATURE=NULL");
|
||||||
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
if (signature == NULL || signature_len == NULL) return PM3_EINVARG;
|
if (signature_len == NULL) {
|
||||||
uint8_t c = 0x00;
|
PrintAndLogEx(DEBUG, "SIGNATURE_LEN=NULL");
|
||||||
sAPDU apdu = {0x90, MFDES_READSIG, 0x00, 0x00, 0x01, &c}; // 0x3C
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t c[] = {0x00};
|
||||||
|
sAPDU apdu = {0x90, MFDES_READSIG, 0x00, 0x00, sizeof(c), c}; // 0x3C
|
||||||
int recv_len = 0;
|
int recv_len = 0;
|
||||||
uint16_t sw = 0;
|
uint16_t sw = 0;
|
||||||
int res = send_desfire_cmd(&apdu, true, signature, &recv_len, &sw, 0, true);
|
int res = send_desfire_cmd(&apdu, true, signature, &recv_len, &sw, 0, true);
|
||||||
if (res == PM3_SUCCESS) {
|
if (res == PM3_SUCCESS) {
|
||||||
if (recv_len != 56) {
|
if (recv_len != 56) {
|
||||||
*signature_len = 0;
|
*signature_len = 0;
|
||||||
DropField();
|
res = PM3_ESOFT;
|
||||||
return PM3_ESOFT;
|
|
||||||
} else {
|
} else {
|
||||||
*signature_len = recv_len;
|
*signature_len = recv_len;
|
||||||
|
|
||||||
}
|
}
|
||||||
DropField();
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
}
|
||||||
DropField();
|
DropField();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- KEY SETTING
|
// --- KEY SETTING
|
||||||
static int desfire_print_keysetting(uint8_t key_settings, uint8_t num_keys) {
|
static int desfire_print_keysetting(uint8_t key_settings, uint8_t num_keys) {
|
||||||
|
|
||||||
|
@ -490,23 +558,29 @@ static int desfire_print_keysetting(uint8_t key_settings, uint8_t num_keys) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// none, verified
|
|
||||||
static int get_desfire_keysettings(uint8_t *key_settings, uint8_t *num_keys) {
|
static int get_desfire_keysettings(uint8_t *key_settings, uint8_t *num_keys) {
|
||||||
if (g_debugMode > 1) {
|
if (key_settings == NULL) {
|
||||||
if (key_settings == NULL) PrintAndLogEx(ERR, "KEY_SETTINGS=NULL");
|
PrintAndLogEx(DEBUG, "KEY_SETTINGS=NULL");
|
||||||
if (num_keys == NULL) PrintAndLogEx(ERR, "NUM_KEYS=NULL");
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (num_keys == NULL) {
|
||||||
|
PrintAndLogEx(DEBUG, "NUM_KEYS=NULL");
|
||||||
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
if (key_settings == NULL || num_keys == NULL) return PM3_EINVARG;
|
|
||||||
sAPDU apdu = {0x90, MFDES_GET_KEY_SETTINGS, 0x00, 0x00, 0x00, NULL}; //0x45
|
sAPDU apdu = {0x90, MFDES_GET_KEY_SETTINGS, 0x00, 0x00, 0x00, NULL}; //0x45
|
||||||
int recv_len = 0;
|
int recv_len = 0;
|
||||||
uint16_t sw = 0;
|
uint16_t sw = 0;
|
||||||
uint8_t data[2] = {0};
|
uint8_t data[2] = {0};
|
||||||
int res = send_desfire_cmd(&apdu, false, data, &recv_len, &sw, 0, true);
|
int res = send_desfire_cmd(&apdu, false, data, &recv_len, &sw, 0, true);
|
||||||
if (res != PM3_SUCCESS) return res;
|
|
||||||
|
if (res != PM3_SUCCESS )
|
||||||
|
return res;
|
||||||
|
if (sw != status(MFDES_S_OPERATION_OK))
|
||||||
|
return PM3_ESOFT;
|
||||||
|
|
||||||
*key_settings = data[0];
|
*key_settings = data[0];
|
||||||
*num_keys = data[1];
|
*num_keys = data[1];
|
||||||
return PM3_SUCCESS;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- KEY VERSION
|
// --- KEY VERSION
|
||||||
|
@ -515,37 +589,52 @@ static int desfire_print_keyversion(uint8_t key_idx, uint8_t key_version) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// none, verified
|
|
||||||
static int get_desfire_keyversion(uint8_t curr_key, uint8_t *num_versions) {
|
static int get_desfire_keyversion(uint8_t curr_key, uint8_t *num_versions) {
|
||||||
if (g_debugMode > 1) {
|
if (num_versions == NULL) {
|
||||||
if (num_versions == NULL) PrintAndLogEx(ERR, "NUM_VERSIONS=NULL");
|
PrintAndLogEx(DEBUG, "NUM_VERSIONS=NULL");
|
||||||
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
if (num_versions == NULL) return PM3_EINVARG;
|
|
||||||
sAPDU apdu = {0x90, MFDES_GET_KEY_VERSION, 0x00, 0x00, 0x01, &curr_key}; //0x64
|
sAPDU apdu = {0x90, MFDES_GET_KEY_VERSION, 0x00, 0x00, 0x01, &curr_key}; //0x64
|
||||||
int recv_len = 0;
|
int recv_len = 0;
|
||||||
uint16_t sw = 0;
|
uint16_t sw = 0;
|
||||||
int res = send_desfire_cmd(&apdu, false, num_versions, &recv_len, &sw, 0, true);
|
int res = send_desfire_cmd(&apdu, false, num_versions, &recv_len, &sw, 0, true);
|
||||||
|
|
||||||
|
if (res != PM3_SUCCESS )
|
||||||
|
return res;
|
||||||
|
|
||||||
|
if (sw != status(MFDES_S_OPERATION_OK))
|
||||||
|
return PM3_ESOFT;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- GET APPIDS
|
||||||
// init / disconnect, verified
|
|
||||||
static int get_desfire_appids(uint8_t *dest, uint8_t *app_ids_len) {
|
static int get_desfire_appids(uint8_t *dest, uint8_t *app_ids_len) {
|
||||||
if (g_debugMode > 1) {
|
if (dest == NULL) {
|
||||||
if (dest == NULL) PrintAndLogEx(ERR, "DEST=NULL");
|
PrintAndLogEx(DEBUG, "DEST=NULL");
|
||||||
if (app_ids_len == NULL) PrintAndLogEx(ERR, "APP_IDS_LEN=NULL");
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
if (dest == NULL || app_ids_len == NULL) return PM3_EINVARG;
|
if (app_ids_len == NULL) {
|
||||||
|
PrintAndLogEx(DEBUG, "APP_IDS_LEN=NULL");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
sAPDU apdu = {0x90, MFDES_GET_APPLICATION_IDS, 0x00, 0x00, 0x00, NULL}; //0x6a
|
sAPDU apdu = {0x90, MFDES_GET_APPLICATION_IDS, 0x00, 0x00, 0x00, NULL}; //0x6a
|
||||||
int recv_len = 0;
|
int recv_len = 0;
|
||||||
uint16_t sw = 0;
|
uint16_t sw = 0;
|
||||||
int res = send_desfire_cmd(&apdu, true, dest, &recv_len, &sw, 0, true);
|
int res = send_desfire_cmd(&apdu, true, dest, &recv_len, &sw, 0, true);
|
||||||
if (res != PM3_SUCCESS) return res;
|
|
||||||
|
if (res != PM3_SUCCESS )
|
||||||
|
return res;
|
||||||
|
|
||||||
|
if (sw != status(MFDES_S_OPERATION_OK))
|
||||||
|
return PM3_ESOFT;
|
||||||
|
|
||||||
*app_ids_len = (uint8_t)recv_len & 0xFF;
|
*app_ids_len = (uint8_t)recv_len & 0xFF;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// init, verified
|
// --- GET DF NAMES
|
||||||
static int get_desfire_dfnames(dfname_t *dest, uint8_t *dfname_count) {
|
static int get_desfire_dfnames(dfname_t *dest, uint8_t *dfname_count) {
|
||||||
if (g_debugMode > 1) {
|
if (g_debugMode > 1) {
|
||||||
if (dest == NULL) PrintAndLogEx(ERR, "DEST=NULL");
|
if (dest == NULL) PrintAndLogEx(ERR, "DEST=NULL");
|
||||||
|
@ -556,13 +645,14 @@ static int get_desfire_dfnames(dfname_t *dest, uint8_t *dfname_count) {
|
||||||
int recv_len = 0;
|
int recv_len = 0;
|
||||||
uint16_t sw = 0;
|
uint16_t sw = 0;
|
||||||
int res = send_desfire_cmd(&apdu, true, (uint8_t *)dest, &recv_len, &sw, sizeof(dfname_t), true);
|
int res = send_desfire_cmd(&apdu, true, (uint8_t *)dest, &recv_len, &sw, sizeof(dfname_t), true);
|
||||||
if (res != PM3_SUCCESS) return res;
|
if (res != PM3_SUCCESS)
|
||||||
|
return res;
|
||||||
|
if (sw != status(MFDES_S_OPERATION_OK))
|
||||||
|
return PM3_ESOFT;
|
||||||
*dfname_count = recv_len;
|
*dfname_count = recv_len;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// init, verified
|
|
||||||
static int get_desfire_select_application(uint8_t *aid) {
|
static int get_desfire_select_application(uint8_t *aid) {
|
||||||
if (g_debugMode > 1) {
|
if (g_debugMode > 1) {
|
||||||
if (aid == NULL) PrintAndLogEx(ERR, "AID=NULL");
|
if (aid == NULL) PrintAndLogEx(ERR, "AID=NULL");
|
||||||
|
@ -632,7 +722,7 @@ static int get_desfire_createapp(aidhdr_t *aidhdr) {
|
||||||
sAPDU apdu = {0x90, MFDES_CREATE_APPLICATION, 0x00, 0x00, sizeof(aidhdr_t), (uint8_t *)aidhdr}; // 0xCA
|
sAPDU apdu = {0x90, MFDES_CREATE_APPLICATION, 0x00, 0x00, sizeof(aidhdr_t), (uint8_t *)aidhdr}; // 0xCA
|
||||||
uint16_t sw = 0;
|
uint16_t sw = 0;
|
||||||
int recvlen = 0;
|
int recvlen = 0;
|
||||||
int res = send_desfire_cmd(&apdu, false, NONE, &recvlen, &sw, 0, true);
|
int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(WARNING, _RED_(" Can't create aid -> %s"), GetErrorString(res, &sw));
|
PrintAndLogEx(WARNING, _RED_(" Can't create aid -> %s"), GetErrorString(res, &sw));
|
||||||
DropField();
|
DropField();
|
||||||
|
@ -646,7 +736,7 @@ static int get_desfire_deleteapp(uint8_t *aid) {
|
||||||
sAPDU apdu = {0x90, MFDES_DELETE_APPLICATION, 0x00, 0x00, 3, aid}; // 0xDA
|
sAPDU apdu = {0x90, MFDES_DELETE_APPLICATION, 0x00, 0x00, 3, aid}; // 0xDA
|
||||||
uint16_t sw = 0;
|
uint16_t sw = 0;
|
||||||
int recvlen = 0;
|
int recvlen = 0;
|
||||||
int res = send_desfire_cmd(&apdu, false, NONE, &recvlen, &sw, 0, true);
|
int res = send_desfire_cmd(&apdu, false, NULL, &recvlen, &sw, 0, true);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(WARNING, _RED_(" Can't delete aid -> %s"), GetErrorString(res, &sw));
|
PrintAndLogEx(WARNING, _RED_(" Can't delete aid -> %s"), GetErrorString(res, &sw));
|
||||||
DropField();
|
DropField();
|
||||||
|
@ -655,6 +745,116 @@ static int get_desfire_deleteapp(uint8_t *aid) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getKeySettings(uint8_t *aid) {
|
||||||
|
if (aid == NULL) return PM3_EINVARG;
|
||||||
|
|
||||||
|
int res = 0;
|
||||||
|
if (memcmp(aid, "\x00\x00\x00", 3) == 0) {
|
||||||
|
|
||||||
|
// CARD MASTER KEY
|
||||||
|
//PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings"));
|
||||||
|
res = get_desfire_select_application(aid);
|
||||||
|
if (res != PM3_SUCCESS) return res;
|
||||||
|
|
||||||
|
// KEY Settings - AMK
|
||||||
|
uint8_t num_keys = 0;
|
||||||
|
uint8_t key_setting = 0;
|
||||||
|
res = get_desfire_keysettings(&key_setting, &num_keys);
|
||||||
|
if (res == PM3_SUCCESS) {
|
||||||
|
// number of Master keys (0x01)
|
||||||
|
PrintAndLogEx(SUCCESS, " Number of Masterkeys : " _YELLOW_("%u"), (num_keys & 0x3F));
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, " [0x08] Configuration changeable : %s", (key_setting & (1 << 3)) ? _GREEN_("YES") : "NO");
|
||||||
|
PrintAndLogEx(SUCCESS, " [0x04] CMK required for create/delete : %s", (key_setting & (1 << 2)) ? _GREEN_("YES") : "NO");
|
||||||
|
PrintAndLogEx(SUCCESS, " [0x02] Directory list access with CMK : %s", (key_setting & (1 << 1)) ? _GREEN_("YES") : "NO");
|
||||||
|
PrintAndLogEx(SUCCESS, " [0x01] CMK is changeable : %s", (key_setting & (1 << 0)) ? _GREEN_("YES") : "NO");
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *str = " Operation of PICC master key : " _YELLOW_("%s");
|
||||||
|
|
||||||
|
// 2 MSB denotes
|
||||||
|
switch (num_keys >> 6) {
|
||||||
|
case 0:
|
||||||
|
PrintAndLogEx(SUCCESS, str, "(3)DES");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
PrintAndLogEx(SUCCESS, str, "3K3DES");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
PrintAndLogEx(SUCCESS, str, "AES");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t cmk_num_versions = 0;
|
||||||
|
if (get_desfire_keyversion(0, &cmk_num_versions) == PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(SUCCESS, " PICC Master key Version : " _YELLOW_("%d (0x%02x)"), cmk_num_versions, cmk_num_versions);
|
||||||
|
PrintAndLogEx(INFO, " ----------------------------------------------------------");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authentication tests
|
||||||
|
int res = test_desfire_authenticate();
|
||||||
|
if (res == PM3_ETIMEOUT) return res;
|
||||||
|
PrintAndLogEx(SUCCESS, " [0x0A] Authenticate : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
|
||||||
|
|
||||||
|
res = test_desfire_authenticate_iso();
|
||||||
|
if (res == PM3_ETIMEOUT) return res;
|
||||||
|
PrintAndLogEx(SUCCESS, " [0x1A] Authenticate ISO : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
|
||||||
|
|
||||||
|
res = test_desfire_authenticate_aes();
|
||||||
|
if (res == PM3_ETIMEOUT) return res;
|
||||||
|
PrintAndLogEx(SUCCESS, " [0xAA] Authenticate AES : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// AID - APPLICATION MASTER KEYS
|
||||||
|
//PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings"));
|
||||||
|
res = get_desfire_select_application(aid);
|
||||||
|
if (res != PM3_SUCCESS) return res;
|
||||||
|
|
||||||
|
// KEY Settings - AMK
|
||||||
|
uint8_t num_keys = 0;
|
||||||
|
uint8_t key_setting = 0;
|
||||||
|
res = get_desfire_keysettings(&key_setting, &num_keys);
|
||||||
|
if (res == PM3_SUCCESS) {
|
||||||
|
desfire_print_keysetting(key_setting, num_keys);
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// KEY VERSION - AMK
|
||||||
|
uint8_t num_version = 0;
|
||||||
|
if (get_desfire_keyversion(0, &num_version) == PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
||||||
|
PrintAndLogEx(INFO, " Application keys");
|
||||||
|
desfire_print_keyversion(0, num_version);
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(WARNING, " Can't read AID master key version. Trying all keys");
|
||||||
|
}
|
||||||
|
|
||||||
|
// From 0x01 to numOfKeys. We already got 0x00. (AMK)
|
||||||
|
num_keys &= 0x3F;
|
||||||
|
if (num_keys > 1) {
|
||||||
|
for (uint8_t i = 0x01; i < num_keys; ++i) {
|
||||||
|
if (get_desfire_keyversion(i, &num_version) == PM3_SUCCESS) {
|
||||||
|
desfire_print_keyversion(i, num_version);
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(WARNING, " Can't read key %d (0x%02x) version", i, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int CmdHF14ADesCreateApp(const char *Cmd) {
|
static int CmdHF14ADesCreateApp(const char *Cmd) {
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
|
|
||||||
|
@ -852,7 +1052,7 @@ static int CmdHF14ADesFormatPICC(const char *Cmd) {
|
||||||
uint8_t isOK = resp.oldarg[0] & 0xff;
|
uint8_t isOK = resp.oldarg[0] & 0xff;
|
||||||
if (isOK) {
|
if (isOK) {
|
||||||
uint8_t rdata[] = {0xFC}; // 0xFC
|
uint8_t rdata[] = {0xFC}; // 0xFC
|
||||||
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(rdata), 0, rdata, sizeof(rdata));
|
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NULL, sizeof(rdata), 0, rdata, sizeof(rdata));
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
|
||||||
PrintAndLogEx(WARNING, "Client reset command execute timeout");
|
PrintAndLogEx(WARNING, "Client reset command execute timeout");
|
||||||
DropField();
|
DropField();
|
||||||
|
@ -893,13 +1093,12 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||||
struct p *package = (struct p *) resp.data.asBytes;
|
struct p *package = (struct p *) resp.data.asBytes;
|
||||||
|
|
||||||
if (resp.status != PM3_SUCCESS) {
|
if (resp.status != PM3_SUCCESS) {
|
||||||
|
|
||||||
switch (package->isOK) {
|
switch (package->isOK) {
|
||||||
case 1:
|
case 1:
|
||||||
PrintAndLogEx(WARNING, "Can't select card");
|
PrintAndLogEx(WARNING, "Can't select card");
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
PrintAndLogEx(WARNING, "Card is most likely not Desfire. Its UID has wrong size");
|
PrintAndLogEx(WARNING, "Card is most likely not DESFire. Wrong size UID");
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
default:
|
default:
|
||||||
|
@ -909,6 +1108,12 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nxp_cardtype_t cardtype = getCardType(package->versionHW[3], package->versionHW[4]);
|
||||||
|
if (cardtype == PLUS_EV1) {
|
||||||
|
PrintAndLogEx(INFO, "Card seems to be MIFARE Plus EV1. Try " _YELLOW_("`hf mfp info`"));
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") "---------------------------");
|
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") "---------------------------");
|
||||||
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
||||||
|
@ -922,7 +1127,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), package->versionHW[2]);
|
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), package->versionHW[2]);
|
||||||
PrintAndLogEx(INFO, " Version: %s", getVersionStr(package->versionHW[3], package->versionHW[4]));
|
PrintAndLogEx(INFO, " Version: %s", getVersionStr(package->versionHW[3], package->versionHW[4]));
|
||||||
PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(package->versionHW[5]));
|
PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(package->versionHW[5]));
|
||||||
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(package->versionHW[6]));
|
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(package->versionHW[6], true));
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("Software Information"));
|
PrintAndLogEx(INFO, "--- " _CYAN_("Software Information"));
|
||||||
PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(package->versionSW[0]));
|
PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(package->versionSW[0]));
|
||||||
|
@ -930,7 +1135,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), package->versionSW[2]);
|
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), package->versionSW[2]);
|
||||||
PrintAndLogEx(INFO, " Version: " _YELLOW_("%d.%d"), package->versionSW[3], package->versionSW[4]);
|
PrintAndLogEx(INFO, " Version: " _YELLOW_("%d.%d"), package->versionSW[3], package->versionSW[4]);
|
||||||
PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(package->versionSW[5]));
|
PrintAndLogEx(INFO, " Storage size: %s", getCardSizeStr(package->versionSW[5]));
|
||||||
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(package->versionSW[6]));
|
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(package->versionSW[6], false));
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("Card capabilities"));
|
PrintAndLogEx(INFO, "--- " _CYAN_("Card capabilities"));
|
||||||
|
@ -954,21 +1159,25 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||||
if (major == 0 && minor == 2)
|
if (major == 0 && minor == 2)
|
||||||
PrintAndLogEx(INFO, "\t0.2 - DESFire Light, Originality check, ");
|
PrintAndLogEx(INFO, "\t0.2 - DESFire Light, Originality check, ");
|
||||||
|
|
||||||
|
if (cardtype == DESFIRE_EV2 || cardtype == DESFIRE_LIGHT || cardtype == DESFIRE_EV3) {
|
||||||
// Signature originality check
|
// Signature originality check
|
||||||
uint8_t signature[56] = {0};
|
uint8_t signature[56] = {0};
|
||||||
size_t signature_len = 0;
|
size_t signature_len = 0;
|
||||||
desfire_cardtype_t cardtype = getCardType(package->versionHW[3], package->versionHW[4]);
|
|
||||||
|
|
||||||
if (get_desfire_signature(signature, &signature_len) == PM3_SUCCESS)
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
|
||||||
|
if (get_desfire_signature(signature, &signature_len) == PM3_SUCCESS) {
|
||||||
desfire_print_signature(package->uid, signature, signature_len, cardtype);
|
desfire_print_signature(package->uid, signature, signature_len, cardtype);
|
||||||
else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "--- " _YELLOW_("Couldn't verify signature. Unknown public key ?"));
|
PrintAndLogEx(WARNING, "--- Card doesn't support GetSignature cmd");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Master Key settings
|
// Master Key settings
|
||||||
uint8_t master_aid[3] = {0x00, 0x00, 0x00};
|
uint8_t master_aid[3] = {0x00, 0x00, 0x00};
|
||||||
getKeySettings(master_aid);
|
getKeySettings(master_aid);
|
||||||
|
|
||||||
|
if (cardtype != DESFIRE_LIGHT) {
|
||||||
// Free memory on card
|
// Free memory on card
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("Free memory"));
|
PrintAndLogEx(INFO, "--- " _CYAN_("Free memory"));
|
||||||
|
@ -979,7 +1188,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||||
PrintAndLogEx(SUCCESS, " Card doesn't support 'free mem' cmd");
|
PrintAndLogEx(SUCCESS, " Card doesn't support 'free mem' cmd");
|
||||||
}
|
}
|
||||||
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
Card Master key (CMK) 0x00 AID = 00 00 00 (card level)
|
Card Master key (CMK) 0x00 AID = 00 00 00 (card level)
|
||||||
Application Master Key (AMK) 0x00 AID != 00 00 00
|
Application Master Key (AMK) 0x00 AID != 00 00 00
|
||||||
|
@ -999,167 +1208,6 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
The 7 MSBits (= n) code the storage size itself based on 2^n,
|
|
||||||
the LSBit is set to '0' if the size is exactly 2^n
|
|
||||||
and set to '1' if the storage size is between 2^n and 2^(n+1).
|
|
||||||
For this version of DESFire the 7 MSBits are set to 0x0C (2^12 = 4096) and the LSBit is '0'.
|
|
||||||
*/
|
|
||||||
char *getCardSizeStr(uint8_t fsize) {
|
|
||||||
|
|
||||||
static char buf[40] = {0x00};
|
|
||||||
char *retStr = buf;
|
|
||||||
|
|
||||||
uint16_t usize = 1 << ((fsize >> 1) + 1);
|
|
||||||
uint16_t lsize = 1 << (fsize >> 1);
|
|
||||||
|
|
||||||
// is LSB set?
|
|
||||||
if (fsize & 1)
|
|
||||||
sprintf(retStr, "0x%02X ( " _YELLOW_("%d - %d bytes") ")", fsize, usize, lsize);
|
|
||||||
else
|
|
||||||
sprintf(retStr, "0x%02X ( " _YELLOW_("%d bytes") ")", fsize, lsize);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *getProtocolStr(uint8_t id) {
|
|
||||||
|
|
||||||
static char buf[40] = {0x00};
|
|
||||||
char *retStr = buf;
|
|
||||||
|
|
||||||
if (id == 0x05)
|
|
||||||
sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") ")", id);
|
|
||||||
else
|
|
||||||
sprintf(retStr, "0x%02X ( " _YELLOW_("Unknown") ")", id);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *getVersionStr(uint8_t major, uint8_t minor) {
|
|
||||||
|
|
||||||
static char buf[40] = {0x00};
|
|
||||||
char *retStr = buf;
|
|
||||||
|
|
||||||
if (major == 0x00)
|
|
||||||
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire MF3ICD40") ")", major, minor);
|
|
||||||
else if (major == 0x01 && minor == 0x00)
|
|
||||||
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV1") ")", major, minor);
|
|
||||||
else if (major == 0x12 && minor == 0x00)
|
|
||||||
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV2") ")", major, minor);
|
|
||||||
// else if (major == 0x13 && minor == 0x00)
|
|
||||||
// sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV3") ")", major, minor);
|
|
||||||
else if (major == 0x30 && minor == 0x00)
|
|
||||||
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire Light") ")", major, minor);
|
|
||||||
else
|
|
||||||
sprintf(retStr, "%x.%x ( " _YELLOW_("Unknown") ")", major, minor);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getKeySettings(uint8_t *aid) {
|
|
||||||
if (aid == NULL) return PM3_EINVARG;
|
|
||||||
int res = 0;
|
|
||||||
if (memcmp(aid, "\x00\x00\x00", 3) == 0) {
|
|
||||||
|
|
||||||
// CARD MASTER KEY
|
|
||||||
//PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings"));
|
|
||||||
res = get_desfire_select_application(aid);
|
|
||||||
if (res != PM3_SUCCESS) return res;
|
|
||||||
|
|
||||||
// KEY Settings - AMK
|
|
||||||
uint8_t num_keys = 0;
|
|
||||||
uint8_t key_setting = 0;
|
|
||||||
res = get_desfire_keysettings(&key_setting, &num_keys);
|
|
||||||
if (res == PM3_SUCCESS) {
|
|
||||||
// number of Master keys (0x01)
|
|
||||||
PrintAndLogEx(SUCCESS, " Number of Masterkeys : " _YELLOW_("%u"), (num_keys & 0x3F));
|
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, " [0x08] Configuration changeable : %s", (key_setting & (1 << 3)) ? _GREEN_("YES") : "NO");
|
|
||||||
PrintAndLogEx(SUCCESS, " [0x04] CMK required for create/delete : %s", (key_setting & (1 << 2)) ? _GREEN_("YES") : "NO");
|
|
||||||
PrintAndLogEx(SUCCESS, " [0x02] Directory list access with CMK : %s", (key_setting & (1 << 1)) ? _GREEN_("YES") : "NO");
|
|
||||||
PrintAndLogEx(SUCCESS, " [0x01] CMK is changeable : %s", (key_setting & (1 << 0)) ? _GREEN_("YES") : "NO");
|
|
||||||
} else {
|
|
||||||
PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings"));
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *str = " Operation of PICC master key : " _YELLOW_("%s");
|
|
||||||
|
|
||||||
// 2 MSB denotes
|
|
||||||
switch (num_keys >> 6) {
|
|
||||||
case 0:
|
|
||||||
PrintAndLogEx(SUCCESS, str, "(3)DES");
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
PrintAndLogEx(SUCCESS, str, "3K3DES");
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
PrintAndLogEx(SUCCESS, str, "AES");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t cmk_num_versions = 0;
|
|
||||||
if (get_desfire_keyversion(0, &cmk_num_versions) == PM3_SUCCESS) {
|
|
||||||
PrintAndLogEx(SUCCESS, " PICC Master key Version : " _YELLOW_("%d (0x%02x)"), cmk_num_versions, cmk_num_versions);
|
|
||||||
PrintAndLogEx(INFO, " ----------------------------------------------------------");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Authentication tests
|
|
||||||
int res = test_desfire_authenticate();
|
|
||||||
if (res == PM3_ETIMEOUT) return res;
|
|
||||||
PrintAndLogEx(SUCCESS, " [0x0A] Authenticate : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
|
|
||||||
|
|
||||||
res = test_desfire_authenticate_iso();
|
|
||||||
if (res == PM3_ETIMEOUT) return res;
|
|
||||||
PrintAndLogEx(SUCCESS, " [0x1A] Authenticate ISO : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
|
|
||||||
|
|
||||||
res = test_desfire_authenticate_aes();
|
|
||||||
if (res == PM3_ETIMEOUT) return res;
|
|
||||||
PrintAndLogEx(SUCCESS, " [0xAA] Authenticate AES : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
|
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// AID - APPLICATION MASTER KEYS
|
|
||||||
//PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings"));
|
|
||||||
res = get_desfire_select_application(aid);
|
|
||||||
if (res != PM3_SUCCESS) return res;
|
|
||||||
|
|
||||||
// KEY Settings - AMK
|
|
||||||
uint8_t num_keys = 0;
|
|
||||||
uint8_t key_setting = 0;
|
|
||||||
res = get_desfire_keysettings(&key_setting, &num_keys);
|
|
||||||
if (res == PM3_SUCCESS) {
|
|
||||||
desfire_print_keysetting(key_setting, num_keys);
|
|
||||||
} else {
|
|
||||||
PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// KEY VERSION - AMK
|
|
||||||
uint8_t num_version = 0;
|
|
||||||
if (get_desfire_keyversion(0, &num_version) == PM3_SUCCESS) {
|
|
||||||
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
|
||||||
PrintAndLogEx(INFO, " Application keys");
|
|
||||||
desfire_print_keyversion(0, num_version);
|
|
||||||
} else {
|
|
||||||
PrintAndLogEx(WARNING, " Can't read AID master key version. Trying all keys");
|
|
||||||
}
|
|
||||||
|
|
||||||
// From 0x01 to numOfKeys. We already got 0x00. (AMK)
|
|
||||||
num_keys &= 0x3F;
|
|
||||||
if (num_keys > 1) {
|
|
||||||
for (uint8_t i = 0x01; i < num_keys; ++i) {
|
|
||||||
if (get_desfire_keyversion(i, &num_version) == PM3_SUCCESS) {
|
|
||||||
desfire_print_keyversion(i, num_version);
|
|
||||||
} else {
|
|
||||||
PrintAndLogEx(WARNING, " Can't read key %d (0x%02x) version", i, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DropField();
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DecodeFileType(uint8_t filetype) {
|
static void DecodeFileType(uint8_t filetype) {
|
||||||
switch (filetype) {
|
switch (filetype) {
|
||||||
|
@ -1202,8 +1250,10 @@ static void DecodeComSet(uint8_t comset) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *DecodeAccessValue(uint8_t value) {
|
static char *DecodeAccessValue(uint8_t value) {
|
||||||
char *car = (char *)malloc(255);
|
char *car = (char *)calloc(255, sizeof(char));
|
||||||
memset(car, 0x0, 255);
|
if (car == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case 0xE:
|
case 0xE:
|
||||||
strcat(car, "(Free Access)");
|
strcat(car, "(Free Access)");
|
||||||
|
@ -1224,9 +1274,17 @@ static void DecodeAccessRights(uint16_t accrights) {
|
||||||
int write_access = (accrights >> 8) & 0xF;
|
int write_access = (accrights >> 8) & 0xF;
|
||||||
int read_access = (accrights >> 12) & 0xF;
|
int read_access = (accrights >> 12) & 0xF;
|
||||||
char *car = DecodeAccessValue(change_access_rights);
|
char *car = DecodeAccessValue(change_access_rights);
|
||||||
|
if (car == NULL) return;
|
||||||
|
|
||||||
char *rwa = DecodeAccessValue(read_write_access);
|
char *rwa = DecodeAccessValue(read_write_access);
|
||||||
|
if (rwa == NULL) return;
|
||||||
|
|
||||||
char *wa = DecodeAccessValue(write_access);
|
char *wa = DecodeAccessValue(write_access);
|
||||||
|
if (wa == NULL) return;
|
||||||
|
|
||||||
char *ra = DecodeAccessValue(read_access);
|
char *ra = DecodeAccessValue(read_access);
|
||||||
|
if (ra == NULL) return;
|
||||||
|
|
||||||
PrintAndLogEx(INFO, " Access Rights: 0x%04X - Change %s - RW %s - W %s - R %s", accrights, car, rwa, wa, ra);
|
PrintAndLogEx(INFO, " Access Rights: 0x%04X - Change %s - RW %s - W %s - R %s", accrights, car, rwa, wa, ra);
|
||||||
free(car);
|
free(car);
|
||||||
free(rwa);
|
free(rwa);
|
||||||
|
@ -1234,23 +1292,23 @@ static void DecodeAccessRights(uint16_t accrights) {
|
||||||
free(ra);
|
free(ra);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int DecodeFileSettings(uint8_t *filesettings, int fileset_len, int maclen) {
|
static int DecodeFileSettings(uint8_t *src, int src_len, int maclen) {
|
||||||
uint8_t filetype = filesettings[0];
|
uint8_t filetype = src[0];
|
||||||
uint8_t comset = filesettings[1];
|
uint8_t comset = src[1];
|
||||||
|
|
||||||
uint16_t accrights = (filesettings[4] << 8) + filesettings[3];
|
uint16_t accrights = (src[4] << 8) + src[3];
|
||||||
if (fileset_len == 1 + 1 + 2 + 3 + maclen) {
|
if (src_len == 1 + 1 + 2 + 3 + maclen) {
|
||||||
int filesize = (filesettings[7] << 16) + (filesettings[6] << 8) + filesettings[5];
|
int filesize = (src[7] << 16) + (src[6] << 8) + src[5];
|
||||||
DecodeFileType(filetype);
|
DecodeFileType(filetype);
|
||||||
DecodeComSet(comset);
|
DecodeComSet(comset);
|
||||||
DecodeAccessRights(accrights);
|
DecodeAccessRights(accrights);
|
||||||
PrintAndLogEx(INFO, " Filesize: %d", filesize);
|
PrintAndLogEx(INFO, " Filesize: %d", filesize);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
} else if (fileset_len == 1 + 1 + 2 + 4 + 4 + 4 + 1 + maclen) {
|
} else if (src_len == 1 + 1 + 2 + 4 + 4 + 4 + 1 + maclen) {
|
||||||
int lowerlimit = (filesettings[8] << 24) + (filesettings[7] << 16) + (filesettings[6] << 8) + filesettings[5];
|
int lowerlimit = (src[8] << 24) + (src[7] << 16) + (src[6] << 8) + src[5];
|
||||||
int upperlimit = (filesettings[12] << 24) + (filesettings[11] << 16) + (filesettings[10] << 8) + filesettings[9];
|
int upperlimit = (src[12] << 24) + (src[11] << 16) + (src[10] << 8) + src[9];
|
||||||
int limitcredvalue = (filesettings[16] << 24) + (filesettings[15] << 16) + (filesettings[14] << 8) + filesettings[13];
|
int limitcredvalue = (src[16] << 24) + (src[15] << 16) + (src[14] << 8) + src[13];
|
||||||
uint8_t limited_credit_enabled = filesettings[17];
|
uint8_t limited_credit_enabled = src[17];
|
||||||
DecodeFileType(filetype);
|
DecodeFileType(filetype);
|
||||||
DecodeComSet(comset);
|
DecodeComSet(comset);
|
||||||
DecodeAccessRights(accrights);
|
DecodeAccessRights(accrights);
|
||||||
|
@ -1547,6 +1605,5 @@ static int CmdHelp(const char *Cmd) {
|
||||||
int CmdHFMFDes(const char *Cmd) {
|
int CmdHFMFDes(const char *Cmd) {
|
||||||
// flush
|
// flush
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
//g_debugMode=2;
|
|
||||||
return CmdsParse(CommandTable, Cmd);
|
return CmdsParse(CommandTable, Cmd);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,10 +14,11 @@
|
||||||
|
|
||||||
int CmdHFMFDes(const char *Cmd);
|
int CmdHFMFDes(const char *Cmd);
|
||||||
|
|
||||||
|
/*
|
||||||
char *getCardSizeStr(uint8_t fsize);
|
char *getCardSizeStr(uint8_t fsize);
|
||||||
char *getProtocolStr(uint8_t id);
|
|
||||||
char *getVersionStr(uint8_t major, uint8_t minor);
|
char *getVersionStr(uint8_t major, uint8_t minor);
|
||||||
int getKeySettings(uint8_t *aid);
|
int getKeySettings(uint8_t *aid);
|
||||||
|
*/
|
||||||
|
|
||||||
// Ev1 card limits
|
// Ev1 card limits
|
||||||
#define MAX_NUM_KEYS 0x0F
|
#define MAX_NUM_KEYS 0x0F
|
||||||
|
@ -26,6 +27,14 @@ int getKeySettings(uint8_t *aid);
|
||||||
#define MAX_FRAME_SIZE 60
|
#define MAX_FRAME_SIZE 60
|
||||||
#define FRAME_PAYLOAD_SIZE (MAX_FRAME_SIZE - 5)
|
#define FRAME_PAYLOAD_SIZE (MAX_FRAME_SIZE - 5)
|
||||||
|
|
||||||
|
// Ev2 card limits
|
||||||
|
|
||||||
|
// Ev3 card limits
|
||||||
|
|
||||||
|
// Light card limits
|
||||||
|
|
||||||
|
// Light Ev1 card limits
|
||||||
|
|
||||||
#define NOT_YET_AUTHENTICATED 0xFF
|
#define NOT_YET_AUTHENTICATED 0xFF
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue