From 55eaed8f2ad26b9db249e2259c13444c38906795 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 12 Jan 2015 22:08:57 +0100 Subject: [PATCH 01/10] Documentation to apps.h, documentation/renaming to iclass --- armsrc/apps.h | 19 ++++++++++ armsrc/iclass.c | 96 +++++++++++++++++++++++++++---------------------- 2 files changed, 73 insertions(+), 42 deletions(-) diff --git a/armsrc/apps.h b/armsrc/apps.h index eafee559..ea70144e 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -37,6 +37,25 @@ uint32_t BigBuf[BIGBUF_SIZE / sizeof(uint32_t)]; #define FREE_BUFFER_OFFSET (CARD_MEMORY_OFFSET + CARD_MEMORY_SIZE) #define FREE_BUFFER_SIZE (BIGBUF_SIZE - FREE_BUFFER_OFFSET - 1) +/* +The statements above translates into this : +BIGBUF_SIZE = 40000 +TRACE_OFFSET = 0 +TRACE_SIZE = 3000 +RECV_CMD_OFFSET = 3000 +MAX_FRAME_SIZE = 256 +MAX_PARITY_SIZE = 32 +RECV_CMD_PAR_OFFSET = 3256 +RECV_RESP_OFFSET = 3288 +RECV_RESP_PAR_OFFSET= 3544 +CARD_MEMORY_OFFSET = 3576 +CARD_MEMORY_SIZE = 4096 +DMA_BUFFER_OFFSET = 3576 +DMA_BUFFER_SIZE = 4096 +FREE_BUFFER_OFFSET = 7672 +FREE_BUFFER_SIZE = 32327 + */ + extern const uint8_t OddByteParity[256]; extern uint8_t *trace; // = (uint8_t *) BigBuf; extern int traceLen; // = 0; diff --git a/armsrc/iclass.c b/armsrc/iclass.c index ea9af7d4..64abc84a 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -687,7 +687,8 @@ void RAMFUNC SnoopIClass(void) SetAdcMuxFor(GPIO_MUXSEL_HIPKD); uint32_t time_0 = GetCountSspClk(); - + uint32_t time_start = 0; + uint32_t time_stop = 0; int div = 0; //int div2 = 0; @@ -738,6 +739,7 @@ void RAMFUNC SnoopIClass(void) smpl = decbyter; if(OutOfNDecoding((smpl & 0xF0) >> 4)) { rsamples = samples - Uart.samples; + time_stop = (GetCountSspClk()-time_0) << 4; LED_C_ON(); //if(!LogTrace(Uart.output,Uart.byteCnt, rsamples, Uart.parityBits,TRUE)) break; @@ -745,7 +747,7 @@ void RAMFUNC SnoopIClass(void) if(tracing) { uint8_t parity[MAX_PARITY_SIZE]; GetParity(Uart.output, Uart.byteCnt, parity); - LogTrace(Uart.output,Uart.byteCnt, (GetCountSspClk()-time_0) << 4, (GetCountSspClk()-time_0) << 4, parity, TRUE); + LogTrace(Uart.output,Uart.byteCnt, time_start, time_stop, parity, TRUE); } @@ -756,6 +758,8 @@ void RAMFUNC SnoopIClass(void) Demod.state = DEMOD_UNSYNCD; LED_B_OFF(); Uart.byteCnt = 0; + }else{ + time_start = (GetCountSspClk()-time_0) << 4; } decbyter = 0; } @@ -763,21 +767,24 @@ void RAMFUNC SnoopIClass(void) if(div > 3) { smpl = decbyte; if(ManchesterDecoding(smpl & 0x0F)) { - rsamples = samples - Demod.samples; + time_stop = (GetCountSspClk()-time_0) << 4; + + rsamples = samples - Demod.samples; LED_B_ON(); if(tracing) { uint8_t parity[MAX_PARITY_SIZE]; GetParity(Demod.output, Demod.len, parity); - LogTrace(Demod.output, Demod.len, (GetCountSspClk()-time_0) << 4, (GetCountSspClk()-time_0) << 4, parity, FALSE); + LogTrace(Demod.output, Demod.len, time_start, time_stop, parity, FALSE); } - // And ready to receive another response. memset(&Demod, 0, sizeof(Demod)); Demod.output = tagToReaderResponse; Demod.state = DEMOD_UNSYNCD; LED_C_OFF(); + }else{ + time_start = (GetCountSspClk()-time_0) << 4; } div = 0; @@ -928,6 +935,7 @@ static void CodeIClassTagSOF() // Convert from last byte pos to length ToSendMax++; } + int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader_mac_buf); /** * @brief SimulateIClass simulates an iClass card. @@ -997,7 +1005,9 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain */ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader_mac_buf) { + // CSN followed by two CRC bytes + uint8_t response1[] = { 0x0F} ; uint8_t response2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t response3[] = { 0,0,0,0,0,0,0,0,0,0}; memcpy(response3,csn,sizeof(response3)); @@ -1020,11 +1030,11 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader // Reader 81 anticoll. CSN // Tag CSN - uint8_t *resp; - int respLen; - uint8_t* respdata = NULL; - int respsize = 0; - uint8_t sof = 0x0f; + uint8_t *modulated_response; + int modulated_response_size; + uint8_t* trace_data = NULL; + int trace_data_size = 0; + //uint8_t sof = 0x0f; // Respond SOF -- takes 8 bytes uint8_t *resp1 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); @@ -1089,11 +1099,6 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader LED_A_ON(); bool buttonPressed = false; - /** Hack for testing - memcpy(reader_mac_buf,csn,8); - exitLoop = true; - end hack **/ - while(!exitLoop) { LED_B_OFF(); @@ -1112,35 +1117,35 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader // Okay, look at the command now. if(receivedCmd[0] == 0x0a ) { // Reader in anticollission phase - resp = resp1; respLen = resp1Len; //order = 1; - respdata = &sof; - respsize = sizeof(sof); + modulated_response = resp1; modulated_response_size = resp1Len; //order = 1; + trace_data = response1; + trace_data_size = sizeof(response1); } else if(receivedCmd[0] == 0x0c) { // Reader asks for anticollission CSN - resp = resp2; respLen = resp2Len; //order = 2; - respdata = response2; - respsize = sizeof(response2); + modulated_response = resp2; modulated_response_size = resp2Len; //order = 2; + trace_data = response2; + trace_data_size = sizeof(response2); //DbpString("Reader requests anticollission CSN:"); } else if(receivedCmd[0] == 0x81) { // Reader selects anticollission CSN. // Tag sends the corresponding real CSN - resp = resp3; respLen = resp3Len; //order = 3; - respdata = response3; - respsize = sizeof(response3); + modulated_response = resp3; modulated_response_size = resp3Len; //order = 3; + trace_data = response3; + trace_data_size = sizeof(response3); //DbpString("Reader selects anticollission CSN:"); } else if(receivedCmd[0] == 0x88) { // Read e-purse (88 02) - resp = resp4; respLen = resp4Len; //order = 4; - respdata = response4; - respsize = sizeof(response4); + modulated_response = resp4; modulated_response_size = resp4Len; //order = 4; + trace_data = response4; + trace_data_size = sizeof(response4); LED_B_ON(); } else if(receivedCmd[0] == 0x05) { // Reader random and reader MAC!!! // Do not respond // We do not know what to answer, so lets keep quiet - resp = resp1; respLen = 0; //order = 5; - respdata = NULL; - respsize = 0; + modulated_response = resp1; modulated_response_size = 0; //order = 5; + trace_data = NULL; + trace_data_size = 0; if (breakAfterMacReceived){ // dbprintf:ing ... Dbprintf("CSN: %02x %02x %02x %02x %02x %02x %02x %02x" @@ -1157,9 +1162,9 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader } } else if(receivedCmd[0] == 0x00 && len == 1) { // Reader ends the session - resp = resp1; respLen = 0; //order = 0; - respdata = NULL; - respsize = 0; + modulated_response = resp1; modulated_response_size = 0; //order = 0; + trace_data = NULL; + trace_data_size = 0; } else { //#db# Unknown command received from reader (len=5): 26 1 0 f6 a 44 44 44 44 // Never seen this command before @@ -1169,9 +1174,9 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader receivedCmd[3], receivedCmd[4], receivedCmd[5], receivedCmd[6], receivedCmd[7], receivedCmd[8]); // Do not respond - resp = resp1; respLen = 0; //order = 0; - respdata = NULL; - respsize = 0; + modulated_response = resp1; modulated_response_size = 0; //order = 0; + trace_data = NULL; + trace_data_size = 0; } if(cmdsRecvd > 100) { @@ -1181,9 +1186,16 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader else { cmdsRecvd++; } - - if(respLen > 0) { - SendIClassAnswer(resp, respLen, 21); + /** + After changes to parity calculation + Time between reader EOT and pm3 SOF + delay 21 -> 480uS + delay 10 -> 220us + delay 16 -> 388us + A legit tag has about 380us. + **/ + if(modulated_response_size > 0) { + SendIClassAnswer(modulated_response, modulated_response_size, timeout); t2r_time = GetCountSspClk(); } @@ -1192,9 +1204,9 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader GetParity(receivedCmd, len, parity); LogTrace(receivedCmd,len, (r2t_time-time_0)<< 4, (r2t_time-time_0) << 4, parity, TRUE); - if (respdata != NULL) { - GetParity(respdata, respsize, parity); - LogTrace(respdata, respsize, (t2r_time-time_0) << 4, (t2r_time-time_0) << 4, parity, FALSE); + if (trace_data != NULL) { + GetParity(trace_data, trace_data_size, parity); + LogTrace(trace_data, trace_data_size, (t2r_time-time_0) << 4, (t2r_time-time_0) << 4, parity, FALSE); } if(!tracing) { DbpString("Trace full"); From 645c960f6111f4820c78c76f209479c3f369a8ac Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 15 Jan 2015 15:16:34 +0100 Subject: [PATCH 02/10] Implemented new FPGA mode for iclass tag simulation. Reduces arm-side size of transfer/memory by a factor of 8. Makes for easier arm-side encoding of messages, for when we start needing to do that on the fly instead of using precalculated messages --- armsrc/apps.h | 2 + armsrc/iclass.c | 136 +++++++++++++++++++++++++++------------------ fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/hi_simulate.v | 39 +++++++++++-- 4 files changed, 118 insertions(+), 59 deletions(-) diff --git a/armsrc/apps.h b/armsrc/apps.h index ea70144e..6a3fa186 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -134,6 +134,8 @@ void SetAdcMuxFor(uint32_t whichGpio); #define FPGA_HF_SIMULATOR_MODULATE_BPSK (1<<0) #define FPGA_HF_SIMULATOR_MODULATE_212K (2<<0) #define FPGA_HF_SIMULATOR_MODULATE_424K (4<<0) +#define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT 0x5//101 + // Options for ISO14443A #define FPGA_HF_ISO14443A_SNIFFER (0<<0) #define FPGA_HF_ISO14443A_TAGSIM_LISTEN (1<<0) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 64abc84a..329e1765 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -857,57 +857,93 @@ static int GetIClassCommandFromReader(uint8_t *received, int *len, int maxLen) } } +static uint8_t encode4Bits(const uint8_t b) +{ + uint8_t c = b & 0xF; + // OTA, the least significant bits first + // The columns are + // 1 - Bit value to send + // 2 - Reversed (big-endian) + // 3 - Encoded + // 4 - Hex values + + switch(c){ + // 1 2 3 4 + case 15: return 0x55; // 1111 -> 1111 -> 01010101 -> 0x55 + case 14: return 0x95; // 1110 -> 0111 -> 10010101 -> 0x95 + case 13: return 0x65; // 1101 -> 1011 -> 01100101 -> 0x65 + case 12: return 0xa5; // 1100 -> 0011 -> 10100101 -> 0xa5 + case 11: return 0x59; // 1011 -> 1101 -> 01011001 -> 0x59 + case 10: return 0x99; // 1010 -> 0101 -> 10011001 -> 0x99 + case 9: return 0x69; // 1001 -> 1001 -> 01101001 -> 0x69 + case 8: return 0xa9; // 1000 -> 0001 -> 10101001 -> 0xa9 + case 7: return 0x56; // 0111 -> 1110 -> 01010110 -> 0x56 + case 6: return 0x96; // 0110 -> 0110 -> 10010110 -> 0x96 + case 5: return 0x66; // 0101 -> 1010 -> 01100110 -> 0x66 + case 4: return 0xa6; // 0100 -> 0010 -> 10100110 -> 0xa6 + case 3: return 0x5a; // 0011 -> 1100 -> 01011010 -> 0x5a + case 2: return 0x9a; // 0010 -> 0100 -> 10011010 -> 0x9a + case 1: return 0x6a; // 0001 -> 1000 -> 01101010 -> 0x6a + default: return 0xaa; // 0000 -> 0000 -> 10101010 -> 0xaa + + } +} //----------------------------------------------------------------------------- // Prepare tag messages //----------------------------------------------------------------------------- static void CodeIClassTagAnswer(const uint8_t *cmd, int len) { - //So far a dummy implementation, not used - //int lastProxToAirDuration =0; + + /* + * SOF comprises 3 parts; + * * An unmodulated time of 56.64 us + * * 24 pulses of 423.75 KHz (fc/32) + * * A logic 1, which starts with an unmodulated time of 18.88us + * followed by 8 pulses of 423.75kHz (fc/32) + * + * + * EOF comprises 3 parts: + * - A logic 0 (which starts with 8 pulses of fc/32 followed by an unmodulated + * time of 18.88us. + * - 24 pulses of fc/32 + * - An unmodulated time of 56.64 us + * + * + * A logic 0 starts with 8 pulses of fc/32 + * followed by an unmodulated time of 256/fc (~18,88us). + * + * A logic 0 starts with unmodulated time of 256/fc (~18,88us) followed by + * 8 pulses of fc/32 (also 18.88us) + * + * The mode FPGA_HF_SIMULATOR_MODULATE_424K_8BIT which we use to simulate tag, + * works like this. + * - A 1-bit input to the FPGA becomes 8 pulses on 423.5kHz (fc/32) (18.88us). + * - A 0-bit inptu to the FPGA becomes an unmodulated time of 18.88us + * + * In thist mode the SOF can be written as 00011101 = 0x1D + * The EOF can be written as 10111000 = 0xb8 + * A logic 1 is 01 + * A logic 0 is 10 + * + * */ + int i; ToSendReset(); // Send SOF - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0xff;//Proxtoair duration starts here - ToSend[++ToSendMax] = 0xff; - ToSend[++ToSendMax] = 0xff; - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0xff; + ToSend[++ToSendMax] = 0x1D; for(i = 0; i < len; i++) { - int j; uint8_t b = cmd[i]; - - // Data bits - for(j = 0; j < 8; j++) { - if(b & 1) { - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0xff; - } else { - ToSend[++ToSendMax] = 0xff; - ToSend[++ToSendMax] = 0x00; - } - b >>= 1; - } + ToSend[++ToSendMax] = encode4Bits(b & 0xF); //Least significant half + ToSend[++ToSendMax] = encode4Bits((b >>4) & 0xF);//Most significant half } // Send EOF - ToSend[++ToSendMax] = 0xff; - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0xff; - ToSend[++ToSendMax] = 0xff; - ToSend[++ToSendMax] = 0xff; - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0x00; - + ToSend[++ToSendMax] = 0xB8; //lastProxToAirDuration = 8*ToSendMax - 3*8 - 3*8;//Not counting zeroes in the beginning or end - // Convert from last byte pos to length ToSendMax++; } @@ -920,18 +956,9 @@ static void CodeIClassTagSOF() ToSendReset(); // Send SOF - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0xff; - ToSend[++ToSendMax] = 0xff; - ToSend[++ToSendMax] = 0xff; - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0xff; - + ToSend[++ToSendMax] = 0x1D; // lastProxToAirDuration = 8*ToSendMax - 3*8;//Not counting zeroes in the beginning - // Convert from last byte pos to length ToSendMax++; } @@ -984,6 +1011,7 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain memcpy(csn_crc, datain+(i*8), 8); if(doIClassSimulation(csn_crc,1,mac_responses+i*8)) { + cmd_send(CMD_ACK,CMD_SIMULATE_TAG_ICLASS,i,0,mac_responses,i*8); return; // Button pressed } } @@ -1036,23 +1064,23 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader int trace_data_size = 0; //uint8_t sof = 0x0f; - // Respond SOF -- takes 8 bytes + // Respond SOF -- takes 1 bytes uint8_t *resp1 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); int resp1Len; // Anticollision CSN (rotated CSN) - // 176: Takes 16 bytes for SOF/EOF and 10 * 16 = 160 bytes (2 bytes/bit) - uint8_t *resp2 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + 10); + // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) + uint8_t *resp2 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + 2); int resp2Len; // CSN - // 176: Takes 16 bytes for SOF/EOF and 10 * 16 = 160 bytes (2 bytes/bit) - uint8_t *resp3 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + 190); + // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) + uint8_t *resp3 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + 30); int resp3Len; // e-Purse - // 144: Takes 16 bytes for SOF/EOF and 8 * 16 = 128 bytes (2 bytes/bit) - uint8_t *resp4 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + 370); + // 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/byte) + uint8_t *resp4 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + 60); int resp4Len; // + 1720.. @@ -1195,7 +1223,7 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader A legit tag has about 380us. **/ if(modulated_response_size > 0) { - SendIClassAnswer(modulated_response, modulated_response_size, timeout); + SendIClassAnswer(modulated_response, modulated_response_size, 1); t2r_time = GetCountSspClk(); } @@ -1232,7 +1260,8 @@ static int SendIClassAnswer(uint8_t *resp, int respLen, int delay) int i = 0, d=0;//, u = 0, d = 0; uint8_t b = 0; - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K); + //FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K_8BIT); AT91C_BASE_SSC->SSC_THR = 0x00; FpgaSetupSsc(); @@ -1256,7 +1285,8 @@ static int SendIClassAnswer(uint8_t *resp, int respLen, int delay) AT91C_BASE_SSC->SSC_THR = b; } - if (i > respLen +4) break; +// if (i > respLen +4) break; + if (i > respLen +1) break; } return 0; diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index 5389428c5539eb60eee9f27b6956ca950aa79b15..8b0c7a3788ef438c94eaed81346a08f24927f954 100644 GIT binary patch literal 42175 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 literal 42175 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

eu*}zWMx6WDri0MtNP{{*8u|VkeY~bQJ-m} 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 diff --git a/fpga/hi_simulate.v b/fpga/hi_simulate.v index c04ade80..0768c29d 100644 --- a/fpga/hi_simulate.v +++ b/fpga/hi_simulate.v @@ -50,12 +50,38 @@ begin else if(~(| adc_d[7:5])) after_hysteresis = 1'b0; end + // Divide 13.56 MHz by 32 to produce the SSP_CLK // The register is bigger to allow higher division factors of up to /128 -reg [6:0] ssp_clk_divider; +reg [10:0] ssp_clk_divider; + always @(posedge adc_clk) ssp_clk_divider <= (ssp_clk_divider + 1); -assign ssp_clk = ssp_clk_divider[4]; + +reg ssp_clk; +reg ssp_frame; +always @(negedge adc_clk) +begin + //If we're in 101, we only need a new bit every 8th carrier bit (53Hz). Otherwise, get next bit at 424Khz + if(mod_type == 3'b101) + begin + if(ssp_clk_divider[7:0] == 8'b00000000) + ssp_clk <= 1'b0; + if(ssp_clk_divider[7:0] == 8'b10000000) + ssp_clk <= 1'b1; + + end + else + begin + if(ssp_clk_divider[4:0] == 5'd0)//[4:0] == 5'b00000) + ssp_clk <= 1'b1; + if(ssp_clk_divider[4:0] == 5'd16) //[4:0] == 5'b10000) + ssp_clk <= 1'b0; + end +end + + +//assign ssp_clk = ssp_clk_divider[4]; // Divide SSP_CLK by 8 to produce the byte framing signal; the phase of // this is arbitrary, because it's just a bitstream. @@ -69,12 +95,13 @@ reg [2:0] ssp_frame_divider_from_arm; always @(negedge ssp_clk) ssp_frame_divider_from_arm <= (ssp_frame_divider_from_arm + 1); -reg ssp_frame; + + always @(ssp_frame_divider_to_arm or ssp_frame_divider_from_arm or mod_type) if(mod_type == 3'b000) // not modulating, so listening, to ARM ssp_frame = (ssp_frame_divider_to_arm == 3'b000); else - ssp_frame = (ssp_frame_divider_from_arm == 3'b000); + ssp_frame = (ssp_frame_divider_from_arm == 3'b000); // Synchronize up the after-hysteresis signal, to produce DIN. reg ssp_din; @@ -90,7 +117,7 @@ always @(mod_type or ssp_clk or ssp_dout) modulating_carrier <= ssp_dout ^ ssp_clk_divider[3]; // XOR means BPSK else if(mod_type == 3'b010) modulating_carrier <= ssp_dout & ssp_clk_divider[5]; // switch 212kHz subcarrier on/off - else if(mod_type == 3'b100) + else if(mod_type == 3'b100 || mod_type == 3'b101) modulating_carrier <= ssp_dout & ssp_clk_divider[4]; // switch 424kHz modulation on/off else modulating_carrier <= 1'b0; // yet unused @@ -106,7 +133,7 @@ assign pwr_oe4 = modulating_carrier; // This one is always on, so that we can watch the carrier. assign pwr_oe3 = 1'b0; -assign dbg = after_hysteresis; +assign dbg = modulating_carrier; //reg dbg; //always @(ssp_dout) // dbg <= ssp_dout; From 7b941c8d7f8d8203316fdfaf1ad0038fc4864cf1 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 15 Jan 2015 15:27:44 +0100 Subject: [PATCH 03/10] Fixed memory corruption after reader-attack in armsrc, fixed annoying LED --- armsrc/iclass.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 329e1765..72cfbefc 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -998,7 +998,7 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain else if(simType == 2) { - uint8_t mac_responses[64] = { 0 }; + uint8_t mac_responses[USB_CMD_DATA_SIZE] = { 0 }; Dbprintf("Going into attack mode, %d CSNS sent", numberOfCSNS); // In this mode, a number of csns are within datain. We'll simulate each one, one at a time // in order to collect MAC's from the reader. This can later be used in an offlne-attack @@ -1248,6 +1248,8 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader //Dbprintf("%x", cmdsRecvd); LED_A_OFF(); LED_B_OFF(); + LED_C_OFF(); + if(buttonPressed) { DbpString("Button pressed"); From 09b69422e221428d7e4870ae413fdda9042eac5f Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 15 Jan 2015 15:29:03 +0100 Subject: [PATCH 04/10] This was resynthezised along with my hf-changes. Nothing changed though --- fpga/fpga_lf.bit | Bin 42175 -> 42175 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/fpga/fpga_lf.bit b/fpga/fpga_lf.bit index e942921a8685731cbcf0e7bb6f86a11ea629dd0c..51b0681cd6a082550a19dccd794ff40439e393f9 100644 GIT binary patch literal 42175 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 literal 42175 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�$DR4HSsNmqcrsV|eYUj>P75ugYUv3T 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 From 6b038d192a8418ec7c5ab74c344b4d4b216efc5e Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 15 Jan 2015 15:45:54 +0100 Subject: [PATCH 05/10] Minor dox --- armsrc/iclass.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 72cfbefc..e7dd9535 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -921,7 +921,7 @@ static void CodeIClassTagAnswer(const uint8_t *cmd, int len) * - A 1-bit input to the FPGA becomes 8 pulses on 423.5kHz (fc/32) (18.88us). * - A 0-bit inptu to the FPGA becomes an unmodulated time of 18.88us * - * In thist mode the SOF can be written as 00011101 = 0x1D + * In this mode the SOF can be written as 00011101 = 0x1D * The EOF can be written as 10111000 = 0xb8 * A logic 1 is 01 * A logic 0 is 10 @@ -1215,12 +1215,7 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader cmdsRecvd++; } /** - After changes to parity calculation - Time between reader EOT and pm3 SOF - delay 21 -> 480uS - delay 10 -> 220us - delay 16 -> 388us - A legit tag has about 380us. + A legit tag has about 380us delay between reader EOT and tag SOF. **/ if(modulated_response_size > 0) { SendIClassAnswer(modulated_response, modulated_response_size, 1); From 758f1fd1f37d52678af1e9b1f72d58aecf41cac4 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 15 Jan 2015 16:07:58 +0100 Subject: [PATCH 06/10] Fixed issue #43 on github --- armsrc/iso14443a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index cf55e606..d326be2c 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1772,7 +1772,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u Dbprintf("Multiple tags detected. Collision after Bit %d", Demod.collisionPos); for (uint16_t i = collision_answer_offset; i < Demod.collisionPos; i++, uid_resp_bits++) { // add valid UID bits before collision point uint16_t UIDbit = (resp[i/8] >> (i % 8)) & 0x01; - uid_resp[uid_resp_bits & 0xf8] |= UIDbit << (uid_resp_bits % 8); + uid_resp[uid_resp_bits / 8] |= UIDbit << (uid_resp_bits % 8); } uid_resp[uid_resp_bits/8] |= 1 << (uid_resp_bits % 8); // next time select the card(s) with a 1 in the collision position uid_resp_bits++; From d60418a05f2cbaa97140c569ba63f1a1eb831a79 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 15 Jan 2015 16:28:28 +0100 Subject: [PATCH 07/10] Synchronized loclass library, imported the legal warning --- client/loclass/cipher.c | 20 +++++++++-- client/loclass/cipher.h | 20 +++++++++-- client/loclass/cipherutils.c | 19 +++++++++-- client/loclass/cipherutils.h | 20 +++++++++-- client/loclass/elite_crack.c | 62 +++++++++++++++++++++++++++++++++-- client/loclass/elite_crack.h | 39 ++++++++++++++++++++++ client/loclass/fileutils.c | 43 ++++++++++++++++++++++-- client/loclass/fileutils.h | 38 +++++++++++++++++++++ client/loclass/ikeys.c | 24 ++++++++++---- client/loclass/ikeys.h | 38 +++++++++++++++++++++ client/loclass/loclass_main.h | 4 +++ client/loclass/main.c | 40 +++++++++++++++++++--- 12 files changed, 342 insertions(+), 25 deletions(-) create mode 100644 client/loclass/loclass_main.h diff --git a/client/loclass/cipher.c b/client/loclass/cipher.c index 463ba9be..d3b1e799 100644 --- a/client/loclass/cipher.c +++ b/client/loclass/cipher.c @@ -1,5 +1,17 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -18,9 +30,13 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ + #include "cipher.h" #include "cipherutils.h" #include diff --git a/client/loclass/cipher.h b/client/loclass/cipher.h index 4bfbe0b7..176a2976 100644 --- a/client/loclass/cipher.h +++ b/client/loclass/cipher.h @@ -1,5 +1,17 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -18,9 +30,13 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ + #ifndef CIPHER_H #define CIPHER_H #include diff --git a/client/loclass/cipherutils.c b/client/loclass/cipherutils.c index e11e8d22..f9c62273 100644 --- a/client/loclass/cipherutils.c +++ b/client/loclass/cipherutils.c @@ -1,5 +1,17 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -18,7 +30,10 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ #include diff --git a/client/loclass/cipherutils.h b/client/loclass/cipherutils.h index acf96115..cb090f69 100644 --- a/client/loclass/cipherutils.h +++ b/client/loclass/cipherutils.h @@ -1,5 +1,17 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -18,9 +30,13 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ + #ifndef CIPHERUTILS_H #define CIPHERUTILS_H #include diff --git a/client/loclass/elite_crack.c b/client/loclass/elite_crack.c index adedba85..a8ab869e 100644 --- a/client/loclass/elite_crack.c +++ b/client/loclass/elite_crack.c @@ -1,3 +1,41 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + * + ****************************************************************************/ + #include #include #include @@ -514,6 +552,7 @@ int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) */ int bruteforceFile(const char *filename, uint16_t keytable[]) { + FILE *f = fopen(filename, "rb"); if(!f) { prnlog("Failed to read from file '%s'", filename); @@ -621,6 +660,21 @@ int _test_iclass_key_permutation() prnlog("[+] Iclass key permutation OK!"); return 0; } +int _testHash1() +{ + uint8_t csn[8]= {0x01,0x02,0x03,0x04,0xF7,0xFF,0x12,0xE0}; + uint8_t k[8] = {0}; + hash1(csn, k); + uint8_t expected[8] = {0x7E,0x72,0x2F,0x40,0x2D,0x02,0x51,0x42}; + if(memcmp(k,expected,8) != 0) + { + prnlog("Error with hash1!"); + printarr("calculated", k, 8); + printarr("expected", expected, 8); + return 1; + } + return 0; +} int testElite() { @@ -653,11 +707,13 @@ int testElite() prnlog("[+] Hash2 looks fine..."); } - prnlog("[+] Testing key diversification ..."); - int errors = 0 ; - errors +=_test_iclass_key_permutation(); + prnlog("[+] Testing hash1..."); + errors += _testHash1(); + prnlog("[+] Testing key diversification ..."); + errors +=_test_iclass_key_permutation(); errors += _testBruteforce(); + return errors; } diff --git a/client/loclass/elite_crack.h b/client/loclass/elite_crack.h index 21004e59..fb27355f 100644 --- a/client/loclass/elite_crack.h +++ b/client/loclass/elite_crack.h @@ -1,3 +1,42 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + * + ****************************************************************************/ + + #ifndef ELITE_CRACK_H #define ELITE_CRACK_H void permutekey(uint8_t key[8], uint8_t dest[8]); diff --git a/client/loclass/fileutils.c b/client/loclass/fileutils.c index 206d9695..4079dccf 100644 --- a/client/loclass/fileutils.c +++ b/client/loclass/fileutils.c @@ -1,3 +1,41 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + * + ****************************************************************************/ + #include #include #include @@ -40,14 +78,13 @@ int saveFile(const char *preferredName, const char *suffix, const void* data, si /*Opening file for writing in binary mode*/ FILE *fileHandle=fopen(fileName,"wb"); if(!fileHandle) { - PrintAndLog("Failed to write to file '%s'", fileName); + prnlog("Failed to write to file '%s'", fileName); free(fileName); return 1; } fwrite(data, 1, datalen, fileHandle); fclose(fileHandle); - PrintAndLog("Saved data to '%s'", fileName); - + prnlog("Saved data to '%s'", fileName); free(fileName); return 0; diff --git a/client/loclass/fileutils.h b/client/loclass/fileutils.h index e02079d5..623190a6 100644 --- a/client/loclass/fileutils.h +++ b/client/loclass/fileutils.h @@ -1,3 +1,41 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + * + ****************************************************************************/ + #ifndef FILEUTILS_H #define FILEUTILS_H /** diff --git a/client/loclass/ikeys.c b/client/loclass/ikeys.c index f7115b19..b21ecdbc 100644 --- a/client/loclass/ikeys.c +++ b/client/loclass/ikeys.c @@ -1,15 +1,23 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and * Milosch Meriac in the paper "Dismantling IClass". * - * This is a reference implementation of iclass key diversification. I'm sure it can be - * optimized heavily. It is written for ease of understanding and correctness, please take it - * and tweak it and make a super fast version instead, using this for testing and verification. - * Copyright (C) 2014 Martin Holst Swende * * This is free software: you can redistribute it and/or modify @@ -22,8 +30,12 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ + /** diff --git a/client/loclass/ikeys.h b/client/loclass/ikeys.h index 1de46b62..13096194 100644 --- a/client/loclass/ikeys.h +++ b/client/loclass/ikeys.h @@ -1,3 +1,41 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + * + ****************************************************************************/ + #ifndef IKEYS_H #define IKEYS_H diff --git a/client/loclass/loclass_main.h b/client/loclass/loclass_main.h new file mode 100644 index 00000000..b6d58a8b --- /dev/null +++ b/client/loclass/loclass_main.h @@ -0,0 +1,4 @@ +#ifndef LOCLASS_MAIN_H +#define LOCLASS_MAIN_H + +#endif // LOCLASS_MAIN_H diff --git a/client/loclass/main.c b/client/loclass/main.c index 42019072..d1b0359b 100644 --- a/client/loclass/main.c +++ b/client/loclass/main.c @@ -1,5 +1,17 @@ /***************************************************************************** - * This file is part of iClassCipher. It is a reconstructon of the cipher engine + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine * used in iClass, and RFID techology. * * The implementation is based on the work performed by @@ -18,11 +30,14 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with IClassCipher. If not, see . + * along with loclass. If not, see . + * + * + * ****************************************************************************/ + #include -#include #include #include #include @@ -40,11 +55,15 @@ int unitTests() errors += testMAC(); errors += doKeyTests(0); errors += testElite(); + if(errors) + { + prnlog("OBS! There were errors!!!"); + } return errors; } int showHelp() { - prnlog("Usage: iclazz [options]"); + prnlog("Usage: loclass [options]"); prnlog("Options:"); prnlog("-t Perform self-test"); prnlog("-h Show this help"); @@ -64,7 +83,18 @@ int main (int argc, char **argv) { prnlog("IClass Cipher version 1.2, Copyright (C) 2014 Martin Holst Swende\n"); prnlog("Comes with ABSOLUTELY NO WARRANTY"); - prnlog("This is free software, and you are welcome to use, abuse and repackage, please keep the credits\n"); + prnlog("Released as GPLv2\n"); + prnlog("WARNING"); + prnlog(""); + prnlog("THIS TOOL IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. "); + prnlog(""); + prnlog("USAGE OF THIS TOOL IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL "); + prnlog("PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, "); + prnlog("AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. "); + prnlog(""); + prnlog("THIS TOOL SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. "); + + char *fileName = NULL; int c; while ((c = getopt (argc, argv, "thf:")) != -1) From 49726b4088b78027b7ce3215c432cbb99a283f27 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 15 Jan 2015 23:00:39 +0100 Subject: [PATCH 08/10] Improved 'hf list iclass' a bit, better understanding of the protocol and when to apply CRC checks --- client/cmdhf.c | 112 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 87 insertions(+), 25 deletions(-) diff --git a/client/cmdhf.c b/client/cmdhf.c index 762fada4..33d01aee 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -123,14 +123,19 @@ NXP/Philips CUSTOM COMMANDS 40 = Long Range CMD (Standard ISO/TR7003:1990) */ -#define ICLASS_CMD_ACTALL 0x0A +#define ICLASS_CMD_ACTALL 0x0A #define ICLASS_CMD_READ_OR_IDENTIFY 0x0C -#define ICLASS_CMD_SELECT 0x81 -#define ICLASS_CMD_PAGESEL 0x84 -#define ICLASS_CMD_READCHECK 0x88 -#define ICLASS_CMD_CHECK 0x05 -#define ICLASS_CMD_SOF 0x0F -#define ICLASS_CMD_HALT 0x00 +#define ICLASS_CMD_SELECT 0x81 +#define ICLASS_CMD_PAGESEL 0x84 +#define ICLASS_CMD_READCHECK_KD 0x88 +#define ICLASS_CMD_READCHECK_KC 0x18 +#define ICLASS_CMD_CHECK 0x05 +#define ICLASS_CMD_DETECT 0x0F +#define ICLASS_CMD_HALT 0x00 +#define ICLASS_CMD_UPDATE 0x87 +#define ICLASS_CMD_ACT 0x8E +#define ICLASS_CMD_READ4 0x06 + #define ISO14443_CMD_REQA 0x26 #define ISO14443_CMD_READBLOCK 0x30 @@ -235,11 +240,15 @@ void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) break; } case ICLASS_CMD_SELECT: snprintf(exp,size,"SELECT"); break; - case ICLASS_CMD_PAGESEL: snprintf(exp,size,"PAGESEL"); break; - case ICLASS_CMD_READCHECK: snprintf(exp,size,"READCHECK"); break; + case ICLASS_CMD_PAGESEL: snprintf(exp,size,"PAGESEL(%d)", cmd[1]); break; + case ICLASS_CMD_READCHECK_KC:snprintf(exp,size,"READCHECK[Kc](%d)", cmd[1]); break; + case ICLASS_CMD_READCHECK_KD:snprintf(exp,size,"READCHECK[Kd](%d)", cmd[1]); break; case ICLASS_CMD_CHECK: snprintf(exp,size,"CHECK"); break; - case ICLASS_CMD_SOF: snprintf(exp,size,"SOF"); break; + case ICLASS_CMD_DETECT: snprintf(exp,size,"DETECT"); break; case ICLASS_CMD_HALT: snprintf(exp,size,"HALT"); break; + case ICLASS_CMD_UPDATE: snprintf(exp,size,"UPDATE(%d)",cmd[1]); break; + case ICLASS_CMD_ACT: snprintf(exp,size,"ACT"); break; + case ICLASS_CMD_READ4: snprintf(exp,size,"READ4(%d)",cmd[1]); break; default: snprintf(exp,size,"?"); break; } return; @@ -276,6 +285,66 @@ void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) } } } +/** + * @brief iclass_CRC_Ok Checks CRC in command or response + * @param isResponse + * @param data + * @param len + * @return 0 : CRC-command, CRC not ok + * 1 : CRC-command, CRC ok + * 2 : Not crc-command + */ +uint8_t iclass_CRC_Ok(bool isResponse, uint8_t* data, uint8_t len) +{ + if(len < 4) return 2;//CRC commands (and responses) are all at least 4 bytes + + uint8_t b1, b2; + + if(!isResponse)//Commands to tag + { + /** + These commands should have CRC. Total length leftmost + 4 READ + 4 READ4 + 12 UPDATE - unsecured, ends with CRC16 + 14 UPDATE - secured, ends with signature instead + 4 PAGESEL + **/ + if(len == 4 || len == 12)//Covers three of them + { + //Don't include the command byte + ComputeCrc14443(CRC_ICLASS, (data+1), len-3, &b1, &b2); + return b1 == data[len -2] && b2 == data[len-1]; + } + return 2; + }else{ + /** + These tag responses should have CRC. Total length leftmost + + 10 READ data[8] crc[2] + 34 READ4 data[32]crc[2] + 10 UPDATE data[8] crc[2] + 10 SELECT csn[8] crc[2] + 10 IDENTIFY asnb[8] crc[2] + 10 PAGESEL block1[8] crc[2] + 10 DETECT csn[8] crc[2] + + These should not + + 4 CHECK chip_response[4] + 8 READCHECK data[8] + 1 ACTALL sof[1] + 1 ACT sof[1] + + In conclusion, without looking at the command; any response + of length 10 or 34 should have CRC + **/ + if(len != 10 && len != 34) return true; + + ComputeCrc14443(CRC_ICLASS, data, len-2, &b1, &b2); + return b1 == data[len -2] && b2 == data[len-1]; + } +} uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool showWaitCycles) { @@ -332,24 +401,14 @@ uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool sho } } //--- Draw the CRC column - bool crcError = false; + uint8_t crcStatus = 2; if (data_len > 2) { uint8_t b1, b2; if(iclass) { - if(!isResponse && data_len == 4 ) { - // Rough guess that this is a command from the reader - // For iClass the command byte is not part of the CRC - ComputeCrc14443(CRC_ICLASS, &frame[1], data_len-3, &b1, &b2); - } else { - // For other data.. CRC might not be applicable (UPDATE commands etc.) - ComputeCrc14443(CRC_ICLASS, frame, data_len-2, &b1, &b2); - } - - if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { - crcError = true; - } + //The following commands have crc + crcStatus = iclass_CRC_Ok(isResponse, frame, data_len); }else{//Iso 14443a @@ -358,12 +417,15 @@ uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool sho if (b1 != frame[data_len-2] || b2 != frame[data_len-1]) { if(!(isResponse & (data_len < 6))) { - crcError = true; + crcStatus = 0; } } } } - char *crc = crcError ? "!crc" :" "; + //0 CRC-command, CRC not ok + //1 CRC-command, CRC ok + //2 Not crc-command + char *crc = (crcStatus == 0 ? "!crc" : (crcStatus == 1 ? " ok " : " ")); EndOfTransmissionTimestamp = timestamp + duration; From 41fdd0f061ae7ef4cdc5bfc027f1097c990c3318 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 16 Jan 2015 22:41:19 +0100 Subject: [PATCH 09/10] First stab at adding 'hf list 14b' and 'hf list raw' --- client/cmdhf.c | 112 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 83 insertions(+), 29 deletions(-) diff --git a/client/cmdhf.c b/client/cmdhf.c index 33d01aee..20ca057b 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -137,14 +137,14 @@ NXP/Philips CUSTOM COMMANDS #define ICLASS_CMD_READ4 0x06 -#define ISO14443_CMD_REQA 0x26 -#define ISO14443_CMD_READBLOCK 0x30 -#define ISO14443_CMD_WUPA 0x52 -#define ISO14443_CMD_ANTICOLL_OR_SELECT 0x93 -#define ISO14443_CMD_ANTICOLL_OR_SELECT_2 0x95 -#define ISO14443_CMD_WRITEBLOCK 0xA0 // or 0xA2 ? -#define ISO14443_CMD_HALT 0x50 -#define ISO14443_CMD_RATS 0xE0 +#define ISO14443A_CMD_REQA 0x26 +#define ISO14443A_CMD_READBLOCK 0x30 +#define ISO14443A_CMD_WUPA 0x52 +#define ISO14443A_CMD_ANTICOLL_OR_SELECT 0x93 +#define ISO14443A_CMD_ANTICOLL_OR_SELECT_2 0x95 +#define ISO14443A_CMD_WRITEBLOCK 0xA0 // or 0xA2 ? +#define ISO14443A_CMD_HALT 0x50 +#define ISO14443A_CMD_RATS 0xE0 #define MIFARE_AUTH_KEYA 0x60 #define MIFARE_AUTH_KEYB 0x61 @@ -180,14 +180,17 @@ NXP/Philips CUSTOM COMMANDS #define ISO15693_READ_MULTI_SECSTATUS 0x2C +#define ISO_14443A 0 +#define ICLASS 1 +#define ISO_14443B 2 void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) { switch(cmd[0]) { - case ISO14443_CMD_WUPA: snprintf(exp,size,"WUPA"); break; - case ISO14443_CMD_ANTICOLL_OR_SELECT:{ + case ISO14443A_CMD_WUPA: snprintf(exp,size,"WUPA"); break; + case ISO14443A_CMD_ANTICOLL_OR_SELECT:{ // 93 20 = Anticollision (usage: 9320 - answer: 4bytes UID+1byte UID-bytes-xor) // 93 70 = Select (usage: 9370+5bytes 9320 answer - answer: 1byte SAK) if(cmd[2] == 0x70) @@ -198,7 +201,7 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) snprintf(exp,size,"ANTICOLL"); break; } } - case ISO14443_CMD_ANTICOLL_OR_SELECT_2:{ + case ISO14443A_CMD_ANTICOLL_OR_SELECT_2:{ //95 20 = Anticollision of cascade level2 //95 70 = Select of cascade level2 if(cmd[2] == 0x70) @@ -209,11 +212,11 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) snprintf(exp,size,"ANTICOLL-2"); break; } } - case ISO14443_CMD_REQA: snprintf(exp,size,"REQA"); break; - case ISO14443_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break; - case ISO14443_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break; - case ISO14443_CMD_HALT: snprintf(exp,size,"HALT"); break; - case ISO14443_CMD_RATS: snprintf(exp,size,"RATS"); break; + case ISO14443A_CMD_REQA: snprintf(exp,size,"REQA"); break; + case ISO14443A_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break; + case ISO14443A_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break; + case ISO14443A_CMD_HALT: snprintf(exp,size,"HALT"); break; + case ISO14443A_CMD_RATS: snprintf(exp,size,"RATS"); break; case MIFARE_CMD_INC: snprintf(exp,size,"INC(%d)",cmd[1]); break; case MIFARE_CMD_DEC: snprintf(exp,size,"DEC(%d)",cmd[1]); break; case MIFARE_CMD_RESTORE: snprintf(exp,size,"RESTORE(%d)",cmd[1]); break; @@ -281,10 +284,44 @@ void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) case ISO15693_LOCK_DSFID :snprintf(exp, size, "LOCK_DSFID");break; case ISO15693_GET_SYSTEM_INFO :snprintf(exp, size, "GET_SYSTEM_INFO");break; case ISO15693_READ_MULTI_SECSTATUS :snprintf(exp, size, "READ_MULTI_SECSTATUS");break; - default: snprintf(exp,size,"?"); break; + default: snprintf(exp,size,"?"); break; } } } +void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) +{ + switch(cmd[0]){ + case ISO14443B_REQB : snprintf(exp,size,"REQB");break; + case ISO14443B_ATTRIB : snprintf(exp,size,"ATTRIB");break; + case ISO14443B_HALT : snprintf(exp,size,"HALT");break; + default: snprintf(exp,size ,"?");break; + } + +} + +/** + * @brief iso14443B_CRC_Ok Checks CRC in command or response + * @param isResponse + * @param data + * @param len + * @return 0 : CRC-command, CRC not ok + * 1 : CRC-command, CRC ok + * 2 : Not crc-command + */ + +uint8_t iso14443B_CRC_check(bool isResponse, uint8_t* data, uint8_t len) +{ + uint8_t b1,b2; + + if(len <= 2) return 2; + + ComputeCrc14443(CRC_14443_B, data, len-2, &b1, &b2); + if(b1 != data[len-2] || b2 != data[len-1]) { + return 0; + } + return 1; +} + /** * @brief iclass_CRC_Ok Checks CRC in command or response * @param isResponse @@ -294,7 +331,7 @@ void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) * 1 : CRC-command, CRC ok * 2 : Not crc-command */ -uint8_t iclass_CRC_Ok(bool isResponse, uint8_t* data, uint8_t len) +uint8_t iclass_CRC_check(bool isResponse, uint8_t* data, uint8_t len) { if(len < 4) return 2;//CRC commands (and responses) are all at least 4 bytes @@ -346,7 +383,7 @@ uint8_t iclass_CRC_Ok(bool isResponse, uint8_t* data, uint8_t len) } } -uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool showWaitCycles) +uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, uint8_t protocol, bool showWaitCycles) { bool isResponse; uint16_t duration, data_len,parity_len; @@ -405,12 +442,15 @@ uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool sho if (data_len > 2) { uint8_t b1, b2; - if(iclass) + if(protocol == ICLASS) { - //The following commands have crc - crcStatus = iclass_CRC_Ok(isResponse, frame, data_len); + crcStatus = iclass_CRC_check(isResponse, frame, data_len); - }else{//Iso 14443a + }else if (protocol == ISO_14443B) + { + crcStatus = iso14443B_CRC_check(isResponse, frame, data_len); + } + else if (protocol == ISO_14443A){//Iso 14443a ComputeCrc14443(CRC_14443_A, frame, data_len-2, &b1, &b2); @@ -431,10 +471,12 @@ uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool sho if(!isResponse) { - if(iclass) + if(protocol == ICLASS) annotateIclass(explanation,sizeof(explanation),frame,data_len); - else + else if (protocol == ISO_14443A) annotateIso14443a(explanation,sizeof(explanation),frame,data_len); + else if(protocol == ISO_14443B) + annotateIso14443b(explanation,sizeof(explanation),frame,data_len); } int num_lines = (data_len - 1)/16 + 1; @@ -477,7 +519,7 @@ int CmdHFList(const char *Cmd) int tlen = param_getstr(Cmd,0,type); char param = param_getchar(Cmd, 1); bool errors = false; - bool iclass = false; + uint8_t protocol = false; //Validate params if(tlen == 0 || (strcmp(type, "iclass") != 0 && strcmp(type,"14a") != 0)) { @@ -490,9 +532,11 @@ int CmdHFList(const char *Cmd) if (errors) { PrintAndLog("List protocol data in trace buffer."); - PrintAndLog("Usage: hf list [14a|iclass] [f]"); + PrintAndLog("Usage: hf list [14a|14b|iclass] [f]"); PrintAndLog(" 14a - interpret data as iso14443a communications"); + PrintAndLog(" 14b - interpret data as iso14443b communications"); PrintAndLog(" iclass - interpret data as iclass communications"); + PrintAndLog(" raw - just show raw data"); PrintAndLog(" f - show frame delay times as well"); PrintAndLog(""); PrintAndLog("example: hf list 14a f"); @@ -501,7 +545,17 @@ int CmdHFList(const char *Cmd) } if(strcmp(type, "iclass") == 0) { - iclass = true; + protocol = ICLASS; + }else if(strcmp(type, "14a") == 0) + { + protocol = ISO_14443A; + } + else if(strcmp(type, "14b") == 0) + { + protocol = ISO_14443B; + }else if(strcmp(type,"raw")== 0) + { + protocol = -1;//No crc, no annotations } if (param == 'f') { @@ -525,7 +579,7 @@ int CmdHFList(const char *Cmd) while(tracepos < TRACE_SIZE) { - tracepos = printTraceLine(tracepos, trace, iclass, showWaitCycles); + tracepos = printTraceLine(tracepos, trace, protocol, showWaitCycles); } return 0; } From b689b842b68c061340f18ff595ffdabf34bdc4f0 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Fri, 16 Jan 2015 22:48:30 +0100 Subject: [PATCH 10/10] Bugfix 'hf list 14b' and 'hf list raw' --- client/cmdhf.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/client/cmdhf.c b/client/cmdhf.c index 20ca057b..9acc9825 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -519,9 +519,9 @@ int CmdHFList(const char *Cmd) int tlen = param_getstr(Cmd,0,type); char param = param_getchar(Cmd, 1); bool errors = false; - uint8_t protocol = false; + uint8_t protocol = 0; //Validate params - if(tlen == 0 || (strcmp(type, "iclass") != 0 && strcmp(type,"14a") != 0)) + if(tlen == 0) { errors = true; } @@ -529,6 +529,25 @@ int CmdHFList(const char *Cmd) { errors = true; } + if(!errors) + { + if(strcmp(type, "iclass") == 0) + { + protocol = ICLASS; + }else if(strcmp(type, "14a") == 0) + { + protocol = ISO_14443A; + } + else if(strcmp(type, "14b") == 0) + { + protocol = ISO_14443B; + }else if(strcmp(type,"raw")== 0) + { + protocol = -1;//No crc, no annotations + }else{ + errors = true; + } + } if (errors) { PrintAndLog("List protocol data in trace buffer."); @@ -543,20 +562,7 @@ int CmdHFList(const char *Cmd) PrintAndLog("example: hf list iclass"); return 0; } - if(strcmp(type, "iclass") == 0) - { - protocol = ICLASS; - }else if(strcmp(type, "14a") == 0) - { - protocol = ISO_14443A; - } - else if(strcmp(type, "14b") == 0) - { - protocol = ISO_14443B; - }else if(strcmp(type,"raw")== 0) - { - protocol = -1;//No crc, no annotations - } + if (param == 'f') { showWaitCycles = true;