This commit is contained in:
iceman1001 2019-04-25 16:55:48 +02:00
commit 5cc3a1b717
11 changed files with 216 additions and 93 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...
## [unreleased][unreleased]
- Change/Add new dump format for Ultralight/NTAG, counters support, simulation (@mceloff)
- Add 'hf mf sim' full-byte split anticollision support (@mceloff)
- Fix/Add 'hf mf sim' bugs fix, RATS support, etc (@mceloff)
- Fix serial of FPC. (@ryan)

View file

@ -624,7 +624,7 @@ void RAMFUNC SniffIso14443a(uint8_t param) {
}
} // end main loop
if (MF_DBGLEVEL >= 1) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) {
Dbprintf("maxDataLen=%d, Uart.state=%x, Uart.len=%d", maxDataLen, Uart.state, Uart.len);
Dbprintf("traceLen=%d, Uart.output[0]=%08x", BigBuf_get_traceLen(), (uint32_t)Uart.output[0]);
}
@ -832,8 +832,6 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
// PACK response to PWD AUTH for EV1/NTAG
uint8_t response8[4] = {0, 0, 0, 0};
// Counter for EV1/NTAG
uint32_t counters[] = {0, 0, 0};
// The first response contains the ATQA (note: bytes are transmitted in reverse order).
uint8_t response1[] = {0, 0};
@ -848,6 +846,9 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
memset(ar_nr_nonces, 0x00, sizeof(ar_nr_nonces));
uint8_t moebius_count = 0;
// some first pages of UL/NTAG dump is special data
mfu_dump_t *mfu_header = tagType == 2 || tagType == 7 ? (mfu_dump_t *) BigBuf_get_EM_addr() : NULL;
switch (tagType) {
case 1: { // MIFARE Classic 1k
response1[0] = 0x04;
@ -884,13 +885,12 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
case 7: { // NTAG
response1[0] = 0x44;
sak = 0x00;
// PACK
response8[0] = 0x80;
response8[1] = 0x80;
// PACK, from last page of dump
emlGetMemBt(response8, MFU_DUMP_PREFIX_LENGTH + mfu_header->pages * 4, 2);
compute_crc(CRC_14443_A, response8, 2, &response8[2], &response8[3]);
// uid not supplied then get from emulator memory
if (data[0] == 0) {
uint16_t start = 4 * (0 + 12);
uint16_t start = MFU_DUMP_PREFIX_LENGTH;
uint8_t emdata[8];
emlGetMemBt(emdata, start, sizeof(emdata));
memcpy(data, emdata, 3); // uid bytes 0-2
@ -1086,12 +1086,17 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
uint8_t block = receivedCmd[1];
// if Ultralight or NTAG (4 byte blocks)
if (tagType == 7 || tagType == 2) {
// first 12 blocks of emu are [getversion answer - check tearing - pack - 0x00 - signature]
uint16_t start = 4 * (block + 12);
uint8_t emdata[MAX_MIFARE_FRAME_SIZE];
emlGetMemBt(emdata, start, 16);
AddCrc14A(emdata, 16);
EmSendCmd(emdata, sizeof(emdata));
if (block > mfu_header->pages) {
// send NACK 0x0 == invalid argument
EmSend4bit(CARD_NACK_IV);
} else {
// first blocks of emu are header
uint16_t start = block * 4 + MFU_DUMP_PREFIX_LENGTH;
uint8_t emdata[MAX_MIFARE_FRAME_SIZE];
emlGetMemBt(emdata, start, 16);
AddCrc14A(emdata, 16);
EmSendCmd(emdata, sizeof(emdata));
}
// We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below
p_response = NULL;
} else if (tagType == 9 && block == 1) {
@ -1110,23 +1115,36 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
p_response = NULL;
}
} else if (receivedCmd[0] == MIFARE_ULEV1_FASTREAD) { // Received a FAST READ (ranged read)
uint8_t emdata[MAX_FRAME_SIZE];
// first 12 blocks of emu are [getversion answer - check tearing - pack - 0x00 - signature]
int start = (receivedCmd[1] + 12) * 4;
len = (receivedCmd[2] - receivedCmd[1] + 1) * 4;
emlGetMemBt(emdata, start, len);
AddCrc14A(emdata, len);
EmSendCmd(emdata, len + 2);
uint8_t block1 = receivedCmd[1];
uint8_t block2 = receivedCmd[2];
if (block1 > mfu_header->pages) {
// send NACK 0x0 == invalid argument
EmSend4bit(CARD_NACK_IV);
} else {
uint8_t emdata[MAX_FRAME_SIZE];
// first blocks of emu are header
int start = block1 * 4 + MFU_DUMP_PREFIX_LENGTH;
len = (block2 - block1 + 1) * 4;
emlGetMemBt(emdata, start, len);
AddCrc14A(emdata, len);
EmSendCmd(emdata, len + 2);
}
p_response = NULL;
} else if ((receivedCmd[0] == MIFARE_ULC_WRITE || receivedCmd[0] == MIFARE_ULC_COMP_WRITE) && (tagType == 2 || tagType == 7)) { // Received a WRITE
// cmd + block + 4/16 bytes data + 2 bytes crc
if (len == 8 || len == 20) {
bool isCrcCorrect = CheckCrc14A(receivedCmd, len);
if (isCrcCorrect) {
int block = receivedCmd[1] + 12; // first 12 blocks of emu are [getversion answer - check tearing - pack - 0x00 - signature]
emlSetMem_xt(&receivedCmd[2], block, 1, 4);
// send ACK
EmSend4bit(CARD_ACK);
uint8_t block = receivedCmd[1];
if (block > mfu_header->pages) {
// send NACK 0x0 == invalid argument
EmSend4bit(CARD_NACK_IV);
} else {
// first blocks of emu are header
emlSetMem_xt(&receivedCmd[2], block + MFU_DUMP_PREFIX_LENGTH / 4, 1, 4);
// send ACK
EmSend4bit(CARD_ACK);
}
} else {
// send NACK 0x1 == crc/parity error
EmSend4bit(CARD_NACK_PA);
@ -1137,10 +1155,9 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
}
p_response = NULL;
} else if (receivedCmd[0] == MIFARE_ULEV1_READSIG && tagType == 7) { // Received a READ SIGNATURE --
// first 12 blocks of emu are [getversion answer - check tearing - pack - 0x00 - signature]
uint16_t start = 4 * 4;
// first blocks of emu are header
uint8_t emdata[34];
emlGetMemBt(emdata, start, 32);
memcpy(emdata, mfu_header->signature, 32);
AddCrc14A(emdata, 32);
EmSendCmd(emdata, sizeof(emdata));
p_response = NULL;
@ -1151,7 +1168,7 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
EmSend4bit(0x00);
} else {
uint8_t cmd[] = {0x00, 0x00, 0x00, 0x14, 0xa5};
num_to_bytes(counters[index], 3, cmd);
memcpy(cmd, mfu_header->counter_tearing[index], 3);
AddCrc14A(cmd, sizeof(cmd) - 2);
EmSendCmd(cmd, sizeof(cmd));
}
@ -1162,15 +1179,13 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
// send NACK 0x0 == invalid argument
EmSend4bit(0x00);
} else {
uint32_t val = bytes_to_num(receivedCmd + 2, 4);
uint32_t val = le24toh(receivedCmd + 2) + le24toh(mfu_header->counter_tearing[index]);
// if new value + old value is bigger 24bits, fail
if (val + counters[index] > 0xFFFFFF) {
if (val > 0xFFFFFF) {
// send NACK 0x4 == counter overflow
EmSend4bit(CARD_NACK_NA);
} else {
counters[index] = val;
htole24(val, mfu_header->counter_tearing[index]);
// send ACK
EmSend4bit(CARD_ACK);
}
@ -1184,7 +1199,7 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
// send NACK 0x0 == invalid argument
EmSend4bit(0x00);
} else {
emlGetMemBt(emdata, 10 + index, 1);
emdata[0] = mfu_header->counter_tearing[index][3];
AddCrc14A(emdata, sizeof(emdata) - 2);
EmSendCmd(emdata, sizeof(emdata));
}
@ -1195,7 +1210,7 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
} else if (receivedCmd[0] == MIFARE_AUTH_KEYA || receivedCmd[0] == MIFARE_AUTH_KEYB) { // Received an authentication request
if (tagType == 7) { // IF NTAG /EV1 0x60 == GET_VERSION, not a authentication request.
uint8_t emdata[10];
emlGetMemBt(emdata, 0, 8);
memcpy(emdata, mfu_header->version, 8);
AddCrc14A(emdata, sizeof(emdata) - 2);
EmSendCmd(emdata, sizeof(emdata));
p_response = NULL;
@ -1291,16 +1306,21 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
} else if (receivedCmd[0] == MIFARE_ULC_AUTH_1) { // ULC authentication, or Desfire Authentication
} else if (receivedCmd[0] == MIFARE_ULEV1_AUTH) { // NTAG / EV-1 authentication
if (tagType == 7) {
uint16_t start = 13; // first 4 blocks of emu are [getversion answer - check tearing - pack - 0x00]
uint8_t emdata[4];
emlGetMemBt(emdata, start, 2);
AddCrc14A(emdata, 2);
EmSendCmd(emdata, sizeof(emdata));
p_response = NULL;
uint32_t pwd = bytes_to_num(receivedCmd + 1, 4);
if (MF_DBGLEVEL >= 3) Dbprintf("Auth attempt: %08x", pwd);
// PWD stored in dump now
uint8_t pwd[4];
emlGetMemBt(pwd, (mfu_header->pages - 1) * 4 + MFU_DUMP_PREFIX_LENGTH, sizeof(pwd));
if (memcmp(receivedCmd + 1, pwd, 4) == 0) {
p_response = &responses[7]; // precompiled PACK
} else {
EmSend4bit(CARD_NACK_NA);
uint32_t pwd = bytes_to_num(receivedCmd + 1, 4);
if (MF_DBGLEVEL >= MF_DBG_DEBUG) Dbprintf("Auth attempt: %08x", pwd);
p_response = NULL;
}
}
} else if (receivedCmd[0] == MIFARE_ULEV1_VCSL) {
EmSend4bit(CARD_NACK_NA);
p_response = NULL;
} else {
// Check for ISO 14443A-4 compliant commands, look at left nibble
switch (receivedCmd[0]) {
@ -1354,8 +1374,10 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
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);
Dbprintf("Received unknown command (len=%d):", len);
Dbhexdump(len, receivedCmd, false);
if (MF_DBGLEVEL >= MF_DBG_DEBUG) {
Dbprintf("Received unknown command (len=%d):", len);
Dbhexdump(len, receivedCmd, false);
}
// Do not respond
dynamic_response_info.response_n = 0;
}
@ -1371,7 +1393,7 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
dynamic_response_info.response_n += 2;
if (prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE) == false) {
DbpString("Error preparing tag response");
if (MF_DBGLEVEL >= MF_DBG_DEBUG) DbpString("Error preparing tag response");
LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true);
break;
}
@ -1398,7 +1420,7 @@ void SimulateIso14443aTag(int tagType, int flags, uint8_t *data) {
set_tracing(false);
BigBuf_free_keep_EM();
if (MF_DBGLEVEL >= 4) {
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) {
Dbprintf("-[ Wake ups after halt [%d]", happened);
Dbprintf("-[ Messages after halt [%d]", happened2);
Dbprintf("-[ Num of received cmd [%d]", cmdsRecvd);
@ -1448,7 +1470,7 @@ static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing
else
PrepareDelayedTransfer(*timing & 0x00000007); // Delay transfer (fine tuning - up to 7 MF clock ticks)
if (MF_DBGLEVEL >= 4 && GetCountSspClk() >= (*timing & 0xfffffff8))
if (MF_DBGLEVEL >= MF_DBG_EXTENDED && GetCountSspClk() >= (*timing & 0xfffffff8))
Dbprintf("TransmitFor14443a: Missed timing");
while (GetCountSspClk() < (*timing & 0xfffffff8)) {}; // Delay transfer (multiple of 8 MF clock ticks)
LastTimeProxToAirStart = *timing;
@ -1930,12 +1952,12 @@ void iso14443a_antifuzz(uint32_t flags) {
}
EmSendCmdEx(resp, 5, true);
if (MF_DBGLEVEL >= 4) Dbprintf("ANTICOLL or SELECT %x", received[1]);
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("ANTICOLL or SELECT %x", received[1]);
LED_D_INV();
continue;
} else if (received[1] == 0x20 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) { // Received request for UID (cascade 2)
if (MF_DBGLEVEL >= 4) Dbprintf("ANTICOLL or SELECT_2");
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("ANTICOLL or SELECT_2");
} else if (received[1] == 0x70 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) { // Received a SELECT (cascade 1)
} else if (received[1] == 0x70 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) { // Received a SELECT (cascade 2)
} else {
@ -2553,7 +2575,7 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
if (!have_uid) { // need a full select cycle to get the uid first
iso14a_card_select_t card_info;
if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Can't select card (ALL)");
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Mifare: Can't select card (ALL)");
continue;
}
switch (card_info.uidlen) {
@ -2572,7 +2594,7 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
have_uid = true;
} else { // no need for anticollision. We can directly select the card
if (!iso14443a_fast_select_card(uid, cascade_levels)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Can't select card (UID)");
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Mifare: Can't select card (UID)");
continue;
}
}
@ -2644,7 +2666,7 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
sync_time = GetCountSspClk() & 0xfffffff8;
}
if (MF_DBGLEVEL >= 4)
if (MF_DBGLEVEL >= MF_DBG_EXTENDED)
Dbprintf("calibrating in cycle %d. nt_distance=%d, elapsed_prng_sequences=%d, new sync_cycles: %d\n", i, nt_distance, elapsed_prng_sequences, sync_cycles);
LED_B_OFF();
@ -2671,13 +2693,13 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
}
if (consecutive_resyncs < 3) {
if (MF_DBGLEVEL >= 4) {
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) {
Dbprintf("Lost sync in cycle %d. nt_distance=%d. Consecutive Resyncs = %d. Trying one time catch up...\n", i, catch_up_cycles, consecutive_resyncs);
}
} else {
sync_cycles += catch_up_cycles;
if (MF_DBGLEVEL >= 4)
if (MF_DBGLEVEL >= MF_DBG_EXTENDED)
Dbprintf("Lost sync in cycle %d for the fourth time consecutively (nt_distance = %d). Adjusting sync_cycles to %d.\n", i, catch_up_cycles, sync_cycles);
last_catch_up = 0;
@ -2727,7 +2749,7 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) {
mf_nr_ar[3] &= 0x1F;
if (MF_DBGLEVEL >= 4) Dbprintf("Number of sent auth requestes: %u", i);
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Number of sent auth requestes: %u", i);
uint8_t buf[32] = {0x00};
memset(buf, 0x00, sizeof(buf));
@ -2802,7 +2824,7 @@ void DetectNACKbug() {
if (!have_uid) { // need a full select cycle to get the uid first
iso14a_card_select_t card_info;
if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Can't select card (ALL)");
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Mifare: Can't select card (ALL)");
continue;
}
switch (card_info.uidlen) {
@ -2821,7 +2843,7 @@ void DetectNACKbug() {
have_uid = true;
} else { // no need for anticollision. We can directly select the card
if (!iso14443a_fast_select_card(uid, cascade_levels)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Can't select card (UID)");
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Mifare: Can't select card (UID)");
continue;
}
}
@ -2899,7 +2921,7 @@ void DetectNACKbug() {
break;
}
if (MF_DBGLEVEL >= 4)
if (MF_DBGLEVEL >= MF_DBG_EXTENDED)
Dbprintf("calibrating in cycle %d. nt_distance=%d, elapsed_prng_sequences=%d, new sync_cycles: %d\n", i, nt_distance, elapsed_prng_sequences, sync_cycles);
continue;
@ -2926,13 +2948,13 @@ void DetectNACKbug() {
}
if (consecutive_resyncs < 3) {
if (MF_DBGLEVEL >= 4) {
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) {
Dbprintf("Lost sync in cycle %d. nt_distance=%d. Consecutive Resyncs = %d. Trying one time catch up...\n", i, catch_up_cycles, consecutive_resyncs);
}
} else {
sync_cycles += catch_up_cycles;
if (MF_DBGLEVEL >= 4) {
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) {
Dbprintf("Lost sync in cycle %d for the fourth time consecutively (nt_distance = %d). Adjusting sync_cycles to %d.\n", i, catch_up_cycles, sync_cycles);
Dbprintf("nt [%08x] attacted [%08x]", nt, nt_attacked);
}

View file

@ -91,6 +91,12 @@ int32_t le24toh(uint8_t data[3]) {
return (data[2] << 16) | (data[1] << 8) | data[0];
}
void htole24(uint32_t val, uint8_t data[3]) {
data[0] = (uint8_t) val;
data[1] = (uint8_t)(val >> 8);
data[2] = (uint8_t)(val >> 16);
}
//convert hex digit to integer
uint8_t hex2int(char hexchar) {
switch (hexchar) {

View file

@ -93,6 +93,7 @@ uint64_t bytes_to_num(uint8_t *src, size_t len);
void rol(uint8_t *data, const size_t len);
void lsl(uint8_t *data, size_t len);
int32_t le24toh(uint8_t data[3]);
void htole24(uint32_t val, uint8_t data[3]);
uint8_t hex2int(char hexchar);
void LED(int led, int ms);

View file

@ -2590,6 +2590,16 @@ int CmdHF14AMfELoad(const char *Cmd) {
return 2;
}
// convert old mfu format to new
if (blockWidth == 4) {
res = convertOldMfuDump(&data, &datalen);
if (res) {
PrintAndLogEx(FAILED, "Failed convert on load to new Ultralight/NTAG format");
free(data);
return res;
}
}
PrintAndLogEx(INFO, "Copying to emulator memory");
blockNum = 0;

View file

@ -1619,11 +1619,13 @@ void printMFUdumpEx(mfu_dump_t *card, uint16_t pages, uint8_t startpage) {
PrintAndLogEx(NORMAL, "----------+-------------------------+---------");
PrintAndLogEx(NORMAL, "Version | %s| %s", sprint_hex(card->version, sizeof(card->version)), sprint_ascii(card->version, sizeof(card->version)));
PrintAndLogEx(NORMAL, "TBD | %-24s| %s", sprint_hex(card->tbo, sizeof(card->tbo)), sprint_ascii(card->tbo, sizeof(card->tbo)));
PrintAndLogEx(NORMAL, "Tearing | %-24s| %s", sprint_hex(card->tearing, sizeof(card->tearing)), sprint_ascii(card->tearing, sizeof(card->tearing)));
PrintAndLogEx(NORMAL, "Pack | %-24s| %s", sprint_hex(card->pack, sizeof(card->pack)), sprint_ascii(card->pack, sizeof(card->pack)));
PrintAndLogEx(NORMAL, "TBD | %-24s| %s", sprint_hex(card->tbo1, sizeof(card->tbo1)), sprint_ascii(card->tbo1, sizeof(card->tbo1)));
PrintAndLogEx(NORMAL, "Signature1| %s| %s", sprint_hex(card->signature, 16), sprint_ascii(card->signature, 16));
PrintAndLogEx(NORMAL, "Signature2| %s| %s", sprint_hex(card->signature + 16, 16), sprint_ascii(card->signature + 16, 16));
for (uint8_t i = 0; i < 3; i ++) {
PrintAndLogEx(NORMAL, "Counter%d | %-24s| %s", i, sprint_hex(card->counter_tearing[i], 3), sprint_ascii(card->counter_tearing[i], 3));
PrintAndLogEx(NORMAL, "Tearing%d | %-24s| %s", i, sprint_hex(card->counter_tearing[i] + 3, 1), sprint_ascii(card->counter_tearing[i] + 3, 1));
}
PrintAndLogEx(NORMAL, "-------------------------------------------------------------");
PrintAndLogEx(NORMAL, "\nBlock# | Data |lck| Ascii");
PrintAndLogEx(NORMAL, "---------+-------------+---+------");
@ -1889,8 +1891,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
mfu_dump_t dump_file_data;
uint8_t get_pack[] = {0, 0};
uint8_t get_version[] = {0, 0, 0, 0, 0, 0, 0, 0};
uint8_t get_tearing[] = {0, 0, 0};
uint8_t get_counter[] = {0, 0, 0};
uint8_t get_counter_tearing[][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
uint8_t dummy_pack[] = {0, 0};
uint8_t get_signature[32];
memset(get_signature, 0, sizeof(get_signature));
@ -1920,8 +1921,8 @@ static int CmdHF14AMfUDump(const char *Cmd) {
ulev1_getVersion(get_version, sizeof(get_version));
for (uint8_t n = 0; n < 3; ++n) {
ulev1_readTearing(n, get_tearing + n, 1);
ulev1_readCounter(n, get_counter, sizeof(get_counter));
ulev1_readTearing(n, &get_counter_tearing[n][3], 1);
ulev1_readCounter(n, &get_counter_tearing[n][0], 3);
}
DropField();
@ -1935,7 +1936,8 @@ static int CmdHF14AMfUDump(const char *Cmd) {
}
// format and add keys to block dump output
if (hasAuthKey) {
// only add keys if not partial read, and complete pages read
if (!is_partial && pages == card_mem_size && hasAuthKey) {
// if we didn't swapendian before - do it now for the sprint_hex call
// NOTE: default entry is bigendian (unless swapped), sprint_hex outputs little endian
// need to swap to keep it the same
@ -1954,11 +1956,11 @@ static int CmdHF14AMfUDump(const char *Cmd) {
}
//add *special* blocks to dump
//iceman: need to add counters and pwd values to the dump format
// pack and pwd saved into last pages of dump, if was not partial read
dump_file_data.pages = pages - 1;
memcpy(dump_file_data.version, get_version, sizeof(dump_file_data.version));
memcpy(dump_file_data.tearing, get_tearing, sizeof(dump_file_data.tearing));
memcpy(dump_file_data.pack, get_pack, sizeof(dump_file_data.pack));
memcpy(dump_file_data.signature, get_signature, sizeof(dump_file_data.signature));
memcpy(dump_file_data.counter_tearing, get_counter_tearing, sizeof(dump_file_data.counter_tearing));
memcpy(dump_file_data.data, data, pages * 4);
printMFUdumpEx(&dump_file_data, pages, startPage);
@ -1971,7 +1973,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
fptr += sprintf(fptr, "hf-mfu-");
FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen);
}
uint16_t datalen = pages * 4 + DUMP_PREFIX_LENGTH;
uint16_t datalen = pages * 4 + MFU_DUMP_PREFIX_LENGTH;
saveFile(filename, "bin", (uint8_t *)&dump_file_data, datalen);
saveFileJSON(filename, "json", jsfMfuMemory, (uint8_t *)&dump_file_data, datalen);
@ -2092,16 +2094,30 @@ static int CmdHF14AMfURestore(const char *Cmd) {
// read all data
size_t bytes_read = fread(dump, 1, fsize, f);
fclose(f);
if (bytes_read < 48) {
if (bytes_read < MFU_DUMP_PREFIX_LENGTH) {
PrintAndLogEx(WARNING, "Error, dump file is too small");
free(dump);
return 1;
}
PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename);
// convert old format to new format, if need
int res = convertOldMfuDump(&dump, &bytes_read);
if (res) {
PrintAndLogEx(WARNING, "Failed convert on load to new Ultralight/NTAG format");
free(dump);
return res;
}
mfu_dump_t *mem = (mfu_dump_t *)dump;
uint8_t pages = (bytes_read - 48) / 4;
uint8_t pages = (bytes_read - MFU_DUMP_PREFIX_LENGTH) / 4;
if (pages - 1 != mem->pages) {
PrintAndLogEx(WARNING, "Error, invalid dump, wrong page count");
free(dump);
return 1;
}
PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", filename);
// print dump
printMFUdumpEx(mem, pages, 0);
@ -2134,7 +2150,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
if (read_key) {
// try reading key from dump and use.
memcpy(c.d.asBytes, mem->data + (bytes_read - 48 - 8), 4);
memcpy(c.d.asBytes, mem->data + (bytes_read - MFU_DUMP_PREFIX_LENGTH - 8), 4);
} else {
memcpy(c.d.asBytes, p_authkey, 4);
}
@ -2150,10 +2166,9 @@ static int CmdHF14AMfURestore(const char *Cmd) {
memcpy(c.d.asBytes + 4, authkey, 4);
}
// pack
// pack now stored in dump
c.arg[0] = MFU_NTAG_SPECIAL_PACK;
c.d.asBytes[0] = mem->pack[0];
c.d.asBytes[1] = mem->pack[1];
memcpy(c.d.asBytes, mem->data + (bytes_read - MFU_DUMP_PREFIX_LENGTH - 4), 2);
c.d.asBytes[2] = 0;
c.d.asBytes[3] = 0;
PrintAndLogEx(NORMAL, "special PACK block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PACK, sprint_hex(c.d.asBytes, 4));

View file

@ -12,7 +12,10 @@
#include "comms.h"
#include "loclass/fileutils.h"
#define DUMP_PREFIX_LENGTH 48
// Old Ultralight/NTAG dump file format
// It is used only for converting
#define OLD_MFU_DUMP_PREFIX_LENGTH 48
typedef struct {
uint8_t version[8];
@ -23,7 +26,8 @@ typedef struct {
uint8_t signature[32];
//uint8_t counter[3];
uint8_t data[1024];
} mfu_dump_t;
} old_mfu_dump_t;
uint32_t GetHF14AMfU_Type(void);
int ul_print_type(uint32_t tagtype, uint8_t spaces);

View file

@ -218,20 +218,24 @@ int saveFileJSON(const char *preferredName, const char *suffix, JSONFileType fty
memcpy(uid, tmp->data, 3);
memcpy(uid + 3, tmp->data + 4, 4);
char path[PATH_MAX_LENGTH] = {0};
JsonSaveBufAsHexCompact(root, "$.Card.UID", uid, sizeof(uid));
JsonSaveBufAsHexCompact(root, "$.Card.Version", tmp->version, sizeof(tmp->version));
JsonSaveBufAsHexCompact(root, "$.Card.TBO_0", tmp->tbo, sizeof(tmp->tbo));
JsonSaveBufAsHexCompact(root, "$.Card.Tearing", tmp->tearing, sizeof(tmp->tearing));
JsonSaveBufAsHexCompact(root, "$.Card.Pack", tmp->pack, sizeof(tmp->pack));
JsonSaveBufAsHexCompact(root, "$.Card.TBO_1", tmp->tbo1, sizeof(tmp->tbo1));
JsonSaveBufAsHexCompact(root, "$.Card.Signature", tmp->signature, sizeof(tmp->signature));
JsonSaveStr(root, "$.Card.Counter", "N/A");
for (uint8_t i = 0; i < 3; i ++) {
sprintf(path, "$.Card.Counter%d", i);
JsonSaveBufAsHexCompact(root, path, tmp->counter_tearing[i], 3);
sprintf(path, "$.Card.Tearing%d", i);
JsonSaveBufAsHexCompact(root, path, tmp->counter_tearing[i] + 3, 1);
}
// size of header 48b
size_t len = (datalen - DUMP_PREFIX_LENGTH) / 4;
// size of header 56b
size_t len = (datalen - MFU_DUMP_PREFIX_LENGTH) / 4;
for (size_t i = 0; i < len; i++) {
char path[PATH_MAX_LENGTH] = {0};
sprintf(path, "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, tmp->data + (i * 4), 4);
}
@ -564,6 +568,39 @@ out:
return retval;
}
int convertOldMfuDump(uint8_t **dump, size_t *dumplen) {
if (!dump || !dumplen || *dumplen < OLD_MFU_DUMP_PREFIX_LENGTH)
return 1;
// try to check new file format
mfu_dump_t *mfu_dump = (mfu_dump_t *) *dump;
if ((*dumplen - MFU_DUMP_PREFIX_LENGTH) / 4 - 1 == mfu_dump->pages)
return 0;
// convert old format
old_mfu_dump_t *old_mfu_dump = (old_mfu_dump_t *) *dump;
size_t old_data_len = *dumplen - OLD_MFU_DUMP_PREFIX_LENGTH;
size_t new_dump_len = old_data_len + MFU_DUMP_PREFIX_LENGTH;
mfu_dump = (mfu_dump_t *) calloc(new_dump_len, sizeof(uint8_t));
memcpy(mfu_dump->version, old_mfu_dump->version, 8);
memcpy(mfu_dump->tbo, old_mfu_dump->tbo, 2);
mfu_dump->tbo1[0] = old_mfu_dump->tbo1[0];
memcpy(mfu_dump->signature, old_mfu_dump->signature, 32);
for (int i = 0; i < 3; i++)
mfu_dump->counter_tearing[i][3] = old_mfu_dump->tearing[i];
memcpy(mfu_dump->data, old_mfu_dump->data, old_data_len);
mfu_dump->pages = old_data_len / 4 - 1;
// free old buffer, return new buffer
*dumplen = new_dump_len;
free(*dump);
*dump = (uint8_t *) mfu_dump;
PrintAndLogDevice(SUCCESS, "old mfu dump format, was converted on load to " _GREEN_("%d") " pages", mfu_dump->pages + 1);
return 0;
}
#else //if we're on ARM
#endif

View file

@ -158,6 +158,15 @@ int loadFileJSON(const char *preferredName, const char *suffix, void *data, size
*/
int loadFileDICTIONARY(const char *preferredName, const char *suffix, void *data, size_t *datalen, uint8_t keylen, uint16_t *keycnt);
/**
* @brief Utility function to check and convert old mfu dump format to new
*
* @param dump pointer to loaded dump to check and convert format
* @param dumplen the number of bytes loaded dump and converted
* @return 0 for ok, 1 for fails
*/
int convertOldMfuDump(uint8_t **dump, size_t *dumplen);
#define PrintAndLogDevice(level, format, args...) PrintAndLogEx(level, format , ## args)
#else
@ -171,6 +180,7 @@ int loadFileDICTIONARY(const char *preferredName, const char *suffix, void *data
#define PrintAndLogDevice(level, format, args...) { }
#endif //ON_DEVICE
#endif // FILEUTILS_H

View file

@ -104,11 +104,11 @@ local function main(args)
-- lua uses start index and endindex, not count.
-- UID is 3three skip bcc0 then 4bytes.
-- 1 lua is one-index.
-- 1 + 96 (48*2) new dump format has version/signature/counter data here
-- 97,98,99,100,101,102 UID first three bytes
-- 103,104 bcc0
-- 105--- UID last four bytes
local uid = string.sub(dumpdata, 97, 97+5)..string.sub(dumpdata, 97+8, 97+8+7)
-- 1 + 112 (56*2) new dump format has version/signature/counter data here
-- 113,114,115,116,117,118 UID first three bytes
-- 119,120 bcc0
-- 121--- UID last four bytes
local uid = string.sub(dumpdata, 113, 113+5)..string.sub(dumpdata, 113+8, 113+8+7)
output = output or (uid .. ".eml")
-- Format some linebreaks

View file

@ -19,6 +19,23 @@
#define MF_MAD1_SECTOR 0x00
#define MF_MAD2_SECTOR 0x10
//-----------------------------------------------------------------------------
// Common types, used by client and ARM
//-----------------------------------------------------------------------------
// New Ultralight/NTAG dump file format
// Length must be aligned to 4 bytes (UL/NTAG page)
#define MFU_DUMP_PREFIX_LENGTH 56
typedef struct {
uint8_t version[8];
uint8_t tbo[2];
uint8_t tbo1[1];
uint8_t pages; // max page number in dump
uint8_t signature[32];
uint8_t counter_tearing[3][4]; // 3 bytes counter, 1 byte tearing flag
uint8_t data[1024];
} mfu_dump_t;
//-----------------------------------------------------------------------------
// ISO 14443A
//-----------------------------------------------------------------------------