From bee99bbf906d04f234c1f47ac84dfc8ce19b89ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20M=C3=B6llers?= Date: Mon, 6 Jul 2015 17:59:23 +0200 Subject: [PATCH 1/7] Small spacing-related cleanups --- armsrc/Makefile | 18 +++++++++--------- armsrc/iso14443b.c | 28 ++++++++++++++-------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/armsrc/Makefile b/armsrc/Makefile index 1214c949..141cf0ec 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -9,17 +9,17 @@ APP_INCLUDES = apps.h #remove one of the following defines and comment out the relevant line -#in the next section to remove that particular feature from compilation +#in the next section to remove that particular feature from compilation APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG -DWITH_CRC -DON_DEVICE \ -fno-strict-aliasing -ffunction-sections -fdata-sections -#-DWITH_LCD +#-DWITH_LCD #SRC_LCD = fonts.c LCD.c SRC_LF = lfops.c hitag2.c lfsampling.c SRC_ISO15693 = iso15693.c iso15693tools.c SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c SRC_ISO14443b = iso14443b.c -SRC_CRAPTO1 = crapto1.c crypto1.c des.c aes.c +SRC_CRAPTO1 = crapto1.c crypto1.c des.c aes.c SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c #the FPGA bitstream files. Note: order matters! @@ -65,7 +65,7 @@ ARMSRC = fpgaloader.c \ # Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC include ../common/Makefile.common -OBJS = $(OBJDIR)/fullimage.s19 +OBJS = $(OBJDIR)/fullimage.s19 FPGA_COMPRESSOR = ../client/fpga_compress all: $(OBJS) @@ -80,13 +80,13 @@ $(OBJDIR)/fpga_all.bit.z: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR) $(FPGA_COMPRESSOR): make -C ../client $(notdir $(FPGA_COMPRESSOR)) - + $(OBJDIR)/fullimage.stage1.elf: $(VERSIONOBJ) $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ) $(CC) $(LDFLAGS) -Wl,-T,ldscript,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ $(LIBS) $(OBJDIR)/fullimage.nodata.bin: $(OBJDIR)/fullimage.stage1.elf $(OBJCOPY) -O binary -I elf32-littlearm --remove-section .data $^ $@ - + $(OBJDIR)/fullimage.nodata.o: $(OBJDIR)/fullimage.nodata.bin $(OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=stage1_image $^ $@ @@ -94,14 +94,14 @@ $(OBJDIR)/fullimage.data.bin: $(OBJDIR)/fullimage.stage1.elf $(OBJCOPY) -O binary -I elf32-littlearm --only-section .data $^ $@ $(OBJDIR)/fullimage.data.bin.z: $(OBJDIR)/fullimage.data.bin $(FPGA_COMPRESSOR) - $(FPGA_COMPRESSOR) $(filter %.bin,$^) $@ - + $(FPGA_COMPRESSOR) $(filter %.bin,$^) $@ + $(OBJDIR)/fullimage.data.o: $(OBJDIR)/fullimage.data.bin.z $(OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=compressed_data $^ $@ $(OBJDIR)/fullimage.elf: $(OBJDIR)/fullimage.nodata.o $(OBJDIR)/fullimage.data.o $(CC) $(LDFLAGS) -Wl,-T,ldscript,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ - + tarbin: $(OBJS) $(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(OBJS:%=armsrc/%) $(OBJS:%.s19=armsrc/%.elf) diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 33c047d8..1b5e07e1 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -311,7 +311,7 @@ static int GetIso14443bCommandFromReader(uint8_t *received, uint16_t *len) } } } - + return FALSE; } @@ -353,7 +353,7 @@ void SimulateIso14443bTag(void) // prepare the (only one) tag answer: CodeIso14443bAsTag(response1, sizeof(response1)); uint8_t *resp1Code = BigBuf_malloc(ToSendMax); - memcpy(resp1Code, ToSend, ToSendMax); + memcpy(resp1Code, ToSend, ToSendMax); uint16_t resp1CodeLen = ToSendMax; // We need to listen to the high-frequency, peak-detected path. @@ -377,9 +377,9 @@ void SimulateIso14443bTag(void) // Good, look at the command now. if ( (len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len) == 0) || (len == sizeof(cmd2) && memcmp(receivedCmd, cmd2, len) == 0) ) { - resp = response1; + resp = response1; respLen = sizeof(response1); - respCode = resp1Code; + respCode = resp1Code; respCodeLen = resp1CodeLen; } else { Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsRecvd); @@ -429,13 +429,13 @@ void SimulateIso14443bTag(void) (void)b; } } - + // trace the response: if (tracing) { uint8_t parity[MAX_PARITY_SIZE]; LogTrace(resp, respLen, 0, 0, parity, FALSE); } - + } } @@ -513,7 +513,7 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) } else { \ v -= cq; \ } \ - } + } */ // Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq))) #define CHECK_FOR_SUBCARRIER() { \ @@ -547,7 +547,7 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) } \ } \ } - + switch(Demod.state) { case DEMOD_UNSYNCD: CHECK_FOR_SUBCARRIER(); @@ -645,7 +645,7 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) Demod.metric -= Demod.thisBit; } (Demod.metricN)++; -*/ +*/ Demod.shiftReg >>= 1; if(Demod.thisBit > 0) { // logic '1' @@ -713,10 +713,10 @@ static void GetSamplesFor14443bDemod(int n, bool quiet) // Allocate memory from BigBuf for some buffers // free all previous allocations first BigBuf_free(); - + // The response (tag -> reader) that we're receiving. uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE); - + // The DMA buffer, used to stream samples from the FPGA int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); @@ -1090,7 +1090,7 @@ void RAMFUNC SnoopIso14443b(void) bool TagIsActive = FALSE; bool ReaderIsActive = FALSE; - + // And now we loop, receiving samples. for(;;) { int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & @@ -1201,7 +1201,7 @@ void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, u FpgaSetupSsc(); set_tracing(TRUE); - + CodeAndTransmit14443bAsReader(data, datalen); if(recv) { @@ -1209,7 +1209,7 @@ void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, u uint16_t iLen = MIN(Demod.len, USB_CMD_DATA_SIZE); cmd_send(CMD_ACK, iLen, 0, 0, Demod.output, iLen); } - + if(!powerfield) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); From 4be2708381b07e36c4ced1393c99ef845aec90f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20M=C3=B6llers?= Date: Mon, 6 Jul 2015 18:01:34 +0200 Subject: [PATCH 2/7] ISO 14443 type B support for EPA functionality Added iso14443b_setup and iso14443b_apdu for general setup and communication with ISO 14443 type B tags. Updated EPA (German electronic ID card) functionality to support both card types. --- armsrc/epa.c | 76 +++++++++++++++++++++++++++---------- armsrc/epa.h | 2 +- armsrc/iso14443b.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++ armsrc/iso14443b.h | 21 ++++++++++ 4 files changed, 173 insertions(+), 21 deletions(-) create mode 100644 armsrc/iso14443b.h diff --git a/armsrc/epa.c b/armsrc/epa.c index 6bd8692e..50c7d878 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -12,10 +12,11 @@ //----------------------------------------------------------------------------- #include "iso14443a.h" +#include "iso14443b.h" #include "epa.h" #include "cmd.h" -// Protocol and Parameter Selection Request +// Protocol and Parameter Selection Request for ISO 14443 type A cards // use regular (1x) speed in both directions // CRC is already included static const uint8_t pps[] = {0xD0, 0x11, 0x00, 0x52, 0xA6}; @@ -100,6 +101,28 @@ static struct { // lengths of the replay APDUs static uint8_t apdu_lengths_replay[5]; +// type of card (ISO 14443 A or B) +static char iso_type = 0; + +//----------------------------------------------------------------------------- +// Wrapper for sending APDUs to type A and B cards +//----------------------------------------------------------------------------- +int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response) +{ + switch(iso_type) + { + case 'a': + return iso14_apdu(apdu, (uint16_t) length, response); + break; + case 'b': + return iso14443b_apdu(apdu, length, response); + break; + default: + return 0; + break; + } +} + //----------------------------------------------------------------------------- // Closes the communication channel and turns off the field //----------------------------------------------------------------------------- @@ -107,6 +130,7 @@ void EPA_Finish() { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); + iso_type = 0; } //----------------------------------------------------------------------------- @@ -204,26 +228,26 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) int rapdu_length = 0; // select the file EF.CardAccess - rapdu_length = iso14_apdu((uint8_t *)apdu_select_binary_cardaccess, + rapdu_length = EPA_APDU((uint8_t *)apdu_select_binary_cardaccess, sizeof(apdu_select_binary_cardaccess), response_apdu); - if (rapdu_length != 6 + if (rapdu_length < 6 || response_apdu[rapdu_length - 4] != 0x90 || response_apdu[rapdu_length - 3] != 0x00) { - Dbprintf("epa - no select cardaccess"); + DbpString("Failed to select EF.CardAccess!"); return -1; } // read the file - rapdu_length = iso14_apdu((uint8_t *)apdu_read_binary, + rapdu_length = EPA_APDU((uint8_t *)apdu_read_binary, sizeof(apdu_read_binary), response_apdu); if (rapdu_length <= 6 || response_apdu[rapdu_length - 4] != 0x90 || response_apdu[rapdu_length - 3] != 0x00) { - Dbprintf("epa - no read cardaccess"); + Dbprintf("Failed to read EF.CardAccess!"); return -1; } @@ -338,7 +362,7 @@ int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce) // send it uint8_t response_apdu[262]; - int send_return = iso14_apdu(apdu, + int send_return = EPA_APDU(apdu, sizeof(apdu), response_apdu); // check if the command succeeded @@ -409,7 +433,7 @@ int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password) apdu[4] = apdu_length - 5; // send it uint8_t response_apdu[6]; - int send_return = iso14_apdu(apdu, + int send_return = EPA_APDU(apdu, apdu_length, response_apdu); // check if the command succeeded @@ -460,16 +484,13 @@ void EPA_PACE_Replay(UsbCommand *c) return; } - // increase the timeout (at least some cards really do need this!)///////////// - // iso14a_set_timeout(0x0003FFFF); - // response APDU uint8_t response_apdu[300] = {0}; // now replay the data and measure the timings for (int i = 0; i < sizeof(apdu_lengths_replay); i++) { StartCountUS(); - func_return = iso14_apdu(apdus_replay[i].data, + func_return = EPA_APDU(apdus_replay[i].data, apdu_lengths_replay[i], response_apdu); timings[i] = GetCountUS(); @@ -501,18 +522,33 @@ int EPA_Setup() uint8_t pps_response_par[1]; iso14a_card_select_t card_select_info; + // first, look for type A cards // power up the field iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); // select the card return_code = iso14443a_select_card(uid, &card_select_info, NULL); - if (return_code != 1) { - return 1; + if (return_code == 1) { + // send the PPS request + ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL); + return_code = ReaderReceive(pps_response, pps_response_par); + if (return_code != 3 || pps_response[0] != 0xD0) { + return return_code == 0 ? 2 : return_code; + } + Dbprintf("ISO 14443 Type A"); + iso_type = 'a'; + return 0; } - // send the PPS request - ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL); - return_code = ReaderReceive(pps_response, pps_response_par); - if (return_code != 3 || pps_response[0] != 0xD0) { - return return_code == 0 ? 2 : return_code; + + // if we're here, there is no type A card, so we look for type B + // power up the field + iso14443b_setup(); + // select the card + return_code = iso14443b_select_card(); + if (return_code == 1) { + Dbprintf("ISO 14443 Type B"); + iso_type = 'b'; + return 0; } - return 0; + Dbprintf("No card found."); + return 1; } diff --git a/armsrc/epa.h b/armsrc/epa.h index 0c580205..d2ebed57 100644 --- a/armsrc/epa.h +++ b/armsrc/epa.h @@ -19,7 +19,7 @@ typedef struct { uint8_t parameter_id; } pace_version_info_t; -// note: EPA_PACE_Collect_Nonce is declared in apps.h +// note: EPA_PACE_Collect_Nonce and EPA_PACE_Replay are declared in apps.h // general functions void EPA_Finish(); diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 1b5e07e1..f8e6046c 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -19,6 +19,9 @@ #define RECEIVE_SAMPLES_TIMEOUT 2000 #define ISO14443B_DMA_BUFFER_SIZE 256 +// PCB Block number for APDUs +static uint8_t pcb_blocknum = 0; + //============================================================================= // An ISO 14443 Type B tag. We listen for commands from the reader, using // a UART kind of thing that's implemented in software. When we get a @@ -896,6 +899,98 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) } } +/* Sends an APDU to the tag + * TODO: check CRC and preamble + */ +int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response) +{ + uint8_t message_frame[message_length + 4]; + // PCB + message_frame[0] = 0x0A | pcb_blocknum; + pcb_blocknum ^= 1; + // CID + message_frame[1] = 0; + // INF + memcpy(message_frame + 2, message, message_length); + // EDC (CRC) + ComputeCrc14443(CRC_14443_B, message_frame, message_length + 2, &message_frame[message_length + 2], &message_frame[message_length + 3]); + // send + CodeAndTransmit14443bAsReader(message_frame, message_length + 4); + // get response + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT*100, TRUE); + if(Demod.len < 3) + { + return 0; + } + // TODO: Check CRC + // copy response contents + if(response != NULL) + { + memcpy(response, Demod.output, Demod.len); + } + return Demod.len; +} + +/* Perform the ISO 14443 B Card Selection procedure + * Currently does NOT do any collision handling. + * It expects 0-1 cards in the device's range. + * TODO: Support multiple cards (perform anticollision) + * TODO: Verify CRC checksums + */ +int iso14443b_select_card() +{ + // WUPB command (including CRC) + // Note: WUPB wakes up all tags, REQB doesn't wake up tags in HALT state + static const uint8_t wupb[] = { 0x05, 0x00, 0x08, 0x39, 0x73 }; + // ATTRIB command (with space for CRC) + uint8_t attrib[] = { 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00}; + + // first, wake up the tag + CodeAndTransmit14443bAsReader(wupb, sizeof(wupb)); + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); + // ATQB too short? + if (Demod.len < 14) + { + return 2; + } + + // select the tag + // copy the PUPI to ATTRIB + memcpy(attrib + 1, Demod.output + 1, 4); + /* copy the protocol info from ATQB (Protocol Info -> Protocol_Type) into + ATTRIB (Param 3) */ + attrib[7] = Demod.output[10] & 0x0F; + ComputeCrc14443(CRC_14443_B, attrib, 9, attrib + 9, attrib + 10); + CodeAndTransmit14443bAsReader(attrib, sizeof(attrib)); + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); + // Answer to ATTRIB too short? + if(Demod.len < 3) + { + return 2; + } + // reset PCB block number + pcb_blocknum = 0; + return 1; +} + +// Set up ISO 14443 Type B communication (similar to iso14443a_setup) +void iso14443b_setup() { + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + // Set up the synchronous serial port + FpgaSetupSsc(); + // connect Demodulated Signal to ADC: + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // Signal field is on with the appropriate LED + LED_D_ON(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); + + // Start the timer + StartCountSspClk(); + + DemodReset(); + UartReset(); +} //----------------------------------------------------------------------------- // Read a SRI512 ISO 14443B tag. diff --git a/armsrc/iso14443b.h b/armsrc/iso14443b.h new file mode 100644 index 00000000..f90c54f3 --- /dev/null +++ b/armsrc/iso14443b.h @@ -0,0 +1,21 @@ +//----------------------------------------------------------------------------- +// Merlok - June 2011 +// Gerhard de Koning Gans - May 2008 +// Hagen Fritsch - June 2010 +// +// 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. +//----------------------------------------------------------------------------- +// Routines to support ISO 14443 type A. +//----------------------------------------------------------------------------- + +#ifndef __ISO14443B_H +#define __ISO14443B_H +#include "common.h" + +int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response); +void iso14443b_setup(); +int iso14443b_select_card(); + +#endif /* __ISO14443B_H */ From 5330f5329f68fa6a95658ebd946d5eefc74e10c4 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Thu, 2 Jul 2015 08:49:34 +0200 Subject: [PATCH 3/7] - fix: trace of hf mf mifare had always been cleared by mfCheckKeys() in nonce2key() - fix: parity was not checked for reader commands in hf list 14a - add: enable tracing for hf mf nested --- armsrc/BigBuf.h | 14 +++++++------- armsrc/apps.h | 2 +- armsrc/mifarecmd.c | 14 +++++++------- client/cmdhf.c | 2 +- client/cmdhfmf.c | 22 ++++++---------------- client/mifarehost.c | 6 +++--- client/mifarehost.h | 2 +- client/nonce2key/nonce2key.c | 2 +- 8 files changed, 27 insertions(+), 37 deletions(-) diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h index b44a1263..0e2f1744 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -24,15 +24,15 @@ extern uint8_t *BigBuf_get_addr(void); extern uint8_t *BigBuf_get_EM_addr(void); extern uint16_t BigBuf_max_traceLen(void); -void BigBuf_Clear(void); +extern void BigBuf_Clear(void); extern uint8_t *BigBuf_malloc(uint16_t); extern void BigBuf_free(void); extern void BigBuf_free_keep_EM(void); -uint16_t BigBuf_get_traceLen(void); -void clear_trace(); -void set_tracing(bool enable); -bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag); -int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwParity, int bReader); -uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length); +extern uint16_t BigBuf_get_traceLen(void); +extern void clear_trace(); +extern void set_tracing(bool enable); +extern bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag); +extern int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwParity, int bReader); +extern uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length); #endif /* __BIGBUF_H */ diff --git a/armsrc/apps.h b/armsrc/apps.h index bb094b33..42efd118 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -121,7 +121,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) //void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain); 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 MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); +void MifareChkKeys(uint16_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); 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); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index c2d85abb..fd6fde63 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -642,8 +642,8 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat // free eventually allocated BigBuf memory BigBuf_free(); - clear_trace(); - set_tracing(false); + if (calibrate) clear_trace(); + set_tracing(true); // statistics on nonce distance int16_t isOK = 0; @@ -820,18 +820,18 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - set_tracing(TRUE); } //----------------------------------------------------------------------------- // MIFARE check keys. key count up to 85. // //----------------------------------------------------------------------------- -void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) +void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { // params - uint8_t blockNo = arg0; - uint8_t keyType = arg1; + uint8_t blockNo = arg0 & 0xff; + uint8_t keyType = (arg0 >> 8) & 0xff; + bool clearTrace = arg1; uint8_t keyCount = arg2; uint64_t ui64Key = 0; @@ -853,7 +853,7 @@ void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) LED_C_OFF(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - clear_trace(); + if (clearTrace) clear_trace(); set_tracing(TRUE); for (i = 0; i < keyCount; i++) { diff --git a/client/cmdhf.c b/client/cmdhf.c index 4c5db589..f8daff7e 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -378,7 +378,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); } uint8_t parityBits = parityBytes[j>>3]; - if (protocol != ISO_14443B && isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) { + if (protocol != ISO_14443B && (isResponse || protocol == ISO_14443A) && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) { snprintf(line[j/16]+(( j % 16) * 4),110, "%02x! ", frame[j]); } else { diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 5ef5273a..16612cba 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -18,7 +18,6 @@ int CmdHF14AMifare(const char *Cmd) uint32_t nt = 0, nr = 0; uint64_t par_list = 0, ks_list = 0, r_key = 0; int16_t isOK = 0; - uint8_t keyBlock[8] = {0}; UsbCommand c = {CMD_READER_MIFARE, {true, 0, 0}}; @@ -74,22 +73,13 @@ start: if (nonce2key(uid, nt, nr, par_list, ks_list, &r_key)) { isOK = 2; PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt); - } else { - printf("------------------------------------------------------------------\n"); - PrintAndLog("Key found:%012"llx" \n", r_key); - - num_to_bytes(r_key, 6, keyBlock); - isOK = mfCheckKeys(0, 0, 1, keyBlock, &r_key); - } - - if (!isOK) - PrintAndLog("Found valid key:%012"llx, r_key); - else - { - if (isOK != 2) PrintAndLog("Found invalid key. "); PrintAndLog("Failing is expected to happen in 25%% of all cases. Trying again with a different reader nonce..."); c.arg[0] = false; goto start; + } else { + isOK = 0; + printf("------------------------------------------------------------------\n"); + PrintAndLog("Found valid key:%012"llx" \n", r_key); } PrintAndLog(""); @@ -689,7 +679,7 @@ int CmdHF14AMfNested(const char *Cmd) for (j = 0; j < 2; j++) { if (e_sector[i].foundKey[j]) continue; - res = mfCheckKeys(FirstBlockOfSector(i), j, 6, keyBlock, &key64); + res = mfCheckKeys(FirstBlockOfSector(i), j, true, 6, keyBlock, &key64); if (!res) { e_sector[i].Key[j] = key64; @@ -973,7 +963,7 @@ int CmdHF14AMfChk(const char *Cmd) uint32_t max_keys = keycnt>USB_CMD_DATA_SIZE/6?USB_CMD_DATA_SIZE/6:keycnt; for (uint32_t c = 0; c < keycnt; c+=max_keys) { uint32_t size = keycnt-c>max_keys?max_keys:keycnt-c; - res = mfCheckKeys(b, t, size, &keyBlock[6*c], &key64); + res = mfCheckKeys(b, t, true, size, &keyBlock[6*c], &key64); if (res != 1) { if (!res) { PrintAndLog("Found valid key:[%012"llx"]",key64); diff --git a/client/mifarehost.c b/client/mifarehost.c index 95453ebf..eb145123 100644 --- a/client/mifarehost.c +++ b/client/mifarehost.c @@ -181,7 +181,7 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo crypto1_get_lfsr(statelists[0].head.slhead + i, &key64); num_to_bytes(key64, 6, keyBlock); key64 = 0; - if (!mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, 1, keyBlock, &key64)) { + if (!mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, false, 1, keyBlock, &key64)) { num_to_bytes(key64, 6, resultKey); break; } @@ -193,11 +193,11 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo return 0; } -int mfCheckKeys (uint8_t blockNo, uint8_t keyType, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key){ +int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key){ *key = 0; - UsbCommand c = {CMD_MIFARE_CHKKEYS, {blockNo, keyType, keycnt}}; + UsbCommand c = {CMD_MIFARE_CHKKEYS, {((blockNo & 0xff) | ((keyType&0xff)<<8)), clear_trace, keycnt}}; memcpy(c.d.asBytes, keyBlock, 6 * keycnt); SendCommand(&c); diff --git a/client/mifarehost.h b/client/mifarehost.h index a11f11d5..f6ffab3f 100644 --- a/client/mifarehost.h +++ b/client/mifarehost.h @@ -50,7 +50,7 @@ typedef struct { extern char logHexFileName[FILE_PATH_SIZE]; int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * ResultKeys, bool calibrate); -int mfCheckKeys (uint8_t blockNo, uint8_t keyType, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key); +int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key); int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount); int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount); diff --git a/client/nonce2key/nonce2key.c b/client/nonce2key/nonce2key.c index 111f58cd..70d874fe 100644 --- a/client/nonce2key/nonce2key.c +++ b/client/nonce2key/nonce2key.c @@ -133,7 +133,7 @@ int nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_ key64 = *(last_keylist + i); num_to_bytes(key64, 6, keyBlock); key64 = 0; - if (!mfCheckKeys(0, 0, 1, keyBlock, &key64)) { + if (!mfCheckKeys(0, 0, false, 1, keyBlock, &key64)) { *key = key64; free(last_keylist); last_keylist = NULL; From 40c514454d80a396e9efcf80950aa631f6647755 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sun, 12 Jul 2015 23:38:52 +0200 Subject: [PATCH 4/7] Fixed issue #94, so lua-script 'mifare_autopwn' reacts correctly to card that are not vulnerable to darkside-attacks --- client/scripts/mifare_autopwn.lua | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/client/scripts/mifare_autopwn.lua b/client/scripts/mifare_autopwn.lua index eb98ffbf..9cc865f0 100644 --- a/client/scripts/mifare_autopwn.lua +++ b/client/scripts/mifare_autopwn.lua @@ -88,10 +88,33 @@ function mfcrack_inner() while not core.ukbhit() do local result = core.WaitForResponseTimeout(cmds.CMD_ACK,1000) if result then - -- Unpacking the three arg-parameters - local count,cmd,isOK = bin.unpack('LL',result) - if isOK ~= 1 then return nil, "Error occurred" end + --[[ + I don't understand, they cmd and args are defined as uint32_t, however, + looking at the returned data, they all look like 64-bit things: + + print("result", bin.unpack("HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH", result)) + + FF 00 00 00 00 00 00 00 <-- 64 bits of data + FE FF FF FF 00 00 00 00 <-- 64 bits of data + 00 00 00 00 00 00 00 00 <-- 64 bits of data + 00 00 00 00 00 00 00 00 <-- 64 bits of data + 04 7F 12 E2 00 <-- this is where 'data' starts + + So below I use LI to pick out the "FEFF FFFF", don't know why it works.. + --]] + -- Unpacking the arg-parameters + local count,cmd,isOK = bin.unpack('LI',result) + --print("response", isOK)--FF FF FF FF + if isOK == 0xFFFFFFFF then + return nil, "Button pressed. Aborted." + elseif isOK == 0xFFFFFFFE then + return nil, "Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys." + elseif isOK == 0xFFFFFFFD then + return nil, "Card is not vulnerable to Darkside attack (its random number generator is not predictable). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys." + elseif isOK ~= 1 then + return nil, "Error occurred" + end -- The data-part is left From 60034782f92e3f8d59a2a56b32663ca16cc59524 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sun, 12 Jul 2015 23:39:27 +0200 Subject: [PATCH 5/7] Some info in the changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f9546d9..8d1cd548 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ### Changed - Changed `hf 14b write` to `hf 14b sriwrite` as it only applied to sri tags (marshmellow) - Added `hf 14b info` to `hf search` (marshmellow) +- Added compression of fpga config and data, *BOOTROM REFLASH REQUIRED* (piwi) +- Implemeted better detection of mifare-tags that are not vulnerable to classic attacks (`hf mf mifare`, `hf mf nested`) (piwi) ### Added - Add `hf 14b info` to find and print info about std 14b tags and sri tags (using 14b raw commands in the client) (marshmellow) From 5ebdce44c014ae29d688367508d0a6f6e6ebc673 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sun, 12 Jul 2015 23:44:34 +0200 Subject: [PATCH 6/7] New release with FPGA compression --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d1cd548..02431d03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,16 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... -## [Unreleased][unreleased] +## [unreleased][unreleased] + + +## [2.2.0][2015-07-12] ### Changed - Changed `hf 14b write` to `hf 14b sriwrite` as it only applied to sri tags (marshmellow) - Added `hf 14b info` to `hf search` (marshmellow) - Added compression of fpga config and data, *BOOTROM REFLASH REQUIRED* (piwi) -- Implemeted better detection of mifare-tags that are not vulnerable to classic attacks (`hf mf mifare`, `hf mf nested`) (piwi) +- Implemented better detection of mifare-tags that are not vulnerable to classic attacks (`hf mf mifare`, `hf mf nested`) (piwi) ### Added - Add `hf 14b info` to find and print info about std 14b tags and sri tags (using 14b raw commands in the client) (marshmellow) From 2c3c08bd2fe9cce76ff5f56029bdcef961639606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20M=C3=B6llers?= Date: Mon, 13 Jul 2015 11:37:28 +0200 Subject: [PATCH 7/7] Mention EPA Type A/B support in CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02431d03..b0135cc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] +### Changed +- EPA functions (`hf epa`) now support both ISO 14443-A and 14443-B cards (frederikmoellers) ## [2.2.0][2015-07-12]