'hf mf sim' full-byte anti-collision frame support

This commit is contained in:
Eloff 2019-04-18 21:02:48 +03:00
parent 0e855f647a
commit 960b21793c
6 changed files with 170 additions and 181 deletions

View file

@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased] ## [unreleased][unreleased]
- Add 'hf mf sim' full-byte split anticollision support (@mceloff)
- Fix/Add 'hf mf sim' bugs fix, RATS support, etc (@mceloff) - Fix/Add 'hf mf sim' bugs fix, RATS support, etc (@mceloff)
- Fix serial of FPC. (@ryan) - Fix serial of FPC. (@ryan)
- Fix 'data shiftgraphzero' corrupting end of GraphBuffer (@doegox) - Fix 'data shiftgraphzero' corrupting end of GraphBuffer (@doegox)

View file

@ -376,7 +376,7 @@ void printUSBSpeed(void) {
uint32_t bytes_transferred = 0; uint32_t bytes_transferred = 0;
LED_B_ON(); LED_B_ON();
while (end_time < start_time + USB_SPEED_TEST_MIN_TIME) { while (end_time < start_time + USB_SPEED_TEST_MIN_TIME) {
cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K, 0, USB_CMD_DATA_SIZE, 0, test_data, USB_CMD_DATA_SIZE); cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K, 0, USB_CMD_DATA_SIZE, 0, test_data, USB_CMD_DATA_SIZE);
end_time = GetTickCount(); end_time = GetTickCount();

View file

@ -164,9 +164,21 @@ static bool MifareSimInit(uint16_t flags, uint8_t *datain, tag_response_info_t *
static uint8_t rSAK_2k = 0x08; // mifare 2k with RATS support static uint8_t rSAK_2k = 0x08; // mifare 2k with RATS support
static uint8_t rSAK_4k = 0x18; // mifare 4k static uint8_t rSAK_4k = 0x18; // mifare 4k
static uint8_t rUIDBCC1[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 1st cascade level static uint8_t rUIDBCC1[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 1st cascade level
static uint8_t rUIDBCC2[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 2nd cascade level static uint8_t rUIDBCC1b4[] = {0x00, 0x00, 0x00, 0x00}; // UID 1st cascade level, last 4 bytes
static uint8_t rUIDBCC3[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 3nd cascade level static uint8_t rUIDBCC1b3[] = {0x00, 0x00, 0x00}; // UID 1st cascade level, last 3 bytes
static uint8_t rUIDBCC1b2[] = {0x00, 0x00}; // UID 1st cascade level, last 2 bytes
static uint8_t rUIDBCC1b1[] = {0x00}; // UID 1st cascade level, last byte
static uint8_t rUIDBCC2[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 2nd cascade level
static uint8_t rUIDBCC2b4[] = {0x00, 0x00, 0x00, 0x00}; // UID 2st cascade level, last 4 bytes
static uint8_t rUIDBCC2b3[] = {0x00, 0x00, 0x00}; // UID 2st cascade level, last 3 bytes
static uint8_t rUIDBCC2b2[] = {0x00, 0x00}; // UID 2st cascade level, last 2 bytes
static uint8_t rUIDBCC2b1[] = {0x00}; // UID 2st cascade level, last byte
static uint8_t rUIDBCC3[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 3nd cascade level
static uint8_t rUIDBCC3b4[] = {0x00, 0x00, 0x00, 0x00}; // UID 3st cascade level, last 4 bytes
static uint8_t rUIDBCC3b3[] = {0x00, 0x00, 0x00}; // UID 3st cascade level, last 3 bytes
static uint8_t rUIDBCC3b2[] = {0x00, 0x00}; // UID 3st cascade level, last 2 bytes
static uint8_t rUIDBCC3b1[] = {0x00}; // UID 3st cascade level, last byte
static uint8_t rATQA[] = {0x00, 0x00}; // Current ATQA static uint8_t rATQA[] = {0x00, 0x00}; // Current ATQA
static uint8_t rSAK[] = {0x00, 0x00, 0x00}; // Current SAK, CRC static uint8_t rSAK[] = {0x00, 0x00, 0x00}; // Current SAK, CRC
@ -312,25 +324,58 @@ static bool MifareSimInit(uint16_t flags, uint8_t *datain, tag_response_info_t *
return false; return false;
} }
// clone UIDs for byte-frame anti-collision multiple tag selection procedure
memcpy(rUIDBCC1b4, &rUIDBCC1[1], 4);
memcpy(rUIDBCC1b3, &rUIDBCC1[2], 3);
memcpy(rUIDBCC1b2, &rUIDBCC1[3], 2);
memcpy(rUIDBCC1b1, &rUIDBCC1[4], 1);
if (*uid_len >= 7) {
memcpy(rUIDBCC2b4, &rUIDBCC2[1], 4);
memcpy(rUIDBCC2b3, &rUIDBCC2[2], 3);
memcpy(rUIDBCC2b2, &rUIDBCC2[3], 2);
memcpy(rUIDBCC2b1, &rUIDBCC2[4], 1);
}
if (*uid_len == 10) {
memcpy(rUIDBCC3b4, &rUIDBCC3[1], 4);
memcpy(rUIDBCC3b3, &rUIDBCC3[2], 3);
memcpy(rUIDBCC3b2, &rUIDBCC3[3], 2);
memcpy(rUIDBCC3b1, &rUIDBCC3[4], 1);
}
// Calculate actual CRC // Calculate actual CRC
AddCrc14A(rSAK, sizeof(rSAK) - 2); AddCrc14A(rSAK, sizeof(rSAK) - 2);
#define TAG_RESPONSE_COUNT 6 #define TAG_RESPONSE_COUNT 18
static tag_response_info_t responses_init[TAG_RESPONSE_COUNT] = { 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 = rUIDBCC1, .response_n = sizeof(rUIDBCC1) }, // Anticollision cascade1 - respond with first part of uid
{ .response = rUIDBCC2, .response_n = sizeof(rUIDBCC2) }, // Anticollision cascade2 - respond with 2nd part of uid
{ .response = rUIDBCC3, .response_n = sizeof(rUIDBCC3) }, // Anticollision cascade3 - respond with 3th part of uid
{ .response = rSAK, .response_n = sizeof(rSAK) }, // { .response = rSAK, .response_n = sizeof(rSAK) }, //
{ .response = rSAKuid, .response_n = sizeof(rSAKuid) } // { .response = rSAKuid, .response_n = sizeof(rSAKuid) }, //
// Do not reorder. Block used via relative index of rUIDBCC1
{ .response = rUIDBCC1, .response_n = sizeof(rUIDBCC1) }, // Anticollision cascade1 - respond with first part of uid
{ .response = rUIDBCC1b4, .response_n = sizeof(rUIDBCC1b4)},
{ .response = rUIDBCC1b3, .response_n = sizeof(rUIDBCC1b3)},
{ .response = rUIDBCC1b2, .response_n = sizeof(rUIDBCC1b2)},
{ .response = rUIDBCC1b1, .response_n = sizeof(rUIDBCC1b1)},
// Do not reorder. Block used via relative index of rUIDBCC2
{ .response = rUIDBCC2, .response_n = sizeof(rUIDBCC2) }, // Anticollision cascade2 - respond with 2nd part of uid
{ .response = rUIDBCC2b4, .response_n = sizeof(rUIDBCC2b4)},
{ .response = rUIDBCC2b3, .response_n = sizeof(rUIDBCC2b3)},
{ .response = rUIDBCC2b2, .response_n = sizeof(rUIDBCC2b2)},
{ .response = rUIDBCC2b1, .response_n = sizeof(rUIDBCC2b1)},
// Do not reorder. Block used via relative index of rUIDBCC3
{ .response = rUIDBCC3, .response_n = sizeof(rUIDBCC3) }, // Anticollision cascade3 - respond with 3th part of uid
{ .response = rUIDBCC3b4, .response_n = sizeof(rUIDBCC3b4)},
{ .response = rUIDBCC3b3, .response_n = sizeof(rUIDBCC3b3)},
{ .response = rUIDBCC3b2, .response_n = sizeof(rUIDBCC3b2)},
{ .response = rUIDBCC3b1, .response_n = sizeof(rUIDBCC3b1)}
}; };
// Prepare ("precompile") the responses of the anticollision phase. // Prepare ("precompile") the responses of the anticollision phase.
// There will be not enough time to do this at the moment the reader sends its REQA or SELECT // There will be not enough time to do this at the moment the reader sends its REQA or SELECT
// There are 6 predefined responses with a total of 23 bytes data to transmit. // There are 18 predefined responses with a total of 53 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)
// 23 * 8 data bits, 23 * 1 parity bits, 6 start bits, 6 stop bits, 6 correction bits -> need 225 bytes buffer // 53 * 8 data bits, 53 * 1 parity bits, 18 start bits, 18 stop bits, 18 correction bits -> need 571 bytes buffer
#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 225 #define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 571
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
@ -348,11 +393,11 @@ static bool MifareSimInit(uint16_t flags, uint8_t *datain, tag_response_info_t *
// indices into responses array: // indices into responses array:
#define ATQA 0 #define ATQA 0
#define UIDBCC1 1 #define SAK 1
#define UIDBCC2 2 #define SAKuid 2
#define UIDBCC3 3 #define UIDBCC1 3
#define SAK 4 #define UIDBCC2 8
#define SAKuid 5 #define UIDBCC3 13
return true; return true;
} }
@ -501,7 +546,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t
LED_B_OFF(); LED_B_OFF();
LED_C_OFF(); LED_C_OFF();
cardSTATE = MFEMUL_SELECT1; cardSTATE = MFEMUL_SELECT;
continue; continue;
} }
@ -519,163 +564,86 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t
// The anti-collision sequence, which is a mandatory part of the card activation sequence. // The anti-collision sequence, which is a mandatory part of the card activation sequence.
// It auto with 4-byte UID (= Single Size UID), // It auto with 4-byte UID (= Single Size UID),
// 7 -byte UID (= Double Size UID) or 10-byte UID (= Triple Size UID). // 7 -byte UID (= Double Size UID) or 10-byte UID (= Triple Size UID).
// For details see chapter 2 of AN10927.pdf
// Cascade Level 1
// //
// In the Cascade Level 1, the card send the anti-collision command CL1 (0x93) and the PICC returns // This case is used for all Cascade Levels, because:
// either the 4-byte UID (UID0...UID4) and one-byte BCC // 1) Any devices (under Android for example) after full select procedure completed,
// or a Cascade Tag (CT) followed by the first 3 byte of the UID (UID0...UID2) and onebyte BCC. // when UID is known, uses "fast-selection" method. In this case reader ignores
// // first cascades and tries to select tag by last bytes of UID of last cascade
// The CT (0x88) indicates that the UID is not yet complete, and another Cascade Level is needed // 2) Any readers (like ACR122U) uses bit oriented anti-collision frames during selectin,
// // same as multiple tags. For details see chapter 6.1.5.3 of ISO/IEC 14443-3
// The UID0 byte of a 4-byte UID must not be 0x88. case MFEMUL_SELECT: {
// The CL1 then must be selected, using the Select command CL1 (0x93). The PICC returns its SAK CL1, which indicates int uid_index = -1;
// whether the UID is complete or not, and (if so), // Extract cascade level
// the type of card and whether the card supports T=CL. if (receivedCmd_len >= 2) {
switch (receivedCmd[0]) {
case MFEMUL_SELECT1: { case ISO14443A_CMD_ANTICOLL_OR_SELECT:
// select all - 0x93 0x20 (Anti Collision CL1) uid_index = UIDBCC1;
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("cardSTATE = MFEMUL_SELECT1 - receivedCmd_len: %d - receivedCmd[0]: %02x - receivedCmd[1]: %02x", receivedCmd_len, receivedCmd[0], receivedCmd[1]);
if (receivedCmd_len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && receivedCmd[1] == 0x20)) {
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT ALL CL1 received - EmSendPrecompiledCmd(%02x)", &responses[UIDBCC1]);
EmSendPrecompiledCmd(&responses[UIDBCC1]);
break;
}
// select card - 0x93 0x70 (Select CL1)
if (receivedCmd_len == 9 &&
(receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT &&
receivedCmd[1] == 0x70 &&
memcmp(&receivedCmd[2], responses[UIDBCC1].response, 4) == 0)) {
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT CL1 %02x%02x%02x%02x received", receivedCmd[2], receivedCmd[3], receivedCmd[4], receivedCmd[5]);
// Send SAK according UID len
switch (uid_len) {
case 4:
// UID completed
EmSendPrecompiledCmd(&responses[SAK]);
LED_B_ON();
cardSTATE = MFEMUL_WORK;
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT1] cardSTATE = MFEMUL_WORK");
break; break;
case 7: case ISO14443A_CMD_ANTICOLL_OR_SELECT_2:
// SAK => Need another select round uid_index = UIDBCC2;
EmSendPrecompiledCmd(&responses[SAKuid]);
cardSTATE = MFEMUL_SELECT2;
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT1] cardSTATE = MFEMUL_SELECT2");
break; break;
case 10: case ISO14443A_CMD_ANTICOLL_OR_SELECT_3:
// SAK => Need another select round uid_index = UIDBCC3;
EmSendPrecompiledCmd(&responses[SAKuid]);
cardSTATE = MFEMUL_SELECT2;
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT1] cardSTATE = MFEMUL_SELECT2");
break;
default:
break;
} // End Switch (uid_len)
} else {
// IDLE
cardSTATE_TO_IDLE();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT1] cardSTATE = MFEMUL_IDLE");
}
// Break Case MFEMUL_SELECT1
break;
}
// Cascade Level 2
//
// If the UID is not yet complete, the PCD continues with an anti-collision CL2 command (0x95),
// and the PICC returns
// • either the last 4 bytes of the Double Size UID (UID3...UID6) and one-byte BCC,
// • or a Cascade Tag (CT) followed by the next 3 bytes of the Triple Size UID (UID3...UID5) and one-byte BCC.
// The CT (0x88) indicates that the UID is not yet complete, and another Cascade Level has to follow.
//
// The UID3 byte of a 7 byte or 10-byte UID must not be 0x88
// The CL2 then must be selected, using the Select command CL2 (0x95).
// The PICC returns its SAK CL2, which indicates
// whether the UID is complete or not, and (if so),
// the type of card and whether the card supports T=CL.
// select all cl2 - 0x95 0x20
case MFEMUL_SELECT2: {
if (receivedCmd_len == 2 &&
(receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && receivedCmd[1] == 0x20)) {
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT2] SELECT ALL CL2 received");
EmSendPrecompiledCmd(&responses[UIDBCC2]);
break;
}
// select cl2 card - 0x95 0x70 xxxxxxxxxxxx
if (receivedCmd_len == 9 &&
(receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 &&
receivedCmd[1] == 0x70 &&
memcmp(&receivedCmd[2], responses[UIDBCC2].response, 4) == 0)) {
switch (uid_len) {
case 7:
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT2] SELECT CL2 %02x%02x%02x%02x received", receivedCmd[2], receivedCmd[3], receivedCmd[4], receivedCmd[5]);
// UID completed
EmSendPrecompiledCmd(&responses[SAK]);
cardSTATE = MFEMUL_WORK;
LED_B_ON();
break;
case 10:
// SAK => Need another select round
EmSendPrecompiledCmd(&responses[SAKuid]);
cardSTATE = MFEMUL_SELECT3;
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT2] cardSTATE = MFEMUL_SELECT3");
default:
break; break;
} }
} else {
// IDLE
cardSTATE_TO_IDLE();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT2] cardSTATE = MFEMUL_IDLE");
} }
// Break Case MFEMUL_SELECT2 if (uid_index < 0) {
break;
}
// Cascade Level 3
// Select command CL3 (0x97)
//
// If the UID is not yet complete, the PCD continues with an anti-collision CL3 command (0x97)
// and the PICC returns the last 4 bytes of the Triple Size UID (UID6...UID9) and one-byte BCC.
// The PICC returns its SAK CL3, which indicates the type of card and whether the card supports T=CL
case MFEMUL_SELECT3: {
if (!uid_len) {
LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true);
break;
}
if (receivedCmd_len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3 && receivedCmd[1] == 0x20)) {
EmSendPrecompiledCmd(&responses[UIDBCC3]);
break;
}
if (receivedCmd_len == 9 &&
(receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3 &&
receivedCmd[1] == 0x70 &&
memcmp(&receivedCmd[2], responses[UIDBCC3].response, 4) == 0)) {
// UID completed
EmSendPrecompiledCmd(&responses[SAK]);
cardSTATE = MFEMUL_WORK;
LED_B_ON();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) {
Dbprintf("[MFEMUL_SELECT3] --> WORK. anticol3 time: %d", GetTickCount() - selTimer);
Dbprintf("[MFEMUL_SELECT3] cardSTATE = MFEMUL_WORK");
}
continue;
} else {
// IDLE
cardSTATE_TO_IDLE(); cardSTATE_TO_IDLE();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT3] cardSTATE = MFEMUL_IDLE"); if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT] Incorrect cascade level received");
break;
} }
// Break Case MFEMUL_SELECT3
// Incoming SELECT ALL for any cascade level
if (receivedCmd_len == 2 && receivedCmd[1] == 0x20) {
EmSendPrecompiledCmd(&responses[uid_index]);
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT ALL - EmSendPrecompiledCmd(%02x)", &responses[uid_index]);
break;
}
// Incoming SELECT CLx for any cascade level
if (receivedCmd_len == 9 && receivedCmd[1] == 0x70) {
if (memcmp(&receivedCmd[2], responses[uid_index].response, 4) == 0) {
bool finished = (uid_len == 4 && uid_index == UIDBCC1) ||
(uid_len == 7 && uid_index == UIDBCC2) ||
(uid_len == 10 && uid_index == UIDBCC3);
EmSendPrecompiledCmd(&responses[finished ? SAK : SAKuid]);
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT CLx %02x%02x%02x%02x received", receivedCmd[2], receivedCmd[3], receivedCmd[4], receivedCmd[5]);
if (finished) {
LED_B_ON();
cardSTATE = MFEMUL_WORK;
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT] cardSTATE = MFEMUL_WORK");
}
} else {
// IDLE, not our UID
LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true);
cardSTATE_TO_IDLE();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT] cardSTATE = MFEMUL_IDLE");
}
break;
}
// Incoming anti-collision frame
if (receivedCmd_len >= 2 && receivedCmd_len <= 6 && receivedCmd[1] == 0x50) {
// we can process only full-byte frame anti-collision procedure
if (memcmp(&receivedCmd[2], responses[uid_index].response, receivedCmd_len - 2) == 0) {
// response missing part of UID via relative array index
EmSendPrecompiledCmd(&responses[uid_index + receivedCmd_len - 2]);
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT ANTICOLLISION - EmSendPrecompiledCmd(%02x)", &responses[uid_index]);
} else {
// IDLE, not our UID or split-byte frame anti-collision (not supports)
LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true);
cardSTATE_TO_IDLE();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT] cardSTATE = MFEMUL_IDLE");
}
break;
}
// Unknown selection procedure
LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true);
cardSTATE_TO_IDLE();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT] Unknown selection procedure");
break; break;
} }

View file

@ -48,16 +48,14 @@
//mifare emulator states //mifare emulator states
#define MFEMUL_NOFIELD 0 #define MFEMUL_NOFIELD 0
#define MFEMUL_IDLE 1 #define MFEMUL_IDLE 1
#define MFEMUL_SELECT1 2 #define MFEMUL_SELECT 2
#define MFEMUL_SELECT2 3 #define MFEMUL_AUTH1 3
#define MFEMUL_SELECT3 4 #define MFEMUL_WORK 4
#define MFEMUL_AUTH1 5 #define MFEMUL_WRITEBL2 5
#define MFEMUL_WORK 7 #define MFEMUL_INTREG_INC 6
#define MFEMUL_WRITEBL2 8 #define MFEMUL_INTREG_DEC 7
#define MFEMUL_INTREG_INC 9 #define MFEMUL_INTREG_REST 8
#define MFEMUL_INTREG_DEC 10 #define MFEMUL_HALTED 9
#define MFEMUL_INTREG_REST 11
#define MFEMUL_HALTED 12
#define cardSTATE_TO_IDLE() cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF(); #define cardSTATE_TO_IDLE() cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF();

View file

@ -45,6 +45,10 @@ void ClearAuthData() {
uint8_t iso14443A_CRC_check(bool isResponse, uint8_t *d, uint8_t n) { uint8_t iso14443A_CRC_check(bool isResponse, uint8_t *d, uint8_t n) {
if (n < 3) return 2; if (n < 3) return 2;
if (isResponse && (n < 6)) return 2; if (isResponse && (n < 6)) return 2;
if (n > 2 && d[1] == 0x50 &&
d[0] >= ISO14443A_CMD_ANTICOLL_OR_SELECT &&
d[0] <= ISO14443A_CMD_ANTICOLL_OR_SELECT_3)
return 2;
return check_crc(CRC_14443_A, d, n); return check_crc(CRC_14443_A, d, n);
} }
@ -143,20 +147,38 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
break; break;
case ISO14443A_CMD_ANTICOLL_OR_SELECT: { case ISO14443A_CMD_ANTICOLL_OR_SELECT: {
// 93 20 = Anticollision (usage: 9320 - answer: 4bytes UID+1byte UID-bytes-xor) // 93 20 = Anticollision (usage: 9320 - answer: 4bytes UID+1byte UID-bytes-xor)
// 93 70 = Select (usage: 9370+5bytes 9320 answer - answer: 1byte SAK) // 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) if (cmd[1] == 0x70)
snprintf(exp, size, "SELECT_UID"); snprintf(exp, size, "SELECT_UID");
else else if (cmd[1] == 0x20 || cmd[1] == 0x50)
snprintf(exp, size, "ANTICOLL"); snprintf(exp, size, "ANTICOLL");
else
snprintf(exp, size, "SELECT_XXX");
break; break;
} }
case ISO14443A_CMD_ANTICOLL_OR_SELECT_2: { case ISO14443A_CMD_ANTICOLL_OR_SELECT_2: {
//95 20 = Anticollision of cascade level2 //95 20 = Anticollision of cascade level2
//95 50 = Bit oriented anti-collision level2
//95 70 = Select of cascade level2 //95 70 = Select of cascade level2
if (cmd[2] == 0x70) if (cmd[1] == 0x70)
snprintf(exp, size, "SELECT_UID-2"); snprintf(exp, size, "SELECT_UID-2");
else else if (cmd[1] == 0x20 || cmd[1] == 0x50)
snprintf(exp, size, "ANTICOLL-2"); 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-2");
else if (cmd[1] == 0x20 || cmd[1] == 0x50)
snprintf(exp, size, "ANTICOLL-3");
else
snprintf(exp, size, "SELECT_XXX-3");
break; break;
} }
case ISO14443A_CMD_REQA: case ISO14443A_CMD_REQA:

View file

@ -71,7 +71,7 @@ static int usage_hf14_mfsim(void) {
PrintAndLogEx(NORMAL, " u (Optional) UID 4,7 or 10bytes. If not specified, the UID 4b from emulator memory will be used"); PrintAndLogEx(NORMAL, " u (Optional) UID 4,7 or 10bytes. If not specified, the UID 4b from emulator memory will be used");
PrintAndLogEx(NORMAL, " t (Optional) 0 = MIFARE Mini"); PrintAndLogEx(NORMAL, " t (Optional) 0 = MIFARE Mini");
PrintAndLogEx(NORMAL, " 1 = MIFARE Classic 1k (Default)"); PrintAndLogEx(NORMAL, " 1 = MIFARE Classic 1k (Default)");
PrintAndLogEx(NORMAL, " 1 = MIFARE Classic 2k plus in SL0 mode"); PrintAndLogEx(NORMAL, " 2 = MIFARE Classic 2k plus in SL0 mode");
PrintAndLogEx(NORMAL, " 4 = MIFARE Classic 4k"); PrintAndLogEx(NORMAL, " 4 = MIFARE Classic 4k");
PrintAndLogEx(NORMAL, " n (Optional) Automatically exit simulation after <numreads> blocks have been read by reader. 0 = infinite"); PrintAndLogEx(NORMAL, " n (Optional) Automatically exit simulation after <numreads> blocks have been read by reader. 0 = infinite");
PrintAndLogEx(NORMAL, " i (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted"); PrintAndLogEx(NORMAL, " i (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted");