diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 061dfe9ae..792d73400 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -899,13 +899,15 @@ bool GetIso14443aCommandFromReader(uint8_t *received, uint8_t *par, int *len) { uint16_t check = 0; for (;;) { - if (check == 1000) { - if (BUTTON_PRESS() || data_available()) + if (check == 4000) { +// if (BUTTON_PRESS() || data_available()) + if (BUTTON_PRESS()) return false; + check = 0; + WDT_HIT(); } ++check; - WDT_HIT(); if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; @@ -981,11 +983,15 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i // Prepare the optional second SAK (for 7 byte UID), drop the cascade bit static uint8_t rSAKc2[3] = { 0x00 }; // dummy ATS (pseudo-ATR), answer to RATS - static uint8_t rRATS[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 }; +// static uint8_t rRATS[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 }; + static uint8_t rRATS[] = { 0x05, 0x75, 0x80, 0x60, 0x02, 0x00, 0x00 }; + // GET_VERSION response for EV1/NTAG static uint8_t rVERSION[10] = { 0x00 }; // READ_SIG response for EV1/NTAG static uint8_t rSIGN[34] = { 0x00 }; + // PPS respoonse + static uint8_t rPPS[3] = { 0xD0 }; switch (tagType) { case 1: { // MIFARE Classic 1k @@ -1059,12 +1065,19 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i sak = 0x18; } break; - case 9 : { // FM11RF005SH (Shanghai Metro) + case 9: { // FM11RF005SH (Shanghai Metro) rATQA[0] = 0x03; rATQA[1] = 0x00; sak = 0x0A; } break; + case 10: { // JCOP31/41 Rothult + rATQA[0] = 0x42; + rATQA[1] = 0x00; + sak = 0x00; + } + break; + default: { if (DBGLEVEL >= DBG_ERROR) Dbprintf("Error: unknown tagtype (%d)", tagType); return false; @@ -1115,13 +1128,20 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i return false; } - // Calculate the BitCountCheck (BCC) for the first 4 bytes of the UID. + // Calculate BCC for the first 4 bytes of the UID. rUIDc1[4] = rUIDc1[0] ^ rUIDc1[1] ^ rUIDc1[2] ^ rUIDc1[3]; - rSAKc1[0] = sak; - AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2); + + if (tagType == 10) { + rSAKc1[0] = 0x04; + rSAKc2[0] = 0x20; + } else { + rSAKc1[0] = sak; + rSAKc2[0] = sak & 0xFB; + } - rSAKc2[0] = sak & 0xFB; + // crc + AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2); AddCrc14A(rSAKc2, sizeof(rSAKc2) - 2); // Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present, @@ -1130,22 +1150,26 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i // TC(1) = 0x02: CID supported, NAD not supported AddCrc14A(rRATS, sizeof(rRATS) - 2); -#define TAG_RESPONSE_COUNT 8 + AddCrc14A(rPPS, sizeof(rPPS) - 2); + +#define TAG_RESPONSE_COUNT 9 static tag_response_info_t responses_init[TAG_RESPONSE_COUNT] = { - { .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type - { .response = rUIDc1, .response_n = sizeof(rUIDc1) }, // Anticollision cascade1 - respond with uid - { .response = rUIDc2, .response_n = sizeof(rUIDc2) }, // Anticollision cascade2 - respond with 2nd half of uid if asked - { .response = rSAKc1, .response_n = sizeof(rSAKc1) }, // Acknowledge select - cascade 1 - { .response = rSAKc2, .response_n = sizeof(rSAKc2) }, // Acknowledge select - cascade 2 - { .response = rRATS, .response_n = sizeof(rRATS) }, // dummy ATS (pseudo-ATR), answer to RATS - { .response = rVERSION, .response_n = sizeof(rVERSION) }, // EV1/NTAG GET_VERSION response - { .response = rSIGN, .response_n = sizeof(rSIGN) } // EV1/NTAG READ_SIG response + { .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type + { .response = rUIDc1, .response_n = sizeof(rUIDc1) }, // Anticollision cascade1 - respond with uid + { .response = rUIDc2, .response_n = sizeof(rUIDc2) }, // Anticollision cascade2 - respond with 2nd half of uid if asked + { .response = rSAKc1, .response_n = sizeof(rSAKc1) }, // Acknowledge select - cascade 1 + { .response = rSAKc2, .response_n = sizeof(rSAKc2) }, // Acknowledge select - cascade 2 + { .response = rRATS, .response_n = sizeof(rRATS) }, // dummy ATS (pseudo-ATR), answer to RATS + { .response = rVERSION, .response_n = sizeof(rVERSION) }, // EV1/NTAG GET_VERSION response + { .response = rSIGN, .response_n = sizeof(rSIGN) }, // EV1/NTAG READ_SIG response + { .response = rPPS, .response_n = sizeof(rPPS) } // PPS response }; - // "precompile" responses. There are 8 predefined responses with a total of 68 bytes data to transmit. + // "precompile" responses. There are 9 predefined responses with a total of 72 bytes data to transmit. // Coded responses need one byte per bit to transfer (data, parity, start, stop, correction) - // 68 * 8 data bits, 68 * 1 parity bits, 8 start bits, 8 stop bits, 8 correction bits -- 636 bytes buffer -#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 636 + // 72 * 8 data bits, 72 * 1 parity bits, 9 start bits, 9 stop bits, 9 correction bits -- 677 bytes buffer +#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 675 +// 576 + 72 + 9 + 9 + 9 == 675 uint8_t *free_buffer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE); // modulation buffer pointer and current buffer free space size @@ -1173,7 +1197,7 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i #define RATS 5 #define VERSION 6 #define SIGNATURE 7 - +#define PPS 8 return true; } @@ -1232,6 +1256,8 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) { // We need to listen to the high-frequency, peak-detected path. iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); + iso14a_set_timeout(201400); // 106 * 19ms default + int len = 0; // To control where we are in the protocol @@ -1246,8 +1272,8 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) { #define ORDER_SELECT_CL2 30 #define ORDER_EV1_COMP_WRITE 40 #define ORDER_RATS 70 - uint8_t order = ORDER_NONE; + uint8_t order = ORDER_NONE; int retval = PM3_SUCCESS; // Just to allow some checks @@ -1257,28 +1283,27 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) { // compatible write block number uint8_t wrblock = 0; + + bool odd_reply = true; clear_trace(); set_tracing(true); LED_A_ON(); + + // main loop for (;;) { WDT_HIT(); + tag_response_info_t *p_response = NULL; + // Clean receive command buffer - if (!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) { - Dbprintf("Emulator stopped. Trace length: %d ", BigBuf_get_traceLen()); + if (GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len) == false) { + Dbprintf("Emulator stopped. Trace length: %d ", BigBuf_get_traceLen()); retval = PM3_EOPABORTED; break; } - tag_response_info_t *p_response = NULL; - // Okay, look at the command now. - int lastorder = order; - - // // we need to check "ordered" states before, because received data may be same to any command - is wrong!!! - // - if (order == ORDER_EV1_COMP_WRITE && len == 18) { // MIFARE_ULC_COMP_WRITE part 2 // 16 bytes data + 2 bytes crc, only least significant 4 bytes are written @@ -1361,28 +1386,22 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) { order = ORDER_NONE; // back to work state p_response = NULL; - // - // now check commands in received buffer - // - - } else if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST - p_response = &responses[ATQA]; - order = ORDER_REQA; + } else if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST, but in HALTED, skip + odd_reply = !odd_reply; + if (odd_reply) + p_response = &responses[ATQA]; } else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { // Received a WAKEUP p_response = &responses[ATQA]; - order = ORDER_WUPA; } else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { // Received request for UID (cascade 1) p_response = &responses[UIDC1]; - order = ORDER_SELECT_ALL_CL1; } else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 2) { // Received request for UID (cascade 2) p_response = &responses[UIDC2]; - order = ORDER_SELECT_ALL_CL2; } else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1) p_response = &responses[SAKC1]; - order = ORDER_SELECT_CL1; } else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 9) { // Received a SELECT (cascade 2) p_response = &responses[SAKC2]; - order = ORDER_SELECT_CL2; + } else if (receivedCmd[0] == ISO14443A_CMD_PPS) { + p_response = &responses[PPS]; } else if (receivedCmd[0] == ISO14443A_CMD_READBLOCK && len == 4) { // Received a (plain) READ uint8_t block = receivedCmd[1]; // if Ultralight or NTAG (4 byte blocks) @@ -1410,8 +1429,6 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) { emlGetMemBt(emdata, block, 16); AddCrc14A(emdata, 16); EmSendCmd(emdata, sizeof(emdata)); - // EmSendCmd(data+(4*receivedCmd[1]),16); - // Dbprintf("Read request from reader: %x %x",receivedCmd[0],receivedCmd[1]); // We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below p_response = NULL; } @@ -1433,8 +1450,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) { p_response = NULL; } else if (receivedCmd[0] == MIFARE_ULC_WRITE && len == 8 && (tagType == 2 || tagType == 7)) { // Received a WRITE // cmd + block + 4 bytes data + 2 bytes crc - bool isCrcCorrect = CheckCrc14A(receivedCmd, len); - if (isCrcCorrect) { + if (CheckCrc14A(receivedCmd, len)) { uint8_t block = receivedCmd[1]; if (block > pages) { // send NACK 0x0 == invalid argument @@ -1452,8 +1468,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) { p_response = NULL; } else if (receivedCmd[0] == MIFARE_ULC_COMP_WRITE && len == 4 && (tagType == 2 || tagType == 7)) { // cmd + block + 2 bytes crc - bool isCrcCorrect = CheckCrc14A(receivedCmd, len); - if (isCrcCorrect) { + if (CheckCrc14A(receivedCmd, len)) { wrblock = receivedCmd[1]; if (wrblock > pages) { // send NACK 0x0 == invalid argument @@ -1538,7 +1553,6 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) { p_response = NULL; } else { p_response = &responses[RATS]; - order = ORDER_RATS; } } else if (receivedCmd[0] == MIFARE_ULC_AUTH_1) { // ULC authentication, or Desfire Authentication LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); @@ -1566,73 +1580,103 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) { AddCrc14A(cmd, sizeof(cmd) - 2); EmSendCmd(cmd, sizeof(cmd)); p_response = NULL; + } else { - // Check for ISO 14443A-4 compliant commands, look at left nibble - switch (receivedCmd[0]) { - case 0x02: - case 0x03: { // IBlock (command no CID) + + // clear old dynamic responses + dynamic_response_info.response_n = 0; + dynamic_response_info.modulation_n = 0; + + // ST25TA512B IKEA Rothult + if (tagType == 10) { + // we replay 90 00 for all commands but the read bin and we deny the verify cmd. + + if (memcmp("\x02\xa2\xb0\x00\x00\x1d\x51\x69", receivedCmd, 8) == 0) { + dynamic_response_info.response[0] = receivedCmd[0]; + memcpy(dynamic_response_info.response + 1, "\x00\x1b\xd1\x01\x17\x54\x02\x7a\x68\xa2\x34\xcb\xd0\xe2\x03\xc7\x3e\x62\x0b\xe8\xc6\x3c\x85\x2c\xc5\x31\x31\x31\x32\x90\x00", 31); + dynamic_response_info.response_n = 32; + } else if (memcmp("\x02\x00\x20\x00\x01\x00\x6e\xa9", receivedCmd, 8) == 0) { + dynamic_response_info.response[0] = receivedCmd[0]; + dynamic_response_info.response[1] = 0x63; + dynamic_response_info.response[2] = 0x00; + dynamic_response_info.response_n = 3; + } else { dynamic_response_info.response[0] = receivedCmd[0]; dynamic_response_info.response[1] = 0x90; dynamic_response_info.response[2] = 0x00; dynamic_response_info.response_n = 3; } - break; - case 0x0B: - case 0x0A: { // IBlock (command CID) - dynamic_response_info.response[0] = receivedCmd[0]; - dynamic_response_info.response[1] = 0x00; - dynamic_response_info.response[2] = 0x90; - dynamic_response_info.response[3] = 0x00; - dynamic_response_info.response_n = 4; - } - break; + } else { - case 0x1A: - case 0x1B: { // Chaining command - dynamic_response_info.response[0] = 0xaa | ((receivedCmd[0]) & 1); - dynamic_response_info.response_n = 2; - } - break; - - case 0xAA: - case 0xBB: { - dynamic_response_info.response[0] = receivedCmd[0] ^ 0x11; - dynamic_response_info.response_n = 2; - } - break; - - case 0xBA: { // ping / pong - dynamic_response_info.response[0] = 0xAB; - dynamic_response_info.response[1] = 0x00; - dynamic_response_info.response_n = 2; - } - break; - - case 0xCA: - case 0xC2: { // Readers sends deselect command - dynamic_response_info.response[0] = 0xCA; - dynamic_response_info.response[1] = 0x00; - dynamic_response_info.response_n = 2; - } - break; - - default: { - // Never seen this command before - LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); - if (DBGLEVEL >= DBG_DEBUG) { - Dbprintf("Received unknown command (len=%d):", len); - Dbhexdump(len, receivedCmd, false); + // Check for ISO 14443A-4 compliant commands, look at left nibble + switch (receivedCmd[0]) { + case 0x02: + case 0x03: { // IBlock (command no CID) + dynamic_response_info.response[0] = receivedCmd[0]; + dynamic_response_info.response[1] = 0x90; + dynamic_response_info.response[2] = 0x00; + dynamic_response_info.response_n = 3; } - // Do not respond - dynamic_response_info.response_n = 0; - order = ORDER_NONE; // back to work state - } - break; - } + break; + case 0x0B: + case 0x0A: { // IBlock (command CID) + dynamic_response_info.response[0] = receivedCmd[0]; + dynamic_response_info.response[1] = 0x00; + dynamic_response_info.response[2] = 0x90; + dynamic_response_info.response[3] = 0x00; + dynamic_response_info.response_n = 4; + } + break; + case 0x1A: + case 0x1B: { // Chaining command + dynamic_response_info.response[0] = 0xaa | ((receivedCmd[0]) & 1); + dynamic_response_info.response_n = 2; + } + break; + + case 0xAA: + case 0xBB: { + dynamic_response_info.response[0] = receivedCmd[0] ^ 0x11; + dynamic_response_info.response_n = 2; + } + break; + + case 0xBA: { // ping / pong + dynamic_response_info.response[0] = 0xAB; + dynamic_response_info.response[1] = 0x00; + dynamic_response_info.response_n = 2; + } + break; + + case 0xCA: + case 0xC2: { // Readers sends deselect command + dynamic_response_info.response[0] = 0xCA; + dynamic_response_info.response[1] = 0x00; + dynamic_response_info.response_n = 2; + } + break; + + default: { + // Never seen this command before + LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); + if (DBGLEVEL >= DBG_DEBUG) { + Dbprintf("Received unknown command (len=%d):", len); + Dbhexdump(len, receivedCmd, false); + } + // Do not respond + dynamic_response_info.response_n = 0; + order = ORDER_NONE; // back to work state + } + break; + } + + } if (dynamic_response_info.response_n > 0) { + // Copy the CID from the reader query - dynamic_response_info.response[1] = receivedCmd[1]; + if (tagType != 10) + dynamic_response_info.response[1] = receivedCmd[1]; // Add CRC bytes, always used in ISO 14443A-4 compliant cards AddCrc14A(dynamic_response_info.response, dynamic_response_info.response_n); @@ -1648,16 +1692,15 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) { } // Count number of wakeups received after a halt - if (order == ORDER_WUPA && lastorder == ORDER_HALTED) { happened++; } +// if (order == ORDER_WUPA && lastorder == ORDER_HALTED) { happened++; } // Count number of other messages after a halt - if (order != ORDER_WUPA && lastorder == ORDER_HALTED) { happened2++; } +// if (order != ORDER_WUPA && lastorder == ORDER_HALTED) { happened2++; } cmdsRecvd++; - if (p_response != NULL) { - EmSendPrecompiledCmd(p_response); - } + // Send response + EmSendPrecompiledCmd(p_response); } switch_off(); @@ -1958,7 +2001,7 @@ int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) { volatile uint8_t b; uint16_t i = 0; uint32_t ThisTransferTime; - bool correctionNeeded; + bool correction_needed; // Modulate Manchester FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD); @@ -1966,21 +2009,23 @@ int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) { // Include correction bit if necessary if (Uart.bitCount == 7) { // Short tags (7 bits) don't have parity, determine the correct value from MSB - correctionNeeded = Uart.output[0] & 0x40; + correction_needed = Uart.output[0] & 0x40; } else { // The parity bits are left-aligned - correctionNeeded = Uart.parity[(Uart.len - 1) / 8] & (0x80 >> ((Uart.len - 1) & 7)); + correction_needed = Uart.parity[(Uart.len - 1) / 8] & (0x80 >> ((Uart.len - 1) & 7)); } // 1236, so correction bit needed - i = (correctionNeeded) ? 0 : 1; + i = (correction_needed) ? 0 : 1; // clear receiving shift register and holding register while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); b = AT91C_BASE_SSC->SSC_RHR; (void) b; - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); - b = AT91C_BASE_SSC->SSC_RHR; +/* + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY)); + b = AT91C_BASE_SSC->SSC_THR; (void) b; +*/ // wait for the FPGA to signal fdt_indicator == 1 (the FPGA is ready to queue new data in its delay line) for (uint8_t j = 0; j < 5; j++) { // allow timeout - better late than never @@ -2000,22 +2045,24 @@ int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) { FpgaSendQueueDelay = (uint8_t)AT91C_BASE_SSC->SSC_RHR; } +/* if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { b = (uint16_t)(AT91C_BASE_SSC->SSC_RHR); (void)b; } + */ } // Ensure that the FPGA Delay Queue is empty before we switch to TAGSIM_LISTEN again: uint8_t fpga_queued_bits = FpgaSendQueueDelay >> 3; - for (i = 0; i <= fpga_queued_bits / 8 + 1;) { + for (i = 0; i <= (fpga_queued_bits >> 3) + 1;) { if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { AT91C_BASE_SSC->SSC_THR = SEC_F; FpgaSendQueueDelay = (uint8_t)AT91C_BASE_SSC->SSC_RHR; i++; } } - LastTimeProxToAirStart = ThisTransferTime + (correctionNeeded ? 8 : 0); + LastTimeProxToAirStart = ThisTransferTime + (correction_needed ? 8 : 0); return 0; } @@ -2069,6 +2116,7 @@ int EmSendCmdEx(uint8_t *resp, uint16_t respLen, bool collision) { } int EmSendPrecompiledCmd(tag_response_info_t *p_response) { + if (p_response == NULL) return 0; int ret = EmSendCmd14443aRaw(p_response->modulation, p_response->modulation_n); // do the tracing for the previous reader request and this tag answer: uint8_t par[MAX_PARITY_SIZE] = {0x00}; diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 4a53ef021..f8fc02f8f 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -201,6 +201,7 @@ static int usage_hf_14a_sim(void) { PrintAndLogEx(NORMAL, " 7 = AMIIBO (NTAG 215), pack 0x8080"); PrintAndLogEx(NORMAL, " 8 = MIFARE Classic 4k"); PrintAndLogEx(NORMAL, " 9 = FM11RF005SH Shanghai Metro"); + PrintAndLogEx(NORMAL, " 10 = JCOP 31/41 Rothult"); // PrintAndLogEx(NORMAL, " u : 4, 7 or 10 byte UID"); PrintAndLogEx(NORMAL, " u : 4, 7 byte UID"); PrintAndLogEx(NORMAL, " x : (Optional) Performs the 'reader attack', nr/ar attack against a reader");