Add support for 10b UID in hf 14a sim

This commit is contained in:
Philippe Teuwen 2020-11-03 01:57:12 +01:00
commit c03daf233c
4 changed files with 100 additions and 57 deletions

View file

@ -5,7 +5,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
## [unreleased][unreleased] ## [unreleased][unreleased]
- Change many commands to cliparser (@iceman1001, @tcprst, @mwalker33,...) - Change many commands to cliparser (@iceman1001, @tcprst, @mwalker33,...)
- ... - ...
- Added `HF_TCPRST` standalone mode which read and emulate IKEA Rothult cards (@tcprst) - Added support for 10b UID in `hf 14a sim` (@doegox)
- Added `HF_TCPRST` standalone mode which read and emulate IKEA Rothult cards (@tcprst)
- Add Gallagher key checking/KDF on MIFARE Desfire (@NZSmartie) - Add Gallagher key checking/KDF on MIFARE Desfire (@NZSmartie)
- Add dictionaries with common words of proper size (@will-caruana) - Add dictionaries with common words of proper size (@will-caruana)
- Add `hf mf supercard` (@iceman1001) - Add `hf mf supercard` (@iceman1001)

View file

@ -94,11 +94,14 @@ void RunMod(void) {
#define ATQA 0 #define ATQA 0
#define UIDC1 1 #define UIDC1 1
#define UIDC2 2 #define UIDC2 2
#define SAKC1 3 #define UIDC3 3
#define SAKC2 4 #define SAKC1 4
#define RATS 5 #define SAKC2 5
#define SIGNATURE 7 #define SAKC3 6
#define PPS 8 #define RATS 7
#define VERSION 8
#define SIGNATURE 9
#define PPS 10
//ST25TA Rothult values //ST25TA Rothult values
#define SAK 0x20 #define SAK 0x20

View file

@ -1005,10 +1005,14 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
static uint8_t rUIDc1[5] = { 0x00 }; static uint8_t rUIDc1[5] = { 0x00 };
// For UID size 7, // For UID size 7,
static uint8_t rUIDc2[5] = { 0x00 }; static uint8_t rUIDc2[5] = { 0x00 };
// Prepare the mandatory SAK (for 4 and 7 byte UID) // For UID size 10,
static uint8_t rUIDc3[5] = { 0x00 };
// Prepare the mandatory SAK (for 4, 7 and 10 byte UID)
static uint8_t rSAKc1[3] = { 0x00 }; static uint8_t rSAKc1[3] = { 0x00 };
// Prepare the optional second SAK (for 7 byte UID), drop the cascade bit // Prepare the optional second SAK (for 7 and 10 byte UID), drop the cascade bit for 7b
static uint8_t rSAKc2[3] = { 0x00 }; static uint8_t rSAKc2[3] = { 0x00 };
// Prepare the optional third SAK (for 10 byte UID), drop the cascade bit
static uint8_t rSAKc3[3] = { 0x00 };
// dummy ATS (pseudo-ATR), answer to RATS // 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 }; static uint8_t rRATS[] = { 0x05, 0x75, 0x80, 0x60, 0x02, 0x00, 0x00 };
@ -1017,7 +1021,7 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
static uint8_t rVERSION[10] = { 0x00 }; static uint8_t rVERSION[10] = { 0x00 };
// READ_SIG response for EV1/NTAG // READ_SIG response for EV1/NTAG
static uint8_t rSIGN[34] = { 0x00 }; static uint8_t rSIGN[34] = { 0x00 };
// PPS respoonse // PPS response
static uint8_t rPPS[3] = { 0xD0 }; static uint8_t rPPS[3] = { 0xD0 };
switch (tagType) { switch (tagType) {
@ -1101,7 +1105,7 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
case 10: { // ST25TA IKEA Rothult case 10: { // ST25TA IKEA Rothult
rATQA[0] = 0x42; rATQA[0] = 0x42;
rATQA[1] = 0x00; rATQA[1] = 0x00;
sak = 0x00; sak = 0x20;
} }
break; break;
@ -1127,11 +1131,25 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
} }
} }
if ((flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA) { if ((flags & FLAG_4B_UID_IN_DATA) == FLAG_4B_UID_IN_DATA) {
rUIDc1[0] = data[0];
rUIDc1[1] = data[1];
rUIDc1[2] = data[2];
rUIDc1[3] = data[3];
rUIDc1[4] = rUIDc1[0] ^ rUIDc1[1] ^ rUIDc1[2] ^ rUIDc1[3];
// Configure the ATQA and SAK accordingly
rATQA[0] &= 0xBF;
rSAKc1[0] = sak & 0xFB;
AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2);
*cuid = bytes_to_num(data, 4);
} else if ((flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA) {
rUIDc1[0] = 0x88; // Cascade Tag marker rUIDc1[0] = 0x88; // Cascade Tag marker
rUIDc1[1] = data[0]; rUIDc1[1] = data[0];
rUIDc1[2] = data[1]; rUIDc1[2] = data[1];
rUIDc1[3] = data[2]; rUIDc1[3] = data[2];
rUIDc1[4] = rUIDc1[0] ^ rUIDc1[1] ^ rUIDc1[2] ^ rUIDc1[3];
rUIDc2[0] = data[3]; rUIDc2[0] = data[3];
rUIDc2[1] = data[4]; rUIDc2[1] = data[4];
@ -1140,37 +1158,49 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
rUIDc2[4] = rUIDc2[0] ^ rUIDc2[1] ^ rUIDc2[2] ^ rUIDc2[3]; rUIDc2[4] = rUIDc2[0] ^ rUIDc2[1] ^ rUIDc2[2] ^ rUIDc2[3];
// Configure the ATQA and SAK accordingly // Configure the ATQA and SAK accordingly
rATQA[0] &= 0xBF;
rATQA[0] |= 0x40; rATQA[0] |= 0x40;
sak |= 0x04; rSAKc1[0] = 0x04;
rSAKc2[0] = sak & 0xFB;
AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2);
AddCrc14A(rSAKc2, sizeof(rSAKc2) - 2);
*cuid = bytes_to_num(data + 3, 4); *cuid = bytes_to_num(data + 3, 4);
} else if ((flags & FLAG_4B_UID_IN_DATA) == FLAG_4B_UID_IN_DATA) { } else if ((flags & FLAG_10B_UID_IN_DATA) == FLAG_10B_UID_IN_DATA) {
memcpy(rUIDc1, data, 4); rUIDc1[0] = 0x88; // Cascade Tag marker
rUIDc1[1] = data[0];
rUIDc1[2] = data[1];
rUIDc1[3] = data[2];
rUIDc1[4] = rUIDc1[0] ^ rUIDc1[1] ^ rUIDc1[2] ^ rUIDc1[3];
rUIDc2[0] = 0x88; // Cascade Tag marker
rUIDc2[1] = data[3];
rUIDc2[2] = data[4];
rUIDc2[3] = data[5];
rUIDc2[4] = rUIDc2[0] ^ rUIDc2[1] ^ rUIDc2[2] ^ rUIDc2[3];
rUIDc3[0] = data[6];
rUIDc3[1] = data[7];
rUIDc3[2] = data[8];
rUIDc3[3] = data[9];
rUIDc3[4] = rUIDc3[0] ^ rUIDc3[1] ^ rUIDc3[2] ^ rUIDc3[3];
// Configure the ATQA and SAK accordingly // Configure the ATQA and SAK accordingly
rATQA[0] &= 0xBF; rATQA[0] &= 0xBF;
sak &= 0xFB; rATQA[0] |= 0x80;
*cuid = bytes_to_num(data, 4); rSAKc1[0] = 0x04;
rSAKc2[0] = 0x04;
rSAKc3[0] = sak & 0xFB;
AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2);
AddCrc14A(rSAKc2, sizeof(rSAKc2) - 2);
AddCrc14A(rSAKc3, sizeof(rSAKc3) - 2);
*cuid = bytes_to_num(data + 3 + 3, 4);
} else { } else {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("[-] ERROR: UID size not defined"); if (DBGLEVEL >= DBG_ERROR) Dbprintf("[-] ERROR: UID size not defined");
return false; return false;
} }
// Calculate BCC for the first 4 bytes of the UID.
rUIDc1[4] = rUIDc1[0] ^ rUIDc1[1] ^ rUIDc1[2] ^ rUIDc1[3];
if (tagType == 10) {
rSAKc1[0] = 0x04;
rSAKc2[0] = 0x20;
} else {
rSAKc1[0] = sak;
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, // Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present,
// TA(1) = 0x80: different divisors not supported, DR = 1, DS = 1 // TA(1) = 0x80: different divisors not supported, DR = 1, DS = 1
// TB(1) = not present. Defaults: FWI = 4 (FWT = 256 * 16 * 2^4 * 1/fc = 4833us), SFGI = 0 (SFG = 256 * 16 * 2^0 * 1/fc = 302us) // TB(1) = not present. Defaults: FWI = 4 (FWT = 256 * 16 * 2^4 * 1/fc = 4833us), SFGI = 0 (SFG = 256 * 16 * 2^0 * 1/fc = 302us)
@ -1179,24 +1209,25 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
AddCrc14A(rPPS, sizeof(rPPS) - 2); AddCrc14A(rPPS, sizeof(rPPS) - 2);
#define TAG_RESPONSE_COUNT 9 static tag_response_info_t responses_init[] = {
static tag_response_info_t responses_init[TAG_RESPONSE_COUNT] = {
{ .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type { .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 = 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 = rUIDc2, .response_n = sizeof(rUIDc2) }, // Anticollision cascade2 - respond with 2nd half of uid if asked
{ .response = rUIDc3, .response_n = sizeof(rUIDc3) }, // Anticollision cascade3 - respond with 3rd half of uid if asked
{ .response = rSAKc1, .response_n = sizeof(rSAKc1) }, // Acknowledge select - cascade 1 { .response = rSAKc1, .response_n = sizeof(rSAKc1) }, // Acknowledge select - cascade 1
{ .response = rSAKc2, .response_n = sizeof(rSAKc2) }, // Acknowledge select - cascade 2 { .response = rSAKc2, .response_n = sizeof(rSAKc2) }, // Acknowledge select - cascade 2
{ .response = rSAKc3, .response_n = sizeof(rSAKc3) }, // Acknowledge select - cascade 3
{ .response = rRATS, .response_n = sizeof(rRATS) }, // dummy ATS (pseudo-ATR), answer to RATS { .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 = rVERSION, .response_n = sizeof(rVERSION) }, // EV1/NTAG GET_VERSION response
{ .response = rSIGN, .response_n = sizeof(rSIGN) }, // EV1/NTAG READ_SIG response { .response = rSIGN, .response_n = sizeof(rSIGN) }, // EV1/NTAG READ_SIG response
{ .response = rPPS, .response_n = sizeof(rPPS) } // PPS response { .response = rPPS, .response_n = sizeof(rPPS) } // PPS response
}; };
// "precompile" responses. There are 9 predefined responses with a total of 72 bytes data to transmit. // "precompile" responses. There are 11 predefined responses with a total of 80 bytes data to transmit.
// Coded responses need one byte per bit to transfer (data, parity, start, stop, correction) // Coded responses need one byte per bit to transfer (data, parity, start, stop, correction)
// 72 * 8 data bits, 72 * 1 parity bits, 9 start bits, 9 stop bits, 9 correction bits -- 677 bytes buffer // 80 * 8 data bits, 80 * 1 parity bits, 11 start bits, 11 stop bits, 11 correction bits
#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 675 // 80 * 8 + 80 + 11 + 11 + 11 == 753
// 576 + 72 + 9 + 9 + 9 == 675 #define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 753
uint8_t *free_buffer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE); uint8_t *free_buffer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE);
// modulation buffer pointer and current buffer free space size // modulation buffer pointer and current buffer free space size
@ -1205,7 +1236,7 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
// Prepare the responses of the anticollision phase // Prepare the responses of the anticollision phase
// there will be not enough time to do this at the moment the reader sends it REQA // there will be not enough time to do this at the moment the reader sends it REQA
for (size_t i = 0; i < TAG_RESPONSE_COUNT; i++) { for (size_t i = 0; i < ARRAYLEN(responses_init); i++) {
if (prepare_allocated_tag_modulation(&responses_init[i], &free_buffer_pointer, &free_buffer_size) == false) { if (prepare_allocated_tag_modulation(&responses_init[i], &free_buffer_pointer, &free_buffer_size) == false) {
BigBuf_free_keep_EM(); BigBuf_free_keep_EM();
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Not enough modulation buffer size, exit after %d elements", i); if (DBGLEVEL >= DBG_ERROR) Dbprintf("Not enough modulation buffer size, exit after %d elements", i);
@ -1219,12 +1250,14 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
#define ATQA 0 #define ATQA 0
#define UIDC1 1 #define UIDC1 1
#define UIDC2 2 #define UIDC2 2
#define SAKC1 3 #define UIDC3 3
#define SAKC2 4 #define SAKC1 4
#define RATS 5 #define SAKC2 5
#define VERSION 6 #define SAKC3 6
#define SIGNATURE 7 #define RATS 7
#define PPS 8 #define VERSION 8
#define SIGNATURE 9
#define PPS 10
return true; return true;
} }
@ -1289,16 +1322,18 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
// To control where we are in the protocol // To control where we are in the protocol
#define ORDER_NONE 0 #define ORDER_NONE 0
#define ORDER_REQA 1 //#define ORDER_REQA 1
#define ORDER_SELECT_ALL_CL1 2 //#define ORDER_SELECT_ALL_CL1 2
#define ORDER_SELECT_CL1 3 //#define ORDER_SELECT_CL1 3
#define ORDER_HALTED 5 #define ORDER_HALTED 5
#define ORDER_WUPA 6 #define ORDER_WUPA 6
#define ORDER_AUTH 7 #define ORDER_AUTH 7
#define ORDER_SELECT_ALL_CL2 20 //#define ORDER_SELECT_ALL_CL2 20
#define ORDER_SELECT_CL2 30 //#define ORDER_SELECT_CL2 25
//#define ORDER_SELECT_ALL_CL3 30
//#define ORDER_SELECT_CL3 35
#define ORDER_EV1_COMP_WRITE 40 #define ORDER_EV1_COMP_WRITE 40
#define ORDER_RATS 70 //#define ORDER_RATS 70
uint8_t order = ORDER_NONE; uint8_t order = ORDER_NONE;
int retval = PM3_SUCCESS; int retval = PM3_SUCCESS;
@ -1423,10 +1458,14 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
p_response = &responses[UIDC1]; p_response = &responses[UIDC1];
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 2) { // Received request for UID (cascade 2) } 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]; p_response = &responses[UIDC2];
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3 && len == 2) { // Received request for UID (cascade 3)
p_response = &responses[UIDC3];
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1) } else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1)
p_response = &responses[SAKC1]; p_response = &responses[SAKC1];
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 9) { // Received a SELECT (cascade 2) } else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 9) { // Received a SELECT (cascade 2)
p_response = &responses[SAKC2]; p_response = &responses[SAKC2];
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3 && len == 9) { // Received a SELECT (cascade 3)
p_response = &responses[SAKC3];
} else if (receivedCmd[0] == ISO14443A_CMD_PPS) { } else if (receivedCmd[0] == ISO14443A_CMD_PPS) {
p_response = &responses[PPS]; p_response = &responses[PPS];
} else if (receivedCmd[0] == ISO14443A_CMD_READBLOCK && len == 4) { // Received a (plain) READ } else if (receivedCmd[0] == ISO14443A_CMD_READBLOCK && len == 4) { // Received a (plain) READ

View file

@ -210,8 +210,7 @@ static int usage_hf_14a_config(void) {
} }
static int usage_hf_14a_sim(void) { static int usage_hf_14a_sim(void) {
// PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n"); PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n");
PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 byte UID\n");
PrintAndLogEx(NORMAL, "Usage: hf 14a sim [h] t <type> u <uid> [x] [e] [v]"); PrintAndLogEx(NORMAL, "Usage: hf 14a sim [h] t <type> u <uid> [x] [e] [v]");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help"); PrintAndLogEx(NORMAL, " h : This help");
@ -225,8 +224,7 @@ static int usage_hf_14a_sim(void) {
PrintAndLogEx(NORMAL, " 8 = MIFARE Classic 4k"); PrintAndLogEx(NORMAL, " 8 = MIFARE Classic 4k");
PrintAndLogEx(NORMAL, " 9 = FM11RF005SH Shanghai Metro"); PrintAndLogEx(NORMAL, " 9 = FM11RF005SH Shanghai Metro");
PrintAndLogEx(NORMAL, " 10 = JCOP 31/41 Rothult"); PrintAndLogEx(NORMAL, " 10 = JCOP 31/41 Rothult");
// PrintAndLogEx(NORMAL, " u : 4, 7 or 10 byte UID"); 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"); PrintAndLogEx(NORMAL, " x : (Optional) Performs the 'reader attack', nr/ar attack against a reader");
PrintAndLogEx(NORMAL, " e : (Optional) Fill simulator keys from found keys"); PrintAndLogEx(NORMAL, " e : (Optional) Fill simulator keys from found keys");
PrintAndLogEx(NORMAL, " v : (Optional) Verbose"); PrintAndLogEx(NORMAL, " v : (Optional) Verbose");
@ -234,7 +232,7 @@ static int usage_hf_14a_sim(void) {
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344 x")); PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344 x"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344")); PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344556677")); PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344556677"));
// PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223445566778899AA\n"); PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 112233445566778899AA"));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_hf_14a_sniff(void) { static int usage_hf_14a_sniff(void) {
@ -689,7 +687,9 @@ int CmdHF14ASim(const char *Cmd) {
param_gethex_ex(Cmd, cmdp + 1, uid, &uidlen); param_gethex_ex(Cmd, cmdp + 1, uid, &uidlen);
uidlen >>= 1; uidlen >>= 1;
switch (uidlen) { switch (uidlen) {
//case 10: flags |= FLAG_10B_UID_IN_DATA; break; case 10:
flags |= FLAG_10B_UID_IN_DATA;
break;
case 7: case 7:
flags |= FLAG_7B_UID_IN_DATA; flags |= FLAG_7B_UID_IN_DATA;
break; break;