From e5d7ce61e67e291533ac0c01f8aed0769ed0aa3f Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Fri, 15 Oct 2021 01:31:16 +0200 Subject: [PATCH] MFULC trace: detect when known key is used during auth --- client/src/cmdhflist.c | 421 ++++++++++++++++++++++------------------- client/src/cmdhflist.h | 4 +- client/src/cmdhfmfu.c | 59 ++++++ client/src/cmdhfmfu.h | 1 + client/src/cmdtrace.c | 12 +- 5 files changed, 298 insertions(+), 199 deletions(-) diff --git a/client/src/cmdhflist.c b/client/src/cmdhflist.c index a9046afc8..47a0c3ee8 100644 --- a/client/src/cmdhflist.c +++ b/client/src/cmdhflist.c @@ -47,6 +47,9 @@ void ClearAuthData(void) { static int gs_ntag_i2c_state = 0; +static int gs_mfuc_state = 0; +static uint8_t gs_mfuc_authdata[3][16] = {0}; +static uint8_t *gs_mfuc_key = NULL; /** * @brief iso14443A_CRC_check Checks CRC in command or response @@ -162,202 +165,240 @@ uint8_t iclass_CRC_check(bool isResponse, uint8_t *d, uint8_t n) { } -int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { +int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response) { + + if (! is_response) { + if ((gs_ntag_i2c_state == 1) && (cmdsize == 6) && (memcmp(cmd + 1, "\x00\x00\x00", 3) == 0)) { + snprintf(exp, size, "SECTOR(%d)", cmd[0]); + gs_ntag_i2c_state = 0; + return 1; + } - if ((gs_ntag_i2c_state == 1) && (cmdsize == 6) && (memcmp(cmd + 1, "\x00\x00\x00", 3) == 0)) { - snprintf(exp, size, "SECTOR(%d)", cmd[0]); gs_ntag_i2c_state = 0; - return 1; - } - - gs_ntag_i2c_state = 0; - - switch (cmd[0]) { - case ISO14443A_CMD_WUPA: - snprintf(exp, size, "WUPA"); - break; - case ISO14443A_CMD_ANTICOLL_OR_SELECT: { - // 93 20 = Anticollision (usage: 9320 - answer: 4bytes UID+1byte UID-bytes-xor) - // 93 50 = Bit oriented anti-collision (usage: 9350+ up to 5bytes, 9350 answer - up to 5bytes UID+BCC) - // 93 70 = Select (usage: 9370+5bytes 9370 answer - answer: 1byte SAK) - if (cmd[1] == 0x70) - snprintf(exp, size, "SELECT_UID"); - else if (cmd[1] == 0x20 || cmd[1] == 0x50) - snprintf(exp, size, "ANTICOLL"); - else - snprintf(exp, size, "SELECT_XXX"); - break; - } - case ISO14443A_CMD_ANTICOLL_OR_SELECT_2: { - //95 20 = Anticollision of cascade level2 - //95 50 = Bit oriented anti-collision level2 - //95 70 = Select of cascade level2 - if (cmd[1] == 0x70) - snprintf(exp, size, "SELECT_UID-2"); - else if (cmd[1] == 0x20 || cmd[1] == 0x50) - snprintf(exp, size, "ANTICOLL-2"); - else - snprintf(exp, size, "SELECT_XXX-2"); - break; - } - case ISO14443A_CMD_ANTICOLL_OR_SELECT_3: { - //97 20 = Anticollision of cascade level3 - //97 50 = Bit oriented anti-collision level3 - //97 70 = Select of cascade level3 - if (cmd[1] == 0x70) - snprintf(exp, size, "SELECT_UID-3"); - else if (cmd[1] == 0x20 || cmd[1] == 0x50) - snprintf(exp, size, "ANTICOLL-3"); - else - snprintf(exp, size, "SELECT_XXX-3"); - break; - } - case ISO14443A_CMD_REQA: - snprintf(exp, size, "REQA"); - break; - case ISO14443A_CMD_READBLOCK: - snprintf(exp, size, "READBLOCK(%d)", cmd[1]); - break; - case ISO14443A_CMD_WRITEBLOCK: - snprintf(exp, size, "WRITEBLOCK(%d)", cmd[1]); - break; - case ISO14443A_CMD_HALT: - snprintf(exp, size, "HALT"); - MifareAuthState = masNone; - break; - case ISO14443A_CMD_RATS: - snprintf(exp, size, "RATS"); - break; - case ISO14443A_CMD_PPS: - snprintf(exp, size, "PPS"); - break; - case ISO14443A_CMD_OPTS: - snprintf(exp, size, "OPTIONAL TIMESLOT"); - break; - case MIFARE_CMD_INC: - snprintf(exp, size, "INC(%d)", cmd[1]); - break; - case MIFARE_CMD_DEC: - snprintf(exp, size, "DEC(%d)", cmd[1]); - break; - case MIFARE_CMD_RESTORE: - - if (cmdsize == 4) - // cmd0 == 0xC2 and cmd1 == 0xFF - // high probability its SELECT SECTOR COMMAND: - if (cmd[1] == 0xFF) { - snprintf(exp, size, "SELECT SECTOR"); - gs_ntag_i2c_state = 1; - } else { - snprintf(exp, size, "RESTORE(%d)", cmd[1]); - } else - return 0; - break; - case MIFARE_CMD_TRANSFER: - snprintf(exp, size, "TRANSFER(%d)", cmd[1]); - break; - case MIFARE_AUTH_KEYA: { - if (cmdsize > 3) { - snprintf(exp, size, "AUTH-A(%d)", cmd[1]); - MifareAuthState = masNt; - } else { - // case MIFARE_ULEV1_VERSION : both 0x60. - snprintf(exp, size, "EV1 VERSION"); + switch (cmd[0]) { + case ISO14443A_CMD_WUPA: + snprintf(exp, size, "WUPA"); + break; + case ISO14443A_CMD_ANTICOLL_OR_SELECT: { + // 93 20 = Anticollision (usage: 9320 - answer: 4bytes UID+1byte UID-bytes-xor) + // 93 50 = Bit oriented anti-collision (usage: 9350+ up to 5bytes, 9350 answer - up to 5bytes UID+BCC) + // 93 70 = Select (usage: 9370+5bytes 9370 answer - answer: 1byte SAK) + if (cmd[1] == 0x70) + snprintf(exp, size, "SELECT_UID"); + else if (cmd[1] == 0x20 || cmd[1] == 0x50) + snprintf(exp, size, "ANTICOLL"); + else + snprintf(exp, size, "SELECT_XXX"); + break; } - break; - } - case MIFARE_AUTH_KEYB: { - MifareAuthState = masNt; - snprintf(exp, size, "AUTH-B(%d)", cmd[1]); - break; - } - case MIFARE_MAGICWUPC1: - snprintf(exp, size, "MAGIC WUPC1"); - break; - case MIFARE_MAGICWUPC2: - snprintf(exp, size, "MAGIC WUPC2"); - break; - case MIFARE_MAGICWIPEC: - snprintf(exp, size, "MAGIC WIPEC"); - break; - case MIFARE_ULC_AUTH_1: - snprintf(exp, size, "AUTH "); - break; - case MIFARE_ULC_AUTH_2: - snprintf(exp, size, "AUTH_ANSW"); - break; - case MIFARE_ULEV1_AUTH: - if (cmdsize == 7) - snprintf(exp, size, "PWD-AUTH KEY: " _YELLOW_("0x%02x%02x%02x%02x"), cmd[1], cmd[2], cmd[3], cmd[4]); - else - snprintf(exp, size, "PWD-AUTH"); - break; - case MIFARE_ULEV1_FASTREAD : { - if (cmdsize >= 3 && cmd[2] <= 0xE6) - snprintf(exp, size, "READ RANGE (%d-%d)", cmd[1], cmd[2]); - else - // outside limits, useful for some tags... - snprintf(exp, size, "READ RANGE (%d-%d) (?)", cmd[1], cmd[2]); - break; - } - case MIFARE_ULC_WRITE : { - if (cmd[1] < 0x21) + case ISO14443A_CMD_ANTICOLL_OR_SELECT_2: { + //95 20 = Anticollision of cascade level2 + //95 50 = Bit oriented anti-collision level2 + //95 70 = Select of cascade level2 + if (cmd[1] == 0x70) + snprintf(exp, size, "SELECT_UID-2"); + else if (cmd[1] == 0x20 || cmd[1] == 0x50) + snprintf(exp, size, "ANTICOLL-2"); + else + snprintf(exp, size, "SELECT_XXX-2"); + break; + } + case ISO14443A_CMD_ANTICOLL_OR_SELECT_3: { + //97 20 = Anticollision of cascade level3 + //97 50 = Bit oriented anti-collision level3 + //97 70 = Select of cascade level3 + if (cmd[1] == 0x70) + snprintf(exp, size, "SELECT_UID-3"); + else if (cmd[1] == 0x20 || cmd[1] == 0x50) + snprintf(exp, size, "ANTICOLL-3"); + else + snprintf(exp, size, "SELECT_XXX-3"); + break; + } + case ISO14443A_CMD_REQA: + snprintf(exp, size, "REQA"); + break; + case ISO14443A_CMD_READBLOCK: + snprintf(exp, size, "READBLOCK(%d)", cmd[1]); + break; + case ISO14443A_CMD_WRITEBLOCK: snprintf(exp, size, "WRITEBLOCK(%d)", cmd[1]); - else - // outside limits, useful for some tags... - snprintf(exp, size, "WRITEBLOCK(%d) (?)", cmd[1]); - break; - } - case MIFARE_ULEV1_READ_CNT : { - if (cmd[1] < 5) - snprintf(exp, size, "READ CNT(%d)", cmd[1]); - else - snprintf(exp, size, "?"); - break; - } - case MIFARE_ULEV1_INCR_CNT : { - if (cmd[1] < 5) - snprintf(exp, size, "INCR(%d)", cmd[1]); - else - snprintf(exp, size, "?"); - break; - } - case MIFARE_ULEV1_READSIG: - snprintf(exp, size, "READ SIG"); - break; - case MIFARE_ULEV1_CHECKTEAR: - snprintf(exp, size, "CHK TEARING(%d)", cmd[1]); - break; - case MIFARE_ULEV1_VCSL: - snprintf(exp, size, "VCSL"); - break; - case MIFARE_ULNANO_WRITESIG: - snprintf(exp, size, "WRITE SIG"); - break; - case MIFARE_ULNANO_LOCKSIG: { - if (cmd[1] == 0) - snprintf(exp, size, "UNLOCK SIG"); - else if (cmd[1] == 2) - snprintf(exp, size, "LOCK SIG"); - else - snprintf(exp, size, "?"); - break; - } - case NTAG_I2C_FASTWRITE: - if (cmdsize == 69) - snprintf(exp, size, "FAST WRITE (%d - %d)", cmd[1], cmd[2]); - else - snprintf(exp, size, "?"); + break; + case ISO14443A_CMD_HALT: + snprintf(exp, size, "HALT"); + MifareAuthState = masNone; + break; + case ISO14443A_CMD_RATS: + snprintf(exp, size, "RATS"); + break; + case ISO14443A_CMD_PPS: + snprintf(exp, size, "PPS"); + break; + case ISO14443A_CMD_OPTS: + snprintf(exp, size, "OPTIONAL TIMESLOT"); + break; + case MIFARE_CMD_INC: + snprintf(exp, size, "INC(%d)", cmd[1]); + break; + case MIFARE_CMD_DEC: + snprintf(exp, size, "DEC(%d)", cmd[1]); + break; + case MIFARE_CMD_RESTORE: - break; - default: - return 0; + if (cmdsize == 4) + // cmd0 == 0xC2 and cmd1 == 0xFF + // high probability its SELECT SECTOR COMMAND: + if (cmd[1] == 0xFF) { + snprintf(exp, size, "SELECT SECTOR"); + gs_ntag_i2c_state = 1; + } else { + snprintf(exp, size, "RESTORE(%d)", cmd[1]); + } else + return 0; + break; + case MIFARE_CMD_TRANSFER: + snprintf(exp, size, "TRANSFER(%d)", cmd[1]); + break; + case MIFARE_AUTH_KEYA: { + if (cmdsize > 3) { + snprintf(exp, size, "AUTH-A(%d)", cmd[1]); + MifareAuthState = masNt; + } else { + // case MIFARE_ULEV1_VERSION : both 0x60. + snprintf(exp, size, "EV1 VERSION"); + } + break; + } + case MIFARE_AUTH_KEYB: { + MifareAuthState = masNt; + snprintf(exp, size, "AUTH-B(%d)", cmd[1]); + break; + } + case MIFARE_MAGICWUPC1: + snprintf(exp, size, "MAGIC WUPC1"); + break; + case MIFARE_MAGICWUPC2: + snprintf(exp, size, "MAGIC WUPC2"); + break; + case MIFARE_MAGICWIPEC: + snprintf(exp, size, "MAGIC WIPEC"); + break; + case MIFARE_ULC_AUTH_1: + gs_mfuc_state = 1; + snprintf(exp, size, "AUTH-1 "); + break; + case MIFARE_ULC_AUTH_2: + if ((gs_mfuc_state == 2) && (cmdsize==19)){ + memcpy(gs_mfuc_authdata[1], &cmd[1], 16); + if (trace_mfuc_try_default_3des_keys(&gs_mfuc_key, gs_mfuc_state, gs_mfuc_authdata) == PM3_SUCCESS) { +// buffer too small to print the full key, +// so we give just a hint that one of the default keys was used +// snprintf(exp, size, "AUTH-2 KEY: " _YELLOW_("%s"), sprint_hex(gs_mfuc_key, 16)); + snprintf(exp, size, "AUTH-2 KEY: " _YELLOW_("%02x%02x%02x%02x..."), gs_mfuc_key[0], gs_mfuc_key[1], gs_mfuc_key[2], gs_mfuc_key[3]); + } else { + snprintf(exp, size, "AUTH-2"); + } + gs_mfuc_state = 3; + } else { + return 0; + } + break; + case MIFARE_ULEV1_AUTH: + if (cmdsize == 7) + snprintf(exp, size, "PWD-AUTH KEY: " _YELLOW_("0x%02x%02x%02x%02x"), cmd[1], cmd[2], cmd[3], cmd[4]); + else + snprintf(exp, size, "PWD-AUTH"); + break; + case MIFARE_ULEV1_FASTREAD : { + if (cmdsize >= 3 && cmd[2] <= 0xE6) + snprintf(exp, size, "READ RANGE (%d-%d)", cmd[1], cmd[2]); + else + // outside limits, useful for some tags... + snprintf(exp, size, "READ RANGE (%d-%d) (?)", cmd[1], cmd[2]); + break; + } + case MIFARE_ULC_WRITE : { + if (cmd[1] < 0x21) + snprintf(exp, size, "WRITEBLOCK(%d)", cmd[1]); + else + // outside limits, useful for some tags... + snprintf(exp, size, "WRITEBLOCK(%d) (?)", cmd[1]); + break; + } + case MIFARE_ULEV1_READ_CNT : { + if (cmd[1] < 5) + snprintf(exp, size, "READ CNT(%d)", cmd[1]); + else + snprintf(exp, size, "?"); + break; + } + case MIFARE_ULEV1_INCR_CNT : { + if (cmd[1] < 5) + snprintf(exp, size, "INCR(%d)", cmd[1]); + else + snprintf(exp, size, "?"); + break; + } + case MIFARE_ULEV1_READSIG: + snprintf(exp, size, "READ SIG"); + break; + case MIFARE_ULEV1_CHECKTEAR: + snprintf(exp, size, "CHK TEARING(%d)", cmd[1]); + break; + case MIFARE_ULEV1_VCSL: + snprintf(exp, size, "VCSL"); + break; + case MIFARE_ULNANO_WRITESIG: + snprintf(exp, size, "WRITE SIG"); + break; + case MIFARE_ULNANO_LOCKSIG: { + if (cmd[1] == 0) + snprintf(exp, size, "UNLOCK SIG"); + else if (cmd[1] == 2) + snprintf(exp, size, "LOCK SIG"); + else + snprintf(exp, size, "?"); + break; + } + case NTAG_I2C_FASTWRITE: + if (cmdsize == 69) + snprintf(exp, size, "FAST WRITE (%d - %d)", cmd[1], cmd[2]); + else + snprintf(exp, size, "?"); + + break; + default: + return 0; + } + } else { + if (gs_mfuc_state==1) { + if ((cmd[0]==0xAF) && (cmdsize==11)) { + // register RndB + memcpy(gs_mfuc_authdata[0], &cmd[1], 8); + gs_mfuc_state=2; + } else { + gs_mfuc_state=0; + } + } + if (gs_mfuc_state==3) { + if ((cmd[0]==0x00) && (cmdsize==11)) { + // register RndA' + memcpy(gs_mfuc_authdata[2], &cmd[1], 8); + if (trace_mfuc_try_default_3des_keys(&gs_mfuc_key, gs_mfuc_state, gs_mfuc_authdata) == PM3_SUCCESS) { + snprintf(exp, size, "AUTH-2 ANSW OK"); + gs_mfuc_state=0; + return 1; + } + } + gs_mfuc_state=0; + } + return 0; } return 1; } -void annotateIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { - applyIso14443a(exp, size, cmd, cmdsize); +void annotateIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response) { + applyIso14443a(exp, size, cmd, cmdsize, is_response); } void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool isResponse) { @@ -770,7 +811,7 @@ void annotateIso7816(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { // it's basically a ISO14443a tag, so try annotation from there - if (applyIso14443a(exp, size, cmd, cmdsize) == 0) { + if (applyIso14443a(exp, size, cmd, cmdsize, false) == 0) { // S-block 11xxx010 if ((cmd[0] & 0xC0) && (cmdsize == 3)) { @@ -1428,8 +1469,8 @@ void annotateMifare(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, uint8 break; } - if (!isResponse && ((MifareAuthState == masNone) || (MifareAuthState == masError))) - annotateIso14443a(exp, size, cmd, cmdsize); + if ((MifareAuthState == masNone) || (MifareAuthState == masError)) + annotateIso14443a(exp, size, cmd, cmdsize, isResponse); } diff --git a/client/src/cmdhflist.h b/client/src/cmdhflist.h index 8ee8fbb91..081b3b20f 100644 --- a/client/src/cmdhflist.h +++ b/client/src/cmdhflist.h @@ -37,7 +37,7 @@ uint8_t mifare_CRC_check(bool isResponse, uint8_t *data, uint8_t len); uint8_t iso15693_CRC_check(uint8_t *d, uint8_t n); uint8_t iclass_CRC_check(bool isResponse, uint8_t *d, uint8_t n); -int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); +int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response); void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool isResponse); void annotateIso15693(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); @@ -46,7 +46,7 @@ void annotateLegic(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); void annotateFelica(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); void annotateIso7816(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); void annotateIso14443b(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); -void annotateIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); +void annotateIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response); void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); void annotateMifare(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, uint8_t paritysize, bool isResponse); void annotateLTO(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index d9df4d5c4..e55f1060d 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -255,6 +255,65 @@ static int ulc_authentication(uint8_t *key, bool switch_off_field) { return 0; } +static int trace_mfuc_try_key(uint8_t *key, int state, uint8_t (*authdata)[16]) { + uint8_t iv[8] = {0}; + uint8_t RndB[8] = {0}; + uint8_t RndARndB[16] = {0}; + uint8_t RndA[8] = {0}; + mbedtls_des3_context ctx_des3; + switch (state) { + case 2: + mbedtls_des3_set2key_dec(&ctx_des3, key); + mbedtls_des3_crypt_cbc(&ctx_des3, MBEDTLS_DES_DECRYPT, + 8, iv, authdata[0], RndB); + mbedtls_des3_crypt_cbc(&ctx_des3, MBEDTLS_DES_DECRYPT, + 16, iv, authdata[1], RndARndB); + if ((memcmp(&RndB[1], &RndARndB[8], 7) == 0) && + (RndB[0] == RndARndB[15])) { + return PM3_SUCCESS; + } + break; + case 3: + if (key == NULL) {// if no key was found + return PM3_ESOFT; + } + memcpy(iv, authdata[0], 8); + mbedtls_des3_set2key_dec(&ctx_des3, key); + mbedtls_des3_crypt_cbc(&ctx_des3, MBEDTLS_DES_DECRYPT, + 16, iv, authdata[1], RndARndB); + mbedtls_des3_crypt_cbc(&ctx_des3, MBEDTLS_DES_DECRYPT, + 8, iv, authdata[2], RndA); + if ((memcmp(&RndARndB[1], RndA, 7) == 0) && + (RndARndB[0] == RndA[7])) { + return PM3_SUCCESS; + } + break; + default: + return PM3_EINVARG; + } + return PM3_ESOFT; +} + +int trace_mfuc_try_default_3des_keys(uint8_t **correct_key, int state, uint8_t (*authdata)[16]) { + switch (state) { + case 2: + for (uint8_t i = 0; i < ARRAYLEN(default_3des_keys); ++i) { + uint8_t *key = default_3des_keys[i]; + if (trace_mfuc_try_key(key, state, authdata) == PM3_SUCCESS) { + *correct_key = key; + return PM3_SUCCESS; + } + } + break; + case 3: + return trace_mfuc_try_key(*correct_key, state, authdata); + break; + default: + return PM3_EINVARG; + } + return PM3_ESOFT; +} + static int try_default_3des_keys(uint8_t **correct_key) { PrintAndLogEx(INFO, "Trying some default 3des keys"); for (uint8_t i = 0; i < ARRAYLEN(default_3des_keys); ++i) { diff --git a/client/src/cmdhfmfu.h b/client/src/cmdhfmfu.h index ab9ec3b7e..9a220e6ec 100644 --- a/client/src/cmdhfmfu.h +++ b/client/src/cmdhfmfu.h @@ -24,6 +24,7 @@ uint32_t GetHF14AMfU_Type(void); int ul_print_type(uint32_t tagtype, uint8_t spaces); void printMFUdumpEx(mfu_dump_t *card, uint16_t pages, uint8_t startpage); int ul_read_uid(uint8_t *uid); +int trace_mfuc_try_default_3des_keys(uint8_t **correct_key, int state, uint8_t (*authdata)[16]); int CmdHFMFUltra(const char *Cmd); int CmdHF14MfuNDEFRead(const char *Cmd); diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c index b4f4264d8..1e49ca64c 100644 --- a/client/src/cmdtrace.c +++ b/client/src/cmdtrace.c @@ -334,6 +334,10 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr // Always annotate these protocols both reader/tag messages switch (protocol) { + case ISO_14443A: + case ISO_7816_4: + annotateIso14443a(explanation, sizeof(explanation), frame, data_len, hdr->isResponse); + break; case PROTO_MIFARE: annotateMifare(explanation, sizeof(explanation), frame, data_len, parityBytes, TRACELOG_PARITY_LEN(hdr), hdr->isResponse); break; @@ -359,9 +363,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr case LEGIC: annotateLegic(explanation, sizeof(explanation), frame, data_len); break; - case ISO_14443A: - annotateIso14443a(explanation, sizeof(explanation), frame, data_len); - break; case MFDES: annotateMfDesfire(explanation, sizeof(explanation), frame, data_len); break; @@ -372,7 +373,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr annotateTopaz(explanation, sizeof(explanation), frame, data_len); break; case ISO_7816_4: - annotateIso14443a(explanation, sizeof(explanation), frame, data_len); annotateIso7816(explanation, sizeof(explanation), frame, data_len); break; case ISO_15693: @@ -466,9 +466,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr if (protocol == PROTO_MIFARE) { if (DecodeMifareData(frame, data_len, parityBytes, hdr->isResponse, mfData, &mfDataLen, mfDicKeys, mfDicKeysCount)) { memset(explanation, 0x00, sizeof(explanation)); - if (hdr->isResponse == false) { - annotateIso14443a(explanation, sizeof(explanation), mfData, mfDataLen); - } + annotateIso14443a(explanation, sizeof(explanation), mfData, mfDataLen, hdr->isResponse); uint8_t crcc = iso14443A_CRC_check(hdr->isResponse, mfData, mfDataLen); PrintAndLogEx(NORMAL, " | | * |%-72s | %-4s| %s", sprint_hex_inrow_spaces(mfData, mfDataLen, 2),