hf 14a sim t 10 - possibility to simulate IKEA rothult locks

This commit is contained in:
iceman1001 2020-09-10 00:05:50 +02:00
parent a785d7ea77
commit 420b29c7bf
2 changed files with 169 additions and 120 deletions

View file

@ -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};

View file

@ -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");