From 7361a18f7a24a7b0dd6e76919ef389202543cdc5 Mon Sep 17 00:00:00 2001 From: "Malte F. Hillmann" Date: Wed, 27 Mar 2019 14:34:42 +0100 Subject: [PATCH 01/16] fixed bug in ASKbiphaseDemod() --- client/cmddata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cmddata.c b/client/cmddata.c index fd31fac4..30148163 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -429,7 +429,7 @@ int CmdBiphaseDecodeRaw(const char *Cmd) int ASKbiphaseDemod(const char *Cmd, bool verbose) { //ask raw demod GraphBuffer first - int offset=0, clk=0, invert=0, maxErr=0; + int offset=0, clk=0, invert=0, maxErr=100; sscanf(Cmd, "%i %i %i %i", &offset, &clk, &invert, &maxErr); uint8_t BitStream[MAX_GRAPH_TRACE_LEN]; -- 2.39.5 From 4306de82770fb4e7e033e03996710d3c50f699f7 Mon Sep 17 00:00:00 2001 From: "Malte F. Hillmann" Date: Wed, 27 Mar 2019 14:36:39 +0100 Subject: [PATCH 02/16] fixed bug in CmdFdxDemod --- client/cmdlffdx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cmdlffdx.c b/client/cmdlffdx.c index 20f834ce..5677c79d 100644 --- a/client/cmdlffdx.c +++ b/client/cmdlffdx.c @@ -137,7 +137,7 @@ int CmdFdxDemod(const char *Cmd){ //Differential Biphase / di-phase (inverted biphase) //get binary from ask wave - if (!ASKbiphaseDemod("0 32 1 0", false)) { + if (!ASKbiphaseDemod("0 32 1 100", false)) { if (g_debugMode) PrintAndLog("DEBUG: Error - FDX-B ASKbiphaseDemod failed"); return 0; } -- 2.39.5 From 3f306c6ded0e995a7150de7d4168ca689e09868f Mon Sep 17 00:00:00 2001 From: "Malte F. Hillmann" Date: Thu, 28 Mar 2019 22:40:29 +0100 Subject: [PATCH 03/16] Bugfixes for LF FDX Changed CmdBiphaseDecodeRaw to allow 7 digits Changed CmdFdxRead to read 39999 samples instead of 10000 to improve reading from small tags --- client/cmddata.c | 2 +- client/cmdlffdx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/cmddata.c b/client/cmddata.c index 30148163..8f93ba17 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -380,7 +380,7 @@ int CmdBiphaseDecodeRaw(const char *Cmd) size_t size=0; int offset=0, invert=0, maxErr=20, errCnt=0; char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 5 || cmdp == 'h' || cmdp == 'H') { + if (strlen(Cmd) > 7 || cmdp == 'h' || cmdp == 'H') { PrintAndLog("Usage: data biphaserawdecode [offset] [invert] [maxErr]"); PrintAndLog(" Converts 10 or 01 to 1 and 11 or 00 to 0"); PrintAndLog(" --must have binary sequence in demodbuffer (run data askrawdemod first)"); diff --git a/client/cmdlffdx.c b/client/cmdlffdx.c index 5677c79d..d0ac52c0 100644 --- a/client/cmdlffdx.c +++ b/client/cmdlffdx.c @@ -206,7 +206,7 @@ int CmdFdxDemod(const char *Cmd){ } int CmdFdxRead(const char *Cmd) { - lf_read(true, 10000); + lf_read(true, 39999); return CmdFdxDemod(Cmd); } -- 2.39.5 From bad582468fd7617e99db8c37789b5523e3ff6b9d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Andr=C3=A1s=20Veres-Szentkir=C3=A1lyi?= Date: Fri, 12 Apr 2019 08:52:18 +0200 Subject: [PATCH 04/16] Added support for Legic tags to `hf search` command (#815) * hf legic: use CMD_ACK instead of Dbprintf * hf search: add support for Legic tags --- CHANGELOG.md | 1 + armsrc/legicrf.c | 10 ++++------ client/cmdhf.c | 5 +++++ client/cmdhflegic.c | 17 ++++++++++++++++- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50c33d0f..adff821f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf plot` (piwi) - Added `hf mfp mad` `hf mf mad` parsing MAD1 and MAD2 (Merlok) - Added `hf mfp ndef` `hf mf ndef` parsing NDEF records (Merlok) +- Added Legic detection to `hf search` (dnet) ## [v3.1.0][2018-10-10] diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index c848e647..97af8843 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -379,8 +379,9 @@ void LegicRfReader(int offset, int bytes) { // establish shared secret and detect card type DbpString("Reading card ..."); uint8_t card_type = setup_phase(SESSION_IV); + uint8_t result = 0; if(init_card(card_type, &card) != 0) { - Dbprintf("No or unknown card found, aborting"); + result = 1; goto OUT; } @@ -397,17 +398,14 @@ void LegicRfReader(int offset, int bytes) { for(uint16_t i = 0; i < bytes; ++i) { int16_t byte = read_byte(offset + i, card.cmdsize); if(byte == -1) { - Dbprintf("operation failed @ 0x%03.3x", bytes); + result = 2; goto OUT; } BigBuf[i] = byte; } - // OK - Dbprintf("Card (MIM %i) read, use 'hf legic decode' or", card.cardsize); - Dbprintf("'data hexsamples %d' to view results", (bytes+7) & ~7); - OUT: + cmd_send(CMD_ACK, result, bytes, 0, &card, sizeof(card)); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_B_OFF(); LED_C_OFF(); diff --git a/client/cmdhf.c b/client/cmdhf.c index 73b0bc76..6d25cac0 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -66,6 +66,11 @@ int CmdHFSearch(const char *Cmd){ PrintAndLog("\nValid ISO14443B Tag Found - Quiting Search\n"); return ans; } + ans = CmdLegicRFRead(""); + if (ans == 0) { + PrintAndLog("\nValid Legic Tag Found - Quiting Search\n"); + return ans; + } PrintAndLog("\nno known/supported 13.56 MHz tags found\n"); return 0; } diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 8fbd4578..66e8ebb1 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -18,6 +18,7 @@ #include "cmdparser.h" #include "cmdmain.h" #include "util.h" +#include "../include/legic.h" static int CmdHelp(const char *Cmd); @@ -214,7 +215,21 @@ int CmdLegicRFRead(const char *Cmd) if(byte_count + offset > 1024) byte_count = 1024 - offset; UsbCommand c={CMD_READER_LEGIC_RF, {offset, byte_count, 0}}; SendCommand(&c); - return 0; + UsbCommand resp; + WaitForResponse(CMD_ACK,&resp); + switch (resp.arg[0]) { + case 0: + PrintAndLog("Card (MIM %i) read, use 'hf legic decode' or", ((legic_card_select_t*)resp.d.asBytes)->cardsize); + PrintAndLog("'data hexsamples %d' to view results", (resp.arg[1] + 7) & ~7); + break; + case 1: + PrintAndLog("No or unknown card found, aborting"); + break; + case 2: + PrintAndLog("operation failed @ 0x%03.3x", resp.arg[1]); + break; + } + return resp.arg[0]; } int CmdLegicLoad(const char *Cmd) -- 2.39.5 From a8561e356bd39b45e7ba4ae66e9ed6233b66a356 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Fri, 19 Apr 2019 10:22:10 +0200 Subject: [PATCH 05/16] fix hf mf sim (#812) * fix parity encryption (thanks to Eloff, http://www.proxmark.org/forum/viewtopic.php?id=6347) * add support to simulate Mifare Mini, Mifare 2K and Mifare 4K * change to standard LED handling (A: PM is working, B: reader is sending, C: tag is responding, D: HF field is on) * NAK on unknown commands * allow unencrypted HALT * don't display messages during simulation (or we will miss next reader command) * use DMA to receive reader command * switch earlier from send to listen mode * move ADC initializer to iso14443_setup * remove remainders of incomplete Mifare 10Byte UID simulation * show 'short' bytes (7Bits or 8Bits without parity) in 'hf list mf' and 'hf list 14a' * whitespace --- CHANGELOG.md | 1 + armsrc/BigBuf.c | 35 +- armsrc/BigBuf.h | 2 +- armsrc/appmain.c | 3 +- armsrc/apps.h | 1 - armsrc/iso14443a.c | 858 ++++++++++++++++++++++---------------------- armsrc/iso14443a.h | 1 - armsrc/mifaresim.c | 431 +++++++++++++--------- armsrc/mifaresim.h | 2 +- armsrc/mifareutil.c | 280 ++++++++------- armsrc/mifareutil.h | 11 +- client/cmdhflist.c | 15 +- client/cmdhfmf.c | 95 +++-- include/usb_cmd.h | 11 +- 14 files changed, 943 insertions(+), 803 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index adff821f..2a8ee1fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf plot` (piwi) - Added `hf mfp mad` `hf mf mad` parsing MAD1 and MAD2 (Merlok) - Added `hf mfp ndef` `hf mf ndef` parsing NDEF records (Merlok) +- Added Mifare Mini, Mifare 2K and 4K support to `hf mf sim` (piwi) - Added Legic detection to `hf search` (dnet) ## [v3.1.0][2018-10-10] diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index e2f51311..ce97e41f 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -21,8 +21,8 @@ /* BigBuf memory layout: Pointer to highest available memory: BigBuf_hi - high BIGBUF_SIZE - reserved = BigBuf_malloc() subtracts amount from BigBuf_hi, + high BIGBUF_SIZE + reserved = BigBuf_malloc() subtracts amount from BigBuf_hi, low 0x00 */ @@ -39,6 +39,7 @@ static uint8_t *emulator_memory = NULL; static uint32_t traceLen = 0; static bool tracing = true; + // get the address of BigBuf uint8_t *BigBuf_get_addr(void) { @@ -53,7 +54,7 @@ uint8_t *BigBuf_get_EM_addr(void) if (emulator_memory == NULL) { emulator_memory = BigBuf_malloc(CARD_MEMORY_SIZE); } - + return emulator_memory; } @@ -63,17 +64,22 @@ void BigBuf_Clear(void) { BigBuf_Clear_ext(true); } + + // clear ALL of BigBuf void BigBuf_Clear_ext(bool verbose) { memset(BigBuf, 0, BIGBUF_SIZE); - if (verbose) - Dbprintf("Buffer cleared (%i bytes)",BIGBUF_SIZE); + if (verbose) + Dbprintf("Buffer cleared (%i bytes)", BIGBUF_SIZE); } + + void BigBuf_Clear_EM(void){ memset(BigBuf_get_EM_addr(), 0, CARD_MEMORY_SIZE); } + void BigBuf_Clear_keep_EM(void) { memset(BigBuf, 0, BigBuf_hi); @@ -83,11 +89,11 @@ void BigBuf_Clear_keep_EM(void) // at the beginning of BigBuf is always for traces/samples uint8_t *BigBuf_malloc(uint16_t chunksize) { - if (BigBuf_hi - chunksize < 0) { - return NULL; // no memory left + if (BigBuf_hi - chunksize < 0) { + return NULL; // no memory left } else { - chunksize = (chunksize + 3) & 0xfffc; // round to next multiple of 4 - BigBuf_hi -= chunksize; // aligned to 4 Byte boundary + chunksize = (chunksize + 3) & 0xfffc; // round to next multiple of 4 + BigBuf_hi -= chunksize; // aligned to 4 Byte boundary return (uint8_t *)BigBuf + BigBuf_hi; } } @@ -128,18 +134,22 @@ uint16_t BigBuf_max_traceLen(void) return BigBuf_hi; } + void clear_trace() { traceLen = 0; } + void set_tracing(bool enable) { tracing = enable; } + bool get_tracing(void) { return tracing; } + /** * Get the number of bytes traced * @return @@ -149,6 +159,7 @@ uint16_t BigBuf_get_traceLen(void) return traceLen; } + /** This is a function to store traces. All protocols can use this generic tracer-function. The traces produced by calling this function can be fetched on the client-side @@ -162,14 +173,14 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ uint8_t *trace = BigBuf_get_addr(); - uint32_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity + uint32_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity uint32_t duration = timestamp_end - timestamp_start; // Return when trace is full uint16_t max_traceLen = BigBuf_max_traceLen(); if (traceLen + sizeof(iLen) + sizeof(timestamp_start) + sizeof(duration) + num_paritybytes + iLen >= max_traceLen) { - tracing = false; // don't trace any more + tracing = false; // don't trace any more return false; } // Traceformat: @@ -237,7 +248,7 @@ int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwP // Return when trace is full if (traceLen + sizeof(rsamples) + sizeof(dwParity) + sizeof(iBits) + iLen > BigBuf_max_traceLen()) { return false; - } + } //Hitag traces appear to use this traceformat: // 32 bits timestamp (little endian,Highest Bit used as readerToTag flag) diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h index 05538044..00d5145f 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -20,7 +20,7 @@ #define MAX_PARITY_SIZE ((MAX_FRAME_SIZE + 7) / 8) #define MAX_MIFARE_FRAME_SIZE 18 // biggest Mifare frame is answer to a read (one block = 16 Bytes) + 2 Bytes CRC #define MAX_MIFARE_PARITY_SIZE 3 // need 18 parity bits for the 18 Byte above. 3 Bytes are enough to store these -#define CARD_MEMORY_SIZE 4096 +#define CARD_MEMORY_SIZE 4096 #define DMA_BUFFER_SIZE 128 extern uint8_t *BigBuf_get_addr(void); diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 926ac52e..37328a50 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -29,6 +29,7 @@ #include "lfsampling.h" #include "BigBuf.h" #include "mifareutil.h" +#include "mifaresim.h" #include "pcf7931.h" #include "i2c.h" #include "hfsnoop.h" @@ -1249,7 +1250,7 @@ void UsbPacketReceived(uint8_t *packet, int len) MifareChkKeys(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; case CMD_SIMULATE_MIFARE_CARD: - Mifare1ksim(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); + MifareSim(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; // emulator diff --git a/armsrc/apps.h b/armsrc/apps.h index 5b8516eb..72a62628 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -119,7 +119,6 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain); void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain); -void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 2f4baf17..0ca9873b 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -68,7 +68,7 @@ typedef struct { // DROP_FIRST_HALF, } state; uint16_t shiftReg; - int16_t bitCount; + int16_t bitCount; uint16_t len; uint16_t byteCntMax; uint16_t posCnt; @@ -77,7 +77,7 @@ typedef struct { uint8_t parityLen; uint32_t fourBits; uint32_t startTime, endTime; - uint8_t *output; + uint8_t *output; uint8_t *parity; } tUart; @@ -94,8 +94,8 @@ static uint8_t iso14_pcb_blocknum = 0; // // minimum time between the start bits of consecutive transfers from reader to tag: 7000 carrier (13.56Mhz) cycles #define REQUEST_GUARD_TIME (7000/16 + 1) -// minimum time between last modulation of tag and next start bit from reader to tag: 1172 carrier cycles -#define FRAME_DELAY_TIME_PICC_TO_PCD (1172/16 + 1) +// minimum time between last modulation of tag and next start bit from reader to tag: 1172 carrier cycles +#define FRAME_DELAY_TIME_PICC_TO_PCD (1172/16 + 1) // bool LastCommandWasRequest = false; // @@ -107,8 +107,8 @@ static uint8_t iso14_pcb_blocknum = 0; // 8 ticks until bit_to_arm is assigned from curbit // 8*16 ticks for the transfer from FPGA to ARM // 4*16 ticks until we measure the time -// - 8*16 ticks because we measure the time of the previous transfer -#define DELAY_AIR2ARM_AS_READER (3 + 16 + 8 + 8*16 + 4*16 - 8*16) +// - 8*16 ticks because we measure the time of the previous transfer +#define DELAY_AIR2ARM_AS_READER (3 + 16 + 8 + 8*16 + 4*16 - 8*16) // When the PM acts as a reader and is sending, it takes // 4*16 ticks until we can write data to the sending hold register @@ -125,10 +125,10 @@ static uint8_t iso14_pcb_blocknum = 0; // 8 ticks until the SSC samples the first data // 7*16 ticks to complete the transfer from FPGA to ARM // 8 ticks until the next ssp_clk rising edge -// 4*16 ticks until we measure the time -// - 8*16 ticks because we measure the time of the previous transfer +// 4*16 ticks until we measure the time +// - 8*16 ticks because we measure the time of the previous transfer #define DELAY_AIR2ARM_AS_TAG (2 + 3 + 8 + 8 + 7*16 + 8 + 4*16 - 8*16) - + // The FPGA will report its internal sending delay in uint16_t FpgaSendQueueDelay; // the 5 first bits are the number of bits buffered in mod_sig_buf @@ -150,16 +150,16 @@ uint16_t FpgaSendQueueDelay; // 8 ticks (on average) until the result is stored in to_arm // + the delays in transferring data - which is the same for // sniffing reader and tag data and therefore not relevant -#define DELAY_TAG_AIR2ARM_AS_SNIFFER (3 + 14 + 8) - +#define DELAY_TAG_AIR2ARM_AS_SNIFFER (3 + 14 + 8) + // When the PM acts as sniffer and is receiving reader data, it takes -// 2 ticks delay in analogue RF receiver (for the falling edge of the +// 2 ticks delay in analogue RF receiver (for the falling edge of the // start bit, which marks the start of the communication) // 3 ticks A/D conversion // 8 ticks on average until the data is stored in to_arm. // + the delays in transferring data - which is the same for // sniffing reader and tag data and therefore not relevant -#define DELAY_READER_AIR2ARM_AS_SNIFFER (2 + 3 + 8) +#define DELAY_READER_AIR2ARM_AS_SNIFFER (2 + 3 + 8) //variables used for timing purposes: //these are in ssp_clk cycles: @@ -177,12 +177,12 @@ static uint32_t LastProxToAirDuration; // Sequence X: 00001100 drop after half a period // Sequence Y: 00000000 no drop // Sequence Z: 11000000 drop at start -#define SEC_D 0xf0 -#define SEC_E 0x0f -#define SEC_F 0x00 -#define SEC_X 0x0c -#define SEC_Y 0x00 -#define SEC_Z 0xc0 +#define SEC_D 0xf0 +#define SEC_E 0x0f +#define SEC_F 0x00 +#define SEC_X 0x0c +#define SEC_Y 0x00 +#define SEC_Z 0xc0 void iso14a_set_trigger(bool enable) { trigger = enable; @@ -214,8 +214,8 @@ void GetParity(const uint8_t *pbtCmd, uint16_t iLen, uint8_t *par) // Generate the parity bits parityBits |= ((oddparity8(pbtCmd[i])) << (7-paritybit_cnt)); if (paritybit_cnt == 7) { - par[paritybyte_cnt] = parityBits; // save 8 Bits parity - parityBits = 0; // and advance to next Parity Byte + par[paritybyte_cnt] = parityBits; // save 8 Bits parity + parityBits = 0; // and advance to next Parity Byte paritybyte_cnt++; paritybit_cnt = 0; } else { @@ -225,7 +225,7 @@ void GetParity(const uint8_t *pbtCmd, uint16_t iLen, uint8_t *par) // save remaining parity bits par[paritybyte_cnt] = parityBits; - + } void AppendCrc14443a(uint8_t* data, int len) @@ -244,14 +244,14 @@ static void AppendCrc14443b(uint8_t* data, int len) //============================================================================= // Basics: // This decoder is used when the PM3 acts as a tag. -// The reader will generate "pauses" by temporarily switching of the field. -// At the PM3 antenna we will therefore measure a modulated antenna voltage. +// The reader will generate "pauses" by temporarily switching of the field. +// At the PM3 antenna we will therefore measure a modulated antenna voltage. // The FPGA does a comparison with a threshold and would deliver e.g.: // ........ 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 ....... // The Miller decoder needs to identify the following sequences: -// 2 (or 3) ticks pause followed by 6 (or 5) ticks unmodulated: pause at beginning - Sequence Z ("start of communication" or a "0") -// 8 ticks without a modulation: no pause - Sequence Y (a "0" or "end of communication" or "no information") -// 4 ticks unmodulated followed by 2 (or 3) ticks pause: pause in second half - Sequence X (a "1") +// 2 (or 3) ticks pause followed by 6 (or 5) ticks unmodulated: pause at beginning - Sequence Z ("start of communication" or a "0") +// 8 ticks without a modulation: no pause - Sequence Y (a "0" or "end of communication" or "no information") +// 4 ticks unmodulated followed by 2 (or 3) ticks pause: pause in second half - Sequence X (a "1") // Note 1: the bitstream may start at any time. We therefore need to sync. // Note 2: the interpretation of Sequence Y and Z depends on the preceding sequence. //----------------------------------------------------------------------------- @@ -274,19 +274,19 @@ static void UartReset() { Uart.state = STATE_UNSYNCD; Uart.bitCount = 0; - Uart.len = 0; // number of decoded data bytes - Uart.parityLen = 0; // number of decoded parity bytes - Uart.shiftReg = 0; // shiftreg to hold decoded data bits - Uart.parityBits = 0; // holds 8 parity bits - Uart.startTime = 0; - Uart.endTime = 0; + Uart.len = 0; // number of decoded data bytes + Uart.parityLen = 0; // number of decoded parity bytes + Uart.shiftReg = 0; // shiftreg to hold decoded data bits + Uart.parityBits = 0; // holds 8 parity bits } static void UartInit(uint8_t *data, uint8_t *parity) { Uart.output = data; Uart.parity = parity; - Uart.fourBits = 0x00000000; // clear the buffer for 4 Bits + Uart.fourBits = 0x00000000; // clear the buffer for 4 Bits + Uart.startTime = 0; + Uart.endTime = 0; UartReset(); } @@ -295,17 +295,17 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) { Uart.fourBits = (Uart.fourBits << 8) | bit; - - if (Uart.state == STATE_UNSYNCD) { // not yet synced - - Uart.syncBit = 9999; // not set + + if (Uart.state == STATE_UNSYNCD) { // not yet synced + + Uart.syncBit = 9999; // not set // The start bit is one ore more Sequence Y followed by a Sequence Z (... 11111111 00x11111). We need to distinguish from // Sequence X followed by Sequence Y followed by Sequence Z (111100x1 11111111 00x11111) - // we therefore look for a ...xx11111111111100x11111xxxxxx... pattern + // we therefore look for a ...xx11111111111100x11111xxxxxx... pattern // (12 '1's followed by 2 '0's, eventually followed by another '0', followed by 5 '1's) - #define ISO14443A_STARTBIT_MASK 0x07FFEF80 // mask is 00000111 11111111 11101111 10000000 - #define ISO14443A_STARTBIT_PATTERN 0x07FF8F80 // pattern is 00000111 11111111 10001111 10000000 - if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 0)) == ISO14443A_STARTBIT_PATTERN >> 0) Uart.syncBit = 7; + #define ISO14443A_STARTBIT_MASK 0x07FFEF80 // mask is 00000111 11111111 11101111 10000000 + #define ISO14443A_STARTBIT_PATTERN 0x07FF8F80 // pattern is 00000111 11111111 10001111 10000000 + if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 0)) == ISO14443A_STARTBIT_PATTERN >> 0) Uart.syncBit = 7; else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 1)) == ISO14443A_STARTBIT_PATTERN >> 1) Uart.syncBit = 6; else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 2)) == ISO14443A_STARTBIT_PATTERN >> 2) Uart.syncBit = 5; else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 3)) == ISO14443A_STARTBIT_PATTERN >> 3) Uart.syncBit = 4; @@ -314,7 +314,7 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 6)) == ISO14443A_STARTBIT_PATTERN >> 6) Uart.syncBit = 1; else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 7)) == ISO14443A_STARTBIT_PATTERN >> 7) Uart.syncBit = 0; - if (Uart.syncBit != 9999) { // found a sync bit + if (Uart.syncBit != 9999) { // found a sync bit Uart.startTime = non_real_time?non_real_time:(GetCountSspClk() & 0xfffffff8); Uart.startTime -= Uart.syncBit; Uart.endTime = Uart.startTime; @@ -324,97 +324,97 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) } else { - if (IsMillerModulationNibble1(Uart.fourBits >> Uart.syncBit)) { - if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) { // Modulation in both halves - error + if (IsMillerModulationNibble1(Uart.fourBits >> Uart.syncBit)) { + if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) { // Modulation in both halves - error LED_B_OFF(); UartReset(); - } else { // Modulation in first half = Sequence Z = logic "0" - if (Uart.state == STATE_MILLER_X) { // error - must not follow after X + } else { // Modulation in first half = Sequence Z = logic "0" + if (Uart.state == STATE_MILLER_X) { // error - must not follow after X LED_B_OFF(); UartReset(); } else { Uart.bitCount++; - Uart.shiftReg = (Uart.shiftReg >> 1); // add a 0 to the shiftreg + Uart.shiftReg = (Uart.shiftReg >> 1); // add a 0 to the shiftreg Uart.state = STATE_MILLER_Z; Uart.endTime = Uart.startTime + 8*(9*Uart.len + Uart.bitCount + 1) - 6; - if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) + if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); - Uart.parityBits <<= 1; // make room for the parity bit - Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit + Uart.parityBits <<= 1; // make room for the parity bit + Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit Uart.bitCount = 0; Uart.shiftReg = 0; - if((Uart.len&0x0007) == 0) { // every 8 data bytes - Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits + if((Uart.len&0x0007) == 0) { // every 8 data bytes + Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits Uart.parityBits = 0; } } } } } else { - if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) { // Modulation second half = Sequence X = logic "1" + if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) { // Modulation second half = Sequence X = logic "1" Uart.bitCount++; - Uart.shiftReg = (Uart.shiftReg >> 1) | 0x100; // add a 1 to the shiftreg + Uart.shiftReg = (Uart.shiftReg >> 1) | 0x100; // add a 1 to the shiftreg Uart.state = STATE_MILLER_X; Uart.endTime = Uart.startTime + 8*(9*Uart.len + Uart.bitCount + 1) - 2; - if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) + if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); - Uart.parityBits <<= 1; // make room for the new parity bit - Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit + Uart.parityBits <<= 1; // make room for the new parity bit + Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit Uart.bitCount = 0; Uart.shiftReg = 0; - if ((Uart.len&0x0007) == 0) { // every 8 data bytes - Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits + if ((Uart.len&0x0007) == 0) { // every 8 data bytes + Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits Uart.parityBits = 0; } } - } else { // no modulation in both halves - Sequence Y - if (Uart.state == STATE_MILLER_Z || Uart.state == STATE_MILLER_Y) { // Y after logic "0" - End of Communication + } else { // no modulation in both halves - Sequence Y + if (Uart.state == STATE_MILLER_Z || Uart.state == STATE_MILLER_Y) { // Y after logic "0" - End of Communication LED_B_OFF(); Uart.state = STATE_UNSYNCD; - Uart.bitCount--; // last "0" was part of EOC sequence - Uart.shiftReg <<= 1; // drop it - if(Uart.bitCount > 0) { // if we decoded some bits - Uart.shiftReg >>= (9 - Uart.bitCount); // right align them - Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); // add last byte to the output - Uart.parityBits <<= 1; // add a (void) parity bit - Uart.parityBits <<= (8 - (Uart.len&0x0007)); // left align parity bits - Uart.parity[Uart.parityLen++] = Uart.parityBits; // and store it + Uart.bitCount--; // last "0" was part of EOC sequence + Uart.shiftReg <<= 1; // drop it + if(Uart.bitCount > 0) { // if we decoded some bits + Uart.shiftReg >>= (9 - Uart.bitCount); // right align them + Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); // add last byte to the output + Uart.parityBits <<= 1; // add a (void) parity bit + Uart.parityBits <<= (8 - (Uart.len&0x0007)); // left align parity bits + Uart.parity[Uart.parityLen++] = Uart.parityBits; // and store it return true; - } else if (Uart.len & 0x0007) { // there are some parity bits to store - Uart.parityBits <<= (8 - (Uart.len&0x0007)); // left align remaining parity bits - Uart.parity[Uart.parityLen++] = Uart.parityBits; // and store them + } else if (Uart.len & 0x0007) { // there are some parity bits to store + Uart.parityBits <<= (8 - (Uart.len&0x0007)); // left align remaining parity bits + Uart.parity[Uart.parityLen++] = Uart.parityBits; // and store them } if (Uart.len) { - return true; // we are finished with decoding the raw data sequence + return true; // we are finished with decoding the raw data sequence } else { - UartReset(); // Nothing received - start over + UartReset(); // Nothing received - start over } } - if (Uart.state == STATE_START_OF_COMMUNICATION) { // error - must not follow directly after SOC + if (Uart.state == STATE_START_OF_COMMUNICATION) { // error - must not follow directly after SOC LED_B_OFF(); UartReset(); - } else { // a logic "0" + } else { // a logic "0" Uart.bitCount++; - Uart.shiftReg = (Uart.shiftReg >> 1); // add a 0 to the shiftreg + Uart.shiftReg = (Uart.shiftReg >> 1); // add a 0 to the shiftreg Uart.state = STATE_MILLER_Y; - if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) + if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); - Uart.parityBits <<= 1; // make room for the parity bit - Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit + Uart.parityBits <<= 1; // make room for the parity bit + Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit Uart.bitCount = 0; Uart.shiftReg = 0; - if ((Uart.len&0x0007) == 0) { // every 8 data bytes - Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits + if ((Uart.len&0x0007) == 0) { // every 8 data bytes + Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits Uart.parityBits = 0; } } } } } - - } - return false; // not finished yet, need more data + } + + return false; // not finished yet, need more data } @@ -428,10 +428,10 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) // at the reader antenna will be modulated as well. The FPGA detects the modulation for us and would deliver e.g. the following: // ........ 0 0 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ....... // The Manchester decoder needs to identify the following sequences: -// 4 ticks modulated followed by 4 ticks unmodulated: Sequence D = 1 (also used as "start of communication") -// 4 ticks unmodulated followed by 4 ticks modulated: Sequence E = 0 -// 8 ticks unmodulated: Sequence F = end of communication -// 8 ticks modulated: A collision. Save the collision position and treat as Sequence D +// 4 ticks modulated followed by 4 ticks unmodulated: Sequence D = 1 (also used as "start of communication") +// 4 ticks unmodulated followed by 4 ticks modulated: Sequence E = 0 +// 8 ticks unmodulated: Sequence F = end of communication +// 8 ticks modulated: A collision. Save the collision position and treat as Sequence D // Note 1: the bitstream may start at any time. We therefore need to sync. // Note 2: parameter offset is used to determine the position of the parity bits (required for the anticollision command only) static tDemod Demod; @@ -450,12 +450,12 @@ const bool Mod_Manchester_LUT[] = { static void DemodReset() { Demod.state = DEMOD_UNSYNCD; - Demod.len = 0; // number of decoded data bytes + Demod.len = 0; // number of decoded data bytes Demod.parityLen = 0; - Demod.shiftReg = 0; // shiftreg to hold decoded data bits - Demod.parityBits = 0; // - Demod.collisionPos = 0; // Position of collision bit - Demod.twoBits = 0xffff; // buffer for 2 Bits + Demod.shiftReg = 0; // shiftreg to hold decoded data bits + Demod.parityBits = 0; // + Demod.collisionPos = 0; // Position of collision bit + Demod.twoBits = 0xffff; // buffer for 2 Bits Demod.highCnt = 0; Demod.startTime = 0; Demod.endTime = 0; @@ -473,18 +473,18 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non { Demod.twoBits = (Demod.twoBits << 8) | bit; - + if (Demod.state == DEMOD_UNSYNCD) { - if (Demod.highCnt < 2) { // wait for a stable unmodulated signal + if (Demod.highCnt < 2) { // wait for a stable unmodulated signal if (Demod.twoBits == 0x0000) { Demod.highCnt++; } else { Demod.highCnt = 0; } } else { - Demod.syncBit = 0xFFFF; // not set - if ((Demod.twoBits & 0x7700) == 0x7000) Demod.syncBit = 7; + Demod.syncBit = 0xFFFF; // not set + if ((Demod.twoBits & 0x7700) == 0x7000) Demod.syncBit = 7; else if ((Demod.twoBits & 0x3B80) == 0x3800) Demod.syncBit = 6; else if ((Demod.twoBits & 0x1DC0) == 0x1C00) Demod.syncBit = 5; else if ((Demod.twoBits & 0x0EE0) == 0x0E00) Demod.syncBit = 4; @@ -495,7 +495,7 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non if (Demod.syncBit != 0xFFFF) { Demod.startTime = non_real_time?non_real_time:(GetCountSspClk() & 0xfffffff8); Demod.startTime -= Demod.syncBit; - Demod.bitCount = offset; // number of decoded data bits + Demod.bitCount = offset; // number of decoded data bits Demod.state = DEMOD_MANCHESTER_DATA; LED_C_ON(); } @@ -503,66 +503,66 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non } else { - if (IsManchesterModulationNibble1(Demod.twoBits >> Demod.syncBit)) { // modulation in first half - if (IsManchesterModulationNibble2(Demod.twoBits >> Demod.syncBit)) { // ... and in second half = collision + if (IsManchesterModulationNibble1(Demod.twoBits >> Demod.syncBit)) { // modulation in first half + if (IsManchesterModulationNibble2(Demod.twoBits >> Demod.syncBit)) { // ... and in second half = collision if (!Demod.collisionPos) { Demod.collisionPos = (Demod.len << 3) + Demod.bitCount; } - } // modulation in first half only - Sequence D = 1 + } // modulation in first half only - Sequence D = 1 Demod.bitCount++; - Demod.shiftReg = (Demod.shiftReg >> 1) | 0x100; // in both cases, add a 1 to the shiftreg - if(Demod.bitCount == 9) { // if we decoded a full byte (including parity) + Demod.shiftReg = (Demod.shiftReg >> 1) | 0x100; // in both cases, add a 1 to the shiftreg + if(Demod.bitCount == 9) { // if we decoded a full byte (including parity) Demod.output[Demod.len++] = (Demod.shiftReg & 0xff); - Demod.parityBits <<= 1; // make room for the parity bit - Demod.parityBits |= ((Demod.shiftReg >> 8) & 0x01); // store parity bit + Demod.parityBits <<= 1; // make room for the parity bit + Demod.parityBits |= ((Demod.shiftReg >> 8) & 0x01); // store parity bit Demod.bitCount = 0; Demod.shiftReg = 0; - if((Demod.len&0x0007) == 0) { // every 8 data bytes - Demod.parity[Demod.parityLen++] = Demod.parityBits; // store 8 parity bits + if((Demod.len&0x0007) == 0) { // every 8 data bytes + Demod.parity[Demod.parityLen++] = Demod.parityBits; // store 8 parity bits Demod.parityBits = 0; } } Demod.endTime = Demod.startTime + 8*(9*Demod.len + Demod.bitCount + 1) - 4; - } else { // no modulation in first half - if (IsManchesterModulationNibble2(Demod.twoBits >> Demod.syncBit)) { // and modulation in second half = Sequence E = 0 + } else { // no modulation in first half + if (IsManchesterModulationNibble2(Demod.twoBits >> Demod.syncBit)) { // and modulation in second half = Sequence E = 0 Demod.bitCount++; - Demod.shiftReg = (Demod.shiftReg >> 1); // add a 0 to the shiftreg - if(Demod.bitCount >= 9) { // if we decoded a full byte (including parity) + Demod.shiftReg = (Demod.shiftReg >> 1); // add a 0 to the shiftreg + if(Demod.bitCount >= 9) { // if we decoded a full byte (including parity) Demod.output[Demod.len++] = (Demod.shiftReg & 0xff); - Demod.parityBits <<= 1; // make room for the new parity bit + Demod.parityBits <<= 1; // make room for the new parity bit Demod.parityBits |= ((Demod.shiftReg >> 8) & 0x01); // store parity bit Demod.bitCount = 0; Demod.shiftReg = 0; - if ((Demod.len&0x0007) == 0) { // every 8 data bytes - Demod.parity[Demod.parityLen++] = Demod.parityBits; // store 8 parity bits1 + if ((Demod.len&0x0007) == 0) { // every 8 data bytes + Demod.parity[Demod.parityLen++] = Demod.parityBits; // store 8 parity bits1 Demod.parityBits = 0; } } Demod.endTime = Demod.startTime + 8*(9*Demod.len + Demod.bitCount + 1); - } else { // no modulation in both halves - End of communication + } else { // no modulation in both halves - End of communication LED_C_OFF(); - if(Demod.bitCount > 0) { // there are some remaining data bits - Demod.shiftReg >>= (9 - Demod.bitCount); // right align the decoded bits - Demod.output[Demod.len++] = Demod.shiftReg & 0xff; // and add them to the output - Demod.parityBits <<= 1; // add a (void) parity bit - Demod.parityBits <<= (8 - (Demod.len&0x0007)); // left align remaining parity bits - Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them + if(Demod.bitCount > 0) { // there are some remaining data bits + Demod.shiftReg >>= (9 - Demod.bitCount); // right align the decoded bits + Demod.output[Demod.len++] = Demod.shiftReg & 0xff; // and add them to the output + Demod.parityBits <<= 1; // add a (void) parity bit + Demod.parityBits <<= (8 - (Demod.len&0x0007)); // left align remaining parity bits + Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them return true; - } else if (Demod.len & 0x0007) { // there are some parity bits to store - Demod.parityBits <<= (8 - (Demod.len&0x0007)); // left align remaining parity bits - Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them + } else if (Demod.len & 0x0007) { // there are some parity bits to store + Demod.parityBits <<= (8 - (Demod.len&0x0007)); // left align remaining parity bits + Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them } if (Demod.len) { - return true; // we are finished with decoding the raw data sequence - } else { // nothing received. Start over + return true; // we are finished with decoding the raw data sequence + } else { // nothing received. Start over DemodReset(); } } } - - } - return false; // not finished yet, need more data + } + + return false; // not finished yet, need more data } //============================================================================= @@ -579,7 +579,7 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { // param: // bit 0 - trigger from first card answer // bit 1 - trigger from first reader 7-bit request - + LEDsoff(); LED_A_ON(); @@ -592,11 +592,11 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { // The command (reader -> tag) that we're receiving. uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); uint8_t *receivedCmdPar = BigBuf_malloc(MAX_PARITY_SIZE); - + // The response (tag -> reader) that we're receiving. uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE); uint8_t *receivedResponsePar = BigBuf_malloc(MAX_PARITY_SIZE); - + // The DMA buffer, used to stream samples from the FPGA uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); @@ -610,26 +610,26 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { int dataLen = 0; bool TagIsActive = false; bool ReaderIsActive = false; - + // Set up the demodulator for tag -> reader responses. DemodInit(receivedResponse, receivedResponsePar); - + // Set up the demodulator for the reader -> tag commands UartInit(receivedCmd, receivedCmdPar); - + // Setup and start DMA. FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); - + // We won't start recording the frames that we acquire until we trigger; // a good trigger condition to get started is probably when we see a // response from the tag. // triggered == false -- to wait first for card - bool triggered = !(param & 0x03); - + bool triggered = !(param & 0x03); + // And now we loop, receiving samples. - for(uint32_t rsamples = 0; true; ) { + for (uint32_t rsamples = 0; true; ) { - if(BUTTON_PRESS()) { + if (BUTTON_PRESS()) { DbpString("cancelled by button"); break; } @@ -665,9 +665,9 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; } - if (rsamples & 0x01) { // Need two samples to feed Miller and Manchester-Decoder + if (rsamples & 0x01) { // Need two samples to feed Miller and Manchester-Decoder - if(!TagIsActive) { // no need to try decoding reader data if the tag is sending + if(!TagIsActive) { // no need to try decoding reader data if the tag is sending uint8_t readerdata = (previous_data & 0xF0) | (*data >> 4); if (MillerDecoding(readerdata, (rsamples-1)*4)) { // check - if there is a short 7bit request from reader @@ -675,11 +675,11 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { triggered = true; } if(triggered) { - if (!LogTrace(receivedCmd, - Uart.len, + if (!LogTrace(receivedCmd, + Uart.len, Uart.startTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, - Uart.parity, + Uart.parity, true)) break; } /* And ready to receive another command. */ @@ -691,12 +691,12 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { ReaderIsActive = (Uart.state != STATE_UNSYNCD); } - if (!ReaderIsActive) { // no need to try decoding tag data if the reader is sending - and we cannot afford the time + if (!ReaderIsActive) { // no need to try decoding tag data if the reader is sending - and we cannot afford the time uint8_t tagdata = (previous_data << 4) | (*data & 0x0F); if (ManchesterDecoding(tagdata, 0, (rsamples-1)*4)) { - if (!LogTrace(receivedResponse, - Demod.len, - Demod.startTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, + if (!LogTrace(receivedResponse, + Demod.len, + Demod.startTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, Demod.endTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, Demod.parity, false)) break; @@ -705,7 +705,7 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { DemodReset(); // And reset the Miller decoder including itS (now outdated) input buffer UartInit(receivedCmd, receivedCmdPar); - } + } TagIsActive = (Demod.state != DEMOD_UNSYNCD); } } @@ -742,16 +742,16 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *par ToSendStuffBit(0); ToSendStuffBit(0); ToSendStuffBit(0); - + // Send startbit ToSend[++ToSendMax] = SEC_D; LastProxToAirDuration = 8 * ToSendMax - 4; - for(uint16_t i = 0; i < len; i++) { + for (uint16_t i = 0; i < len; i++) { uint8_t b = cmd[i]; // Data bits - for(uint16_t j = 0; j < 8; j++) { + for (uint16_t j = 0; j < 8; j++) { if(b & 1) { ToSend[++ToSendMax] = SEC_D; } else { @@ -798,7 +798,7 @@ static void Code4bitAnswerAsTag(uint8_t cmd) ToSend[++ToSendMax] = SEC_D; uint8_t b = cmd; - for(i = 0; i < 4; i++) { + for (i = 0; i < 4; i++) { if(b & 1) { ToSend[++ToSendMax] = SEC_D; LastProxToAirDuration = 8 * ToSendMax - 4; @@ -839,7 +839,7 @@ static void FixLastReaderTraceTime(uint32_t tag_StartTime) { LastReaderTraceTime[3] = (reader_StartTime >> 24) & 0xff; } - + static void EmLogTraceTag(uint8_t *tag_data, uint16_t tag_len, uint8_t *tag_Parity, uint32_t ProxToAirDuration) { uint32_t tag_StartTime = LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_TAG; uint32_t tag_EndTime = (LastTimeProxToAirStart + ProxToAirDuration)*16 + DELAY_ARM2AIR_AS_TAG; @@ -855,39 +855,38 @@ static void EmLogTraceTag(uint8_t *tag_data, uint16_t tag_len, uint8_t *tag_Pari //----------------------------------------------------------------------------- static int GetIso14443aCommandFromReader(uint8_t *received, uint8_t *parity, int *len) { - // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen - // only, since we are receiving, not transmitting). - // Signal field is off with the appropriate LED - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); + // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen + // only, since we are receiving, not transmitting). + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); - // Now run a `software UART' on the stream of incoming samples. + // Now run a `software UART' on the stream of incoming samples. UartInit(received, parity); // clear RXRDY: - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + + for (;;) { + WDT_HIT(); - for(;;) { - WDT_HIT(); + if(BUTTON_PRESS()) return false; - if(BUTTON_PRESS()) return false; - - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; if(MillerDecoding(b, 0)) { *len = Uart.len; EmLogTraceReader(); return true; } - } - } + } + } } -static int EmSend4bitEx(uint8_t resp); int EmSend4bit(uint8_t resp); static int EmSendCmdExPar(uint8_t *resp, uint16_t respLen, uint8_t *par); -int EmSendCmdEx(uint8_t *resp, uint16_t respLen); +int EmSendCmd(uint8_t *resp, uint16_t respLen); int EmSendPrecompiledCmd(tag_response_info_t *response_info); @@ -902,32 +901,32 @@ static bool prepare_tag_modulation(tag_response_info_t* response_info, size_t ma // ----------- + // 166 bytes, since every bit that needs to be send costs us a byte // - - + + // Prepare the tag modulation bits from the message GetParity(response_info->response, response_info->response_n, &(response_info->par)); CodeIso14443aAsTagPar(response_info->response,response_info->response_n, &(response_info->par)); - + // Make sure we do not exceed the free buffer space if (ToSendMax > max_buffer_size) { - Dbprintf("Out of memory, when modulating bits for tag answer:"); - Dbhexdump(response_info->response_n, response_info->response, false); - return false; + Dbprintf("Out of memory, when modulating bits for tag answer:"); + Dbhexdump(response_info->response_n, response_info->response, false); + return false; } - + // Copy the byte array, used for this modulation to the buffer position memcpy(response_info->modulation, ToSend, ToSendMax); - + // Store the number of bytes that were used for encoding/modulation and the time needed to transfer them response_info->modulation_n = ToSendMax; response_info->ProxToAirDuration = LastProxToAirDuration; - + return true; } // "precompile" responses. There are 7 predefined responses with a total of 28 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) // 28 * 8 data bits, 28 * 1 parity bits, 7 start bits, 7 stop bits, 7 correction bits for the modulation // -> need 273 bytes buffer #define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 273 @@ -936,15 +935,15 @@ bool prepare_allocated_tag_modulation(tag_response_info_t* response_info, uint8_ // Retrieve and store the current buffer index response_info->modulation = *buffer; - + // Forward the prepare tag modulation function to the inner function if (prepare_tag_modulation(response_info, *max_buffer_size)) { - // Update the free buffer offset and the remaining buffer size - *buffer += ToSendMax; + // Update the free buffer offset and the remaining buffer size + *buffer += ToSendMax; *max_buffer_size -= ToSendMax; - return true; + return true; } else { - return false; + return false; } } @@ -958,7 +957,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) // The first response contains the ATQA (note: bytes are transmitted in reverse order). uint8_t response1[2]; - + switch (tagType) { case 1: { // MIFARE Classic // Says: I am Mifare 1k - original line @@ -989,19 +988,19 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) response1[0] = 0x01; response1[1] = 0x0f; sak = 0x01; - } break; + } break; default: { Dbprintf("Error: unkown tagtype (%d)",tagType); return; } break; } - + // The second response contains the (mandatory) first 24 bits of the UID uint8_t response2[5] = {0x00}; // Check if the uid uses the (optional) part uint8_t response2a[5] = {0x00}; - + if (uid_2nd) { response2[0] = 0x88; num_to_bytes(uid_1st,3,response2+1); @@ -1032,8 +1031,8 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); uint8_t response5[] = { 0x00, 0x00, 0x00, 0x00 }; // Very random tag nonce - uint8_t response6[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 }; // dummy ATS (pseudo-ATR), answer to RATS: - // Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present, + uint8_t response6[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 }; // dummy ATS (pseudo-ATR), answer to RATS: + // Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present, // TA(1) = 0x80: different divisors not supported, DR = 1, DS = 1 // TB(1) = not present. Defaults: FWI = 4 (FWT = 256 * 16 * 2^4 * 1/fc = 4833us), SFGI = 0 (SFG = 256 * 16 * 2^0 * 1/fc = 302us) // TC(1) = 0x02: CID supported, NAD not supported @@ -1062,7 +1061,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) .modulation = dynamic_modulation_buffer, .modulation_n = 0 }; - + // We need to listen to the high-frequency, peak-detected path. iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); @@ -1098,7 +1097,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) tag_response_info_t* p_response; LED_A_ON(); - for(;;) { + for (;;) { // Clean receive command buffer if(!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) { DbpString("Button press"); @@ -1106,32 +1105,32 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) } p_response = NULL; - + // Okay, look at the command now. lastorder = order; if(receivedCmd[0] == 0x26) { // Received a REQUEST p_response = &responses[0]; order = 1; } else if(receivedCmd[0] == 0x52) { // Received a WAKEUP p_response = &responses[0]; order = 6; - } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x93) { // Received request for UID (cascade 1) + } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x93) { // Received request for UID (cascade 1) p_response = &responses[1]; order = 2; - } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x95) { // Received request for UID (cascade 2) + } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x95) { // Received request for UID (cascade 2) p_response = &responses[2]; order = 20; - } else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x93) { // Received a SELECT (cascade 1) + } else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x93) { // Received a SELECT (cascade 1) p_response = &responses[3]; order = 3; - } else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x95) { // Received a SELECT (cascade 2) + } else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x95) { // Received a SELECT (cascade 2) p_response = &responses[4]; order = 30; - } else if(receivedCmd[0] == 0x30) { // Received a (plain) READ - EmSendCmdEx(data+(4*receivedCmd[1]),16); + } else if(receivedCmd[0] == 0x30) { // Received a (plain) READ + EmSendCmd(data+(4*receivedCmd[1]),16); // Dbprintf("Read request from reader: %x %x",receivedCmd[0],receivedCmd[1]); // We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below p_response = NULL; - } else if(receivedCmd[0] == 0x50) { // Received a HALT + } else if(receivedCmd[0] == 0x50) { // Received a HALT p_response = NULL; - } else if(receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61) { // Received an authentication request + } else if(receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61) { // Received an authentication request p_response = &responses[5]; order = 7; - } else if(receivedCmd[0] == 0xE0) { // Received a RATS request - if (tagType == 1 || tagType == 2) { // RATS not supported + } else if(receivedCmd[0] == 0xE0) { // Received a RATS request + if (tagType == 1 || tagType == 2) { // RATS not supported EmSend4bit(CARD_NACK_NA); p_response = NULL; } else { @@ -1165,7 +1164,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) dynamic_response_info.response[0] = receivedCmd[0] ^ 0x11; dynamic_response_info.response_n = 2; } break; - + case 0xBA: { // memcpy(dynamic_response_info.response,"\xAB\x00",2); dynamic_response_info.response_n = 2; @@ -1185,7 +1184,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) dynamic_response_info.response_n = 0; } break; } - + if (dynamic_response_info.response_n > 0) { // Copy the CID from the reader query dynamic_response_info.response[1] = receivedCmd[1]; @@ -1193,7 +1192,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) // Add CRC bytes, always used in ISO 14443A-4 compliant cards AppendCrc14443a(dynamic_response_info.response,dynamic_response_info.response_n); dynamic_response_info.response_n += 2; - + if (prepare_tag_modulation(&dynamic_response_info,DYNAMIC_MODULATION_BUFFER_SIZE) == false) { Dbprintf("Error preparing tag response"); break; @@ -1217,7 +1216,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) if (p_response != NULL) { EmSendPrecompiledCmd(p_response); } - + if (!get_tracing()) { Dbprintf("Trace Full. Simulation stopped."); break; @@ -1237,7 +1236,7 @@ static void PrepareDelayedTransfer(uint16_t delay) uint8_t bitmask = 0; uint8_t bits_to_shift = 0; uint8_t bits_shifted = 0; - + delay &= 0x07; if (delay) { for (uint16_t i = 0; i < delay; i++) { @@ -1258,37 +1257,38 @@ static void PrepareDelayedTransfer(uint16_t delay) // Transmit the command (to the tag) that was placed in ToSend[]. // Parameter timing: // if NULL: transfer at next possible time, taking into account -// request guard time, startup frame guard time and frame delay time -// if == 0: transfer immediately and return time of transfer +// request guard time, startup frame guard time and frame delay time +// if == 0: transfer immediately and return time of transfer // if != 0: delay transfer until time specified //------------------------------------------------------------------------------------- static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing) { + LED_B_ON(); LED_D_ON(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); uint32_t ThisTransferTime = 0; if (timing) { - if(*timing == 0) { // Measure time + if(*timing == 0) { // Measure time *timing = (GetCountSspClk() + 8) & 0xfffffff8; } else { - PrepareDelayedTransfer(*timing & 0x00000007); // Delay transfer (fine tuning - up to 7 MF clock ticks) + PrepareDelayedTransfer(*timing & 0x00000007); // Delay transfer (fine tuning - up to 7 MF clock ticks) } if(MF_DBGLEVEL >= 4 && GetCountSspClk() >= (*timing & 0xfffffff8)) Dbprintf("TransmitFor14443a: Missed timing"); - while(GetCountSspClk() < (*timing & 0xfffffff8)); // Delay transfer (multiple of 8 MF clock ticks) + while (GetCountSspClk() < (*timing & 0xfffffff8)); // Delay transfer (multiple of 8 MF clock ticks) LastTimeProxToAirStart = *timing; } else { ThisTransferTime = ((MAX(NextTransferTime, GetCountSspClk()) & 0xfffffff8) + 8); - while(GetCountSspClk() < ThisTransferTime); + while (GetCountSspClk() < ThisTransferTime); LastTimeProxToAirStart = ThisTransferTime; } - + // clear TXRDY AT91C_BASE_SSC->SSC_THR = SEC_Y; uint16_t c = 0; - for(;;) { + for (;;) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { AT91C_BASE_SSC->SSC_THR = cmd[c]; c++; @@ -1297,8 +1297,9 @@ static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing } } } - + NextTransferTime = MAX(NextTransferTime, LastTimeProxToAirStart + REQUEST_GUARD_TIME); + LED_B_OFF(); } @@ -1391,84 +1392,98 @@ static void CodeIso14443aBitsAsReaderPar(const uint8_t *cmd, uint16_t bits, cons //----------------------------------------------------------------------------- int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity) { + uint32_t field_off_time = -1; + uint32_t samples = 0; + int ret = 0; + uint8_t b = 0;; + uint8_t dmaBuf[DMA_BUFFER_SIZE]; + uint8_t *upTo = dmaBuf; + *len = 0; - uint32_t timer = 0, vtime = 0; - int analogCnt = 0; - int analogAVG = 0; + // Run a 'software UART' on the stream of incoming samples. + UartInit(received, parity); - // Set ADC to read field strength - AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST; - AT91C_BASE_ADC->ADC_MR = - ADC_MODE_PRESCALE(63) | - ADC_MODE_STARTUP_TIME(1) | - ADC_MODE_SAMPLE_HOLD_TIME(15); - AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ADC_CHAN_HF_LOW); // start ADC AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; - - // Run a 'software UART' on the stream of incoming samples. - UartInit(received, parity); // Ensure that the FPGA Delay Queue is empty before we switch to TAGSIM_LISTEN - do { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = SEC_F; - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; (void) b; - } - } while (GetCountSspClk() < LastTimeProxToAirStart + LastProxToAirDuration + (FpgaSendQueueDelay>>3)); + while (GetCountSspClk() < LastTimeProxToAirStart + LastProxToAirDuration + (FpgaSendQueueDelay>>3) - 8 - 3) /* wait */ ; // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen // only, since we are receiving, not transmitting). - // Signal field is off with the appropriate LED - LED_D_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); + // clear receive register, measure time of next transfer + uint32_t temp = AT91C_BASE_SSC->SSC_RHR; (void) temp; + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) ; + uint32_t start_time = GetCountSspClk() & 0xfffffff8; + + // Setup and start DMA. + FpgaSetupSscDma(dmaBuf, DMA_BUFFER_SIZE); + for(;;) { - WDT_HIT(); + uint16_t behindBy = ((uint8_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE-1); - if (BUTTON_PRESS()) return 1; + if (behindBy == 0) continue; - // test if the field exists - if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF_LOW)) { - analogCnt++; - analogAVG += AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF_LOW]; - AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; - if (analogCnt >= 32) { - if ((MAX_ADC_HF_VOLTAGE_LOW * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) { - vtime = GetTickCount(); - if (!timer) timer = vtime; - // 50ms no field --> card to idle state - if (vtime - timer > 50) return 2; - } else - if (timer) timer = 0; - analogCnt = 0; - analogAVG = 0; + b = *upTo++; + + if(upTo >= dmaBuf + DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dmaBuf; // start reading the circular buffer from the beginning + if(behindBy > (9*DMA_BUFFER_SIZE/10)) { + Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); + ret = 1; + break; } } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; // DMA Next Counter registers + } - // receive and test the miller decoding - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - if(MillerDecoding(b, 0)) { - *len = Uart.len; - EmLogTraceReader(); - return 0; + if (BUTTON_PRESS()) { + ret = 1; + break; + } + + // check reader's HF field + if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF_LOW)) { + if ((MAX_ADC_HF_VOLTAGE_LOW * AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF_LOW]) >> 10 < MF_MINFIELDV) { + if (GetTickCount() - field_off_time > 50) { + ret = 2; // reader has switched off HF field for more than 50ms. Timeout + break; + } + } else { + field_off_time = GetTickCount(); // HF field is still there. Reset timer } - } + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; // restart ADC + } + + if (MillerDecoding(b, start_time + samples*8)) { + *len = Uart.len; + EmLogTraceReader(); + ret = 0; + break; + } + samples++; } + + FpgaDisableSscDma(); + return ret; } static int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) { + LED_C_ON(); + uint8_t b; uint16_t i = 0; bool correctionNeeded; // Modulate Manchester - LED_D_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD); // include correction bit if necessary @@ -1483,73 +1498,61 @@ static int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) correctionNeeded = Uart.parity[(Uart.len-1)/8] & (0x80 >> ((Uart.len-1) & 7)); } - if(correctionNeeded) { + if (correctionNeeded) { // 1236, so correction bit needed i = 0; } else { i = 1; } - // clear receiving shift register and holding register - while(!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); + // clear receiving shift register and holding register b = AT91C_BASE_SSC->SSC_RHR; (void) b; - while(!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); b = AT91C_BASE_SSC->SSC_RHR; (void) b; - + // wait for the FPGA to signal fdt_indicator == 1 (the FPGA is ready to queue new data in its delay line) - for (uint16_t j = 0; j < 5; j++) { // allow timeout - better late than never - while(!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); + for (uint16_t j = 0; j < 5; j++) { // allow timeout - better late than never + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); if (AT91C_BASE_SSC->SSC_RHR) break; } LastTimeProxToAirStart = (GetCountSspClk() & 0xfffffff8) + (correctionNeeded?8:0); // send cycle - for(; i < respLen; ) { + for (; i < respLen; ) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { AT91C_BASE_SSC->SSC_THR = resp[i++]; FpgaSendQueueDelay = (uint8_t)AT91C_BASE_SSC->SSC_RHR; } - + if(BUTTON_PRESS()) { break; } } + LED_C_OFF(); return 0; } -static int EmSend4bitEx(uint8_t resp){ +int EmSend4bit(uint8_t resp){ Code4bitAnswerAsTag(resp); int res = EmSendCmd14443aRaw(ToSend, ToSendMax); - // do the tracing for the previous reader request and this tag answer: + // Log this tag answer and fix timing of previous reader command: EmLogTraceTag(&resp, 1, NULL, LastProxToAirDuration); return res; } -int EmSend4bit(uint8_t resp){ - return EmSend4bitEx(resp); -} - - static int EmSendCmdExPar(uint8_t *resp, uint16_t respLen, uint8_t *par){ CodeIso14443aAsTagPar(resp, respLen, par); int res = EmSendCmd14443aRaw(ToSend, ToSendMax); - // do the tracing for the previous reader request and this tag answer: + // Log this tag answer and fix timing of previous reader command: EmLogTraceTag(resp, respLen, par, LastProxToAirDuration); return res; } -int EmSendCmdEx(uint8_t *resp, uint16_t respLen){ - uint8_t par[MAX_PARITY_SIZE]; - GetParity(resp, respLen, par); - return EmSendCmdExPar(resp, respLen, par); -} - - int EmSendCmd(uint8_t *resp, uint16_t respLen){ uint8_t par[MAX_PARITY_SIZE]; GetParity(resp, respLen, par); @@ -1564,7 +1567,7 @@ int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par){ int EmSendPrecompiledCmd(tag_response_info_t *response_info) { int ret = EmSendCmd14443aRaw(response_info->modulation, response_info->modulation_n); - // do the tracing for the previous reader request and this tag answer: + // Log this tag answer and fix timing of previous reader command: EmLogTraceTag(response_info->response, response_info->response_n, &(response_info->par), response_info->ProxToAirDuration); return ret; } @@ -1578,21 +1581,21 @@ int EmSendPrecompiledCmd(tag_response_info_t *response_info) { static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receivedResponsePar, uint16_t offset) { uint32_t c; - + // Set FPGA mode to "reader listen mode", no modulation (listen // only, since we are receiving, not transmitting). // Signal field is on with the appropriate LED LED_D_ON(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_LISTEN); - + // Now get the answer from the card DemodInit(receivedResponse, receivedResponsePar); // clear RXRDY: - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; c = 0; - for(;;) { + for (;;) { WDT_HIT(); if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { @@ -1601,7 +1604,7 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receive NextTransferTime = MAX(NextTransferTime, Demod.endTime - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/16 + FRAME_DELAY_TIME_PICC_TO_PCD); return true; } else if (c++ > iso14a_timeout && Demod.state == DEMOD_UNSYNCD) { - return false; + return false; } } } @@ -1611,12 +1614,12 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receive void ReaderTransmitBitsPar(uint8_t* frame, uint16_t bits, uint8_t *par, uint32_t *timing) { CodeIso14443aBitsAsReaderPar(frame, bits, par); - + // Send command to tag TransmitFor14443a(ToSend, ToSendMax, timing); if(trigger) LED_A_ON(); - + // Log reader command in trace buffer LogTrace(frame, nbytes(bits), LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_READER, (LastTimeProxToAirStart + LastProxToAirDuration)*16 + DELAY_ARM2AIR_AS_READER, par, true); } @@ -1665,24 +1668,24 @@ int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity) static void iso14a_set_ATS_times(uint8_t *ats) { uint8_t tb1; - uint8_t fwi, sfgi; + uint8_t fwi, sfgi; uint32_t fwt, sfgt; - - if (ats[0] > 1) { // there is a format byte T0 - if ((ats[1] & 0x20) == 0x20) { // there is an interface byte TB(1) - if ((ats[1] & 0x10) == 0x10) { // there is an interface byte TA(1) preceding TB(1) + + if (ats[0] > 1) { // there is a format byte T0 + if ((ats[1] & 0x20) == 0x20) { // there is an interface byte TB(1) + if ((ats[1] & 0x10) == 0x10) { // there is an interface byte TA(1) preceding TB(1) tb1 = ats[3]; } else { tb1 = ats[2]; } - fwi = (tb1 & 0xf0) >> 4; // frame waiting time integer (FWI) + fwi = (tb1 & 0xf0) >> 4; // frame waiting time integer (FWI) if (fwi != 15) { - fwt = 256 * 16 * (1 << fwi); // frame waiting time (FWT) in 1/fc + fwt = 256 * 16 * (1 << fwi); // frame waiting time (FWT) in 1/fc iso14a_set_timeout(fwt/(8*16)); } - sfgi = tb1 & 0x0f; // startup frame guard time integer (SFGI) + sfgi = tb1 & 0x0f; // startup frame guard time integer (SFGI) if (sfgi != 0 && sfgi != 15) { - sfgt = 256 * 16 * (1 << sfgi); // startup frame guard time (SFGT) in 1/fc + sfgt = 256 * 16 * (1 << sfgi); // startup frame guard time (SFGT) in 1/fc NextTransferTime = MAX(NextTransferTime, Demod.endTime + (sfgt - DELAY_AIR2ARM_AS_READER - DELAY_ARM2AIR_AS_READER)/16); } } @@ -1692,15 +1695,15 @@ static void iso14a_set_ATS_times(uint8_t *ats) { static int GetATQA(uint8_t *resp, uint8_t *resp_par) { -#define WUPA_RETRY_TIMEOUT 10 // 10ms +#define WUPA_RETRY_TIMEOUT 10 // 10ms uint8_t wupa[] = { 0x52 }; // 0x26 - REQA 0x52 - WAKE-UP uint32_t save_iso14a_timeout = iso14a_get_timeout(); - iso14a_set_timeout(1236/(16*8)+1); // response to WUPA is expected at exactly 1236/fc. No need to wait longer. - + iso14a_set_timeout(1236/(16*8)+1); // response to WUPA is expected at exactly 1236/fc. No need to wait longer. + uint32_t start_time = GetTickCount(); int len; - + // we may need several tries if we did send an unknown command or a wrong authentication before... do { // Broadcast for a card, WUPA (0x52) will force response from all cards in the field @@ -1708,7 +1711,7 @@ static int GetATQA(uint8_t *resp, uint8_t *resp_par) { // Receive the ATQA len = ReaderReceive(resp, resp_par); } while (len == 0 && GetTickCount() <= start_time + WUPA_RETRY_TIMEOUT); - + iso14a_set_timeout(save_iso14a_timeout); return len; } @@ -1717,7 +1720,7 @@ static int GetATQA(uint8_t *resp, uint8_t *resp_par) { // performs iso14443a anticollision (optional) and card select procedure // fills the uid and cuid pointer unless NULL // fills the card info record unless NULL -// if anticollision is false, then the UID must be provided in uid_ptr[] +// if anticollision is false, then the UID must be provided in uid_ptr[] // and num_cascades must be set (1: 4 Byte UID, 2: 7 Byte UID, 3: 10 Byte UID) // requests ATS unless no_rats is true int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats) { @@ -1759,11 +1762,11 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u if ((resp[0] & 0x1F) == 0) { return 3; } - + // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in // which case we need to make a cascade 2 request and select - this is a long UID - // While the UID is not complete, the 3nd bit (from the right) is set in the SAK. - for(; sak & 0x04; cascade_level++) { + // While the UID is not complete, the 3rd bit (from the right) is set in the SAK. + for (; sak & 0x04; cascade_level++) { // SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97) sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2; @@ -1774,21 +1777,21 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u return 0; } - if (Demod.collisionPos) { // we had a collision and need to construct the UID bit by bit + if (Demod.collisionPos) { // we had a collision and need to construct the UID bit by bit memset(uid_resp, 0, 4); uint16_t uid_resp_bits = 0; uint16_t collision_answer_offset = 0; // anti-collision-loop: while (Demod.collisionPos) { Dbprintf("Multiple tags detected. Collision after Bit %d", Demod.collisionPos); - for (uint16_t i = collision_answer_offset; i < Demod.collisionPos; i++, uid_resp_bits++) { // add valid UID bits before collision point + for (uint16_t i = collision_answer_offset; i < Demod.collisionPos; i++, uid_resp_bits++) { // add valid UID bits before collision point uint16_t UIDbit = (resp[i/8] >> (i % 8)) & 0x01; uid_resp[uid_resp_bits / 8] |= UIDbit << (uid_resp_bits % 8); } - uid_resp[uid_resp_bits/8] |= 1 << (uid_resp_bits % 8); // next time select the card(s) with a 1 in the collision position + uid_resp[uid_resp_bits/8] |= 1 << (uid_resp_bits % 8); // next time select the card(s) with a 1 in the collision position uid_resp_bits++; // construct anticollosion command: - sel_uid[1] = ((2 + uid_resp_bits/8) << 4) | (uid_resp_bits & 0x07); // length of data in bytes and bits + sel_uid[1] = ((2 + uid_resp_bits/8) << 4) | (uid_resp_bits & 0x07); // length of data in bytes and bits for (uint16_t i = 0; i <= uid_resp_bits/8; i++) { sel_uid[2+i] = uid_resp[i]; } @@ -1804,7 +1807,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u uid_resp[uid_resp_bits/8] |= UIDbit << (uid_resp_bits % 8); } - } else { // no collision, use the response to SELECT_ALL as current uid + } else { // no collision, use the response to SELECT_ALL as current uid memcpy(uid_resp, resp, 4); } } else { @@ -1823,10 +1826,10 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u } // Construct SELECT UID command - sel_uid[1] = 0x70; // transmitting a full UID (1 Byte cmd, 1 Byte NVB, 4 Byte UID, 1 Byte BCC, 2 Bytes CRC) - memcpy(sel_uid+2, uid_resp, 4); // the UID received during anticollision, or the provided UID - sel_uid[6] = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5]; // calculate and add BCC - AppendCrc14443a(sel_uid, 7); // calculate and add CRC + sel_uid[1] = 0x70; // transmitting a full UID (1 Byte cmd, 1 Byte NVB, 4 Byte UID, 1 Byte BCC, 2 Bytes CRC) + memcpy(sel_uid+2, uid_resp, 4); // the UID received during anticollision, or the provided UID + sel_uid[6] = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5]; // calculate and add BCC + AppendCrc14443a(sel_uid, 7); // calculate and add CRC ReaderTransmit(sel_uid, sizeof(sel_uid), NULL); // Receive the SAK @@ -1834,14 +1837,14 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u return 0; } sak = resp[0]; - + // Test if more parts of the uid are coming if ((sak & 0x04) /* && uid_resp[0] == 0x88 */) { // Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of: // http://www.nxp.com/documents/application_note/AN10927.pdf uid_resp[0] = uid_resp[1]; uid_resp[1] = uid_resp[2]; - uid_resp[2] = uid_resp[3]; + uid_resp[2] = uid_resp[3]; uid_resp_len = 3; } @@ -1860,7 +1863,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u } // PICC compilant with iso14443a-4 ---> (SAK & 0x20 != 0) - if( (sak & 0x20) == 0) return 2; + if( (sak & 0x20) == 0) return 2; if (!no_rats) { // Request for answer to select @@ -1881,9 +1884,9 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u // set default timeout and delay next transfer based on ATS iso14a_set_ATS_times(resp); - + } - return 1; + return 1; } @@ -1903,11 +1906,22 @@ void iso14443a_setup(uint8_t fpga_minor_mode) { } FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | fpga_minor_mode); + // Set ADC to read field strength + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST; + AT91C_BASE_ADC->ADC_MR = + ADC_MODE_PRESCALE(63) | + ADC_MODE_STARTUP_TIME(1) | + ADC_MODE_SAMPLE_HOLD_TIME(15); + AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ADC_CHAN_HF_LOW); + // Start the timer StartCountSspClk(); - + DemodReset(); UartReset(); + LastTimeProxToAirStart = 0; + FpgaSendQueueDelay = 0; + LastProxToAirDuration = 20; // arbitrary small value. Avoid lock in EmGetCmd() NextTransferTime = 2*DELAY_ARM2AIR_AS_READER; iso14a_set_timeout(1060); // 10ms default } @@ -1932,17 +1946,17 @@ b8 b7 b6 b5 b4 b3 b2 b1 b5 = ACK/NACK Coding of S-block: b8 b7 b6 b5 b4 b3 b2 b1 -1 1 x x x 0 1 0 +1 1 x x x 0 1 0 b5,b6 = 00 - DESELECT - 11 - WTX -*/ + 11 - WTX +*/ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint8_t *res) { uint8_t parity[MAX_PARITY_SIZE]; uint8_t real_cmd[cmd_len + 4]; - + if (cmd_len) { // ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02 - real_cmd[0] = 0x02; // bnr,nad,cid,chn=0; i-block(0x00) + real_cmd[0] = 0x02; // bnr,nad,cid,chn=0; i-block(0x00) if (send_chaining) { real_cmd[0] |= 0x10; } @@ -1951,11 +1965,11 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, u memcpy(real_cmd + 1, cmd, cmd_len); } else { // R-block. ACK - real_cmd[0] = 0xA2; // r-block + ACK + real_cmd[0] = 0xA2; // r-block + ACK real_cmd[0] |= iso14_pcb_blocknum; } AppendCrc14443a(real_cmd, cmd_len + 1); - + ReaderTransmit(real_cmd, cmd_len + 3, NULL); size_t len = ReaderReceive(data, parity); @@ -1963,20 +1977,20 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, u if (!len) { return 0; //DATA LINK ERROR - } else{ - // S-Block WTX - while(len && ((data_bytes[0] & 0xF2) == 0xF2)) { + } else { + // S-Block WTX + while (len && ((data_bytes[0] & 0xF2) == 0xF2)) { uint32_t save_iso14a_timeout = iso14a_get_timeout(); // temporarily increase timeout iso14a_set_timeout(MAX((data_bytes[1] & 0x3f) * save_iso14a_timeout, MAX_ISO14A_TIMEOUT)); - // Transmit WTX back + // Transmit WTX back // byte1 - WTXM [1..59]. command FWT=FWT*WTXM data_bytes[1] = data_bytes[1] & 0x3f; // 2 high bits mandatory set to 0b // now need to fix CRC. AppendCrc14443a(data_bytes, len - 2); // transmit S-Block ReaderTransmit(data_bytes, len, NULL); - // retrieve the result again (with increased timeout) + // retrieve the result again (with increased timeout) len = ReaderReceive(data, parity); data_bytes = data; // restore timeout @@ -1986,13 +2000,13 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, u // if we received an I- or R(ACK)-Block with a block number equal to the // current block number, toggle the current block number if (len >= 3 // PCB+CRC = 3 bytes - && ((data_bytes[0] & 0xC0) == 0 // I-Block - || (data_bytes[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0 - && (data_bytes[0] & 0x01) == iso14_pcb_blocknum) // equal block numbers + && ((data_bytes[0] & 0xC0) == 0 // I-Block + || (data_bytes[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0 + && (data_bytes[0] & 0x01) == iso14_pcb_blocknum) // equal block numbers { iso14_pcb_blocknum ^= 1; } - + // if we received I-block with chaining we need to send ACK and receive another block of data if (res) *res = data_bytes[0]; @@ -2001,9 +2015,9 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, u if (len >= 3 && !CheckCrc14443(CRC_14443_A, data_bytes, len)) { return -1; } - + } - + if (len) { // cut frame byte len -= 1; @@ -2011,7 +2025,7 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, u for (int i = 0; i < len; i++) data_bytes[i] = data_bytes[i + 1]; } - + return len; } @@ -2031,9 +2045,9 @@ void ReaderIso14443a(UsbCommand *c) byte_t buf[USB_CMD_DATA_SIZE] = {0}; uint8_t par[MAX_PARITY_SIZE]; bool cantSELECT = false; - + set_tracing(true); - + if(param & ISO14A_CLEAR_TRACE) { clear_trace(); } @@ -2084,29 +2098,29 @@ void ReaderIso14443a(UsbCommand *c) len += 2; if (lenbits) lenbits += 16; } - if(lenbits>0) { // want to send a specific number of bits (e.g. short commands) + if(lenbits>0) { // want to send a specific number of bits (e.g. short commands) if(param & ISO14A_TOPAZMODE) { int bits_to_send = lenbits; uint16_t i = 0; - ReaderTransmitBitsPar(&cmd[i++], MIN(bits_to_send, 7), NULL, NULL); // first byte is always short (7bits) and no parity + ReaderTransmitBitsPar(&cmd[i++], MIN(bits_to_send, 7), NULL, NULL); // first byte is always short (7bits) and no parity bits_to_send -= 7; while (bits_to_send > 0) { - ReaderTransmitBitsPar(&cmd[i++], MIN(bits_to_send, 8), NULL, NULL); // following bytes are 8 bit and no parity + ReaderTransmitBitsPar(&cmd[i++], MIN(bits_to_send, 8), NULL, NULL); // following bytes are 8 bit and no parity bits_to_send -= 8; } } else { GetParity(cmd, lenbits/8, par); - ReaderTransmitBitsPar(cmd, lenbits, par, NULL); // bytes are 8 bit with odd parity + ReaderTransmitBitsPar(cmd, lenbits, par, NULL); // bytes are 8 bit with odd parity } - } else { // want to send complete bytes only + } else { // want to send complete bytes only if(param & ISO14A_TOPAZMODE) { uint16_t i = 0; - ReaderTransmitBitsPar(&cmd[i++], 7, NULL, NULL); // first byte: 7 bits, no paritiy + ReaderTransmitBitsPar(&cmd[i++], 7, NULL, NULL); // first byte: 7 bits, no paritiy while (i < len) { - ReaderTransmitBitsPar(&cmd[i++], 8, NULL, NULL); // following bytes: 8 bits, no paritiy + ReaderTransmitBitsPar(&cmd[i++], 8, NULL, NULL); // following bytes: 8 bits, no paritiy } } else { - ReaderTransmit(cmd,len, NULL); // 8 bits, odd parity + ReaderTransmit(cmd,len, NULL); // 8 bits, odd parity } } arg0 = ReaderReceive(buf, par); @@ -2142,14 +2156,14 @@ static int32_t dist_nt(uint32_t nt1, uint32_t nt2) { nttmp1 = nt1; nttmp2 = nt2; - + for (i = 1; i < 32768; i++) { nttmp1 = prng_successor(nttmp1, 1); if (nttmp1 == nt2) return i; nttmp2 = prng_successor(nttmp2, 1); if (nttmp2 == nt1) return -i; } - + return(-99999); // either nt1 or nt2 are invalid nonces } @@ -2171,15 +2185,15 @@ void ReaderMifare(bool first_try) uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); - + // free eventually allocated BigBuf memory. We want all for tracing. BigBuf_free(); - + clear_trace(); set_tracing(true); uint8_t nt_diff = 0; - uint8_t par[1] = {0}; // maximum 8 Bytes to be sent here, 1 byte parity is therefore enough + uint8_t par[1] = {0}; // maximum 8 Bytes to be sent here, 1 byte parity is therefore enough static uint8_t par_low = 0; bool led_on = true; uint8_t uid[10] ={0}; @@ -2200,10 +2214,10 @@ void ReaderMifare(bool first_try) uint16_t consecutive_resyncs = 0; int isOK = 0; - if (first_try) { + if (first_try) { mf_nr_ar3 = 0; par[0] = par_low = 0; - sync_cycles = PRNG_SEQUENCE_LENGTH; // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the tag nonces). + sync_cycles = PRNG_SEQUENCE_LENGTH; // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the tag nonces). nt_attacked = 0; } else { @@ -2216,13 +2230,13 @@ void ReaderMifare(bool first_try) LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - - #define MAX_UNEXPECTED_RANDOM 4 // maximum number of unexpected (i.e. real) random numbers when trying to sync. Then give up. - #define MAX_SYNC_TRIES 32 - #define SYNC_TIME_BUFFER 16 // if there is only SYNC_TIME_BUFFER left before next planned sync, wait for next PRNG cycle - #define NUM_DEBUG_INFOS 8 // per strategy - #define MAX_STRATEGY 3 + + #define MAX_UNEXPECTED_RANDOM 4 // maximum number of unexpected (i.e. real) random numbers when trying to sync. Then give up. + #define MAX_SYNC_TRIES 32 + #define SYNC_TIME_BUFFER 16 // if there is only SYNC_TIME_BUFFER left before next planned sync, wait for next PRNG cycle + #define NUM_DEBUG_INFOS 8 // per strategy + #define MAX_STRATEGY 3 uint16_t unexpected_random = 0; uint16_t sync_tries = 0; int16_t debug_info_nr = -1; @@ -2230,9 +2244,9 @@ void ReaderMifare(bool first_try) int32_t debug_info[MAX_STRATEGY][NUM_DEBUG_INFOS]; uint32_t select_time; uint32_t halt_time; - - for(uint16_t i = 0; true; i++) { - + + for (uint16_t i = 0; true; i++) { + LED_C_ON(); WDT_HIT(); @@ -2241,7 +2255,7 @@ void ReaderMifare(bool first_try) isOK = -1; break; } - + if (strategy == 2) { // test with additional hlt command halt_time = 0; @@ -2258,9 +2272,9 @@ void ReaderMifare(bool first_try) iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); SpinDelay(100); } - + if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Can't select card"); + if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Can't select card"); continue; } select_time = GetCountSspClk(); @@ -2276,11 +2290,11 @@ void ReaderMifare(bool first_try) sync_time = (sync_time & 0xfffffff8) + sync_cycles; } - // Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked) + // Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked) ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time); } else { // collect some information on tag nonces for debugging: - #define DEBUG_FIXED_SYNC_CYCLES PRNG_SEQUENCE_LENGTH + #define DEBUG_FIXED_SYNC_CYCLES PRNG_SEQUENCE_LENGTH if (strategy == 0) { // nonce distances at fixed time after card select: sync_time = select_time + DEBUG_FIXED_SYNC_CYCLES; @@ -2295,11 +2309,11 @@ void ReaderMifare(bool first_try) sync_time = DEBUG_FIXED_SYNC_CYCLES; } ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time); - } + } // Receive the (4 Byte) "random" nonce if (!ReaderReceive(receivedAnswer, receivedAnswerPar)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Couldn't receive tag nonce"); + if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Couldn't receive tag nonce"); continue; } @@ -2317,17 +2331,17 @@ void ReaderMifare(bool first_try) if (nt_distance == -99999) { // invalid nonce received unexpected_random++; if (unexpected_random > MAX_UNEXPECTED_RANDOM) { - isOK = -3; // Card has an unpredictable PRNG. Give up + isOK = -3; // Card has an unpredictable PRNG. Give up break; } else { - continue; // continue trying... + continue; // continue trying... } } if (++sync_tries > MAX_SYNC_TRIES) { if (strategy > MAX_STRATEGY || MF_DBGLEVEL < 3) { - isOK = -4; // Card's PRNG runs at an unexpected frequency or resets unexpectedly + isOK = -4; // Card's PRNG runs at an unexpected frequency or resets unexpectedly break; - } else { // continue for a while, just to collect some debug info + } else { // continue for a while, just to collect some debug info debug_info[strategy][debug_info_nr] = nt_distance; debug_info_nr++; if (debug_info_nr == NUM_DEBUG_INFOS) { @@ -2348,9 +2362,9 @@ void ReaderMifare(bool first_try) } } - if ((nt != nt_attacked) && nt_attacked) { // we somehow lost sync. Try to catch up again... + if ((nt != nt_attacked) && nt_attacked) { // we somehow lost sync. Try to catch up again... catch_up_cycles = -dist_nt(nt_attacked, nt); - if (catch_up_cycles == 99999) { // invalid nonce received. Don't resync on that one. + if (catch_up_cycles == 99999) { // invalid nonce received. Don't resync on that one. catch_up_cycles = 0; continue; } @@ -2360,12 +2374,12 @@ void ReaderMifare(bool first_try) } else { last_catch_up = catch_up_cycles; - consecutive_resyncs = 0; + consecutive_resyncs = 0; } if (consecutive_resyncs < 3) { if (MF_DBGLEVEL >= 3) 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 { + else { sync_cycles = sync_cycles + catch_up_cycles; if (MF_DBGLEVEL >= 3) 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; @@ -2374,13 +2388,13 @@ void ReaderMifare(bool first_try) } continue; } - + consecutive_resyncs = 0; - + // Receive answer. This will be a 4 Bit NACK when the 8 parity bits are OK after decoding if (ReaderReceive(receivedAnswer, receivedAnswerPar)) { - catch_up_cycles = 8; // the PRNG is delayed by 8 cycles due to the NAC (4Bits = 0x05 encrypted) transfer - + catch_up_cycles = 8; // the PRNG is delayed by 8 cycles due to the NAC (4Bits = 0x05 encrypted) transfer + if (nt_diff == 0) { par_low = par[0] & 0xE0; // there is no need to check all parities for other nt_diff. Parity Bits for mf_nr_ar[0..2] won't change } @@ -2404,7 +2418,7 @@ void ReaderMifare(bool first_try) if (nt_diff == 0 && first_try) { par[0]++; - if (par[0] == 0x00) { // tried all 256 possible parities without success. Card doesn't send NACK. + if (par[0] == 0x00) { // tried all 256 possible parities without success. Card doesn't send NACK. isOK = -2; break; } @@ -2420,13 +2434,13 @@ void ReaderMifare(bool first_try) if (isOK == -4) { if (MF_DBGLEVEL >= 3) { for (uint16_t i = 0; i <= MAX_STRATEGY; i++) { - for(uint16_t j = 0; j < NUM_DEBUG_INFOS; j++) { + for (uint16_t j = 0; j < NUM_DEBUG_INFOS; j++) { Dbprintf("collected debug info[%d][%d] = %d", i, j, debug_info[i][j]); } } } } - + FpgaDisableTracing(); uint8_t buf[32]; @@ -2435,7 +2449,7 @@ void ReaderMifare(bool first_try) memcpy(buf + 8, par_list, 8); memcpy(buf + 16, ks_list, 8); memcpy(buf + 24, mf_nr_ar, 8); - + cmd_send(CMD_ACK, isOK, 0, 0, buf, 32); // Thats it... @@ -2447,8 +2461,8 @@ void ReaderMifare(bool first_try) //----------------------------------------------------------------------------- -// MIFARE sniffer. -// +// MIFARE sniffer. +// //----------------------------------------------------------------------------- void RAMFUNC SniffMifare(uint8_t param) { // param: @@ -2458,7 +2472,7 @@ void RAMFUNC SniffMifare(uint8_t param) { // C(red) A(yellow) B(green) LEDsoff(); LED_A_ON(); - + // init trace buffer clear_trace(); set_tracing(true); @@ -2498,19 +2512,19 @@ void RAMFUNC SniffMifare(uint8_t param) { MfSniffInit(); // And now we loop, receiving samples. - for(uint32_t sniffCounter = 0; true; ) { - + for (uint32_t sniffCounter = 0; true; ) { + if(BUTTON_PRESS()) { DbpString("Canceled by button."); break; } WDT_HIT(); - - if ((sniffCounter & 0x0000FFFF) == 0) { // from time to time + + if ((sniffCounter & 0x0000FFFF) == 0) { // from time to time // check if a transaction is completed (timeout after 2000ms). // if yes, stop the DMA transfer and send what we have so far to the client - if (MfSniffSend(2000)) { + if (MfSniffSend(2000)) { // Reset everything - we missed some sniffed data anyway while the DMA was stopped sniffCounter = 0; data = dmaBuf; @@ -2520,17 +2534,17 @@ void RAMFUNC SniffMifare(uint8_t param) { FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); // set transfer address and number of bytes. Start transfer. } } - - int register readBufDataP = data - dmaBuf; // number of bytes we have processed so far + + int register readBufDataP = data - dmaBuf; // number of bytes we have processed so far int register dmaBufDataP = DMA_BUFFER_SIZE - AT91C_BASE_PDC_SSC->PDC_RCR; // number of bytes already transferred - if (readBufDataP <= dmaBufDataP){ // we are processing the same block of data which is currently being transferred - dataLen = dmaBufDataP - readBufDataP; // number of bytes still to be processed - } else { + if (readBufDataP <= dmaBufDataP){ // we are processing the same block of data which is currently being transferred + dataLen = dmaBufDataP - readBufDataP; // number of bytes still to be processed + } else { dataLen = DMA_BUFFER_SIZE - readBufDataP + dmaBufDataP; // number of bytes still to be processed } // test for length of buffer - if(dataLen > maxDataLen) { // we are more behind than ever... - maxDataLen = dataLen; + if(dataLen > maxDataLen) { // we are more behind than ever... + maxDataLen = dataLen; if(dataLen > (9 * DMA_BUFFER_SIZE / 10)) { Dbprintf("blew circular buffer! dataLen=0x%x", dataLen); break; @@ -2552,7 +2566,7 @@ void RAMFUNC SniffMifare(uint8_t param) { if (sniffCounter & 0x01) { - if(!TagIsActive) { // no need to try decoding tag data if the reader is sending + if(!TagIsActive) { // no need to try decoding tag data if the reader is sending uint8_t readerdata = (previous_data & 0xF0) | (*data >> 4); if(MillerDecoding(readerdata, (sniffCounter-1)*4)) { @@ -2560,14 +2574,14 @@ void RAMFUNC SniffMifare(uint8_t param) { /* And ready to receive another command. */ UartInit(receivedCmd, receivedCmdPar); - + /* And also reset the demod code */ DemodReset(); } ReaderIsActive = (Uart.state != STATE_UNSYNCD); } - - if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending + + if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending uint8_t tagdata = (previous_data << 4) | (*data & 0x0F); if(ManchesterDecoding(tagdata, 0, (sniffCounter-1)*4)) { @@ -2598,6 +2612,6 @@ void RAMFUNC SniffMifare(uint8_t param) { DbpString("COMMAND FINISHED."); MfSniffEnd(); - + Dbprintf("maxDataLen=%x, Uart.state=%x, Uart.len=%x", maxDataLen, Uart.state, Uart.len); } diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 6954a29b..df2dcbea 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -41,7 +41,6 @@ extern void ReaderMifare(bool first_try); extern int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity); extern int EmSendCmd(uint8_t *resp, uint16_t respLen); -extern int EmSendCmdEx(uint8_t *resp, uint16_t respLen); extern int EmSend4bit(uint8_t resp); extern int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par); extern int EmSendPrecompiledCmd(tag_response_info_t *response_info); diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c index c9264836..6f97e1b4 100644 --- a/armsrc/mifaresim.c +++ b/armsrc/mifaresim.c @@ -25,26 +25,24 @@ #include "apps.h" //mifare emulator states -#define MFEMUL_NOFIELD 0 -#define MFEMUL_IDLE 1 -#define MFEMUL_SELECT1 2 -#define MFEMUL_SELECT2 3 -#define MFEMUL_SELECT3 4 -#define MFEMUL_AUTH1 5 -#define MFEMUL_AUTH2 6 -#define MFEMUL_WORK 7 -#define MFEMUL_WRITEBL2 8 -#define MFEMUL_INTREG_INC 9 -#define MFEMUL_INTREG_DEC 10 -#define MFEMUL_INTREG_REST 11 -#define MFEMUL_HALTED 12 - -#define cardSTATE_TO_IDLE() { cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF(); } +#define MFEMUL_NOFIELD 0 +#define MFEMUL_IDLE 1 +#define MFEMUL_SELECT1 2 +#define MFEMUL_SELECT2 3 +#define MFEMUL_SELECT3 4 +#define MFEMUL_AUTH1 5 +#define MFEMUL_AUTH2 6 +#define MFEMUL_WORK 7 +#define MFEMUL_WRITEBL2 8 +#define MFEMUL_INTREG_INC 9 +#define MFEMUL_INTREG_DEC 10 +#define MFEMUL_INTREG_REST 11 +#define MFEMUL_HALTED 12 #define AC_DATA_READ 0 #define AC_DATA_WRITE 1 -#define AC_DATA_INC 2 -#define AC_DATA_DEC_TRANS_REST 3 +#define AC_DATA_INC 2 +#define AC_DATA_DEC_TRANS_REST 3 #define AC_KEYA_READ 0 #define AC_KEYA_WRITE 1 #define AC_KEYB_READ 2 @@ -57,11 +55,30 @@ #define AUTHKEYNONE 0xff +static int ParamCardSizeBlocks(const char c) { + int numBlocks = 16 * 4; + switch (c) { + case '0' : numBlocks = 5 * 4; break; + case '2' : numBlocks = 32 * 4; break; + case '4' : numBlocks = 32 * 4 + 8 * 16; break; + default: numBlocks = 16 * 4; + } + return numBlocks; +} + +static uint8_t BlockToSector(int block_num) { + if (block_num < 32 * 4) { // 4 blocks per sector + return (block_num / 4); + } else { // 16 blocks per sector + return 32 + (block_num - 32 * 4) / 16; + } +} + static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) { uint8_t sector_trailer[16]; emlGetMem(sector_trailer, blockNo, 1); uint8_t AC = ((sector_trailer[7] >> 5) & 0x04) - | ((sector_trailer[8] >> 2) & 0x02) + | ((sector_trailer[8] >> 2) & 0x02) | ((sector_trailer[8] >> 7) & 0x01); switch (action) { case AC_KEYA_READ: { @@ -69,8 +86,8 @@ static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t act break; } case AC_KEYA_WRITE: { - return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x01)) - || (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03))); + return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x01)) + || (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03))); break; } case AC_KEYB_READ: { @@ -79,17 +96,17 @@ static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t act } case AC_KEYB_WRITE: { return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x04)) - || (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03))); + || (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03))); break; } case AC_AC_READ: { return ((keytype == AUTHKEYA) - || (keytype == AUTHKEYB && !(AC == 0x00 || AC == 0x02 || AC == 0x01))); + || (keytype == AUTHKEYB && !(AC == 0x00 || AC == 0x02 || AC == 0x01))); break; } case AC_AC_WRITE: { return ((keytype == AUTHKEYA && (AC == 0x01)) - || (keytype == AUTHKEYB && (AC == 0x03 || AC == 0x05))); + || (keytype == AUTHKEYB && (AC == 0x03 || AC == 0x05))); break; } default: return false; @@ -129,33 +146,33 @@ static bool IsDataAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action | ((sector_trailer[8] >> 6) & 0x01); break; } - default: + default: return false; } - + switch (action) { case AC_DATA_READ: { return ((keytype == AUTHKEYA && !(AC == 0x03 || AC == 0x05 || AC == 0x07)) - || (keytype == AUTHKEYB && !(AC == 0x07))); + || (keytype == AUTHKEYB && !(AC == 0x07))); break; } case AC_DATA_WRITE: { return ((keytype == AUTHKEYA && (AC == 0x00)) - || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x04 || AC == 0x06 || AC == 0x03))); + || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x04 || AC == 0x06 || AC == 0x03))); break; } case AC_DATA_INC: { return ((keytype == AUTHKEYA && (AC == 0x00)) - || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06))); + || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06))); break; } case AC_DATA_DEC_TRANS_REST: { return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x06 || AC == 0x01)) - || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06 || AC == 0x01))); + || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06 || AC == 0x01))); break; } } - + return false; } @@ -169,18 +186,18 @@ static bool IsAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) { } -static void MifareSimInit(uint8_t flags, uint8_t *datain, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len) { +static void MifareSimInit(uint8_t flags, uint8_t *datain, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len, uint8_t cardsize) { - #define TAG_RESPONSE_COUNT 5 // number of precompiled responses - static uint8_t rATQA[] = {0x04, 0x00}; // indicate Mifare classic 1k 4Byte UID - 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 rSAKfinal[]= {0x08, 0xb6, 0xdd}; // mifare 1k indicated - static uint8_t rSAK1[] = {0x04, 0xda, 0x17}; // indicate UID not finished + #define TAG_RESPONSE_COUNT 5 // number of precompiled responses + static uint8_t rATQA[] = {0x00, 0x00}; + 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 rSAKfinal[]= {0x00, 0x00, 0x00}; // SAK after UID complete + static uint8_t rSAK1[] = {0x00, 0x00, 0x00}; // indicate UID not finished *uid_len = 4; // UID can be set from emulator memory or incoming data and can be 4 or 7 bytes long - if (flags & FLAG_4B_UID_IN_DATA) { // get UID from datain + if (flags & FLAG_4B_UID_IN_DATA) { // get UID from datain memcpy(rUIDBCC1, datain, 4); } else if (flags & FLAG_7B_UID_IN_DATA) { rUIDBCC1[0] = 0x88; @@ -189,10 +206,10 @@ static void MifareSimInit(uint8_t flags, uint8_t *datain, tag_response_info_t ** *uid_len = 7; } else { uint8_t probable_atqa; - emlGetMemBt(&probable_atqa, 7, 1); // get UID from emul memory - weak guess at length - if (probable_atqa == 0x00) { // ---------- 4BUID + emlGetMemBt(&probable_atqa, 7, 1); // get UID from emul memory - weak guess at length + if (probable_atqa == 0x00) { // ---------- 4BUID emlGetMemBt(rUIDBCC1, 0, 4); - } else { // ---------- 7BUID + } else { // ---------- 7BUID rUIDBCC1[0] = 0x88; emlGetMemBt(rUIDBCC1+1, 0, 3); emlGetMemBt(rUIDBCC2, 3, 4); @@ -204,37 +221,65 @@ static void MifareSimInit(uint8_t flags, uint8_t *datain, tag_response_info_t ** case 4: *cuid = bytes_to_num(rUIDBCC1, 4); rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; - if (MF_DBGLEVEL >= 2) { - Dbprintf("4B UID: %02x%02x%02x%02x", - rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3] ); + if (MF_DBGLEVEL >= MF_DBG_INFO) { + Dbprintf("4B UID: %02x%02x%02x%02x", + rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3] ); } break; case 7: - rATQA[0] |= 0x40; *cuid = bytes_to_num(rUIDBCC2, 4); - rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; - rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; - if (MF_DBGLEVEL >= 2) { + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; + if (MF_DBGLEVEL >= MF_DBG_INFO) { Dbprintf("7B UID: %02x %02x %02x %02x %02x %02x %02x", rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3], rUIDBCC2[0], rUIDBCC2[1], rUIDBCC2[2], rUIDBCC2[3] ); } break; - default: + default: break; } - + + // set SAK based on cardsize + switch (cardsize) { + case '0': rSAKfinal[0] = 0x09; break; // Mifare Mini + case '2': rSAKfinal[0] = 0x10; break; // Mifare 2K + case '4': rSAKfinal[0] = 0x18; break; // Mifare 4K + default: rSAKfinal[0] = 0x08; // Mifare 1K + } + ComputeCrc14443(CRC_14443_A, rSAKfinal, 1, rSAKfinal + 1, rSAKfinal + 2); + if (MF_DBGLEVEL >= MF_DBG_INFO) { + Dbprintf("SAK: %02x", rSAKfinal[0]); + } + + // set SAK for incomplete UID + rSAK1[0] = 0x04; // Bit 3 indicates incomplete UID + ComputeCrc14443(CRC_14443_A, rSAK1, 1, rSAK1 + 1, rSAK1 + 2); + + // set ATQA based on cardsize and UIDlen + if (cardsize == '4') { + rATQA[0] = 0x02; + } else { + rATQA[0] = 0x04; + } + if (*uid_len == 7) { + rATQA[0] |= 0x40; + } + if (MF_DBGLEVEL >= MF_DBG_INFO) { + Dbprintf("ATQA: %02x %02x", rATQA[1], rATQA[0]); + } + static tag_response_info_t responses_init[TAG_RESPONSE_COUNT] = { - { .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 = rSAKfinal, .response_n = sizeof(rSAKfinal) }, // Acknowledge select - last cascade - { .response = rSAK1, .response_n = sizeof(rSAK1) } // Acknowledge select - previous cascades + { .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 = rSAKfinal, .response_n = sizeof(rSAKfinal) }, // Acknowledge select - last cascade + { .response = rSAK1, .response_n = sizeof(rSAK1) } // Acknowledge select - previous cascades }; // 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 are 7 predefined responses with a total of 18 bytes data to transmit. Coded responses need one byte per bit to transfer (data, parity, start, stop, correction) + // There are 5 predefined responses with a total of 18 bytes data to transmit. Coded responses need one byte per bit to transfer (data, parity, start, stop, correction) // 18 * 8 data bits, 18 * 1 parity bits, 5 start bits, 5 stop bits, 5 correction bits -> need 177 bytes buffer - #define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 177 // number of bytes required for precompiled responses + #define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 177 // number of bytes required for precompiled responses uint8_t *free_buffer_pointer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE); size_t free_buffer_size = ALLOCATED_TAG_MODULATION_BUFFER_SIZE; @@ -262,22 +307,23 @@ static bool HasValidCRC(uint8_t *receivedCmd, uint16_t receivedCmd_len) { /** - *MIFARE 1K simulate. + *MIFARE simulate. * *@param flags : - * FLAG_INTERACTIVE - In interactive mode, we are expected to finish the operation with an ACK + * FLAG_INTERACTIVE - In interactive mode, we are expected to finish the operation with an ACK * FLAG_4B_UID_IN_DATA - means that there is a 4-byte UID in the data-section, we're expected to use that * FLAG_7B_UID_IN_DATA - means that there is a 7-byte UID in the data-section, we're expected to use that - * FLAG_10B_UID_IN_DATA - use 10-byte UID in the data-section not finished - * FLAG_NR_AR_ATTACK - means we should collect NR_AR responses for bruteforcing later + * FLAG_NR_AR_ATTACK - means we should collect NR_AR responses for bruteforcing later * FLAG_RANDOM_NONCE - means we should generate some pseudo-random nonce data (only allows moebius attack) *@param exitAfterNReads, exit simulation after n blocks have been read, 0 is infinite ... * (unless reader attack mode enabled then it runs util it gets enough nonces to recover all keys attmpted) */ -void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *datain) +void MifareSim(uint8_t flags, uint8_t exitAfterNReads, uint8_t cardsize, uint8_t *datain) { + LED_A_ON(); + tag_response_info_t *responses; - uint8_t uid_len = 4; + uint8_t uid_len = 4; uint32_t cuid = 0; uint8_t cardWRBL = 0; uint8_t cardAUTHSC = 0; @@ -288,48 +334,47 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * uint32_t cardINTREG = 0; uint8_t cardINTBLOCK = 0; struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - uint32_t numReads = 0;//Counts numer of times reader reads a block + struct Crypto1State *pcs = &mpcs; + uint32_t numReads = 0; //Counts numer of times reader reads a block uint8_t receivedCmd[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedCmd_dec[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedCmd_par[MAX_MIFARE_PARITY_SIZE]; uint16_t receivedCmd_len; uint8_t response[MAX_MIFARE_FRAME_SIZE]; uint8_t response_par[MAX_MIFARE_PARITY_SIZE]; - - uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04}; - uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00}; - - //Here, we collect UID,sector,keytype,NT,AR,NR,NT2,AR2,NR2 + uint8_t fixed_nonce[] = {0x01, 0x02, 0x03, 0x04}; + + int num_blocks = ParamCardSizeBlocks(cardsize); + + // Here we collect UID, sector, keytype, NT, AR, NR, NT2, AR2, NR2 // This will be used in the reader-only attack. - //allow collecting up to 7 sets of nonces to allow recovery of up to 7 keys + // allow collecting up to 7 sets of nonces to allow recovery of up to 7 keys #define ATTACK_KEY_COUNT 7 // keep same as define in cmdhfmf.c -> readerAttack() (Cannot be more than 7) - nonces_t ar_nr_resp[ATTACK_KEY_COUNT*2]; //*2 for 2 separate attack types (nml, moebius) 36 * 7 * 2 bytes = 504 bytes + nonces_t ar_nr_resp[ATTACK_KEY_COUNT*2]; // *2 for 2 separate attack types (nml, moebius) 36 * 7 * 2 bytes = 504 bytes memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp)); - uint8_t ar_nr_collected[ATTACK_KEY_COUNT*2]; //*2 for 2nd attack type (moebius) + uint8_t ar_nr_collected[ATTACK_KEY_COUNT*2]; // *2 for 2nd attack type (moebius) memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected)); - uint8_t nonce1_count = 0; - uint8_t nonce2_count = 0; - uint8_t moebius_n_count = 0; + uint8_t nonce1_count = 0; + uint8_t nonce2_count = 0; + uint8_t moebius_n_count = 0; bool gettingMoebius = false; - uint8_t mM = 0; //moebius_modifier for collection storage + uint8_t mM = 0; // moebius_modifier for collection storage // Authenticate response - nonce uint32_t nonce; if (flags & FLAG_RANDOM_NONCE) { nonce = prand(); } else { - nonce = bytes_to_num(rAUTH_NT, 4); + nonce = bytes_to_num(fixed_nonce, 4); } // free eventually allocated BigBuf memory but keep Emulator Memory BigBuf_free_keep_EM(); - MifareSimInit(flags, datain, &responses, &cuid, &uid_len); - + MifareSimInit(flags, datain, &responses, &cuid, &uid_len, cardsize); + // We need to listen to the high-frequency, peak-detected path. iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); @@ -337,7 +382,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * clear_trace(); set_tracing(true); ResetSspClk(); - + bool finished = false; bool button_pushed = BUTTON_PRESS(); int cardSTATE = MFEMUL_NOFIELD; @@ -345,25 +390,28 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * while (!button_pushed && !finished && !usb_poll_validate_length()) { WDT_HIT(); - // find reader field if (cardSTATE == MFEMUL_NOFIELD) { + // wait for reader HF field int vHf = (MAX_ADC_HF_VOLTAGE_LOW * AvgAdc(ADC_CHAN_HF_LOW)) >> 10; if (vHf > MF_MINFIELDV) { - LED_A_ON(); - cardSTATE_TO_IDLE(); + LED_D_ON(); + cardSTATE = MFEMUL_IDLE; } button_pushed = BUTTON_PRESS(); continue; } //Now, get data + FpgaEnableTracing(); int res = EmGetCmd(receivedCmd, &receivedCmd_len, receivedCmd_par); - - if (res == 2) { //Field is off! - LEDsoff(); + + if (res == 2) { // Reader has dropped the HF field. Power off. + FpgaDisableTracing(); + LED_D_OFF(); cardSTATE = MFEMUL_NOFIELD; continue; } else if (res == 1) { // button pressed + FpgaDisableTracing(); button_pushed = true; break; } @@ -371,6 +419,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * // WUPA in HALTED state or REQA or WUPA in any other state if (receivedCmd_len == 1 && ((receivedCmd[0] == ISO14443A_CMD_REQA && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == ISO14443A_CMD_WUPA)) { EmSendPrecompiledCmd(&responses[ATQA]); + FpgaDisableTracing(); // init crypto block crypto1_destroy(pcs); @@ -378,66 +427,68 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * if (flags & FLAG_RANDOM_NONCE) { nonce = prand(); } - LED_B_OFF(); - LED_C_OFF(); cardSTATE = MFEMUL_SELECT1; continue; } - + switch (cardSTATE) { case MFEMUL_NOFIELD: case MFEMUL_HALTED: case MFEMUL_IDLE:{ break; } + case MFEMUL_SELECT1:{ // select all - 0x93 0x20 if (receivedCmd_len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && receivedCmd[1] == 0x20)) { - if (MF_DBGLEVEL >= 4) Dbprintf("SELECT ALL CL1 received"); EmSendPrecompiledCmd(&responses[UIDBCC1]); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT ALL CL1 received"); break; } // select card - 0x93 0x70 ... 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 >= 4) Dbprintf("SELECT CL1 %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]); if (uid_len == 4) { EmSendPrecompiledCmd(&responses[SAKfinal]); - LED_B_ON(); cardSTATE = MFEMUL_WORK; - break; } else if (uid_len == 7) { EmSendPrecompiledCmd(&responses[SAK1]); - cardSTATE = MFEMUL_SELECT2; - break; + cardSTATE = MFEMUL_SELECT2; } + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT CL1 %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]); + break; } - cardSTATE_TO_IDLE(); + cardSTATE = MFEMUL_IDLE; break; } + case MFEMUL_SELECT2:{ // select all cl2 - 0x95 0x20 if (receivedCmd_len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && receivedCmd[1] == 0x20)) { - if (MF_DBGLEVEL >= 4) Dbprintf("SELECT ALL CL2 received"); EmSendPrecompiledCmd(&responses[UIDBCC2]); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT ALL CL2 received"); break; } // select cl2 card - 0x95 0x70 xxxxxxxxxxxx - if (receivedCmd_len == 9 && + if (receivedCmd_len == 9 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], responses[UIDBCC2].response, 4) == 0)) { if (uid_len == 7) { - if (MF_DBGLEVEL >= 4) Dbprintf("SELECT CL2 %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]); EmSendPrecompiledCmd(&responses[SAKfinal]); - LED_B_ON(); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT CL2 %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]); cardSTATE = MFEMUL_WORK; break; } } - cardSTATE_TO_IDLE(); + cardSTATE = MFEMUL_IDLE; break; } + case MFEMUL_WORK:{ - if (receivedCmd_len != 4) { // all commands must have exactly 4 bytes + if (receivedCmd_len != 4) { // all commands must have exactly 4 bytes break; } bool encrypted_data = (cardAUTHKEY != AUTHKEYNONE) ; @@ -448,76 +499,92 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * memcpy(receivedCmd_dec, receivedCmd, receivedCmd_len); } if (!HasValidCRC(receivedCmd_dec, receivedCmd_len)) { // all commands must have a valid CRC - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_TR)); break; } + if (receivedCmd_dec[0] == MIFARE_AUTH_KEYA || receivedCmd_dec[0] == MIFARE_AUTH_KEYB) { // if authenticating to a block that shouldn't exist - as long as we are not doing the reader attack - if (receivedCmd_dec[1] >= 16 * 4 && !(flags & FLAG_NR_AR_ATTACK)) { + if (receivedCmd_dec[1] >= num_blocks && !(flags & FLAG_NR_AR_ATTACK)) { //is this the correct response to an auth on a out of range block? marshmellow EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],receivedCmd_dec[1]); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking", receivedCmd_dec[0], receivedCmd_dec[1], receivedCmd_dec[1]); break; } - cardAUTHSC = receivedCmd_dec[1] / 4; // received block num + cardAUTHSC = BlockToSector(receivedCmd_dec[1]); // received block num cardAUTHKEY = receivedCmd_dec[0] & 0x01; crypto1_destroy(pcs);//Added by martin crypto1_create(pcs, emlGetKey(cardAUTHSC, cardAUTHKEY)); if (!encrypted_data) { // first authentication - if (MF_DBGLEVEL >= 4) Dbprintf("Reader authenticating for block %d (0x%02x) with key %d",receivedCmd_dec[1], receivedCmd_dec[1], cardAUTHKEY); - crypto1_word(pcs, cuid ^ nonce, 0);//Update crypto state - num_to_bytes(nonce, 4, rAUTH_AT); // Send nonce + crypto1_word(pcs, cuid ^ nonce, 0); // Update crypto state + num_to_bytes(nonce, 4, response); // Send unencrypted nonce + EmSendCmd(response, sizeof(nonce)); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader authenticating for block %d (0x%02x) with key %d", receivedCmd_dec[1], receivedCmd_dec[1], cardAUTHKEY); } else { // nested authentication - if (MF_DBGLEVEL >= 4) Dbprintf("Reader doing nested authentication for block %d (0x%02x) with key %d", receivedCmd_dec[1], receivedCmd_dec[1], cardAUTHKEY); - ans = nonce ^ crypto1_word(pcs, cuid ^ nonce, 0); - num_to_bytes(ans, 4, rAUTH_AT); + num_to_bytes(nonce, sizeof(nonce), response); + uint8_t pcs_in[4] = {0}; + num_to_bytes(cuid ^ nonce, sizeof(nonce), pcs_in); + mf_crypto1_encryptEx(pcs, response, pcs_in, sizeof(nonce), response_par); + EmSendCmdPar(response, sizeof(nonce), response_par); // send encrypted nonce + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader doing nested authentication for block %d (0x%02x) with key %d", receivedCmd_dec[1], receivedCmd_dec[1], cardAUTHKEY); } - EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT)); cardSTATE = MFEMUL_AUTH1; break; } - if (!encrypted_data) { // all other commands must be encrypted (authenticated) + + // halt can be sent encrypted or in clear + if (receivedCmd_dec[0] == ISO14443A_CMD_HALT && receivedCmd_dec[1] == 0x00) { + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("--> HALTED."); + cardSTATE = MFEMUL_HALTED; break; } + if(receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK || receivedCmd_dec[0] == ISO14443A_CMD_WRITEBLOCK || receivedCmd_dec[0] == MIFARE_CMD_INC || receivedCmd_dec[0] == MIFARE_CMD_DEC || receivedCmd_dec[0] == MIFARE_CMD_RESTORE || receivedCmd_dec[0] == MIFARE_CMD_TRANSFER) { - if (receivedCmd_dec[1] >= 16 * 4) { + if (receivedCmd_dec[1] >= num_blocks) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],receivedCmd_dec[1]); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],receivedCmd_dec[1]); break; } - if (receivedCmd_dec[1] / 4 != cardAUTHSC) { + if (BlockToSector(receivedCmd_dec[1]) != cardAUTHSC) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],cardAUTHSC); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],cardAUTHSC); break; } } + if (receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK) { uint8_t blockNo = receivedCmd_dec[1]; - if (MF_DBGLEVEL >= 4) { - Dbprintf("Reader reading block %d (0x%02x)", blockNo, blockNo); - } emlGetMem(response, blockNo, 1); if (IsSectorTrailer(blockNo)) { - memset(response, 0x00, 6); // keyA can never be read + memset(response, 0x00, 6); // keyA can never be read if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_KEYB_READ)) { - memset(response+10, 0x00, 6); // keyB cannot be read + memset(response+10, 0x00, 6); // keyB cannot be read } if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_AC_READ)) { - memset(response+6, 0x00, 4); // AC bits cannot be read + memset(response+6, 0x00, 4); // AC bits cannot be read } } else { if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_DATA_READ)) { - memset(response, 0x00, 16); // datablock cannot be read + memset(response, 0x00, 16); // datablock cannot be read } } AppendCrc14443a(response, 16); mf_crypto1_encrypt(pcs, response, 18, response_par); EmSendCmdPar(response, 18, response_par); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { + Dbprintf("Reader reading block %d (0x%02x)", blockNo, blockNo); + } numReads++; if(exitAfterNReads > 0 && numReads == exitAfterNReads) { Dbprintf("%d reads done, exiting", numReads); @@ -525,23 +592,33 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } break; } + if (receivedCmd_dec[0] == ISO14443A_CMD_WRITEBLOCK) { uint8_t blockNo = receivedCmd_dec[1]; - if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0xA0 write block %d (%02x)", blockNo, blockNo); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("RECV 0xA0 write block %d (%02x)", blockNo, blockNo); cardWRBL = blockNo; cardSTATE = MFEMUL_WRITEBL2; break; } + if (receivedCmd_dec[0] == MIFARE_CMD_INC || receivedCmd_dec[0] == MIFARE_CMD_DEC || receivedCmd_dec[0] == MIFARE_CMD_RESTORE) { uint8_t blockNo = receivedCmd_dec[1]; - if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo); if (emlCheckValBl(blockNo)) { - if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate on block, but emlCheckValBl failed, nacking"); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { + Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo); + } + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader tried to operate on block, but emlCheckValBl failed, nacking"); break; } EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { + Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo); + } cardWRBL = blockNo; if (receivedCmd_dec[0] == MIFARE_CMD_INC) cardSTATE = MFEMUL_INTREG_INC; @@ -551,31 +628,29 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * cardSTATE = MFEMUL_INTREG_REST; break; } + if (receivedCmd_dec[0] == MIFARE_CMD_TRANSFER) { uint8_t blockNo = receivedCmd_dec[1]; - if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0x%02x transfer block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo); if (emlSetValBl(cardINTREG, cardINTBLOCK, receivedCmd_dec[1])) EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); else EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("RECV 0x%02x transfer block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo); break; } - // halt - if (receivedCmd_dec[0] == ISO14443A_CMD_HALT && receivedCmd_dec[1] == 0x00) { - if (MF_DBGLEVEL >= 4) Dbprintf("--> HALTED."); - LED_B_OFF(); - LED_C_OFF(); - cardSTATE = MFEMUL_HALTED; - break; - } + // command not allowed - if (MF_DBGLEVEL >= 4) Dbprintf("Received command not allowed, nacking"); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Received command not allowed, nacking"); + cardSTATE = MFEMUL_IDLE; break; } + case MFEMUL_AUTH1:{ if (receivedCmd_len != 8) { - cardSTATE_TO_IDLE(); + cardSTATE = MFEMUL_IDLE; break; } @@ -590,7 +665,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * if (ar_nr_collected[i+mM] < 2) { // if we haven't already collected 2 nonces for this sector if (ar_nr_resp[ar_nr_collected[i+mM]].ar != ar) { - // Avoid duplicates... probably not necessary, ar should vary. + // Avoid duplicates... probably not necessary, ar should vary. if (ar_nr_collected[i+mM]==0) { // first nonce collect ar_nr_resp[i+mM].cuid = cuid; @@ -618,7 +693,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * if ( nonce2_count == nonce1_count ) { // done collecting std test switch to moebius // first finish incrementing last sample - ar_nr_collected[i+mM]++; + ar_nr_collected[i+mM]++; // switch to moebius collection gettingMoebius = true; mM = ATTACK_KEY_COUNT; @@ -650,25 +725,28 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * // test if auth OK if (cardRr != prng_successor(nonce, 64)){ - if (MF_DBGLEVEL >= 2) Dbprintf("AUTH FAILED for sector %d with key %c. cardRr=%08x, succ=%08x", + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("AUTH FAILED for sector %d with key %c. cardRr=%08x, succ=%08x", cardAUTHSC, cardAUTHKEY == AUTHKEYA ? 'A' : 'B', cardRr, prng_successor(nonce, 64)); // Shouldn't we respond anything here? // Right now, we don't nack or anything, which causes the // reader to do a WUPA after a while. /Martin // -- which is the correct response. /piwi - cardAUTHKEY = AUTHKEYNONE; // not authenticated - cardSTATE_TO_IDLE(); + cardAUTHKEY = AUTHKEYNONE; // not authenticated + cardSTATE = MFEMUL_IDLE; break; } - ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0); - num_to_bytes(ans, 4, rAUTH_AT); - EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT)); - if (MF_DBGLEVEL >= 4) Dbprintf("AUTH COMPLETED for sector %d with key %c.", cardAUTHSC, cardAUTHKEY == AUTHKEYA ? 'A' : 'B'); - LED_C_ON(); + ans = prng_successor(nonce, 96); + num_to_bytes(ans, 4, response); + mf_crypto1_encrypt(pcs, response, 4, response_par); + EmSendCmdPar(response, 4, response_par); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("AUTH COMPLETED for sector %d with key %c.", cardAUTHSC, cardAUTHKEY == AUTHKEYA ? 'A' : 'B'); cardSTATE = MFEMUL_WORK; break; } + case MFEMUL_WRITEBL2:{ if (receivedCmd_len == 18) { mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, receivedCmd_dec); @@ -676,73 +754,80 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * if (IsSectorTrailer(cardWRBL)) { emlGetMem(response, cardWRBL, 1); if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_KEYA_WRITE)) { - memcpy(receivedCmd_dec, response, 6); // don't change KeyA + memcpy(receivedCmd_dec, response, 6); // don't change KeyA } if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_KEYB_WRITE)) { - memcpy(receivedCmd_dec+10, response+10, 6); // don't change KeyA + memcpy(receivedCmd_dec+10, response+10, 6); // don't change KeyA } if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_AC_WRITE)) { - memcpy(receivedCmd_dec+6, response+6, 4); // don't change AC bits + memcpy(receivedCmd_dec+6, response+6, 4); // don't change AC bits } } else { if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_DATA_WRITE)) { - memcpy(receivedCmd_dec, response, 16); // don't change anything + memcpy(receivedCmd_dec, response, 16); // don't change anything } } emlSetMem(receivedCmd_dec, cardWRBL, 1); - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); // always ACK? + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); // always ACK? cardSTATE = MFEMUL_WORK; break; } } - cardSTATE_TO_IDLE(); + cardSTATE = MFEMUL_IDLE; break; } + case MFEMUL_INTREG_INC:{ if (receivedCmd_len == 6) { mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t*)&ans); if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - cardSTATE_TO_IDLE(); + cardSTATE = MFEMUL_IDLE; break; } cardINTREG = cardINTREG + ans; + cardSTATE = MFEMUL_WORK; } - cardSTATE = MFEMUL_WORK; break; } + case MFEMUL_INTREG_DEC:{ if (receivedCmd_len == 6) { mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t*)&ans); if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - cardSTATE_TO_IDLE(); + cardSTATE = MFEMUL_IDLE; break; } + cardINTREG = cardINTREG - ans; + cardSTATE = MFEMUL_WORK; } - cardINTREG = cardINTREG - ans; - cardSTATE = MFEMUL_WORK; break; } + case MFEMUL_INTREG_REST:{ mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t*)&ans); if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - cardSTATE_TO_IDLE(); + cardSTATE = MFEMUL_IDLE; break; } cardSTATE = MFEMUL_WORK; break; } - } + + } // end of switch + + FpgaDisableTracing(); button_pushed = BUTTON_PRESS(); - } + + } // end of while FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - if(flags & FLAG_NR_AR_ATTACK && MF_DBGLEVEL >= 1) { - for ( uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { + if(flags & FLAG_NR_AR_ATTACK && MF_DBGLEVEL >= MF_DBG_INFO) { + for ( uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { if (ar_nr_collected[i] == 2) { Dbprintf("Collected two pairs of AR/NR which can be used to extract %s from reader for sector %d:", (i= 1) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", get_tracing(), BigBuf_get_traceLen()); + if (MF_DBGLEVEL >= MF_DBG_INFO) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", get_tracing(), BigBuf_get_traceLen()); if(flags & FLAG_INTERACTIVE) { // Interactive mode flag, means we need to send ACK //Send the collected ar_nr in the response - cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,button_pushed,0,&ar_nr_resp,sizeof(ar_nr_resp)); + cmd_send(CMD_ACK, CMD_SIMULATE_MIFARE_CARD, button_pushed, 0, &ar_nr_resp, sizeof(ar_nr_resp)); } + + LED_A_OFF(); } diff --git a/armsrc/mifaresim.h b/armsrc/mifaresim.h index 1e17a882..8f089b85 100644 --- a/armsrc/mifaresim.h +++ b/armsrc/mifaresim.h @@ -15,6 +15,6 @@ #include -extern void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *datain); +extern void MifareSim(uint8_t flags, uint8_t exitAfterNReads, uint8_t cardsize, uint8_t *datain); #endif diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index ab04aee4..36e29721 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -23,13 +23,13 @@ #include "crapto1/crapto1.h" #include "mbedtls/des.h" -int MF_DBGLEVEL = MF_DBG_ALL; +int MF_DBGLEVEL = MF_DBG_INFO; // crypto1 helpers void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, uint8_t *data_out){ - uint8_t bt = 0; + uint8_t bt = 0; int i; - + if (len != 1) { for (i = 0; i < len; i++) data_out[i] = crypto1_byte(pcs, 0x00, 0) ^ data_in[i]; @@ -37,7 +37,7 @@ void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, u bt = 0; for (i = 0; i < 4; i++) bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data_in[0], i)) << i; - + data_out[0] = bt; } return; @@ -47,28 +47,32 @@ void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len){ mf_crypto1_decryptEx(pcs, data, len, data); } -void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par) { +void mf_crypto1_encryptEx(struct Crypto1State *pcs, uint8_t *data, uint8_t *in, uint16_t len, uint8_t *par) { uint8_t bt = 0; int i; par[0] = 0; - + for (i = 0; i < len; i++) { bt = data[i]; - data[i] = crypto1_byte(pcs, 0x00, 0) ^ data[i]; - if((i&0x0007) == 0) + data[i] = crypto1_byte(pcs, in==NULL?0x00:in[i], 0) ^ data[i]; + if((i&0x0007) == 0) par[i>>3] = 0; par[i>>3] |= (((filter(pcs->odd) ^ oddparity8(bt)) & 0x01)<<(7-(i&0x0007))); - } + } return; } +void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par) { + mf_crypto1_encryptEx(pcs, data, NULL, len, par); +} + uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data) { uint8_t bt = 0; int i; for (i = 0; i < 4; i++) bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data, i)) << i; - + return bt; } @@ -94,20 +98,20 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, { uint8_t dcmd[4], ecmd[4]; uint16_t pos, res; - uint8_t par[1]; // 1 Byte parity is enough here + uint8_t par[1]; // 1 Byte parity is enough here dcmd[0] = cmd; dcmd[1] = data; AppendCrc14443a(dcmd, 2); - + memcpy(ecmd, dcmd, sizeof(dcmd)); - + if (crypted) { par[0] = 0; for (pos = 0; pos < 4; pos++) { ecmd[pos] = crypto1_byte(pcs, 0x00, 0) ^ dcmd[pos]; par[0] |= (((filter(pcs->odd) ^ oddparity8(dcmd[pos])) & 0x01) << (7-pos)); - } + } ReaderTransmitPar(ecmd, sizeof(ecmd), par, timing); @@ -116,17 +120,17 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, } int len = ReaderReceive(answer, par); - + if (answer_parity) *answer_parity = par[0]; - + if (crypted == CRYPT_ALL) { if (len == 1) { res = 0; for (pos = 0; pos < 4; pos++) res |= (crypto1_bit(pcs, 0, 0) ^ BIT(answer[0], pos)) << pos; - + answer[0] = res; - + } else { for (pos = 0; pos < len; pos++) { @@ -134,41 +138,41 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, } } } - + return len; } // mifare classic commands -int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested) +int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested) { return mifare_classic_authex(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL); } -int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing) +int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing) { // variables - int len; + int len; uint32_t pos; uint8_t tmp4[4]; uint8_t par[1] = {0x00}; byte_t nr[4]; uint32_t nt, ntpp; // Supplied tag nonce - + uint8_t mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + // Transmit MIFARE_CLASSIC_AUTH len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer, receivedAnswerPar, timing); - if (MF_DBGLEVEL >= 4) Dbprintf("rand tag nonce len: %x", len); + if (MF_DBGLEVEL >= 4) Dbprintf("rand tag nonce len: %x", len); if (len != 4) return 1; - + // "random" reader nonce: nr[0] = 0x55; nr[1] = 0x41; nr[2] = 0x49; - nr[3] = 0x92; - + nr[3] = 0x92; + // Save the tag nonce (nt) nt = bytes_to_num(receivedAnswer, 4); @@ -180,7 +184,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN crypto1_create(pcs, ui64Key); if (isNested == AUTH_NESTED) { - // decrypt nt with help of new key + // decrypt nt with help of new key nt = crypto1_word(pcs, nt ^ uid, 1) ^ nt; } else { // Load (plain) uid^nt into the cipher @@ -189,8 +193,8 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN // some statistic if (!ntptr && (MF_DBGLEVEL >= 3)) - Dbprintf("auth uid: %08x nt: %08x", uid, nt); - + Dbprintf("auth uid: %08x nt: %08x", uid, nt); + // save Nt if (ntptr) *ntptr = nt; @@ -201,8 +205,8 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN { mf_nr_ar[pos] = crypto1_byte(pcs, nr[pos], 0) ^ nr[pos]; par[0] |= (((filter(pcs->odd) ^ oddparity8(nr[pos])) & 0x01) << (7-pos)); - } - + } + // Skip 32 bits in pseudo random generator nt = prng_successor(nt,32); @@ -212,8 +216,8 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN nt = prng_successor(nt,8); mf_nr_ar[pos] = crypto1_byte(pcs,0x00,0) ^ (nt & 0xff); par[0] |= (((filter(pcs->odd) ^ oddparity8(nt)) & 0x01) << (7-pos)); - } - + } + // Transmit reader nonce and reader answer ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par, NULL); @@ -221,48 +225,48 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN len = ReaderReceive(receivedAnswer, receivedAnswerPar); if (!len) { - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); return 2; } - + memcpy(tmp4, receivedAnswer, 4); ntpp = prng_successor(nt, 32) ^ crypto1_word(pcs, 0,0); - + if (ntpp != bytes_to_num(tmp4, 4)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Error card response."); + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Error card response."); return 3; } return 0; } -int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) +int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) { // variables - int len; - uint8_t bt[2]; - + int len; + uint8_t bt[2]; + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + // command MIFARE_CLASSIC_READBLOCK len = mifare_sendcmd_short(pcs, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL); if (len == 1) { - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); return 1; } if (len != 18) { - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: card timeout. len: %x", len); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: card timeout. len: %x", len); return 2; } memcpy(bt, receivedAnswer + 16, 2); AppendCrc14443a(receivedAnswer, 16); if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) { - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd CRC response error."); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd CRC response error."); return 3; } - + memcpy(blockData, receivedAnswer, 16); return 0; } @@ -277,7 +281,7 @@ int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack){ memcpy(key, keybytes, 4); if (MF_DBGLEVEL >= MF_DBG_EXTENDED) - Dbprintf("EV1 Auth : %02x%02x%02x%02x", key[0], key[1], key[2], key[3]); + Dbprintf("EV1 Auth : %02x%02x%02x%02x", key[0], key[1], key[2], key[3]); len = mifare_sendcmd(0x1B, key, sizeof(key), resp, respPar, NULL); //len = mifare_sendcmd_short_mfuev1auth(NULL, 0, 0x1B, key, resp, respPar, NULL); if (len != 4) { @@ -322,12 +326,12 @@ int mifare_ultra_auth(uint8_t *keybytes){ // decrypt nonce. // tdes_2key_dec(random_b, enc_random_b, sizeof(random_b), key, IV ); mbedtls_des3_set2key_dec(&ctx, key); - mbedtls_des3_crypt_cbc(&ctx // des3_context - , MBEDTLS_DES_DECRYPT // int mode - , sizeof(random_b) // length - , IV // iv[8] - , enc_random_b // input - , random_b // output + mbedtls_des3_crypt_cbc(&ctx // des3_context + , MBEDTLS_DES_DECRYPT // int mode + , sizeof(random_b) // length + , IV // iv[8] + , enc_random_b // input + , random_b // output ); rol(random_b,8); @@ -351,12 +355,12 @@ int mifare_ultra_auth(uint8_t *keybytes){ // encrypt out, in, length, key, iv //tdes_2key_enc(rnd_ab, rnd_ab, sizeof(rnd_ab), key, enc_random_b); mbedtls_des3_set2key_enc(&ctx, key); - mbedtls_des3_crypt_cbc(&ctx // des3_context - , MBEDTLS_DES_ENCRYPT // int mode - , sizeof(rnd_ab) // length - , enc_random_b // iv[8] - , rnd_ab // input - , rnd_ab // output + mbedtls_des3_crypt_cbc(&ctx // des3_context + , MBEDTLS_DES_ENCRYPT // int mode + , sizeof(rnd_ab) // length + , enc_random_b // iv[8] + , rnd_ab // input + , rnd_ab // output ); //len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, rnd_ab, resp, respPar, NULL); @@ -370,15 +374,15 @@ int mifare_ultra_auth(uint8_t *keybytes){ uint8_t resp_random_a[8] = { 0,0,0,0,0,0,0,0 }; memcpy(enc_resp, resp+1, 8); - // decrypt out, in, length, key, iv + // decrypt out, in, length, key, iv // tdes_2key_dec(resp_random_a, enc_resp, 8, key, enc_random_b); mbedtls_des3_set2key_dec(&ctx, key); - mbedtls_des3_crypt_cbc(&ctx // des3_context - , MBEDTLS_DES_DECRYPT // int mode - , 8 // length - , enc_random_b // iv[8] - , enc_resp // input - , resp_random_a // output + mbedtls_des3_crypt_cbc(&ctx // des3_context + , MBEDTLS_DES_DECRYPT // int mode + , 8 // length + , enc_random_b // iv[8] + , enc_resp // input + , resp_random_a // output ); if ( memcmp(resp_random_a, random_a, 8) != 0 ) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("failed authentication"); @@ -386,7 +390,7 @@ int mifare_ultra_auth(uint8_t *keybytes){ } if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { - Dbprintf("e_AB: %02x %02x %02x %02x %02x %02x %02x %02x", + Dbprintf("e_AB: %02x %02x %02x %02x %02x %02x %02x %02x", rnd_ab[0],rnd_ab[1],rnd_ab[2],rnd_ab[3], rnd_ab[4],rnd_ab[5],rnd_ab[6],rnd_ab[7]); @@ -410,7 +414,7 @@ int mifare_ultra_auth(uint8_t *keybytes){ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) { uint16_t len; - uint8_t bt[2]; + uint8_t bt[2]; uint8_t receivedAnswer[MAX_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; uint8_t retries; @@ -451,55 +455,55 @@ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) return 0; } -int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) +int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) { // variables - uint16_t len, i; + uint16_t len, i; uint32_t pos; - uint8_t par[3] = {0}; // enough for 18 Bytes to send + uint8_t par[3] = {0}; // enough for 18 Bytes to send byte_t res; - + uint8_t d_block[18], d_block_enc[18]; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + // command MIFARE_CLASSIC_WRITEBLOCK len = mifare_sendcmd_short(pcs, 1, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL); if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); return 1; } - + memcpy(d_block, blockData, 16); AppendCrc14443a(d_block, 16); - + // crypto for (pos = 0; pos < 18; pos++) { d_block_enc[pos] = crypto1_byte(pcs, 0x00, 0) ^ d_block[pos]; par[pos>>3] |= (((filter(pcs->odd) ^ oddparity8(d_block[pos])) & 0x01) << (7 - (pos&0x0007))); - } + } ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL); // Receive the response - len = ReaderReceive(receivedAnswer, receivedAnswerPar); + len = ReaderReceive(receivedAnswer, receivedAnswerPar); res = 0; for (i = 0; i < 4; i++) res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], i)) << i; if ((len != 1) || (res != 0x0A)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd send data2 Error: %02x", res); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd send data2 Error: %02x", res); return 2; } - + return 0; } /* // command not needed, but left for future testing -int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) +int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) { uint16_t len; uint8_t par[3] = {0}; // enough for 18 parity bits @@ -553,16 +557,16 @@ int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) return 0; } -int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) +int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) { - uint16_t len; + uint16_t len; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; len = mifare_sendcmd_short(pcs, pcs == NULL ? false:true, 0x50, 0x00, receivedAnswer, receivedAnswerPar, NULL); if (len != 0) { if (MF_DBGLEVEL >= MF_DBG_ERROR) - Dbprintf("halt error. response len: %x", len); + Dbprintf("halt error. response len: %x", len); return 1; } @@ -574,7 +578,7 @@ int mifare_ultra_halt() uint16_t len; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + len = mifare_sendcmd_short(NULL, true, 0x50, 0x00, receivedAnswer, receivedAnswerPar, NULL); if (len != 0) { if (MF_DBGLEVEL >= MF_DBG_ERROR) @@ -587,21 +591,21 @@ int mifare_ultra_halt() // Mifare Memory Structure: up to 32 Sectors with 4 blocks each (1k and 2k cards), // plus evtl. 8 sectors with 16 blocks each (4k cards) -uint8_t NumBlocksPerSector(uint8_t sectorNo) +uint8_t NumBlocksPerSector(uint8_t sectorNo) { - if (sectorNo < 32) + if (sectorNo < 32) return 4; else return 16; } -uint8_t FirstBlockOfSector(uint8_t sectorNo) +uint8_t FirstBlockOfSector(uint8_t sectorNo) { if (sectorNo < 32) return sectorNo * 4; else return 32*4 + (sectorNo - 32) * 16; - + } uint8_t SectorTrailer(uint8_t blockNo) @@ -644,7 +648,7 @@ int emlCheckValBl(int blockNum) { (data[3] != (data[7] ^ 0xff)) || (data[3] != data[11]) || (data[12] != (data[13] ^ 0xff)) || (data[12] != data[14]) || (data[12] != (data[15] ^ 0xff)) - ) + ) return 1; return 0; } @@ -652,11 +656,11 @@ int emlCheckValBl(int blockNum) { int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum) { uint8_t* emCARD = BigBuf_get_EM_addr(); uint8_t* data = emCARD + blockNum * 16; - + if (emlCheckValBl(blockNum)) { return 1; } - + memcpy(blReg, data, 4); *blBlock = data[12]; return 0; @@ -665,41 +669,41 @@ int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum) { int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum) { uint8_t* emCARD = BigBuf_get_EM_addr(); uint8_t* data = emCARD + blockNum * 16; - + memcpy(data + 0, &blReg, 4); memcpy(data + 8, &blReg, 4); blReg = blReg ^ 0xffffffff; memcpy(data + 4, &blReg, 4); - + data[12] = blBlock; data[13] = blBlock ^ 0xff; data[14] = blBlock; data[15] = blBlock ^ 0xff; - + return 0; } uint64_t emlGetKey(int sectorNum, int keyType) { uint8_t key[6]; uint8_t* emCARD = BigBuf_get_EM_addr(); - + memcpy(key, emCARD + 16 * (FirstBlockOfSector(sectorNum) + NumBlocksPerSector(sectorNum) - 1) + keyType * 10, 6); return bytes_to_num(key, 6); } void emlClearMem(void) { int b; - + const uint8_t trailer[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x80, 0x69, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; const uint8_t uid[] = {0xe6, 0x84, 0x87, 0xf3, 0x16, 0x88, 0x04, 0x00, 0x46, 0x8e, 0x45, 0x55, 0x4d, 0x70, 0x41, 0x04}; uint8_t* emCARD = BigBuf_get_EM_addr(); - + memset(emCARD, 0, CARD_MEMORY_SIZE); - + // fill sectors trailer data for(b = 3; b < 256; b<127?(b+=4):(b+=16)) { emlSetMem((uint8_t *)trailer, b , 1); - } + } // uid emlSetMem((uint8_t *)uid, 0, 1); @@ -710,35 +714,35 @@ void emlClearMem(void) { // Mifare desfire commands int mifare_sendcmd_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing) { - uint8_t dcmd[5] = {0x00}; - dcmd[0] = cmd; - memcpy(dcmd+1,data,2); + uint8_t dcmd[5] = {0x00}; + dcmd[0] = cmd; + memcpy(dcmd+1,data,2); AppendCrc14443a(dcmd, 3); - + ReaderTransmit(dcmd, sizeof(dcmd), NULL); int len = ReaderReceive(answer, answer_parity); if(!len) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) + if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Authentication failed. Card timeout."); return 1; - } + } return len; } int mifare_sendcmd_special2(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer,uint8_t *answer_parity, uint32_t *timing) { - uint8_t dcmd[20] = {0x00}; - dcmd[0] = cmd; - memcpy(dcmd+1,data,17); + uint8_t dcmd[20] = {0x00}; + dcmd[0] = cmd; + memcpy(dcmd+1,data,17); AppendCrc14443a(dcmd, 18); ReaderTransmit(dcmd, sizeof(dcmd), NULL); int len = ReaderReceive(answer, answer_parity); if(!len){ - if (MF_DBGLEVEL >= MF_DBG_ERROR) + if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Authentication failed. Card timeout."); return 1; - } + } return len; } @@ -749,23 +753,23 @@ int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData){ uint8_t data[2]={0x0a, 0x00}; uint8_t receivedAnswer[MAX_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; - + len = mifare_sendcmd_special(NULL, 1, 0x02, data, receivedAnswer,receivedAnswerPar,NULL); if (len == 1) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); return 1; } - + if (len == 12) { - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { Dbprintf("Auth1 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", receivedAnswer[0],receivedAnswer[1],receivedAnswer[2],receivedAnswer[3],receivedAnswer[4], receivedAnswer[5],receivedAnswer[6],receivedAnswer[7],receivedAnswer[8],receivedAnswer[9], receivedAnswer[10],receivedAnswer[11]); } memcpy(blockData, receivedAnswer, 12); - return 0; + return 0; } return 1; } @@ -776,18 +780,18 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){ uint8_t data[17] = {0x00}; data[0] = 0xAF; memcpy(data+1,key,16); - + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + len = mifare_sendcmd_special2(NULL, 1, 0x03, data, receivedAnswer, receivedAnswerPar ,NULL); - + if ((receivedAnswer[0] == 0x03) && (receivedAnswer[1] == 0xae)) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Auth Error: %02x %02x", receivedAnswer[0], receivedAnswer[1]); return 1; } - + if (len == 12){ if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { Dbprintf("Auth2 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", @@ -816,7 +820,7 @@ int MifareChkBlockKey(uint8_t *uid, uint32_t *cuid, uint8_t *cascade_levels, uin if (*cascade_levels == 0) { // 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 (debugLevel >= 1) Dbprintf("ChkKeys: Can't select card"); + if (debugLevel >= 1) Dbprintf("ChkKeys: Can't select card"); return 1; } switch (card_info.uidlen) { @@ -827,26 +831,26 @@ int MifareChkBlockKey(uint8_t *uid, uint32_t *cuid, uint8_t *cascade_levels, uin } } else { // no need for anticollision. We can directly select the card if(!iso14443a_select_card(uid, NULL, NULL, false, *cascade_levels, true)) { - if (debugLevel >= 1) Dbprintf("ChkKeys: Can't select card (UID) lvl=%d", *cascade_levels); + if (debugLevel >= 1) Dbprintf("ChkKeys: Can't select card (UID) lvl=%d", *cascade_levels); return 1; } } - + if(mifare_classic_auth(pcs, *cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { -// SpinDelayUs(AUTHENTICATION_TIMEOUT); // it not needs because mifare_classic_auth have timeout from iso14a_set_timeout() +// SpinDelayUs(AUTHENTICATION_TIMEOUT); // it not needs because mifare_classic_auth have timeout from iso14a_set_timeout() return 2; } else { -/* // let it be here. it like halt command, but maybe it will work in some strange cases +/* // let it be here. it like halt command, but maybe it will work in some strange cases uint8_t dummy_answer = 0; ReaderTransmit(&dummy_answer, 1, NULL); - int timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT; + int timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT; // wait for the card to become ready again while(GetCountSspClk() < timeout) {}; */ // it needs after success authentication mifare_classic_halt(pcs, *cuid); } - + return 0; } @@ -861,14 +865,14 @@ int MifareChkBlockKeys(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t for (uint8_t i = 0; i < keyCount; i++) { // Allow button press / usb cmd to interrupt device - if (BUTTON_PRESS() && !usb_poll_validate_length()) { + if (BUTTON_PRESS() && !usb_poll_validate_length()) { Dbprintf("ChkKeys: Cancel operation. Exit..."); return -2; } ui64Key = bytes_to_num(keys + i * 6, 6); int res = MifareChkBlockKey(uid, &cuid, &cascade_levels, ui64Key, blockNo, keyType, debugLevel); - + // can't select if (res == 1) { retryCount++; @@ -879,10 +883,10 @@ int MifareChkBlockKeys(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t --i; // try the same key once again SpinDelay(20); -// Dbprintf("ChkKeys: block=%d key=%d. Try the same key once again...", blockNo, keyType); +// Dbprintf("ChkKeys: block=%d key=%d. Try the same key once again...", blockNo, keyType); continue; } - + // can't authenticate if (res == 2) { retryCount = 0; @@ -891,15 +895,15 @@ int MifareChkBlockKeys(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t return i + 1; } - + return 0; } // multisector multikey check int MifareMultisectorChk(uint8_t *keys, uint8_t keyCount, uint8_t SectorCount, uint8_t keyType, uint8_t debugLevel, TKeyIndex *keyIndex) { int res = 0; - -// int clk = GetCountSspClk(); + +// int clk = GetCountSspClk(); for(int sc = 0; sc < SectorCount; sc++){ WDT_HIT(); @@ -915,9 +919,9 @@ int MifareMultisectorChk(uint8_t *keys, uint8_t keyCount, uint8_t SectorCount, u } } while(--keyAB > 0); } - -// Dbprintf("%d %d", GetCountSspClk() - clk, (GetCountSspClk() - clk)/(SectorCount*keyCount*(keyType==2?2:1))); - + +// Dbprintf("%d %d", GetCountSspClk() - clk, (GetCountSspClk() - clk)/(SectorCount*keyCount*(keyType==2?2:1))); + return 0; } diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index b2912895..589f780b 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -34,11 +34,11 @@ #define MF_MINFIELDV 4000 // debug -// 0 - no debug messages 1 - error messages 2 - all messages 4 - extended debug mode -#define MF_DBG_NONE 0 -#define MF_DBG_ERROR 1 -#define MF_DBG_ALL 2 -#define MF_DBG_EXTENDED 4 +#define MF_DBG_NONE 0 // no messages +#define MF_DBG_ERROR 1 // errors only +#define MF_DBG_INFO 2 // errors + info messages +#define MF_DBG_DEBUG 3 // errors + info + debug messages +#define MF_DBG_EXTENDED 4 // errors + info + debug + breaking debug messages extern int MF_DBGLEVEL; @@ -71,6 +71,7 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData); void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *receivedCmd, int len); void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, uint8_t *data_out); void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par); +void mf_crypto1_encryptEx(struct Crypto1State *pcs, uint8_t *data, uint8_t *in, uint16_t len, uint8_t *par); uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data); // Mifare memory structure diff --git a/client/cmdhflist.c b/client/cmdhflist.c index 1aa501e6..4499cd0d 100644 --- a/client/cmdhflist.c +++ b/client/cmdhflist.c @@ -937,7 +937,6 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui char line[16][110]; for (int j = 0; j < data_len && j/16 < 16; j++) { - uint8_t parityBits = parityBytes[j>>3]; if (protocol != ISO_14443B && protocol != ISO_15693 @@ -948,7 +947,6 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui } else { snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x ", frame[j]); } - } if (markCRCBytes) { @@ -961,6 +959,13 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui } } + // mark short bytes (less than 8 Bit + Parity) + if (protocol == ISO_14443A || protocol == PROTO_MIFARE) { + if (duration < 128 * (9 * data_len)) { + line[(data_len-1)/16][((data_len-1)%16) * 4 + 3] = '\''; + } + } + if (data_len == 0) { sprintf(line[0]," "); } @@ -990,7 +995,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui int num_lines = MIN((data_len - 1)/16 + 1, 16); for (int j = 0; j < num_lines ; j++) { if (j == 0) { - PrintAndLog(" %10d | %10d | %s |%-64s | %s| %s", + PrintAndLog(" %10" PRIu32 " | %10" PRIu32 " | %s |%-64s | %s| %s", (timestamp - first_timestamp), (EndOfTransmissionTimestamp - first_timestamp), (isResponse ? "Tag" : "Rdr"), @@ -1004,7 +1009,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui (j == num_lines-1) ? explanation : ""); } } - + if (DecodeMifareData(frame, data_len, parityBytes, isResponse, mfData, &mfDataLen)) { memset(explanation, 0x00, sizeof(explanation)); if (!isResponse) { @@ -1222,7 +1227,7 @@ int CmdHFList(const char *Cmd) PrintAndLog("iso14443a - All times are in carrier periods (1/13.56Mhz)"); PrintAndLog("iClass - Timings are not as accurate"); PrintAndLog(""); - PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation |"); + PrintAndLog(" Start | End | Src | Data (! denotes parity error, ' denotes short bytes) | CRC | Annotation |"); PrintAndLog("------------|------------|-----|-----------------------------------------------------------------|-----|--------------------|"); ClearAuthData(); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 1c006fbf..903e8575 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -254,14 +254,14 @@ uint8_t NumBlocksPerSector(uint8_t sectorNo) } static int ParamCardSizeSectors(const char c) { - int numBlocks = 16; + int numSectors = 16; switch (c) { - case '0' : numBlocks = 5; break; - case '2' : numBlocks = 32; break; - case '4' : numBlocks = 40; break; - default: numBlocks = 16; + case '0' : numSectors = 5; break; + case '2' : numSectors = 32; break; + case '4' : numSectors = 40; break; + default: numSectors = 16; } - return numBlocks; + return numSectors; } static int ParamCardSizeBlocks(const char c) { @@ -1421,11 +1421,12 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack }*/ } -int usage_hf14_mf1ksim(void) { - PrintAndLog("Usage: hf mf sim h u n i x"); +int usage_hf14_mfsim(void) { + PrintAndLog("Usage: hf mf sim [h] [*] [u ] [n ] [i] [x]"); PrintAndLog("options:"); - PrintAndLog(" h this help"); - PrintAndLog(" u (Optional) UID 4,7 or 10 bytes. If not specified, the UID 4B from emulator memory will be used"); + PrintAndLog(" h (Optional) this help"); + PrintAndLog(" card memory: 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); + PrintAndLog(" u (Optional) UID 4 or 7 bytes. If not specified, the UID 4B from emulator memory will be used"); PrintAndLog(" n (Optional) Automatically exit simulation after blocks have been read by reader. 0 = infinite"); PrintAndLog(" i (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted"); PrintAndLog(" x (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)"); @@ -1434,21 +1435,20 @@ int usage_hf14_mf1ksim(void) { PrintAndLog(" r (Optional) Generate random nonces instead of sequential nonces. Standard reader attack won't work with this option, only moebius attack works."); PrintAndLog("samples:"); PrintAndLog(" hf mf sim u 0a0a0a0a"); + PrintAndLog(" hf mf sim *4"); PrintAndLog(" hf mf sim u 11223344556677"); - PrintAndLog(" hf mf sim u 112233445566778899AA"); PrintAndLog(" hf mf sim f uids.txt"); PrintAndLog(" hf mf sim u 0a0a0a0a e"); return 0; } -int CmdHF14AMf1kSim(const char *Cmd) { +int CmdHF14AMfSim(const char *Cmd) { UsbCommand resp; - uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t uid[7] = {0}; uint8_t exitAfterNReads = 0; uint8_t flags = 0; int uidlen = 0; - uint8_t pnr = 0; bool setEmulatorMem = false; bool attackFromFile = false; FILE *f; @@ -1459,9 +1459,21 @@ int CmdHF14AMf1kSim(const char *Cmd) { uint8_t cmdp = 0; bool errors = false; + uint8_t cardsize = '1'; while(param_getchar(Cmd, cmdp) != 0x00) { switch(param_getchar(Cmd, cmdp)) { + case '*': + cardsize = param_getchar(Cmd + 1, cmdp); + switch(cardsize) { + case '0': + case '1': + case '2': + case '4': break; + default: cardsize = '1'; + } + cmdp++; + break; case 'e': case 'E': setEmulatorMem = true; @@ -1485,7 +1497,7 @@ int CmdHF14AMf1kSim(const char *Cmd) { break; case 'h': case 'H': - return usage_hf14_mf1ksim(); + return usage_hf14_mfsim(); case 'i': case 'I': flags |= FLAG_INTERACTIVE; @@ -1493,7 +1505,7 @@ int CmdHF14AMf1kSim(const char *Cmd) { break; case 'n': case 'N': - exitAfterNReads = param_get8(Cmd, pnr+1); + exitAfterNReads = param_get8(Cmd, cmdp+1); cmdp += 2; break; case 'r': @@ -1505,10 +1517,9 @@ int CmdHF14AMf1kSim(const char *Cmd) { case 'U': param_gethex_ex(Cmd, cmdp+1, uid, &uidlen); switch(uidlen) { - case 20: flags = FLAG_10B_UID_IN_DATA; break; //not complete case 14: flags = FLAG_7B_UID_IN_DATA; break; case 8: flags = FLAG_4B_UID_IN_DATA; break; - default: return usage_hf14_mf1ksim(); + default: return usage_hf14_mfsim(); } cmdp += 2; break; @@ -1525,7 +1536,7 @@ int CmdHF14AMf1kSim(const char *Cmd) { if(errors) break; } //Validations - if(errors) return usage_hf14_mf1ksim(); + if(errors) return usage_hf14_mfsim(); //get uid from file if (attackFromFile) { @@ -1552,7 +1563,6 @@ int CmdHF14AMf1kSim(const char *Cmd) { uidlen = strlen(buf)-1; switch(uidlen) { - case 20: flags |= FLAG_10B_UID_IN_DATA; break; //not complete case 14: flags |= FLAG_7B_UID_IN_DATA; break; case 8: flags |= FLAG_4B_UID_IN_DATA; break; default: @@ -1565,18 +1575,22 @@ int CmdHF14AMf1kSim(const char *Cmd) { sscanf(&buf[i], "%02x", (unsigned int *)&uid[i / 2]); } - PrintAndLog("mf 1k sim uid: %s, numreads:%d, flags:%d (0x%02x) - press button to abort", - flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): - flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): - flags & FLAG_10B_UID_IN_DATA ? sprint_hex(uid,10): "N/A" - , exitAfterNReads, flags, flags); + PrintAndLog("mf sim cardsize: %s, uid: %s, numreads:%d, flags:%d (0x%02x) - press button to abort", + cardsize == '0' ? "Mini" : + cardsize == '2' ? "2K" : + cardsize == '4' ? "4K" : "1K", + flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): + flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A", + exitAfterNReads, + flags, + flags); - UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}}; + UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads, cardsize}}; memcpy(c.d.asBytes, uid, sizeof(uid)); clearCommandBuffer(); SendCommand(&c); - while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + while (! WaitForResponseTimeout(CMD_ACK,&resp,1500)) { //We're waiting only 1.5 s at a time, otherwise we get the // annoying message about "Waiting for a response... " } @@ -1593,22 +1607,27 @@ int CmdHF14AMf1kSim(const char *Cmd) { count++; } fclose(f); - } else { //not from file - PrintAndLog("mf 1k sim uid: %s, numreads:%d, flags:%d (0x%02x) ", - flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): - flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): - flags & FLAG_10B_UID_IN_DATA ? sprint_hex(uid,10): "N/A" - , exitAfterNReads, flags, flags); + } else { //not from file - UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}}; + PrintAndLog("mf sim cardsize: %s, uid: %s, numreads:%d, flags:%d (0x%02x) ", + cardsize == '0' ? "Mini" : + cardsize == '2' ? "2K" : + cardsize == '4' ? "4K" : "1K", + flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): + flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A", + exitAfterNReads, + flags, + flags); + + UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads, cardsize}}; memcpy(c.d.asBytes, uid, sizeof(uid)); clearCommandBuffer(); SendCommand(&c); if(flags & FLAG_INTERACTIVE) { PrintAndLog("Press pm3-button to abort simulation"); - while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + while(! WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { //We're waiting only 1.5 s at a time, otherwise we get the // annoying message about "Waiting for a response... " } @@ -1745,7 +1764,7 @@ int CmdHF14AMfELoad(const char *Cmd) } } - len = param_getstr(Cmd,nameParamNo,filename,sizeof(filename)); + len = param_getstr(Cmd, nameParamNo, filename, sizeof(filename)); if (len > FILE_PATH_SIZE - 5) len = FILE_PATH_SIZE - 5; @@ -2925,8 +2944,8 @@ static command_t CommandTable[] = {"hardnested", CmdHF14AMfNestedHard, 0, "Nested attack for hardened Mifare cards"}, {"nested", CmdHF14AMfNested, 0, "Test nested authentication"}, {"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"}, - {"sim", CmdHF14AMf1kSim, 0, "Simulate MIFARE card"}, - {"eclr", CmdHF14AMfEClear, 0, "Clear simulator memory block"}, + {"sim", CmdHF14AMfSim, 0, "Simulate MIFARE card"}, + {"eclr", CmdHF14AMfEClear, 0, "Clear simulator memory"}, {"eget", CmdHF14AMfEGet, 0, "Get simulator memory block"}, {"eset", CmdHF14AMfESet, 0, "Set simulator memory block"}, {"eload", CmdHF14AMfELoad, 0, "Load from file emul dump"}, diff --git a/include/usb_cmd.h b/include/usb_cmd.h index ef282256..9ef929b9 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -226,12 +226,11 @@ typedef struct{ //Mifare simulation flags -#define FLAG_INTERACTIVE 0x01 -#define FLAG_4B_UID_IN_DATA 0x02 -#define FLAG_7B_UID_IN_DATA 0x04 -#define FLAG_10B_UID_IN_DATA 0x08 -#define FLAG_NR_AR_ATTACK 0x10 -#define FLAG_RANDOM_NONCE 0x20 +#define FLAG_INTERACTIVE (1<<0) +#define FLAG_4B_UID_IN_DATA (1<<1) +#define FLAG_7B_UID_IN_DATA (1<<2) +#define FLAG_NR_AR_ATTACK (1<<4) +#define FLAG_RANDOM_NONCE (1<<5) //Iclass reader flags -- 2.39.5 From 131c44883c8ecc92910c09cff450b43b8c6b986c Mon Sep 17 00:00:00 2001 From: Fl0-0 Date: Fri, 19 Apr 2019 13:14:41 +0200 Subject: [PATCH 06/16] Fix typo lf config usage --- client/cmdlf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cmdlf.c b/client/cmdlf.c index c09a299c..12d30663 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -227,7 +227,7 @@ int usage_lf_config(void) PrintAndLog(" h This help"); PrintAndLog(" L Low frequency (125 KHz)"); PrintAndLog(" H High frequency (134 KHz)"); - PrintAndLog(" q Manually set divisor. 88-> 134KHz, 95-> 125 Hz"); + PrintAndLog(" q Manually set divisor. 88-> 134 KHz, 95-> 125 KHz"); PrintAndLog(" b Sets resolution of bits per sample. Default (max): 8"); PrintAndLog(" d Sets decimation. A value of N saves only 1 in N samples. Default: 1"); PrintAndLog(" a [0|1] Averaging - if set, will average the stored sample value when decimating. Default: 1"); -- 2.39.5 From 9ebbfd898ca6ce4f9e32b64aca3f3972a3a74e2c Mon Sep 17 00:00:00 2001 From: Iceman Date: Mon, 22 Apr 2019 18:25:52 +0200 Subject: [PATCH 07/16] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 09f23a6b..2f7007e2 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,10 @@ following locations: * [RyscCorp](https://proxmark3.com/) (US) * [Hackerwarehouse](https://hackerwarehouse.com/) (US) * [Elechouse](http://www.elechouse.com/) (HK) -* [Lab401](https://lab401.com/) (FR) +* [Lab401](https://lab401.com/) (HK) * [RFxSecure](http://www.rfxsecure.com/) (SG) -* [IceSQL](http://proxmark3.tictail.com/) (SE) +* [Sneaktechnology](https://www.sneaktechnology.com/) (ASIA/OCEANIA) + Most of the ultra-low-volume contract assemblers could put something like this together with a reasonable yield. A run of around -- 2.39.5 From a39af1cb9cab6298fcf01d7243e9f48db0f45f26 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 22 May 2019 19:02:58 +0200 Subject: [PATCH 08/16] Add: new option 'd' in 'hf mf ekeyprn' to create dumpkeys.bin from emulator memory (#822) (and whitespace fixes) --- client/cmdhfmf.c | 636 +++++++++++++++++++++++++---------------------- 1 file changed, 334 insertions(+), 302 deletions(-) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 903e8575..9284d14c 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -34,7 +34,7 @@ #include "mifare/ndef.h" #include "emv/dump.h" -#define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up +#define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up static int CmdHelp(const char *Cmd); @@ -65,7 +65,7 @@ int CmdHF14AMfWrBl(const char *Cmd) uint8_t key[6] = {0, 0, 0, 0, 0, 0}; uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - char cmdp = 0x00; + char cmdp = 0x00; if (strlen(Cmd)<3) { PrintAndLog("Usage: hf mf wrbl "); @@ -113,7 +113,7 @@ int CmdHF14AMfRdBl(const char *Cmd) uint8_t keyType = 0; uint8_t key[6] = {0, 0, 0, 0, 0, 0}; - char cmdp = 0x00; + char cmdp = 0x00; if (strlen(Cmd)<3) { @@ -177,7 +177,7 @@ int CmdHF14AMfRdSc(const char *Cmd) uint8_t key[6] = {0, 0, 0, 0, 0, 0}; uint8_t isOK = 0; uint8_t *data = NULL; - char cmdp = 0x00; + char cmdp = 0x00; if (strlen(Cmd)<3) { PrintAndLog("Usage: hf mf rdsc "); @@ -218,15 +218,15 @@ int CmdHF14AMfRdSc(const char *Cmd) PrintAndLog("data : %s", sprint_hex(data + i * 16, 16)); } PrintAndLog("trailer: %s", sprint_hex(data + (sectorNo<32?3:15) * 16, 16)); - + PrintAndLogEx(NORMAL, "Trailer decoded:"); - int bln = mfFirstBlockOfSector(sectorNo); - int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1; - for (i = 0; i < 4; i++) { - PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &(data + (sectorNo<32?3:15) * 16)[6])); - bln += blinc; - } - PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&(data + (sectorNo<32?3:15) * 16)[9], 1)); + int bln = mfFirstBlockOfSector(sectorNo); + int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1; + for (i = 0; i < 4; i++) { + PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &(data + (sectorNo<32?3:15) * 16)[6])); + bln += blinc; + } + PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&(data + (sectorNo<32?3:15) * 16)[9], 1)); } } else { PrintAndLog("Command execute timeout"); @@ -324,7 +324,7 @@ int CmdHF14AMfDump(const char *Cmd) fclose(fin); return 2; } - } + } } fclose(fin); @@ -371,7 +371,7 @@ int CmdHF14AMfDump(const char *Cmd) for (blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) { bool received = false; for (tries = 0; tries < 3; tries++) { - if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. At least the Access Conditions can always be read with key A. + if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. At least the Access Conditions can always be read with key A. UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 0, 0}}; memcpy(c.d.asBytes, keys[0][sectorNo], 6); SendCommand(&c); @@ -387,14 +387,14 @@ int CmdHF14AMfDump(const char *Cmd) // Don't try the other one on success. if (resp.arg[0] & 0xff) break; } - } else { // data block. Check if it can be read with key A or key B + } else { // data block. Check if it can be read with key A or key B uint8_t data_area = sectorNo<32?blockNo:blockNo/5; - if ((rights[sectorNo][data_area] == 0x03) || (rights[sectorNo][data_area] == 0x05)) { // only key B would work + if ((rights[sectorNo][data_area] == 0x03) || (rights[sectorNo][data_area] == 0x05)) { // only key B would work UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 1, 0}}; memcpy(c.d.asBytes, keys[1][sectorNo], 6); SendCommand(&c); received = WaitForResponseTimeout(CMD_ACK,&resp,1500); - } else if (rights[sectorNo][data_area] == 0x07) { // no key would work + } else if (rights[sectorNo][data_area] == 0x07) { // no key would work PrintAndLog("Access rights do not allow reading of sector %2d block %3d", sectorNo, blockNo); if (nullMissingKeys) { memset(resp.d.asBytes, 0, 16); @@ -405,7 +405,7 @@ int CmdHF14AMfDump(const char *Cmd) isOK = false; tries = 2; } - } else { // key A would work + } else { // key A would work UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 0, 0}}; memcpy(c.d.asBytes, keys[0][sectorNo], 6); SendCommand(&c); @@ -421,13 +421,13 @@ int CmdHF14AMfDump(const char *Cmd) if (received) { isOK = resp.arg[0] & 0xff; uint8_t *data = resp.d.asBytes; - if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. Fill in the keys. + if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. Fill in the keys. memcpy(data, keys[0][sectorNo], 6); memcpy(data + 10, keys[1][sectorNo], 6); } if (isOK) { memcpy(carddata[FirstBlockOfSector(sectorNo) + blockNo], data, 16); - PrintAndLog("Successfully read block %2d of sector %2d.", blockNo, sectorNo); + PrintAndLog("Successfully read block %2d of sector %2d.", blockNo, sectorNo); } else { PrintAndLog("Could not read block %2d of sector %2d", blockNo, sectorNo); break; @@ -530,7 +530,7 @@ int CmdHF14AMfRestore(const char *Cmd) return 2; } - if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer + if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer bldata[0] = (keyA[sectorNo][0]); bldata[1] = (keyA[sectorNo][1]); bldata[2] = (keyA[sectorNo][2]); @@ -573,7 +573,7 @@ static void parseParamTDS(const char *Cmd, const uint8_t indx, bool *paramT, boo int len = param_getlength(Cmd, indx); if (len > 0 && len < 4){ param_getstr(Cmd, indx, ctmp3, sizeof(ctmp3)); - + *paramT |= (ctmp3[0] == 't' || ctmp3[0] == 'T'); *paramD |= (ctmp3[0] == 'd' || ctmp3[0] == 'D'); bool paramS1 = *paramT || *paramD; @@ -581,7 +581,7 @@ static void parseParamTDS(const char *Cmd, const uint8_t indx, bool *paramT, boo // slow and very slow if (ctmp3[0] == 's' || ctmp3[0] == 'S' || ctmp3[1] == 's' || ctmp3[1] == 'S') { *timeout = 11; // slow - + if (!paramS1 && (ctmp3[1] == 's' || ctmp3[1] == 'S')) { *timeout = 53; // very slow } @@ -606,7 +606,7 @@ int CmdHF14AMfNested(const char *Cmd) uint64_t key64 = 0; // timeout in units. (ms * 106)/10 or us*0.0106 uint8_t btimeout14a = MF_CHKKEYS_DEFTIMEOUT; // fast by default - + bool autosearchKey = false; bool transferToEml = false; @@ -647,14 +647,14 @@ int CmdHF14AMfNested(const char *Cmd) } else { SectorsCnt = ParamCardSizeSectors(cmdp); } - + // . number or autosearch key (*) if (param_getchar(Cmd, 1) == '*') { autosearchKey = true; parseParamTDS(Cmd, 2, &transferToEml, &createDumpFile, &btimeout14a); - PrintAndLog("--nested. sectors:%2d, block no:*, eml:%c, dmp=%c checktimeout=%d us", + PrintAndLog("--nested. sectors:%2d, block no:*, eml:%c, dmp=%c checktimeout=%d us", SectorsCnt, transferToEml?'y':'n', createDumpFile?'y':'n', ((int)btimeout14a * 10000) / 106); } else { blockNo = param_get8(Cmd, 1); @@ -681,7 +681,7 @@ int CmdHF14AMfNested(const char *Cmd) } // one sector nested - if (cmdp == 'o') { + if (cmdp == 'o') { trgBlockNo = param_get8(Cmd, 4); ctmp = param_getchar(Cmd, 5); @@ -697,7 +697,7 @@ int CmdHF14AMfNested(const char *Cmd) parseParamTDS(Cmd, 4, &transferToEml, &createDumpFile, &btimeout14a); } - PrintAndLog("--nested. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c checktimeout=%d us", + PrintAndLog("--nested. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c checktimeout=%d us", SectorsCnt, blockNo, keyType?'B':'A', transferToEml?'y':'n', createDumpFile?'y':'n', ((int)btimeout14a * 10000) / 106); } @@ -721,9 +721,9 @@ int CmdHF14AMfNested(const char *Cmd) // transfer key to the emulator if (transferToEml) { uint8_t sectortrailer; - if (trgBlockNo < 32*4) { // 4 block sector + if (trgBlockNo < 32*4) { // 4 block sector sectortrailer = trgBlockNo | 0x03; - } else { // 16 block sector + } else { // 16 block sector sectortrailer = trgBlockNo | 0x0f; } mfEmlGetMem(keyBlock, sectortrailer, 1); @@ -753,7 +753,7 @@ int CmdHF14AMfNested(const char *Cmd) PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt); mfCheckKeysSec(SectorsCnt, 2, btimeout14a, true, MifareDefaultKeysSize, keyBlock, e_sector); - + // get known key from array bool keyFound = false; if (autosearchKey) { @@ -769,7 +769,7 @@ int CmdHF14AMfNested(const char *Cmd) } } if (keyFound) break; - } + } // Can't found a key.... if (!keyFound) { @@ -810,7 +810,7 @@ int CmdHF14AMfNested(const char *Cmd) PrintAndLog("Found valid key:%012" PRIx64, key64); e_sector[sectorNo].foundKey[trgKeyType] = 1; e_sector[sectorNo].Key[trgKeyType] = key64; - + // try to check this key as a key to the other sectors mfCheckKeysSec(SectorsCnt, 2, btimeout14a, true, 1, keyBlock, e_sector); } @@ -821,7 +821,7 @@ int CmdHF14AMfNested(const char *Cmd) // print nested statistic PrintAndLog("\n\n-----------------------------------------------\nNested statistic:\nIterations count: %d", iterations); PrintAndLog("Time in nested: %1.3f (%1.3f sec per key)", ((float)(msclock() - msclock1))/1000.0, ((float)(msclock() - msclock1))/iterations/1000.0); - + // print result PrintAndLog("|---|----------------|---|----------------|---|"); PrintAndLog("|sec|key A |res|key B |res|"); @@ -990,7 +990,7 @@ int CmdHF14AMfNestedHard(const char *Cmd) i++; } } - + SetSIMDInstr(SIMD_AUTO); if (iindx > 0) { while ((ctmp = param_getchar(Cmd, iindx))) { @@ -1020,7 +1020,7 @@ int CmdHF14AMfNestedHard(const char *Cmd) } } iindx++; - } + } } PrintAndLog("--target block no:%3d, target key type:%c, known target key: 0x%02x%02x%02x%02x%02x%02x%s, file action: %s, Slow: %s, Tests: %d ", @@ -1072,8 +1072,8 @@ int CmdHF14AMfChk(const char *Cmd) uint16_t stKeyBlock = 20; int i, res; - int keycnt = 0; - char ctmp = 0x00; + int keycnt = 0; + char ctmp = 0x00; int clen = 0; uint8_t blockNo = 0; uint8_t SectorsCnt = 0; @@ -1085,7 +1085,7 @@ int CmdHF14AMfChk(const char *Cmd) bool transferToEml = 0; bool createDumpFile = 0; - + sector_t *e_sector = NULL; keyBlock = calloc(stKeyBlock, 6); @@ -1123,12 +1123,12 @@ int CmdHF14AMfChk(const char *Cmd) } parseParamTDS(Cmd, 2, &transferToEml, &createDumpFile, &btimeout14a); - + param3InUse = transferToEml | createDumpFile | (btimeout14a != MF_CHKKEYS_DEFTIMEOUT); - PrintAndLog("--chk keys. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c checktimeout=%d us", + PrintAndLog("--chk keys. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c checktimeout=%d us", SectorsCnt, blockNo, keyType?'B':'A', transferToEml?'y':'n', createDumpFile?'y':'n', ((int)btimeout14a * 10000) / 106); - + for (i = param3InUse; param_getchar(Cmd, 2 + i); i++) { if (!param_gethex(Cmd, 2 + i, keyBlock + 6 * keycnt, 12)) { if ( stKeyBlock - keycnt < 2) { @@ -1142,7 +1142,7 @@ int CmdHF14AMfChk(const char *Cmd) } PrintAndLog("chk key[%2d] %02x%02x%02x%02x%02x%02x", keycnt, (keyBlock + 6*keycnt)[0],(keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2], - (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); + (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); keycnt++; } else { // May be a dic file @@ -1159,7 +1159,7 @@ int CmdHF14AMfChk(const char *Cmd) while (fgetc(f) != '\n' && !feof(f)) ; //goto next line - if( buf[0]=='#' ) continue; //The line start with # is comment, skip + if( buf[0]=='#' ) continue; //The line start with # is comment, skip if (!isxdigit((unsigned char)buf[0])){ PrintAndLog("File content error. '%s' must include 12 HEX symbols",buf); @@ -1200,7 +1200,7 @@ int CmdHF14AMfChk(const char *Cmd) for (;keycnt < defaultKeysSize; keycnt++) PrintAndLog("chk default key[%2d] %02x%02x%02x%02x%02x%02x", keycnt, (keyBlock + 6*keycnt)[0],(keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2], - (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); + (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); } // initialize storage for found keys @@ -1245,7 +1245,7 @@ int CmdHF14AMfChk(const char *Cmd) for (uint32_t c = 0; c < keycnt; c+=max_keys) { uint32_t size = keycnt-c > max_keys ? max_keys : keycnt-c; - res = mfCheckKeys(blockNo, keyAB & 0x01, true, size, &keyBlock[6 * c], &key64); + res = mfCheckKeys(blockNo, keyAB & 0x01, true, size, &keyBlock[6 * c], &key64); if (res != 1) { if (!res) { @@ -1258,7 +1258,7 @@ int CmdHF14AMfChk(const char *Cmd) } } while(--keyAB > 0); } - + // print result if (foundAKey) { if (SectorsCnt) { @@ -1275,8 +1275,8 @@ int CmdHF14AMfChk(const char *Cmd) } else { PrintAndLog(""); PrintAndLog("No valid keys found."); - } - + } + if (transferToEml) { uint8_t block[16]; for (uint16_t sectorNo = 0; sectorNo < SectorsCnt; sectorNo++) { @@ -1320,7 +1320,7 @@ int CmdHF14AMfChk(const char *Cmd) void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack) { #define ATTACK_KEY_COUNT 7 // keep same as define in iso14443a.c -> Mifare1ksim() - // cannot be more than 7 or it will overrun c.d.asBytes(512) + // cannot be more than 7 or it will overrun c.d.asBytes(512) uint64_t key = 0; typedef struct { uint64_t keyA; @@ -1329,7 +1329,7 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack st_t sector_trailer[ATTACK_KEY_COUNT]; memset(sector_trailer, 0x00, sizeof(sector_trailer)); - uint8_t stSector[ATTACK_KEY_COUNT]; + uint8_t stSector[ATTACK_KEY_COUNT]; memset(stSector, 0x00, sizeof(stSector)); uint8_t key_cnt[ATTACK_KEY_COUNT]; memset(key_cnt, 0x00, sizeof(key_cnt)); @@ -1392,7 +1392,7 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack if (setEmulatorMem) { for (uint8_t i = 0; i0) { - uint8_t memBlock[16]; + uint8_t memBlock[16]; memset(memBlock, 0x00, sizeof(memBlock)); char cmd1[36]; memset(cmd1,0x00,sizeof(cmd1)); @@ -1463,7 +1463,7 @@ int CmdHF14AMfSim(const char *Cmd) { while(param_getchar(Cmd, cmdp) != 0x00) { switch(param_getchar(Cmd, cmdp)) { - case '*': + case '*': cardsize = param_getchar(Cmd + 1, cmdp); switch(cardsize) { case '0': @@ -1580,7 +1580,7 @@ int CmdHF14AMfSim(const char *Cmd) { cardsize == '2' ? "2K" : cardsize == '4' ? "4K" : "1K", flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): - flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A", + flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A", exitAfterNReads, flags, flags); @@ -1615,7 +1615,7 @@ int CmdHF14AMfSim(const char *Cmd) { cardsize == '2' ? "2K" : cardsize == '4' ? "4K" : "1K", flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): - flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A", + flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A", exitAfterNReads, flags, flags); @@ -1951,31 +1951,37 @@ int CmdHF14AMfECFill(const char *Cmd) return 0; } + int CmdHF14AMfEKeyPrn(const char *Cmd) { int i; - uint8_t numSectors; + uint8_t numSectors = 16; uint8_t data[16]; uint64_t keyA, keyB; + bool createDumpFile = false; if (param_getchar(Cmd, 0) == 'h') { PrintAndLog("It prints the keys loaded in the emulator memory"); - PrintAndLog("Usage: hf mf ekeyprn [card memory]"); + PrintAndLog("Usage: hf mf ekeyprn [card memory] [d]"); PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); + PrintAndLog(" [d] : write keys to binary file dumpkeys.bin"); PrintAndLog(""); PrintAndLog(" sample: hf mf ekeyprn 1"); return 0; } - char cmdp = param_getchar(Cmd, 0); - - switch (cmdp) { - case '0' : numSectors = 5; break; - case '1' : - case '\0': numSectors = 16; break; - case '2' : numSectors = 32; break; - case '4' : numSectors = 40; break; - default: numSectors = 16; + uint8_t cmdp = 0; + while (param_getchar(Cmd, cmdp) != 0x00) { + switch (param_getchar(Cmd, cmdp)) { + case '0' : numSectors = 5; break; + case '1' : + case '\0': numSectors = 16; break; + case '2' : numSectors = 32; break; + case '4' : numSectors = 40; break; + case 'd' : + case 'D' : createDumpFile = true; break; + } + cmdp++; } PrintAndLog("|---|----------------|----------------|"); @@ -1992,9 +1998,35 @@ int CmdHF14AMfEKeyPrn(const char *Cmd) } PrintAndLog("|---|----------------|----------------|"); + // Create dump file + if (createDumpFile) { + FILE *fkeys; + if ((fkeys = fopen("dumpkeys.bin","wb")) == NULL) { + PrintAndLog("Could not create file dumpkeys.bin"); + return 1; + } + PrintAndLog("Printing keys to binary file dumpkeys.bin..."); + for(i = 0; i < numSectors; i++) { + if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1)) { + PrintAndLog("error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1); + break; + } + fwrite(data+6, 1, 6, fkeys); + } + for(i = 0; i < numSectors; i++) { + if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1)) { + PrintAndLog("error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1); + break; + } + fwrite(data+10, 1, 6, fkeys); + } + fclose(fkeys); + } + return 0; } + int CmdHF14AMfCSetUID(const char *Cmd) { uint8_t uid[8] = {0x00}; @@ -2006,7 +2038,7 @@ int CmdHF14AMfCSetUID(const char *Cmd) uint8_t needHelp = 0; char cmdp = 1; - + if (param_getchar(Cmd, 0) && param_gethex(Cmd, 0, uid, 8)) { PrintAndLog("UID must include 8 HEX symbols"); return 1; @@ -2015,12 +2047,12 @@ int CmdHF14AMfCSetUID(const char *Cmd) if (param_getlength(Cmd, 1) > 1 && param_getlength(Cmd, 2) > 1) { atqaPresent = 1; cmdp = 3; - + if (param_gethex(Cmd, 1, atqa, 4)) { PrintAndLog("ATQA must include 4 HEX symbols"); return 1; } - + if (param_gethex(Cmd, 2, sak, 2)) { PrintAndLog("SAK must include 2 HEX symbols"); return 1; @@ -2074,7 +2106,7 @@ int CmdHF14AMfCWipe(const char *Cmd) int numBlocks = 16 * 4; bool wipeCard = false; bool fillCard = false; - + if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') { PrintAndLog("Usage: hf mf cwipe [card size] [w] [f]"); PrintAndLog("sample: hf mf cwipe 1 w f"); @@ -2085,9 +2117,9 @@ int CmdHF14AMfCWipe(const char *Cmd) } gen = mfCIdentify(); - if ((gen != 1) && (gen != 2)) + if ((gen != 1) && (gen != 2)) return 1; - + numBlocks = ParamCardSizeBlocks(param_getchar(Cmd, 0)); char cmdp = 0; @@ -2107,7 +2139,7 @@ int CmdHF14AMfCWipe(const char *Cmd) cmdp++; } - if (!wipeCard && !fillCard) + if (!wipeCard && !fillCard) wipeCard = true; PrintAndLog("--blocks count:%2d wipe:%c fill:%c", numBlocks, (wipeCard)?'y':'n', (fillCard)?'y':'n'); @@ -2117,10 +2149,10 @@ int CmdHF14AMfCWipe(const char *Cmd) if (wipeCard) { PrintAndLog("WARNING: can't wipe magic card 1b generation"); } - res = mfCWipe(numBlocks, true, false, fillCard); + res = mfCWipe(numBlocks, true, false, fillCard); } else { /* generation 1a magic card by default */ - res = mfCWipe(numBlocks, false, wipeCard, fillCard); + res = mfCWipe(numBlocks, false, wipeCard, fillCard); } if (res) { @@ -2147,7 +2179,7 @@ int CmdHF14AMfCSetBlk(const char *Cmd) } gen = mfCIdentify(); - if ((gen != 1) && (gen != 2)) + if ((gen != 1) && (gen != 2)) return 1; blockNo = param_get8(Cmd, 0); @@ -2213,9 +2245,9 @@ int CmdHF14AMfCLoad(const char *Cmd) PrintAndLog("Cant get block: %d", blockNum); return 2; } - if (blockNum == 0) flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC; // switch on field and send magic sequence - if (blockNum == 1) flags = 0; // just write - if (blockNum == numblock - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD; // Done. Magic Halt and switch off field. + if (blockNum == 0) flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC; // switch on field and send magic sequence + if (blockNum == 1) flags = 0; // just write + if (blockNum == numblock - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD; // Done. Magic Halt and switch off field. if (gen == 2) /* generation 1b magic card */ @@ -2265,9 +2297,9 @@ int CmdHF14AMfCLoad(const char *Cmd) for (i = 0; i < 32; i += 2) sscanf(&buf[i], "%02x", (unsigned int *)&buf8[i / 2]); - if (blockNum == 0) flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC; // switch on field and send magic sequence - if (blockNum == 1) flags = 0; // just write - if (blockNum == numblock - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD; // Done. Switch off field. + if (blockNum == 0) flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC; // switch on field and send magic sequence + if (blockNum == 1) flags = 0; // just write + if (blockNum == numblock - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD; // Done. Switch off field. if (gen == 2) /* generation 1b magic card */ @@ -2326,7 +2358,7 @@ int CmdHF14AMfCGetBlk(const char *Cmd) { } PrintAndLog("block data:%s", sprint_hex(memBlock, 16)); - + if (mfIsSectorTrailer(blockNo)) { PrintAndLogEx(NORMAL, "Trailer decoded:"); PrintAndLogEx(NORMAL, "Key A: %s", sprint_hex_inrow(memBlock, 6)); @@ -2339,7 +2371,7 @@ int CmdHF14AMfCGetBlk(const char *Cmd) { } PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&memBlock[9], 1)); } - + return 0; } @@ -2390,19 +2422,19 @@ int CmdHF14AMfCGetSc(const char *Cmd) { } PrintAndLog("block %3d data:%s", baseblock + i, sprint_hex(memBlock, 16)); - + if (mfIsSectorTrailer(baseblock + i)) { - PrintAndLogEx(NORMAL, "Trailer decoded:"); - PrintAndLogEx(NORMAL, "Key A: %s", sprint_hex_inrow(memBlock, 6)); - PrintAndLogEx(NORMAL, "Key B: %s", sprint_hex_inrow(&memBlock[10], 6)); - int bln = baseblock; - int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1; - for (int i = 0; i < 4; i++) { - PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &memBlock[6])); - bln += blinc; - } - PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&memBlock[9], 1)); - } + PrintAndLogEx(NORMAL, "Trailer decoded:"); + PrintAndLogEx(NORMAL, "Key A: %s", sprint_hex_inrow(memBlock, 6)); + PrintAndLogEx(NORMAL, "Key B: %s", sprint_hex_inrow(&memBlock[10], 6)); + int bln = baseblock; + int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1; + for (int i = 0; i < 4; i++) { + PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &memBlock[6])); + bln += blinc; + } + PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&memBlock[9], 1)); + } } return 0; } @@ -2599,17 +2631,17 @@ int CmdHF14AMfSniff(const char *Cmd){ uint16_t traceLen = resp.arg[1]; len = resp.arg[2]; - if (res == 0) { // we are done + if (res == 0) { // we are done break; } - if (res == 1) { // there is (more) data to be transferred - if (pckNum == 0) { // first packet, (re)allocate necessary buffer + if (res == 1) { // there is (more) data to be transferred + if (pckNum == 0) { // first packet, (re)allocate necessary buffer if (traceLen > bufsize || buf == NULL) { uint8_t *p; - if (buf == NULL) { // not yet allocated + if (buf == NULL) { // not yet allocated p = malloc(traceLen); - } else { // need more memory + } else { // need more memory p = realloc(buf, traceLen); } if (p == NULL) { @@ -2628,13 +2660,13 @@ int CmdHF14AMfSniff(const char *Cmd){ pckNum++; } - if (res == 2) { // received all data, start displaying + if (res == 2) { // received all data, start displaying blockLen = bufPtr - buf; bufPtr = buf; printf(">\n"); PrintAndLog("received trace len: %d packages: %d", blockLen, pckNum); while (bufPtr - buf < blockLen) { - bufPtr += 6; // skip (void) timing information + bufPtr += 6; // skip (void) timing information len = *((uint16_t *)bufPtr); if(len & 0x8000) { isTag = true; @@ -2662,11 +2694,11 @@ int CmdHF14AMfSniff(const char *Cmd){ mfTraceInit(uid, atqa, sak, wantSaveToEmlFile); } else { oddparitybuf(bufPtr, len, parity); - PrintAndLog("%s(%d):%s [%s] c[%s]%c", - isTag ? "TAG":"RDR", - num, - sprint_hex(bufPtr, len), - printBitsPar(bufPtr + len, len), + PrintAndLog("%s(%d):%s [%s] c[%s]%c", + isTag ? "TAG":"RDR", + num, + sprint_hex(bufPtr, len), + printBitsPar(bufPtr + len, len), printBitsPar(parity, len), memcmp(bufPtr + len, parity, len / 8 + 1) ? '!' : ' '); if (wantLogToFile) @@ -2676,7 +2708,7 @@ int CmdHF14AMfSniff(const char *Cmd){ num++; } bufPtr += len; - bufPtr += parlen; // ignore parity + bufPtr += parlen; // ignore parity } pckNum = 0; } @@ -2684,7 +2716,7 @@ int CmdHF14AMfSniff(const char *Cmd){ } // while (true) free(buf); - + msleep(300); // wait for exiting arm side. PrintAndLog("Done."); return 0; @@ -2704,8 +2736,8 @@ int CmdHF14AMfAuth4(const char *cmd) { uint8_t key[16] = {0}; int keylen = 0; - CLIParserInit("hf mf auth4", - "Executes AES authentication command in ISO14443-4", + CLIParserInit("hf mf auth4", + "Executes AES authentication command in ISO14443-4", "Usage:\n\thf mf auth4 4000 000102030405060708090a0b0c0d0e0f -> executes authentication\n" "\thf mf auth4 9003 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -> executes authentication\n"); @@ -2716,16 +2748,16 @@ int CmdHF14AMfAuth4(const char *cmd) { arg_param_end }; CLIExecWithReturn(cmd, argtable, true); - + CLIGetHexWithReturn(1, keyn, &keynlen); CLIGetHexWithReturn(2, key, &keylen); CLIParserFree(); - + if (keynlen != 2) { PrintAndLog("ERROR: must be 2 bytes long instead of: %d", keynlen); return 1; } - + if (keylen != 16) { PrintAndLog("ERROR: must be 16 bytes long instead of: %d", keylen); return 1; @@ -2737,196 +2769,196 @@ int CmdHF14AMfAuth4(const char *cmd) { // https://www.nxp.com/docs/en/application-note/AN10787.pdf int CmdHF14AMfMAD(const char *cmd) { - CLIParserInit("hf mf mad", - "Checks and prints Mifare Application Directory (MAD)", - "Usage:\n\thf mf mad -> shows MAD if exists\n" - "\thf mf mad -a 03e1 -k ffffffffffff -b -> shows NDEF data if exists. read card with custom key and key B\n"); - - void *argtable[] = { - arg_param_begin, - arg_lit0("vV", "verbose", "show technical data"), - arg_str0("aA", "aid", "print all sectors with aid", NULL), - arg_str0("kK", "key", "key for printing sectors", NULL), - arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"), - arg_param_end - }; - CLIExecWithReturn(cmd, argtable, true); - bool verbose = arg_get_lit(1); - uint8_t aid[2] = {0}; - int aidlen; - CLIGetHexWithReturn(2, aid, &aidlen); - uint8_t key[6] = {0}; - int keylen; - CLIGetHexWithReturn(3, key, &keylen); - bool keyB = arg_get_lit(4); - - CLIParserFree(); - - if (aidlen != 2 && keylen > 0) { - PrintAndLogEx(WARNING, "do not need a key without aid."); - } - - uint8_t sector0[16 * 4] = {0}; - uint8_t sector10[16 * 4] = {0}; - if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { - PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); - return 2; - } - - if (verbose) { - for (int i = 0; i < 4; i ++) - PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(§or0[i * 16], 16)); - } - - bool haveMAD2 = false; - MAD1DecodeAndPrint(sector0, verbose, &haveMAD2); - - if (haveMAD2) { - if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) { - PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); - return 2; - } - - MAD2DecodeAndPrint(sector10, verbose); - } - - if (aidlen == 2) { - uint16_t aaid = (aid[0] << 8) + aid[1]; - PrintAndLogEx(NORMAL, "\n-------------- AID 0x%04x ---------------", aaid); - - uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; - size_t madlen = 0; - if (MADDecode(sector0, sector10, mad, &madlen)) { - PrintAndLogEx(ERR, "can't decode mad."); - return 10; - } - - uint8_t akey[6] = {0}; - memcpy(akey, g_mifare_ndef_key, 6); - if (keylen == 6) { - memcpy(akey, key, 6); - } - - for (int i = 0; i < madlen; i++) { - if (aaid == mad[i]) { - uint8_t vsector[16 * 4] = {0}; - if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(ERR, "read sector %d error.", i + 1); - return 2; - } - - for (int j = 0; j < (verbose ? 4 : 3); j ++) - PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16)); - } - } - } - - return 0; + CLIParserInit("hf mf mad", + "Checks and prints Mifare Application Directory (MAD)", + "Usage:\n\thf mf mad -> shows MAD if exists\n" + "\thf mf mad -a 03e1 -k ffffffffffff -b -> shows NDEF data if exists. read card with custom key and key B\n"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("vV", "verbose", "show technical data"), + arg_str0("aA", "aid", "print all sectors with aid", NULL), + arg_str0("kK", "key", "key for printing sectors", NULL), + arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + bool verbose = arg_get_lit(1); + uint8_t aid[2] = {0}; + int aidlen; + CLIGetHexWithReturn(2, aid, &aidlen); + uint8_t key[6] = {0}; + int keylen; + CLIGetHexWithReturn(3, key, &keylen); + bool keyB = arg_get_lit(4); + + CLIParserFree(); + + if (aidlen != 2 && keylen > 0) { + PrintAndLogEx(WARNING, "do not need a key without aid."); + } + + uint8_t sector0[16 * 4] = {0}; + uint8_t sector10[16 * 4] = {0}; + if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { + PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + + if (verbose) { + for (int i = 0; i < 4; i ++) + PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(§or0[i * 16], 16)); + } + + bool haveMAD2 = false; + MAD1DecodeAndPrint(sector0, verbose, &haveMAD2); + + if (haveMAD2) { + if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) { + PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + + MAD2DecodeAndPrint(sector10, verbose); + } + + if (aidlen == 2) { + uint16_t aaid = (aid[0] << 8) + aid[1]; + PrintAndLogEx(NORMAL, "\n-------------- AID 0x%04x ---------------", aaid); + + uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; + size_t madlen = 0; + if (MADDecode(sector0, sector10, mad, &madlen)) { + PrintAndLogEx(ERR, "can't decode mad."); + return 10; + } + + uint8_t akey[6] = {0}; + memcpy(akey, g_mifare_ndef_key, 6); + if (keylen == 6) { + memcpy(akey, key, 6); + } + + for (int i = 0; i < madlen; i++) { + if (aaid == mad[i]) { + uint8_t vsector[16 * 4] = {0}; + if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(ERR, "read sector %d error.", i + 1); + return 2; + } + + for (int j = 0; j < (verbose ? 4 : 3); j ++) + PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16)); + } + } + } + + return 0; } int CmdHFMFNDEF(const char *cmd) { - CLIParserInit("hf mf ndef", - "Prints NFC Data Exchange Format (NDEF)", - "Usage:\n\thf mf ndef -> shows NDEF data\n" - "\thf mf ndef -a 03e1 -k ffffffffffff -b -> shows NDEF data with custom AID, key and with key B\n"); - - void *argtable[] = { - arg_param_begin, - arg_litn("vV", "verbose", 0, 2, "show technical data"), - arg_str0("aA", "aid", "replace default aid for NDEF", NULL), - arg_str0("kK", "key", "replace default key for NDEF", NULL), - arg_lit0("bB", "keyb", "use key B for access sectors (by default: key A)"), - arg_param_end - }; - CLIExecWithReturn(cmd, argtable, true); - - bool verbose = arg_get_lit(1); - bool verbose2 = arg_get_lit(1) > 1; - uint8_t aid[2] = {0}; - int aidlen; - CLIGetHexWithReturn(2, aid, &aidlen); - uint8_t key[6] = {0}; - int keylen; - CLIGetHexWithReturn(3, key, &keylen); - bool keyB = arg_get_lit(4); - - CLIParserFree(); - - uint16_t ndefAID = 0x03e1; - if (aidlen == 2) - ndefAID = (aid[0] << 8) + aid[1]; - - uint8_t ndefkey[6] = {0}; - memcpy(ndefkey, g_mifare_ndef_key, 6); - if (keylen == 6) { - memcpy(ndefkey, key, 6); - } - - uint8_t sector0[16 * 4] = {0}; - uint8_t sector10[16 * 4] = {0}; - uint8_t data[4096] = {0}; - int datalen = 0; - - PrintAndLogEx(NORMAL, ""); - - if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { - PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); - return 2; - } - - bool haveMAD2 = false; - int res = MADCheck(sector0, NULL, verbose, &haveMAD2); - if (res) { - PrintAndLogEx(ERR, "MAD error %d.", res); - return res; - } - - if (haveMAD2) { - if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) { - PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); - return 2; - } - } - - uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; - size_t madlen = 0; - if (MADDecode(sector0, (haveMAD2 ? sector10 : NULL), mad, &madlen)) { - PrintAndLogEx(ERR, "can't decode mad."); - return 10; - } - - printf("data reading:"); - for (int i = 0; i < madlen; i++) { - if (ndefAID == mad[i]) { - uint8_t vsector[16 * 4] = {0}; - if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, ndefkey, vsector)) { - PrintAndLogEx(ERR, "read sector %d error.", i + 1); - return 2; - } - - memcpy(&data[datalen], vsector, 16 * 3); - datalen += 16 * 3; - - printf("."); - } - } - printf(" OK\n"); - - if (!datalen) { - PrintAndLogEx(ERR, "no NDEF data."); - return 11; - } - - if (verbose2) { - PrintAndLogEx(NORMAL, "NDEF data:"); - dump_buffer(data, datalen, stdout, 1); - } - - NDEFDecodeAndPrint(data, datalen, verbose); - - return 0; + CLIParserInit("hf mf ndef", + "Prints NFC Data Exchange Format (NDEF)", + "Usage:\n\thf mf ndef -> shows NDEF data\n" + "\thf mf ndef -a 03e1 -k ffffffffffff -b -> shows NDEF data with custom AID, key and with key B\n"); + + void *argtable[] = { + arg_param_begin, + arg_litn("vV", "verbose", 0, 2, "show technical data"), + arg_str0("aA", "aid", "replace default aid for NDEF", NULL), + arg_str0("kK", "key", "replace default key for NDEF", NULL), + arg_lit0("bB", "keyb", "use key B for access sectors (by default: key A)"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + bool verbose = arg_get_lit(1); + bool verbose2 = arg_get_lit(1) > 1; + uint8_t aid[2] = {0}; + int aidlen; + CLIGetHexWithReturn(2, aid, &aidlen); + uint8_t key[6] = {0}; + int keylen; + CLIGetHexWithReturn(3, key, &keylen); + bool keyB = arg_get_lit(4); + + CLIParserFree(); + + uint16_t ndefAID = 0x03e1; + if (aidlen == 2) + ndefAID = (aid[0] << 8) + aid[1]; + + uint8_t ndefkey[6] = {0}; + memcpy(ndefkey, g_mifare_ndef_key, 6); + if (keylen == 6) { + memcpy(ndefkey, key, 6); + } + + uint8_t sector0[16 * 4] = {0}; + uint8_t sector10[16 * 4] = {0}; + uint8_t data[4096] = {0}; + int datalen = 0; + + PrintAndLogEx(NORMAL, ""); + + if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { + PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + + bool haveMAD2 = false; + int res = MADCheck(sector0, NULL, verbose, &haveMAD2); + if (res) { + PrintAndLogEx(ERR, "MAD error %d.", res); + return res; + } + + if (haveMAD2) { + if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) { + PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + } + + uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; + size_t madlen = 0; + if (MADDecode(sector0, (haveMAD2 ? sector10 : NULL), mad, &madlen)) { + PrintAndLogEx(ERR, "can't decode mad."); + return 10; + } + + printf("data reading:"); + for (int i = 0; i < madlen; i++) { + if (ndefAID == mad[i]) { + uint8_t vsector[16 * 4] = {0}; + if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, ndefkey, vsector)) { + PrintAndLogEx(ERR, "read sector %d error.", i + 1); + return 2; + } + + memcpy(&data[datalen], vsector, 16 * 3); + datalen += 16 * 3; + + printf("."); + } + } + printf(" OK\n"); + + if (!datalen) { + PrintAndLogEx(ERR, "no NDEF data."); + return 11; + } + + if (verbose2) { + PrintAndLogEx(NORMAL, "NDEF data:"); + dump_buffer(data, datalen, stdout, 1); + } + + NDEFDecodeAndPrint(data, datalen, verbose); + + return 0; } static command_t CommandTable[] = @@ -2936,7 +2968,7 @@ static command_t CommandTable[] = {"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"}, {"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"}, {"dump", CmdHF14AMfDump, 0, "Dump MIFARE classic tag to binary file"}, - {"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"}, + {"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"}, {"wrbl", CmdHF14AMfWrBl, 0, "Write MIFARE classic block"}, {"auth4", CmdHF14AMfAuth4, 0, "ISO14443-4 AES authentication"}, {"chk", CmdHF14AMfChk, 0, "Test block keys"}, -- 2.39.5 From 2378bb24c3d4ce21d71b4ab5739c58a9979b8b69 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Mon, 27 May 2019 07:57:40 +0200 Subject: [PATCH 09/16] fix compiler warning in cmdhflegic.c (and whitespace fixes) (#826) --- client/cmdhflegic.c | 580 ++++++++++++++++++++++---------------------- 1 file changed, 291 insertions(+), 289 deletions(-) diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 66e8ebb1..14942017 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -22,29 +22,29 @@ static int CmdHelp(const char *Cmd); -static command_t CommandTable[] = +static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"decode", CmdLegicDecode, 0, "Display deobfuscated and decoded LEGIC RF tag data (use after hf legic reader)"}, - {"reader", CmdLegicRFRead, 0, "[offset [length]] -- read bytes from a LEGIC card"}, - {"save", CmdLegicSave, 0, " [] -- Store samples"}, - {"load", CmdLegicLoad, 0, " -- Restore samples"}, - {"sim", CmdLegicRfSim, 0, "[tagtype, 0:MIM22, 1:MIM256, 2:MIM1024] Start tag simulator (use after load or read)"}, - {"write", CmdLegicRfWrite,0, " -- Write sample buffer (user after load or read)"}, - {"fill", CmdLegicRfFill, 0, " -- Fill/Write tag with constant value"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, 1, "This help"}, + {"decode", CmdLegicDecode, 0, "Display deobfuscated and decoded LEGIC RF tag data (use after hf legic reader)"}, + {"reader", CmdLegicRFRead, 0, "[offset [length]] -- read bytes from a LEGIC card"}, + {"save", CmdLegicSave, 0, " [] -- Store samples"}, + {"load", CmdLegicLoad, 0, " -- Restore samples"}, + {"sim", CmdLegicRfSim, 0, "[tagtype, 0:MIM22, 1:MIM256, 2:MIM1024] Start tag simulator (use after load or read)"}, + {"write", CmdLegicRfWrite,0, " -- Write sample buffer (user after load or read)"}, + {"fill", CmdLegicRfFill, 0, " -- Fill/Write tag with constant value"}, + {NULL, NULL, 0, NULL} }; int CmdHFLegic(const char *Cmd) { - CmdsParse(CommandTable, Cmd); - return 0; + CmdsParse(CommandTable, Cmd); + return 0; } int CmdHelp(const char *Cmd) { - CmdsHelp(CommandTable); - return 0; + CmdsHelp(CommandTable); + return 0; } /* @@ -54,189 +54,191 @@ int CmdHelp(const char *Cmd) */ int CmdLegicDecode(const char *Cmd) { - int i, j, k, n; - int segment_len = 0; - int segment_flag = 0; - int stamp_len = 0; - int crc = 0; - int wrp = 0; - int wrc = 0; - uint8_t data_buf[1053]; // receiver buffer - char out_string[3076]; // just use big buffer - bad practice - char token_type[4]; - - // copy data from proxmark into buffer - GetFromBigBuf(data_buf, sizeof(data_buf), 0, NULL, -1, false); - - // Output CDF System area (9 bytes) plus remaining header area (12 bytes) - - PrintAndLog("\nCDF: System Area"); - - PrintAndLog("MCD: %02x, MSN: %02x %02x %02x, MCC: %02x", - data_buf[0], - data_buf[1], - data_buf[2], - data_buf[3], - data_buf[4] - ); - - crc = data_buf[4]; - - switch (data_buf[5]&0x7f) { - case 0x00 ... 0x2f: - strncpy(token_type, "IAM",sizeof(token_type)); - break; - case 0x30 ... 0x6f: - strcpy(token_type, "SAM"); - break; - case 0x70 ... 0x7f: - strcpy(token_type, "GAM"); - break; - default: - strcpy(token_type, "???"); - break; - } - - stamp_len = 0xfc - data_buf[6]; - - PrintAndLog("DCF: %02x %02x, Token_Type=%s (OLE=%01u), Stamp_len=%02u", - data_buf[5], - data_buf[6], - token_type, - (data_buf[5]&0x80)>>7, - stamp_len - ); - - PrintAndLog("WRP=%02u, WRC=%01u, RD=%01u, raw=%02x, SSC=%02x", - data_buf[7]&0x0f, - (data_buf[7]&0x70)>>4, - (data_buf[7]&0x80)>>7, - data_buf[7], - data_buf[8] - ); - - PrintAndLog("Remaining Header Area"); - - PrintAndLog("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", - data_buf[9], - data_buf[10], - data_buf[11], - data_buf[12], - data_buf[13], - data_buf[14], - data_buf[15], - data_buf[16], - data_buf[17], - data_buf[18], - data_buf[19], - data_buf[20], - data_buf[21] - ); - - PrintAndLog("\nADF: User Area"); - - i = 22; - for (n=0; n<64; n++) { - segment_len = ((data_buf[i+1]^crc)&0x0f) * 256 + (data_buf[i]^crc); - segment_flag = ((data_buf[i+1]^crc)&0xf0)>>4; - - wrp = (data_buf[i+2]^crc); - wrc = ((data_buf[i+3]^crc)&0x70)>>4; - - PrintAndLog("Segment %02u: raw header=%02x %02x %02x %02x, flag=%01x (valid=%01u, last=%01u), len=%04u, WRP=%02u, WRC=%02u, RD=%01u, CRC=%02x", - n, - data_buf[i]^crc, - data_buf[i+1]^crc, - data_buf[i+2]^crc, - data_buf[i+3]^crc, - segment_flag, - (segment_flag&0x4)>>2, - (segment_flag&0x8)>>3, - segment_len, - wrp, - wrc, - ((data_buf[i+3]^crc)&0x80)>>7, - (data_buf[i+4]^crc) - ); - - i+=5; - - if (wrc>0) { - PrintAndLog("WRC protected area:"); - for (k=0, j=0; k < wrc && j<(sizeof(out_string)-3); k++, i++, j += 3) { - sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); - out_string[j+2] = ' '; - }; - - out_string[j] = '\0'; - - PrintAndLog("%s", out_string); - } - - if (wrp>wrc) { - PrintAndLog("Remaining write protected area:"); - - for (k=0, j=0; k < (wrp-wrc) && j<(sizeof(out_string)-3); k++, i++, j += 3) { - sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); - out_string[j+2] = ' '; - }; - - out_string[j] = '\0'; - - PrintAndLog("%s", out_string); - if((wrp-wrc) == 8) { - sprintf(out_string,"Card ID: %2X%02X%02X",data_buf[i-4]^crc,data_buf[i-3]^crc,data_buf[i-2]^crc); - PrintAndLog("%s", out_string); - } - } - - PrintAndLog("Remaining segment payload:"); - for (k=0, j=0; k < (segment_len - wrp - 5) && j<(sizeof(out_string)-3); k++, i++, j += 3) { - sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); - out_string[j+2] = ' '; - }; - - out_string[j] = '\0'; - - PrintAndLog("%s", out_string); - - // end with last segment - if (segment_flag & 0x8) - return 0; - }; - return 0; + int i, j, k, n; + int segment_len = 0; + int segment_flag = 0; + int stamp_len = 0; + int crc = 0; + int wrp = 0; + int wrc = 0; + uint8_t data_buf[1053]; // receiver buffer + char out_string[3076]; // just use big buffer - bad practice + char token_type[4]; + + // copy data from proxmark into buffer + GetFromBigBuf(data_buf, sizeof(data_buf), 0, NULL, -1, false); + + // Output CDF System area (9 bytes) plus remaining header area (12 bytes) + + PrintAndLog("\nCDF: System Area"); + + PrintAndLog("MCD: %02x, MSN: %02x %02x %02x, MCC: %02x", + data_buf[0], + data_buf[1], + data_buf[2], + data_buf[3], + data_buf[4] + ); + + crc = data_buf[4]; + + switch (data_buf[5]&0x7f) { + case 0x00 ... 0x2f: + strncpy(token_type, "IAM",sizeof(token_type)); + break; + case 0x30 ... 0x6f: + strcpy(token_type, "SAM"); + break; + case 0x70 ... 0x7f: + strcpy(token_type, "GAM"); + break; + default: + strcpy(token_type, "???"); + break; + } + + stamp_len = 0xfc - data_buf[6]; + + PrintAndLog("DCF: %02x %02x, Token_Type=%s (OLE=%01u), Stamp_len=%02u", + data_buf[5], + data_buf[6], + token_type, + (data_buf[5]&0x80)>>7, + stamp_len + ); + + PrintAndLog("WRP=%02u, WRC=%01u, RD=%01u, raw=%02x, SSC=%02x", + data_buf[7]&0x0f, + (data_buf[7]&0x70)>>4, + (data_buf[7]&0x80)>>7, + data_buf[7], + data_buf[8] + ); + + PrintAndLog("Remaining Header Area"); + + PrintAndLog("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + data_buf[9], + data_buf[10], + data_buf[11], + data_buf[12], + data_buf[13], + data_buf[14], + data_buf[15], + data_buf[16], + data_buf[17], + data_buf[18], + data_buf[19], + data_buf[20], + data_buf[21] + ); + + PrintAndLog("\nADF: User Area"); + + i = 22; + for (n=0; n<64; n++) { + segment_len = ((data_buf[i+1]^crc)&0x0f) * 256 + (data_buf[i]^crc); + segment_flag = ((data_buf[i+1]^crc)&0xf0)>>4; + + wrp = (data_buf[i+2]^crc); + wrc = ((data_buf[i+3]^crc)&0x70)>>4; + + PrintAndLog("Segment %02u: raw header=%02x %02x %02x %02x, flag=%01x (valid=%01u, last=%01u), len=%04u, WRP=%02u, WRC=%02u, RD=%01u, CRC=%02x", + n, + data_buf[i]^crc, + data_buf[i+1]^crc, + data_buf[i+2]^crc, + data_buf[i+3]^crc, + segment_flag, + (segment_flag&0x4)>>2, + (segment_flag&0x8)>>3, + segment_len, + wrp, + wrc, + ((data_buf[i+3]^crc)&0x80)>>7, + (data_buf[i+4]^crc) + ); + + i+=5; + + if (wrc>0) { + PrintAndLog("WRC protected area:"); + for (k=0, j=0; k < wrc && j<(sizeof(out_string)-3); k++, i++, j += 3) { + sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); + out_string[j+2] = ' '; + }; + + out_string[j] = '\0'; + + PrintAndLog("%s", out_string); + } + + if (wrp>wrc) { + PrintAndLog("Remaining write protected area:"); + + for (k=0, j=0; k < (wrp-wrc) && j<(sizeof(out_string)-3); k++, i++, j += 3) { + sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); + out_string[j+2] = ' '; + }; + + out_string[j] = '\0'; + + PrintAndLog("%s", out_string); + if((wrp-wrc) == 8) { + sprintf(out_string,"Card ID: %2X%02X%02X",data_buf[i-4]^crc,data_buf[i-3]^crc,data_buf[i-2]^crc); + PrintAndLog("%s", out_string); + } + } + + PrintAndLog("Remaining segment payload:"); + for (k=0, j=0; k < (segment_len - wrp - 5) && j<(sizeof(out_string)-3); k++, i++, j += 3) { + sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); + out_string[j+2] = ' '; + }; + + out_string[j] = '\0'; + + PrintAndLog("%s", out_string); + + // end with last segment + if (segment_flag & 0x8) + return 0; + }; + return 0; } int CmdLegicRFRead(const char *Cmd) { - int byte_count=0,offset=0; - sscanf(Cmd, "%i %i", &offset, &byte_count); - if(byte_count == 0) byte_count = -1; - if(byte_count + offset > 1024) byte_count = 1024 - offset; - UsbCommand c={CMD_READER_LEGIC_RF, {offset, byte_count, 0}}; - SendCommand(&c); - UsbCommand resp; - WaitForResponse(CMD_ACK,&resp); - switch (resp.arg[0]) { - case 0: - PrintAndLog("Card (MIM %i) read, use 'hf legic decode' or", ((legic_card_select_t*)resp.d.asBytes)->cardsize); - PrintAndLog("'data hexsamples %d' to view results", (resp.arg[1] + 7) & ~7); - break; - case 1: - PrintAndLog("No or unknown card found, aborting"); - break; - case 2: - PrintAndLog("operation failed @ 0x%03.3x", resp.arg[1]); - break; - } - return resp.arg[0]; + int byte_count=0,offset=0; + sscanf(Cmd, "%i %i", &offset, &byte_count); + if(byte_count == 0) byte_count = -1; + if(byte_count + offset > 1024) byte_count = 1024 - offset; + UsbCommand c={CMD_READER_LEGIC_RF, {offset, byte_count, 0}}; + SendCommand(&c); + UsbCommand resp; + WaitForResponse(CMD_ACK,&resp); + switch (resp.arg[0]) { + legic_card_select_t card; + case 0: + memcpy(&card, resp.d.asBytes, sizeof(card)); + PrintAndLog("Card (MIM %i) read, use 'hf legic decode' or", card.cardsize); + PrintAndLog("'data hexsamples %d' to view results", (resp.arg[1] + 7) & ~7); + break; + case 1: + PrintAndLog("No or unknown card found, aborting"); + break; + case 2: + PrintAndLog("operation failed @ 0x%03.3x", resp.arg[1]); + break; + } + return resp.arg[0]; } int CmdLegicLoad(const char *Cmd) { char filename[FILE_PATH_SIZE] = {0x00}; int len = 0; - + if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) { PrintAndLog("It loads datasamples from the file `filename`"); PrintAndLog("Usage: hf legic load "); @@ -244,92 +246,92 @@ int CmdLegicLoad(const char *Cmd) return 0; } - len = strlen(Cmd); + len = strlen(Cmd); if (len > FILE_PATH_SIZE) { PrintAndLog("Filepath too long (was %s bytes), max allowed is %s ", len, FILE_PATH_SIZE); return 0; } memcpy(filename, Cmd, len); - FILE *f = fopen(filename, "r"); - if(!f) { - PrintAndLog("couldn't open '%s'", Cmd); - return -1; - } - char line[80]; int offset = 0; unsigned int data[8]; - while(fgets(line, sizeof(line), f)) { - int res = sscanf(line, "%x %x %x %x %x %x %x %x", - &data[0], &data[1], &data[2], &data[3], - &data[4], &data[5], &data[6], &data[7]); - if(res != 8) { - PrintAndLog("Error: could not read samples"); - fclose(f); - return -1; - } - UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {offset, 1, 0}}; - int j; for(j = 0; j < 8; j++) { - c.d.asBytes[j] = data[j]; - } - SendCommand(&c); - WaitForResponse(CMD_ACK, NULL); - offset += 8; - } - fclose(f); - PrintAndLog("loaded %u samples", offset); - return 0; + FILE *f = fopen(filename, "r"); + if (!f) { + PrintAndLog("couldn't open '%s'", Cmd); + return -1; + } + char line[80]; int offset = 0; unsigned int data[8]; + while (fgets(line, sizeof(line), f)) { + int res = sscanf(line, "%x %x %x %x %x %x %x %x", + &data[0], &data[1], &data[2], &data[3], + &data[4], &data[5], &data[6], &data[7]); + if (res != 8) { + PrintAndLog("Error: could not read samples"); + fclose(f); + return -1; + } + UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {offset, 1, 0}}; + int j; for(j = 0; j < 8; j++) { + c.d.asBytes[j] = data[j]; + } + SendCommand(&c); + WaitForResponse(CMD_ACK, NULL); + offset += 8; + } + fclose(f); + PrintAndLog("loaded %u samples", offset); + return 0; } int CmdLegicSave(const char *Cmd) { - int requested = 1024; - int offset = 0; - int delivered = 0; - char filename[FILE_PATH_SIZE]; - uint8_t got[1024]; - - sscanf(Cmd, " %s %i %i", filename, &requested, &offset); - - /* If no length given save entire legic read buffer */ - /* round up to nearest 8 bytes so the saved data can be used with legicload */ - if (requested == 0) { - requested = 1024; - } - if (requested % 8 != 0) { - int remainder = requested % 8; - requested = requested + 8 - remainder; - } - if (offset + requested > sizeof(got)) { - PrintAndLog("Tried to read past end of buffer, + > 1024"); - return 0; - } - - FILE *f = fopen(filename, "w"); - if(!f) { - PrintAndLog("couldn't open '%s'", Cmd+1); - return -1; - } - - GetFromBigBuf(got, requested, offset, NULL, -1, false); - - for (int j = 0; j < requested; j += 8) { - fprintf(f, "%02x %02x %02x %02x %02x %02x %02x %02x\n", - got[j+0], - got[j+1], - got[j+2], - got[j+3], - got[j+4], - got[j+5], - got[j+6], - got[j+7] - ); - delivered += 8; - if (delivered >= requested) - break; - } - - fclose(f); - PrintAndLog("saved %u samples", delivered); - return 0; + int requested = 1024; + int offset = 0; + int delivered = 0; + char filename[FILE_PATH_SIZE]; + uint8_t got[1024]; + + sscanf(Cmd, " %s %i %i", filename, &requested, &offset); + + /* If no length given save entire legic read buffer */ + /* round up to nearest 8 bytes so the saved data can be used with legicload */ + if (requested == 0) { + requested = 1024; + } + if (requested % 8 != 0) { + int remainder = requested % 8; + requested = requested + 8 - remainder; + } + if (offset + requested > sizeof(got)) { + PrintAndLog("Tried to read past end of buffer, + > 1024"); + return 0; + } + + FILE *f = fopen(filename, "w"); + if (!f) { + PrintAndLog("couldn't open '%s'", Cmd+1); + return -1; + } + + GetFromBigBuf(got, requested, offset, NULL, -1, false); + + for (int j = 0; j < requested; j += 8) { + fprintf(f, "%02x %02x %02x %02x %02x %02x %02x %02x\n", + got[j+0], + got[j+1], + got[j+2], + got[j+3], + got[j+4], + got[j+5], + got[j+6], + got[j+7] + ); + delivered += 8; + if (delivered >= requested) + break; + } + + fclose(f); + PrintAndLog("saved %u samples", delivered); + return 0; } int CmdLegicRfSim(const char *Cmd) @@ -343,36 +345,36 @@ int CmdLegicRfSim(const char *Cmd) int CmdLegicRfWrite(const char *Cmd) { - UsbCommand c={CMD_WRITER_LEGIC_RF}; - int res = sscanf(Cmd, " 0x%" SCNx64 " 0x%" SCNx64, &c.arg[0], &c.arg[1]); - if(res != 2) { + UsbCommand c={CMD_WRITER_LEGIC_RF}; + int res = sscanf(Cmd, " 0x%" SCNx64 " 0x%" SCNx64, &c.arg[0], &c.arg[1]); + if (res != 2) { PrintAndLog("Please specify the offset and length as two hex strings"); - return -1; - } - SendCommand(&c); - return 0; + return -1; + } + SendCommand(&c); + return 0; } int CmdLegicRfFill(const char *Cmd) { - UsbCommand cmd ={CMD_WRITER_LEGIC_RF}; - int res = sscanf(Cmd, " 0x%" SCNx64 " 0x%" SCNx64 " 0x%" SCNx64, &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]); - if(res != 3) { - PrintAndLog("Please specify the offset, length and value as two hex strings"); - return -1; - } - - int i; - UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 1, 0}}; - for(i = 0; i < 48; i++) { - c.d.asBytes[i] = cmd.arg[2]; - } - for(i = 0; i < 22; i++) { - c.arg[0] = i*48; - SendCommand(&c); - WaitForResponse(CMD_ACK,NULL); - } - SendCommand(&cmd); - return 0; + UsbCommand cmd ={CMD_WRITER_LEGIC_RF}; + int res = sscanf(Cmd, " 0x%" SCNx64 " 0x%" SCNx64 " 0x%" SCNx64, &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]); + if (res != 3) { + PrintAndLog("Please specify the offset, length and value as two hex strings"); + return -1; + } + + int i; + UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 1, 0}}; + for (i = 0; i < 48; i++) { + c.d.asBytes[i] = cmd.arg[2]; + } + for (i = 0; i < 22; i++) { + c.arg[0] = i*48; + SendCommand(&c); + WaitForResponse(CMD_ACK,NULL); + } + SendCommand(&cmd); + return 0; } -- 2.39.5 From 5f18b0c45dba436e05df637b1b91137ab68cbefb Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Mon, 27 May 2019 07:58:09 +0200 Subject: [PATCH 10/16] add: Home (Pos1) and End key bindings in graph GUI (based on @mcd1992 change on RRG repo) (#823) --- CHANGELOG.md | 1 + client/proxguiqt.cpp | 37 ++++++++++++++++++++++++------------- client/proxguiqt.h | 14 +++++++------- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a8ee1fe..399f87f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf mfp ndef` `hf mf ndef` parsing NDEF records (Merlok) - Added Mifare Mini, Mifare 2K and 4K support to `hf mf sim` (piwi) - Added Legic detection to `hf search` (dnet) +- Added Home (Pos1) and End key bindings to the plot GUI (based on @mcd1992) ## [v3.1.0][2018-10-10] diff --git a/client/proxguiqt.cpp b/client/proxguiqt.cpp index 30e4c8de..cda90cc0 100644 --- a/client/proxguiqt.cpp +++ b/client/proxguiqt.cpp @@ -34,8 +34,8 @@ extern "C" { bool g_useOverlays = false; int g_absVMax = 0; -int startMax; -int PageWidth; +int startMax; // Maximum offset in the graph (right side of graph) +int PageWidth; // How many samples are currently visible on this 'page' / graph int unlockStart = 0; void ProxGuiQT::ShowGraphWindow(void) @@ -134,8 +134,8 @@ ProxGuiQT::~ProxGuiQT(void) { //if (plotwidget) { //plotwidget->destroy(true,true); - // delete plotwidget; - // plotwidget = NULL; + // delete plotwidget; + // plotwidget = NULL; //} if (plotapp) { plotapp->quit(); @@ -474,7 +474,7 @@ void Plot::plotGridLines(QPainter* painter,QRect r) if ((PlotGridX > 0) && ((PlotGridX * GraphPixelsPerPoint) > 1)) { for(i = (offset * GraphPixelsPerPoint); i < r.right(); i += grid_delta_x) { painter->drawLine(r.left()+i, r.top(), r.left()+i, r.bottom()); - } + } } if (PlotGridY > 0) { for(i = 0; yCoordOf(i,r,g_absVMax) > r.top(); i += grid_delta_y) { @@ -509,8 +509,9 @@ void Plot::paintEvent(QPaintEvent *event) if(CursorDPos > GraphTraceLen) CursorDPos= 0; - QRect plotRect(WIDTH_AXES, 0, width()-WIDTH_AXES, height()-HEIGHT_INFO); - QRect infoRect(0, height()-HEIGHT_INFO, width(), HEIGHT_INFO); + QRect plotRect(WIDTH_AXES, 0, width() - WIDTH_AXES, height() - HEIGHT_INFO); + QRect infoRect(0, height() - HEIGHT_INFO, width(), HEIGHT_INFO); + PageWidth = plotRect.width() / GraphPixelsPerPoint; //Grey background painter.fillRect(rect(), QColor(60, 60, 60)); @@ -529,7 +530,7 @@ void Plot::paintEvent(QPaintEvent *event) //Start painting graph PlotGraph(GraphBuffer, GraphTraceLen,plotRect,infoRect,&painter,0); - if (showDemod && DemodBufferLen > 8) { + if (showDemod && DemodBufferLen > 8) { PlotDemod(DemodBuffer, DemodBufferLen,plotRect,infoRect,&painter,2,g_DemodStartIdx); } if (g_useOverlays) { @@ -564,7 +565,7 @@ void Plot::paintEvent(QPaintEvent *event) //Draw annotations char str[200]; sprintf(str, "@%d dt=%d [%2.2f] zoom=%2.2f CursorAPos=%d CursorBPos=%d GridX=%d GridY=%d (%s) GridXoffset=%d", - GraphStart, CursorBPos - CursorAPos, (CursorBPos - CursorAPos)/CursorScaleFactor, + GraphStart, CursorBPos - CursorAPos, (CursorBPos - CursorAPos)/CursorScaleFactor, GraphPixelsPerPoint,CursorAPos,CursorBPos,PlotGridXdefault,PlotGridYdefault,GridLocked?"Locked":"Unlocked",GridOffset); painter.setPen(QColor(255, 255, 255)); painter.drawText(20, infoRect.bottom() - 3, str); @@ -616,14 +617,14 @@ void Plot::mouseMoveEvent(QMouseEvent *event) void Plot::keyPressEvent(QKeyEvent *event) { - int offset; + int offset; // Left/right movement offset (in sample size) if(event->modifiers() & Qt::ShiftModifier) { if (PlotGridX) offset= PageWidth - (PageWidth % PlotGridX); else offset= PageWidth; - } else + } else if(event->modifiers() & Qt::ControlModifier) offset= 1; else @@ -671,20 +672,22 @@ void Plot::keyPressEvent(QKeyEvent *event) case Qt::Key_H: puts("Plot Window Keystrokes:\n"); puts(" Key Action\n"); + puts(" UP Zoom out"); puts(" DOWN Zoom in"); puts(" G Toggle grid display"); puts(" H Show help"); puts(" L Toggle lock grid relative to samples"); + puts(" Q Hide window"); + puts(" HOME Move to the start of the graph"); + puts(" END Move to the end of the graph"); puts(" LEFT Move left"); puts(" LEFT Move left 1 sample"); puts(" LEFT Page left"); puts(" LEFT-MOUSE-CLICK Set yellow cursor"); - puts(" Q Hide window"); puts(" RIGHT Move right"); puts(" RIGHT Move right 1 sample"); puts(" RIGHT Page right"); puts(" RIGHT-MOUSE-CLICK Set purple cursor"); - puts(" UP Zoom out"); puts(""); puts("Use client window 'data help' for more plot commands\n"); break; @@ -701,6 +704,14 @@ void Plot::keyPressEvent(QKeyEvent *event) master->hide(); break; + case Qt::Key_Home: + GraphStart = 0; + break; + + case Qt::Key_End: + GraphStart = startMax; + break; + default: QWidget::keyPressEvent(event); return; diff --git a/client/proxguiqt.h b/client/proxguiqt.h index 5f7199fc..9677b49c 100644 --- a/client/proxguiqt.h +++ b/client/proxguiqt.h @@ -29,8 +29,8 @@ class Plot: public QWidget { private: QWidget *master; - int GraphStart; - double GraphPixelsPerPoint; + int GraphStart; // Starting point/offset for the left side of the graph + double GraphPixelsPerPoint; // How many visual pixels are between each sample point (x axis) int CursorAPos; int CursorBPos; void PlotGraph(int *buffer, int len, QRect r,QRect r2, QPainter* painter, int graphNum); @@ -73,13 +73,13 @@ class ProxWidget : public QWidget //OpsShow(void); protected: - // void paintEvent(QPaintEvent *event); + // void paintEvent(QPaintEvent *event); void closeEvent(QCloseEvent *event); void showEvent(QShowEvent *event); void hideEvent(QHideEvent *event); - // void mouseMoveEvent(QMouseEvent *event); - // void mousePressEvent(QMouseEvent *event) { mouseMoveEvent(event); } - // void keyPressEvent(QKeyEvent *event); + // void mouseMoveEvent(QMouseEvent *event); + // void mousePressEvent(QMouseEvent *event) { mouseMoveEvent(event); } + // void keyPressEvent(QKeyEvent *event); public slots: void applyOperation(); void stickOperation(); @@ -111,7 +111,7 @@ class ProxGuiQT : public QObject int argc; char **argv; WorkerThread *proxmarkThread; - + public: ProxGuiQT(int argc, char **argv, WorkerThread *wthread); ~ProxGuiQT(void); -- 2.39.5 From 4be9f36ebe31c2ade9754518f848db754a5d0e26 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 28 May 2019 07:48:55 +0200 Subject: [PATCH 11/16] start updating 'hf mfu' commands (#818) * use PrintAndLogEx() * fix some printouts * some #include refactoring * whitespace --- client/cmdhf14a.h | 13 +- client/cmdhficlass.c | 1 + client/cmdhfmf.c | 1 + client/cmdhfmf.h | 32 -- client/cmdhfmfu.c | 837 +++++++++++++++++++++++-------------------- client/cmdhfmfu.h | 52 +-- client/util.c | 6 +- client/util.h | 1 + 8 files changed, 463 insertions(+), 480 deletions(-) diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h index c4294b4c..d1669f3a 100644 --- a/client/cmdhf14a.h +++ b/client/cmdhf14a.h @@ -16,13 +16,14 @@ #include #include "mifare.h" -int CmdHF14A(const char *Cmd); -int CmdHF14AList(const char *Cmd); -int CmdHF14AMifare(const char *Cmd); -int CmdHF14AReader(const char *Cmd); +extern int CmdHF14A(const char *Cmd); +extern int CmdHF14AMfDbg(const char* cmd); +extern int CmdHF14AList(const char *Cmd); +extern int CmdHF14AMifare(const char *Cmd); +extern int CmdHF14AReader(const char *Cmd); extern int CmdHF14AInfo(const char *Cmd); -int CmdHF14ASim(const char *Cmd); -int CmdHF14ASnoop(const char *Cmd); +extern int CmdHF14ASim(const char *Cmd); +extern int CmdHF14ASnoop(const char *Cmd); extern void DropField(); diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 55804cf8..a2e31754 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -33,6 +33,7 @@ #include "usb_cmd.h" #include "cmdhfmfu.h" #include "util_posix.h" +#include "cmdhf14a.h" // DropField() static int CmdHelp(const char *Cmd); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 9284d14c..38b7f988 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -29,6 +29,7 @@ #include "hardnested/hardnested_bf_core.h" #include "cliparser/cliparser.h" #include "cmdhf14a.h" +#include "mifare/mifaredefault.h" #include "mifare/mifare4.h" #include "mifare/mad.h" #include "mifare/ndef.h" diff --git a/client/cmdhfmf.h b/client/cmdhfmf.h index 746fcbc1..d7c981f4 100644 --- a/client/cmdhfmf.h +++ b/client/cmdhfmf.h @@ -11,38 +11,6 @@ #ifndef CMDHFMF_H__ #define CMDHFMF_H__ -#include "mifare/mifaredefault.h" - -extern int CmdHFMF(const char *Cmd); extern int CmdHFMF(const char *Cmd); - -extern int CmdHF14AMfDbg(const char* cmd); -extern int CmdHF14AMfRdBl(const char* cmd); -extern int CmdHF14AMfURdBl(const char* cmd); -extern int CmdHF14AMfRdSc(const char* cmd); -extern int CmdHF14SMfURdCard(const char* cmd); -extern int CmdHF14AMfDump(const char* cmd); -extern int CmdHF14AMfRestore(const char* cmd); -extern int CmdHF14AMfWrBl(const char* cmd); -extern int CmdHF14AMfUWrBl(const char* cmd); -extern int CmdHF14AMfChk(const char* cmd); -extern int CmdHF14AMifare(const char* cmd); -extern int CmdHF14AMfNested(const char* cmd); -extern int CmdHF14AMfSniff(const char* cmd); -extern int CmdHF14AMf1kSim(const char* cmd); -extern int CmdHF14AMfEClear(const char* cmd); -extern int CmdHF14AMfEGet(const char* cmd); -extern int CmdHF14AMfESet(const char* cmd); -extern int CmdHF14AMfELoad(const char* cmd); -extern int CmdHF14AMfESave(const char* cmd); -extern int CmdHF14AMfECFill(const char* cmd); -extern int CmdHF14AMfEKeyPrn(const char* cmd); -extern int CmdHF14AMfCWipe(const char* cmd); -extern int CmdHF14AMfCSetUID(const char* cmd); -extern int CmdHF14AMfCSetBlk(const char* cmd); -extern int CmdHF14AMfCGetBlk(const char* cmd); -extern int CmdHF14AMfCGetSc(const char* cmd); -extern int CmdHF14AMfCLoad(const char* cmd); -extern int CmdHF14AMfCSave(const char* cmd); #endif diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index 9bdc6ce3..dac51be3 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -18,11 +18,39 @@ #include "ui.h" #include "mbedtls/des.h" #include "cmdhfmf.h" +#include "cmdhf14a.h" // DropField() #include "mifare.h" #include "util.h" #include "protocols.h" #include "taginfo.h" +typedef enum TAGTYPE_UL { + UNKNOWN = 0x000000, + UL = 0x000001, + UL_C = 0x000002, + UL_EV1_48 = 0x000004, + UL_EV1_128 = 0x000008, + NTAG = 0x000010, + NTAG_203 = 0x000020, + NTAG_210 = 0x000040, + NTAG_212 = 0x000080, + NTAG_213 = 0x000100, + NTAG_215 = 0x000200, + NTAG_216 = 0x000400, + MY_D = 0x000800, + MY_D_NFC = 0x001000, + MY_D_MOVE = 0x002000, + MY_D_MOVE_NFC = 0x004000, + MY_D_MOVE_LEAN= 0x008000, + NTAG_I2C_1K = 0x010000, + NTAG_I2C_2K = 0x020000, + FUDAN_UL = 0x040000, + MAGIC = 0x080000, + UL_MAGIC = UL | MAGIC, + UL_C_MAGIC = UL_C | MAGIC, + UL_ERROR = 0xFFFFFF, +} TagTypeUL_t; + #define MAX_UL_BLOCKS 0x0f #define MAX_ULC_BLOCKS 0x2b #define MAX_ULEV1a_BLOCKS 0x13 @@ -37,57 +65,63 @@ #define MAX_MY_D_MOVE 0x25 #define MAX_MY_D_MOVE_LEAN 0x0f +#define PUBLIC_ECDA_KEYLEN 33 +static uint8_t public_ecda_key[PUBLIC_ECDA_KEYLEN] = { + 0x04, 0x49, 0x4e, 0x1a, 0x38, 0x6d, 0x3d, 0x3c, + 0xfe, 0x3d, 0xc1, 0x0e, 0x5d, 0xe6, 0x8a, 0x49, + 0x9b, 0x1c, 0x20, 0x2d, 0xb5, 0xb1, 0x32, 0x39, + 0x3e, 0x89, 0xed, 0x19, 0xfe, 0x5b, 0xe8, 0xbc, + 0x61 +}; + #define KEYS_3DES_COUNT 7 -uint8_t default_3des_keys[KEYS_3DES_COUNT][16] = { - { 0x42,0x52,0x45,0x41,0x4b,0x4d,0x45,0x49,0x46,0x59,0x4f,0x55,0x43,0x41,0x4e,0x21 },// 3des std key - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },// all zeroes - { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f },// 0x00-0x0F - { 0x49,0x45,0x4D,0x4B,0x41,0x45,0x52,0x42,0x21,0x4E,0x41,0x43,0x55,0x4F,0x59,0x46 },// NFC-key - { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 },// all ones - { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF },// all FF - { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF } // 11 22 33 +static uint8_t default_3des_keys[KEYS_3DES_COUNT][16] = { + { 0x42,0x52,0x45,0x41,0x4b,0x4d,0x45,0x49,0x46,0x59,0x4f,0x55,0x43,0x41,0x4e,0x21 },// 3des std key + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },// all zeroes + { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f },// 0x00-0x0F + { 0x49,0x45,0x4D,0x4B,0x41,0x45,0x52,0x42,0x21,0x4E,0x41,0x43,0x55,0x4F,0x59,0x46 },// NFC-key + { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 },// all ones + { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF },// all FF + { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF } // 11 22 33 }; #define KEYS_PWD_COUNT 6 -uint8_t default_pwd_pack[KEYS_PWD_COUNT][4] = { +static uint8_t default_pwd_pack[KEYS_PWD_COUNT][4] = { {0xFF,0xFF,0xFF,0xFF}, // PACK 0x00,0x00 -- factory default - {0x4A,0xF8,0x4B,0x19}, // PACK 0xE5,0xBE -- italian bus (sniffed) {0x33,0x6B,0xA1,0x19}, // PACK 0x9c,0x2d -- italian bus (sniffed) - {0xFF,0x90,0x6C,0xB2}, // PACK 0x12,0x9e -- italian bus (sniffed) + {0xFF,0x90,0x6C,0xB2}, // PACK 0x12,0x9e -- italian bus (sniffed) {0x46,0x1c,0xA3,0x19}, // PACK 0xE9,0x5A -- italian bus (sniffed) {0x35,0x1C,0xD0,0x19}, // PACK 0x9A,0x5a -- italian bus (sniffed) }; #define MAX_UL_TYPES 18 -uint32_t UL_TYPES_ARRAY[MAX_UL_TYPES] = {UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, NTAG_203, - NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, FUDAN_UL}; - -uint8_t UL_MEMORY_ARRAY[MAX_UL_TYPES] = {MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_ULEV1a_BLOCKS, - MAX_ULEV1b_BLOCKS, MAX_NTAG_203, MAX_NTAG_203, MAX_NTAG_210, MAX_NTAG_212, MAX_NTAG_213, - MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS}; +static uint32_t UL_TYPES_ARRAY[MAX_UL_TYPES] = {UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, NTAG_203, + NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, FUDAN_UL}; +static uint8_t UL_MEMORY_ARRAY[MAX_UL_TYPES] = {MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_ULEV1a_BLOCKS, + MAX_ULEV1b_BLOCKS, MAX_NTAG_203, MAX_NTAG_203, MAX_NTAG_210, MAX_NTAG_212, MAX_NTAG_213, + MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS}; -static int CmdHelp(const char *Cmd); -// get version nxp product type -char *getProductTypeStr( uint8_t id){ +// get version nxp product type +static char *getProductTypeStr( uint8_t id){ static char buf[20]; char *retStr = buf; switch(id) { case 3: sprintf(retStr, "%02X, Ultralight", id); break; - case 4: sprintf(retStr, "%02X, NTAG", id); break; + case 4: sprintf(retStr, "%02X, NTAG", id); break; default: sprintf(retStr, "%02X, unknown", id); break; } return buf; } /* - The 7 MSBits (=n) code the storage size itself based on 2^n, + The 7 MSBits (=n) code the storage size itself based on 2^n, the LSBit is set to '0' if the size is exactly 2^n - and set to '1' if the storage size is between 2^n and 2^(n+1). + and set to '1' if the storage size is between 2^n and 2^(n+1). */ char *getUlev1CardSizeStr( uint8_t fsize ){ @@ -101,8 +135,8 @@ char *getUlev1CardSizeStr( uint8_t fsize ){ // is LSB set? if ( fsize & 1 ) sprintf(retStr, "%02X, (%u <-> %u bytes)",fsize, usize, lsize); - else - sprintf(retStr, "%02X, (%u bytes)", fsize, lsize); + else + sprintf(retStr, "%02X, (%u bytes)", fsize, lsize); return buf; } @@ -131,7 +165,7 @@ static int ul_send_cmd_raw_crc( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, if (append_crc) c.arg[0] |= ISO14A_APPEND_CRC; - memcpy(c.d.asBytes, cmd, cmdlen); + memcpy(c.d.asBytes, cmd, cmdlen); clearCommandBuffer(); SendCommand(&c); UsbCommand resp; @@ -151,7 +185,7 @@ static int ul_select( iso14a_card_select_t *card ){ bool ans = false; ans = WaitForResponseTimeout(CMD_ACK, &resp, 1500); if (!ans || resp.arg[0] < 1) { - PrintAndLog("iso14443a card select failed"); + PrintAndLogEx(WARNING, "iso14443a card select failed"); DropField(); return 0; } @@ -217,7 +251,7 @@ static int ul_auth_select( iso14a_card_select_t *card, TagTypeUL_t tagtype, bool if ( hasAuthKey && (tagtype & UL_C)) { //will select card automatically and close connection on error if (!ulc_authentication(authenticationkey, false)) { - PrintAndLog("Error: Authentication Failed UL-C"); + PrintAndLogEx(WARNING, "Authentication Failed UL-C"); return 0; } } else { @@ -226,7 +260,7 @@ static int ul_auth_select( iso14a_card_select_t *card, TagTypeUL_t tagtype, bool if (hasAuthKey) { if (ulev1_requestAuthentication(authenticationkey, pack, packSize) < 1) { DropField(); - PrintAndLog("Error: Authentication Failed UL-EV1/NTAG"); + PrintAndLogEx(WARNING, "Authentication Failed UL-EV1/NTAG"); return 0; } } @@ -236,15 +270,15 @@ static int ul_auth_select( iso14a_card_select_t *card, TagTypeUL_t tagtype, bool static int ulev1_getVersion( uint8_t *response, uint16_t responseLength ){ - uint8_t cmd[] = {MIFARE_ULEV1_VERSION}; + uint8_t cmd[] = {MIFARE_ULEV1_VERSION}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); return len; } // static int ulev1_fastRead( uint8_t startblock, uint8_t endblock, uint8_t *response ){ - + // uint8_t cmd[] = {MIFARE_ULEV1_FASTREAD, startblock, endblock}; - + // if ( !ul_send_cmd_raw(cmd, sizeof(cmd), response)){ // return -1; // } @@ -276,7 +310,7 @@ static int ulev1_readSignature( uint8_t *response, uint16_t responseLength ){ // Fudan check checks for which error is given for a command with incorrect crc // NXP UL chip responds with 01, fudan 00. // other possible checks: -// send a0 + crc +// send a0 + crc // UL responds with 00, fudan doesn't respond // or // send a200 + crc @@ -288,7 +322,7 @@ static int ulev1_readSignature( uint8_t *response, uint16_t responseLength ){ // make sure field is off before calling this function static int ul_fudan_check( void ){ iso14a_card_select_t card; - if ( !ul_select(&card) ) + if ( !ul_select(&card) ) return UL_ERROR; UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT, 4, 0}}; @@ -315,39 +349,43 @@ static int ul_print_default( uint8_t *data){ uid[5] = data[6]; uid[6] = data[7]; - PrintAndLog(" UID : %s ", sprint_hex(uid, 7)); - PrintAndLog(" UID[0] : %02X, %s", uid[0], getManufacturerName(uid[0])); + PrintAndLogEx(NORMAL," UID : %s ", sprint_hex(uid, 7)); + PrintAndLogEx(NORMAL," UID[0] : %02X, %s", uid[0], getManufacturerName(uid[0])); if ( uid[0] == 0x05 && ((uid[1] & 0xf0) >> 4) == 2 ) { // is infineon and 66RxxP uint8_t chip = (data[8] & 0xC7); // 11000111 mask, bit 3,4,5 RFU switch (chip){ - case 0xc2: PrintAndLog(" IC type : SLE 66R04P 770 Bytes"); break; //77 pages - case 0xc4: PrintAndLog(" IC type : SLE 66R16P 2560 Bytes"); break; //256 pages - case 0xc6: PrintAndLog(" IC type : SLE 66R32P 5120 Bytes"); break; //512 pages /2 sectors + case 0xc2: PrintAndLogEx(NORMAL, " IC type : SLE 66R04P 770 Bytes"); break; //77 pages + case 0xc4: PrintAndLogEx(NORMAL, " IC type : SLE 66R16P 2560 Bytes"); break; //256 pages + case 0xc6: PrintAndLogEx(NORMAL, " IC type : SLE 66R32P 5120 Bytes"); break; //512 pages /2 sectors } } - // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 + // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 int crc0 = 0x88 ^ data[0] ^ data[1] ^data[2]; if ( data[3] == crc0 ) - PrintAndLog(" BCC0 : %02X, Ok", data[3]); + PrintAndLogEx(NORMAL, " BCC0 : %02X, Ok", data[3]); else - PrintAndLog(" BCC0 : %02X, crc should be %02X", data[3], crc0); + PrintAndLogEx(NORMAL, " BCC0 : %02X, crc should be %02X", data[3], crc0); int crc1 = data[4] ^ data[5] ^ data[6] ^data[7]; if ( data[8] == crc1 ) - PrintAndLog(" BCC1 : %02X, Ok", data[8]); + PrintAndLogEx(NORMAL, " BCC1 : %02X, Ok", data[8]); else - PrintAndLog(" BCC1 : %02X, crc should be %02X", data[8], crc1 ); + PrintAndLogEx(NORMAL, " BCC1 : %02X, crc should be %02X", data[8], crc1 ); - PrintAndLog(" Internal : %02X, %sdefault", data[9], (data[9]==0x48)?"":"not " ); + PrintAndLogEx(NORMAL, " Internal : %02X, %sdefault", data[9], (data[9]==0x48)?"":"not " ); - PrintAndLog(" Lock : %s - %s", + PrintAndLogEx(NORMAL, " Lock : %s (binary %s %s)", sprint_hex(data+10, 2), - printBits(2, data+10) + printBits(1, data+10), + printBits(1, data+11) ); - PrintAndLog("OneTimePad : %s - %s\n", + PrintAndLogEx(NORMAL, "OneTimePad : %s (binary %s %s %s %s)\n", sprint_hex(data + 12, 4), - printBits(4, data+12) + printBits(1, data+12), + printBits(1, data+13), + printBits(1, data+14), + printBits(1, data+15) ); return 0; @@ -358,20 +396,20 @@ static int ndef_print_CC(uint8_t *data) { if(data[0] != 0xe1) return -1; - PrintAndLog("--- NDEF Message"); - PrintAndLog("Capability Container: %s", sprint_hex(data,4) ); - PrintAndLog(" %02X : NDEF Magic Number", data[0]); - PrintAndLog(" %02X : version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f); - PrintAndLog(" %02X : Physical Memory Size: %d bytes", data[2], (data[2] + 1) * 8); + PrintAndLogEx(NORMAL, "--- NDEF Message"); + PrintAndLogEx(NORMAL, "Capability Container: %s", sprint_hex(data,4) ); + PrintAndLogEx(NORMAL, " %02X : NDEF Magic Number", data[0]); + PrintAndLogEx(NORMAL, " %02X : version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f); + PrintAndLogEx(NORMAL, " %02X : Physical Memory Size: %d bytes", data[2], (data[2] + 1) * 8); if ( data[2] == 0x12 ) - PrintAndLog(" %02X : NDEF Memory Size: %d bytes", data[2], 144); + PrintAndLogEx(NORMAL, " %02X : NDEF Memory Size: %d bytes", data[2], 144); else if ( data[2] == 0x3e ) - PrintAndLog(" %02X : NDEF Memory Size: %d bytes", data[2], 496); + PrintAndLogEx(NORMAL, " %02X : NDEF Memory Size: %d bytes", data[2], 496); else if ( data[2] == 0x6d ) - PrintAndLog(" %02X : NDEF Memory Size: %d bytes", data[2], 872); + PrintAndLogEx(NORMAL, " %02X : NDEF Memory Size: %d bytes", data[2], 872); - PrintAndLog(" %02X : %s / %s", data[3], - (data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security", + PrintAndLogEx(NORMAL, " %02X : %s / %s", data[3], + (data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security", (data[3] & 0x0F)==0 ? "Write access granted without any security" : (data[3] & 0x0F)==0x0F ? "No write access granted at all" : "(RFU)"); return 0; } @@ -381,75 +419,85 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces){ spc[10]=0x00; char *spacer = spc + (10-spaces); - if ( tagtype & UL ) - PrintAndLog("%sTYPE : MIFARE Ultralight (MF0ICU1) %s", spacer, (tagtype & MAGIC) ? "" : "" ); + if ( tagtype & UL ) + PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight (MF0ICU1) %s", spacer, (tagtype & MAGIC) ? "" : "" ); else if ( tagtype & UL_C) - PrintAndLog("%sTYPE : MIFARE Ultralight C (MF0ULC) %s", spacer, (tagtype & MAGIC) ? "" : "" ); + PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight C (MF0ULC) %s", spacer, (tagtype & MAGIC) ? "" : "" ); else if ( tagtype & UL_EV1_48) - PrintAndLog("%sTYPE : MIFARE Ultralight EV1 48bytes (MF0UL1101)", spacer); - else if ( tagtype & UL_EV1_128) - PrintAndLog("%sTYPE : MIFARE Ultralight EV1 128bytes (MF0UL2101)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 48bytes (MF0UL1101)", spacer); + else if ( tagtype & UL_EV1_128) + PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 128bytes (MF0UL2101)", spacer); else if ( tagtype & NTAG ) - PrintAndLog("%sTYPE : NTAG UNKNOWN", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG UNKNOWN", spacer); else if ( tagtype & NTAG_203 ) - PrintAndLog("%sTYPE : NTAG 203 144bytes (NT2H0301F0DT)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 203 144bytes (NT2H0301F0DT)", spacer); else if ( tagtype & NTAG_210 ) - PrintAndLog("%sTYPE : NTAG 210 48bytes (NT2L1011G0DU)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 210 48bytes (NT2L1011G0DU)", spacer); else if ( tagtype & NTAG_212 ) - PrintAndLog("%sTYPE : NTAG 212 128bytes (NT2L1211G0DU)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 212 128bytes (NT2L1211G0DU)", spacer); else if ( tagtype & NTAG_213 ) - PrintAndLog("%sTYPE : NTAG 213 144bytes (NT2H1311G0DU)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 213 144bytes (NT2H1311G0DU)", spacer); else if ( tagtype & NTAG_215 ) - PrintAndLog("%sTYPE : NTAG 215 504bytes (NT2H1511G0DU)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 215 504bytes (NT2H1511G0DU)", spacer); else if ( tagtype & NTAG_216 ) - PrintAndLog("%sTYPE : NTAG 216 888bytes (NT2H1611G0DU)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 216 888bytes (NT2H1611G0DU)", spacer); else if ( tagtype & NTAG_I2C_1K ) - PrintAndLog("%sTYPE : NTAG I%sC 888bytes (NT3H1101FHK)", spacer, "\xFD"); - else if ( tagtype & NTAG_I2C_2K ) - PrintAndLog("%sTYPE : NTAG I%sC 1904bytes (NT3H1201FHK)", spacer, "\xFD"); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG I%sC 888bytes (NT3H1101FHK)", spacer, "\xFD"); + else if ( tagtype & NTAG_I2C_2K ) + PrintAndLogEx(NORMAL, "%sTYPE : NTAG I%sC 1904bytes (NT3H1201FHK)", spacer, "\xFD"); else if ( tagtype & MY_D ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 (SLE 66RxxS)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 (SLE 66RxxS)", spacer); else if ( tagtype & MY_D_NFC ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 NFC (SLE 66RxxP)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 NFC (SLE 66RxxP)", spacer); else if ( tagtype & MY_D_MOVE ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 move (SLE 66R01P)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move (SLE 66R01P)", spacer); else if ( tagtype & MY_D_MOVE_NFC ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 move NFC (SLE 66R01P)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move NFC (SLE 66R01P)", spacer); else if ( tagtype & MY_D_MOVE_LEAN ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 move lean (SLE 66R01L)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move lean (SLE 66R01L)", spacer); else if ( tagtype & FUDAN_UL ) - PrintAndLog("%sTYPE : FUDAN Ultralight Compatible (or other compatible) %s", spacer, (tagtype & MAGIC) ? "" : "" ); + PrintAndLogEx(NORMAL, "%sTYPE : FUDAN Ultralight Compatible (or other compatible) %s", spacer, (tagtype & MAGIC) ? "" : "" ); else - PrintAndLog("%sTYPE : Unknown %06x", spacer, tagtype); + PrintAndLogEx(NORMAL, "%sTYPE : Unknown %06x", spacer, tagtype); return 0; } static int ulc_print_3deskey( uint8_t *data){ - PrintAndLog(" deskey1 [44/0x2C] : %s [%.4s]", sprint_hex(data ,4),data); - PrintAndLog(" deskey1 [45/0x2D] : %s [%.4s]", sprint_hex(data+4 ,4),data+4); - PrintAndLog(" deskey2 [46/0x2E] : %s [%.4s]", sprint_hex(data+8 ,4),data+8); - PrintAndLog(" deskey2 [47/0x2F] : %s [%.4s]", sprint_hex(data+12,4),data+12); - PrintAndLog("\n 3des key : %s", sprint_hex(SwapEndian64(data, 16, 8), 16)); + PrintAndLogEx(NORMAL, " deskey1 [44/0x2C] : %s [%.4s]", sprint_hex(data ,4),data); + PrintAndLogEx(NORMAL, " deskey1 [45/0x2D] : %s [%.4s]", sprint_hex(data+4 ,4),data+4); + PrintAndLogEx(NORMAL, " deskey2 [46/0x2E] : %s [%.4s]", sprint_hex(data+8 ,4),data+8); + PrintAndLogEx(NORMAL, " deskey2 [47/0x2F] : %s [%.4s]", sprint_hex(data+12,4),data+12); + PrintAndLogEx(NORMAL, "\n 3des key : %s", sprint_hex(SwapEndian64(data, 16, 8), 16)); return 0; } static int ulc_print_configuration( uint8_t *data){ - PrintAndLog("--- UL-C Configuration"); - PrintAndLog(" Higher Lockbits [40/0x28] : %s - %s", sprint_hex(data, 4), printBits(2, data)); - PrintAndLog(" Counter [41/0x29] : %s - %s", sprint_hex(data+4, 4), printBits(2, data+4)); + PrintAndLogEx(NORMAL, "--- UL-C Configuration"); + PrintAndLogEx(NORMAL, " Higher Lockbits [40/0x28] : %s (binary %s %s)", + sprint_hex(data, 2), + printBits(1, data), + printBits(1, data+1) + ); + PrintAndLogEx(NORMAL, " Counter [41/0x29] : %s (binary %s %s %s %s)", + sprint_hex(data+4, 4), + printBits(1, data+4), + printBits(1, data+5), + printBits(1, data+6), + printBits(1, data+7) + ); bool validAuth = (data[8] >= 0x03 && data[8] <= 0x30); if ( validAuth ) - PrintAndLog(" Auth0 [42/0x2A] : %s page %d/0x%02X and above need authentication", sprint_hex(data+8, 4), data[8],data[8] ); + PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s page %d/0x%02X and above need authentication", sprint_hex(data+8, 4), data[8], data[8] ); else{ if ( data[8] == 0){ - PrintAndLog(" Auth0 [42/0x2A] : %s default", sprint_hex(data+8, 4) ); + PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s default", sprint_hex(data+8, 4) ); } else { - PrintAndLog(" Auth0 [42/0x2A] : %s auth byte is out-of-range", sprint_hex(data+8, 4) ); + PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s auth byte is out-of-range", sprint_hex(data+8, 4) ); } } - PrintAndLog(" Auth1 [43/0x2B] : %s %s", + PrintAndLogEx(NORMAL, " Auth1 [43/0x2B] : %s %s", sprint_hex(data+12, 4), (data[12] & 1) ? "write access restricted": "read and write access restricted" ); @@ -458,7 +506,7 @@ static int ulc_print_configuration( uint8_t *data){ static int ulev1_print_configuration( uint8_t *data, uint8_t startPage){ - PrintAndLog("\n--- Tag Configuration"); + PrintAndLogEx(NORMAL, "\n--- Tag Configuration"); bool strg_mod_en = (data[0] & 2); uint8_t authlim = (data[4] & 0x07); @@ -466,28 +514,28 @@ static int ulev1_print_configuration( uint8_t *data, uint8_t startPage){ bool prot = (data[4] & 0x80); uint8_t vctid = data[5]; - PrintAndLog(" cfg0 [%u/0x%02X] : %s", startPage, startPage, sprint_hex(data, 4)); + PrintAndLogEx(NORMAL, " cfg0 [%u/0x%02X] : %s", startPage, startPage, sprint_hex(data, 4)); if ( data[3] < 0xff ) - PrintAndLog(" - page %d and above need authentication",data[3]); - else - PrintAndLog(" - pages don't need authentication"); - PrintAndLog(" - strong modulation mode %s", (strg_mod_en) ? "enabled":"disabled"); - PrintAndLog(" cfg1 [%u/0x%02X] : %s", startPage + 1, startPage + 1, sprint_hex(data+4, 4) ); + PrintAndLogEx(NORMAL, " - page %d and above need authentication",data[3]); + else + PrintAndLogEx(NORMAL, " - pages don't need authentication"); + PrintAndLogEx(NORMAL, " - strong modulation mode %s", (strg_mod_en) ? "enabled" : "disabled"); + PrintAndLogEx(NORMAL, " cfg1 [%u/0x%02X] : %s", startPage + 1, startPage + 1, sprint_hex(data+4, 4) ); if ( authlim == 0) - PrintAndLog(" - Unlimited password attempts"); + PrintAndLogEx(NORMAL, " - Unlimited password attempts"); else - PrintAndLog(" - Max number of password attempts is %d", authlim); - PrintAndLog(" - user configuration %s", cfglck ? "permanently locked":"writeable"); - PrintAndLog(" - %s access is protected with password", prot ? "read and write":"write"); - PrintAndLog(" - %02X, Virtual Card Type Identifier is %s default", vctid, (vctid==0x05)? "":"not"); - PrintAndLog(" PWD [%u/0x%02X] : %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data+8, 4)); - PrintAndLog(" PACK [%u/0x%02X] : %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+12, 2)); - PrintAndLog(" RFU [%u/0x%02X] : %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+12, 2)); + PrintAndLogEx(NORMAL, " - Max number of password attempts is %d", authlim); + PrintAndLogEx(NORMAL, " - user configuration %s", cfglck ? "permanently locked":"writeable"); + PrintAndLogEx(NORMAL, " - %s access is protected with password", prot ? "read and write":"write"); + PrintAndLogEx(NORMAL, " - %02X, Virtual Card Type Identifier is %s default", vctid, (vctid==0x05)? "":"not"); + PrintAndLogEx(NORMAL, " PWD [%u/0x%02X] : %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data+8, 4)); + PrintAndLogEx(NORMAL, " PACK [%u/0x%02X] : %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+12, 2)); + PrintAndLogEx(NORMAL, " RFU [%u/0x%02X] : %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+14, 2)); return 0; } static int ulev1_print_counters(){ - PrintAndLog("--- Tag Counters"); + PrintAndLogEx(NORMAL, "--- Tag Counters"); uint8_t tear[1] = {0}; uint8_t counter[3] = {0,0,0}; uint16_t len = 0; @@ -495,34 +543,34 @@ static int ulev1_print_counters(){ ulev1_readTearing(i,tear,sizeof(tear)); len = ulev1_readCounter(i,counter, sizeof(counter) ); if (len == 3) { - PrintAndLog(" [%0d] : %s", i, sprint_hex(counter,3)); - PrintAndLog(" - %02X tearing %s", tear[0], ( tear[0]==0xBD)?"Ok":"failure"); + PrintAndLogEx(NORMAL, " [%0d] : %s", i, sprint_hex(counter,3)); + PrintAndLogEx(NORMAL, " - %02X tearing %s", tear[0], ( tear[0]==0xBD)?"Ok":"failure"); } } return len; } static int ulev1_print_signature( uint8_t *data, uint8_t len){ - PrintAndLog("\n--- Tag Signature"); - //PrintAndLog("IC signature public key name : NXP NTAG21x 2013"); // don't know if there is other NXP public keys.. :( - PrintAndLog("IC signature public key value : 04494e1a386d3d3cfe3dc10e5de68a499b1c202db5b132393e89ed19fe5be8bc61"); - PrintAndLog(" Elliptic curve parameters : secp128r1"); - PrintAndLog(" Tag ECC Signature : %s", sprint_hex(data, len)); + PrintAndLogEx(NORMAL, "\n--- Tag Signature"); + PrintAndLogEx(NORMAL, "IC signature public key name : NXP NTAG21x (2013)"); + PrintAndLogEx(NORMAL, "IC signature public key value : %s", sprint_hex(public_ecda_key, PUBLIC_ECDA_KEYLEN)); + PrintAndLogEx(NORMAL, " Elliptic curve parameters : secp128r1"); + PrintAndLogEx(NORMAL, " Tag ECC Signature : %s", sprint_hex(data, len)); //to do: verify if signature is valid - //PrintAndLog("IC signature status: %s valid", (iseccvalid() )?"":"not"); + //PrintAndLogEx(NORMAL, "IC signature status: %s valid", (iseccvalid() )?"":"not"); return 0; } static int ulev1_print_version(uint8_t *data){ - PrintAndLog("\n--- Tag Version"); - PrintAndLog(" Raw bytes : %s",sprint_hex(data, 8) ); - PrintAndLog(" Vendor ID : %02X, %s", data[1], getManufacturerName(data[1])); - PrintAndLog(" Product type : %s", getProductTypeStr(data[2])); - PrintAndLog(" Product subtype : %02X, %s", data[3], (data[3]==1) ?"17 pF":"50pF"); - PrintAndLog(" Major version : %02X", data[4]); - PrintAndLog(" Minor version : %02X", data[5]); - PrintAndLog(" Size : %s", getUlev1CardSizeStr(data[6])); - PrintAndLog(" Protocol type : %02X", data[7]); + PrintAndLogEx(NORMAL, "\n--- Tag Version"); + PrintAndLogEx(NORMAL, " Raw bytes : %s",sprint_hex(data, 8) ); + PrintAndLogEx(NORMAL, " Vendor ID : %02X, %s", data[1], getManufacturerName(data[1])); + PrintAndLogEx(NORMAL, " Product type : %s", getProductTypeStr(data[2])); + PrintAndLogEx(NORMAL, " Product subtype : %02X, %s", data[3], (data[3]==1) ?"17 pF":"50pF"); + PrintAndLogEx(NORMAL, " Major version : %02X", data[4]); + PrintAndLogEx(NORMAL, " Minor version : %02X", data[5]); + PrintAndLogEx(NORMAL, " Size : %s", getUlev1CardSizeStr(data[6])); + PrintAndLogEx(NORMAL, " Protocol type : %02X", data[7]); return 0; } @@ -548,7 +596,7 @@ static int ulc_magic_test(){ returnValue = ( !memcmp(nonce1, nonce2, 11) ) ? UL_C_MAGIC : UL_C; } else { returnValue = UL; - } + } DropField(); return returnValue; } @@ -556,14 +604,14 @@ static int ulc_magic_test(){ static int ul_magic_test(){ // Magic Ultralight tests - // 1) take present UID, and try to write it back. OBSOLETE + // 1) take present UID, and try to write it back. OBSOLETE // 2) make a wrong length write to page0, and see if tag answers with ACK/NACK: iso14a_card_select_t card; - if ( !ul_select(&card) ) + if ( !ul_select(&card) ) return UL_ERROR; int status = ul_comp_write(0, NULL, 0); DropField(); - if ( status == 0 ) + if ( status == 0 ) return MAGIC; return 0; } @@ -578,9 +626,9 @@ uint32_t GetHF14AMfU_Type(void){ if (!ul_select(&card)) return UL_ERROR; - // Ultralight - ATQA / SAK + // Ultralight - ATQA / SAK if ( card.atqa[1] != 0x00 || card.atqa[0] != 0x44 || card.sak != 0x00 ) { - PrintAndLog("Tag is not Ultralight | NTAG | MY-D [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak); + PrintAndLogEx(NORMAL, "Tag is not Ultralight | NTAG | MY-D [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak); DropField(); return UL_ERROR; } @@ -631,7 +679,7 @@ uint32_t GetHF14AMfU_Type(void){ DropField(); if (status > 1) { tagtype = UL_C; - } else { + } else { // need to re-select after authentication error if ( !ul_select(&card) ) return UL_ERROR; @@ -653,18 +701,18 @@ uint32_t GetHF14AMfU_Type(void){ } } if (tagtype & UL) { - tagtype = ul_fudan_check(); + tagtype = ul_fudan_check(); DropField(); } } else { DropField(); - // Infinition MY-D tests Exam high nibble + // Infinition MY-D tests Exam high nibble uint8_t nib = (card.uid[1] & 0xf0) >> 4; switch ( nib ){ // case 0: tagtype = SLE66R35E7; break; //or SLE 66R35E7 - mifare compat... should have different sak/atqa for mf 1k - case 1: tagtype = MY_D; break; //or SLE 66RxxS ... up to 512 pages of 8 user bytes... - case 2: tagtype = (MY_D_NFC); break; //or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes) - case 3: tagtype = (MY_D_MOVE | MY_D_MOVE_NFC); break; //or SLE 66R01P // 38 pages of 4 bytes //notice: we can not currently distinguish between these two + case 1: tagtype = MY_D; break; //or SLE 66RxxS ... up to 512 pages of 8 user bytes... + case 2: tagtype = (MY_D_NFC); break; //or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes) + case 3: tagtype = (MY_D_MOVE | MY_D_MOVE_NFC); break; //or SLE 66R01P // 38 pages of 4 bytes //notice: we can not currently distinguish between these two case 7: tagtype = MY_D_MOVE_LEAN; break; //or SLE 66R01L // 16 pages of 4 bytes } } @@ -674,7 +722,25 @@ uint32_t GetHF14AMfU_Type(void){ return tagtype; } -int CmdHF14AMfUInfo(const char *Cmd){ +static int usage_hf_mfu_info(void) { + PrintAndLogEx(NORMAL, "It gathers information about the tag and tries to detect what kind it is."); + PrintAndLogEx(NORMAL, "Sometimes the tags are locked down, and you may need a key to be able to read the information"); + PrintAndLogEx(NORMAL, "The following tags can be identified:\n"); + PrintAndLogEx(NORMAL, "Ultralight, Ultralight-C, Ultralight EV1, NTAG 203, NTAG 210,"); + PrintAndLogEx(NORMAL, "NTAG 212, NTAG 213, NTAG 215, NTAG 216, NTAG I2C 1K & 2K"); + PrintAndLogEx(NORMAL, "my-d, my-d NFC, my-d move, my-d move NFC\n"); + PrintAndLogEx(NORMAL, "Usage: hf mfu info k l"); + PrintAndLogEx(NORMAL, " Options : "); + PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); + PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " sample : hf mfu info"); + PrintAndLogEx(NORMAL, " : hf mfu info k 00112233445566778899AABBCCDDEEFF"); + PrintAndLogEx(NORMAL, " : hf mfu info k AABBCCDDD"); + return 0; +} + +static int CmdHF14AMfUInfo(const char *Cmd){ uint8_t authlim = 0xff; uint8_t data[16] = {0x00}; @@ -688,7 +754,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ uint8_t dataLen = 0; uint8_t authenticationkey[16] = {0x00}; uint8_t *authkeyptr = authenticationkey; - uint8_t *key; + uint8_t *key; uint8_t pack[4] = {0,0,0,0}; int len = 0; char tempStr[50]; @@ -707,7 +773,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ errors = param_gethex(tempStr, 0, authenticationkey, dataLen); dataLen /= 2; // handled as bytes from now on } else { - PrintAndLog("\nERROR: Key is incorrect length\n"); + PrintAndLogEx(ERR, "Key has incorrect length\n"); errors = true; } cmdp += 2; @@ -719,7 +785,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ cmdp++; break; default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -732,11 +798,11 @@ int CmdHF14AMfUInfo(const char *Cmd){ TagTypeUL_t tagtype = GetHF14AMfU_Type(); if (tagtype == UL_ERROR) return -1; - PrintAndLog("\n--- Tag Information ---------"); - PrintAndLog("-------------------------------------------------------------"); + PrintAndLogEx(NORMAL, "\n--- Tag Information ---------"); + PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); ul_print_type(tagtype, 6); - // Swap endianness + // Swap endianness if (swapEndian && hasAuthKey) authkeyptr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4 ); if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; @@ -745,7 +811,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ status = ul_read(0, data, sizeof(data)); if ( status == -1 ) { DropField(); - PrintAndLog("Error: tag didn't answer to READ"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ"); return status; } else if (status == 16) { ul_print_default(data); @@ -761,10 +827,10 @@ int CmdHF14AMfUInfo(const char *Cmd){ uint8_t ulc_conf[16] = {0x00}; status = ul_read(0x28, ulc_conf, sizeof(ulc_conf)); if ( status == -1 ){ - PrintAndLog("Error: tag didn't answer to READ UL-C"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ UL-C"); DropField(); return status; - } + } if (status == 16) ulc_print_configuration(ulc_conf); else locked = true; @@ -774,33 +840,33 @@ int CmdHF14AMfUInfo(const char *Cmd){ status = ul_read(0x2C, ulc_deskey, sizeof(ulc_deskey)); if ( status == -1 ) { DropField(); - PrintAndLog("Error: tag didn't answer to READ magic"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ magic"); return status; } if (status == 16) ulc_print_3deskey(ulc_deskey); } else { DropField(); - // if we called info with key, just return + // if we called info with key, just return if ( hasAuthKey ) return 1; // also try to diversify default keys.. look into CmdHF14AMfuGenDiverseKeys - PrintAndLog("Trying some default 3des keys"); + PrintAndLogEx(INFO, "Trying some default 3des keys"); for (uint8_t i = 0; i < KEYS_3DES_COUNT; ++i ) { key = default_3des_keys[i]; if (ulc_authentication(key, true)) { - PrintAndLog("Found default 3des key: "); + PrintAndLogEx(SUCCESS, "Found default 3des key: "); uint8_t keySwap[16]; memcpy(keySwap, SwapEndian64(key,16,8), 16); ulc_print_3deskey(keySwap); return 1; - } + } } return 1; } } - // do counters and signature first (don't neet auth) + // do counters and signature first (don't neet auth) // ul counters are different than ntag counters if ((tagtype & (UL_EV1_48 | UL_EV1_128))) { @@ -810,11 +876,11 @@ int CmdHF14AMfUInfo(const char *Cmd){ } } - if ((tagtype & (UL_EV1_48 | UL_EV1_128 | NTAG_213 | NTAG_215 | NTAG_216 | NTAG_I2C_1K | NTAG_I2C_2K ))) { + if ((tagtype & (UL_EV1_48 | UL_EV1_128 | NTAG_213 | NTAG_215 | NTAG_216 | NTAG_I2C_1K | NTAG_I2C_2K ))) { uint8_t ulev1_signature[32] = {0x00}; status = ulev1_readSignature( ulev1_signature, sizeof(ulev1_signature)); if ( status == -1 ) { - PrintAndLog("Error: tag didn't answer to READ SIGNATURE"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ SIGNATURE"); DropField(); return status; } @@ -829,7 +895,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ uint8_t version[10] = {0x00}; status = ulev1_getVersion(version, sizeof(version)); if ( status == -1 ) { - PrintAndLog("Error: tag didn't answer to GETVERSION"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to GETVERSION"); DropField(); return status; } else if (status == 10) { @@ -849,7 +915,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ if (startconfigblock){ // if we know where the config block is... status = ul_read(startconfigblock, ulev1_conf, sizeof(ulev1_conf)); if ( status == -1 ) { - PrintAndLog("Error: tag didn't answer to READ EV1"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ EV1"); DropField(); return status; } else if (status == 16) { @@ -864,32 +930,46 @@ int CmdHF14AMfUInfo(const char *Cmd){ // 1-7 = limit. No automatic tries then. // hasAuthKey, if we was called with key, skip test. if ( !authlim && !hasAuthKey ) { - PrintAndLog("\n--- Known EV1/NTAG passwords."); + PrintAndLogEx(NORMAL, "\n--- Known EV1/NTAG passwords."); len = 0; for (uint8_t i = 0; i < KEYS_PWD_COUNT; ++i ) { key = default_pwd_pack[i]; len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len >= 1) { - PrintAndLog("Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); break; } else { if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; } } - if (len < 1) PrintAndLog("password not known"); + if (len < 1) PrintAndLogEx(WARNING, "password not known"); } } DropField(); - if (locked) PrintAndLog("\nTag appears to be locked, try using the key to get more info"); - PrintAndLog(""); + if (locked) PrintAndLogEx(FAILED, "\nTag appears to be locked, try using the key to get more info"); + PrintAndLogEx(NORMAL, ""); return 1; } // // Write Single Block // -int CmdHF14AMfUWrBl(const char *Cmd){ +static int usage_hf_mfu_wrbl(void) { + PrintAndLogEx(NORMAL, "Write a block. It autodetects card type.\n"); + PrintAndLogEx(NORMAL, "Usage: hf mfu wrbl b d k l\n"); + PrintAndLogEx(NORMAL, " Options:"); + PrintAndLogEx(NORMAL, " b : block to write"); + PrintAndLogEx(NORMAL, " d : block data - (8 hex symbols)"); + PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); + PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " sample : hf mfu wrbl b 0 d 01234567"); + PrintAndLogEx(NORMAL, " : hf mfu wrbl b 0 d 01234567 k AABBCCDDD\n"); + return 0; +} + +static int CmdHF14AMfUWrBl(const char *Cmd){ int blockNo = -1; bool errors = false; @@ -921,7 +1001,7 @@ int CmdHF14AMfUWrBl(const char *Cmd){ hasPwdKey = true; break; } - // UL-C size key + // UL-C size key keylen = param_gethex(Cmd, cmdp+1, data, 32); if (!keylen){ memcpy(authenticationkey, data, 16); @@ -929,14 +1009,14 @@ int CmdHF14AMfUWrBl(const char *Cmd){ hasAuthKey = true; break; } - PrintAndLog("\nERROR: Key is incorrect length\n"); - errors = true; + PrintAndLogEx(ERR, "Key has incorrect length\n"); + errors = true; break; case 'b': case 'B': blockNo = param_get8(Cmd, cmdp+1); if (blockNo < 0) { - PrintAndLog("Wrong block number"); + PrintAndLogEx(ERR, "Wrong block number"); errors = true; } cmdp += 2; @@ -944,19 +1024,19 @@ int CmdHF14AMfUWrBl(const char *Cmd){ case 'l': case 'L': swapEndian = true; - cmdp++; + cmdp++; break; case 'd': case 'D': if ( param_gethex(Cmd, cmdp+1, blockdata, 8) ) { - PrintAndLog("Block data must include 8 HEX symbols"); + PrintAndLogEx(ERR, "Block data must include 8 HEX symbols"); errors = true; break; } cmdp += 2; break; default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(ERR, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -975,18 +1055,18 @@ int CmdHF14AMfUWrBl(const char *Cmd){ maxblockno = UL_MEMORY_ARRAY[idx]; } if (blockNo > maxblockno){ - PrintAndLog("block number too large. Max block is %u/0x%02X \n", maxblockno,maxblockno); + PrintAndLogEx(WARNING, "block number too large. Max block is %u/0x%02X \n", maxblockno,maxblockno); return usage_hf_mfu_wrbl(); } - // Swap endianness + // Swap endianness if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); if ( blockNo <= 3) - PrintAndLog("Special Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); + PrintAndLogEx(NORMAL, "Special Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); else - PrintAndLog("Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); + PrintAndLogEx(NORMAL, "Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); //Send write Block UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}}; @@ -1006,19 +1086,35 @@ int CmdHF14AMfUWrBl(const char *Cmd){ UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); + PrintAndLogEx(SUCCESS, "isOk:%02x", isOK); } else { - PrintAndLog("Command execute timeout"); + PrintAndLogEx(ERR, "Command execute timeout"); } return 0; } + + // // Read Single Block // -int CmdHF14AMfURdBl(const char *Cmd){ +static int usage_hf_mfu_rdbl(void) { + PrintAndLogEx(NORMAL, "Read a block and print. It autodetects card type.\n"); + PrintAndLogEx(NORMAL, "Usage: hf mfu rdbl b k l\n"); + PrintAndLogEx(NORMAL, " Options:"); + PrintAndLogEx(NORMAL, " b : block to read"); + PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); + PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " sample : hf mfu rdbl b 0"); + PrintAndLogEx(NORMAL, " : hf mfu rdbl b 0 k 00112233445566778899AABBCCDDEEFF"); + PrintAndLogEx(NORMAL, " : hf mfu rdbl b 0 k AABBCCDDD\n"); + return 0; +} - int blockNo = -1; +static int CmdHF14AMfURdBl(const char *Cmd){ + + int blockNo = -1; bool errors = false; bool hasAuthKey = false; bool hasPwdKey = false; @@ -1046,7 +1142,7 @@ int CmdHF14AMfURdBl(const char *Cmd){ hasPwdKey = true; break; } - // UL-C size key + // UL-C size key keylen = param_gethex(Cmd, cmdp+1, data, 32); if (!keylen){ memcpy(authenticationkey, data, 16); @@ -1054,14 +1150,14 @@ int CmdHF14AMfURdBl(const char *Cmd){ hasAuthKey = true; break; } - PrintAndLog("\nERROR: Key is incorrect length\n"); - errors = true; + PrintAndLogEx(ERR, "Key has incorrect length\n"); + errors = true; break; case 'b': case 'B': blockNo = param_get8(Cmd, cmdp+1); if (blockNo < 0) { - PrintAndLog("Wrong block number"); + PrintAndLogEx(ERR, "Wrong block number"); errors = true; } cmdp += 2; @@ -1072,7 +1168,7 @@ int CmdHF14AMfURdBl(const char *Cmd){ cmdp++; break; default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -1091,11 +1187,11 @@ int CmdHF14AMfURdBl(const char *Cmd){ maxblockno = UL_MEMORY_ARRAY[idx]; } if (blockNo > maxblockno){ - PrintAndLog("block number to large. Max block is %u/0x%02X \n", maxblockno,maxblockno); + PrintAndLogEx(WARNING, "block number to large. Max block is %u/0x%02X \n", maxblockno,maxblockno); return usage_hf_mfu_rdbl(); } - // Swap endianness + // Swap endianness if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); @@ -1117,90 +1213,44 @@ int CmdHF14AMfURdBl(const char *Cmd){ uint8_t isOK = resp.arg[0] & 0xff; if (isOK) { uint8_t *data = resp.d.asBytes; - PrintAndLog("\n Block# | Data | Ascii"); - PrintAndLog("---------+-------------+------"); - PrintAndLog(" %02d/0x%02X | %s| %.4s\n", blockNo, blockNo, sprint_hex(data, 4), data); - } - else { - PrintAndLog("Failed reading block: (%02x)", isOK); + PrintAndLogEx(NORMAL, "\n Block# | Data | Ascii"); + PrintAndLogEx(NORMAL, "---------+-------------+------"); + PrintAndLogEx(NORMAL, " %02d/0x%02X | %s| %s\n", blockNo, blockNo, sprint_hex(data, 4), sprint_ascii(data, 4)); + } else { + PrintAndLogEx(ERR, "Failed reading block: (%02x)", isOK); } } else { - PrintAndLog("Command execute time-out"); + PrintAndLogEx(ERR, "Command execute time-out"); } return 0; } -int usage_hf_mfu_info(void) { - PrintAndLog("It gathers information about the tag and tries to detect what kind it is."); - PrintAndLog("Sometimes the tags are locked down, and you may need a key to be able to read the information"); - PrintAndLog("The following tags can be identified:\n"); - PrintAndLog("Ultralight, Ultralight-C, Ultralight EV1, NTAG 203, NTAG 210,"); - PrintAndLog("NTAG 212, NTAG 213, NTAG 215, NTAG 216, NTAG I2C 1K & 2K"); - PrintAndLog("my-d, my-d NFC, my-d move, my-d move NFC\n"); - PrintAndLog("Usage: hf mfu info k l"); - PrintAndLog(" Options : "); - PrintAndLog(" k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLog(" l : (optional) swap entered key's endianness"); - PrintAndLog(""); - PrintAndLog(" sample : hf mfu info"); - PrintAndLog(" : hf mfu info k 00112233445566778899AABBCCDDEEFF"); - PrintAndLog(" : hf mfu info k AABBCCDDD"); - return 0; -} - -int usage_hf_mfu_dump(void) { - PrintAndLog("Reads all pages from Ultralight, Ultralight-C, Ultralight EV1"); - PrintAndLog("NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216"); - PrintAndLog("and saves binary dump into the file `filename.bin` or `cardUID.bin`"); - PrintAndLog("It autodetects card type.\n"); - PrintAndLog("Usage: hf mfu dump k l n "); - PrintAndLog(" Options : "); - PrintAndLog(" k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLog(" l : (optional) swap entered key's endianness"); - PrintAndLog(" n : filename w/o .bin to save the dump as"); - PrintAndLog(" p : starting Page number to manually set a page to start the dump at"); - PrintAndLog(" q : number of Pages to manually set how many pages to dump"); - - PrintAndLog(""); - PrintAndLog(" sample : hf mfu dump"); - PrintAndLog(" : hf mfu dump n myfile"); - PrintAndLog(" : hf mfu dump k 00112233445566778899AABBCCDDEEFF"); - PrintAndLog(" : hf mfu dump k AABBCCDDD\n"); - return 0; -} - -int usage_hf_mfu_rdbl(void) { - PrintAndLog("Read a block and print. It autodetects card type.\n"); - PrintAndLog("Usage: hf mfu rdbl b k l\n"); - PrintAndLog(" Options:"); - PrintAndLog(" b : block to read"); - PrintAndLog(" k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLog(" l : (optional) swap entered key's endianness"); - PrintAndLog(""); - PrintAndLog(" sample : hf mfu rdbl b 0"); - PrintAndLog(" : hf mfu rdbl b 0 k 00112233445566778899AABBCCDDEEFF"); - PrintAndLog(" : hf mfu rdbl b 0 k AABBCCDDD\n"); - return 0; -} - -int usage_hf_mfu_wrbl(void) { - PrintAndLog("Write a block. It autodetects card type.\n"); - PrintAndLog("Usage: hf mfu wrbl b d k l\n"); - PrintAndLog(" Options:"); - PrintAndLog(" b : block to write"); - PrintAndLog(" d : block data - (8 hex symbols)"); - PrintAndLog(" k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLog(" l : (optional) swap entered key's endianness"); - PrintAndLog(""); - PrintAndLog(" sample : hf mfu wrbl b 0 d 01234567"); - PrintAndLog(" : hf mfu wrbl b 0 d 01234567 k AABBCCDDD\n"); - return 0; -} // // Mifare Ultralight / Ultralight-C / Ultralight-EV1 // Read and Dump Card Contents, using auto detection of tag size. -int CmdHF14AMfUDump(const char *Cmd){ +static int usage_hf_mfu_dump(void) { + PrintAndLogEx(NORMAL, "Reads all pages from Ultralight, Ultralight-C, Ultralight EV1"); + PrintAndLogEx(NORMAL, "NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216"); + PrintAndLogEx(NORMAL, "and saves binary dump into the file `filename.bin` or `cardUID.bin`"); + PrintAndLogEx(NORMAL, "It autodetects card type.\n"); + PrintAndLogEx(NORMAL, "Usage: hf mfu dump k l n "); + PrintAndLogEx(NORMAL, " Options : "); + PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); + PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); + PrintAndLogEx(NORMAL, " n : filename w/o .bin to save the dump as"); + PrintAndLogEx(NORMAL, " p : starting Page number to manually set a page to start the dump at"); + PrintAndLogEx(NORMAL, " q : number of Pages to manually set how many pages to dump"); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " sample : hf mfu dump"); + PrintAndLogEx(NORMAL, " : hf mfu dump n myfile"); + PrintAndLogEx(NORMAL, " : hf mfu dump k 00112233445566778899AABBCCDDEEFF"); + PrintAndLogEx(NORMAL, " : hf mfu dump k AABBCCDDD\n"); + return 0; +} + +static int CmdHF14AMfUDump(const char *Cmd){ FILE *fout; char filename[FILE_PATH_SIZE] = {0x00}; @@ -1219,7 +1269,7 @@ int CmdHF14AMfUDump(const char *Cmd){ uint8_t dataLen = 0; uint8_t cmdp = 0; uint8_t authenticationkey[16] = {0x00}; - uint8_t *authKeyPtr = authenticationkey; + uint8_t *authKeyPtr = authenticationkey; size_t fileNlen = 0; bool errors = false; bool swapEndian = false; @@ -1242,7 +1292,7 @@ int CmdHF14AMfUDump(const char *Cmd){ errors = param_gethex(tempStr, 0, authenticationkey, dataLen); dataLen /= 2; } else { - PrintAndLog("\nERROR: Key is incorrect length\n"); + PrintAndLogEx(ERR, "Key has incorrect length\n"); errors = true; } cmdp += 2; @@ -1256,7 +1306,7 @@ int CmdHF14AMfUDump(const char *Cmd){ case 'n': case 'N': fileNlen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); - if (!fileNlen) errors = true; + if (!fileNlen) errors = true; if (fileNlen > FILE_PATH_SIZE-5) fileNlen = FILE_PATH_SIZE-5; cmdp += 2; break; @@ -1273,7 +1323,7 @@ int CmdHF14AMfUDump(const char *Cmd){ manualPages = true; break; default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -1283,7 +1333,7 @@ int CmdHF14AMfUDump(const char *Cmd){ //Validations if(errors) return usage_hf_mfu_dump(); - if (swapEndian && hasAuthKey) + if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4); TagTypeUL_t tagtype = GetHF14AMfU_Type(); @@ -1295,7 +1345,7 @@ int CmdHF14AMfUDump(const char *Cmd){ Pages = UL_MEMORY_ARRAY[idx]+1; //add one as maxblks starts at 0 ul_print_type(tagtype, 0); - PrintAndLog("Reading tag memory..."); + PrintAndLogEx(NORMAL, "Reading tag memory..."); UsbCommand c = {CMD_MIFAREU_READCARD, {startPage,Pages}}; if ( hasAuthKey ) { if (tagtype & UL_C) @@ -1310,18 +1360,18 @@ int CmdHF14AMfUDump(const char *Cmd){ SendCommand(&c); UsbCommand resp; if (!WaitForResponseTimeout(CMD_ACK, &resp,1500)) { - PrintAndLog("Command execute time-out"); + PrintAndLogEx(ERR, "Command execute time-out"); return 1; } if (resp.arg[0] != 1) { - PrintAndLog("Failed reading block: (%02x)", i); + PrintAndLogEx(ERR, "Failed reading block: (%02x)", i); return 1; } uint32_t startindex = resp.arg[2]; uint32_t bufferSize = resp.arg[1]; if (bufferSize > sizeof(data)) { - PrintAndLog("Data exceeded Buffer size!"); + PrintAndLogEx(FAILED, "Data exceeded Buffer size!"); bufferSize = sizeof(data); } GetFromBigBuf(data, bufferSize, startindex, NULL, -1, false); @@ -1358,17 +1408,17 @@ int CmdHF14AMfUDump(const char *Cmd){ if (tagtype & UL_C){ //add 4 pages memcpy(data + Pages*4, authKeyPtr, dataLen); - Pages += dataLen/4; + Pages += dataLen/4; } else { // 2nd page from end memcpy(data + (Pages*4) - 8, authenticationkey, dataLen); } } - PrintAndLog("\n Block# | Data |lck| Ascii"); - PrintAndLog("---------+-------------+---+------"); + PrintAndLogEx(NORMAL, "\n Block# | Data |lck| Ascii"); + PrintAndLogEx(NORMAL, "---------+-------------+---+------"); for (i = 0; i < Pages; ++i) { if ( i < 3 ) { - PrintAndLog("%3d/0x%02X | %s| | ", i+startPage, i+startPage, sprint_hex(data + i * 4, 4)); + PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| | ", i+startPage, i+startPage, sprint_hex(data + i * 4, 4)); continue; } switch(i){ @@ -1392,7 +1442,7 @@ int CmdHF14AMfUDump(const char *Cmd){ case 20: case 21: case 22: - case 23: tmplockbit = bit2[5]; break; + case 23: tmplockbit = bit2[5]; break; case 24: case 25: case 26: @@ -1404,11 +1454,11 @@ int CmdHF14AMfUDump(const char *Cmd){ case 32: case 33: case 34: - case 35: tmplockbit = bit2[1]; break; + case 35: tmplockbit = bit2[1]; break; case 36: case 37: case 38: - case 39: tmplockbit = bit2[0]; break; + case 39: tmplockbit = bit2[0]; break; case 40: tmplockbit = bit2[12]; break; case 41: tmplockbit = bit2[11]; break; case 42: tmplockbit = bit2[10]; break; //auth0 @@ -1420,9 +1470,9 @@ int CmdHF14AMfUDump(const char *Cmd){ memcpy(cleanASCII, data+i*4, 4); clean_ascii(cleanASCII, 4); - PrintAndLog("%3d/0x%02X | %s| %d | %.4s", i+startPage, i+startPage, sprint_hex(data + i * 4, 4), tmplockbit, cleanASCII); + PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| %d | %.4s", i+startPage, i+startPage, sprint_hex(data + i * 4, 4), tmplockbit, cleanASCII); } - PrintAndLog("---------------------------------"); + PrintAndLogEx(NORMAL, "---------------------------------"); // user supplied filename? if (fileNlen < 1) { @@ -1433,14 +1483,14 @@ int CmdHF14AMfUDump(const char *Cmd){ sprintf(fnameptr + fileNlen,".bin"); } - if ((fout = fopen(filename,"wb")) == NULL) { - PrintAndLog("Could not create file name %s", filename); + if ((fout = fopen(filename,"wb")) == NULL) { + PrintAndLogEx(NORMAL, "Could not create file name %s", filename); return 1; } fwrite( data, 1, Pages*4, fout ); fclose(fout); - - PrintAndLog("Dumped %d pages, wrote %d bytes to %s", Pages, Pages*4, filename); + + PrintAndLogEx(SUCCESS, "Dumped %d pages, wrote %d bytes to %s", Pages, Pages*4, filename); return 0; } @@ -1451,7 +1501,7 @@ int CmdHF14AMfUDump(const char *Cmd){ // // Ultralight C Authentication Demo {currently uses hard-coded key} // -int CmdHF14AMfucAuth(const char *Cmd){ +static int CmdHF14AMfucAuth(const char *Cmd){ uint8_t keyNo = 3; bool errors = false; @@ -1461,49 +1511,49 @@ int CmdHF14AMfucAuth(const char *Cmd){ //Change key to user defined one if (cmdp == 'k' || cmdp == 'K'){ keyNo = param_get8(Cmd, 1); - if(keyNo > KEYS_3DES_COUNT-1) + if(keyNo > KEYS_3DES_COUNT-1) errors = true; } if (cmdp == 'h' || cmdp == 'H') errors = true; - + if (errors) { - PrintAndLog("Usage: hf mfu cauth k "); - PrintAndLog(" 0 (default): 3DES standard key"); - PrintAndLog(" 1 : all 0x00 key"); - PrintAndLog(" 2 : 0x00-0x0F key"); - PrintAndLog(" 3 : nfc key"); - PrintAndLog(" 4 : all 0x01 key"); - PrintAndLog(" 5 : all 0xff key"); - PrintAndLog(" 6 : 0x00-0xFF key"); - PrintAndLog("\n sample : hf mfu cauth k"); - PrintAndLog(" : hf mfu cauth k 3"); + PrintAndLogEx(NORMAL, "Usage: hf mfu cauth k "); + PrintAndLogEx(NORMAL, " 0 (default): 3DES standard key"); + PrintAndLogEx(NORMAL, " 1 : all 0x00 key"); + PrintAndLogEx(NORMAL, " 2 : 0x00-0x0F key"); + PrintAndLogEx(NORMAL, " 3 : nfc key"); + PrintAndLogEx(NORMAL, " 4 : all 0x01 key"); + PrintAndLogEx(NORMAL, " 5 : all 0xff key"); + PrintAndLogEx(NORMAL, " 6 : 0x00-0xFF key"); + PrintAndLogEx(NORMAL, "\n sample : hf mfu cauth k"); + PrintAndLogEx(NORMAL, " : hf mfu cauth k 3"); return 0; - } + } uint8_t *key = default_3des_keys[keyNo]; if (ulc_authentication(key, true)) - PrintAndLog("Authentication successful. 3des key: %s",sprint_hex(key, 16)); + PrintAndLogEx(SUCCESS, "Authentication successful. 3des key: %s",sprint_hex(key, 16)); else - PrintAndLog("Authentication failed"); - + PrintAndLogEx(WARNING, "Authentication failed"); + return 0; } /** -A test function to validate that the polarssl-function works the same -was as the openssl-implementation. -Commented out, since it requires openssl +A test function to validate that the polarssl-function works the same +was as the openssl-implementation. +Commented out, since it requires openssl int CmdTestDES(const char * cmd) { - uint8_t key[16] = {0x00}; - - memcpy(key,key3_3des_data,16); + uint8_t key[16] = {0x00}; + + memcpy(key,key3_3des_data,16); DES_cblock RndA, RndB; - PrintAndLog("----------OpenSSL DES implementation----------"); + PrintAndLogEx(NORMAL, "----------OpenSSL DES implementation----------"); { uint8_t e_RndB[8] = {0x00}; unsigned char RndARndB[16] = {0x00}; @@ -1512,7 +1562,7 @@ int CmdTestDES(const char * cmd) DES_key_schedule ks1,ks2; DES_cblock key1,key2; - memcpy(key,key3_3des_data,16); + memcpy(key,key3_3des_data,16); memcpy(key1,key,8); memcpy(key2,key+8,8); @@ -1521,23 +1571,23 @@ int CmdTestDES(const char * cmd) DES_set_key((DES_cblock *)key2,&ks2); DES_random_key(&RndA); - PrintAndLog(" RndA:%s",sprint_hex(RndA, 8)); - PrintAndLog(" e_RndB:%s",sprint_hex(e_RndB, 8)); + PrintAndLogEx(NORMAL, " RndA:%s",sprint_hex(RndA, 8)); + PrintAndLogEx(NORMAL, " e_RndB:%s",sprint_hex(e_RndB, 8)); //void DES_ede2_cbc_encrypt(const unsigned char *input, // unsigned char *output, long length, DES_key_schedule *ks1, // DES_key_schedule *ks2, DES_cblock *ivec, int enc); DES_ede2_cbc_encrypt(e_RndB,RndB,sizeof(e_RndB),&ks1,&ks2,&iv,0); - PrintAndLog(" RndB:%s",sprint_hex(RndB, 8)); + PrintAndLogEx(NORMAL, " RndB:%s",sprint_hex(RndB, 8)); rol(RndB,8); memcpy(RndARndB,RndA,8); memcpy(RndARndB+8,RndB,8); - PrintAndLog(" RA+B:%s",sprint_hex(RndARndB, 16)); + PrintAndLogEx(NORMAL, " RA+B:%s",sprint_hex(RndARndB, 16)); DES_ede2_cbc_encrypt(RndARndB,RndARndB,sizeof(RndARndB),&ks1,&ks2,&e_RndB,1); - PrintAndLog("enc(RA+B):%s",sprint_hex(RndARndB, 16)); + PrintAndLogEx(NORMAL, "enc(RA+B):%s",sprint_hex(RndARndB, 16)); } - PrintAndLog("----------PolarSSL implementation----------"); + PrintAndLogEx(NORMAL, "----------PolarSSL implementation----------"); { uint8_t random_a[8] = { 0 }; uint8_t enc_random_a[8] = { 0 }; @@ -1551,8 +1601,8 @@ int CmdTestDES(const char * cmd) uint8_t output[8] = { 0 }; uint8_t iv[8] = { 0 }; - PrintAndLog(" RndA :%s",sprint_hex(random_a, 8)); - PrintAndLog(" e_RndB:%s",sprint_hex(enc_random_b, 8)); + PrintAndLogEx(NORMAL, " RndA :%s",sprint_hex(random_a, 8)); + PrintAndLogEx(NORMAL, " e_RndB:%s",sprint_hex(enc_random_b, 8)); des3_set2key_dec(&ctx, key); @@ -1564,13 +1614,13 @@ int CmdTestDES(const char * cmd) , random_b // unsigned char *output ); - PrintAndLog(" RndB:%s",sprint_hex(random_b, 8)); + PrintAndLogEx(NORMAL, " RndB:%s",sprint_hex(random_b, 8)); rol(random_b,8); memcpy(random_a_and_b ,random_a,8); memcpy(random_a_and_b+8,random_b,8); - - PrintAndLog(" RA+B:%s",sprint_hex(random_a_and_b, 16)); + + PrintAndLogEx(NORMAL, " RA+B:%s",sprint_hex(random_a_and_b, 16)); des3_set2key_enc(&ctx, key); @@ -1582,97 +1632,97 @@ int CmdTestDES(const char * cmd) , random_a_and_b // unsigned char *output ); - PrintAndLog("enc(RA+B):%s",sprint_hex(random_a_and_b, 16)); + PrintAndLogEx(NORMAL, "enc(RA+B):%s",sprint_hex(random_a_and_b, 16)); } - return 0; + return 0; } **/ -// +// // Mifare Ultralight C - Set password // -int CmdHF14AMfucSetPwd(const char *Cmd){ +static int CmdHF14AMfucSetPwd(const char *Cmd){ uint8_t pwd[16] = {0x00}; - + char cmdp = param_getchar(Cmd, 0); - - if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: hf mfu setpwd "); - PrintAndLog(" [password] - (32 hex symbols)"); - PrintAndLog(""); - PrintAndLog("sample: hf mfu setpwd 000102030405060708090a0b0c0d0e0f"); - PrintAndLog(""); + + if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') { + PrintAndLogEx(NORMAL, "Usage: hf mfu setpwd "); + PrintAndLogEx(NORMAL, " [password] - (32 hex symbols)"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "sample: hf mfu setpwd 000102030405060708090a0b0c0d0e0f"); + PrintAndLogEx(NORMAL, ""); return 0; } - + if (param_gethex(Cmd, 0, pwd, 32)) { - PrintAndLog("Password must include 32 HEX symbols"); + PrintAndLogEx(WARNING, "Password must include 32 HEX symbols"); return 1; } - - UsbCommand c = {CMD_MIFAREUC_SETPWD}; + + UsbCommand c = {CMD_MIFAREUC_SETPWD}; memcpy( c.d.asBytes, pwd, 16); clearCommandBuffer(); SendCommand(&c); UsbCommand resp; - + if (WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { if ( (resp.arg[0] & 0xff) == 1) - PrintAndLog("Ultralight-C new password: %s", sprint_hex(pwd,16)); + PrintAndLogEx(INFO, "Ultralight-C new password: %s", sprint_hex(pwd,16)); else{ - PrintAndLog("Failed writing at block %d", resp.arg[1] & 0xff); + PrintAndLogEx(ERR, "Failed writing at block %d", resp.arg[1] & 0xff); return 1; } } else { - PrintAndLog("command execution time out"); + PrintAndLogEx(ERR, "command execution time out"); return 1; } - + return 0; } // // Magic UL / UL-C tags - Set UID // -int CmdHF14AMfucSetUid(const char *Cmd){ +static int CmdHF14AMfucSetUid(const char *Cmd){ UsbCommand c; UsbCommand resp; uint8_t uid[7] = {0x00}; char cmdp = param_getchar(Cmd, 0); - - if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: hf mfu setuid "); - PrintAndLog(" [uid] - (14 hex symbols)"); - PrintAndLog("\nThis only works for Magic Ultralight tags."); - PrintAndLog(""); - PrintAndLog("sample: hf mfu setuid 11223344556677"); - PrintAndLog(""); + + if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') { + PrintAndLogEx(NORMAL, "Usage: hf mfu setuid "); + PrintAndLogEx(NORMAL, " [uid] - (14 hex symbols)"); + PrintAndLogEx(NORMAL, "\nThis only works for Magic Ultralight tags."); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "sample: hf mfu setuid 11223344556677"); + PrintAndLogEx(NORMAL, ""); return 0; } - + if (param_gethex(Cmd, 0, uid, 14)) { - PrintAndLog("UID must include 14 HEX symbols"); + PrintAndLogEx(WARNING, "UID must include 14 HEX symbols"); return 1; } - // read block2. + // read block2. c.cmd = CMD_MIFAREU_READBL; c.arg[0] = 2; clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - PrintAndLog("Command execute timeout"); + PrintAndLogEx(WARNING, "Command execute timeout"); return 2; } - + // save old block2. uint8_t oldblock2[4] = {0x00}; memcpy(resp.d.asBytes, oldblock2, 4); - + // block 0. c.cmd = CMD_MIFAREU_WRITEBL; c.arg[0] = 0; @@ -1683,10 +1733,10 @@ int CmdHF14AMfucSetUid(const char *Cmd){ clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - PrintAndLog("Command execute timeout"); + PrintAndLogEx(WARNING, "Command execute timeout"); return 3; } - + // block 1. c.arg[0] = 1; c.d.asBytes[0] = uid[3]; @@ -1696,7 +1746,7 @@ int CmdHF14AMfucSetUid(const char *Cmd){ clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { - PrintAndLog("Command execute timeout"); + PrintAndLogEx(WARNING, "Command execute timeout"); return 4; } @@ -1709,14 +1759,14 @@ int CmdHF14AMfucSetUid(const char *Cmd){ clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { - PrintAndLog("Command execute timeout"); + PrintAndLogEx(WARNING, "Command execute timeout"); return 5; } - + return 0; } -int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ +static int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ uint8_t iv[8] = { 0x00 }; uint8_t block = 0x07; @@ -1729,9 +1779,9 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ uint8_t mifarekeyB[] = { 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5 }; uint8_t dkeyA[8] = { 0x00 }; uint8_t dkeyB[8] = { 0x00 }; - + uint8_t masterkey[] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff }; - + uint8_t mix[8] = { 0x00 }; uint8_t divkey[8] = { 0x00 }; @@ -1753,26 +1803,24 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ , divkey // output ); - PrintAndLog("3DES version"); - PrintAndLog("Masterkey :\t %s", sprint_hex(masterkey,sizeof(masterkey))); - PrintAndLog("UID :\t %s", sprint_hex(uid, sizeof(uid))); - PrintAndLog("Sector :\t %0d", block); - PrintAndLog("Mifare key :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA))); - PrintAndLog("Message :\t %s", sprint_hex(mix, sizeof(mix))); - PrintAndLog("Diversified key: %s", sprint_hex(divkey+1, 6)); - - PrintAndLog("\n DES version"); + PrintAndLogEx(NORMAL, "-- 3DES version"); + PrintAndLogEx(NORMAL, "Masterkey :\t %s", sprint_hex(masterkey,sizeof(masterkey))); + PrintAndLogEx(NORMAL, "UID :\t %s", sprint_hex(uid, sizeof(uid))); + PrintAndLogEx(NORMAL, "Block :\t %0d", block); + PrintAndLogEx(NORMAL, "Mifare key :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA))); + PrintAndLogEx(NORMAL, "Message :\t %s", sprint_hex(mix, sizeof(mix))); + PrintAndLogEx(NORMAL, "Diversified key: %s", sprint_hex(divkey+1, 6)); for (int i=0; i < sizeof(mifarekeyA); ++i){ dkeyA[i] = (mifarekeyA[i] << 1) & 0xff; dkeyA[6] |= ((mifarekeyA[i] >> 7) & 1) << (i+1); } - + for (int i=0; i < sizeof(mifarekeyB); ++i){ dkeyB[1] |= ((mifarekeyB[i] >> 7) & 1) << (i+1); dkeyB[2+i] = (mifarekeyB[i] << 1) & 0xff; } - + uint8_t zeros[8] = {0x00}; uint8_t newpwd[8] = {0x00}; uint8_t dmkey[24] = {0x00}; @@ -1790,17 +1838,18 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ , zeros // input , newpwd // output ); - - PrintAndLog("Mifare dkeyA :\t %s", sprint_hex(dkeyA, sizeof(dkeyA))); - PrintAndLog("Mifare dkeyB :\t %s", sprint_hex(dkeyB, sizeof(dkeyB))); - PrintAndLog("Mifare ABA :\t %s", sprint_hex(dmkey, sizeof(dmkey))); - PrintAndLog("Mifare Pwd :\t %s", sprint_hex(newpwd, sizeof(newpwd))); - + + PrintAndLogEx(NORMAL, "\n-- DES version"); + PrintAndLogEx(NORMAL, "Mifare dkeyA :\t %s", sprint_hex(dkeyA, sizeof(dkeyA))); + PrintAndLogEx(NORMAL, "Mifare dkeyB :\t %s", sprint_hex(dkeyB, sizeof(dkeyB))); + PrintAndLogEx(NORMAL, "Mifare ABA :\t %s", sprint_hex(dmkey, sizeof(dmkey))); + PrintAndLogEx(NORMAL, "Mifare Pwd :\t %s", sprint_hex(newpwd, sizeof(newpwd))); + return 0; } // static uint8_t * diversify_key(uint8_t * key){ - + // for(int i=0; i<16; i++){ // if(i<=6) key[i]^=cuid[i]; // if(i>6) key[i]^=cuid[i%7]; @@ -1810,7 +1859,7 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ // static void GenerateUIDe( uint8_t *uid, uint8_t len){ // for (int i=0; i -typedef enum TAGTYPE_UL { - UNKNOWN = 0x000000, - UL = 0x000001, - UL_C = 0x000002, - UL_EV1_48 = 0x000004, - UL_EV1_128 = 0x000008, - NTAG = 0x000010, - NTAG_203 = 0x000020, - NTAG_210 = 0x000040, - NTAG_212 = 0x000080, - NTAG_213 = 0x000100, - NTAG_215 = 0x000200, - NTAG_216 = 0x000400, - MY_D = 0x000800, - MY_D_NFC = 0x001000, - MY_D_MOVE = 0x002000, - MY_D_MOVE_NFC = 0x004000, - MY_D_MOVE_LEAN= 0x008000, - NTAG_I2C_1K = 0x010000, - NTAG_I2C_2K = 0x020000, - FUDAN_UL = 0x040000, - MAGIC = 0x080000, - UL_MAGIC = UL | MAGIC, - UL_C_MAGIC = UL_C | MAGIC, - UL_ERROR = 0xFFFFFF, -} TagTypeUL_t; +extern int CmdHFMFUltra(const char *Cmd); +extern uint32_t GetHF14AMfU_Type(void); +extern int ul_print_type(uint32_t tagtype, uint8_t spacer); #endif diff --git a/client/util.c b/client/util.c index f13d730c..eef97e2a 100644 --- a/client/util.c +++ b/client/util.c @@ -268,6 +268,10 @@ char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_st return buf; } +char *sprint_ascii(const uint8_t *data, const size_t len) { + return sprint_ascii_ex(data, len, 0); +} + void num_to_bytes(uint64_t n, size_t len, uint8_t* dest) { while (len--) { @@ -329,7 +333,7 @@ uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockS } //assumes little endian -char * printBits(size_t const size, void const * const ptr) +char *printBits(size_t const size, void const * const ptr) { unsigned char *b = (unsigned char*) ptr; unsigned char byte; diff --git a/client/util.h b/client/util.h index 29dd7d5c..18482dfe 100644 --- a/client/util.h +++ b/client/util.h @@ -101,6 +101,7 @@ extern char *sprint_hex_inrow_ex(const uint8_t *data, const size_t len, const si extern char *sprint_bin(const uint8_t * data, const size_t len); extern char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks); extern char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_str_len); +extern char *sprint_ascii(const uint8_t *data, const size_t len); extern void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); extern uint64_t bytes_to_num(uint8_t* src, size_t len); -- 2.39.5 From caaa4293ad077ba5cf2205288984a3f470464286 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 28 May 2019 07:50:58 +0200 Subject: [PATCH 12/16] fix 'lf pcf7931 bruteforce' (bug reported in http://www.proxmark.org/forum/viewtopic.php?id=6490) (#824) (and whitespace fixes) --- armsrc/pcf7931.c | 116 ++++++++++++++++++++---------------------- client/cmdlfpcf7931.c | 56 ++++++++++---------- 2 files changed, 83 insertions(+), 89 deletions(-) diff --git a/armsrc/pcf7931.c b/armsrc/pcf7931.c index 9aa0d9be..e3bac386 100644 --- a/armsrc/pcf7931.c +++ b/armsrc/pcf7931.c @@ -13,11 +13,11 @@ size_t DemodPCF7931(uint8_t **outBlocks) { uint8_t bits[256] = {0x00}; uint8_t blocks[8][16]; uint8_t *dest = BigBuf_get_addr(); - + int GraphTraceLen = BigBuf_max_traceLen(); if (GraphTraceLen > 18000) GraphTraceLen = 18000; - + int i, j, lastval, bitidx, half_switch; int clock = 64; int tolerance = clock / 8; @@ -107,7 +107,7 @@ size_t DemodPCF7931(uint8_t **outBlocks) { for(j = 0; j < 16; ++j) { blocks[num_blocks][j] = 128 * bits[j*8 + 7]+ - 64 * bits[j*8 + 6] + + 64 * bits[j*8 + 6] + 32 * bits[j*8 + 5] + 16 * bits[j*8 + 4] + 8 * bits[j*8 + 3] + @@ -161,44 +161,44 @@ bool IsBlock1PCF7931(uint8_t *block) { void ReadPCF7931() { int found_blocks = 0; // successfully read blocks - int max_blocks = 8; // readable blocks + int max_blocks = 8; // readable blocks uint8_t memory_blocks[8][17]; // PCF content - + uint8_t single_blocks[8][17]; // PFC blocks with unknown position int single_blocks_cnt = 0; - size_t n = 0; // transmitted blocks + size_t n = 0; // transmitted blocks uint8_t tmp_blocks[4][16]; // temporary read buffer - + uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found int errors = 0; // error counter int tries = 0; // tries counter - + memset(memory_blocks, 0, 8*17*sizeof(uint8_t)); memset(single_blocks, 0, 8*17*sizeof(uint8_t)); - + int i = 0, j = 0; do { i = 0; - + memset(tmp_blocks, 0, 4*16*sizeof(uint8_t)); n = DemodPCF7931((uint8_t**)tmp_blocks); if(!n) ++errors; - - // exit if no block is received + + // exit if no block is received if (errors >= 10 && found_blocks == 0 && single_blocks_cnt == 0) { Dbprintf("Error, no tag or bad tag"); return; } - // exit if too many errors during reading + // exit if too many errors during reading if (tries > 50 && (2*errors > tries)) { Dbprintf("Error reading the tag"); Dbprintf("Here is the partial content"); goto end; } - + // our logic breaks if we don't get at least two blocks if (n < 2) { if (n == 0 || !memcmp(tmp_blocks[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) @@ -219,12 +219,12 @@ void ReadPCF7931() { } ++tries; continue; - } - - Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors); + } + + Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors); i = 0; - if(!found_0_1) { + if(!found_0_1) { while (i < n - 1) { if (IsBlock0PCF7931(tmp_blocks[i]) && IsBlock1PCF7931(tmp_blocks[i+1])) { found_0_1 = 1; @@ -234,9 +234,9 @@ void ReadPCF7931() { // block 1 tells how many blocks are going to be sent max_blocks = MAX((memory_blocks[1][14] & 0x7f), memory_blocks[1][15]) + 1; found_blocks = 2; - + Dbprintf("Found blocks 0 and 1. PCF is transmitting %d blocks.", max_blocks); - + // handle the following blocks for (j = i + 2; j < n; ++j) { memcpy(memory_blocks[found_blocks], tmp_blocks[j], 16); @@ -297,14 +297,14 @@ void ReadPCF7931() { Dbprintf("", i); } Dbprintf("-----------------------------------------"); - + if (found_blocks < max_blocks) { Dbprintf("-----------------------------------------"); Dbprintf("Blocks with unknown position:"); Dbprintf("-----------------------------------------"); for (i = 0; i < single_blocks_cnt; ++i) print_result("Block", single_blocks[i], 16); - + Dbprintf("-----------------------------------------"); } cmd_send(CMD_ACK,0,0,0,0,0); @@ -332,42 +332,42 @@ static void RealWritePCF7931(uint8_t *pass, uint16_t init_delay, int32_t l, int3 AddBytePCF7931(pass[6], tab, l, p); //programming mode (0 or 1) AddBitPCF7931(0, tab, l, p); - + //block adress on 6 bits for (u = 0; u < 6; ++u) { - if (address & (1 << u)) { // bit 1 + if (address & (1 << u)) { // bit 1 ++parity; AddBitPCF7931(1, tab, l, p); - } else { // bit 0 + } else { // bit 0 AddBitPCF7931(0, tab, l, p); } } - + //byte address on 4 bits for (u = 0; u < 4; ++u) { - if (byte & (1 << u)) { // bit 1 + if (byte & (1 << u)) { // bit 1 parity++; AddBitPCF7931(1, tab, l, p); } - else // bit 0 + else // bit 0 AddBitPCF7931(0, tab, l, p); } - + //data on 8 bits for (u=0; u<8; u++) { - if (data&(1<> 8) & 0xFF; - pass_array[2] = (password >> 16) & 0xFF; - pass_array[3] = (password >> 24) & 0xFF; - pass_array[4] = (password >> 32) & 0xFF; - pass_array[5] = (password >> 40) & 0xFF; - pass_array[6] = (password >> 48) & 0xFF; + + num_to_bytes(password, 7, pass_array); Dbprintf("Trying: %02x %02x %02x %02x %02x %02x %02x ...", pass_array[0], @@ -417,7 +411,7 @@ void BruteForcePCF7931(uint64_t password, uint8_t tries, uint16_t init_delay, in pass_array[4], pass_array[5], pass_array[6]); - + for (i = 0; i < tries; ++i) RealWritePCF7931 ( @@ -429,15 +423,15 @@ void BruteForcePCF7931(uint64_t password, uint8_t tries, uint16_t init_delay, in 7, 0x01 ); - - ++password; + + ++password; } } /* Write on a byte of a PCF7931 tag * @param address : address of the block to write @param byte : address of the byte to write - @param data : data to write + @param data : data to write */ void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) { Dbprintf("Initialization delay : %d us", init_delay); @@ -446,9 +440,9 @@ void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, ui Dbprintf("Block address : %02x", address); Dbprintf("Byte address : %02x", byte); Dbprintf("Data : %02x", data); - + uint8_t password[7] = {pass1, pass2, pass3, pass4, pass5, pass6, pass7}; - + RealWritePCF7931 (password, init_delay, l, p, address, byte, data); } @@ -488,7 +482,7 @@ void SendCmdPCF7931(uint32_t * tab) { HIGH(GPIO_SSC_DOUT); while(tempo != tab[u]) tempo = AT91C_BASE_TC0->TC_CV; - + // stop modulating antenna LOW(GPIO_SSC_DOUT); while(tempo != tab[u+1]) @@ -510,7 +504,7 @@ void SendCmdPCF7931(uint32_t * tab) { } -/* Add a byte for building the data frame of PCF7931 tags +/* Add a byte for building the data frame of PCF7931 tags * @param b : byte to add * @param tab : array of the data frame * @param l : offset on low pulse width @@ -519,7 +513,7 @@ void SendCmdPCF7931(uint32_t * tab) { bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p) { uint32_t u; for (u = 0; u < 8; ++u) { - if (byte & (1 << u)) { //bit is 1 + if (byte & (1 << u)) { //bit is 1 if(AddBitPCF7931(1, tab, l, p)==1)return 1; } else { //bit is 0 if(AddBitPCF7931(0, tab, l, p)==1)return 1; @@ -529,7 +523,7 @@ bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p) { return 0; } -/* Add a bits for building the data frame of PCF7931 tags +/* Add a bits for building the data frame of PCF7931 tags * @param b : bit to add * @param tab : array of the data frame * @param l : offset on low pulse width @@ -540,23 +534,23 @@ bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p) { for (u = 0; tab[u] != 0; u += 3){} //we put the cursor at the last value of the array - if (b == 1) { //add a bit 1 - if (u == 0) tab[u] = 34 * T0_PCF + p; - else tab[u] = 34 * T0_PCF + tab[u-1] + p; + if (b == 1) { //add a bit 1 + if (u == 0) tab[u] = 34 * T0_PCF + p; + else tab[u] = 34 * T0_PCF + tab[u-1] + p; tab[u+1] = 6 * T0_PCF+tab[u] + l; tab[u+2] = 88 * T0_PCF+tab[u + 1] - l - p; return 0; - } else { //add a bit 0 + } else { //add a bit 0 - if (u == 0) tab[u] = 98 * T0_PCF + p; - else tab[u] = 98 * T0_PCF + tab[u-1] + p; + if (u == 0) tab[u] = 98 * T0_PCF + p; + else tab[u] = 98 * T0_PCF + tab[u-1] + p; tab[u + 1] = 6 * T0_PCF + tab[u] + l; tab[u + 2] = 24 * T0_PCF + tab[u + 1] - l - p; return 0; } - + return 1; } @@ -570,8 +564,8 @@ bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t * tab) { uint32_t u = 0; for(u = 0; tab[u] != 0; u += 3){} //we put the cursor at the last value of the array - if (u == 0) tab[u] = a; - else tab[u] = a + tab[u - 1]; + if (u == 0) tab[u] = a; + else tab[u] = a + tab[u - 1]; tab[u + 1] = b + tab[u]; tab[u + 2] = c + tab[u + 1]; diff --git a/client/cmdlfpcf7931.c b/client/cmdlfpcf7931.c index 9882da5f..74bc3b3e 100644 --- a/client/cmdlfpcf7931.c +++ b/client/cmdlfpcf7931.c @@ -1,7 +1,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 2012 Chalk // 2015 Dake -// 2018 sguerrini97 +// 2018 sguerrini97 // This code is licensed to you under the terms of the GNU GPL, version 2 or, // at your option, any later version. See the LICENSE.txt file for the text of @@ -33,7 +33,7 @@ static int CmdHelp(const char *Cmd); struct pcf7931_config configPcf = { {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}, PCF7931_DEFAULT_INITDELAY, - PCF7931_DEFAULT_OFFSET_WIDTH, + PCF7931_DEFAULT_OFFSET_WIDTH, PCF7931_DEFAULT_OFFSET_POSITION }; @@ -41,8 +41,8 @@ struct pcf7931_config configPcf = { int pcf7931_resetConfig(){ memset(configPcf.Pwd, 0xFF, sizeof(configPcf.Pwd) ); configPcf.InitDelay = PCF7931_DEFAULT_INITDELAY; - configPcf.OffsetWidth = PCF7931_DEFAULT_OFFSET_WIDTH; - configPcf.OffsetPosition = PCF7931_DEFAULT_OFFSET_POSITION; + configPcf.OffsetWidth = PCF7931_DEFAULT_OFFSET_WIDTH; + configPcf.OffsetPosition = PCF7931_DEFAULT_OFFSET_POSITION; return 0; } @@ -103,7 +103,7 @@ int usage_pcf7931_config(){ PrintAndLog(" pwd Password, hex, 7bytes, LSB-order"); PrintAndLog(" delay Tag initialization delay (in us) decimal"); PrintAndLog(" offset Low pulses width (in us) decimal"); - PrintAndLog(" offset Low pulses position (in us) decimal"); + PrintAndLog(" offset Low pulses position (in us) decimal"); PrintAndLog("Examples:"); PrintAndLog(" lf pcf7931 config"); PrintAndLog(" lf pcf7931 config r"); @@ -112,7 +112,7 @@ int usage_pcf7931_config(){ return 0; } -int CmdLFPCF7931Read(const char *Cmd){ +int CmdLFPCF7931Read(const char *Cmd){ uint8_t ctmp = param_getchar(Cmd, 0); if ( ctmp == 'H' || ctmp == 'h' ) return usage_pcf7931_read(); @@ -128,12 +128,12 @@ int CmdLFPCF7931Read(const char *Cmd){ return 0; } -int CmdLFPCF7931Config(const char *Cmd){ +int CmdLFPCF7931Config(const char *Cmd){ uint8_t ctmp = param_getchar(Cmd, 0); if ( ctmp == 0) return pcf7931_printConfig(); if ( ctmp == 'H' || ctmp == 'h' ) return usage_pcf7931_config(); - if ( ctmp == 'R' || ctmp == 'r' ) return pcf7931_resetConfig(); + if ( ctmp == 'R' || ctmp == 'r' ) return pcf7931_resetConfig(); if ( param_gethex(Cmd, 0, configPcf.Pwd, 14) ) return usage_pcf7931_config(); @@ -148,17 +148,17 @@ int CmdLFPCF7931Config(const char *Cmd){ int CmdLFPCF7931Write(const char *Cmd){ uint8_t ctmp = param_getchar(Cmd, 0); - if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_write(); + if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_write(); uint8_t block = 0, bytepos = 0, data = 0; - + if ( param_getdec(Cmd, 0, &block) ) return usage_pcf7931_write(); if ( param_getdec(Cmd, 1, &bytepos) ) return usage_pcf7931_write(); - + if ( (block > 7) || (bytepos > 15) ) return usage_pcf7931_write(); data = param_get8ex(Cmd, 2, 0, 16); - + PrintAndLog("Writing block: %d", block); PrintAndLog(" pos: %d", bytepos); PrintAndLog(" data: 0x%02X", data); @@ -178,27 +178,27 @@ int CmdLFPCF7931Write(const char *Cmd){ int CmdLFPCF7931BruteForce(const char *Cmd){ uint8_t ctmp = param_getchar(Cmd, 0); - if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_bruteforce(); + if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_bruteforce(); - uint64_t start_password = 0; + uint8_t start_password[7] = {0}; uint8_t tries = 3; - - if (param_gethex(Cmd, 0, (uint8_t*)(&start_password), 14)) return usage_pcf7931_bruteforce(); + + if (param_gethex(Cmd, 0, start_password, 14)) return usage_pcf7931_bruteforce(); if (param_getdec(Cmd, 1, &tries)) return usage_pcf7931_bruteforce(); - + PrintAndLog("Bruteforcing from password: %02x %02x %02x %02x %02x %02x %02x", - start_password & 0xFF, - (start_password >> 8) & 0xFF, - (start_password >> 16) & 0xFF, - (start_password >> 24) & 0xFF, - (start_password >> 32) & 0xFF, - (start_password >> 48) & 0xFF, - (start_password >> 56) & 0xFF); - + start_password[0], + start_password[1], + start_password[2], + start_password[3], + start_password[4], + start_password[5], + start_password[6]); + PrintAndLog("Trying each password %d times", tries); - UsbCommand c = {CMD_PCF7931_BRUTEFORCE, {start_password, tries} }; - + UsbCommand c = {CMD_PCF7931_BRUTEFORCE, {bytes_to_num(start_password, 7), tries} }; + c.d.asDwords[7] = (configPcf.OffsetWidth + 128); c.d.asDwords[8] = (configPcf.OffsetPosition + 128); c.d.asDwords[9] = configPcf.InitDelay; @@ -209,7 +209,7 @@ int CmdLFPCF7931BruteForce(const char *Cmd){ return 0; } -static command_t CommandTable[] = +static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"read", CmdLFPCF7931Read, 0, "Read content of a PCF7931 transponder"}, -- 2.39.5 From d38bb3acc3957efdac0204f147de1d8494a03966 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Wed, 29 May 2019 18:57:17 +0200 Subject: [PATCH 13/16] Specify that we need TCP and not UDP connection (#828) --- uart/uart_posix.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/uart/uart_posix.c b/uart/uart_posix.c index 214cb56a..29a02cf7 100644 --- a/uart/uart_posix.c +++ b/uart/uart_posix.c @@ -80,7 +80,7 @@ serial_port uart_open(const char* pcPortName) if (sp == 0) return INVALID_SERIAL_PORT; if (memcmp(pcPortName, "tcp:", 4) == 0) { - struct addrinfo *addr, *rp; + struct addrinfo *addr = NULL, *rp; char *addrstr = strdup(pcPortName + 4); if (addrstr == NULL) { printf("Error: strdup\n"); @@ -98,7 +98,13 @@ serial_port uart_open(const char* pcPortName) } else portstr = "7901"; - int s = getaddrinfo(addrstr, portstr, NULL, &addr); + struct addrinfo info; + + memset (&info, 0, sizeof(info)); + + info.ai_socktype = SOCK_STREAM; + + int s = getaddrinfo(addrstr, portstr, &info, &addr); if (s != 0) { printf("Error: getaddrinfo: %s\n", gai_strerror(s)); return INVALID_SERIAL_PORT; -- 2.39.5 From b8dd1ef6490a49784c797e9312df8622445e28dd Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Thu, 6 Jun 2019 07:33:12 +0200 Subject: [PATCH 14/16] upgrading 'hf mfu' (#830) * chg: write new dump file format by @mceloff * chg: rename 'hf mfu dump' option 'n' to 'f' to align with other commands and RRG repo * chg: replace ISO14443A_CMD_READBLOCK by MIFARE_CMD_READBLOCK, same for WRITEBLOCK * fix: mifare_ultra_readblock() returned 14 bytes instead of 16 * chg: param_gethex_ex() now checks maximum output buffer length * chg: ul_comp_write() was incomplete and for magic testing only * fix: 16bit ULC counter had been displayed as 32bit * chg: add check for 7 Byte UID, drop check for ATQA in type identification GetHF14AMfU_Type() * fix: send HALT instead of dropping field in order to maintain a defined state * chg: DropField() when command ends * chg: check for invalid page ranges in 'hf mfu dump' * fix: print correct lock bits when page range is used * fix: do not write (incomplete) dumpfile when page range is used * add: use UID for filename when no filename is given (RRG repo) * chg: don't clear trace on each ULC authentication, clear trace at beginning of each command * fix: don't send (DESFire?) deselect command after authentication --- armsrc/apps.h | 2 - armsrc/iclass.c | 5 +- armsrc/mifarecmd.c | 82 ++- armsrc/mifaresim.c | 8 +- armsrc/mifareutil.c | 2 +- armsrc/mifareutil.h | 5 - client/cmdhflist.c | 4 +- client/cmdhfmf.c | 13 +- client/cmdhfmfu.c | 1200 +++++++++++++++++++++---------------------- client/util.c | 17 +- common/protocols.h | 67 +-- 11 files changed, 681 insertions(+), 724 deletions(-) diff --git a/armsrc/apps.h b/armsrc/apps.h index 72a62628..d1c885ab 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -142,8 +142,6 @@ void MifareDES_Auth1(uint8_t arg0,uint8_t arg1,uint8_t arg2, uint8_t *datain); void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain); int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout); size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout); -void OnSuccess(); -void OnError(uint8_t reason); /// iclass.h diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 83c9a75b..7ffac62d 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1963,7 +1963,10 @@ void iClass_Dump(uint8_t blockno, uint8_t numblks) { uint8_t *dataout = BigBuf_malloc(255*8); if (dataout == NULL){ Dbprintf("out of memory"); - OnError(1); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + cmd_send(CMD_ACK,0,1,0,0,0); + LED_A_OFF(); return; } memset(dataout,0xFF,255*8); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 14ce1bcc..a3807cf7 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -23,24 +23,42 @@ #define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) #define HARDNESTED_PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication +/* // the block number for the ISO14443-4 PCB static uint8_t pcb_blocknum = 0; // Deselect card by sending a s-block. the crc is precalced for speed static uint8_t deselect_cmd[] = {0xc2,0xe0,0xb4}; +static void OnSuccess(){ + pcb_blocknum = 0; + ReaderTransmit(deselect_cmd, 3 , NULL); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} +*/ + +static void OnError(uint8_t reason){ + // pcb_blocknum = 0; + // ReaderTransmit(deselect_cmd, 3 , NULL); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + cmd_send(CMD_ACK,0,reason,0,0,0); + LED_A_OFF(); +} + //----------------------------------------------------------------------------- // Select, Authenticate, Read a MIFARE tag. // read block //----------------------------------------------------------------------------- void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { - // params + LED_A_ON(); + uint8_t blockNo = arg0; uint8_t keyType = arg1; uint64_t ui64Key = 0; ui64Key = bytes_to_num(datain, 6); - // variables byte_t isOK = 0; byte_t dataoutbuf[16]; uint8_t uid[10]; @@ -53,10 +71,6 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) clear_trace(); - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - while (true) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); @@ -97,21 +111,18 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){ + LED_A_ON(); bool turnOffField = (arg0 == 1); - LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - clear_trace(); - - if(!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { + if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card"); OnError(0); return; }; - if(!mifare_ultra_auth(keybytes)){ + if (!mifare_ultra_auth(keybytes)){ if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Authentication failed"); OnError(1); return; @@ -119,9 +130,11 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){ if (turnOffField) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); } + cmd_send(CMD_ACK,1,0,0,0,0); + LED_A_OFF(); } // Arg0 = BlockNo, @@ -129,17 +142,15 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){ // datain = PWD bytes, void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) { + LED_A_ON(); + uint8_t blockNo = arg0; byte_t dataout[16] = {0x00}; bool useKey = (arg1 == 1); //UL_C bool usePwd = (arg1 == 2); //UL_EV1/NTAG - LEDsoff(); - LED_A_ON(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - clear_trace(); - int len = iso14443a_select_card(NULL, NULL, NULL, true, 0, true); if(!len) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%02X)",len); @@ -148,7 +159,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) } // UL-C authentication - if ( useKey ) { + if (useKey) { uint8_t key[16] = {0x00}; memcpy(key, datain, sizeof(key) ); @@ -159,7 +170,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) } // UL-EV1 / NTAG authentication - if ( usePwd ) { + if (usePwd) { uint8_t pwd[4] = {0x00}; memcpy(pwd, datain, 4); uint8_t pack[4] = {0,0,0,0}; @@ -169,13 +180,13 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) } } - if( mifare_ultra_readblock(blockNo, dataout) ) { + if (mifare_ultra_readblock(blockNo, dataout)) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Read block error"); OnError(2); return; } - if( mifare_ultra_halt() ) { + if (mifare_ultra_halt()) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Halt error"); OnError(3); return; @@ -183,7 +194,8 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) cmd_send(CMD_ACK,1,0,0,dataout,16); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); + LED_A_OFF(); } //----------------------------------------------------------------------------- @@ -259,13 +271,11 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // datain = KEY bytes void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) { - LEDsoff(); LED_A_ON(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); // free eventually allocated BigBuf memory BigBuf_free(); - clear_trace(); // params uint8_t blockNo = arg0; @@ -288,7 +298,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) } // UL-C authentication - if ( useKey ) { + if (useKey) { uint8_t key[16] = {0x00}; memcpy(key, datain, sizeof(key) ); @@ -340,14 +350,14 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) return; } - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Blocks read %d", countblocks); + if (MF_DBGLEVEL >= MF_DBG_DEBUG) Dbprintf("Blocks read %d", countblocks); - countblocks *= 4; + cmd_send(CMD_ACK, 1, countblocks*4, BigBuf_max_traceLen(), 0, 0); - cmd_send(CMD_ACK, 1, countblocks, BigBuf_max_traceLen(), 0, 0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); BigBuf_free(); + LED_A_OFF(); } //----------------------------------------------------------------------------- @@ -1598,17 +1608,3 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){ LEDsoff(); } -void OnSuccess(){ - pcb_blocknum = 0; - ReaderTransmit(deselect_cmd, 3 , NULL); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -} - -void OnError(uint8_t reason){ - pcb_blocknum = 0; - ReaderTransmit(deselect_cmd, 3 , NULL); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - cmd_send(CMD_ACK,0,reason,0,0,0); - LEDsoff(); -} diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c index 6f97e1b4..137a586d 100644 --- a/armsrc/mifaresim.c +++ b/armsrc/mifaresim.c @@ -542,8 +542,8 @@ void MifareSim(uint8_t flags, uint8_t exitAfterNReads, uint8_t cardsize, uint8_t break; } - if(receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK - || receivedCmd_dec[0] == ISO14443A_CMD_WRITEBLOCK + if(receivedCmd_dec[0] == MIFARE_CMD_READBLOCK + || receivedCmd_dec[0] == MIFARE_CMD_WRITEBLOCK || receivedCmd_dec[0] == MIFARE_CMD_INC || receivedCmd_dec[0] == MIFARE_CMD_DEC || receivedCmd_dec[0] == MIFARE_CMD_RESTORE @@ -562,7 +562,7 @@ void MifareSim(uint8_t flags, uint8_t exitAfterNReads, uint8_t cardsize, uint8_t } } - if (receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK) { + if (receivedCmd_dec[0] == MIFARE_CMD_READBLOCK) { uint8_t blockNo = receivedCmd_dec[1]; emlGetMem(response, blockNo, 1); if (IsSectorTrailer(blockNo)) { @@ -593,7 +593,7 @@ void MifareSim(uint8_t flags, uint8_t exitAfterNReads, uint8_t cardsize, uint8_t break; } - if (receivedCmd_dec[0] == ISO14443A_CMD_WRITEBLOCK) { + if (receivedCmd_dec[0] == MIFARE_CMD_WRITEBLOCK) { uint8_t blockNo = receivedCmd_dec[1]; EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); FpgaDisableTracing(); diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 36e29721..647305e8 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -451,7 +451,7 @@ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) return result; } - memcpy(blockData, receivedAnswer, 14); + memcpy(blockData, receivedAnswer, 16); return 0; } diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index 589f780b..856040ca 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -25,11 +25,6 @@ #define AUTH_FIRST 0 #define AUTH_NESTED 2 -// mifare 4bit card answers -#define CARD_ACK 0x0A // 1010 - ACK -#define CARD_NACK_NA 0x04 // 0100 - NACK, not allowed (command not allowed) -#define CARD_NACK_TR 0x05 // 0101 - NACK, transmission error - // reader voltage field detector #define MF_MINFIELDV 4000 diff --git a/client/cmdhflist.c b/client/cmdhflist.c index 4499cd0d..5384bfce 100644 --- a/client/cmdhflist.c +++ b/client/cmdhflist.c @@ -415,8 +415,8 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) case ISO14443A_CMD_REQA: snprintf(exp,size,"REQA"); break; - case ISO14443A_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break; - case ISO14443A_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break; + case MIFARE_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break; + case MIFARE_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break; case ISO14443A_CMD_HALT: snprintf(exp,size,"HALT"); MifareAuthState = masNone; diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 38b7f988..ef48b825 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1516,8 +1516,11 @@ int CmdHF14AMfSim(const char *Cmd) { break; case 'u': case 'U': - param_gethex_ex(Cmd, cmdp+1, uid, &uidlen); - switch(uidlen) { + uidlen = 14; + if (param_gethex_ex(Cmd, cmdp+1, uid, &uidlen)) { + return usage_hf14_mfsim(); + } + switch (uidlen) { case 14: flags = FLAG_7B_UID_IN_DATA; break; case 8: flags = FLAG_4B_UID_IN_DATA; break; default: return usage_hf14_mfsim(); @@ -2726,9 +2729,9 @@ int CmdHF14AMfSniff(const char *Cmd){ //needs nt, ar, at, Data to decrypt int CmdDecryptTraceCmds(const char *Cmd){ uint8_t data[50]; - int len = 0; - param_gethex_ex(Cmd,3,data,&len); - return tryDecryptWord(param_get32ex(Cmd,0,0,16),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16),data,len/2); + int len = 100; + param_gethex_ex(Cmd, 3, data, &len); + return tryDecryptWord(param_get32ex(Cmd, 0, 0, 16), param_get32ex(Cmd, 1, 0, 16), param_get32ex(Cmd, 2, 0, 16), data, len/2); } int CmdHF14AMfAuth4(const char *cmd) { diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index dac51be3..89e58263 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -21,6 +21,7 @@ #include "cmdhf14a.h" // DropField() #include "mifare.h" #include "util.h" +#include "util_posix.h" #include "protocols.h" #include "taginfo.h" @@ -40,12 +41,11 @@ typedef enum TAGTYPE_UL { MY_D = 0x000800, MY_D_NFC = 0x001000, MY_D_MOVE = 0x002000, - MY_D_MOVE_NFC = 0x004000, - MY_D_MOVE_LEAN= 0x008000, - NTAG_I2C_1K = 0x010000, - NTAG_I2C_2K = 0x020000, - FUDAN_UL = 0x040000, - MAGIC = 0x080000, + MY_D_MOVE_LEAN= 0x004000, + NTAG_I2C_1K = 0x008000, + NTAG_I2C_2K = 0x010000, + FUDAN_UL = 0x020000, + MAGIC = 0x040000, UL_MAGIC = UL | MAGIC, UL_C_MAGIC = UL_C | MAGIC, UL_ERROR = 0xFFFFFF, @@ -95,14 +95,13 @@ static uint8_t default_pwd_pack[KEYS_PWD_COUNT][4] = { {0x35,0x1C,0xD0,0x19}, // PACK 0x9A,0x5a -- italian bus (sniffed) }; -#define MAX_UL_TYPES 18 +#define MAX_UL_TYPES 17 static uint32_t UL_TYPES_ARRAY[MAX_UL_TYPES] = {UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, NTAG_203, - NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, FUDAN_UL}; + NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_LEAN, FUDAN_UL}; static uint8_t UL_MEMORY_ARRAY[MAX_UL_TYPES] = {MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_ULEV1a_BLOCKS, MAX_ULEV1b_BLOCKS, MAX_NTAG_203, MAX_NTAG_203, MAX_NTAG_210, MAX_NTAG_212, MAX_NTAG_213, - MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS}; - + MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS}; // get version nxp product type static char *getProductTypeStr( uint8_t id){ @@ -123,7 +122,7 @@ static char *getProductTypeStr( uint8_t id){ the LSBit is set to '0' if the size is exactly 2^n and set to '1' if the storage size is between 2^n and 2^(n+1). */ -char *getUlev1CardSizeStr( uint8_t fsize ){ +static char *getUlev1CardSizeStr( uint8_t fsize ){ static char buf[40]; char *retStr = buf; @@ -140,13 +139,8 @@ char *getUlev1CardSizeStr( uint8_t fsize ){ return buf; } -static void ul_switch_on_field(void) { - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); -} -static int ul_send_cmd_raw( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uint16_t responseLength ) { +static int ul_send_cmd_raw(uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uint16_t responseLength) { UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT | ISO14A_APPEND_CRC, cmdlen, 0}}; memcpy(c.d.asBytes, cmd, cmdlen); clearCommandBuffer(); @@ -159,34 +153,19 @@ static int ul_send_cmd_raw( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uin memcpy(response, resp.d.asBytes, resplen); return resplen; } -/* -static int ul_send_cmd_raw_crc( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uint16_t responseLength, bool append_crc ) { - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT , cmdlen, 0}}; - if (append_crc) - c.arg[0] |= ISO14A_APPEND_CRC; - memcpy(c.d.asBytes, cmd, cmdlen); - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return -1; - if (!resp.arg[0] && responseLength) return -1; - uint16_t resplen = (resp.arg[0] < responseLength) ? resp.arg[0] : responseLength; - memcpy(response, resp.d.asBytes, resplen); - return resplen; -} -*/ -static int ul_select( iso14a_card_select_t *card ){ +static int ul_select(iso14a_card_select_t *card, bool clear_trace) { - ul_switch_on_field(); + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS | (clear_trace?ISO14A_CLEAR_TRACE:0), 0, 0}}; + clearCommandBuffer(); + SendCommand(&c); UsbCommand resp; bool ans = false; ans = WaitForResponseTimeout(CMD_ACK, &resp, 1500); - if (!ans || resp.arg[0] < 1) { + if (ans == 0 || resp.arg[0] == 0) { PrintAndLogEx(WARNING, "iso14443a card select failed"); - DropField(); return 0; } @@ -194,40 +173,62 @@ static int ul_select( iso14a_card_select_t *card ){ return 1; } -// This read command will at least return 16bytes. -static int ul_read( uint8_t page, uint8_t *response, uint16_t responseLength ){ - uint8_t cmd[] = {ISO14443A_CMD_READBLOCK, page}; +// This read command will return 16 bytes. +static int ul_read(uint8_t page, uint8_t *response, uint16_t responseLength) { + uint8_t cmd[] = {MIFARE_CMD_READBLOCK, page}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); return len; } -static int ul_comp_write( uint8_t page, uint8_t *data, uint8_t datalen ){ - uint8_t cmd[18]; - memset(cmd, 0x00, sizeof(cmd)); +static int ul_halt(void) { + uint8_t cmd[] = {ISO14443A_CMD_HALT, 0x00}; + uint8_t response; + int len = ul_send_cmd_raw(cmd, sizeof(cmd), &response, sizeof(response)); + return len; +} + + +static int ul_comp_write_ex(uint8_t page, uint8_t *data, uint8_t datalen, bool first_part_only) { + + uint8_t cmd[18] = {0x00}; datalen = ( datalen > 16) ? 16 : datalen; - cmd[0] = ISO14443A_CMD_WRITEBLOCK; + cmd[0] = MIFARE_CMD_WRITEBLOCK; cmd[1] = page; - memcpy(cmd+2, data, datalen); - - uint8_t response[1] = {0xff}; - ul_send_cmd_raw(cmd, 2+datalen, response, sizeof(response)); - // ACK - if ( response[0] == 0x0a ) return 0; - // NACK - return -1; + + uint8_t response = {0xff}; + ul_send_cmd_raw(cmd, 2, &response, sizeof(response)); + if (response != CARD_ACK) + return -1; + if (first_part_only) + return 0; + + memcpy(cmd, data, datalen); + ul_send_cmd_raw(cmd, 16, &response, sizeof(response)); + if (response != CARD_ACK) + return -1; + + return 0; } -static int ulc_requestAuthentication( uint8_t *nonce, uint16_t nonceLength ){ + +// not used yet +// static int ul_comp_write(uint8_t page, uint8_t *data, uint8_t datalen) { + // return ul_comp_write_ex(page, data, datalen, false); +// } + + +static int ulc_requestAuthentication(uint8_t *nonce, uint16_t nonceLength) { uint8_t cmd[] = {MIFARE_ULC_AUTH_1, 0x00}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), nonce, nonceLength); return len; } -static int ulc_authentication( uint8_t *key, bool switch_off_field ){ + +static int ulc_authentication(uint8_t *key, bool switch_off_field) { UsbCommand c = {CMD_MIFAREUC_AUTH, {switch_off_field}}; memcpy(c.d.asBytes, key, 16); @@ -240,27 +241,29 @@ static int ulc_authentication( uint8_t *key, bool switch_off_field ){ return 0; } -static int ulev1_requestAuthentication( uint8_t *pwd, uint8_t *pack, uint16_t packLength ){ + +static int ulev1_requestAuthentication(uint8_t *pwd, uint8_t *pack, uint16_t packLength) { uint8_t cmd[] = {MIFARE_ULEV1_AUTH, pwd[0], pwd[1], pwd[2], pwd[3]}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), pack, packLength); return len; } -static int ul_auth_select( iso14a_card_select_t *card, TagTypeUL_t tagtype, bool hasAuthKey, uint8_t *authenticationkey, uint8_t *pack, uint8_t packSize){ - if ( hasAuthKey && (tagtype & UL_C)) { + +static int ul_auth_select(iso14a_card_select_t *card, TagTypeUL_t tagtype, bool hasAuthKey, uint8_t *authenticationkey, uint8_t *pack, uint8_t packSize) { + + if (hasAuthKey && (tagtype & UL_C)) { //will select card automatically and close connection on error if (!ulc_authentication(authenticationkey, false)) { - PrintAndLogEx(WARNING, "Authentication Failed UL-C"); + PrintAndLogEx(ERR, "Authentication Failed UL-C"); return 0; } } else { - if ( !ul_select(card) ) return 0; + if (!ul_select(card, false)) return 0; if (hasAuthKey) { if (ulev1_requestAuthentication(authenticationkey, pack, packSize) < 1) { - DropField(); - PrintAndLogEx(WARNING, "Authentication Failed UL-EV1/NTAG"); + PrintAndLogEx(ERR, "Authentication Failed UL-EV1/NTAG"); return 0; } } @@ -268,7 +271,7 @@ static int ul_auth_select( iso14a_card_select_t *card, TagTypeUL_t tagtype, bool return 1; } -static int ulev1_getVersion( uint8_t *response, uint16_t responseLength ){ +static int ulev1_getVersion(uint8_t *response, uint16_t responseLength) { uint8_t cmd[] = {MIFARE_ULEV1_VERSION}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); @@ -285,21 +288,24 @@ static int ulev1_getVersion( uint8_t *response, uint16_t responseLength ){ // return 0; // } -static int ulev1_readCounter( uint8_t counter, uint8_t *response, uint16_t responseLength ){ + +static int ulev1_readCounter(uint8_t counter, uint8_t *response, uint16_t responseLength) { uint8_t cmd[] = {MIFARE_ULEV1_READ_CNT, counter}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); return len; } -static int ulev1_readTearing( uint8_t counter, uint8_t *response, uint16_t responseLength ){ + +static int ulev1_readTearing(uint8_t counter, uint8_t *response, uint16_t responseLength) { uint8_t cmd[] = {MIFARE_ULEV1_CHECKTEAR, counter}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); return len; } -static int ulev1_readSignature( uint8_t *response, uint16_t responseLength ){ + +static int ulev1_readSignature(uint8_t *response, uint16_t responseLength) { uint8_t cmd[] = {MIFARE_ULEV1_READSIG, 0x00}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); @@ -320,9 +326,9 @@ static int ulev1_readSignature( uint8_t *response, uint16_t responseLength ){ // UL responds with read of page 0, fudan doesn't respond. // // make sure field is off before calling this function -static int ul_fudan_check( void ){ +static int ul_fudan_check(void) { iso14a_card_select_t card; - if ( !ul_select(&card) ) + if (!ul_select(&card, false)) return UL_ERROR; UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT, 4, 0}}; @@ -338,20 +344,17 @@ static int ul_fudan_check( void ){ return (!resp.d.asBytes[0]) ? FUDAN_UL : UL; //if response == 0x00 then Fudan, else Genuine NXP } -static int ul_print_default( uint8_t *data){ + +static int ul_print_default(uint8_t *data) { uint8_t uid[7]; - uid[0] = data[0]; - uid[1] = data[1]; - uid[2] = data[2]; - uid[3] = data[4]; - uid[4] = data[5]; - uid[5] = data[6]; - uid[6] = data[7]; - - PrintAndLogEx(NORMAL," UID : %s ", sprint_hex(uid, 7)); + memcpy(uid, data, 3); + memcpy(uid+3, data+4, 4); + + PrintAndLogEx(NORMAL," UID : %s", sprint_hex(uid, 7)); PrintAndLogEx(NORMAL," UID[0] : %02X, %s", uid[0], getManufacturerName(uid[0])); - if ( uid[0] == 0x05 && ((uid[1] & 0xf0) >> 4) == 2 ) { // is infineon and 66RxxP + + if (uid[0] == 0x05 && ((uid[1] & 0xf0) >> 4) == 2 ) { // is infineon and 66RxxP uint8_t chip = (data[8] & 0xC7); // 11000111 mask, bit 3,4,5 RFU switch (chip){ case 0xc2: PrintAndLogEx(NORMAL, " IC type : SLE 66R04P 770 Bytes"); break; //77 pages @@ -360,13 +363,13 @@ static int ul_print_default( uint8_t *data){ } } // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 - int crc0 = 0x88 ^ data[0] ^ data[1] ^data[2]; + int crc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; if ( data[3] == crc0 ) PrintAndLogEx(NORMAL, " BCC0 : %02X, Ok", data[3]); else PrintAndLogEx(NORMAL, " BCC0 : %02X, crc should be %02X", data[3], crc0); - int crc1 = data[4] ^ data[5] ^ data[6] ^data[7]; + int crc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6]; if ( data[8] == crc1 ) PrintAndLogEx(NORMAL, " BCC1 : %02X, Ok", data[8]); else @@ -374,14 +377,14 @@ static int ul_print_default( uint8_t *data){ PrintAndLogEx(NORMAL, " Internal : %02X, %sdefault", data[9], (data[9]==0x48)?"":"not " ); - PrintAndLogEx(NORMAL, " Lock : %s (binary %s %s)", + PrintAndLogEx(NORMAL, " Lock : %s (binary %s %s)", sprint_hex(data+10, 2), printBits(1, data+10), printBits(1, data+11) ); PrintAndLogEx(NORMAL, "OneTimePad : %s (binary %s %s %s %s)\n", - sprint_hex(data + 12, 4), + sprint_hex(data+12, 4), printBits(1, data+12), printBits(1, data+13), printBits(1, data+14), @@ -391,6 +394,7 @@ static int ul_print_default( uint8_t *data){ return 0; } + static int ndef_print_CC(uint8_t *data) { // no NDEF message if(data[0] != 0xe1) @@ -414,55 +418,55 @@ static int ndef_print_CC(uint8_t *data) { return 0; } + int ul_print_type(uint32_t tagtype, uint8_t spaces){ char spc[11] = " "; spc[10]=0x00; char *spacer = spc + (10-spaces); - if ( tagtype & UL ) + if (tagtype & UL ) PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight (MF0ICU1) %s", spacer, (tagtype & MAGIC) ? "" : "" ); - else if ( tagtype & UL_C) + else if (tagtype & UL_C) PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight C (MF0ULC) %s", spacer, (tagtype & MAGIC) ? "" : "" ); - else if ( tagtype & UL_EV1_48) + else if (tagtype & UL_EV1_48) PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 48bytes (MF0UL1101)", spacer); - else if ( tagtype & UL_EV1_128) + else if (tagtype & UL_EV1_128) PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 128bytes (MF0UL2101)", spacer); - else if ( tagtype & NTAG ) + else if (tagtype & NTAG) PrintAndLogEx(NORMAL, "%sTYPE : NTAG UNKNOWN", spacer); - else if ( tagtype & NTAG_203 ) + else if (tagtype & NTAG_203) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 203 144bytes (NT2H0301F0DT)", spacer); - else if ( tagtype & NTAG_210 ) + else if (tagtype & NTAG_210) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 210 48bytes (NT2L1011G0DU)", spacer); - else if ( tagtype & NTAG_212 ) + else if (tagtype & NTAG_212) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 212 128bytes (NT2L1211G0DU)", spacer); - else if ( tagtype & NTAG_213 ) + else if (tagtype & NTAG_213) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 213 144bytes (NT2H1311G0DU)", spacer); - else if ( tagtype & NTAG_215 ) + else if (tagtype & NTAG_215) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 215 504bytes (NT2H1511G0DU)", spacer); - else if ( tagtype & NTAG_216 ) + else if (tagtype & NTAG_216) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 216 888bytes (NT2H1611G0DU)", spacer); - else if ( tagtype & NTAG_I2C_1K ) + else if (tagtype & NTAG_I2C_1K) PrintAndLogEx(NORMAL, "%sTYPE : NTAG I%sC 888bytes (NT3H1101FHK)", spacer, "\xFD"); - else if ( tagtype & NTAG_I2C_2K ) + else if (tagtype & NTAG_I2C_2K) PrintAndLogEx(NORMAL, "%sTYPE : NTAG I%sC 1904bytes (NT3H1201FHK)", spacer, "\xFD"); - else if ( tagtype & MY_D ) + else if (tagtype & MY_D) PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 (SLE 66RxxS)", spacer); - else if ( tagtype & MY_D_NFC ) + else if (tagtype & MY_D_NFC) PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 NFC (SLE 66RxxP)", spacer); - else if ( tagtype & MY_D_MOVE ) - PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move (SLE 66R01P)", spacer); - else if ( tagtype & MY_D_MOVE_NFC ) - PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move NFC (SLE 66R01P)", spacer); - else if ( tagtype & MY_D_MOVE_LEAN ) + else if (tagtype & MY_D_MOVE) + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move | my-d\x99move NFC (SLE 66R01P)", spacer); + else if (tagtype & MY_D_MOVE_LEAN) PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move lean (SLE 66R01L)", spacer); - else if ( tagtype & FUDAN_UL ) + else if (tagtype & FUDAN_UL) PrintAndLogEx(NORMAL, "%sTYPE : FUDAN Ultralight Compatible (or other compatible) %s", spacer, (tagtype & MAGIC) ? "" : "" ); else PrintAndLogEx(NORMAL, "%sTYPE : Unknown %06x", spacer, tagtype); return 0; } -static int ulc_print_3deskey( uint8_t *data){ + +static int ulc_print_3deskey(uint8_t *data) { PrintAndLogEx(NORMAL, " deskey1 [44/0x2C] : %s [%.4s]", sprint_hex(data ,4),data); PrintAndLogEx(NORMAL, " deskey1 [45/0x2D] : %s [%.4s]", sprint_hex(data+4 ,4),data+4); PrintAndLogEx(NORMAL, " deskey2 [46/0x2E] : %s [%.4s]", sprint_hex(data+8 ,4),data+8); @@ -471,27 +475,22 @@ static int ulc_print_3deskey( uint8_t *data){ return 0; } -static int ulc_print_configuration( uint8_t *data){ + +static int ulc_print_configuration(uint8_t *data) { PrintAndLogEx(NORMAL, "--- UL-C Configuration"); - PrintAndLogEx(NORMAL, " Higher Lockbits [40/0x28] : %s (binary %s %s)", + PrintAndLogEx(NORMAL, " Higher Lockbits [40/0x28] : %s (binary %s %s)", sprint_hex(data, 2), printBits(1, data), printBits(1, data+1) ); - PrintAndLogEx(NORMAL, " Counter [41/0x29] : %s (binary %s %s %s %s)", - sprint_hex(data+4, 4), - printBits(1, data+4), - printBits(1, data+5), - printBits(1, data+6), - printBits(1, data+7) - ); + PrintAndLogEx(NORMAL, " Counter [41/0x29] : %s", sprint_hex(data+4, 2)); bool validAuth = (data[8] >= 0x03 && data[8] <= 0x30); - if ( validAuth ) + if (validAuth) PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s page %d/0x%02X and above need authentication", sprint_hex(data+8, 4), data[8], data[8] ); else{ - if ( data[8] == 0){ + if (data[8] == 0) { PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s default", sprint_hex(data+8, 4) ); } else { PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s auth byte is out-of-range", sprint_hex(data+8, 4) ); @@ -504,7 +503,8 @@ static int ulc_print_configuration( uint8_t *data){ return 0; } -static int ulev1_print_configuration( uint8_t *data, uint8_t startPage){ + +static int ulev1_print_configuration(uint8_t *data, uint8_t startPage) { PrintAndLogEx(NORMAL, "\n--- Tag Configuration"); @@ -515,33 +515,34 @@ static int ulev1_print_configuration( uint8_t *data, uint8_t startPage){ uint8_t vctid = data[5]; PrintAndLogEx(NORMAL, " cfg0 [%u/0x%02X] : %s", startPage, startPage, sprint_hex(data, 4)); - if ( data[3] < 0xff ) - PrintAndLogEx(NORMAL, " - page %d and above need authentication",data[3]); + if (data[3] < 0xff) + PrintAndLogEx(NORMAL, " - page %d and above need authentication", data[3]); else PrintAndLogEx(NORMAL, " - pages don't need authentication"); PrintAndLogEx(NORMAL, " - strong modulation mode %s", (strg_mod_en) ? "enabled" : "disabled"); PrintAndLogEx(NORMAL, " cfg1 [%u/0x%02X] : %s", startPage + 1, startPage + 1, sprint_hex(data+4, 4) ); - if ( authlim == 0) + if (authlim == 0) PrintAndLogEx(NORMAL, " - Unlimited password attempts"); else PrintAndLogEx(NORMAL, " - Max number of password attempts is %d", authlim); PrintAndLogEx(NORMAL, " - user configuration %s", cfglck ? "permanently locked":"writeable"); PrintAndLogEx(NORMAL, " - %s access is protected with password", prot ? "read and write":"write"); PrintAndLogEx(NORMAL, " - %02X, Virtual Card Type Identifier is %s default", vctid, (vctid==0x05)? "":"not"); - PrintAndLogEx(NORMAL, " PWD [%u/0x%02X] : %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data+8, 4)); - PrintAndLogEx(NORMAL, " PACK [%u/0x%02X] : %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+12, 2)); - PrintAndLogEx(NORMAL, " RFU [%u/0x%02X] : %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+14, 2)); + PrintAndLogEx(NORMAL, " PWD [%u/0x%02X] : %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data+8, 4)); + PrintAndLogEx(NORMAL, " PACK [%u/0x%02X] : %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+12, 2)); + PrintAndLogEx(NORMAL, " RFU [%u/0x%02X] : %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+14, 2)); return 0; } -static int ulev1_print_counters(){ + +static int ulev1_print_counters(void) { PrintAndLogEx(NORMAL, "--- Tag Counters"); uint8_t tear[1] = {0}; uint8_t counter[3] = {0,0,0}; uint16_t len = 0; for ( uint8_t i = 0; i<3; ++i) { - ulev1_readTearing(i,tear,sizeof(tear)); - len = ulev1_readCounter(i,counter, sizeof(counter) ); + ulev1_readTearing(i, tear, sizeof(tear)); + len = ulev1_readCounter(i, counter, sizeof(counter) ); if (len == 3) { PrintAndLogEx(NORMAL, " [%0d] : %s", i, sprint_hex(counter,3)); PrintAndLogEx(NORMAL, " - %02X tearing %s", tear[0], ( tear[0]==0xBD)?"Ok":"failure"); @@ -550,6 +551,7 @@ static int ulev1_print_counters(){ return len; } + static int ulev1_print_signature( uint8_t *data, uint8_t len){ PrintAndLogEx(NORMAL, "\n--- Tag Signature"); PrintAndLogEx(NORMAL, "IC signature public key name : NXP NTAG21x (2013)"); @@ -561,9 +563,10 @@ static int ulev1_print_signature( uint8_t *data, uint8_t len){ return 0; } + static int ulev1_print_version(uint8_t *data){ PrintAndLogEx(NORMAL, "\n--- Tag Version"); - PrintAndLogEx(NORMAL, " Raw bytes : %s",sprint_hex(data, 8) ); + PrintAndLogEx(NORMAL, " Raw bytes : %s", sprint_hex(data, 8) ); PrintAndLogEx(NORMAL, " Vendor ID : %02X, %s", data[1], getManufacturerName(data[1])); PrintAndLogEx(NORMAL, " Product type : %s", getProductTypeStr(data[2])); PrintAndLogEx(NORMAL, " Product subtype : %02X, %s", data[3], (data[3]==1) ?"17 pF":"50pF"); @@ -574,154 +577,131 @@ static int ulev1_print_version(uint8_t *data){ return 0; } -/* -static int ulc_magic_test(){ - // Magic Ultralight test - // Magic UL-C, by observation, - // 1) it seems to have a static nonce response to 0x1A command. - // 2) the deskey bytes is not-zero:d out on as datasheet states. - // 3) UID - changeable, not only, but pages 0-1-2-3. - // 4) use the ul_magic_test ! magic tags answers specially! - int returnValue = UL_ERROR; - iso14a_card_select_t card; - uint8_t nonce1[11] = {0x00}; - uint8_t nonce2[11] = {0x00}; - int status = ul_select(&card); - if ( !status ){ - return UL_ERROR; - } - status = ulc_requestAuthentication(nonce1, sizeof(nonce1)); - if ( status > 0 ) { - status = ulc_requestAuthentication(nonce2, sizeof(nonce2)); - returnValue = ( !memcmp(nonce1, nonce2, 11) ) ? UL_C_MAGIC : UL_C; - } else { - returnValue = UL; - } - DropField(); - return returnValue; -} -*/ -static int ul_magic_test(){ - // Magic Ultralight tests - // 1) take present UID, and try to write it back. OBSOLETE - // 2) make a wrong length write to page0, and see if tag answers with ACK/NACK: +static int ul_magic_test(void) { + // try a compatibility write to page0, and see if tag answers with ACK/NACK to the first part of the command iso14a_card_select_t card; - if ( !ul_select(&card) ) + if (!ul_select(&card, false)) return UL_ERROR; - int status = ul_comp_write(0, NULL, 0); - DropField(); - if ( status == 0 ) + int status = ul_comp_write_ex(0, NULL, 0, true); + if (status == 0) { return MAGIC; + } return 0; } + uint32_t GetHF14AMfU_Type(void){ TagTypeUL_t tagtype = UNKNOWN; iso14a_card_select_t card; uint8_t version[10] = {0x00}; - int status = 0; int len; - if (!ul_select(&card)) return UL_ERROR; - - // Ultralight - ATQA / SAK - if ( card.atqa[1] != 0x00 || card.atqa[0] != 0x44 || card.sak != 0x00 ) { - PrintAndLogEx(NORMAL, "Tag is not Ultralight | NTAG | MY-D [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak); + if (!ul_select(&card, true)) { DropField(); + msleep(200); return UL_ERROR; } - if ( card.uid[0] != 0x05) { - - len = ulev1_getVersion(version, sizeof(version)); + // Check for Ultralight Family + if (card.uidlen != 7 || (card.sak & 0x38) != 0x00) { DropField(); + PrintAndLogEx(NORMAL, "Tag is not Ultralight | NTAG | MY-D [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak); + return UL_ERROR; + } - switch (len) { - case 0x0A: { - - if ( version[2] == 0x03 && version[6] == 0x0B ) - tagtype = UL_EV1_48; - else if ( version[2] == 0x03 && version[6] != 0x0B ) - tagtype = UL_EV1_128; - else if ( version[2] == 0x04 && version[3] == 0x01 && version[6] == 0x0B ) - tagtype = NTAG_210; - else if ( version[2] == 0x04 && version[3] == 0x01 && version[6] == 0x0E ) - tagtype = NTAG_212; - else if ( version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x0F ) - tagtype = NTAG_213; - else if ( version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x11 ) - tagtype = NTAG_215; - else if ( version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x13 ) - tagtype = NTAG_216; - else if ( version[2] == 0x04 && version[3] == 0x05 && version[6] == 0x13 ) - tagtype = NTAG_I2C_1K; - else if ( version[2] == 0x04 && version[3] == 0x05 && version[6] == 0x15 ) - tagtype = NTAG_I2C_2K; - else if ( version[2] == 0x04 ) - tagtype = NTAG; - - break; - } - case 0x01: tagtype = UL_C; break; - case 0x00: tagtype = UL; break; - case -1 : tagtype = (UL | UL_C | NTAG_203); break; // could be UL | UL_C magic tags - default : tagtype = UNKNOWN; break; + if (card.uid[0] != 0x05) { + len = ulev1_getVersion(version, sizeof(version)); + if (len == 10) { + if (version[2] == 0x03 && version[6] == 0x0B) + tagtype = UL_EV1_48; + else if (version[2] == 0x03 && version[6] != 0x0B) + tagtype = UL_EV1_128; + else if (version[2] == 0x04 && version[3] == 0x01 && version[6] == 0x0B) + tagtype = NTAG_210; + else if (version[2] == 0x04 && version[3] == 0x01 && version[6] == 0x0E) + tagtype = NTAG_212; + else if (version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x0F) + tagtype = NTAG_213; + else if (version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x11) + tagtype = NTAG_215; + else if (version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x13) + tagtype = NTAG_216; + else if (version[2] == 0x04 && version[3] == 0x05 && version[6] == 0x13) + tagtype = NTAG_I2C_1K; + else if (version[2] == 0x04 && version[3] == 0x05 && version[6] == 0x15) + tagtype = NTAG_I2C_2K; + else if (version[2] == 0x04) + tagtype = NTAG; } + // UL vs UL-C vs ntag203 test - if (tagtype & (UL | UL_C | NTAG_203)) { - if ( !ul_select(&card) ) return UL_ERROR; + if (tagtype == UNKNOWN) { + ul_halt(); + if (!ul_select(&card, false)) { + DropField(); + msleep(200); + return UL_ERROR; + } // do UL_C check first... uint8_t nonce[11] = {0x00}; - status = ulc_requestAuthentication(nonce, sizeof(nonce)); - DropField(); - if (status > 1) { + len = ulc_requestAuthentication(nonce, sizeof(nonce)); + ul_halt(); + if (len == 11) { tagtype = UL_C; } else { // need to re-select after authentication error - if ( !ul_select(&card) ) return UL_ERROR; + if (!ul_select(&card, false)) { + DropField(); + msleep(200); + return UL_ERROR; + } uint8_t data[16] = {0x00}; - // read page 0x26-0x29 (last valid ntag203 page) - status = ul_read(0x26, data, sizeof(data)); - if ( status <= 1 ) { + // read page 0x29 (last valid ntag203 page) + len = ul_read(0x29, data, sizeof(data)); + if (len <= 1) { tagtype = UL; } else { // read page 0x30 (should error if it is a ntag203) - status = ul_read(0x30, data, sizeof(data)); - if ( status <= 1 ){ + len = ul_read(0x30, data, sizeof(data)); + if (len <= 1) { + ul_halt(); tagtype = NTAG_203; - } else { - tagtype = UNKNOWN; } } - DropField(); } } if (tagtype & UL) { tagtype = ul_fudan_check(); - DropField(); + ul_halt(); } - } else { - DropField(); - // Infinition MY-D tests Exam high nibble + + } else { // manufacturer Infineon. Check for my-d variants + uint8_t nib = (card.uid[1] & 0xf0) >> 4; - switch ( nib ){ - // case 0: tagtype = SLE66R35E7; break; //or SLE 66R35E7 - mifare compat... should have different sak/atqa for mf 1k - case 1: tagtype = MY_D; break; //or SLE 66RxxS ... up to 512 pages of 8 user bytes... - case 2: tagtype = (MY_D_NFC); break; //or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes) - case 3: tagtype = (MY_D_MOVE | MY_D_MOVE_NFC); break; //or SLE 66R01P // 38 pages of 4 bytes //notice: we can not currently distinguish between these two - case 7: tagtype = MY_D_MOVE_LEAN; break; //or SLE 66R01L // 16 pages of 4 bytes + switch (nib) { + case 1: tagtype = MY_D; break; //or SLE 66RxxS ... up to 512 pages of 8 user bytes... + case 2: tagtype = MY_D_NFC; break; //or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes) + case 3: tagtype = MY_D_MOVE; break; //or SLE 66R01P // 38 pages of 4 bytes + case 7: tagtype = MY_D_MOVE_LEAN; break; //or SLE 66R01L // 16 pages of 4 bytes } } tagtype |= ul_magic_test(); + if (tagtype == (UNKNOWN | MAGIC)) tagtype = (UL_MAGIC); + + DropField(); + msleep(200); + + printf("Tagtype: %08x\n", tagtype); return tagtype; } + static int usage_hf_mfu_info(void) { PrintAndLogEx(NORMAL, "It gathers information about the tag and tries to detect what kind it is."); PrintAndLogEx(NORMAL, "Sometimes the tags are locked down, and you may need a key to be able to read the information"); @@ -740,24 +720,21 @@ static int usage_hf_mfu_info(void) { return 0; } -static int CmdHF14AMfUInfo(const char *Cmd){ + +static int CmdHF14AMfUInfo(const char *Cmd) { uint8_t authlim = 0xff; - uint8_t data[16] = {0x00}; iso14a_card_select_t card; - int status; bool errors = false; + uint8_t keybytes[16] = {0x00}; + uint8_t *authenticationkey = keybytes; + int keyLen = 0; bool hasAuthKey = false; bool locked = false; bool swapEndian = false; uint8_t cmdp = 0; - uint8_t dataLen = 0; - uint8_t authenticationkey[16] = {0x00}; - uint8_t *authkeyptr = authenticationkey; - uint8_t *key; uint8_t pack[4] = {0,0,0,0}; int len = 0; - char tempStr[50]; while(param_getchar(Cmd, cmdp) != 0x00) { @@ -768,15 +745,14 @@ static int CmdHF14AMfUInfo(const char *Cmd){ return usage_hf_mfu_info(); case 'k': case 'K': - dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr)); - if (dataLen == 32 || dataLen == 8) { //ul-c or ev1/ntag key length - errors = param_gethex(tempStr, 0, authenticationkey, dataLen); - dataLen /= 2; // handled as bytes from now on - } else { - PrintAndLogEx(ERR, "Key has incorrect length\n"); + keyLen = 32; + errors = param_gethex_ex(Cmd, cmdp+1, authenticationkey, &keyLen); + if (errors || (keyLen != 32 && keyLen != 8)) { //ul-c or ev1/ntag key length + PrintAndLogEx(ERR, "Key has incorrect length.\n"); errors = true; } cmdp += 2; + keyLen /= 2; hasAuthKey = true; break; case 'l': @@ -793,27 +769,35 @@ static int CmdHF14AMfUInfo(const char *Cmd){ } //Validations - if(errors) return usage_hf_mfu_info(); + if (errors) + return usage_hf_mfu_info(); TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return -1; + if (tagtype == UL_ERROR) { + return -1; + } PrintAndLogEx(NORMAL, "\n--- Tag Information ---------"); PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); ul_print_type(tagtype, 6); // Swap endianness - if (swapEndian && hasAuthKey) authkeyptr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4 ); + if (swapEndian && hasAuthKey) + authenticationkey = SwapEndian64(authenticationkey, keyLen, (keyLen == 16) ? 8 : 4 ); - if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; + if (!ul_auth_select(&card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) { + DropField(); + return -1; + } // read pages 0,1,2,3 (should read 4pages) - status = ul_read(0, data, sizeof(data)); - if ( status == -1 ) { + uint8_t data[16]; + len = ul_read(0, data, sizeof(data)); + if (len == -1) { DropField(); PrintAndLogEx(WARNING, "Error: tag didn't answer to READ"); - return status; - } else if (status == 16) { + return -1; + } else if (len == 16) { ul_print_default(data); ndef_print_CC(data+12); } else { @@ -825,36 +809,41 @@ static int CmdHF14AMfUInfo(const char *Cmd){ // read pages 0x28, 0x29, 0x2A, 0x2B uint8_t ulc_conf[16] = {0x00}; - status = ul_read(0x28, ulc_conf, sizeof(ulc_conf)); - if ( status == -1 ){ - PrintAndLogEx(WARNING, "Error: tag didn't answer to READ UL-C"); + len = ul_read(0x28, ulc_conf, sizeof(ulc_conf)); + if (len == -1) { DropField(); - return status; + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ UL-C"); + return -1; + } + if (len == 16) { + ulc_print_configuration(ulc_conf); + } else { + locked = true; } - if (status == 16) ulc_print_configuration(ulc_conf); - else locked = true; if ((tagtype & MAGIC)) { //just read key uint8_t ulc_deskey[16] = {0x00}; - status = ul_read(0x2C, ulc_deskey, sizeof(ulc_deskey)); - if ( status == -1 ) { + len = ul_read(0x2C, ulc_deskey, sizeof(ulc_deskey)); + if (len == -1) { DropField(); PrintAndLogEx(WARNING, "Error: tag didn't answer to READ magic"); - return status; + return -1; } - if (status == 16) ulc_print_3deskey(ulc_deskey); - + if (len == 16) ulc_print_3deskey(ulc_deskey); } else { - DropField(); // if we called info with key, just return - if ( hasAuthKey ) return 1; + if (hasAuthKey) { + DropField(); + return 1; + } // also try to diversify default keys.. look into CmdHF14AMfuGenDiverseKeys PrintAndLogEx(INFO, "Trying some default 3des keys"); for (uint8_t i = 0; i < KEYS_3DES_COUNT; ++i ) { - key = default_3des_keys[i]; + uint8_t *key = default_3des_keys[i]; if (ulc_authentication(key, true)) { + DropField(); PrintAndLogEx(SUCCESS, "Found default 3des key: "); uint8_t keySwap[16]; memcpy(keySwap, SwapEndian64(key,16,8), 16); @@ -862,6 +851,7 @@ static int CmdHF14AMfUInfo(const char *Cmd){ return 1; } } + DropField(); return 1; } } @@ -872,53 +862,66 @@ static int CmdHF14AMfUInfo(const char *Cmd){ if ((tagtype & (UL_EV1_48 | UL_EV1_128))) { if (ulev1_print_counters() != 3) { // failed - re-select - if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; + if (!ul_auth_select( &card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) { + DropField(); + return -1; + } } } if ((tagtype & (UL_EV1_48 | UL_EV1_128 | NTAG_213 | NTAG_215 | NTAG_216 | NTAG_I2C_1K | NTAG_I2C_2K ))) { uint8_t ulev1_signature[32] = {0x00}; - status = ulev1_readSignature( ulev1_signature, sizeof(ulev1_signature)); - if ( status == -1 ) { - PrintAndLogEx(WARNING, "Error: tag didn't answer to READ SIGNATURE"); + len = ulev1_readSignature(ulev1_signature, sizeof(ulev1_signature)); + if (len == -1) { DropField(); - return status; + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ SIGNATURE"); + return -1; } - if (status == 32) ulev1_print_signature( ulev1_signature, sizeof(ulev1_signature)); - else { + if (len == 32) { + ulev1_print_signature( ulev1_signature, sizeof(ulev1_signature)); + } else { // re-select - if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; + if (!ul_auth_select( &card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) { + DropField(); + return -1; + } } } if ((tagtype & (UL_EV1_48 | UL_EV1_128 | NTAG_210 | NTAG_212 | NTAG_213 | NTAG_215 | NTAG_216 | NTAG_I2C_1K | NTAG_I2C_2K))) { uint8_t version[10] = {0x00}; - status = ulev1_getVersion(version, sizeof(version)); - if ( status == -1 ) { - PrintAndLogEx(WARNING, "Error: tag didn't answer to GETVERSION"); + len = ulev1_getVersion(version, sizeof(version)); + if (len == -1) { DropField(); - return status; - } else if (status == 10) { + PrintAndLogEx(WARNING, "Error: tag didn't answer to GETVERSION"); + return -1; + } else if (len == 10) { ulev1_print_version(version); } else { locked = true; - if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; + if (!ul_auth_select( &card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) { + DropField(); + return -1; + } } uint8_t startconfigblock = 0; uint8_t ulev1_conf[16] = {0x00}; // config blocks always are last 4 pages - for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) - if (tagtype & UL_TYPES_ARRAY[idx]) + for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) { + if (tagtype & UL_TYPES_ARRAY[idx]) { startconfigblock = UL_MEMORY_ARRAY[idx]-3; + break; + } + } - if (startconfigblock){ // if we know where the config block is... - status = ul_read(startconfigblock, ulev1_conf, sizeof(ulev1_conf)); - if ( status == -1 ) { - PrintAndLogEx(WARNING, "Error: tag didn't answer to READ EV1"); + if (startconfigblock) { // if we know where the config block is... + len = ul_read(startconfigblock, ulev1_conf, sizeof(ulev1_conf)); + if (len == -1) { DropField(); - return status; - } else if (status == 16) { + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ EV1"); + return -1; + } else if (len == 16) { // save AUTHENTICATION LIMITS for later: authlim = (ulev1_conf[4] & 0x07); ulev1_print_configuration(ulev1_conf, startconfigblock); @@ -929,17 +932,20 @@ static int CmdHF14AMfUInfo(const char *Cmd){ // 0 = limitless. // 1-7 = limit. No automatic tries then. // hasAuthKey, if we was called with key, skip test. - if ( !authlim && !hasAuthKey ) { + if (!authlim && !hasAuthKey) { PrintAndLogEx(NORMAL, "\n--- Known EV1/NTAG passwords."); len = 0; for (uint8_t i = 0; i < KEYS_PWD_COUNT; ++i ) { - key = default_pwd_pack[i]; + uint8_t *key = default_pwd_pack[i]; len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len >= 1) { - PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); break; } else { - if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; + if (!ul_auth_select( &card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) { + DropField(); + return -1; + } } } if (len < 1) PrintAndLogEx(WARNING, "password not known"); @@ -947,8 +953,11 @@ static int CmdHF14AMfUInfo(const char *Cmd){ } DropField(); - if (locked) PrintAndLogEx(FAILED, "\nTag appears to be locked, try using the key to get more info"); + + if (locked) + PrintAndLogEx(FAILED, "\nTag appears to be locked, try using the key to get more info"); PrintAndLogEx(NORMAL, ""); + return 1; } @@ -969,48 +978,35 @@ static int usage_hf_mfu_wrbl(void) { return 0; } + static int CmdHF14AMfUWrBl(const char *Cmd){ int blockNo = -1; bool errors = false; + uint8_t keybytes[16] = {0x00}; + uint8_t *authenticationkey = keybytes; + int keyLen = 0; bool hasAuthKey = false; - bool hasPwdKey = false; bool swapEndian = false; - uint8_t cmdp = 0; - uint8_t keylen = 0; uint8_t blockdata[20] = {0x00}; - uint8_t data[16] = {0x00}; - uint8_t authenticationkey[16] = {0x00}; - uint8_t *authKeyPtr = authenticationkey; - while(param_getchar(Cmd, cmdp) != 0x00) - { - switch(param_getchar(Cmd, cmdp)) - { + while(param_getchar(Cmd, cmdp) != 0x00) { + switch(param_getchar(Cmd, cmdp)) { case 'h': case 'H': return usage_hf_mfu_wrbl(); case 'k': case 'K': - // EV1/NTAG size key - keylen = param_gethex(Cmd, cmdp+1, data, 8); - if ( !keylen ) { - memcpy(authenticationkey, data, 4); - cmdp += 2; - hasPwdKey = true; - break; - } - // UL-C size key - keylen = param_gethex(Cmd, cmdp+1, data, 32); - if (!keylen){ - memcpy(authenticationkey, data, 16); - cmdp += 2; - hasAuthKey = true; - break; + keyLen = 32; + errors = param_gethex_ex(Cmd, cmdp+1, authenticationkey, &keyLen); + if (errors || (keyLen != 32 && keyLen != 8)) { //ul-c or ev1/ntag key length + PrintAndLogEx(ERR, "Key has incorrect length.\n"); + errors = true; } - PrintAndLogEx(ERR, "Key has incorrect length\n"); - errors = true; + cmdp += 2; + keyLen /= 2; + hasAuthKey = true; break; case 'b': case 'B': @@ -1044,24 +1040,28 @@ static int CmdHF14AMfUWrBl(const char *Cmd){ if(errors) return usage_hf_mfu_wrbl(); } - if ( blockNo == -1 ) return usage_hf_mfu_wrbl(); + if (blockNo == -1) return usage_hf_mfu_wrbl(); // starting with getting tagtype TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return -1; + if (tagtype == UL_ERROR) { + return -1; + } uint8_t maxblockno = 0; - for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){ - if (tagtype & UL_TYPES_ARRAY[idx]) + for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) { + if (tagtype & UL_TYPES_ARRAY[idx]) { maxblockno = UL_MEMORY_ARRAY[idx]; + break; + } } if (blockNo > maxblockno){ + DropField(); PrintAndLogEx(WARNING, "block number too large. Max block is %u/0x%02X \n", maxblockno,maxblockno); return usage_hf_mfu_wrbl(); } // Swap endianness - if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); - if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); + if (swapEndian && hasAuthKey) authenticationkey = SwapEndian64(authenticationkey, keyLen, (keyLen == 16) ? 8 : 4); if ( blockNo <= 3) PrintAndLogEx(NORMAL, "Special Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); @@ -1070,27 +1070,24 @@ static int CmdHF14AMfUWrBl(const char *Cmd){ //Send write Block UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(c.d.asBytes,blockdata,4); + memcpy(c.d.asBytes, blockdata, 4); - if ( hasAuthKey ) { - c.arg[1] = 1; - memcpy(c.d.asBytes+4,authKeyPtr,16); - } - else if ( hasPwdKey ) { - c.arg[1] = 2; - memcpy(c.d.asBytes+4,authKeyPtr,4); + if (hasAuthKey) { + c.arg[1] = (keyLen == 16) ? 1 : 2; + memcpy(c.d.asBytes+4, authenticationkey, keyLen); } clearCommandBuffer(); SendCommand(&c); UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { uint8_t isOK = resp.arg[0] & 0xff; PrintAndLogEx(SUCCESS, "isOk:%02x", isOK); } else { PrintAndLogEx(ERR, "Command execute timeout"); } + DropField(); return 0; } @@ -1112,18 +1109,17 @@ static int usage_hf_mfu_rdbl(void) { return 0; } + static int CmdHF14AMfURdBl(const char *Cmd){ int blockNo = -1; bool errors = false; + uint8_t keybytes[16] = {0x00}; + uint8_t *authenticationkey = keybytes; + int keyLen = 0; bool hasAuthKey = false; - bool hasPwdKey = false; bool swapEndian = false; uint8_t cmdp = 0; - uint8_t keylen = 0; - uint8_t data[16] = {0x00}; - uint8_t authenticationkey[16] = {0x00}; - uint8_t *authKeyPtr = authenticationkey; while(param_getchar(Cmd, cmdp) != 0x00) { @@ -1134,24 +1130,15 @@ static int CmdHF14AMfURdBl(const char *Cmd){ return usage_hf_mfu_rdbl(); case 'k': case 'K': - // EV1/NTAG size key - keylen = param_gethex(Cmd, cmdp+1, data, 8); - if ( !keylen ) { - memcpy(authenticationkey, data, 4); - cmdp += 2; - hasPwdKey = true; - break; - } - // UL-C size key - keylen = param_gethex(Cmd, cmdp+1, data, 32); - if (!keylen){ - memcpy(authenticationkey, data, 16); - cmdp += 2; - hasAuthKey = true; - break; + keyLen = 32; + errors = param_gethex_ex(Cmd, cmdp+1, authenticationkey, &keyLen); + if (errors || (keyLen != 32 && keyLen != 8)) { //ul-c or ev1/ntag key length + PrintAndLogEx(ERR, "Key has incorrect length.\n"); + errors = true; } - PrintAndLogEx(ERR, "Key has incorrect length\n"); - errors = true; + cmdp += 2; + keyLen /= 2; + hasAuthKey = true; break; case 'b': case 'B': @@ -1173,43 +1160,43 @@ static int CmdHF14AMfURdBl(const char *Cmd){ break; } //Validations - if(errors) return usage_hf_mfu_rdbl(); + if (errors) return usage_hf_mfu_rdbl(); } - if ( blockNo == -1 ) return usage_hf_mfu_rdbl(); + if (blockNo == -1) return usage_hf_mfu_rdbl(); // start with getting tagtype TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return -1; + if (tagtype == UL_ERROR) { + return -1; + } uint8_t maxblockno = 0; - for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){ - if (tagtype & UL_TYPES_ARRAY[idx]) + for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) { + if (tagtype & UL_TYPES_ARRAY[idx]) { maxblockno = UL_MEMORY_ARRAY[idx]; + break; + } } if (blockNo > maxblockno){ + DropField(); PrintAndLogEx(WARNING, "block number to large. Max block is %u/0x%02X \n", maxblockno,maxblockno); return usage_hf_mfu_rdbl(); } // Swap endianness - if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); - if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); + if (swapEndian) authenticationkey = SwapEndian64(authenticationkey, keyLen, (keyLen == 16) ? 8 : 4); //Read Block UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}}; - if ( hasAuthKey ){ - c.arg[1] = 1; - memcpy(c.d.asBytes,authKeyPtr,16); - } - else if ( hasPwdKey ) { - c.arg[1] = 2; - memcpy(c.d.asBytes,authKeyPtr,4); + if (hasAuthKey) { + c.arg[1] = (keyLen == 16) ? 1 : 2; + memcpy(c.d.asBytes, authenticationkey, keyLen); } clearCommandBuffer(); SendCommand(&c); UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { uint8_t isOK = resp.arg[0] & 0xff; if (isOK) { uint8_t *data = resp.d.asBytes; @@ -1222,6 +1209,7 @@ static int CmdHF14AMfURdBl(const char *Cmd){ } else { PrintAndLogEx(ERR, "Command execute time-out"); } + DropField(); return 0; } @@ -1229,6 +1217,96 @@ static int CmdHF14AMfURdBl(const char *Cmd){ // // Mifare Ultralight / Ultralight-C / Ultralight-EV1 // Read and Dump Card Contents, using auto detection of tag size. + +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; + + +static void printMFUdumpEx(mfu_dump_t *card, uint16_t pages, uint8_t startpage, TagTypeUL_t tagtype) { + + bool tmplockbit = false; + bool bit[16] = {false}; + bool bit2[16] = {false}; + + // standard lock bits + for(int i = 0; i < 16; i++){ + bit[i] = card->data[10+i/8] & (1 << (7-i%8)); + } + + // dynamic lock bits + // TODO -- FIGURE OUT LOCK BYTES FOR EV1 and/or NTAG + if (tagtype & UL_C) { + for (int i = 0; i < 16; i++) { + bit2[i] = card->data[40*4+i/8] & (1 << (7-i%8)); + } + } + + PrintAndLogEx(NORMAL, "\n Block# | Data |lck| Ascii"); + PrintAndLogEx(NORMAL, "---------+-------------+---+------"); + + for (int i = startpage; i < startpage + pages; i++) { + if (i < 3) { + PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| | ", i, i, sprint_hex(card->data + i * 4, 4)); + continue; + } + switch(i){ + case 3: tmplockbit = bit[4]; break; + case 4: tmplockbit = bit[3]; break; + case 5: tmplockbit = bit[2]; break; + case 6: tmplockbit = bit[1]; break; + case 7: tmplockbit = bit[0]; break; + case 8: tmplockbit = bit[15]; break; + case 9: tmplockbit = bit[14]; break; + case 10: tmplockbit = bit[13]; break; + case 11: tmplockbit = bit[12]; break; + case 12: tmplockbit = bit[11]; break; + case 13: tmplockbit = bit[10]; break; + case 14: tmplockbit = bit[9]; break; + case 15: tmplockbit = bit[8]; break; + case 16: + case 17: + case 18: + case 19: tmplockbit = bit2[6]; break; + case 20: + case 21: + case 22: + case 23: tmplockbit = bit2[5]; break; + case 24: + case 25: + case 26: + case 27: tmplockbit = bit2[4]; break; + case 28: + case 29: + case 30: + case 31: tmplockbit = bit2[2]; break; + case 32: + case 33: + case 34: + case 35: tmplockbit = bit2[1]; break; + case 36: + case 37: + case 38: + case 39: tmplockbit = bit2[0]; break; + case 40: tmplockbit = bit2[12]; break; + case 41: tmplockbit = bit2[11]; break; + case 42: tmplockbit = bit2[10]; break; //auth0 + case 43: tmplockbit = bit2[9]; break; //auth1 + default: break; + } + + PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| %d | %.4s", i, i, sprint_hex(card->data + i * 4, 4), tmplockbit, sprint_ascii(card->data + i * 4, 4)); + } + PrintAndLogEx(NORMAL, "---------------------------------"); +} + + static int usage_hf_mfu_dump(void) { PrintAndLogEx(NORMAL, "Reads all pages from Ultralight, Ultralight-C, Ultralight EV1"); PrintAndLogEx(NORMAL, "NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216"); @@ -1238,7 +1316,7 @@ static int usage_hf_mfu_dump(void) { PrintAndLogEx(NORMAL, " Options : "); PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); - PrintAndLogEx(NORMAL, " n : filename w/o .bin to save the dump as"); + PrintAndLogEx(NORMAL, " f : filename w/o .bin to save the dump as"); PrintAndLogEx(NORMAL, " p : starting Page number to manually set a page to start the dump at"); PrintAndLogEx(NORMAL, " q : number of Pages to manually set how many pages to dump"); @@ -1250,33 +1328,23 @@ static int usage_hf_mfu_dump(void) { return 0; } + static int CmdHF14AMfUDump(const char *Cmd){ - FILE *fout; - char filename[FILE_PATH_SIZE] = {0x00}; - char *fnameptr = filename; - uint8_t *lockbytes_t = NULL; - uint8_t lockbytes[2] = {0x00}; - uint8_t *lockbytes_t2 = NULL; - uint8_t lockbytes2[2] = {0x00}; - bool bit[16] = {0x00}; - bool bit2[16] = {0x00}; - uint8_t data[1024] = {0x00}; + char filename[FILE_PATH_SIZE] = {'\0'}; + size_t fileNameLen = 0; + uint8_t keybytes[16] = {0x00}; + uint8_t *authenticationkey = keybytes; + int keyLen = 0; bool hasAuthKey = false; - int i = 0; - int Pages = 16; - bool tmplockbit = false; - uint8_t dataLen = 0; uint8_t cmdp = 0; - uint8_t authenticationkey[16] = {0x00}; - uint8_t *authKeyPtr = authenticationkey; - size_t fileNlen = 0; bool errors = false; bool swapEndian = false; bool manualPages = false; uint8_t startPage = 0; - char tempStr[50]; - unsigned char cleanASCII[4]; + int Pages = 16; + iso14a_card_select_t card_select; + mfu_dump_t card; while(param_getchar(Cmd, cmdp) != 0x00) { @@ -1287,15 +1355,14 @@ static int CmdHF14AMfUDump(const char *Cmd){ return usage_hf_mfu_dump(); case 'k': case 'K': - dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr)); - if (dataLen == 32 || dataLen == 8) { //ul-c or ev1/ntag key length - errors = param_gethex(tempStr, 0, authenticationkey, dataLen); - dataLen /= 2; - } else { - PrintAndLogEx(ERR, "Key has incorrect length\n"); + keyLen = 32; + errors = param_gethex_ex(Cmd, cmdp+1, authenticationkey, &keyLen); + if (errors || (keyLen != 32 && keyLen != 8)) { //ul-c or ev1/ntag key length + PrintAndLogEx(ERR, "Key has incorrect length.\n"); errors = true; } cmdp += 2; + keyLen /= 2; hasAuthKey = true; break; case 'l': @@ -1303,11 +1370,11 @@ static int CmdHF14AMfUDump(const char *Cmd){ swapEndian = true; cmdp++; break; - case 'n': - case 'N': - fileNlen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); - if (!fileNlen) errors = true; - if (fileNlen > FILE_PATH_SIZE-5) fileNlen = FILE_PATH_SIZE-5; + case 'f': + case 'F': + fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); + if (fileNameLen == 0) errors = true; + if (fileNameLen > FILE_PATH_SIZE-5) fileNameLen = FILE_PATH_SIZE-5; cmdp += 2; break; case 'p': @@ -1323,177 +1390,151 @@ static int CmdHF14AMfUDump(const char *Cmd){ manualPages = true; break; default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(ERR, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } - if(errors) break; + if (errors) break; } //Validations - if(errors) return usage_hf_mfu_dump(); + if (errors) return usage_hf_mfu_dump(); if (swapEndian && hasAuthKey) - authKeyPtr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4); + authenticationkey = SwapEndian64(authenticationkey, keyLen, (keyLen == 16) ? 8 : 4); TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return -1; - if (!manualPages) //get number of pages to read - for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) - if (tagtype & UL_TYPES_ARRAY[idx]) - Pages = UL_MEMORY_ARRAY[idx]+1; //add one as maxblks starts at 0 + if (tagtype == UL_ERROR) { + return -1; + } + + uint8_t maxPages = 0; + for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) { + if (tagtype & UL_TYPES_ARRAY[idx]) { + maxPages = UL_MEMORY_ARRAY[idx]+1; //add one as maxblks starts at 0 + break; + } + } + + if (!manualPages) { + Pages = maxPages; + } else { + if (startPage + Pages - 1 > maxPages - 1) { + PrintAndLogEx(ERR, "Invalid page range. Card has only %d readable pages.", maxPages); + DropField(); + return 1; + } + } ul_print_type(tagtype, 0); + PrintAndLogEx(NORMAL, "Reading tag memory..."); - UsbCommand c = {CMD_MIFAREU_READCARD, {startPage,Pages}}; - if ( hasAuthKey ) { + memset(&card, 0x00, sizeof(card)); + UsbCommand c = {CMD_MIFAREU_READCARD, {startPage, Pages}}; + if (hasAuthKey) { if (tagtype & UL_C) c.arg[2] = 1; //UL_C auth else c.arg[2] = 2; //UL_EV1/NTAG auth - - memcpy(c.d.asBytes, authKeyPtr, dataLen); + memcpy(c.d.asBytes, authenticationkey, keyLen); } clearCommandBuffer(); SendCommand(&c); UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp,1500)) { - PrintAndLogEx(ERR, "Command execute time-out"); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + PrintAndLogEx(ERR, "Command execution timeout"); + DropField(); return 1; } if (resp.arg[0] != 1) { - PrintAndLogEx(ERR, "Failed reading block: (%02x)", i); + PrintAndLogEx(ERR, "Failed reading card"); + DropField(); return 1; } uint32_t startindex = resp.arg[2]; uint32_t bufferSize = resp.arg[1]; - if (bufferSize > sizeof(data)) { + if (bufferSize > sizeof(card.data)) { PrintAndLogEx(FAILED, "Data exceeded Buffer size!"); - bufferSize = sizeof(data); + bufferSize = sizeof(card.data); } - GetFromBigBuf(data, bufferSize, startindex, NULL, -1, false); - Pages = bufferSize/4; - // Load lock bytes. - int j = 0; - - lockbytes_t = data + 8; - lockbytes[0] = lockbytes_t[2]; - lockbytes[1] = lockbytes_t[3]; - for(j = 0; j < 16; j++){ - bit[j] = lockbytes[j/8] & ( 1 <<(7-j%8)); + if (!GetFromBigBuf(card.data + startPage*4, bufferSize, startindex, NULL, -1, false)) { + PrintAndLogEx(ERR, "Command execution timeout"); + DropField(); + return 1; } - // Load bottom lockbytes if available - // TODO -- FIGURE OUT LOCK BYTES FOR TO EV1 and/or NTAG - if ( Pages == 44 ) { - lockbytes_t2 = data + (40*4); - lockbytes2[0] = lockbytes_t2[2]; - lockbytes2[1] = lockbytes_t2[3]; - for (j = 0; j < 16; j++) { - bit2[j] = lockbytes2[j/8] & ( 1 <<(7-j%8)); + // not ul_c and not std ul then attempt to collect + // VERSION, SIGNATURE, COUNTERS, TEARING, PACK + if (!(tagtype & UL_C || tagtype & UL)) { + //attempt to read pack + if (!ul_auth_select(&card_select, tagtype, true, authenticationkey, card.data + maxPages*4 - 4, 2)) { + //reset pack + card.data[maxPages*4 - 4] = 0; + card.data[maxPages*4 - 3] = 0; } - } - // add keys to block dump - if (hasAuthKey) { - if (!swapEndian){ - authKeyPtr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4); + if (hasAuthKey) { + uint8_t dummy_pack[2]; + ul_auth_select(&card_select, tagtype, hasAuthKey, authenticationkey, dummy_pack, sizeof(dummy_pack)); } else { - authKeyPtr = authenticationkey; + ul_select(&card_select, false); + } + ulev1_getVersion(card.version, sizeof(card.version)); + for (uint8_t n = 0; n < 3; ++n) { + ulev1_readTearing(n, &card.counter_tearing[n][3], 1); + ulev1_readCounter(n, &card.counter_tearing[n][0], 3); } - if (tagtype & UL_C){ //add 4 pages - memcpy(data + Pages*4, authKeyPtr, dataLen); - Pages += dataLen/4; + ulev1_readSignature(card.signature, sizeof(card.signature)); + } + + DropField(); + + // add key to dump data + if (hasAuthKey) { + authenticationkey = SwapEndian64(authenticationkey, keyLen, (keyLen == 16) ? 8 : 4); + if (tagtype & UL_C){ // additional 4 pages + memcpy(card.data + maxPages*4, authenticationkey, keyLen); + maxPages += 4; } else { // 2nd page from end - memcpy(data + (Pages*4) - 8, authenticationkey, dataLen); + memcpy(card.data + (maxPages*4) - 8, authenticationkey, 4); } } - PrintAndLogEx(NORMAL, "\n Block# | Data |lck| Ascii"); - PrintAndLogEx(NORMAL, "---------+-------------+---+------"); - for (i = 0; i < Pages; ++i) { - if ( i < 3 ) { - PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| | ", i+startPage, i+startPage, sprint_hex(data + i * 4, 4)); - continue; - } - switch(i){ - case 3: tmplockbit = bit[4]; break; - case 4: tmplockbit = bit[3]; break; - case 5: tmplockbit = bit[2]; break; - case 6: tmplockbit = bit[1]; break; - case 7: tmplockbit = bit[0]; break; - case 8: tmplockbit = bit[15]; break; - case 9: tmplockbit = bit[14]; break; - case 10: tmplockbit = bit[13]; break; - case 11: tmplockbit = bit[12]; break; - case 12: tmplockbit = bit[11]; break; - case 13: tmplockbit = bit[10]; break; - case 14: tmplockbit = bit[9]; break; - case 15: tmplockbit = bit[8]; break; - case 16: - case 17: - case 18: - case 19: tmplockbit = bit2[6]; break; - case 20: - case 21: - case 22: - case 23: tmplockbit = bit2[5]; break; - case 24: - case 25: - case 26: - case 27: tmplockbit = bit2[4]; break; - case 28: - case 29: - case 30: - case 31: tmplockbit = bit2[2]; break; - case 32: - case 33: - case 34: - case 35: tmplockbit = bit2[1]; break; - case 36: - case 37: - case 38: - case 39: tmplockbit = bit2[0]; break; - case 40: tmplockbit = bit2[12]; break; - case 41: tmplockbit = bit2[11]; break; - case 42: tmplockbit = bit2[10]; break; //auth0 - case 43: tmplockbit = bit2[9]; break; //auth1 - default: break; + printMFUdumpEx(&card, Pages, startPage, tagtype); + + if (!manualPages) { + // user supplied filename? + if (fileNameLen < 1) { + char *fptr = filename; + fptr += sprintf(fptr, "hf-mfu-"); + uint8_t UID[] = {card.data[0], card.data[1], card.data[2], card.data[4], card.data[5], card.data[6], card.data[7]}; + FillFileNameByUID(fptr, UID, "-dump.bin", 7); + } else { + sprintf(filename + fileNameLen, ".bin"); } - // convert unprintable characters and line breaks to dots - memcpy(cleanASCII, data+i*4, 4); - clean_ascii(cleanASCII, 4); +#define MFU_DUMP_PREFIX_LENGTH (sizeof(card) - sizeof(card.data)) - PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| %d | %.4s", i+startPage, i+startPage, sprint_hex(data + i * 4, 4), tmplockbit, cleanASCII); - } - PrintAndLogEx(NORMAL, "---------------------------------"); + FILE *fout; + if ((fout = fopen(filename, "wb")) == NULL) { + PrintAndLogEx(ERR, "Could not create file name %s", filename); + return 1; + } + fwrite(&card, 1, MFU_DUMP_PREFIX_LENGTH + maxPages*4, fout); + fclose(fout); - // user supplied filename? - if (fileNlen < 1) { - // UID = data 0-1-2 4-5-6-7 (skips a beat) - sprintf(fnameptr,"%02X%02X%02X%02X%02X%02X%02X.bin", - data[0],data[1], data[2], data[4],data[5],data[6], data[7]); - } else { - sprintf(fnameptr + fileNlen,".bin"); + PrintAndLogEx(SUCCESS, "Dumped %d pages, wrote %d bytes to %s", maxPages, MFU_DUMP_PREFIX_LENGTH + maxPages*4, filename); } - if ((fout = fopen(filename,"wb")) == NULL) { - PrintAndLogEx(NORMAL, "Could not create file name %s", filename); - return 1; - } - fwrite( data, 1, Pages*4, fout ); - fclose(fout); - - PrintAndLogEx(SUCCESS, "Dumped %d pages, wrote %d bytes to %s", Pages, Pages*4, filename); return 0; } + //------------------------------------------------------------------------------- // Ultralight C Methods //------------------------------------------------------------------------------- @@ -1533,110 +1574,16 @@ static int CmdHF14AMfucAuth(const char *Cmd){ } uint8_t *key = default_3des_keys[keyNo]; - if (ulc_authentication(key, true)) + if (ulc_authentication(key, true)) { + DropField(); PrintAndLogEx(SUCCESS, "Authentication successful. 3des key: %s",sprint_hex(key, 16)); - else + } else { + DropField(); PrintAndLogEx(WARNING, "Authentication failed"); - - return 0; -} - -/** -A test function to validate that the polarssl-function works the same -was as the openssl-implementation. -Commented out, since it requires openssl - -int CmdTestDES(const char * cmd) -{ - uint8_t key[16] = {0x00}; - - memcpy(key,key3_3des_data,16); - DES_cblock RndA, RndB; - - PrintAndLogEx(NORMAL, "----------OpenSSL DES implementation----------"); - { - uint8_t e_RndB[8] = {0x00}; - unsigned char RndARndB[16] = {0x00}; - - DES_cblock iv = { 0 }; - DES_key_schedule ks1,ks2; - DES_cblock key1,key2; - - memcpy(key,key3_3des_data,16); - memcpy(key1,key,8); - memcpy(key2,key+8,8); - - - DES_set_key((DES_cblock *)key1,&ks1); - DES_set_key((DES_cblock *)key2,&ks2); - - DES_random_key(&RndA); - PrintAndLogEx(NORMAL, " RndA:%s",sprint_hex(RndA, 8)); - PrintAndLogEx(NORMAL, " e_RndB:%s",sprint_hex(e_RndB, 8)); - //void DES_ede2_cbc_encrypt(const unsigned char *input, - // unsigned char *output, long length, DES_key_schedule *ks1, - // DES_key_schedule *ks2, DES_cblock *ivec, int enc); - DES_ede2_cbc_encrypt(e_RndB,RndB,sizeof(e_RndB),&ks1,&ks2,&iv,0); - - PrintAndLogEx(NORMAL, " RndB:%s",sprint_hex(RndB, 8)); - rol(RndB,8); - memcpy(RndARndB,RndA,8); - memcpy(RndARndB+8,RndB,8); - PrintAndLogEx(NORMAL, " RA+B:%s",sprint_hex(RndARndB, 16)); - DES_ede2_cbc_encrypt(RndARndB,RndARndB,sizeof(RndARndB),&ks1,&ks2,&e_RndB,1); - PrintAndLogEx(NORMAL, "enc(RA+B):%s",sprint_hex(RndARndB, 16)); - - } - PrintAndLogEx(NORMAL, "----------PolarSSL implementation----------"); - { - uint8_t random_a[8] = { 0 }; - uint8_t enc_random_a[8] = { 0 }; - uint8_t random_b[8] = { 0 }; - uint8_t enc_random_b[8] = { 0 }; - uint8_t random_a_and_b[16] = { 0 }; - des3_context ctx = { 0 }; - - memcpy(random_a, RndA,8); - - uint8_t output[8] = { 0 }; - uint8_t iv[8] = { 0 }; - - PrintAndLogEx(NORMAL, " RndA :%s",sprint_hex(random_a, 8)); - PrintAndLogEx(NORMAL, " e_RndB:%s",sprint_hex(enc_random_b, 8)); - - des3_set2key_dec(&ctx, key); - - des3_crypt_cbc(&ctx // des3_context *ctx - , DES_DECRYPT // int mode - , sizeof(random_b) // size_t length - , iv // unsigned char iv[8] - , enc_random_b // const unsigned char *input - , random_b // unsigned char *output - ); - - PrintAndLogEx(NORMAL, " RndB:%s",sprint_hex(random_b, 8)); - - rol(random_b,8); - memcpy(random_a_and_b ,random_a,8); - memcpy(random_a_and_b+8,random_b,8); - - PrintAndLogEx(NORMAL, " RA+B:%s",sprint_hex(random_a_and_b, 16)); - - des3_set2key_enc(&ctx, key); - - des3_crypt_cbc(&ctx // des3_context *ctx - , DES_ENCRYPT // int mode - , sizeof(random_a_and_b) // size_t length - , enc_random_b // unsigned char iv[8] - , random_a_and_b // const unsigned char *input - , random_a_and_b // unsigned char *output - ); - - PrintAndLogEx(NORMAL, "enc(RA+B):%s",sprint_hex(random_a_and_b, 16)); } return 0; } -**/ + // // Mifare Ultralight C - Set password @@ -1668,16 +1615,18 @@ static int CmdHF14AMfucSetPwd(const char *Cmd){ UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { - if ( (resp.arg[0] & 0xff) == 1) + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) ) { + DropField(); + if ((resp.arg[0] & 0xff) == 1) { PrintAndLogEx(INFO, "Ultralight-C new password: %s", sprint_hex(pwd,16)); - else{ + return 0; + } else { PrintAndLogEx(ERR, "Failed writing at block %d", resp.arg[1] & 0xff); return 1; } - } - else { - PrintAndLogEx(ERR, "command execution time out"); + } else { + DropField(); + PrintAndLogEx(ERR, "command execution timeout"); return 1; } @@ -1715,6 +1664,7 @@ static int CmdHF14AMfucSetUid(const char *Cmd){ clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + DropField(); PrintAndLogEx(WARNING, "Command execute timeout"); return 2; } @@ -1732,7 +1682,8 @@ static int CmdHF14AMfucSetUid(const char *Cmd){ c.d.asBytes[3] = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; clearCommandBuffer(); SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + DropField(); PrintAndLogEx(WARNING, "Command execute timeout"); return 3; } @@ -1745,7 +1696,8 @@ static int CmdHF14AMfucSetUid(const char *Cmd){ c.d.asBytes[3] = uid[6]; clearCommandBuffer(); SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500) ) { + DropField(); PrintAndLogEx(WARNING, "Command execute timeout"); return 4; } @@ -1758,14 +1710,17 @@ static int CmdHF14AMfucSetUid(const char *Cmd){ c.d.asBytes[3] = oldblock2[3]; clearCommandBuffer(); SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500) ) { + DropField(); PrintAndLogEx(WARNING, "Command execute timeout"); return 5; } + DropField(); return 0; } + static int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ uint8_t iv[8] = { 0x00 }; @@ -1875,6 +1830,7 @@ static command_t CommandTable[] = {"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"}, {"info", CmdHF14AMfUInfo, 0, "Tag information"}, {"dump", CmdHF14AMfUDump, 0, "Dump Ultralight / Ultralight-C / NTAG tag to binary file"}, + // {"restore", CmdHF14AMfURestore, 0, "Restore a dump onto a MFU MAGIC tag"}, {"rdbl", CmdHF14AMfURdBl, 0, "Read block"}, {"wrbl", CmdHF14AMfUWrBl, 0, "Write block"}, {"cauth", CmdHF14AMfucAuth, 0, "Authentication - Ultralight C"}, diff --git a/client/util.c b/client/util.c index eef97e2a..cd18fc00 100644 --- a/client/util.c +++ b/client/util.c @@ -117,9 +117,8 @@ void AddLogCurrentDT(char *fileName) { AddLogLine(fileName, "\nanticollision: ", buff); } -void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount) { +void FillFileNameByUID(char *fileName, uint8_t *uid, char *ext, int byteCount) { char * fnameptr = fileName; - memset(fileName, 0x00, 200); for (int j = 0; j < byteCount; j++, fnameptr += 2) sprintf(fnameptr, "%02x", (unsigned int) uid[j]); @@ -323,13 +322,12 @@ uint32_t SwapBits(uint32_t value, int nrbits) { uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize){ static uint8_t buf[64]; memset(buf, 0x00, 64); - uint8_t *tmp = buf; for (uint8_t block=0; block < (uint8_t)(len/blockSize); block++){ for (size_t i = 0; i < blockSize; i++){ - tmp[i+(blockSize*block)] = src[(blockSize-1-i)+(blockSize*block)]; + buf[i+(blockSize*block)] = src[(blockSize-1-i)+(blockSize*block)]; } } - return tmp; + return buf; } //assumes little endian @@ -338,7 +336,7 @@ char *printBits(size_t const size, void const * const ptr) unsigned char *b = (unsigned char*) ptr; unsigned char byte; static char buf[1024]; - char * tmp = buf; + char *tmp = buf; int i, j; for (i=size-1;i>=0;i--) @@ -354,7 +352,7 @@ char *printBits(size_t const size, void const * const ptr) return buf; } -char * printBitsPar(const uint8_t *b, size_t len) { +char *printBitsPar(const uint8_t *b, size_t len) { static char buf1[512] = {0}; static char buf2[512] = {0}; static char *buf; @@ -519,7 +517,8 @@ int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt) return 0; } -int param_gethex_ex(const char *line, int paramnum, uint8_t * data, int *hexcnt) + +int param_gethex_ex(const char *line, int paramnum, uint8_t *data, int *hexcnt) { int bg, en, temp, i; @@ -528,6 +527,8 @@ int param_gethex_ex(const char *line, int paramnum, uint8_t * data, int *hexcnt) if (param_getptr(line, &bg, &en, paramnum)) return 1; + if (en - bg + 1 > *hexcnt) return 1; + *hexcnt = en - bg + 1; if (*hexcnt % 2) //error if not complete hex bytes return 1; diff --git a/common/protocols.h b/common/protocols.h index 39fed40f..ab556516 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -105,44 +105,49 @@ NXP/Philips CUSTOM COMMANDS #define ISO14443A_CMD_REQA 0x26 -#define ISO14443A_CMD_READBLOCK 0x30 #define ISO14443A_CMD_WUPA 0x52 #define ISO14443A_CMD_ANTICOLL_OR_SELECT 0x93 #define ISO14443A_CMD_ANTICOLL_OR_SELECT_2 0x95 #define ISO14443A_CMD_ANTICOLL_OR_SELECT_3 0x97 -#define ISO14443A_CMD_WRITEBLOCK 0xA0 // or 0xA2 ? #define ISO14443A_CMD_HALT 0x50 #define ISO14443A_CMD_RATS 0xE0 -#define MIFARE_AUTH_KEYA 0x60 -#define MIFARE_AUTH_KEYB 0x61 -#define MIFARE_MAGICWUPC1 0x40 -#define MIFARE_MAGICWUPC2 0x43 -#define MIFARE_MAGICWIPEC 0x41 -#define MIFARE_CMD_INC 0xC0 -#define MIFARE_CMD_DEC 0xC1 -#define MIFARE_CMD_RESTORE 0xC2 -#define MIFARE_CMD_TRANSFER 0xB0 - -#define MIFARE_EV1_PERSONAL_UID 0x40 -#define MIFARE_EV1_SETMODE 0x43 - - -#define MIFARE_ULC_WRITE 0xA2 -//#define MIFARE_ULC__COMP_WRITE 0xA0 -#define MIFARE_ULC_AUTH_1 0x1A -#define MIFARE_ULC_AUTH_2 0xAF - -#define MIFARE_ULEV1_AUTH 0x1B -#define MIFARE_ULEV1_VERSION 0x60 -#define MIFARE_ULEV1_FASTREAD 0x3A -//#define MIFARE_ULEV1_WRITE 0xA2 -//#define MIFARE_ULEV1_COMP_WRITE 0xA0 -#define MIFARE_ULEV1_READ_CNT 0x39 -#define MIFARE_ULEV1_INCR_CNT 0xA5 -#define MIFARE_ULEV1_READSIG 0x3C -#define MIFARE_ULEV1_CHECKTEAR 0x3E -#define MIFARE_ULEV1_VCSL 0x4B +#define MIFARE_CMD_READBLOCK 0x30 +#define MIFARE_CMD_WRITEBLOCK 0xA0 +#define MIFARE_AUTH_KEYA 0x60 +#define MIFARE_AUTH_KEYB 0x61 +#define MIFARE_MAGICWUPC1 0x40 +#define MIFARE_MAGICWUPC2 0x43 +#define MIFARE_MAGICWIPEC 0x41 +#define MIFARE_CMD_INC 0xC0 +#define MIFARE_CMD_DEC 0xC1 +#define MIFARE_CMD_RESTORE 0xC2 +#define MIFARE_CMD_TRANSFER 0xB0 + +#define MIFARE_EV1_PERSONAL_UID 0x40 +#define MIFARE_EV1_SETMODE 0x43 + +#define MIFARE_ULC_WRITE 0xA2 +#define MIFARE_ULC_COMP_WRITE MIFARE_CMD_WRITEBLOCK +#define MIFARE_ULC_AUTH_1 0x1A +#define MIFARE_ULC_AUTH_2 0xAF + +#define MIFARE_ULEV1_AUTH 0x1B +#define MIFARE_ULEV1_VERSION 0x60 +#define MIFARE_ULEV1_FASTREAD 0x3A +#define MIFARE_ULEV1_WRITE 0xA2 +#define MIFARE_ULEV1_COMP_WRITE MIFARE_CMD_WRITEBLOCK +#define MIFARE_ULEV1_READ_CNT 0x39 +#define MIFARE_ULEV1_INCR_CNT 0xA5 +#define MIFARE_ULEV1_READSIG 0x3C +#define MIFARE_ULEV1_CHECKTEAR 0x3E +#define MIFARE_ULEV1_VCSL 0x4B + +// mifare 4bit card answers +#define CARD_ACK 0x0A // 1010 - ACK +#define CARD_NACK_NA 0x04 // 0100 - NACK, not allowed (command not allowed) +#define CARD_NACK_TR 0x05 // 0101 - NACK, transmission error + /** 06 00 = INITIATE -- 2.39.5 From dd8e45133090d9684a7f0d37ef59137e6b7159a9 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Sun, 16 Jun 2019 15:35:10 +1000 Subject: [PATCH 15/16] T55xx downlink Modes Changes : - Added t55xx downlink protocols (long leading reference, leading 0 and 1 of 4) - Added function to all read to call differnet downlink functions (to match write) - Update functions to support using differnet downlink modes. - Added support for calling downlink modes for lf t55 read, write and detect - Added new function lf t55 bruteforcedl to support downlink modes as well as try each mode for each password in password file. for functions with downlink mode extenstion. e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference, '2' Leading Zero, '3' 1 of 4 --- armsrc/lfops.c | 442 +++++++++++++++++++++++++++++++++++++++++++- client/cmdlft55xx.c | 332 +++++++++++++++++++++++++++++++-- client/cmdlft55xx.h | 3 +- 3 files changed, 755 insertions(+), 22 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 81fdd7a6..36efe729 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1203,6 +1203,8 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) #define WRITE_0 18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc) #define WRITE_1 50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) 432 for T55x7; 448 for E5550 #define READ_GAP 15*8 +// Long Leading Reference +#define Reference_llr (136+18)*8 // Needs to be WRITR_0 + 136 clocks. void TurnReadLFOn(int delay) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); @@ -1220,6 +1222,265 @@ void T55xxWriteBit(int bit) { WaitUS(WRITE_GAP); } +void T55xxWrite_LLR (void) +{ + TurnReadLFOn (Reference_llr); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(WRITE_GAP); +} + +#define START_GAPlz 31*8 +#define WRITE_GAPlz 20*8 +#define WRITElz_0 18*8 +#define WRITElz_1 40*8 +#define READ_GAP 15*8 + +void T55xxWriteBit_Leading0(int bit) { + if (!bit) + TurnReadLFOn(WRITElz_0); + else + TurnReadLFOn(WRITElz_1); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(WRITE_GAPlz); +// WaitUS(160); +} + +#define START_GAP1of4 31*8 // SPEC: 1*8 to 50*8 - typ 10*8 (or 15fc) +#define WRITE_GAP1of4 20*8 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) +// 00 = reference // 8 * 8 - - 68 * 8 +#define WRITE1of4_00 18*8 // SPEC: 8*8 to 68*8 - typ 24*8 (or 24fc) +#define WRITE1of4_01 34*8 // SPEC: dref+9 - dref+16 - dref+24 +#define WRITE1of4_10 50*8 // SPEC: dref+25 - dref+32 - dref+40 +#define WRITE1of4_11 66*8 // SPEC: dref+41 - dref+48 - dref+56 +#define READ1of4_GAP 15*8 + +void T55xxWriteBit_1of4(int bits) { + + switch (bits) + { + case 0 : TurnReadLFOn(WRITE1of4_00); break; + case 1 : TurnReadLFOn(WRITE1of4_01); break; + case 2 : TurnReadLFOn(WRITE1of4_10); break; + case 3 : TurnReadLFOn(WRITE1of4_11); break; + default: + TurnReadLFOn(WRITE1of4_00); + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(WRITE_GAP1of4); +// WaitUS(160); +} + +void T55xxWriteBlockExt_Leading0 (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { + + LED_A_ON(); + bool PwdMode = arg & 0x1; + uint8_t Page = (arg & 0x2)>>1; + bool testMode = arg & 0x4; + uint32_t i = 0; + + // Set up FPGA, 125kHz + LFSetupFPGAForADC(95, true); + StartTicks(); + // make sure tag is fully powered up... + WaitMS(5); + // Trigger T55x7 in mode. + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + WaitUS(START_GAPlz); + + + /* + 0 : Leading Zero + 11 : Opcode + 00 : Fixed 00 if protected write (i.e. have password) + <32 bit Password> + 0 : Lock Bit + <32 bit data> + <3 bit addr> + + Standard Write : 0 1p L <32 data bits> <3 bit addr> + 0 10 0 00000000000000000000000000000000 001 + Protected Write: 0 1p 00 <32 pwd bits> L <32 data bits> <3 bit addr> + 0 10 00 00000000000000000000000000000000 0 00000000000000000000000000000000 001 + Wake Up 0 10 00 <32 pwd bits> + Protected Read 0 1p 00 <32 pwd bits> 0 <3 bit addr> + Standard Read 0 1p 0 <3 bit addr> + Page 0/1 read 0 1p + Reset 0 00 + + */ + T55xxWriteBit_Leading0 (0); //T55xxWriteBit(0); + + + if (testMode) Dbprintf("TestMODE"); + // Std Opcode 10 + T55xxWriteBit_Leading0 (testMode ? 0 : 1); + T55xxWriteBit_Leading0 (testMode ? 1 : Page); //Page 0 + + + if (PwdMode) { + // Leading zero - insert two fixed 00 between opcode and password + T55xxWriteBit_Leading0 (0); + T55xxWriteBit_Leading0 (0); + // Send Pwd + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit_Leading0 (Pwd & i); + } + + // Send Lock bit + T55xxWriteBit_Leading0 (0); + + // Send Data + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit_Leading0(Data & i); + + // Send Block number + for (i = 0x04; i != 0; i >>= 1) + T55xxWriteBit_Leading0 (Block & i); + + // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, + // so wait a little more) + // "there is a clock delay before programming" + // - programming takes ~5.6ms for t5577 ~18ms for E5550 or t5567 + // so we should wait 1 clock + 5.6ms then read response? + // but we need to know we are dealing with t5577 vs t5567 vs e5550 (or q5) marshmellow... + if (testMode) { + //TESTMODE TIMING TESTS: + // <566us does nothing + // 566-568 switches between wiping to 0s and doing nothing + // 5184 wipes and allows 1 block to be programmed. + // indefinite power on wipes and then programs all blocks with bitshifted data sent. + TurnReadLFOn(5184); + + } else { + TurnReadLFOn(20 * 1000); + //could attempt to do a read to confirm write took + // as the tag should repeat back the new block + // until it is reset, but to confirm it we would + // need to know the current block 0 config mode for + // modulation clock an other details to demod the response... + // response should be (for t55x7) a 0 bit then (ST if on) + // block data written in on repeat until reset. + + //DoPartialAcquisition(20, true, 12000); + } + + // turn field off + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_A_OFF(); + +} +void T55xxWriteBlockExt_1of4 (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { + + LED_A_ON(); + bool PwdMode = arg & 0x1; + uint8_t Page = (arg & 0x2)>>1; + bool testMode = arg & 0x4; + int bitpos; + uint8_t bits; + + // Set up FPGA, 125kHz + LFSetupFPGAForADC(95, true); + StartTicks(); + // make sure tag is fully powered up... + WaitMS(5); + // Trigger T55x7 in mode. + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + + WaitUS(START_GAP1of4); + + + /* + 00 : 1 if 4 + 11 : Opcode + 00 : Fixed 00 if protected write (i.e. have password) + <32 bit Password> + 0 : Lock Bit + <32 bit data> + <3 bit addr> + + Standard Write : 00 1p L <32 data bits> <3 bit addr> + 00 10 0 00000000000000000000000000000000 001 + Protected Write: 00 1p 00 <32 pwd bits> L <32 data bits> <3 bit addr> + 00 10 00 00000000000000000000000000000000 0 00000000000000000000000000000000 001 + Wake Up 00 10 00 <32 pwd bits> + Protected Read 00 1p 00 <32 pwd bits> 0 <3 bit addr> + Standard Read 00 1p 0 <3 bit addr> + Page 0/1 read 00 1p + Reset 00 00 + + */ + T55xxWriteBit_1of4 (0); //Send Reference 00 + + if (testMode) Dbprintf("TestMODE"); + // Std Opcode 10 + if (testMode) bits = 0; else bits = 2; // 0x or 1x + if (testMode) bits |= 1; else bits += (Page); // x0 or x1 + T55xxWriteBit_1of4 (bits); + + if (PwdMode) { + // 1 of 4 00 - insert two fixed 00 between opcode and password + T55xxWriteBit_1of4 (0); // 00 + + // Send Pwd + for (bitpos = 31; bitpos >= 1; bitpos -= 2) { // 2 bits at a time + bits = (((Pwd >> bitpos) & 1) << 1) + ((Pwd >> (bitpos-1)) & 1); + T55xxWriteBit_1of4 (bits); + } + } + + // Send Lock bit + bits = 0; // Add lock bit (Not Set) to the next 2 bits + + // Send Data - offset by 1 bit due to lock bit + // 2 bits at a time - Initilised with lock bit above + for (bitpos = 31; bitpos >= 1; bitpos -= 2) { + bits |= ((Data >> bitpos) & 1); // Add Low bit + T55xxWriteBit_1of4 (bits); + bits = ((Data >> (bitpos-1)) & 1) << 1; // Set next high bit + } + + // Send Block number + bits |= ((Block >> 2) & 1); + T55xxWriteBit_1of4 (bits); + bits = (Block & 3);// 1) & 2) + (Block & 1); + T55xxWriteBit_1of4 (bits); + + // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, + // so wait a little more) + // "there is a clock delay before programming" + // - programming takes ~5.6ms for t5577 ~18ms for E5550 or t5567 + // so we should wait 1 clock + 5.6ms then read response? + // but we need to know we are dealing with t5577 vs t5567 vs e5550 (or q5) marshmellow... + if (testMode) { + //TESTMODE TIMING TESTS: + // <566us does nothing + // 566-568 switches between wiping to 0s and doing nothing + // 5184 wipes and allows 1 block to be programmed. + // indefinite power on wipes and then programs all blocks with bitshifted data sent. + TurnReadLFOn(5184); + + } else { + TurnReadLFOn(20 * 1000); + //could attempt to do a read to confirm write took + // as the tag should repeat back the new block + // until it is reset, but to confirm it we would + // need to know the current block 0 config mode for + // modulation clock an other details to demod the response... + // response should be (for t55x7) a 0 bit then (ST if on) + // block data written in on repeat until reset. + + //DoPartialAcquisition(20, true, 12000); + } + + // turn field off + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_A_OFF(); + +} + // Send T5577 reset command then read stream (see if we can identify the start of the stream) void T55xxResetRead(void) { LED_A_ON(); @@ -1324,12 +1585,34 @@ void T55xxWriteBlockExt(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg // Write one card block in page 0, no lock void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { - T55xxWriteBlockExt(Data, Block, Pwd, arg); +// arg 8 bit 00000000 +// 0000000x Password +// 000000x0 Page +// 00000x00 Test Mode +// 000xx000 (0x18) where xx : 00 - Normal Write, 01 - Long Leading Reference +// 10 - Leading 0, 11 - 1 of 4 + uint8_t downlink_mode; + + downlink_mode = (arg >> 3) & 0x03; + + switch (downlink_mode) + { + case 0 : T55xxWriteBlockExt (Data, Block, Pwd, arg); break; + case 1 : T55xxWrite_LLR (); + T55xxWriteBlockExt (Data, Block, Pwd, arg); + break; + case 2 : T55xxWriteBlockExt_Leading0 (Data, Block, Pwd, arg); break; + case 3 : T55xxWriteBlockExt_1of4 (Data, Block, Pwd, arg); break; + + default: + T55xxWriteBlockExt (Data, Block, Pwd, arg); + } + cmd_send(CMD_ACK,0,0,0,0,0); } // Read one card block in page [page] -void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) { +void T55xxReadBlockExt (uint16_t arg0, uint8_t Block, uint32_t Pwd) { LED_A_ON(); bool PwdMode = arg0 & 0x1; uint8_t Page = (arg0 & 0x2) >> 1; @@ -1379,10 +1662,163 @@ void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) { // Turn the field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - cmd_send(CMD_ACK,0,0,0,0,0); +// cmd_send(CMD_ACK,0,0,0,0,0); + LED_A_OFF(); +} + +void T55xxReadBlockExt_Leading0 (uint16_t arg0, uint8_t Block, uint32_t Pwd) { + LED_A_ON(); + bool PwdMode = arg0 & 0x1; + uint8_t Page = (arg0 & 0x2) >> 1; + uint32_t i = 0; + bool RegReadMode = (Block == 0xFF);//regular read mode + + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + //make sure block is at max 7 + Block &= 0x7; + + // Set up FPGA, 125kHz to power up the tag + LFSetupFPGAForADC(95, true); + StartTicks(); + // make sure tag is fully powered up... + WaitMS(5); + // Trigger T55x7 Direct Access Mode with start gap + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(START_GAPlz); + + T55xxWriteBit_Leading0 (0); + + // Opcode 1[page] + T55xxWriteBit_Leading0 (1); + T55xxWriteBit_Leading0 (Page); //Page 0 + + if (PwdMode){ + // Send Pwd + T55xxWriteBit_Leading0 (0); + T55xxWriteBit_Leading0 (0); + + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit_Leading0 (Pwd & i); + } + // Send a zero bit separation + T55xxWriteBit_Leading0(0); + + // Send Block number (if direct access mode) + if (!RegReadMode) + for (i = 0x04; i != 0; i >>= 1) + T55xxWriteBit_Leading0(Block & i); + + // Turn field on to read the response + // 137*8 seems to get to the start of data pretty well... + // but we want to go past the start and let the repeating data settle in... + TurnReadLFOn(210*8); + + // Acquisition + // Now do the acquisition + DoPartialAcquisition(0, true, 12000, 0); + + // Turn the field off + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off +// cmd_send(CMD_ACK,0,0,0,0,0); LED_A_OFF(); } +void T55xxReadBlockExt_1of4 (uint16_t arg0, uint8_t Block, uint32_t Pwd) { + LED_A_ON(); + bool PwdMode = arg0 & 0x1; + uint8_t Page = (arg0 & 0x2) >> 1; + //uint32_t i = 0; + bool RegReadMode = (Block == 0xFF);//regular read mode + uint8_t bits; + int bitpos; + + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + //make sure block is at max 7 + Block &= 0x7; + + // Set up FPGA, 125kHz to power up the tag + LFSetupFPGAForADC(95, true); + StartTicks(); + // make sure tag is fully powered up... + WaitMS(5); + // Trigger T55x7 Direct Access Mode with start gap + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(START_GAP1of4); + + T55xxWriteBit_1of4 (0); // 2 Bit 00 leading reference + + // Opcode 1[page] + bits = 2 + Page; + T55xxWriteBit_1of4 (bits); + + if (PwdMode) { + // 1 of 4 00 - insert two fixed 00 between opcode and password + T55xxWriteBit_1of4 (0); // 00 + + // Send Pwd + for (bitpos = 31; bitpos >= 1; bitpos -= 2) { // 2 bits at a time + bits = (((Pwd >> bitpos) & 1) << 1) + ((Pwd >> (bitpos-1)) & 1); + T55xxWriteBit_1of4 (bits); + } + } + + // Send Lock bit + bits = 0; // Add lock bit (Not Set) to the next 2 bits + + // Send Block number (if direct access mode) + if (!RegReadMode){ + // Send Block number + bits += ((Block >> 2) & 1); + T55xxWriteBit_1of4 (bits); + bits = (Block & 3); // + (Block & 1); + T55xxWriteBit_1of4 (bits); + } + + // Turn field on to read the response + // 137*8 seems to get to the start of data pretty well... + // but we want to go past the start and let the repeating data settle in... + TurnReadLFOn(210*8); + + // Acquisition + // Now do the acquisition + DoPartialAcquisition(0, true, 12000, 0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off +// cmd_send(CMD_ACK,0,0,0,0,0); + LED_A_OFF(); +} + +void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) { +// arg0 16 bit 00000000 +// 0000000x Password +// 000000x0 Page +// 00000x00 +// 000xx000 (0x18) where xx : 00 - Normal Write, 01 - Long Leading Reference +// 10 - Leading 0, 11 - 1 of 4 + uint8_t downlink_mode; + + downlink_mode = (arg0 >> 3) & 0x03; + + // downlink mode id set to match the 2 bit as per Tech Sheet + switch (downlink_mode) + { + case 0 : T55xxReadBlockExt (arg0, Block, Pwd); break; + case 1 : T55xxWrite_LLR (); + T55xxReadBlockExt (arg0, Block, Pwd); + break; + case 2 : T55xxReadBlockExt_Leading0 (arg0, Block, Pwd); break; + case 3 : T55xxReadBlockExt_1of4 (arg0, Block, Pwd); break; + default: + T55xxReadBlockExt (arg0, Block, Pwd) ; + } + +// T55xxReadBlockExt (arg0, Block, Pwd) ; + cmd_send(CMD_ACK,0,0,0,0,0); +} + void T55xxWakeUp(uint32_t Pwd){ LED_B_ON(); uint32_t i = 0; diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index b286c392..25df4c76 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -67,6 +67,8 @@ int usage_t55xx_read(){ PrintAndLog(" p - OPTIONAL password (8 hex characters)"); PrintAndLog(" o - OPTIONAL override safety check"); PrintAndLog(" 1 - OPTIONAL read Page 1 instead of Page 0"); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); + PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); PrintAndLog(" ****WARNING****"); PrintAndLog(" Use of read with password on a tag not configured for a pwd"); PrintAndLog(" can damage the tag"); @@ -86,6 +88,8 @@ int usage_t55xx_write(){ PrintAndLog(" p - OPTIONAL password 4bytes (8 hex characters)"); PrintAndLog(" 1 - OPTIONAL write Page 1 instead of Page 0"); PrintAndLog(" t - OPTIONAL test mode write - ****DANGER****"); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); + PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx write b 3 d 11223344 - write 11223344 to block 3"); @@ -132,6 +136,8 @@ int usage_t55xx_detect(){ PrintAndLog("Options:"); PrintAndLog(" 1 - if set, use Graphbuffer otherwise read data from tag."); PrintAndLog(" p - OPTIONAL password (8 hex characters)"); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); + PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx detect"); @@ -182,6 +188,24 @@ int usage_t55xx_bruteforce(){ PrintAndLog(""); return 0; } +int usage_t55xx_bruteforce_downlink(){ + PrintAndLog("This command uses A) bruteforce to scan a number range"); + PrintAndLog(" B) a dictionary attack"); + PrintAndLog("Usage: lf t55xx bruteforce [i <*.dic>]"); + PrintAndLog(" password must be 4 bytes (8 hex symbols)"); + PrintAndLog("Options:"); + PrintAndLog(" h - this help"); + PrintAndLog(" r - 4 byte hex value to start and end pwd search at"); + PrintAndLog(" i <*.dic> - loads a default keys dictionary file <*.dic>"); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); + PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); + PrintAndLog(""); + PrintAndLog("Examples:"); + PrintAndLog(" lf t55xx bruteforce aaaaaaaa bbbbbbbb"); + PrintAndLog(" lf t55xx bruteforce i default_pwd.dic"); + PrintAndLog(""); + return 0; +} int usage_t55xx_wipe(){ PrintAndLog("Usage: lf t55xx wipe [h] [Q5]"); PrintAndLog("This commands wipes a tag, fills blocks 1-7 with zeros and a default configuration block"); @@ -311,12 +335,12 @@ int CmdT55xxSetConfig(const char *Cmd) { return printConfiguration ( config ); } -int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32_t password){ +int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32_t password, uint8_t downlink_mode){ //Password mode if ( usepwd ) { // try reading the config block and verify that PWD bit is set before doing this! if ( !override ) { - if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0 ) ) return 0; + if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0,downlink_mode ) ) return 0; if ( !tryDetectModulation() ) { PrintAndLog("Safety Check: Could not detect if PWD bit is set in config block. Exits."); return 0; @@ -330,7 +354,7 @@ int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32 } } - if (!AquireData(page1, block, usepwd, password) ) return 0; + if (!AquireData(page1, block, usepwd, password,downlink_mode) ) return 0; if (!DecodeT55xxBlock()) return 0; char blk[10]={0}; @@ -342,6 +366,8 @@ int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32 int CmdT55xxReadBlock(const char *Cmd) { uint8_t block = REGULAR_READ_MODE_BLOCK; uint32_t password = 0; //default to blank Block 7 + uint8_t downlink_mode = 0; + bool usepwd = false; bool override = false; bool page1 = false; @@ -372,6 +398,12 @@ int CmdT55xxReadBlock(const char *Cmd) { page1 = true; cmdp++; break; + case 'e': + case 'E': + downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; + if (downlink_mode > 3) downlink_mode = 0; + cmdp +=2; + break; default: PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -386,7 +418,7 @@ int CmdT55xxReadBlock(const char *Cmd) { } printT5xxHeader(page1); - return T55xxReadBlock(block, page1, usepwd, override, password); + return T55xxReadBlock(block, page1, usepwd, override, password, downlink_mode); } bool DecodeT55xxBlock(){ @@ -465,6 +497,7 @@ int CmdT55xxDetect(const char *Cmd){ bool usepwd = false; uint32_t password = 0; uint8_t cmdp = 0; + uint8_t downlink_mode = 0; while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch(param_getchar(Cmd, cmdp)) { @@ -482,6 +515,12 @@ int CmdT55xxDetect(const char *Cmd){ useGB = true; cmdp++; break; + case 'e': + case 'E': + downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; + if (downlink_mode > 3) downlink_mode = 0; + cmdp +=2; + break; default: PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -491,13 +530,24 @@ int CmdT55xxDetect(const char *Cmd){ if (errors) return usage_t55xx_detect(); if ( !useGB) { - if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password) ) + if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password,downlink_mode) ) return 0; } if ( !tryDetectModulation() ) PrintAndLog("Could not detect modulation automatically. Try setting it manually with \'lf t55xx config\'"); - + else { + // Add downlink mode to reference. + switch (downlink_mode) { + case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; + case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; + case 2 : PrintAndLog ("Downlink : e 2 - Leading Zero Reference"); break; + case 3 : PrintAndLog ("Downlink : e 3 - 1 of 4 Coding"); break; + // default: + + // No default action + } + } return 1; } @@ -898,6 +948,8 @@ int CmdT55xxWriteBlock(const char *Cmd) { uint8_t block = 0xFF; //default to invalid block uint32_t data = 0; //default to blank Block uint32_t password = 0; //default to blank Block 7 + uint32_t downlink_mode = 0; + bool usepwd = false; bool page1 = false; bool gotdata = false; @@ -935,6 +987,12 @@ int CmdT55xxWriteBlock(const char *Cmd) { page1 = true; cmdp++; break; + case 'e': + case 'E': + downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; + if (downlink_mode > 3) downlink_mode = 0; + cmdp +=2; + break; default: PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -952,17 +1010,19 @@ int CmdT55xxWriteBlock(const char *Cmd) { UsbCommand resp; c.d.asBytes[0] = (page1) ? 0x2 : 0; c.d.asBytes[0] |= (testMode) ? 0x4 : 0; - + c.d.asBytes[0] |= (downlink_mode << 3); + char pwdStr[16] = {0}; snprintf(pwdStr, sizeof(pwdStr), "pwd: 0x%08X", password); PrintAndLog("Writing page %d block: %02d data: 0x%08X %s", page1, block, data, (usepwd) ? pwdStr : "" ); - + //Password mode if (usepwd) { c.arg[2] = password; c.d.asBytes[0] |= 0x1; } + clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)){ @@ -980,7 +1040,7 @@ int CmdT55xxReadTrace(const char *Cmd) { return usage_t55xx_trace(); if (strlen(Cmd)==0) - if ( !AquireData( T55x7_PAGE1, REGULAR_READ_MODE_BLOCK, pwdmode, password ) ) + if ( !AquireData( T55x7_PAGE1, REGULAR_READ_MODE_BLOCK, pwdmode, password,0 ) ) return 0; if ( config.Q5 ) { @@ -1144,7 +1204,7 @@ int CmdT55xxInfo(const char *Cmd){ return usage_t55xx_info(); if (strlen(Cmd)==0) - if ( !AquireData( T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, pwdmode, password ) ) + if ( !AquireData( T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, pwdmode, password,0 ) ) return 1; if (!DecodeT55xxBlock()) return 1; @@ -1212,20 +1272,21 @@ int CmdT55xxDump(const char *Cmd){ printT5xxHeader(0); for ( uint8_t i = 0; i <8; ++i) - T55xxReadBlock(i, 0, usepwd, override, password); + T55xxReadBlock(i, 0, usepwd, override, password,0); printT5xxHeader(1); for ( uint8_t i = 0; i<4; i++) - T55xxReadBlock(i, 1, usepwd, override, password); + T55xxReadBlock(i, 1, usepwd, override, password,0); return 1; } -int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password ){ +int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password, uint8_t downlink_mode ){ // arg0 bitmodes: // bit0 = pwdmode // bit1 = page to read from uint8_t arg0 = (page<<1) | pwdmode; + arg0 |= (downlink_mode << 3); UsbCommand c = {CMD_T55XX_READ_BLOCK, {arg0, block, password}}; clearCommandBuffer(); @@ -1397,6 +1458,7 @@ int CmdT55xxBruteForce(const char *Cmd) { char buf[9]; char filename[FILE_PATH_SIZE]={0}; int keycnt = 0; + uint8_t downlink_mode = 0; int ch; uint8_t stKeyBlock = 20; uint8_t *keyBlock = NULL, *p = NULL; @@ -1480,7 +1542,7 @@ int CmdT55xxBruteForce(const char *Cmd) { PrintAndLog("Testing %08X", testpwd); - if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd)) { + if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd,downlink_mode)) { PrintAndLog("Aquireing data from device failed. Quitting"); free(keyBlock); return 0; @@ -1525,7 +1587,7 @@ int CmdT55xxBruteForce(const char *Cmd) { return 0; } - if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i)) { + if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i,downlink_mode)) { PrintAndLog("Aquireing data from device failed. Quitting"); free(keyBlock); return 0; @@ -1547,6 +1609,239 @@ int CmdT55xxBruteForce(const char *Cmd) { return 0; } +int CmdT55xxBruteForce_downlink(const char *Cmd) { + + // load a default pwd file. + char buf[9]; + char filename[FILE_PATH_SIZE]={0}; + int keycnt = 0; + uint8_t downlink_mode = 0; + int ch; + uint8_t stKeyBlock = 20; + uint8_t *keyBlock = NULL, *p = NULL; + uint32_t start_password = 0x00000000; //start password + uint32_t end_password = 0xFFFFFFFF; //end password + bool found = false; + uint8_t cmdp = 0; + int cmd_offset = 0; + int errors = 0; + int len; + bool use_file = false; + bool use_range = false; + bool try_all_dl_modes = false; + uint8_t dl_mode = 0; + + keyBlock = calloc(stKeyBlock, 6); + if (keyBlock == NULL) return 1; + + PrintAndLog("New Downlink Supprt"); + + while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch(param_getchar(Cmd, cmdp)) { + case 'h': + case 'H': + return usage_t55xx_bruteforce_downlink(); + case 'e': + case 'E': + downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; + if (downlink_mode == 4) try_all_dl_modes = true; + if (downlink_mode > 3) downlink_mode = 0; + cmdp +=2; + cmd_offset += 4; + PrintAndLog ("DL Mode : %d",downlink_mode); + break; + case 'i': + case 'I': + if (use_range) { + PrintAndLog ("use Range or File"); + return 0; + } + use_file = true; + len = strlen(Cmd+2); + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + memcpy(filename, Cmd+cmd_offset+2, len); + cmdp += 2; + // PrintAndLog (" File : [%s]",filename); + break; + case 'r': + case 'R': + if (use_file) { + PrintAndLog ("use Range or File"); + return 0; + } + use_range = true; // = param_get32ex(Cmd, cmdp+1, 0, 16); + start_password = param_get32ex(Cmd, cmdp+1, 0, 16); + end_password = param_get32ex(Cmd, cmdp+2, 0, 16); + cmdp += 3; + cmd_offset += 20; // 8 + 8 + 1 + 1 + 1 + // PrintAndLog (" Range : [%0X] - [%0X]",start_password,end_password); + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + +// if (cmdp == 'i' || cmdp == 'I') { + + if (use_file) + { + FILE * f = fopen( filename , "r"); + + if ( !f ) { + PrintAndLog("File: %s: not found or locked.", filename); + free(keyBlock); + return 1; + } + + while( fgets(buf, sizeof(buf), f) ) { + if (strlen(buf) < 8 || buf[7] == '\n') continue; + + while (fgetc(f) != '\n' && !feof(f)) ; //goto next line + + //The line start with # is comment, skip + if( buf[0]=='#' ) continue; + + if (!isxdigit((unsigned char)buf[0])) { + PrintAndLog("File content error. '%s' must include 8 HEX symbols", buf); + continue; + } + + buf[8] = 0; + + if ( stKeyBlock - keycnt < 2) { + p = realloc(keyBlock, 6*(stKeyBlock+=10)); + if (!p) { + PrintAndLog("Cannot allocate memory for defaultKeys"); + free(keyBlock); + fclose(f); + return 2; + } + keyBlock = p; + } + memset(keyBlock + 4 * keycnt, 0, 4); + num_to_bytes(strtoll(buf, NULL, 16), 4, keyBlock + 4*keycnt); + PrintAndLog("chk custom pwd[%2d] %08X", keycnt, bytes_to_num(keyBlock + 4*keycnt, 4)); + keycnt++; + memset(buf, 0, sizeof(buf)); + } + fclose(f); + + if (keycnt == 0) { + PrintAndLog("No keys found in file"); + free(keyBlock); + return 1; + } + PrintAndLog("Loaded %d keys", keycnt); + + // loop + uint64_t testpwd = 0x00; + for (uint16_t c = 0; c < keycnt; ++c ) { + + if (ukbhit()) { + ch = getchar(); + (void)ch; + printf("\naborted via keyboard!\n"); + free(keyBlock); + return 0; + } + + testpwd = bytes_to_num(keyBlock + 4*c, 4); + + PrintAndLog("Testing %08X", testpwd); + + // Try each downlink_mode of asked to + // donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3 + for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) + { + if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd,dl_mode)) { + PrintAndLog("Aquireing data from device failed. Quitting"); + free(keyBlock); + return 0; + } + + found = tryDetectModulation(); + + if ( found ) { + PrintAndLog("Found valid password: [%08X]", testpwd); + free(keyBlock); + // Add downlink mode to reference. + switch (dl_mode) { + case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; + case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; + case 2 : PrintAndLog ("Downlink : e 2 - Leading Zero Reference"); break; + case 3 : PrintAndLog ("Downlink : e 3 - 1 of 4 Coding"); break; + } + return 0; + } + if (!try_all_dl_modes) // Exit loop + dl_mode = 4; + } + } + PrintAndLog("Password NOT found."); + free(keyBlock); + return 0; + } + + if (use_range) + { + // incremental pwd range search + // start_password = param_get32ex(Cmd, 0, 0, 16); + // end_password = param_get32ex(Cmd, 1, 0, 16); + + if ( start_password >= end_password ) { + free(keyBlock); + return usage_t55xx_bruteforce_downlink(); + } + PrintAndLog("Search password range [%08X -> %08X]", start_password, end_password); + + uint32_t i = start_password; + + while ((!found) && (i <= end_password)) { + + printf("."); + fflush(stdout); + if (ukbhit()) { + ch = getchar(); + (void)ch; + printf("\naborted via keyboard!\n"); + free(keyBlock); + return 0; + } + + if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i,downlink_mode)) { + PrintAndLog("Aquireing data from device failed. Quitting"); + free(keyBlock); + return 0; + } + found = tryDetectModulation(); + + if (found) break; + i++; + } + + PrintAndLog(""); + + if (found) { + PrintAndLog("Found valid password: [%08x]", i); + // Add downlink mode to reference. + switch (downlink_mode) { + case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; + case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; + case 2 : PrintAndLog ("Downlink : e 2 - Leading Zero Reference"); break; + case 3 : PrintAndLog ("Downlink : e 3 - 1 of 4 Coding"); break; + } + } + else + PrintAndLog("Password NOT found. Last tried: [%08x]", --i); + + free(keyBlock); + } + return 0; +} + // note length of data returned is different for different chips. // some return all page 1 (64 bits) and others return just that block (32 bits) // unfortunately the 64 bits makes this more likely to get a false positive... @@ -1558,7 +1853,7 @@ bool tryDetectP1(bool getData) { bool st = true; if ( getData ) { - if ( !AquireData(T55x7_PAGE1, 1, false, 0) ) + if ( !AquireData(T55x7_PAGE1, 1, false, 0,0) ) return false; } @@ -1687,7 +1982,7 @@ int CmdT55xxDetectPage1(const char *Cmd){ if (errors) return usage_t55xx_detectP1(); if ( !useGB ) { - if ( !AquireData(T55x7_PAGE1, 1, usepwd, password) ) + if ( !AquireData(T55x7_PAGE1, 1, usepwd, password,0) ) return false; } bool success = tryDetectP1(false); @@ -1697,7 +1992,8 @@ int CmdT55xxDetectPage1(const char *Cmd){ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"bruteforce",CmdT55xxBruteForce,0, " [i <*.dic>] Simple bruteforce attack to find password"}, + {"bruteforce",CmdT55xxBruteForce,0, " [i <*.dic>] Simple bruteforce attack to find password"}, + {"bruteforcedl",CmdT55xxBruteForce_downlink,0, "r [i <*.dic>] [e ] Simple bruteforce attack to find password"}, {"config", CmdT55xxSetConfig, 1, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"}, {"detect", CmdT55xxDetect, 1, "[1] Try detecting the tag modulation from reading the configuration block."}, {"p1detect", CmdT55xxDetectPage1,1, "[1] Try detecting if this is a t55xx tag by reading page 1"}, diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index 2ae3e69b..1ba4dca4 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -74,6 +74,7 @@ void Set_t55xx_Config(t55xx_conf_block_t conf); extern int CmdLFT55XX(const char *Cmd); extern int CmdT55xxBruteForce(const char *Cmd); +extern int CmdT55xxBruteForce_downlink(const char *Cmd); extern int CmdT55xxSetConfig(const char *Cmd); extern int CmdT55xxReadBlock(const char *Cmd); extern int CmdT55xxWriteBlock(const char *Cmd); @@ -98,7 +99,7 @@ bool tryDetectModulation(void); extern bool tryDetectP1(bool getData); bool test(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk, bool *Q5); int special(const char *Cmd); -int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password ); +int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password,uint8_t downlink_mode ); void printT55x7Trace( t55x7_tracedata_t data, uint8_t repeat ); void printT5555Trace( t5555_tracedata_t data, uint8_t repeat ); -- 2.39.5 From 6dd0ff3035ed40ab47f22d76dbc22942a492dca3 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Mon, 17 Jun 2019 21:37:50 +1000 Subject: [PATCH 16/16] Update cmdlft55xx.c Minor Cleanup --- client/cmdlft55xx.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 25df4c76..a05838b4 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -67,8 +67,8 @@ int usage_t55xx_read(){ PrintAndLog(" p - OPTIONAL password (8 hex characters)"); PrintAndLog(" o - OPTIONAL override safety check"); PrintAndLog(" 1 - OPTIONAL read Page 1 instead of Page 0"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); - PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(" ****WARNING****"); PrintAndLog(" Use of read with password on a tag not configured for a pwd"); PrintAndLog(" can damage the tag"); @@ -88,8 +88,8 @@ int usage_t55xx_write(){ PrintAndLog(" p - OPTIONAL password 4bytes (8 hex characters)"); PrintAndLog(" 1 - OPTIONAL write Page 1 instead of Page 0"); PrintAndLog(" t - OPTIONAL test mode write - ****DANGER****"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); - PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx write b 3 d 11223344 - write 11223344 to block 3"); @@ -136,8 +136,8 @@ int usage_t55xx_detect(){ PrintAndLog("Options:"); PrintAndLog(" 1 - if set, use Graphbuffer otherwise read data from tag."); PrintAndLog(" p - OPTIONAL password (8 hex characters)"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); - PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx detect"); @@ -196,9 +196,10 @@ int usage_t55xx_bruteforce_downlink(){ PrintAndLog("Options:"); PrintAndLog(" h - this help"); PrintAndLog(" r - 4 byte hex value to start and end pwd search at"); - PrintAndLog(" i <*.dic> - loads a default keys dictionary file <*.dic>"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); - PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); + PrintAndLog(" i <*.dic> - loads a default keys dictionary file <*.dic>"); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default)"); + PrintAndLog(" '1' long leading reference, '2' leading zero "); + PrintAndLog(" '3' 1 of 4 coding reference, '4' special - try all downlink modes"); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx bruteforce aaaaaaaa bbbbbbbb"); -- 2.39.5