diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e20a023f..8198cd15b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ 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] + - Added `HF_15SIM` standalone mode that dump then simulate iso15 tags (@lnv42) + - Changed `iso15 simulation`, reworked, added support for lot of features (@lnv42) + - Changed `hf 15 sniff` quality while low signal (@lnv42) - Fixed `hf sniff` broken since 17ab86c52 (@nvx) - Added `--dumpmem` to proxmark3 client for memory dumping to file (@martian01010) - Changed `hw readmem` to allow larger reads, write to file and better hex viewer (@martian01010) diff --git a/armsrc/Standalone/Makefile.hal b/armsrc/Standalone/Makefile.hal index 62dd8813d..91d87dd14 100644 --- a/armsrc/Standalone/Makefile.hal +++ b/armsrc/Standalone/Makefile.hal @@ -80,6 +80,9 @@ define KNOWN_STANDALONE_DEFINITIONS | HF_15SNIFF | 15693 sniff to flashmem (rdv4) or ram | | | | +----------------------------------------------------------+ +| HF_15SIM | 15693 tag simulator | +| | | ++----------------------------------------------------------+ | HF_AVEFUL | Mifare ultralight read/simulation | | | - Ave Ozkal | +----------------------------------------------------------+ @@ -136,7 +139,7 @@ endef STANDALONE_MODES := LF_SKELETON STANDALONE_MODES += LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_MULTIHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE -STANDALONE_MODES += HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_AVEFUL HF_BOG HF_CARDHOPPER HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_UNISNIFF HF_YOUNG +STANDALONE_MODES += HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_15SIM HF_AVEFUL HF_BOG HF_CARDHOPPER HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_UNISNIFF HF_YOUNG STANDALONE_MODES += DANKARMULTI STANDALONE_MODES_REQ_BT := HF_CARDHOPPER HF_REBLAY STANDALONE_MODES_REQ_SMARTCARD := diff --git a/armsrc/Standalone/Makefile.inc b/armsrc/Standalone/Makefile.inc index 6f9ec5465..5873c0aff 100644 --- a/armsrc/Standalone/Makefile.inc +++ b/armsrc/Standalone/Makefile.inc @@ -89,6 +89,10 @@ endif ifneq (,$(findstring WITH_STANDALONE_HF_15SNIFF,$(APP_CFLAGS))) SRC_STANDALONE = hf_15sniff.c endif +# WITH_STANDALONE_HF_15SIM +ifneq (,$(findstring WITH_STANDALONE_HF_15SIM,$(APP_CFLAGS))) + SRC_STANDALONE = hf_15sim.c +endif # WITH_STANDALONE_HF_AVEFUL ifneq (,$(findstring WITH_STANDALONE_HF_AVEFUL,$(APP_CFLAGS))) SRC_STANDALONE = hf_aveful.c diff --git a/armsrc/Standalone/hf_15sim.c b/armsrc/Standalone/hf_15sim.c new file mode 100644 index 000000000..edea4b30f --- /dev/null +++ b/armsrc/Standalone/hf_15sim.c @@ -0,0 +1,238 @@ +//----------------------------------------------------------------------------- +// Copyright (C) lnv42 2024 +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// Main code for standalone HF/iso15693 Simulation +// This code is trying to dump an iso15 tag, then simulate it +// It doesn't support any password protected/authenticated features +//----------------------------------------------------------------------------- + +#include "standalone.h" // standalone definitions +#include "proxmark3_arm.h" +#include "fpgaloader.h" +#include "iso15693.h" +#include "iso15.h" +#include "protocols.h" +#include "iso15693tools.h" +#include "util.h" +#include "spiffs.h" +#include "appmain.h" +#include "dbprint.h" +#include "ticks.h" +#include "BigBuf.h" +#include "crc16.h" + +#define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1) +//#define CalculateCrc15(data, len) Crc16ex(CRC_15693, (data), (len) + 2); +#define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len)) + +#define ISO15693_READER_TIMEOUT 330 // 330/212kHz = 1558us +#define HF_15693SIM_LOGFILE "hf_15693sim.trace" + +static void DownloadTraceInstructions(void) { + Dbprintf(""); +#ifdef WITH_FLASH + Dbprintf("To get the trace from flash and display it:"); + Dbprintf("1. mem spiffs dump -s "HF_15693SIM_LOGFILE" -d hf_15693sim.trace"); + Dbprintf("2. trace load -f hf_15693sim.trace"); + Dbprintf("3. trace list -t 15 -1"); +#else + Dbprintf("To get the trace from PM3 memory:"); + Dbprintf("trace list -t 15"); +#endif +} + +void ModInfo(void) { + DbpString(" HF 15693 SIM, a ISO15693 simulator - lnv42"); + DownloadTraceInstructions(); +} + +void RunMod(void) { + StandAloneMode(); + + Dbprintf(_YELLOW_("HF 15693 SIM started")); +#ifdef WITH_FLASH + rdv40_spiffs_lazy_mount(); +#endif + + FpgaDownloadAndGo(FPGA_BITSTREAM_HF_15); + + iso15_tag_t *tag = (iso15_tag_t*) BigBuf_get_EM_addr(); + if (tag == NULL) return; + + uint8_t cmd[8] = {0}; + int res; + uint16_t recvLen; + uint8_t recv[32]; + uint32_t eof_time = 0, start_time; + + cmd[0] = ISO15_REQ_DATARATE_HIGH; + cmd[1] = ISO15693_GET_SYSTEM_INFO; + AddCrc15(cmd, 2); + uint8_t i; + + LED_B_ON(); + + Dbprintf("Wait for a dumpable tag"); + + while (1) { + SpinDelay(200); + LED_B_OFF(); + if (BUTTON_HELD(500) > 0) + { + LEDsoff(); + Dbprintf("Quiting"); + return; + } + start_time = 0;//eof_time; + res = SendDataTag(cmd, 4, true, true, recv, sizeof(recv), start_time, ISO15693_READER_TIMEOUT, &eof_time, &recvLen); + if (res < 0) + continue; + if (recvLen<10) // error: recv too short + { + Dbprintf("recvLen<10"); + continue; + } + if (!CheckCrc15(recv,recvLen)) // error crc not valid + { + Dbprintf("crc failed"); + continue; + } + if (recv[0] & ISO15_RES_ERROR) // received error from tag + { + Dbprintf("error received"); + continue; + } + + Dbprintf("Start dumping tag"); + + memset(tag, 0, sizeof(iso15_tag_t)); + memcpy(tag->uid, &recv[2], 8); + + i=10; + if (recv[1] & 0x01) + tag->dsfid = recv[i++]; + if (recv[1] & 0x02) + tag->afi = recv[i++]; + if (recv[1] & 0x04) + { + tag->pagesCount = recv[i++]+1; + tag->bytesPerPage = recv[i++]+1; + } + else + { // Set default tag values (if can't be readed in SYSINFO) + tag->bytesPerPage = 4; + tag->pagesCount = 128; + } + if (recv[1] & 0x08) + tag->ic = recv[i++]; + break; + } + + cmd[0] = ISO15_REQ_DATARATE_HIGH | ISO15_REQ_OPTION; + cmd[1] = ISO15693_READBLOCK; + + uint8_t blocknum = 0; + int retry; + + for (retry = 0; retry < 8; retry++) { + if (blocknum >= tag->pagesCount) + break; + + cmd[2] = blocknum; + AddCrc15(cmd, 3); + + start_time = eof_time; + res = SendDataTag(cmd, 5, false, true, recv, sizeof(recv), start_time, ISO15693_READER_TIMEOUT, &eof_time, &recvLen); + + if (res < 0) + { + SpinDelay(100); + continue; + } + if (recvLen < 4 + tag->bytesPerPage) // error: recv too short + { + Dbprintf("recvLen < 4 + tag->bytesPerPage"); + continue; + } + if (!CheckCrc15(recv,recvLen)) // error crc not valid + { + Dbprintf("crc failed"); + continue; + } + if (recv[0] & ISO15_RES_ERROR) // received error from tag + { + Dbprintf("error received"); + continue; + } + + tag->locks[blocknum] = recv[1]; + memcpy(&tag->data[blocknum * tag->bytesPerPage], recv + 2, tag->bytesPerPage); + retry = 0; + blocknum++; + } + + LEDsoff(); + if (retry >= 8) + { + Dbprintf("Max retry attemps exeeded"); + Dbprintf("-=[ exit ]=-"); + return; + } + + Dbprintf("Tag dumped"); + Dbprintf("Start simulation"); + + SimTagIso15693(0, 0); + + Dbprintf("Simulation stopped"); + SpinDelay(200); + + uint32_t trace_len = BigBuf_get_traceLen(); +#ifndef WITH_FLASH + // Keep stuff in BigBuf for USB/BT dumping + if (trace_len > 0) + Dbprintf("[!] Trace length (bytes) = %u", trace_len); +#else + // Write stuff to spiffs logfile + if (trace_len > 0) { + Dbprintf("[!] Trace length (bytes) = %u", trace_len); + + uint8_t *trace_buffer = BigBuf_get_addr(); + if (!exists_in_spiffs(HF_15693SSIM_LOGFILE)) { + rdv40_spiffs_write( + HF_15693SIM_LOGFILE, trace_buffer, trace_len, RDV40_SPIFFS_SAFETY_SAFE); + Dbprintf("[!] Wrote trace to "HF_15693SIM_LOGFILE); + } else { + rdv40_spiffs_append( + HF_15693SIM_LOGFILE, trace_buffer, trace_len, RDV40_SPIFFS_SAFETY_SAFE); + Dbprintf("[!] Appended trace to "HF_15693SIM_LOGFILE); + } + } else { + Dbprintf("[!] Trace buffer is empty, nothing to write!"); + } + + LED_D_ON(); + rdv40_spiffs_lazy_unmount(); + LED_D_OFF(); + + SpinErr(LED_A, 200, 5); + SpinDelay(100); +#endif + + Dbprintf("-=[ exit ]=-"); + LEDsoff(); + DownloadTraceInstructions(); +} diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index b9115b561..7e2302725 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -107,7 +107,7 @@ /////////////////////////////////////////////////////////////////////// // buffers -#define ISO15693_MAX_RESPONSE_LENGTH 36 // allows read single block with the maximum block size of 256bits. Read multiple blocks not supported yet +#define ISO15693_MAX_RESPONSE_LENGTH 2116 // allows read multiple block with the maximum block size of 256bits and a maximum block number of 64 with REQ_OPTION (lock status for each block). #define ISO15693_MAX_COMMAND_LENGTH 45 // allows write single block with the maximum block size of 256bits. Write multiple blocks not supported yet // 32 + 2 crc + 1 @@ -120,6 +120,7 @@ //#define Crc(data, len) Crc(CRC_15693, (data), (len)) #define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len)) #define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1) +#define CalculateCrc15(data, len) Crc16ex(CRC_15693, (data), (len)) static void BuildIdentifyRequest(uint8_t *cmd); @@ -1200,42 +1201,39 @@ static int RAMFUNC Handle15693SampleFromReader(bool bit, DecodeReader_t *reader) break; case STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF: - reader->posCount++; if (bit) { // detected rising edge - if (reader->posCount < 4) { // rising edge too early (nominally expected at 5) + if (reader->posCount < 2) { // rising edge too early (nominally expected at 4) reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; } else { // SOF reader->state = STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF; + reader->posCount = 1; } } else { - if (reader->posCount > 5) { // stayed low for too long + reader->posCount++; + if (reader->posCount > 6) { // stayed low for too long DecodeReaderReset(reader); - } else { - // do nothing, keep waiting } } break; case STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF: - - reader->posCount++; - - if (bit == false) { // detected a falling edge - - if (reader->posCount < 20) { // falling edge too early (nominally expected at 21 earliest) + if (!bit) { // detected a falling edge + if (reader->posCount < 14) { // falling edge too early (nominally expected at 16 earliest) DecodeReaderReset(reader); - } else if (reader->posCount < 23) { // SOF for 1 out of 4 coding + } else if (reader->posCount <= 18) { // SOF for 1 out of 4 coding reader->Coding = CODING_1_OUT_OF_4; reader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; - } else if (reader->posCount < 28) { // falling edge too early (nominally expected at 29 latest) + reader->posCount = 1; + } else if (reader->posCount < 22) { // falling edge too early (nominally expected at 24 latest) DecodeReaderReset(reader); - } else { // SOF for 1 out of 256 coding + } else { // SOF for 1 out of 256 coding reader->Coding = CODING_1_OUT_OF_256; reader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; + reader->posCount = 1; } - } else { - if (reader->posCount > 29) { // stayed high for too long + reader->posCount++; + if (reader->posCount > 26) { // stayed high for too long reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; } else { // do nothing, keep waiting @@ -1244,60 +1242,42 @@ static int RAMFUNC Handle15693SampleFromReader(bool bit, DecodeReader_t *reader) break; case STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF: - - reader->posCount++; - if (bit) { // detected rising edge - if (reader->Coding == CODING_1_OUT_OF_256) { - if (reader->posCount < 32) { // rising edge too early (nominally expected at 33) - reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; - } else { - reader->posCount = 1; - reader->bitCount = 0; + if (reader->posCount < 2) { // rising edge too early (nominally expected at 8) + reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + } else { + reader->posCount = 1; + if (reader->Coding == CODING_1_OUT_OF_256) { + reader->bitCount = 1; reader->byteCount = 0; reader->sum1 = 1; - reader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256; LED_B_ON(); - } - } else { // CODING_1_OUT_OF_4 - if (reader->posCount < 24) { // rising edge too early (nominally expected at 25) - reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; - } else { - reader->posCount = 1; + reader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256; + } else { // CODING_1_OUT_OF_4 reader->state = STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4; } } } else { - if (reader->Coding == CODING_1_OUT_OF_256) { - if (reader->posCount > 34) { // signal stayed low for too long - DecodeReaderReset(reader); - } else { - // do nothing, keep waiting - } - } else { // CODING_1_OUT_OF_4 - if (reader->posCount > 26) { // signal stayed low for too long - DecodeReaderReset(reader); - } else { - // do nothing, keep waiting - } + reader->posCount++; + if (reader->posCount > 6) { // signal stayed low for too long + DecodeReaderReset(reader); + } else { + // do nothing, keep waiting } } break; case STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4: - - reader->posCount++; - if (bit) { - if (reader->posCount == 9) { - reader->posCount = 1; + reader->posCount++; + + if (reader->posCount == 8) { + reader->posCount = 0; reader->bitCount = 0; reader->byteCount = 0; - reader->sum1 = 1; + reader->sum1 = 0; reader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4; LED_B_ON(); - } else { - // do nothing, keep waiting } } else { // unexpected falling edge DecodeReaderReset(reader); @@ -1305,62 +1285,103 @@ static int RAMFUNC Handle15693SampleFromReader(bool bit, DecodeReader_t *reader) break; case STATE_READER_RECEIVE_DATA_1_OUT_OF_4: - - reader->posCount++; - - if (reader->posCount == 1) { - - reader->sum1 = bit ? 1 : 0; - - } else if (reader->posCount <= 4) { - - if (bit) - reader->sum1++; - - } else if (reader->posCount == 5) { - - reader->sum2 = bit ? 1 : 0; - - } else { - if (bit) - reader->sum2++; - } - - if (reader->posCount == 8) { - reader->posCount = 0; - if (reader->sum1 <= 1 && reader->sum2 >= 3) { // EOF - LED_B_OFF(); // Finished receiving - DecodeReaderReset(reader); - if (reader->byteCount != 0) { - return true; - } - - } else if (reader->sum1 >= 3 && reader->sum2 <= 1) { // detected a 2bit position - reader->shiftReg >>= 2; - reader->shiftReg |= (reader->bitCount << 6); - } - - if (reader->bitCount == 15) { // we have a full byte - - reader->output[reader->byteCount++] = reader->shiftReg; - if (reader->byteCount > reader->byteCountMax) { - // buffer overflow, give up - LED_B_OFF(); + if (!bit) { + reader->sum1++; + if (reader->sum1 == 1) { // first low bit + if (reader->posCount <= 6) { // bits : 00 + reader->shiftReg >>= 2; + //reader->shiftReg |= (0 << 6); + reader->bitCount += 2; + reader->posCount = -28; + } else if (reader->posCount <= 9) { // EOF + LED_B_OFF(); // Finished receiving DecodeReaderReset(reader); + if (reader->byteCount > 0) { + return true; + } + } else if (reader->posCount <= 14) { // bits : 01 + reader->shiftReg >>= 2; + reader->shiftReg |= (1 << 6); + reader->bitCount += 2; + reader->posCount = -20; + } else if (reader->posCount < 18) { // unexpected falling edge + DecodeReaderReset(reader); + if (reader->byteCount >= 0) { + reader->output[reader->byteCount++] = reader->posCount; + reader->output[reader->byteCount++] = reader->bitCount; + reader->output[reader->byteCount++] = 0x42; + return true; + } + } else if (reader->posCount <= 22) { // bits : 10 + reader->shiftReg >>= 2; + reader->shiftReg |= (2 << 6); + reader->bitCount += 2; + reader->posCount = -12; + } else if (reader->posCount < 26) { // unexpected falling edge + DecodeReaderReset(reader); + if (reader->byteCount >= 0) { + reader->output[reader->byteCount++] = reader->posCount; + reader->output[reader->byteCount++] = reader->bitCount; + reader->output[reader->byteCount++] = 0x43; + return true; + } + } else { // bits : 11 + reader->shiftReg >>= 2; + reader->shiftReg |= (3 << 6); + reader->bitCount += 2; + reader->posCount = -4; } - reader->bitCount = 0; - reader->shiftReg = 0; - if (reader->byteCount == reader->jam_search_len) { - if (!memcmp(reader->output, reader->jam_search_string, reader->jam_search_len)) { - LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_JAM); - reader->state = STATE_READER_RECEIVE_JAMMING; + if (reader->bitCount == 8) + { + reader->output[reader->byteCount++] = reader->shiftReg; + if (reader->byteCount > reader->byteCountMax) { + // buffer overflow, give up + LED_B_OFF(); + DecodeReaderReset(reader); + } + + reader->bitCount = 0; + reader->shiftReg = 0; + if (reader->byteCount == reader->jam_search_len) { + if (!memcmp(reader->output, reader->jam_search_string, reader->jam_search_len)) { + LED_D_ON(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_JAM); + reader->state = STATE_READER_RECEIVE_JAMMING; + } } } - - } else { - reader->bitCount++; + } else if (reader->sum1 > 6) { // too long low bit + DecodeReaderReset(reader); + if (reader->byteCount >= 0) { + reader->output[reader->byteCount++] = reader->posCount; + reader->output[reader->byteCount++] = reader->bitCount; + reader->output[reader->byteCount++] = 0x44; + return true; + } + } + } else { + reader->posCount++; + if (reader->posCount > 30) { + reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + if (reader->byteCount >= 0) { + reader->output[reader->byteCount++] = reader->posCount; + reader->output[reader->byteCount++] = reader->bitCount; + reader->output[reader->byteCount++] = 0x45; + return true; + } + } + if (reader->sum1 == 1) { + reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + if (reader->byteCount >= 0) { + reader->output[reader->byteCount++] = reader->posCount; + reader->output[reader->byteCount++] = reader->bitCount; + reader->output[reader->byteCount++] = 0x46; + return true; + } + } else if (reader->sum1 > 1) { + reader->posCount += reader->sum1; + reader->sum1 = 0; } } break; @@ -2111,20 +2132,61 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) { // free eventually allocated BigBuf memory BigBuf_free_keep_EM(); - Iso15693InitTag(); + iso15_tag_t *tag = (iso15_tag_t*) BigBuf_get_EM_addr(); + if (tag == NULL) + { + Dbprintf("Can't allocate emulator memory"); + reply_ng(CMD_HF_ISO15693_SIMULATE, PM3_EFAILED, NULL, 0); + return; + } + if (uid != NULL) { // new tag (need initialization) + uint8_t nullUid[8] = { 0 }; + if (memcmp(uid, nullUid, 8) != 0) + { // simulate a new tag bazed on client parameters + memcpy(tag->uid, uid, 8); + tag->dsfid = 0; + tag->dsfidLock = false; + tag->afi = 0; + tag->afiLock = false; + tag->bytesPerPage = (block_size > 0) ? block_size : 4; + tag->pagesCount = 64; + tag->ic = 0; + memset(tag->locks, 0, sizeof(tag->locks)); + memset(tag->data, 0, sizeof(tag->data)); + } + } + if (tag->pagesCount > ISO15693_TAG_MAX_PAGES || \ + tag->pagesCount * tag->bytesPerPage > ISO15693_TAG_MAX_SIZE || + tag->pagesCount == 0 || tag->bytesPerPage == 0) { + Dbprintf("Tag size error: pagesCount = %d, bytesPerPage=%d", tag->pagesCount, tag->bytesPerPage); + reply_ng(CMD_HF_ISO15693_SIMULATE, PM3_EOPABORTED, NULL, 0); + return; + } + + Iso15693InitTag(); // init simulator LED_A_ON(); - Dbprintf("ISO-15963 Simulating uid: %02X%02X%02X%02X%02X%02X%02X%02X block size %d", uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6], uid[7], block_size); + if (g_dbglevel >= DBG_DEBUG) + Dbprintf("ISO-15963 Simulating uid: %02X%02X%02X%02X%02X%02X%02X%02X, %u bytes/blocks x %u blocks", tag->uid[7], tag->uid[6], tag->uid[5], tag->uid[4], tag->uid[3], tag->uid[2], tag->uid[1], tag->uid[0], tag->bytesPerPage, tag->pagesCount); LED_C_ON(); - enum { NO_FIELD, IDLE, ACTIVATED, SELECTED, HALTED } chip_state = NO_FIELD; - bool button_pressed = false; int vHf; // in mV bool exit_loop = false; + uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH] = {0}; + uint8_t recv[ISO15693_MAX_RESPONSE_LENGTH] = {0}; + uint8_t mask_len = 0; + uint8_t maskCpt = 0; + uint8_t cmdCpt = 0; + uint16_t recvLen = 0; + uint8_t error = 0; + uint8_t pageNum = 0; + uint8_t nbPages = 0; + uint8_t pwdId = 0; + while (exit_loop == false) { button_pressed = BUTTON_PRESS(); @@ -2134,11 +2196,11 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) { WDT_HIT(); // find reader field - if (chip_state == NO_FIELD) { + if (tag->state == TAG_STATE_NO_FIELD) { vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15; if (vHf > MF_MINFIELDV) { - chip_state = IDLE; + tag->state = TAG_STATE_READY; LED_A_ON(); } else { continue; @@ -2146,7 +2208,6 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) { } // Listen to reader - uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; uint32_t reader_eof_time = 0; int cmd_len = GetIso15693CommandFromReader(cmd, sizeof(cmd), &reader_eof_time); if (cmd_len < 0) { @@ -2154,171 +2215,365 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) { break; } - // TODO: check more flags - if ((cmd_len >= 5) && (cmd[0] & ISO15_REQ_INVENTORY) && (cmd[1] == ISO15693_INVENTORY)) { - bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); - uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; + if (cmd_len <= 3) + continue; - // Build INVENTORY command - uint8_t resp_inv[CMD_INV_RESP] = {0}; - - resp_inv[0] = 0; // No error, no protocol format extension - resp_inv[1] = 0; // DSFID (data storage format identifier). 0x00 = not supported - - // 64-bit UID - resp_inv[2] = uid[7]; - resp_inv[3] = uid[6]; - resp_inv[4] = uid[5]; - resp_inv[5] = uid[4]; - resp_inv[6] = uid[3]; - resp_inv[7] = uid[2]; - resp_inv[8] = uid[1]; - resp_inv[9] = uid[0]; - - // CRC - AddCrc15(resp_inv, 10); - CodeIso15693AsTag(resp_inv, CMD_INV_RESP); - - tosend_t *ts = get_tosend(); - - TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow); - LogTrace_ISO15693(resp_inv, CMD_INV_RESP, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false); - - chip_state = SELECTED; + // Shorten 0 terminated msgs + // (Some times received commands are prolonged with a random number of 0 bytes...) + while (cmd[cmd_len-1] == 0) { + cmd_len--; + if (cmd_len <= 3) + break; } - // GET_SYSTEM_INFO - if ((cmd[1] == ISO15693_GET_SYSTEM_INFO)) { - bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); - uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; - - // Build GET_SYSTEM_INFO response - uint8_t resp_sysinfo[CMD_SYSINFO_RESP] = {0}; - - resp_sysinfo[0] = 0; // Response flags. - resp_sysinfo[1] = 0x0F; // Information flags (0x0F - DSFID, AFI, Mem size, IC) - - // 64-bit UID - resp_sysinfo[2] = uid[7]; - resp_sysinfo[3] = uid[6]; - resp_sysinfo[4] = uid[5]; - resp_sysinfo[5] = uid[4]; - resp_sysinfo[6] = uid[3]; - resp_sysinfo[7] = uid[2]; - resp_sysinfo[8] = uid[1]; - resp_sysinfo[9] = uid[0]; - - resp_sysinfo[10] = 0; // DSFID - resp_sysinfo[11] = 0; // AFI - - resp_sysinfo[12] = 0x1F; // Block count - resp_sysinfo[13] = block_size - 1; // Block size. - resp_sysinfo[14] = 0x01; // IC reference. - - // CRC - AddCrc15(resp_sysinfo, 15); - CodeIso15693AsTag(resp_sysinfo, CMD_SYSINFO_RESP); - - tosend_t *ts = get_tosend(); - - TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow); - LogTrace_ISO15693(resp_sysinfo, CMD_SYSINFO_RESP, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false); + if (g_dbglevel >= DBG_DEBUG) { + Dbprintf("%d bytes read from reader:", cmd_len); + Dbhexdump(cmd_len, cmd, false); } - // READ_BLOCK and READ_MULTI_BLOCK - if ((cmd[1] == ISO15693_READBLOCK) || (cmd[1] == ISO15693_READ_MULTI_BLOCK)) { - bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); - bool addressed = cmd[0] & ISO15_REQ_ADDRESS; - bool option = cmd[0] & ISO15_REQ_OPTION; - uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; + if (cmd_len < 3) + continue; - uint8_t address_offset = 0; - if (addressed) { - address_offset = 8; - } - - uint8_t block_idx = cmd[2 + address_offset]; - uint8_t block_count = 1; - if (cmd[1] == ISO15693_READ_MULTI_BLOCK) { - block_count = cmd[3 + address_offset] + 1; - } - - // Build READ_(MULTI_)BLOCK response - int response_length = 3 + block_size * block_count; - int security_offset = 0; - if (option) { - response_length += block_count; - security_offset = 1; - } - uint8_t resp_readblock[response_length]; - memset(resp_readblock, 0, response_length); - - resp_readblock[0] = 0; // Response flags - for (int j = 0; j < block_count; j++) { - // where to put the data of the current block - int work_offset = 1 + j * (block_size + security_offset); - if (option) { - resp_readblock[work_offset] = 0; // Security status + // Check CRC and drop received cmd with bad CRC + uint16_t crc = CalculateCrc15(cmd, cmd_len - 2); + if ((( crc & 0xff ) != cmd[cmd_len - 2]) || (( crc >> 8 ) != cmd[cmd_len - 1])) { + crc = CalculateCrc15(cmd, ++cmd_len - 2); // if crc end with 00 + if ((( crc & 0xff ) != cmd[cmd_len - 2]) || (( crc >> 8 ) != cmd[cmd_len - 1])) { + crc = CalculateCrc15(cmd, ++cmd_len - 2); // if crc end with 00 00 + if ((( crc & 0xff ) != cmd[cmd_len - 2]) || (( crc >> 8 ) != cmd[cmd_len - 1])) { + if (g_dbglevel >= DBG_DEBUG) Dbprintf("CrcFail!, expected CRC=%02X%02X", crc & 0xff, crc >> 8); + continue; } - // Block data - if (block_size * (block_idx + j + 1) <= CARD_MEMORY_SIZE) { - emlGet( - resp_readblock + (work_offset + security_offset), - block_size * (block_idx + j), - block_size - ); - } else { - memset(resp_readblock + work_offset + security_offset, 0, block_size); + else if (g_dbglevel >= DBG_DEBUG) + Dbprintf("CrcOK"); + } + else if (g_dbglevel >= DBG_DEBUG) + Dbprintf("CrcOK"); + } + else if (g_dbglevel >= DBG_DEBUG) + Dbprintf("CrcOK"); + + cmd_len -= 2; // remove the CRC from the cmd + recvLen = 0; + + tag->expectFast = ((cmd[0] & ISO15_REQ_DATARATE_HIGH) == ISO15_REQ_DATARATE_HIGH); + tag->expectFsk = ((cmd[0] & ISO15_REQ_SUBCARRIER_TWO) == ISO15_REQ_SUBCARRIER_TWO); + + if (g_dbglevel >= DBG_DEBUG) { + if (tag->expectFsk) + Dbprintf("ISO15_REQ_SUBCARRIER_TWO support is currently experimental!"); + if ((cmd[0] & ISO15_REQ_PROTOCOL_EXT) == ISO15_REQ_PROTOCOL_EXT) + Dbprintf("ISO15_REQ_PROTOCOL_EXT not supported!"); + if ((cmd[0] & ISO15_REQ_OPTION) == ISO15_REQ_OPTION) + Dbprintf("ISO15_REQ_OPTION not supported!"); + } + + if (((cmd[0] & ISO15_REQ_INVENTORY) == ISO15_REQ_INVENTORY) && tag->state != TAG_STATE_SILENCED) { + // REQ_INVENTORY flaged requests are interpreted as a INVENTORY no matter + // what is the CMD (as observed from various actual tags) + + // TODO: support colision avoidances + + if (g_dbglevel >= DBG_DEBUG) { + Dbprintf("Inventory req"); + if ((cmd[0] & ISO15_REQINV_SLOT1) == ISO15_REQINV_SLOT1) + Dbprintf("ISO15_REQINV_SLOT1/SLOT16 not supported!"); + } + + cmdCpt = 2; + + // Check AFI + if ((cmd[0] & ISO15_REQINV_AFI) == ISO15_REQINV_AFI) { + if (cmd[cmdCpt] != tag->afi && cmd[cmdCpt] != 0) + continue; // bad AFI : drop request + cmdCpt++; + } + + // Check mask + if (cmdCpt >= cmd_len) + continue; // mask is not present : drop request + mask_len = cmd[cmdCpt++]; + + maskCpt = 0; + + while (mask_len >= 8 && cmdCpt < (uint8_t)cmd_len && maskCpt < 8) { // Byte comparison + if (cmd[cmdCpt++] != tag->uid[maskCpt++]) { + error++; // mask don't match : drop request + break; + } + mask_len -= 8; + } + + if (mask_len > 0 && cmdCpt >= cmd_len) + continue; // mask is shorter than declared mask lenght: drop request + + while (mask_len > 0) { // Bit comparison + mask_len--; + if (((cmd[cmdCpt] >> mask_len) & 1) != ((tag->uid[maskCpt] >> mask_len) & 1)) { + error++; // mask don't match : drop request + break; } } - // CRC - AddCrc15(resp_readblock, response_length - 2); - CodeIso15693AsTag(resp_readblock, response_length); + if (error > 0) + continue; - tosend_t *ts = get_tosend(); + // No error: Answer + recv[0] = ISO15_NOERROR; + recv[1] = tag->dsfid; + memcpy(&recv[2], tag->uid, 8); + recvLen = 10; + } + else { + if ((cmd[0] & ISO15_REQ_SELECT) == ISO15_REQ_SELECT) { + if (g_dbglevel >= DBG_DEBUG) Dbprintf("Selected Request"); + if (tag->state != TAG_STATE_SELECTED) + continue; // drop selected request if not selected + tag->state = TAG_STATE_READY; // Select flag set if already selected : unselect + } - TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow); - LogTrace_ISO15693(resp_readblock, response_length, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false); + cmdCpt = 2; + if ((cmd[0] & ISO15_REQ_ADDRESS) == ISO15_REQ_ADDRESS) { + if (g_dbglevel >= DBG_DEBUG) Dbprintf("Addressed Request"); + if (cmd_len < cmdCpt+8) + continue; + if (memcmp(&cmd[cmdCpt], tag->uid, 8) != 0) + { + if (cmd_len < cmdCpt+9 || memcmp(&cmd[cmdCpt+1], tag->uid, 8) != 0) + { // check uid even if manifacturer byte is present + if (g_dbglevel >= DBG_DEBUG) Dbprintf("Address don't match tag uid"); + if (cmd[1] == ISO15693_SELECT) + tag->state = TAG_STATE_READY; // we are not anymore the selected TAG + continue; // drop addressed request with other uid + } + cmdCpt++; + } + if (g_dbglevel >= DBG_DEBUG) Dbprintf("Address match tag uid"); + cmdCpt+=8; + } + else if (tag->state == TAG_STATE_SILENCED) + { + if (g_dbglevel >= DBG_DEBUG) Dbprintf("Unaddressed request in quiet state: drop"); + continue; // drop unadressed request in quiet state + } + + switch(cmd[1]) { + case ISO15693_INVENTORY: + if (g_dbglevel >= DBG_DEBUG) Dbprintf("Inventory cmd"); + recv[0] = ISO15_NOERROR; + recv[1] = tag->dsfid; + memcpy(&recv[2], tag->uid, 8); + recvLen = 10; + break; + case ISO15693_STAYQUIET: + if (g_dbglevel >= DBG_DEBUG) Dbprintf("StayQuiet cmd"); + tag->state = TAG_STATE_SILENCED; + break; + case ISO15693_READBLOCK: + if (g_dbglevel >= DBG_DEBUG) Dbprintf("ReadBlock cmd"); + pageNum = cmd[cmdCpt++]; + if (pageNum >= tag->pagesCount) + error = ISO15_ERROR_BLOCK_UNAVAILABLE; + else { + recv[0] = ISO15_NOERROR; + recvLen = 1; + if ((cmd[0] & ISO15_REQ_OPTION) == ISO15_REQ_OPTION) { // ask for lock status + recv[1] = tag->locks[pageNum]; + recvLen++; + } + for (uint8_t i = 0 ; i < tag->bytesPerPage ; i++) + recv[recvLen+i] = tag->data[(pageNum * tag->bytesPerPage) + i]; + recvLen += tag->bytesPerPage; + } + break; + case ISO15693_WRITEBLOCK: + if (g_dbglevel >= DBG_DEBUG) Dbprintf("WriteBlock cmd"); + pageNum = cmd[cmdCpt++]; + if (pageNum >= tag->pagesCount) + error = ISO15_ERROR_BLOCK_UNAVAILABLE; + else { + for (uint8_t i = 0 ; i < tag->bytesPerPage ; i++) + tag->data[(pageNum*tag->bytesPerPage) + i] = cmd[i + cmdCpt]; + recv[0] = ISO15_NOERROR; + recvLen = 1; + } + break; + case ISO15693_LOCKBLOCK: + if (g_dbglevel >= DBG_DEBUG) Dbprintf("LockBlock cmd"); + pageNum = cmd[cmdCpt++]; + if (pageNum >= tag->pagesCount) + error = ISO15_ERROR_BLOCK_UNAVAILABLE; + else if (tag->locks[pageNum]) + error = ISO15_ERROR_BLOCK_LOCKED_ALREADY; + else { + tag->locks[pageNum] = 1; + recv[0] = ISO15_NOERROR; + recvLen = 1; + } + break; + case ISO15693_READ_MULTI_BLOCK: + if (g_dbglevel >= DBG_DEBUG) Dbprintf("ReadMultiBlock cmd"); + pageNum = cmd[cmdCpt++]; + nbPages = cmd[cmdCpt++]; + if (pageNum+nbPages >= tag->pagesCount) + error = ISO15_ERROR_BLOCK_UNAVAILABLE; + else { + recv[0] = ISO15_NOERROR; + recvLen = 1; + for (int i = 0 ; i < (nbPages + 1) * tag->bytesPerPage && \ + recvLen + 3 < ISO15693_MAX_RESPONSE_LENGTH ; i++) { + if ((i % tag->bytesPerPage) == 0 && (cmd[0] & ISO15_REQ_OPTION)) + recv[recvLen++] = tag->locks[pageNum + (i / tag->bytesPerPage)]; + recv[recvLen++] = tag->data[(pageNum * tag->bytesPerPage) + i]; + } + if (recvLen + 3 > ISO15693_MAX_RESPONSE_LENGTH) // limit response size + recvLen = ISO15693_MAX_RESPONSE_LENGTH - 3; // to avoid overflow + } + break; + case ISO15693_WRITE_AFI: + if (g_dbglevel >= DBG_DEBUG) Dbprintf("WriteAFI cmd"); + if (tag->afiLock) + error = ISO15_ERROR_BLOCK_LOCKED; + else { + tag->afi = cmd[cmdCpt++]; + recv[0] = ISO15_NOERROR; + recvLen = 1; + } + break; + case ISO15693_LOCK_AFI: + if (g_dbglevel >= DBG_DEBUG) Dbprintf("LockAFI cmd"); + if (tag->afiLock) + error = ISO15_ERROR_BLOCK_LOCKED_ALREADY; + else { + tag->afiLock = true; + recv[0] = ISO15_NOERROR; + recvLen = 1; + } + break; + case ISO15693_WRITE_DSFID: + if (g_dbglevel >= DBG_DEBUG) Dbprintf("WriteDSFID cmd"); + if (tag->dsfidLock) + error = ISO15_ERROR_BLOCK_LOCKED; + else { + tag->dsfid = cmd[cmdCpt++]; + recv[0] = ISO15_NOERROR; + recvLen = 1; + } + break; + case ISO15693_LOCK_DSFID: + if (g_dbglevel >= DBG_DEBUG) Dbprintf("LockDSFID cmd"); + if (tag->dsfidLock) + error = ISO15_ERROR_BLOCK_LOCKED_ALREADY; + else { + tag->dsfidLock = true; + recv[0] = ISO15_NOERROR; + recvLen = 1; + } + break; + case ISO15693_SELECT: + if (g_dbglevel >= DBG_DEBUG) Dbprintf("Select cmd"); + tag->state = TAG_STATE_SELECTED; + recv[0] = ISO15_NOERROR; + recvLen = 1; + break; + case ISO15693_RESET_TO_READY: + if (g_dbglevel >= DBG_DEBUG) Dbprintf("ResetToReady cmd"); + tag->state = TAG_STATE_READY; + recv[0] = ISO15_NOERROR; + recvLen = 1; + break; + case ISO15693_GET_SYSTEM_INFO: + if (g_dbglevel >= DBG_DEBUG) Dbprintf("GetSystemInfo cmd"); + recv[0] = ISO15_NOERROR; + recv[1] = 0x0f; // sysinfo contain all info + memcpy(&recv[2], tag->uid, 8); + recv[10] = tag->dsfid; + recv[11] = tag->afi; + recv[12] = tag->pagesCount - 1; + recv[13] = tag->bytesPerPage - 1; + recv[14] = tag->ic; + recvLen = 15; + break; + case ISO15693_READ_MULTI_SECSTATUS: + if (g_dbglevel >= DBG_DEBUG) Dbprintf("ReadMultiSecStatus cmd"); + pageNum = cmd[cmdCpt++]; + nbPages = cmd[cmdCpt++]; + if (pageNum + nbPages >= tag->pagesCount) + error = ISO15_ERROR_BLOCK_UNAVAILABLE; + else { + recv[0] = ISO15_NOERROR; + recvLen = 1; + for (uint8_t i = 0 ; i < nbPages + 1 ; i++) + recv[recvLen++] = tag->locks[pageNum + i]; + } + break; + case ISO15693_GET_RANDOM_NUMBER: + if (g_dbglevel >= DBG_DEBUG) Dbprintf("GetRandomNumber cmd"); + tag->random[0] = (uint8_t)(reader_eof_time) ^ 0xFF; // poor random number + tag->random[1] = (uint8_t)(reader_eof_time >> 8) ^ 0xFF; + recv[0] = ISO15_NOERROR; + recv[1] = tag->random[0]; // poor random number + recv[2] = tag->random[1]; + recvLen = 3; + break; + case ISO15693_SET_PASSWORD: + if (g_dbglevel >= DBG_DEBUG) Dbprintf("SetPassword cmd"); + if (cmd_len > cmdCpt+5) + cmdCpt++; // skip manifacturer code + if (cmd_len > cmdCpt+4) + { + pwdId = cmd[cmdCpt++]; + if (pwdId == 4) // Privacy password + { + tag->privacyPasswd[0] = cmd[cmdCpt] ^ tag->random[0]; + tag->privacyPasswd[1] = cmd[cmdCpt+1] ^ tag->random[1]; + tag->privacyPasswd[2] = cmd[cmdCpt+2] ^ tag->random[0]; + tag->privacyPasswd[3] = cmd[cmdCpt+3] ^ tag->random[1]; + } + } + recv[0] = ISO15_NOERROR; + recvLen = 1; + break; + case ISO15693_ENABLE_PRIVACY: + if (g_dbglevel >= DBG_DEBUG) Dbprintf("EnablePrivacy cmd"); + // not realy entering privacy mode + // just return NOERROR + recv[0] = ISO15_NOERROR; + recvLen = 1; + break; + default: + if (g_dbglevel >= DBG_DEBUG) + Dbprintf("ISO15693 CMD 0x%2X not supported", cmd[1]); + + error = ISO15_ERROR_CMD_NOT_SUP; + break; + } + + if (error != 0) { // Error happened + recv[0] = ISO15_RES_ERROR; + recv[1] = error; + recvLen = 2; + error = 0; + if (g_dbglevel >= DBG_DEBUG) + Dbprintf("ERROR 0x%2X in received request", error); + } } - // WRITE_BLOCK and WRITE_MULTI_BLOCK - if ((cmd[1] == ISO15693_WRITEBLOCK) || (cmd[1] == ISO15693_WRITE_MULTI_BLOCK)) { - bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH); - bool addressed = cmd[0] & ISO15_REQ_ADDRESS; + if (recvLen > 0) { // We need to answer + AddCrc15(recv, recvLen); + recvLen += 2; + CodeIso15693AsTag(recv, recvLen); + tosend_t *ts = get_tosend(); uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; - uint8_t address_offset = 0; - if (addressed) { - address_offset = 8; + if (tag->expectFsk) { // Not suppoted yet + if (g_dbglevel >= DBG_DEBUG) Dbprintf("%ERROR: FSK answers are not supported yet"); + //TransmitTo15693ReaderFSK(ts->buf,ts->max, &response_time, 0, !tag->expectFast); } + else + TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, !tag->expectFast); - uint8_t block_idx = cmd[2 + address_offset]; - uint8_t block_count = 1; - uint8_t multi_offset = 0; - if (cmd[1] == ISO15693_WRITE_MULTI_BLOCK) { - block_count = cmd[3 + address_offset] + 1; - multi_offset = 1; - } - uint8_t *data = cmd + 3 + address_offset + multi_offset; - - // write data - emlSet(data, (block_idx * block_size), (block_count * block_size)); - - // Build WRITE_(MULTI_)BLOCK response - int response_length = 3; - uint8_t resp_writeblock[response_length]; - memset(resp_writeblock, 0, response_length); - resp_writeblock[0] = 0; // Response flags - - // CRC - AddCrc15(resp_writeblock, response_length - 2); - CodeIso15693AsTag(resp_writeblock, response_length); - - tosend_t *ts = get_tosend(); - - TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow); - LogTrace_ISO15693(resp_writeblock, response_length, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false); + LogTrace_ISO15693(recv, recvLen, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false); } } diff --git a/client/src/cmdhf15.c b/client/src/cmdhf15.c index 55ae1c028..84e677946 100644 --- a/client/src/cmdhf15.c +++ b/client/src/cmdhf15.c @@ -532,15 +532,13 @@ static uint8_t arg_add_default(void *at[]) { } static uint16_t arg_get_raw_flag(uint8_t uidlen, bool unaddressed, bool scan, bool add_option) { uint16_t flags = 0; - if (unaddressed) { - // unaddressed mode may not be supported by all vendors - flags |= (ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY); +; + if (uidlen == 8 || scan || unaddressed) { + flags = (ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY); } - if (uidlen == 8) { - flags |= (ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS); - } - if (scan) { - flags |= (ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS); + if ((!unaddressed) || scan) + { + flags |= ISO15_REQ_ADDRESS; } if (add_option) { flags |= (ISO15_REQ_OPTION); @@ -1176,7 +1174,7 @@ static int CmdHF15ELoad(const char *Cmd) { return res; } - if (bytes_read > CARD_MEMORY_SIZE) { + if (bytes_read > CARD_MEMORY_SIZE || bytes_read > sizeof(iso15_tag_t)) { PrintAndLogEx(FAILED, "Memory image too large."); free(data); return PM3_EINVARG; @@ -1232,13 +1230,10 @@ static int CmdHF15ESave(const char *Cmd) { CLIParserInit(&ctx, "hf 15 esave", "Save emulator memory into two files (bin/json) ", "hf 15 esave -f hf-15-01020304" - "hf 15 esave -b 8 -c 42 -f hf-15-01020304" ); void *argtable[] = { arg_param_begin, arg_str1("f", "file", "", "Specify a filename for dump file"), - arg_int0(NULL, "bsize", "", "block size (def 4)"), - arg_int0("c", "count", "", "number of blocks to export (def all)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -1246,20 +1241,9 @@ static int CmdHF15ESave(const char *Cmd) { int fnlen = 0; char filename[FILE_PATH_SIZE]; CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); - int blocksize = arg_get_int_def(ctx, 2, 4); - int count = arg_get_int_def(ctx, 3, -1); CLIParserFree(ctx); - // sanity checks - if (blocksize < 4) { - PrintAndLogEx(WARNING, "Blocksize too small, using default 4 bytes"); - blocksize = 4; - } - - int bytes = CARD_MEMORY_SIZE; - if (count > 0 && count * blocksize <= bytes) { - bytes = count * blocksize; - } + int bytes = sizeof(iso15_tag_t); // reserve memory uint8_t *dump = calloc(bytes, sizeof(uint8_t)); @@ -1275,11 +1259,7 @@ static int CmdHF15ESave(const char *Cmd) { return PM3_ETIMEOUT; } - if (blocksize == 8) { - pm3_save_dump(filename, dump, bytes, jsf15_v3); - } else { - pm3_save_dump(filename, dump, bytes, jsf15_v2); - } + pm3_save_dump(filename, dump, bytes, jsf15_v4); free(dump); return PM3_SUCCESS; @@ -1297,6 +1277,13 @@ static void print_blocks_15693(uint8_t *data, uint16_t bytes, int blocksize, boo PrintAndLogEx(INFO, "----------- " _CYAN_("Tag Memory") " ---------------"); PrintAndLogEx(NORMAL, ""); + + if (blocksize == 0 || bytes == 0) + { + PrintAndLogEx(INFO, "Tag is empty!"); + return; + } + print_hrule(blocksize); char spaces[] = " "; @@ -1354,38 +1341,46 @@ static void print_blocks_15693(uint8_t *data, uint16_t bytes, int blocksize, boo PrintAndLogEx(NORMAL, ""); } +static void print_emltag_info_15693(iso15_tag_t *tag) { + PrintAndLogEx(SUCCESS, " TYPE... " _YELLOW_("%s"), getTagInfo_15(tag->uid)); + PrintAndLogEx(SUCCESS, " UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, tag->uid)); + PrintAndLogEx(SUCCESS, " - DSFID [0x%02X]", tag->dsfid); + PrintAndLogEx(SUCCESS, " - AFI [0x%02X]", tag->afi); + PrintAndLogEx(SUCCESS, " - IC reference [0x%02X]", tag->ic); + PrintAndLogEx(SUCCESS, " - Tag memory layout"); + PrintAndLogEx(SUCCESS, " %u bytes/blocks x %u blocks", tag->bytesPerPage, tag->pagesCount); +} + +static void print_emltag_15693(iso15_tag_t *tag, bool dense_output) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Emulator Tag Information") " ---------------------------"); + + print_emltag_info_15693(tag); + + print_blocks_15693(tag->data, (tag->pagesCount * tag->bytesPerPage), + tag->bytesPerPage, dense_output); +} + static int CmdHF15EView(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf 15 eview", "It displays emulator memory", "hf 15 eview\n" - "hf 15 eview -b 8 -c 60\n" + "hf 15 eview -z\n" ); void *argtable[] = { arg_param_begin, - arg_int0("b", "blocksize", "", "block size (def 4)"), - arg_int0("c", "count", "", "number of blocks to display (def all)"), arg_lit0("z", "dense", "dense dump output style"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - int blocksize = arg_get_int_def(ctx, 1, 4); - int count = arg_get_int_def(ctx, 2, -1); - bool dense_output = (g_session.dense_output || arg_get_lit(ctx, 3)); + bool dense_output = (g_session.dense_output || arg_get_lit(ctx, 1)); CLIParserFree(ctx); - // santity checks - if (blocksize < 4) { - PrintAndLogEx(WARNING, "Blocksize too small, using default 4 bytes"); - blocksize = 4; - } - - int bytes = CARD_MEMORY_SIZE; - if (count > 0 && count * blocksize <= bytes) { - bytes = count * blocksize; - } + int bytes = sizeof(iso15_tag_t); + // reserve memory uint8_t *dump = calloc(bytes, sizeof(uint8_t)); if (dump == NULL) { PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); @@ -1399,7 +1394,8 @@ static int CmdHF15EView(const char *Cmd) { return PM3_ETIMEOUT; } - print_blocks_15693(dump, bytes, blocksize, dense_output); + print_emltag_15693((iso15_tag_t *)dump, dense_output); + free(dump); return PM3_SUCCESS; } @@ -1411,39 +1407,49 @@ static int CmdHF15Sim(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf 15 sim", "Simulate a ISO-15693 tag\n", + "hf 15 sim\n" "hf 15 sim -u E011223344556677"); - void *argtable[] = { arg_param_begin, - arg_str1("u", "uid", "", "UID, 8 hex bytes"), + arg_str0("u", "uid", "", "UID, 8 hex bytes"), arg_int0("b", "blocksize", "", "block size (def 4)"), arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, false); + CLIExecWithReturn(ctx, Cmd, argtable, true); struct { uint8_t uid[HF15_UID_LENGTH]; uint8_t block_size; } PACKED payload; + memset(&payload, 0, sizeof(payload)); int uidlen = 0; CLIGetHexWithReturn(ctx, 1, payload.uid, &uidlen); - if (uidlen != HF15_UID_LENGTH) { + if (uidlen != 0 && uidlen != HF15_UID_LENGTH) { PrintAndLogEx(WARNING, "UID must include 8 hex bytes"); CLIParserFree(ctx); return PM3_EINVARG; } - - payload.block_size = arg_get_int_def(ctx, 2, 4); CLIParserFree(ctx); - // santity checks - if (payload.block_size < 4) { - PrintAndLogEx(WARNING, "Blocksize too small, using default 4 bytes"); - payload.block_size = 4; - } + if (uidlen == 0) // get UID from emulator + { + // reserve memory + iso15_tag_t *tag = calloc(1, sizeof(iso15_tag_t)); + if (tag == NULL) { + PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); + return PM3_EMALLOC; + } - PrintAndLogEx(SUCCESS, "Starting simulating UID " _YELLOW_("%s"), iso15693_sprintUID(NULL, payload.uid)); + if (GetFromDevice(BIG_BUF_EML, (uint8_t*)tag, sizeof(iso15_tag_t), 0, NULL, 0, NULL, 2500, false) == false) { + PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); + free(tag); + return PM3_ETIMEOUT; + } + + PrintAndLogEx(SUCCESS, "Starting simulating UID " _YELLOW_("%s"), iso15693_sprintUID(NULL, tag->uid)); + free(tag); + } PrintAndLogEx(INFO, "Press " _YELLOW_("`pm3-button`") " to abort simulation"); PacketResponseNG resp; @@ -1723,8 +1729,8 @@ static int CmdHF15Dump(const char *Cmd) { uint8_t arglen = arg_add_default(argtable); argtable[arglen++] = arg_str0("f", "file", "", "Specify a filename for dump file"), argtable[arglen++] = arg_int0(NULL, "bs", "", "block size (def 4)"), - argtable[arglen++] = arg_lit0(NULL, "ns", "no save to file"), - argtable[arglen++] = arg_lit0("v", "verbose", "verbose output"); + argtable[arglen++] = arg_lit0(NULL, "ns", "no save to file"), + argtable[arglen++] = arg_lit0("v", "verbose", "verbose output"); argtable[arglen++] = arg_param_end; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -1748,7 +1754,7 @@ static int CmdHF15Dump(const char *Cmd) { CLIParserFree(ctx); // sanity checks - if ((scan + unaddressed + uidlen) > 1) { + if ((scan + unaddressed + (uidlen > 0)) > 1) { PrintAndLogEx(WARNING, "Select only one option /scan/unaddress/uid"); return PM3_EINVARG; } @@ -1759,8 +1765,7 @@ static int CmdHF15Dump(const char *Cmd) { } // default fallback to scan for tag. - // overriding unaddress parameter :) - if (uidlen != HF15_UID_LENGTH) { + if (uidlen != HF15_UID_LENGTH && !unaddressed) { scan = true; } @@ -1772,9 +1777,16 @@ static int CmdHF15Dump(const char *Cmd) { return PM3_EMALLOC; } + iso15_tag_t *tag = (iso15_tag_t *)calloc(1, sizeof(iso15_tag_t)); + + if (tag == NULL) { + PrintAndLogEx(FAILED, "failed to allocate memory"); + return PM3_EMALLOC; + }; + // ISO15693 Protocol params packet->raw[packet->rawlen++] = arg_get_raw_flag(uidlen, unaddressed, scan, add_option); - packet->raw[packet->rawlen++] = ISO15693_READBLOCK; + packet->raw[packet->rawlen++] = ISO15693_GET_SYSTEM_INFO; bool used_uid = false; if (unaddressed == false) { @@ -1796,9 +1808,8 @@ static int CmdHF15Dump(const char *Cmd) { PrintAndLogEx(SUCCESS, "Using unaddressed mode"); } - if (verbose) { - PrintAndLogEx(INFO, "Using block size... " _YELLOW_("%d"), blocksize); - } + AddCrc15(packet->raw, packet->rawlen); + packet->rawlen += 2; // PM3 params packet->flags = (ISO15_CONNECT | ISO15_READ_RESPONSE | ISO15_NO_DISCONNECT); @@ -1806,31 +1817,69 @@ static int CmdHF15Dump(const char *Cmd) { packet->flags |= ISO15_HIGH_SPEED; } - // add CRC length (2) to packet and blockno (1) - packet->rawlen += 3; + clearCommandBuffer(); + SendCommandNG(CMD_HF_ISO15693_COMMAND, (uint8_t *)packet, ISO15_RAW_LEN(packet->rawlen)); + + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) { + PrintAndLogEx(DEBUG, "iso15693 timeout"); + return PM3_ETIMEOUT; + } + + if (resp.status == PM3_ETEAROFF) { + return resp.status; + } + + if (resp.length < 2) { + PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command (%d)", resp.length); + PrintAndLogEx(WARNING, "%%d)", resp.length); + return PM3_EWRONGANSWER; + } + + uint8_t *d = resp.data.asBytes; + uint8_t dCpt = 10; + + ISO15_ERROR_HANDLING_CARD_RESPONSE(d, resp.length); + + memcpy(tag->uid, &d[2], 8); + + if (d[1] & 0x01) + tag->dsfid = d[dCpt++]; + if (d[1] & 0x02) + tag->afi = d[dCpt++]; + if (d[1] & 0x04) + { + tag->pagesCount = d[dCpt++]+1; + tag->bytesPerPage = d[dCpt++]+1; + } + else + { // Set tag memory layout values (if can't be readed in SYSINFO) + tag->bytesPerPage = blocksize; + tag->pagesCount = 128; + } + if (d[1] & 0x08) + tag->ic = d[dCpt++]; + + if (verbose) + { + print_emltag_info_15693(tag); + } + + // add lenght for blockno (1) + packet->rawlen++; + packet->raw[0] |= ISO15_REQ_OPTION; // Add option to dump lock status + packet->raw[1] = ISO15693_READBLOCK; + + packet->flags = (ISO15_READ_RESPONSE | ISO15_NO_DISCONNECT); + if (fast) { + packet->flags |= ISO15_HIGH_SPEED; + } PrintAndLogEx(SUCCESS, "Reading memory"); int blocknum = 0; - // memory. - t15memory_t mem[256]; - - uint8_t data[256 * 4]; - memset(data, 0, sizeof(data)); - - // keep track of which block length tag returned? - uint8_t blklen = blocksize; - - - for (int retry = 0; (retry < 2 && blocknum < 0x100); retry++) { - - if (blocknum > 0) { - packet->flags = (ISO15_READ_RESPONSE | ISO15_NO_DISCONNECT); - if (fast) { - packet->flags |= ISO15_HIGH_SPEED; - } - } + for (int retry = 0; (retry < 2 && blocknum < tag->pagesCount); retry++) { if (used_uid) { packet->raw[10] = (uint8_t)blocknum & 0xFF; AddCrc15(packet->raw, 11); @@ -1841,7 +1890,7 @@ static int CmdHF15Dump(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_HF_ISO15693_COMMAND, (uint8_t *)packet, ISO15_RAW_LEN(packet->rawlen)); - PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000)) { if (resp.length < 2) { @@ -1850,7 +1899,7 @@ static int CmdHF15Dump(const char *Cmd) { continue; } - uint8_t *d = resp.data.asBytes; + d = resp.data.asBytes; if (CheckCrc15(d, resp.length) == false) { PrintAndLogEx(NORMAL, ""); @@ -1870,21 +1919,10 @@ static int CmdHF15Dump(const char *Cmd) { break; } - // is tag responding with 4 or 8 bytes? - if (resp.length > 8) { - blklen = 8; - } - - uint8_t offset = 0; - if (add_option) { - offset = 1; - } - // lock byte value - mem[blocknum].lock = d[0 + offset]; + tag->locks[blocknum] = d[1]; // copy read data - memcpy(mem[blocknum].block, d + 1 + offset, blklen); - memcpy(data + (blocknum * 4), d + 1 + offset, 4); + memcpy(&tag->data[blocknum * tag->bytesPerPage], d + 2, tag->bytesPerPage); retry = 0; blocknum++; @@ -1896,9 +1934,9 @@ static int CmdHF15Dump(const char *Cmd) { free(packet); DropField(); - if (blklen != blocksize) { + if (tag->bytesPerPage != blocksize) { PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, _YELLOW_("%u") " byte block length detected, called with " _YELLOW_("%d"), blklen, blocksize); + PrintAndLogEx(INFO, _YELLOW_("%u") " byte block length detected, called with " _YELLOW_("%d"), tag->bytesPerPage, blocksize); } PrintAndLogEx(NORMAL, ""); @@ -1910,18 +1948,18 @@ static int CmdHF15Dump(const char *Cmd) { for (int i = 0; i < blocknum; i++) { char lck[16] = {0}; - if (mem[i].lock) { - snprintf(lck, sizeof(lck), _RED_("%d"), mem[i].lock); + if (tag->locks[i]) { + snprintf(lck, sizeof(lck), _RED_("%d"), tag->locks[i]); } else { - snprintf(lck, sizeof(lck), "%d", mem[i].lock); + snprintf(lck, sizeof(lck), "%d", tag->locks[i]); } PrintAndLogEx(INFO, "%3d/0x%02X | %s| %s | %s" , i , i - , sprint_hex(mem[i].block, blklen) + , sprint_hex(&tag->data[i*tag->bytesPerPage], tag->bytesPerPage) , lck - , sprint_ascii(mem[i].block, blklen) + , sprint_ascii(&tag->data[i*tag->bytesPerPage], tag->bytesPerPage) ); } PrintAndLogEx(INFO, "---------+-------------+---+-------"); @@ -1941,11 +1979,8 @@ static int CmdHF15Dump(const char *Cmd) { FillFileNameByUID(fptr, SwapEndian64(uid, sizeof(uid), 8), "-dump", sizeof(uid)); } - if (blklen == 8) { - pm3_save_dump(filename, data, (size_t)(blocknum * blklen), jsf15_v3); - } else { - pm3_save_dump(filename, data, (size_t)(blocknum * blklen), jsf15_v2); - } + pm3_save_dump(filename, (uint8_t*)tag, sizeof(iso15_tag_t), jsf15_v4); + return PM3_SUCCESS; } diff --git a/client/src/fileutils.c b/client/src/fileutils.c index 4f8ecda69..dc0ff8c3f 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -28,6 +28,7 @@ #include "util.h" #include "cmdhficlass.h" // pagemap #include "iclass_cmd.h" +#include "iso15.h" #ifdef _WIN32 #include "scandir.h" @@ -518,6 +519,33 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, } break; } + // handles ISO15693 in iso15_tag_t format + case jsf15_v4: { + JsonSaveStr(root, "FileType", "15693 v4"); + iso15_tag_t *tag = (iso15_tag_t *)data; + JsonSaveBufAsHexCompact(root, "$.Card.uid", tag->uid, 8); + JsonSaveBufAsHexCompact(root, "$.Card.dsfid", &tag->dsfid, 1); + JsonSaveBufAsHexCompact(root, "$.Card.dsfidLock", (uint8_t*)&tag->dsfidLock, 1); + JsonSaveBufAsHexCompact(root, "$.Card.afi", &tag->afi, 1); + JsonSaveBufAsHexCompact(root, "$.Card.afiLock", (uint8_t*)&tag->afiLock, 1); + JsonSaveBufAsHexCompact(root, "$.Card.bytesPerPage", &tag->bytesPerPage, 1); + JsonSaveBufAsHexCompact(root, "$.Card.pagesCount", &tag->pagesCount, 1); + JsonSaveBufAsHexCompact(root, "$.Card.IC", &tag->ic, 1); + JsonSaveBufAsHexCompact(root, "$.Card.locks", tag->locks, tag->pagesCount); + JsonSaveBufAsHexCompact(root, "$.Card.random", tag->random, 2); + JsonSaveBufAsHexCompact(root, "$.Card.privacyPasswd", tag->privacyPasswd, 4); + JsonSaveBufAsHexCompact(root, "$.Card.state", (uint8_t*)&tag->state, 1); + + for (size_t i = 0 ; i < tag->pagesCount ; i++) { + if (((i+1) * tag->bytesPerPage) > ISO15693_TAG_MAX_SIZE) + break; + snprintf(path, sizeof(path), "$.blocks.%zu", i); + JsonSaveBufAsHexCompact(root, path, + &tag->data[i * tag->bytesPerPage], + tag->bytesPerPage); + } + break; + } case jsfLegic_v2: { JsonSaveStr(root, "FileType", "legic v2"); JsonSaveBufAsHexCompact(root, "$.Card.UID", data, 4); @@ -1673,6 +1701,41 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz goto out; } + if (!strcmp(ctype, "15693 v4")) { + iso15_tag_t *tag = (iso15_tag_t *)udata.bytes; + JsonLoadBufAsHex(root, "$.Card.UID", tag->uid, 8, datalen); + JsonLoadBufAsHex(root, "$.Card.dsfid", &tag->dsfid, 1, datalen); + JsonLoadBufAsHex(root, "$.Card.dsfidLock", (uint8_t*)&tag->dsfidLock, 1, datalen); + JsonLoadBufAsHex(root, "$.Card.afi", &tag->afi, 1, datalen); + JsonLoadBufAsHex(root, "$.Card.afiLock", (uint8_t*)&tag->afiLock, 1, datalen); + JsonLoadBufAsHex(root, "$.Card.bytesPerPage", &tag->bytesPerPage, 1, datalen); + JsonLoadBufAsHex(root, "$.Card.pagesCount", &tag->pagesCount, 1, datalen); + JsonLoadBufAsHex(root, "$.Card.IC", &tag->ic, 1, datalen); + JsonLoadBufAsHex(root, "$.Card.locks", tag->locks, tag->pagesCount, datalen); + JsonLoadBufAsHex(root, "$.Card.random", tag->random, 2, datalen); + JsonLoadBufAsHex(root, "$.Card.privacyPasswd", tag->privacyPasswd, 4, datalen); + JsonLoadBufAsHex(root, "$.Card.state", (uint8_t*)&tag->state, 1, datalen); + + size_t sptr = 0; + for (int i = 0; i < tag->pagesCount ; i++) { + if (((i+1) * tag->bytesPerPage) > ISO15693_TAG_MAX_SIZE) { + PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr); + retval = PM3_EMALLOC; + goto out; + } + + snprintf(blocks, sizeof(blocks), "$.blocks.%d", i); + JsonLoadBufAsHex(root, blocks, &tag->data[sptr], tag->bytesPerPage, &len); + if (load_file_sanity(ctype, tag->bytesPerPage, i, len) == false) { + break; + } + sptr += len; + } + + *datalen = sptr; + goto out; + } + if (!strcmp(ctype, "legic v2")) { size_t sptr = 0; for (int i = 0; i < 64; i++) { diff --git a/client/src/fileutils.h b/client/src/fileutils.h index fa36fb89e..c4dcc5a0c 100644 --- a/client/src/fileutils.h +++ b/client/src/fileutils.h @@ -55,6 +55,7 @@ typedef enum { jsf15, jsf15_v2, jsf15_v3, + jsf15_v4, jsfLegic, jsfLegic_v2, jsfT55x7, diff --git a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md index 406a7bcec..3e85e1369 100644 --- a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md +++ b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md @@ -127,6 +127,7 @@ Here are the supported values you can assign to `STANDALONE` in `Makefile.platfo | HF_14ASNIFF | 14a sniff storing to flashmem - Micolous | HF_14BSNIFF | 14b sniff - jacopo-j | HF_15SNIFF | 15693 sniff storing to flashmem - Glaser +| HF_15SNIFF | 15693 simulator - lnv42 | HF_AVEFUL | MIFARE Ultralight read/simulation - Ave Ozkal | HF_BOG | 14a sniff with ULC/ULEV1/NTAG auth storing in flashmem - Bogito | HF_CARDHOPPER | Long distance (over IP) relay of 14a protocols - Sam Haskins diff --git a/fpga/Makefile b/fpga/Makefile index 1731d4869..8a95c7638 100644 --- a/fpga/Makefile +++ b/fpga/Makefile @@ -67,7 +67,7 @@ TARGET1_OPTIONS = -define \{WITH_LF WITH_LF0 WITH_LF1 WITH_LF2 WITH_LF3\} # RDV40/Generic - Enable all HF modules except Felica TARGET2_OPTIONS = -define \{WITH_HF0 WITH_HF1 WITH_HF2 WITH_HF3 WITH_HF5\} # RDV40/Generic - Enable all HF modules except Felica and ISO14443, select HF_15 instead of HF -TARGET3_OPTIONS = -define \{WITH_HF0 WITH_HF1 WITH_HF3 WITH_HF5 WITH_HF_15\} +TARGET3_OPTIONS = -define \{WITH_HF0 WITH_HF1 WITH_HF3 WITH_HF5 WITH_HF_15 WITH_HF_15_LOWSIGNAL\} # RDV40/Generic - Enable all HF modules except ISO14443 TARGET4_OPTIONS = -define \{WITH_HF0 WITH_HF1 WITH_HF3 WITH_HF4 WITH_HF5\} # ICOPYX diff --git a/fpga/fpga_pm3_hf_15.bit b/fpga/fpga_pm3_hf_15.bit index c19f86bed..32d8344da 100644 Binary files a/fpga/fpga_pm3_hf_15.bit and b/fpga/fpga_pm3_hf_15.bit differ diff --git a/fpga/hi_reader.v b/fpga/hi_reader.v index 1a0b375d3..07afdc2de 100644 --- a/fpga/hi_reader.v +++ b/fpga/hi_reader.v @@ -44,8 +44,13 @@ reg after_hysteresis, after_hysteresis_prev, after_hysteresis_prev_prev; reg [11:0] has_been_low_for; always @(negedge adc_clk) begin +`ifdef WITH_HF_15_LOWSIGNAL + if (& adc_d[7:4]) after_hysteresis <= 1'b1; + else if (~(| adc_d[7:6])) after_hysteresis <= 1'b0; +`else if (& adc_d[7:0]) after_hysteresis <= 1'b1; else if (~(| adc_d[7:0])) after_hysteresis <= 1'b0; +`endif if (after_hysteresis) begin diff --git a/include/iso15.h b/include/iso15.h index 7d2b0e12f..7f1e5b306 100644 --- a/include/iso15.h +++ b/include/iso15.h @@ -44,4 +44,31 @@ typedef struct { uint8_t raw[]; // First byte in raw, raw[0] is ISO15693 protocol flag byte } PACKED iso15_raw_cmd_t; +#define ISO15693_TAG_MAX_PAGES 64 // in page +#define ISO15693_TAG_MAX_SIZE 2048 // in byte (64 pages of 256 bits) + +typedef struct { + uint8_t uid[8]; + uint8_t dsfid; + bool dsfidLock; + uint8_t afi; + bool afiLock; + uint8_t bytesPerPage; + uint8_t pagesCount; + uint8_t ic; + uint8_t locks[ISO15693_TAG_MAX_PAGES]; + uint8_t data[ISO15693_TAG_MAX_SIZE]; + uint8_t random[2]; + uint8_t privacyPasswd[4]; + enum { + TAG_STATE_NO_FIELD, + TAG_STATE_READY, + TAG_STATE_ACTIVATED, // useless ? + TAG_STATE_SELECTED, + TAG_STATE_SILENCED + } state; + bool expectFast; + bool expectFsk; +} PACKED iso15_tag_t; + #endif // _ISO15_H_ diff --git a/tools/build_all_firmwares.sh b/tools/build_all_firmwares.sh index 22a3ee60f..2740d7150 100755 --- a/tools/build_all_firmwares.sh +++ b/tools/build_all_firmwares.sh @@ -32,7 +32,7 @@ mv bootrom/obj/bootrom.elf "$DEST/PM3BOOTROM.elf" # cf armsrc/Standalone/Makefile.hal STANDALONE_MODES=(LF_SKELETON) STANDALONE_MODES+=(LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_MULTIHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE) -STANDALONE_MODES+=(HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_AVEFUL HF_BOG HF_CARDHOPPER HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_UNISNIFF HF_YOUNG) +STANDALONE_MODES+=(HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_15SIM HF_AVEFUL HF_BOG HF_CARDHOPPER HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_UNISNIFF HF_YOUNG) STANDALONE_MODES+=(DANKARMULTI) STANDALONE_MODES_REQ_BT=(HF_CARDHOPPER HF_REBLAY) STANDALONE_MODES_REQ_SMARTCARD=()