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..2f881652 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1264,6 +1264,7 @@ static void PrepareDelayedTransfer(uint16_t delay) //------------------------------------------------------------------------------------- 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); @@ -1299,6 +1300,7 @@ static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing } NextTransferTime = MAX(NextTransferTime, LastTimeProxToAirStart + REQUEST_GUARD_TIME); + LED_B_OFF(); } @@ -1420,8 +1422,6 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity) // 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); for(;;) { @@ -1463,12 +1463,13 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity) 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 @@ -1516,6 +1517,7 @@ static int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) } } + LED_C_OFF(); return 0; } @@ -1762,7 +1764,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u // 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. + // 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; diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c index c9264836..3d31e3a4 100644 --- a/armsrc/mifaresim.c +++ b/armsrc/mifaresim.c @@ -32,19 +32,17 @@ #define MFEMUL_SELECT3 4 #define MFEMUL_AUTH1 5 #define MFEMUL_AUTH2 6 -#define MFEMUL_WORK 7 +#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 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 >= 2) { + 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 >= 2) { 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 >= 2) { + 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 >= 2) { + 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 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) // 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,24 @@ 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_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_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; @@ -297,25 +344,27 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * 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 + + 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; @@ -328,8 +377,8 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * // 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 +386,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; @@ -349,18 +398,19 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * if (cardSTATE == MFEMUL_NOFIELD) { 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; } + FpgaEnableTracing(); //Now, get data int res = EmGetCmd(receivedCmd, &receivedCmd_len, receivedCmd_par); - + if (res == 2) { //Field is off! - LEDsoff(); + LED_D_OFF(); cardSTATE = MFEMUL_NOFIELD; continue; } else if (res == 1) { // button pressed @@ -371,6 +421,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,12 +429,10 @@ 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: @@ -393,8 +442,9 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * 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"); + if (MF_DBGLEVEL >= 4) Dbprintf("SELECT ALL CL1 received"); EmSendPrecompiledCmd(&responses[UIDBCC1]); + FpgaDisableTracing(); break; } // select card - 0x93 0x70 ... @@ -403,41 +453,44 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * 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(); + FpgaDisableTracing(); cardSTATE = MFEMUL_WORK; break; } else if (uid_len == 7) { EmSendPrecompiledCmd(&responses[SAK1]); - cardSTATE = MFEMUL_SELECT2; + FpgaDisableTracing(); + cardSTATE = MFEMUL_SELECT2; 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"); + if (MF_DBGLEVEL >= 4) Dbprintf("SELECT ALL CL2 received"); EmSendPrecompiledCmd(&responses[UIDBCC2]); + FpgaDisableTracing(); 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(); 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 + FpgaDisableTracing(); break; } bool encrypted_data = (cardAUTHKEY != AUTHKEYNONE) ; @@ -448,35 +501,43 @@ 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)); + FpgaDisableTracing(); 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 >= 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]); 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 + 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 unencrypted nonce + EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT)); } 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 } - EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT)); + FpgaDisableTracing(); cardSTATE = MFEMUL_AUTH1; break; } + if (!encrypted_data) { // all other commands must be encrypted (authenticated) + FpgaDisableTracing(); break; } if(receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK @@ -485,13 +546,15 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * || 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)); + FpgaDisableTracing(); 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]); break; } - if (receivedCmd_dec[1] / 4 != cardAUTHSC) { + if (BlockToSector(receivedCmd_dec[1]) != cardAUTHSC) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + FpgaDisableTracing(); 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); break; } @@ -503,21 +566,22 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } 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(); numReads++; if(exitAfterNReads > 0 && numReads == exitAfterNReads) { Dbprintf("%d reads done, exiting", numReads); @@ -529,6 +593,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * 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(); cardWRBL = blockNo; cardSTATE = MFEMUL_WRITEBL2; break; @@ -539,9 +604,11 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * 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(); break; } EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + FpgaDisableTracing(); cardWRBL = blockNo; if (receivedCmd_dec[0] == MIFARE_CMD_INC) cardSTATE = MFEMUL_INTREG_INC; @@ -558,24 +625,23 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); else EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + FpgaDisableTracing(); 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(); + if (MF_DBGLEVEL >= 4) Dbprintf("--> HALTED."); cardSTATE = MFEMUL_HALTED; break; } // command not allowed - if (MF_DBGLEVEL >= 4) Dbprintf("Received command not allowed, nacking"); + if (MF_DBGLEVEL >= 4) Dbprintf("Received command not allowed, nacking"); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); break; } case MFEMUL_AUTH1:{ if (receivedCmd_len != 8) { - cardSTATE_TO_IDLE(); + cardSTATE = MFEMUL_IDLE; break; } @@ -590,7 +656,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 +684,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; @@ -657,15 +723,16 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * // 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 >= 4) Dbprintf("AUTH COMPLETED for sector %d with key %c.", cardAUTHSC, cardAUTHKEY == AUTHKEYA ? 'A' : 'B'); cardSTATE = MFEMUL_WORK; break; } @@ -676,26 +743,27 @@ 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? + FpgaDisableTracing(); cardSTATE = MFEMUL_WORK; break; } } - cardSTATE_TO_IDLE(); + cardSTATE = MFEMUL_IDLE; break; } case MFEMUL_INTREG_INC:{ @@ -703,7 +771,8 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * 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(); + FpgaDisableTracing(); + cardSTATE = MFEMUL_IDLE; break; } cardINTREG = cardINTREG + ans; @@ -716,7 +785,8 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * 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(); + FpgaDisableTracing(); + cardSTATE = MFEMUL_IDLE; break; } } @@ -728,7 +798,8 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * 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(); + FpgaDisableTracing(); + cardSTATE = MFEMUL_IDLE; break; } cardSTATE = MFEMUL_WORK; @@ -742,7 +813,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * LEDsoff(); if(flags & FLAG_NR_AR_ATTACK && MF_DBGLEVEL >= 1) { - for ( uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { + 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 >= 1) 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..563afc06 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -47,14 +47,14 @@ 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]; + 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))); @@ -62,6 +62,10 @@ void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, u 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; diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index b2912895..6e9c1dac 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -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/cmdhfmf.c b/client/cmdhfmf.c index 1c006fbf..4ba000f3 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 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) { @@ -1565,13 +1576,18 @@ 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): + flags & FLAG_10B_UID_IN_DATA ? sprint_hex(uid,10): "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); @@ -1595,20 +1611,25 @@ int CmdHF14AMf1kSim(const char *Cmd) { 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); + 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): + flags & FLAG_10B_UID_IN_DATA ? sprint_hex(uid,10): "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); 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 +1766,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 +2946,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"},