From 9ca155ba443e8f2a9feb7640f4b461842cce9e35 Mon Sep 17 00:00:00 2001 From: "Merlokbr@gmail.com" Date: Fri, 10 Jun 2011 13:35:10 +0000 Subject: [PATCH] 0. its alpha version!!! 1. commands changed from "hf 14a" to "hf mf" 2. some code cleaning and small bugfixes 3. alpha version hf mf sim 4. added internal function GetTickCount() for time measuring --- armsrc/appmain.c | 4 +- armsrc/apps.h | 2 + armsrc/iso14443a.c | 277 +++++++++++++++++++++- armsrc/mifareutil.c | 1 + armsrc/mifareutil.h | 10 +- armsrc/util.c | 27 +++ armsrc/util.h | 5 + client/Makefile | 1 + client/cmdhf.c | 2 + client/cmdhf14a.c | 512 ++-------------------------------------- client/cmdhfmf.c | 559 ++++++++++++++++++++++++++++++++++++++++++++ client/cmdhfmf.h | 29 +++ client/util.c | 4 + include/usb_cmd.h | 89 +++---- 14 files changed, 974 insertions(+), 548 deletions(-) create mode 100644 client/cmdhfmf.c create mode 100644 client/cmdhfmf.h diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 49718ee8..501f07a5 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -171,7 +171,7 @@ static int ReadAdc(int ch) return d; } -static int AvgAdc(int ch) +int AvgAdc(int ch) // was static - merlok { int i; int a = 0; @@ -930,6 +930,8 @@ void __attribute__((noreturn)) AppMain(void) // Load the FPGA image, which we have stored in our flash. FpgaDownloadAndGo(); + StartTickCount(); + #ifdef WITH_LCD LCDInit(); diff --git a/armsrc/apps.h b/armsrc/apps.h index 322f2674..3b461136 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -33,6 +33,8 @@ void DbpString(char *str); void Dbprintf(const char *fmt, ...); void Dbhexdump(int len, uint8_t *d); +int AvgAdc(int ch); + void ToSendStuffBit(int b); void ToSendReset(void); void ListenReaderField(int limit); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 9e1eea54..fb50cc82 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -932,6 +932,7 @@ static int GetIso14443aCommandFromReader(uint8_t *received, int *len, int maxLen } } } +static int EmSendCmd14443aRaw(uint8_t *resp, int respLen, int correctionNeeded); //----------------------------------------------------------------------------- // Main loop of simulated tag: receive commands from reader, decide what @@ -1180,8 +1181,13 @@ ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); } if(respLen <= 0) continue; + //---------------------------- + u = 0; + b = 0x00; + fdt_indicator = FALSE; - // Modulate Manchester + EmSendCmd14443aRaw(resp, respLen, receivedCmd[0] == 0x52); +/* // Modulate Manchester FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD); AT91C_BASE_SSC->SSC_THR = 0x00; FpgaSetupSsc(); @@ -1213,7 +1219,7 @@ ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); break; } } - +*/ } Dbprintf("%x %x %x", happened, happened2, cmdsRecvd); @@ -1398,6 +1404,133 @@ void CodeIso14443aAsReaderPar(const uint8_t * cmd, int len, uint32_t dwParity) ToSendMax++; } +//----------------------------------------------------------------------------- +// Wait for commands from reader +// Stop when button is pressed (return 1) or field was gone (return 2) +// Or return 0 when command is captured +//----------------------------------------------------------------------------- +static int EmGetCmd(uint8_t *received, int *len, int maxLen) +{ + *len = 0; + + uint32_t timer = 0, vtime = 0; + int analogCnt = 0; + int analogAVG = 0; + + // 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 ADC to read field strength + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST; + AT91C_BASE_ADC->ADC_MR = + ADC_MODE_PRESCALE(32) | + ADC_MODE_STARTUP_TIME(16) | + ADC_MODE_SAMPLE_HOLD_TIME(8); + AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ADC_CHAN_HF); + // start ADC + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; + + // Now run a 'software UART' on the stream of incoming samples. + Uart.output = received; + Uart.byteCntMax = maxLen; + Uart.state = STATE_UNSYNCD; + + for(;;) { + WDT_HIT(); + + if (BUTTON_PRESS()) return 1; + + // test if the field exists + if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF)) { + analogCnt++; + analogAVG += AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF]; + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; + if (analogCnt >= 32) { + if ((33000 * (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; + } + } + // transmit none + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x00; + } + // receive and test the miller decoding + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + if(MillerDecoding((b & 0xf0) >> 4)) { + *len = Uart.byteCnt; + return 0; + } + if(MillerDecoding(b & 0x0f)) { + *len = Uart.byteCnt; + return 0; + } + } + } +} + +static int EmSendCmd14443aRaw(uint8_t *resp, int respLen, int correctionNeeded) +{ + int i, u = 0; + uint8_t b = 0; + + // Modulate Manchester + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD); + AT91C_BASE_SSC->SSC_THR = 0x00; + FpgaSetupSsc(); + + // include correction bit + i = 1; + if((Uart.parityBits & 0x01) || correctionNeeded) { + // 1236, so correction bit needed + i = 0; + } + + // send cycle + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + (void)b; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + if(i > respLen) { + b = 0x00; + u++; + } else { + b = resp[i]; + i++; + } + AT91C_BASE_SSC->SSC_THR = b; + + if(u > 4) break; + } + if(BUTTON_PRESS()) { + break; + } + } + + return 0; +} + +static int EmSendCmdEx(uint8_t *resp, int respLen, int correctionNeeded){ + CodeIso14443aAsTag(resp, respLen); + return EmSendCmd14443aRaw(ToSend, ToSendMax, correctionNeeded); +} + +static int EmSendCmd(uint8_t *resp, int respLen){ + return EmSendCmdEx(resp, respLen, 0); +} + //----------------------------------------------------------------------------- // Wait a certain time for tag response // If a response is captured return TRUE @@ -2390,33 +2523,161 @@ void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { int cardSTATE = MFEMUL_NOFIELD; + int vHf = 0; // in mV + int res; + uint32_t timer = 0; + int len = 0; + uint8_t cardAUTHSC = 0; + uint8_t cardAUTHKEY = 0xff; // no authentication + uint32_t cuid = 0; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + uint64_t key64 = 0xffffffffffffULL; + + uint8_t* receivedCmd = mifare_get_bigbufptr(); + + static uint8_t rATQA[] = {0x04, 0x00}; // Mifare classic 1k + + static uint8_t rUIDBCC1[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; + static uint8_t rUIDBCC2[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; // !!! + + static uint8_t rSAK[] = {0x08, 0xb6, 0xdd}; + + static uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04}; + +// -------------------------------------- test area - while (true) { +// -------------------------------------- END test area + + // We need to listen to the high-frequency, peak-detected path. + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); + SpinDelay(200); + +Dbprintf("--> start"); + while (true) { + WDT_HIT(); +// timer = GetTickCount(); +// Dbprintf("time: %d", GetTickCount() - timer); + + // find reader field + // Vref = 3300mV, and an 10:1 voltage divider on the input + // can measure voltages up to 33000 mV + if (cardSTATE == MFEMUL_NOFIELD) { + vHf = (33000 * AvgAdc(ADC_CHAN_HF)) >> 10; + if (vHf > MF_MINFIELDV) { + cardSTATE = MFEMUL_IDLE; + LED_A_ON(); + } + } + + if (cardSTATE != MFEMUL_NOFIELD) { + res = EmGetCmd(receivedCmd, &len, 100); + if (res == 2) { + cardSTATE = MFEMUL_NOFIELD; + LEDsoff(); + continue; + } + if(res) break; + } + if(BUTTON_PRESS()) { - break; - } + break; + } +// if (len) Dbprintf("len:%d cmd: %02x %02x %02x %02x", len, receivedCmd[0], receivedCmd[1], receivedCmd[2], receivedCmd[3]); + switch (cardSTATE) { case MFEMUL_NOFIELD:{ break; } + case MFEMUL_HALTED:{ + // WUP request + if (!(len == 1 && receivedCmd[0] == 0x52)) break; + } case MFEMUL_IDLE:{ + // REQ or WUP request + if (len == 1 && (receivedCmd[0] == 0x26 || receivedCmd[0] == 0x52)) { +timer = GetTickCount(); + EmSendCmdEx(rATQA, sizeof(rATQA), (receivedCmd[0] == 0x52)); + cardSTATE = MFEMUL_SELECT1; + + // init crypto block + crypto1_destroy(pcs); + cardAUTHKEY = 0xff; + } break; } case MFEMUL_SELECT1:{ + // select all + if (len == 2 && (receivedCmd[0] == 0x93 && receivedCmd[1] == 0x20)) { + EmSendCmd(rUIDBCC1, sizeof(rUIDBCC1)); + + if (rUIDBCC1[0] == 0x88) { + cardSTATE = MFEMUL_SELECT2; + } + } + + // select card + if (len == 9 && (receivedCmd[0] == 0x93 && receivedCmd[1] == 0x70)) { + EmSendCmd(rSAK, sizeof(rSAK)); + + cuid = bytes_to_num(rUIDBCC1, 4); + cardSTATE = MFEMUL_WORK; + LED_B_ON(); +Dbprintf("--> WORK. anticol1 time: %d", GetTickCount() - timer); + } + break; } case MFEMUL_SELECT2:{ + EmSendCmd(rUIDBCC2, sizeof(rUIDBCC2)); + + cuid = bytes_to_num(rUIDBCC2, 4); + cardSTATE = MFEMUL_WORK; + LED_B_ON(); +Dbprintf("--> WORK. anticol2 time: %d", GetTickCount() - timer); break; } case MFEMUL_AUTH1:{ +if (len) Dbprintf("au1 len:%d cmd: %02x %02x %02x %02x", len, receivedCmd[0], receivedCmd[1], receivedCmd[2], receivedCmd[3]); + if (len == 8) { + + } break; } case MFEMUL_AUTH2:{ + + LED_C_ON(); +Dbprintf("AUTH COMPLETED. sec=%d, key=%d time=%d", cardAUTHSC, cardAUTHKEY, GetTickCount() - timer); break; } - case MFEMUL_HALTED:{ + case MFEMUL_WORK:{ + // auth + if (len == 4 && (receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61)) { +timer = GetTickCount(); + crypto1_create(pcs, key64); +// if (cardAUTHKEY == 0xff) { // first auth + crypto1_word(pcs, cuid ^ bytes_to_num(rAUTH_NT, 4), 0); // uid ^ nonce +// } else { // nested auth +// } + + EmSendCmd(rAUTH_NT, sizeof(rAUTH_NT)); + cardAUTHSC = receivedCmd[1]; + cardAUTHKEY = receivedCmd[0] - 0x60; + cardSTATE = MFEMUL_AUTH1; + } + + // halt + if (len == 4 && (receivedCmd[0] == 0x50 || receivedCmd[0] == 0x00)) { + cardSTATE = MFEMUL_HALTED; + LED_B_OFF(); + } break; } @@ -2424,4 +2685,8 @@ void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + + DbpString("Emulator stopped."); } diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 53e785f5..fc95de72 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -266,3 +266,4 @@ int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) return 0; } + diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index 9a909a35..4433fe65 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -8,15 +8,20 @@ //----------------------------------------------------------------------------- // code for work with mifare cards. //----------------------------------------------------------------------------- + #ifndef __MIFAREUTIL_H #define __MIFAREUTIL_H +// mifare authentication #define CRYPT_NONE 0 #define CRYPT_ALL 1 #define CRYPT_REQUEST 2 #define AUTH_FIRST 0 #define AUTH_NESTED 2 +// reader voltage field detector +#define MF_MINFIELDV 4000 + // debug // 0 - no debug messages 1 - error messages 2 - all messages 4 - extended debug mode #define MF_DBG_NONE 0 @@ -33,14 +38,15 @@ extern int MF_DBGLEVEL; #define NS_RETRIES_GETNONCE 15 #define NES_MAX_INFO 5 -//mifare emulate states +//mifare emulator states #define MFEMUL_NOFIELD 0 #define MFEMUL_IDLE 1 #define MFEMUL_SELECT1 2 #define MFEMUL_SELECT2 3 #define MFEMUL_AUTH1 4 #define MFEMUL_AUTH2 5 -#define MFEMUL_HALTED 6 +#define MFEMUL_WORK 6 +#define MFEMUL_HALTED 7 //functions uint8_t* mifare_get_bigbufptr(void); diff --git a/armsrc/util.c b/armsrc/util.c index 5a8cfeec..9c6b3e8d 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -235,3 +235,30 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers strncat(dst, " ", len); strncat(dst, v->buildtime, len); } + +// ------------------------------------------------------------------------- +// timer lib +// ------------------------------------------------------------------------- +// test procedure: +// +// ti = GetTickCount(); +// SpinDelay(1000); +// ti = GetTickCount() - ti; +// Dbprintf("timer(1s): %d t=%d", ti, GetTickCount()); + +void StartTickCount() +{ +// must be 0x40, but on my cpu - included divider is optimal +// 0x20 - 1 ms / bit +// 0x40 - 2 ms / bit + + AT91C_BASE_RTTC->RTTC_RTMR = AT91C_RTTC_RTTRST + 0x003B; +} + +/* +* Get the current count. +*/ +uint32_t RAMFUNC GetTickCount(){ + return AT91C_BASE_RTTC->RTTC_RTVR * 2; +} + diff --git a/armsrc/util.h b/armsrc/util.h index 34760ab1..080dac6b 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -14,6 +14,8 @@ #include #include +#define RAMFUNC __attribute((long_call, section(".ramfunc"))) + #define BYTEx(x, n) (((x) >> (n * 8)) & 0xff ) #define LED_RED 1 @@ -37,4 +39,7 @@ int BUTTON_CLICKED(int ms); int BUTTON_HELD(int ms); void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information); +void StartTickCount(); +uint32_t RAMFUNC GetTickCount(); + #endif diff --git a/client/Makefile b/client/Makefile index cf647c38..c76edf52 100644 --- a/client/Makefile +++ b/client/Makefile @@ -58,6 +58,7 @@ CMDSRCS = \ cmdhf15.c \ cmdhflegic.c \ cmdhficlass.c \ + cmdhfmf.c \ cmdhw.c \ cmdlf.c \ cmdlfem4x.c \ diff --git a/client/cmdhf.c b/client/cmdhf.c index 15b9e984..87c819fb 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -19,6 +19,7 @@ #include "cmdhf15.h" #include "cmdhflegic.h" #include "cmdhficlass.h" +#include "cmdhfmf.h" static int CmdHelp(const char *Cmd); @@ -37,6 +38,7 @@ static command_t CommandTable[] = {"15", CmdHF15, 1, "{ ISO15693 RFIDs... }"}, {"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"}, {"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"}, + {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index f2774a16..2a8c1f87 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -13,7 +13,6 @@ #include #include #include -#include #include "util.h" #include "iso14443crc.h" #include "data.h" @@ -23,9 +22,6 @@ #include "cmdhf14a.h" #include "common.h" #include "cmdmain.h" -#include "nonce2key/nonce2key.h" -#include "nonce2key/crapto1.h" -#include "mifarehost.h" static int CmdHelp(const char *Cmd); @@ -161,500 +157,13 @@ void iso14a_set_timeout(uint32_t timeout) { SendCommand(&c); } -int CmdHF14AMifare(const char *Cmd) -{ - uint32_t uid = 0; - uint32_t nt = 0; - uint64_t par_list = 0, ks_list = 0, r_key = 0; - uint8_t isOK = 0; - uint8_t keyBlock[6] = {0,0,0,0,0,0}; - - if (param_getchar(Cmd, 0) && param_gethex(Cmd, 0, keyBlock, 8)) { - PrintAndLog("Nt must include 8 HEX symbols"); - return 1; - } - - UsbCommand c = {CMD_READER_MIFARE, {(uint32_t)bytes_to_num(keyBlock, 4), 0, 0}}; - SendCommand(&c); - - //flush queue - while (ukbhit()) getchar(); - - // message - printf("-------------------------------------------------------------------------\n"); - printf("Executing command. It may take up to 30 min.\n"); - printf("Press the key on proxmark3 device to abort proxmark3.\n"); - printf("Press the key on the proxmark3 device to abort both proxmark3 and client.\n"); - printf("-------------------------------------------------------------------------\n"); - - // wait cycle - while (true) { - printf("."); - if (ukbhit()) { - getchar(); - printf("\naborted via keyboard!\n"); - break; - } - - UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 2000); - if (resp != NULL) { - isOK = resp->arg[0] & 0xff; - - uid = (uint32_t)bytes_to_num(resp->d.asBytes + 0, 4); - nt = (uint32_t)bytes_to_num(resp->d.asBytes + 4, 4); - par_list = bytes_to_num(resp->d.asBytes + 8, 8); - ks_list = bytes_to_num(resp->d.asBytes + 16, 8); - - printf("\n\n"); - PrintAndLog("isOk:%02x", isOK); - if (!isOK) PrintAndLog("Proxmark can't get statistic info. Execution aborted.\n"); - break; - } - } - printf("\n"); - - // error - if (isOK != 1) return 1; - - // execute original function from util nonce2key - if (nonce2key(uid, nt, par_list, ks_list, &r_key)) return 2; - printf("------------------------------------------------------------------\n"); - PrintAndLog("Key found:%012llx \n", r_key); - - num_to_bytes(r_key, 6, keyBlock); - isOK = mfCheckKeys(0, 0, 1, keyBlock, &r_key); - if (!isOK) - PrintAndLog("Found valid key:%012llx", r_key); - else - PrintAndLog("Found invalid key. ("); - - - return 0; -} - -int CmdHF14AMfWrBl(const char *Cmd) -{ - uint8_t blockNo = 0; - uint8_t keyType = 0; - 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; - - if (strlen(Cmd)<3) { - PrintAndLog("Usage: hf 14 mfwrbl "); - PrintAndLog(" sample: hf 14a mfwrbl 0 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F"); - return 0; - } - - blockNo = param_get8(Cmd, 0); - cmdp = param_getchar(Cmd, 1); - if (cmdp == 0x00) { - PrintAndLog("Key type must be A or B"); - return 1; - } - if (cmdp != 'A' && cmdp != 'a') keyType = 1; - if (param_gethex(Cmd, 2, key, 12)) { - PrintAndLog("Key must include 12 HEX symbols"); - return 1; - } - if (param_gethex(Cmd, 3, bldata, 32)) { - PrintAndLog("Block data must include 32 HEX symbols"); - return 1; - } - PrintAndLog("--block no:%02x key type:%02x key:%s", blockNo, keyType, sprint_hex(key, 6)); - PrintAndLog("--data: %s", sprint_hex(bldata, 16)); - - UsbCommand c = {CMD_MIFARE_WRITEBL, {blockNo, keyType, 0}}; - memcpy(c.d.asBytes, key, 6); - memcpy(c.d.asBytes + 10, bldata, 16); - SendCommand(&c); - UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500); - - if (resp != NULL) { - uint8_t isOK = resp->arg[0] & 0xff; - - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - - return 0; -} - -int CmdHF14AMfRdBl(const char *Cmd) -{ - uint8_t blockNo = 0; - uint8_t keyType = 0; - uint8_t key[6] = {0, 0, 0, 0, 0, 0}; - - char cmdp = 0x00; - - - if (strlen(Cmd)<3) { - PrintAndLog("Usage: hf 14 mfrdbl "); - PrintAndLog(" sample: hf 14a mfrdbl 0 A FFFFFFFFFFFF "); - return 0; - } - - blockNo = param_get8(Cmd, 0); - cmdp = param_getchar(Cmd, 1); - if (cmdp == 0x00) { - PrintAndLog("Key type must be A or B"); - return 1; - } - if (cmdp != 'A' && cmdp != 'a') keyType = 1; - if (param_gethex(Cmd, 2, key, 12)) { - PrintAndLog("Key must include 12 HEX symbols"); - return 1; - } - PrintAndLog("--block no:%02x key type:%02x key:%s ", blockNo, keyType, sprint_hex(key, 6)); - - UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}}; - memcpy(c.d.asBytes, key, 6); - SendCommand(&c); - UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500); - - if (resp != NULL) { - uint8_t isOK = resp->arg[0] & 0xff; - uint8_t * data = resp->d.asBytes; - - if (isOK) - PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 16)); - else - PrintAndLog("isOk:%02x", isOK); - } else { - PrintAndLog("Command execute timeout"); - } - - return 0; -} - -int CmdHF14AMfRdSc(const char *Cmd) -{ - int i; - uint8_t sectorNo = 0; - uint8_t keyType = 0; - uint8_t key[6] = {0, 0, 0, 0, 0, 0}; - - uint8_t isOK = 0; - uint8_t * data = NULL; - - char cmdp = 0x00; - - if (strlen(Cmd)<3) { - PrintAndLog("Usage: hf 14 mfrdsc "); - PrintAndLog(" sample: hf 14a mfrdsc 0 A FFFFFFFFFFFF "); - return 0; - } - - sectorNo = param_get8(Cmd, 0); - if (sectorNo > 63) { - PrintAndLog("Sector number must be less than 64"); - return 1; - } - cmdp = param_getchar(Cmd, 1); - if (cmdp == 0x00) { - PrintAndLog("Key type must be A or B"); - return 1; - } - if (cmdp != 'A' && cmdp != 'a') keyType = 1; - if (param_gethex(Cmd, 2, key, 12)) { - PrintAndLog("Key must include 12 HEX symbols"); - return 1; - } - PrintAndLog("--sector no:%02x key type:%02x key:%s ", sectorNo, keyType, sprint_hex(key, 6)); - - UsbCommand c = {CMD_MIFARE_READSC, {sectorNo, keyType, 0}}; - memcpy(c.d.asBytes, key, 6); - SendCommand(&c); - UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500); - PrintAndLog(" "); - - if (resp != NULL) { - isOK = resp->arg[0] & 0xff; - data = resp->d.asBytes; - - PrintAndLog("isOk:%02x", isOK); - if (isOK) - for (i = 0; i < 2; i++) { - PrintAndLog("data:%s", sprint_hex(data + i * 16, 16)); - } - } else { - PrintAndLog("Command1 execute timeout"); - } - - // response2 - resp = WaitForResponseTimeout(CMD_ACK, 500); - PrintAndLog(" "); - - if (resp != NULL) { - isOK = resp->arg[0] & 0xff; - data = resp->d.asBytes; - - if (isOK) - for (i = 0; i < 2; i++) { - PrintAndLog("data:%s", sprint_hex(data + i * 16, 16)); - } - } else { - PrintAndLog("Command2 execute timeout"); - } - - return 0; -} - -int CmdHF14AMfNested(const char *Cmd) -{ - int i, j, res, iterations; - sector * e_sector = NULL; - uint8_t blockNo = 0; - uint8_t keyType = 0; - uint8_t trgBlockNo = 0; - uint8_t trgKeyType = 0; - uint8_t blDiff = 0; - int SectorsCnt = 0; - uint8_t key[6] = {0, 0, 0, 0, 0, 0}; - uint8_t keyBlock[16 * 6]; - uint64_t key64 = 0; - - char cmdp, ctmp; - - if (strlen(Cmd)<3) { - PrintAndLog("Usage:"); - PrintAndLog(" all sectors: hf 14a nested "); - PrintAndLog(" one sector: hf 14a nested o "); - PrintAndLog(" "); - PrintAndLog("card memory - 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); - PrintAndLog(" "); - PrintAndLog(" sample1: hf 14a nested 1 0 A FFFFFFFFFFFF "); - PrintAndLog(" sample2: hf 14a nested o 0 A FFFFFFFFFFFF 4 A"); - return 0; - } - - cmdp = param_getchar(Cmd, 0); - blockNo = param_get8(Cmd, 1); - ctmp = param_getchar(Cmd, 2); - if (ctmp == 0x00) { - PrintAndLog("Key type must be A or B"); - return 1; - } - if (ctmp != 'A' && ctmp != 'a') keyType = 1; - if (param_gethex(Cmd, 3, key, 12)) { - PrintAndLog("Key must include 12 HEX symbols"); - return 1; - } - - if (cmdp =='o' || cmdp == 'O') { - cmdp = 'o'; - trgBlockNo = param_get8(Cmd, 4); - ctmp = param_getchar(Cmd, 5); - if (ctmp == 0x00) { - PrintAndLog("Target key type must be A or B"); - return 1; - } - if (ctmp != 'A' && ctmp != 'a') trgKeyType = 1; - } else { - switch (cmdp) { - case '1': SectorsCnt = 16; break; - case '2': SectorsCnt = 32; break; - case '4': SectorsCnt = 64; break; - default: SectorsCnt = 16; - } - } - - PrintAndLog("--block no:%02x key type:%02x key:%s ", blockNo, keyType, sprint_hex(key, 6)); - if (cmdp == 'o') - PrintAndLog("--target block no:%02x target key type:%02x ", trgBlockNo, trgKeyType); - - if (cmdp == 'o') { - if (mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock)) { - PrintAndLog("Nested error."); - return 2; - } - - for (i = 0; i < 16; i++) { - PrintAndLog("cnt=%d key= %s", i, sprint_hex(keyBlock + i * 6, 6)); - } - - // test keys - res = mfCheckKeys(trgBlockNo, trgKeyType, 8, keyBlock, &key64); - if (res) - res = mfCheckKeys(trgBlockNo, trgKeyType, 8, &keyBlock[6 * 8], &key64); - if (!res) - PrintAndLog("Found valid key:%012llx", key64); - else - PrintAndLog("No valid key found"); - } else // ------------------------------------ multiple sectors working - { - blDiff = blockNo % 4; - PrintAndLog("Block shift=%d", blDiff); - e_sector = calloc(SectorsCnt, sizeof(sector)); - if (e_sector == NULL) return 1; - - //test current key 4 sectors - memcpy(keyBlock, key, 6); - num_to_bytes(0xa0a1a2a3a4a5, 6, (uint8_t*)(keyBlock + 1 * 6)); - num_to_bytes(0xb0b1b2b3b4b5, 6, (uint8_t*)(keyBlock + 2 * 6)); - num_to_bytes(0xffffffffffff, 6, (uint8_t*)(keyBlock + 3 * 6)); - num_to_bytes(0x000000000000, 6, (uint8_t*)(keyBlock + 4 * 6)); - num_to_bytes(0xaabbccddeeff, 6, (uint8_t*)(keyBlock + 5 * 6)); - - PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt); - for (i = 0; i < SectorsCnt; i++) { - for (j = 0; j < 2; j++) { - if (e_sector[i].foundKey[j]) continue; - - res = mfCheckKeys(i * 4 + blDiff, j, 6, keyBlock, &key64); - - if (!res) { - e_sector[i].Key[j] = key64; - e_sector[i].foundKey[j] = 1; - } - } - } - - - // nested sectors - iterations = 0; - PrintAndLog("nested..."); - for (i = 0; i < NESTED_SECTOR_RETRY; i++) { - for (trgBlockNo = blDiff; trgBlockNo < SectorsCnt * 4; trgBlockNo = trgBlockNo + 4) - for (trgKeyType = 0; trgKeyType < 2; trgKeyType++) { - if (e_sector[trgBlockNo / 4].foundKey[trgKeyType]) continue; - if (mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock)) continue; - - iterations++; - - //try keys from nested - res = mfCheckKeys(trgBlockNo, trgKeyType, 8, keyBlock, &key64); - if (res) - res = mfCheckKeys(trgBlockNo, trgKeyType, 8, &keyBlock[6 * 8], &key64); - if (!res) { - PrintAndLog("Found valid key:%012llx", key64); - e_sector[trgBlockNo / 4].foundKey[trgKeyType] = 1; - e_sector[trgBlockNo / 4].Key[trgKeyType] = key64; - } - } - } - - PrintAndLog("Iterations count: %d", iterations); - //print them - PrintAndLog("|---|----------------|---|----------------|---|"); - PrintAndLog("|blk|key A |res|key B |res|"); - PrintAndLog("|---|----------------|---|----------------|---|"); - for (i = 0; i < SectorsCnt; i++) { - PrintAndLog("|%03d| %012llx | %d | %012llx | %d |", i, - e_sector[i].Key[0], e_sector[i].foundKey[0], e_sector[i].Key[1], e_sector[i].foundKey[1]); - } - PrintAndLog("|---|----------------|---|----------------|---|"); - - free(e_sector); - } - - return 0; -} - -int CmdHF14AMfChk(const char *Cmd) -{ - int i, res; - int keycnt = 0; - char ctmp = 0x00; - uint8_t blockNo = 0; - uint8_t keyType = 0; - uint8_t keyBlock[8 * 6]; - uint64_t key64 = 0; - - memset(keyBlock, 0x00, sizeof(keyBlock)); - - if (strlen(Cmd)<3) { - PrintAndLog("Usage: hf 14a chk []"); - PrintAndLog(" sample: hf 14a chk 0 A FFFFFFFFFFFF a0a1a2a3a4a5 b01b2b3b4b5 "); - return 0; - } - - blockNo = param_get8(Cmd, 0); - ctmp = param_getchar(Cmd, 1); - if (ctmp == 0x00) { - PrintAndLog("Key type must be A or B"); - return 1; - } - if (ctmp != 'A' && ctmp != 'a') keyType = 1; - - for (i = 0; i < 6; i++) { - if (!isxdigit(param_getchar(Cmd, 2 + i))) break; - - if (param_gethex(Cmd, 2 + i, keyBlock + 6 * i, 12)) { - PrintAndLog("Key[%d] must include 12 HEX symbols", i); - return 1; - } - keycnt = i + 1; - } - - if (keycnt == 0) { - PrintAndLog("There is must be at least one key"); - return 1; - } - - PrintAndLog("--block no:%02x key type:%02x key count:%d ", blockNo, keyType, keycnt); - - res = mfCheckKeys(blockNo, keyType, keycnt, keyBlock, &key64); - if (res !=1) { - if (!res) - PrintAndLog("isOk:%02x valid key:%012llx", 1, key64); - else - PrintAndLog("isOk:%02x", 0); - } else { - PrintAndLog("Command execute timeout"); - } - - return 0; -} - -int CmdHF14AMf1kSim(const char *Cmd) -{ - int i, temp; - uint8_t uid[4] = {0, 0, 0, 0}; - - const char *cmdp = Cmd; - - - if (strlen(Cmd)<3) { - PrintAndLog("Usage: hf 14a mfsim "); - PrintAndLog(" sample: hf 14a mfsim 0a0a0a0a "); - return 0; - } - - // skip spaces - while (*cmdp==' ' || *cmdp=='\t') cmdp++; - - if (strlen(cmdp) != 8) { - PrintAndLog("Length of UID must be 8 hex symbols"); - return 0; - } - - for(i = 0; i < 4; i++) { - sscanf((char[]){cmdp[0],cmdp[1],0},"%X",&temp); - uid[i] = temp & 0xff; - cmdp++; - cmdp++; - } - PrintAndLog(" uid:%s ", sprint_hex(uid, 4)); - - UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {0, 0, 0}}; - memcpy(c.d.asBytes, uid, 6); - SendCommand(&c); - - return 0; -} - - int CmdHF14AReader(const char *Cmd) { UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}}; SendCommand(&c); UsbCommand * resp = WaitForResponse(CMD_ACK); uint8_t * uid = resp->d.asBytes; - iso14a_card_select_t * card = uid + 12; + iso14a_card_select_t * card = (iso14a_card_select_t *)(uid + 12); if(resp->arg[0] == 0) { PrintAndLog("iso14443a card select failed"); @@ -664,6 +173,18 @@ int CmdHF14AReader(const char *Cmd) PrintAndLog("ATQA : %02x %02x", card->atqa[0], card->atqa[1]); PrintAndLog(" UID : %s", sprint_hex(uid, 12)); PrintAndLog(" SAK : %02x [%d]", card->sak, resp->arg[0]); + switch (card->sak) { + case 0: PrintAndLog(" SAK : MIFARE ultralight?"); break; + case 8: PrintAndLog(" SAK : MIFARE CLASSIC 1K"); break; + case 9: PrintAndLog(" SAK : MIFARE MINI"); break; + case 18: PrintAndLog(" SAK : MIFARE CLASSIC 4K"); break; + case 20: PrintAndLog(" SAK : MIFARE DESFIRE or JCOP 31/41"); break; + case 28: PrintAndLog(" SAK : JCOP31 or JCOP41 v2.3.1"); break; + case 38: PrintAndLog(" SAK : Nokia 6212 or 6131 MIFARE CLASSIC 4K"); break; + case 88: PrintAndLog(" SAK : Infineon MIFARE CLASSIC 1K"); break; + case 98: PrintAndLog(" SAK : Gemplus MPCOS"); break; + default: ; + } if(resp->arg[0] == 1) PrintAndLog(" ATS : %s", sprint_hex(card->ats, card->ats_len)); else @@ -702,13 +223,6 @@ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"list", CmdHF14AList, 0, "List ISO 14443a history"}, - {"mifare", CmdHF14AMifare, 0, "Read out sector 0 parity error messages. param - "}, - {"mfrdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"}, - {"mfrdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"}, - {"mfwrbl", CmdHF14AMfWrBl, 0, "Write MIFARE classic block"}, - {"nested", CmdHF14AMfNested, 0, "Test nested authentication"}, - {"chk", CmdHF14AMfChk, 0, "Test block up to 8 keys"}, - {"mfsim", CmdHF14AMf1kSim, 0, "Simulate MIFARE 1k card - NOT WORKING!!!"}, {"reader", CmdHF14AReader, 0, "Act like an ISO14443 Type A reader"}, {"sim", CmdHF14ASim, 0, " -- Fake ISO 14443a tag"}, {"snoop", CmdHF14ASnoop, 0, "Eavesdrop ISO 14443 Type A"}, diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c new file mode 100644 index 00000000..ee72dad5 --- /dev/null +++ b/client/cmdhfmf.c @@ -0,0 +1,559 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2011 Merlok +// +// 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 +// the license. +//----------------------------------------------------------------------------- +// High frequency MIFARE commands +//----------------------------------------------------------------------------- + +#include "cmdhfmf.h" + +static int CmdHelp(const char *Cmd); + + +int CmdHF14AMifare(const char *Cmd) +{ + uint32_t uid = 0; + uint32_t nt = 0; + uint64_t par_list = 0, ks_list = 0, r_key = 0; + uint8_t isOK = 0; + uint8_t keyBlock[6] = {0,0,0,0,0,0}; + + if (param_getchar(Cmd, 0) && param_gethex(Cmd, 0, keyBlock, 8)) { + PrintAndLog("Nt must include 8 HEX symbols"); + return 1; + } + + UsbCommand c = {CMD_READER_MIFARE, {(uint32_t)bytes_to_num(keyBlock, 4), 0, 0}}; + SendCommand(&c); + + //flush queue + while (ukbhit()) getchar(); + + // message + printf("-------------------------------------------------------------------------\n"); + printf("Executing command. It may take up to 30 min.\n"); + printf("Press the key on proxmark3 device to abort proxmark3.\n"); + printf("Press the key on the proxmark3 device to abort both proxmark3 and client.\n"); + printf("-------------------------------------------------------------------------\n"); + + // wait cycle + while (true) { + printf("."); + if (ukbhit()) { + getchar(); + printf("\naborted via keyboard!\n"); + break; + } + + UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 2000); + if (resp != NULL) { + isOK = resp->arg[0] & 0xff; + + uid = (uint32_t)bytes_to_num(resp->d.asBytes + 0, 4); + nt = (uint32_t)bytes_to_num(resp->d.asBytes + 4, 4); + par_list = bytes_to_num(resp->d.asBytes + 8, 8); + ks_list = bytes_to_num(resp->d.asBytes + 16, 8); + + printf("\n\n"); + PrintAndLog("isOk:%02x", isOK); + if (!isOK) PrintAndLog("Proxmark can't get statistic info. Execution aborted.\n"); + break; + } + } + printf("\n"); + + // error + if (isOK != 1) return 1; + + // execute original function from util nonce2key + if (nonce2key(uid, nt, par_list, ks_list, &r_key)) return 2; + printf("------------------------------------------------------------------\n"); + PrintAndLog("Key found:%012llx \n", r_key); + + num_to_bytes(r_key, 6, keyBlock); + isOK = mfCheckKeys(0, 0, 1, keyBlock, &r_key); + if (!isOK) + PrintAndLog("Found valid key:%012llx", r_key); + else + PrintAndLog("Found invalid key. ( Nt=%08x", nt); + + + return 0; +} + +int CmdHF14AMfWrBl(const char *Cmd) +{ + uint8_t blockNo = 0; + uint8_t keyType = 0; + 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; + + if (strlen(Cmd)<3) { + PrintAndLog("Usage: hf mf wrbl "); + PrintAndLog(" sample: hf mf wrbl 0 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F"); + return 0; + } + + blockNo = param_get8(Cmd, 0); + cmdp = param_getchar(Cmd, 1); + if (cmdp == 0x00) { + PrintAndLog("Key type must be A or B"); + return 1; + } + if (cmdp != 'A' && cmdp != 'a') keyType = 1; + if (param_gethex(Cmd, 2, key, 12)) { + PrintAndLog("Key must include 12 HEX symbols"); + return 1; + } + if (param_gethex(Cmd, 3, bldata, 32)) { + PrintAndLog("Block data must include 32 HEX symbols"); + return 1; + } + PrintAndLog("--block no:%02x key type:%02x key:%s", blockNo, keyType, sprint_hex(key, 6)); + PrintAndLog("--data: %s", sprint_hex(bldata, 16)); + + UsbCommand c = {CMD_MIFARE_WRITEBL, {blockNo, keyType, 0}}; + memcpy(c.d.asBytes, key, 6); + memcpy(c.d.asBytes + 10, bldata, 16); + SendCommand(&c); + UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500); + + if (resp != NULL) { + uint8_t isOK = resp->arg[0] & 0xff; + + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + + return 0; +} + +int CmdHF14AMfRdBl(const char *Cmd) +{ + uint8_t blockNo = 0; + uint8_t keyType = 0; + uint8_t key[6] = {0, 0, 0, 0, 0, 0}; + + char cmdp = 0x00; + + + if (strlen(Cmd)<3) { + PrintAndLog("Usage: hf mf rdbl "); + PrintAndLog(" sample: hf mf rdbl 0 A FFFFFFFFFFFF "); + return 0; + } + + blockNo = param_get8(Cmd, 0); + cmdp = param_getchar(Cmd, 1); + if (cmdp == 0x00) { + PrintAndLog("Key type must be A or B"); + return 1; + } + if (cmdp != 'A' && cmdp != 'a') keyType = 1; + if (param_gethex(Cmd, 2, key, 12)) { + PrintAndLog("Key must include 12 HEX symbols"); + return 1; + } + PrintAndLog("--block no:%02x key type:%02x key:%s ", blockNo, keyType, sprint_hex(key, 6)); + + UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}}; + memcpy(c.d.asBytes, key, 6); + SendCommand(&c); + UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500); + + if (resp != NULL) { + uint8_t isOK = resp->arg[0] & 0xff; + uint8_t * data = resp->d.asBytes; + + if (isOK) + PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 16)); + else + PrintAndLog("isOk:%02x", isOK); + } else { + PrintAndLog("Command execute timeout"); + } + + return 0; +} + +int CmdHF14AMfRdSc(const char *Cmd) +{ + int i; + uint8_t sectorNo = 0; + uint8_t keyType = 0; + uint8_t key[6] = {0, 0, 0, 0, 0, 0}; + + uint8_t isOK = 0; + uint8_t * data = NULL; + + char cmdp = 0x00; + + if (strlen(Cmd)<3) { + PrintAndLog("Usage: hf mf rdsc "); + PrintAndLog(" sample: hf mf rdsc 0 A FFFFFFFFFFFF "); + return 0; + } + + sectorNo = param_get8(Cmd, 0); + if (sectorNo > 63) { + PrintAndLog("Sector number must be less than 64"); + return 1; + } + cmdp = param_getchar(Cmd, 1); + if (cmdp == 0x00) { + PrintAndLog("Key type must be A or B"); + return 1; + } + if (cmdp != 'A' && cmdp != 'a') keyType = 1; + if (param_gethex(Cmd, 2, key, 12)) { + PrintAndLog("Key must include 12 HEX symbols"); + return 1; + } + PrintAndLog("--sector no:%02x key type:%02x key:%s ", sectorNo, keyType, sprint_hex(key, 6)); + + UsbCommand c = {CMD_MIFARE_READSC, {sectorNo, keyType, 0}}; + memcpy(c.d.asBytes, key, 6); + SendCommand(&c); + UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500); + PrintAndLog(" "); + + if (resp != NULL) { + isOK = resp->arg[0] & 0xff; + data = resp->d.asBytes; + + PrintAndLog("isOk:%02x", isOK); + if (isOK) + for (i = 0; i < 2; i++) { + PrintAndLog("data:%s", sprint_hex(data + i * 16, 16)); + } + } else { + PrintAndLog("Command1 execute timeout"); + } + + // response2 + resp = WaitForResponseTimeout(CMD_ACK, 500); + PrintAndLog(" "); + + if (resp != NULL) { + isOK = resp->arg[0] & 0xff; + data = resp->d.asBytes; + + if (isOK) + for (i = 0; i < 2; i++) { + PrintAndLog("data:%s", sprint_hex(data + i * 16, 16)); + } + } else { + PrintAndLog("Command2 execute timeout"); + } + + return 0; +} + +int CmdHF14AMfNested(const char *Cmd) +{ + int i, j, res, iterations; + sector * e_sector = NULL; + uint8_t blockNo = 0; + uint8_t keyType = 0; + uint8_t trgBlockNo = 0; + uint8_t trgKeyType = 0; + uint8_t blDiff = 0; + int SectorsCnt = 0; + uint8_t key[6] = {0, 0, 0, 0, 0, 0}; + uint8_t keyBlock[16 * 6]; + uint64_t key64 = 0; + + char cmdp, ctmp; + + if (strlen(Cmd)<3) { + PrintAndLog("Usage:"); + PrintAndLog(" all sectors: hf mf nested "); + PrintAndLog(" one sector: hf mf nested o "); + PrintAndLog(" "); + PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); + PrintAndLog(" "); + PrintAndLog(" sample1: hf mf nested 1 0 A FFFFFFFFFFFF "); + PrintAndLog(" sample2: hf mf nested o 0 A FFFFFFFFFFFF 4 A"); + return 0; + } + + cmdp = param_getchar(Cmd, 0); + blockNo = param_get8(Cmd, 1); + ctmp = param_getchar(Cmd, 2); + if (ctmp == 0x00) { + PrintAndLog("Key type must be A or B"); + return 1; + } + if (ctmp != 'A' && ctmp != 'a') keyType = 1; + if (param_gethex(Cmd, 3, key, 12)) { + PrintAndLog("Key must include 12 HEX symbols"); + return 1; + } + + if (cmdp =='o' || cmdp == 'O') { + cmdp = 'o'; + trgBlockNo = param_get8(Cmd, 4); + ctmp = param_getchar(Cmd, 5); + if (ctmp == 0x00) { + PrintAndLog("Target key type must be A or B"); + return 1; + } + if (ctmp != 'A' && ctmp != 'a') trgKeyType = 1; + } else { + switch (cmdp) { + case '0': SectorsCnt = 05; break; + case '1': SectorsCnt = 16; break; + case '2': SectorsCnt = 32; break; + case '4': SectorsCnt = 64; break; + default: SectorsCnt = 16; + } + } + + PrintAndLog("--block no:%02x key type:%02x key:%s ", blockNo, keyType, sprint_hex(key, 6)); + if (cmdp == 'o') + PrintAndLog("--target block no:%02x target key type:%02x ", trgBlockNo, trgKeyType); + + if (cmdp == 'o') { + if (mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock)) { + PrintAndLog("Nested error."); + return 2; + } + + for (i = 0; i < 16; i++) { + PrintAndLog("cnt=%d key= %s", i, sprint_hex(keyBlock + i * 6, 6)); + } + + // test keys + res = mfCheckKeys(trgBlockNo, trgKeyType, 8, keyBlock, &key64); + if (res) + res = mfCheckKeys(trgBlockNo, trgKeyType, 8, &keyBlock[6 * 8], &key64); + if (!res) + PrintAndLog("Found valid key:%012llx", key64); + else + PrintAndLog("No valid key found"); + } else // ------------------------------------ multiple sectors working + { + blDiff = blockNo % 4; + PrintAndLog("Block shift=%d", blDiff); + e_sector = calloc(SectorsCnt, sizeof(sector)); + if (e_sector == NULL) return 1; + + //test current key 4 sectors + memcpy(keyBlock, key, 6); + num_to_bytes(0xa0a1a2a3a4a5, 6, (uint8_t*)(keyBlock + 1 * 6)); + num_to_bytes(0xb0b1b2b3b4b5, 6, (uint8_t*)(keyBlock + 2 * 6)); + num_to_bytes(0xffffffffffff, 6, (uint8_t*)(keyBlock + 3 * 6)); + num_to_bytes(0x000000000000, 6, (uint8_t*)(keyBlock + 4 * 6)); + num_to_bytes(0xaabbccddeeff, 6, (uint8_t*)(keyBlock + 5 * 6)); + + PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt); + for (i = 0; i < SectorsCnt; i++) { + for (j = 0; j < 2; j++) { + if (e_sector[i].foundKey[j]) continue; + + res = mfCheckKeys(i * 4 + blDiff, j, 6, keyBlock, &key64); + + if (!res) { + e_sector[i].Key[j] = key64; + e_sector[i].foundKey[j] = 1; + } + } + } + + + // nested sectors + iterations = 0; + PrintAndLog("nested..."); + for (i = 0; i < NESTED_SECTOR_RETRY; i++) { + for (trgBlockNo = blDiff; trgBlockNo < SectorsCnt * 4; trgBlockNo = trgBlockNo + 4) + for (trgKeyType = 0; trgKeyType < 2; trgKeyType++) { + if (e_sector[trgBlockNo / 4].foundKey[trgKeyType]) continue; + if (mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock)) continue; + + iterations++; + + //try keys from nested + res = mfCheckKeys(trgBlockNo, trgKeyType, 8, keyBlock, &key64); + if (res) + res = mfCheckKeys(trgBlockNo, trgKeyType, 8, &keyBlock[6 * 8], &key64); + if (!res) { + PrintAndLog("Found valid key:%012llx", key64); + e_sector[trgBlockNo / 4].foundKey[trgKeyType] = 1; + e_sector[trgBlockNo / 4].Key[trgKeyType] = key64; + } + } + } + + PrintAndLog("Iterations count: %d", iterations); + //print them + PrintAndLog("|---|----------------|---|----------------|---|"); + PrintAndLog("|sec|key A |res|key B |res|"); + PrintAndLog("|---|----------------|---|----------------|---|"); + for (i = 0; i < SectorsCnt; i++) { + PrintAndLog("|%03d| %012llx | %d | %012llx | %d |", i, + e_sector[i].Key[0], e_sector[i].foundKey[0], e_sector[i].Key[1], e_sector[i].foundKey[1]); + } + PrintAndLog("|---|----------------|---|----------------|---|"); + + free(e_sector); + } + + return 0; +} + +int CmdHF14AMfChk(const char *Cmd) +{ + int i, res; + int keycnt = 0; + char ctmp = 0x00; + uint8_t blockNo = 0; + uint8_t keyType = 0; + uint8_t keyBlock[8 * 6]; + uint64_t key64 = 0; + + memset(keyBlock, 0x00, sizeof(keyBlock)); + + if (strlen(Cmd)<3) { + PrintAndLog("Usage: hf mf chk []"); + PrintAndLog(" sample: hf mf chk 0 A FFFFFFFFFFFF a0a1a2a3a4a5 b01b2b3b4b5 "); + return 0; + } + + blockNo = param_get8(Cmd, 0); + ctmp = param_getchar(Cmd, 1); + if (ctmp == 0x00) { + PrintAndLog("Key type must be A or B"); + return 1; + } + if (ctmp != 'A' && ctmp != 'a') keyType = 1; + + for (i = 0; i < 6; i++) { + if (!isxdigit(param_getchar(Cmd, 2 + i))) break; + + if (param_gethex(Cmd, 2 + i, keyBlock + 6 * i, 12)) { + PrintAndLog("Key[%d] must include 12 HEX symbols", i); + return 1; + } + keycnt = i + 1; + } + + if (keycnt == 0) { + PrintAndLog("There is must be at least one key"); + return 1; + } + + PrintAndLog("--block no:%02x key type:%02x key count:%d ", blockNo, keyType, keycnt); + + res = mfCheckKeys(blockNo, keyType, keycnt, keyBlock, &key64); + if (res !=1) { + if (!res) + PrintAndLog("isOk:%02x valid key:%012llx", 1, key64); + else + PrintAndLog("isOk:%02x", 0); + } else { + PrintAndLog("Command execute timeout"); + } + + return 0; +} + +int CmdHF14AMf1kSim(const char *Cmd) +{ + uint8_t uid[4] = {0, 0, 0, 0}; + + if (param_getchar(Cmd, 0) == 'h') { + PrintAndLog("Usage: hf mf sim "); + PrintAndLog(" sample: hf mf sim 0a0a0a0a "); + return 0; + } + + if (param_getchar(Cmd, 0) && param_gethex(Cmd, 0, uid, 8)) { + PrintAndLog("UID must include 8 HEX symbols"); + return 1; + } + PrintAndLog(" uid:%s ", sprint_hex(uid, 4)); + + UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {0, 0, 0}}; + memcpy(c.d.asBytes, uid, 4); + SendCommand(&c); + + return 0; +} + +int CmdHF14AMfDbg(const char *Cmd) +{ + if (strlen(Cmd) < 1) { + PrintAndLog("Usage: hf mf dbg "); + PrintAndLog(" 0 - no debug messages"); + PrintAndLog(" 1 - error messages"); + PrintAndLog(" 2 - all messages"); + PrintAndLog(" 4 - extended debug mode"); + return 0; + } + + PrintAndLog("No code here ("); + return 0; +} + +int CmdHF14AMfEGet(const char *Cmd) +{ + PrintAndLog("No code here ("); + return 0; +} + +int CmdHF14AMfESet(const char *Cmd) +{ + PrintAndLog("No code here ("); + return 0; +} + +int CmdHF14AMfELoad(const char *Cmd) +{ + PrintAndLog("No code here ("); + return 0; +} + +int CmdHF14AMfESave(const char *Cmd) +{ + PrintAndLog("No code here ("); + return 0; +} + +static command_t CommandTable[] = +{ + {"help", CmdHelp, 1, "This help"}, + {"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"}, + {"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"}, + {"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"}, + {"wrbl", CmdHF14AMfWrBl, 0, "Write MIFARE classic block"}, + {"chk", CmdHF14AMfChk, 0, "Test block up to 8 keys"}, + {"mifare", CmdHF14AMifare, 0, "Read parity error messages. param - "}, + {"nested", CmdHF14AMfNested, 0, "Test nested authentication"}, + {"sim", CmdHF14AMf1kSim, 0, "Simulate MIFARE 1k card"}, + {"eget", CmdHF14AMfEGet, 0, "Set simulator memory block"}, + {"eset", CmdHF14AMfESet, 0, "Get simulator memory block"}, + {"eload", CmdHF14AMfELoad, 0, "Load from file emul dump"}, + {"esave", CmdHF14AMfESave, 0, "Save to file emul dump"}, + {NULL, NULL, 0, NULL} +}; + +int CmdHFMF(const char *Cmd) +{ + // flush + while (WaitForResponseTimeout(CMD_ACK, 500) != NULL) ; + + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd) +{ + CmdsHelp(CommandTable); + return 0; +} diff --git a/client/cmdhfmf.h b/client/cmdhfmf.h new file mode 100644 index 00000000..a4ca7760 --- /dev/null +++ b/client/cmdhfmf.h @@ -0,0 +1,29 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2011 Merlok +// +// 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 +// the license. +//----------------------------------------------------------------------------- +// High frequency MIFARE commands +//----------------------------------------------------------------------------- + +#ifndef CMDHFMF_H__ +#define CMDHFMF_H__ + +#include +#include +#include +#include +#include "iso14443crc.h" +#include "data.h" +#include "proxusb.h" +#include "ui.h" +#include "cmdparser.h" +#include "common.h" +#include "util.h" +#include "mifarehost.h" + +int CmdHFMF(const char *Cmd); + +#endif diff --git a/client/util.c b/client/util.c index 6825d721..c7764f70 100644 --- a/client/util.c +++ b/client/util.c @@ -89,6 +89,10 @@ uint64_t bytes_to_num(uint8_t* src, size_t len) return num; } +// ------------------------------------------------------------------------- +// string parameters lib +// ------------------------------------------------------------------------- + // ------------------------------------------------------------------------- // line - param line // bg, en - symbol numbers in param line of beginning an ending parameter diff --git a/include/usb_cmd.h b/include/usb_cmd.h index f4793cfc..3e8066b0 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -33,13 +33,13 @@ typedef struct { } PACKED UsbCommand; // For the bootloader -#define CMD_DEVICE_INFO 0x0000 -#define CMD_SETUP_WRITE 0x0001 -#define CMD_FINISH_WRITE 0x0003 -#define CMD_HARDWARE_RESET 0x0004 -#define CMD_START_FLASH 0x0005 -#define CMD_NACK 0x00fe -#define CMD_ACK 0x00ff +#define CMD_DEVICE_INFO 0x0000 +#define CMD_SETUP_WRITE 0x0001 +#define CMD_FINISH_WRITE 0x0003 +#define CMD_HARDWARE_RESET 0x0004 +#define CMD_START_FLASH 0x0005 +#define CMD_NACK 0x00fe +#define CMD_ACK 0x00ff // For general mucking around #define CMD_DEBUG_PRINT_STRING 0x0100 @@ -52,32 +52,32 @@ typedef struct { #define CMD_VERSION 0x0107 // For low-frequency tags -#define CMD_READ_TI_TYPE 0x0202 -#define CMD_WRITE_TI_TYPE 0x0203 -#define CMD_DOWNLOADED_RAW_BITS_TI_TYPE 0x0204 -#define CMD_ACQUIRE_RAW_ADC_SAMPLES_125K 0x0205 -#define CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K 0x0206 -#define CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K 0x0207 -#define CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K 0x0208 -#define CMD_DOWNLOADED_SIM_SAMPLES_125K 0x0209 -#define CMD_SIMULATE_TAG_125K 0x020A -#define CMD_HID_DEMOD_FSK 0x020B -#define CMD_HID_SIM_TAG 0x020C -#define CMD_SET_LF_DIVISOR 0x020D -#define CMD_LF_SIMULATE_BIDIR 0x020E -#define CMD_SET_ADC_MUX 0x020F +#define CMD_READ_TI_TYPE 0x0202 +#define CMD_WRITE_TI_TYPE 0x0203 +#define CMD_DOWNLOADED_RAW_BITS_TI_TYPE 0x0204 +#define CMD_ACQUIRE_RAW_ADC_SAMPLES_125K 0x0205 +#define CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K 0x0206 +#define CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K 0x0207 +#define CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K 0x0208 +#define CMD_DOWNLOADED_SIM_SAMPLES_125K 0x0209 +#define CMD_SIMULATE_TAG_125K 0x020A +#define CMD_HID_DEMOD_FSK 0x020B +#define CMD_HID_SIM_TAG 0x020C +#define CMD_SET_LF_DIVISOR 0x020D +#define CMD_LF_SIMULATE_BIDIR 0x020E +#define CMD_SET_ADC_MUX 0x020F /* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */ // For the 13.56 MHz tags #define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693 0x0300 #define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443 0x0301 -#define CMD_READ_SRI512_TAG 0x0303 -#define CMD_READ_SRIX4K_TAG 0x0304 -#define CMD_READER_ISO_15693 0x0310 -#define CMD_SIMTAG_ISO_15693 0x0311 +#define CMD_READ_SRI512_TAG 0x0303 +#define CMD_READ_SRIX4K_TAG 0x0304 +#define CMD_READER_ISO_15693 0x0310 +#define CMD_SIMTAG_ISO_15693 0x0311 #define CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693 0x0312 -#define CMD_ISO_15693_COMMAND 0x0313 -#define CMD_ISO_15693_COMMAND_DONE 0x0314 +#define CMD_ISO_15693_COMMAND 0x0313 +#define CMD_ISO_15693_COMMAND_DONE 0x0314 #define CMD_ISO_15693_FIND_AFI 0x0315 #define CMD_ISO_15693_DEBUG 0x0316 #define CMD_SIMULATE_TAG_HF_LISTEN 0x0380 @@ -86,28 +86,37 @@ typedef struct { #define CMD_SNOOP_ISO_14443a 0x0383 #define CMD_SIMULATE_TAG_ISO_14443a 0x0384 #define CMD_READER_ISO_14443a 0x0385 -#define CMD_SIMULATE_MIFARE_CARD 0x0386 #define CMD_SIMULATE_TAG_LEGIC_RF 0x0387 #define CMD_READER_LEGIC_RF 0x0388 #define CMD_WRITER_LEGIC_RF 0x0399 -#define CMD_READER_MIFARE 0x0389 -#define CMD_MIFARE_NESTED 0x0390 -#define CMD_MIFARE_READBL 0x0391 -#define CMD_MIFARE_READSC 0x0393 -#define CMD_MIFARE_WRITEBL 0x0394 -#define CMD_MIFARE_CHKKEYS 0x0395 + #define CMD_SNOOP_ICLASS 0x0392 // For measurements of the antenna tuning -#define CMD_MEASURE_ANTENNA_TUNING 0x0400 -#define CMD_MEASURE_ANTENNA_TUNING_HF 0x0401 -#define CMD_MEASURED_ANTENNA_TUNING 0x0410 -#define CMD_LISTEN_READER_FIELD 0x0420 +#define CMD_MEASURE_ANTENNA_TUNING 0x0400 +#define CMD_MEASURE_ANTENNA_TUNING_HF 0x0401 +#define CMD_MEASURED_ANTENNA_TUNING 0x0410 +#define CMD_LISTEN_READER_FIELD 0x0420 // For direct FPGA control -#define CMD_FPGA_MAJOR_MODE_OFF 0x0500 +#define CMD_FPGA_MAJOR_MODE_OFF 0x0500 + +// For mifare commands +#define CMD_MIFARE_SET_DBGMODE 0x0600 +#define CMD_MIFARE_EML_MEMSET 0x0601 +#define CMD_MIFARE_EML_MEMGET 0x0602 + +#define CMD_SIMULATE_MIFARE_CARD 0x0603 + +#define CMD_READER_MIFARE 0x0605 +#define CMD_MIFARE_NESTED 0x0606 + +#define CMD_MIFARE_READBL 0x0610 +#define CMD_MIFARE_READSC 0x0611 +#define CMD_MIFARE_WRITEBL 0x0612 +#define CMD_MIFARE_CHKKEYS 0x0613 -#define CMD_UNKNOWN 0xFFFF +#define CMD_UNKNOWN 0xFFFF // CMD_DEVICE_INFO response packet has flags in arg[0], flag definitions: /* Whether a bootloader that understands the common_area is present */ -- 2.39.2