diff --git a/armsrc/apps.h b/armsrc/apps.h index 1e97f2945..93760aae3 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -146,7 +146,7 @@ void RAMFUNC SnoopIso14443a(uint8_t param); void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data); void ReaderIso14443a(UsbCommand * c); // Also used in iclass.c -bool RAMFUNC LogTrace(const uint8_t * btBytes, uint8_t iLen, uint32_t iSamples, uint32_t dwParity, bool bReader); +bool RAMFUNC LogTrace(const uint8_t * btBytes, uint8_t iLen, uint32_t iSamples, uint32_t dwParity, bool readerToTag); uint32_t GetParity(const uint8_t * pbtCmd, int iLen); void iso14a_set_trigger(bool enable); void iso14a_clear_trace(); diff --git a/armsrc/iclass.c b/armsrc/iclass.c index bfa4a730c..42fed888f 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -666,12 +666,7 @@ static RAMFUNC int ManchesterDecoding(int v) //----------------------------------------------------------------------------- void RAMFUNC SnoopIClass(void) { -// DEFINED ABOVE -// #define RECV_CMD_OFFSET 3032 -// #define RECV_RES_OFFSET 3096 -// #define DMA_BUFFER_OFFSET 3160 -// #define DMA_BUFFER_SIZE 4096 -// #define TRACE_SIZE 3000 + // We won't start recording the frames that we acquire until we trigger; // a good trigger condition to get started is probably when we see a @@ -681,14 +676,10 @@ void RAMFUNC SnoopIClass(void) // The command (reader -> tag) that we're receiving. // The length of a received command will in most cases be no more than 18 bytes. // So 32 should be enough! - uint8_t *receivedCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); + uint8_t *readerToTagCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); // The response (tag -> reader) that we're receiving. - uint8_t *receivedResponse = (((uint8_t *)BigBuf) + RECV_RES_OFFSET); + uint8_t *tagToReaderResponse = (((uint8_t *)BigBuf) + RECV_RES_OFFSET); - // As we receive stuff, we copy it from receivedCmd or receivedResponse - // into trace, along with its length and other annotations. - //uint8_t *trace = (uint8_t *)BigBuf; - // reset traceLen to 0 iso14a_set_tracing(TRUE); iso14a_clear_trace(); @@ -709,7 +700,7 @@ void RAMFUNC SnoopIClass(void) memset(trace, 0x44, RECV_CMD_OFFSET); // Set up the demodulator for tag -> reader responses. - Demod.output = receivedResponse; + Demod.output = tagToReaderResponse; Demod.len = 0; Demod.state = DEMOD_UNSYNCD; @@ -721,7 +712,7 @@ void RAMFUNC SnoopIClass(void) // And the reader -> tag commands memset(&Uart, 0, sizeof(Uart)); - Uart.output = receivedCmd; + Uart.output = readerToTagCmd; Uart.byteCntMax = 32; // was 100 (greg)//////////////////////////////////////////////////////////////////////// Uart.state = STATE_UNSYNCD; @@ -764,20 +755,13 @@ void RAMFUNC SnoopIClass(void) //samples += 4; samples += 1; - //div2++; - //if(div2 > 3) { - //div2 = 0; - //decbyte ^= ((smpl & 0x01) << (3 - div)); - //decbyte ^= (((smpl & 0x01) | ((smpl & 0x02) >> 1)) << (3 - div)); // better already... - //decbyte ^= (((smpl & 0x01) | ((smpl & 0x02) >> 1) | ((smpl & 0x04) >> 2)) << (3 - div)); // even better... if(smpl & 0xF) { decbyte ^= (1 << (3 - div)); } - //decbyte ^= (MajorityNibble[(smpl & 0x0F)] << (3 - div)); // FOR READER SIDE COMMUMICATION... - //decbyte ^= ((smpl & 0x10) << (3 - div)); + decbyter <<= 2; decbyter ^= (smpl & 0x30); @@ -788,21 +772,11 @@ void RAMFUNC SnoopIClass(void) if(OutOfNDecoding((smpl & 0xF0) >> 4)) { rsamples = samples - Uart.samples; LED_C_ON(); - //if(triggered) { - trace[traceLen++] = ((rsamples >> 0) & 0xff); - trace[traceLen++] = ((rsamples >> 8) & 0xff); - trace[traceLen++] = ((rsamples >> 16) & 0xff); - trace[traceLen++] = ((rsamples >> 24) & 0xff); - trace[traceLen++] = ((Uart.parityBits >> 0) & 0xff); - trace[traceLen++] = ((Uart.parityBits >> 8) & 0xff); - trace[traceLen++] = ((Uart.parityBits >> 16) & 0xff); - trace[traceLen++] = ((Uart.parityBits >> 24) & 0xff); - trace[traceLen++] = Uart.byteCnt; - memcpy(trace+traceLen, receivedCmd, Uart.byteCnt); - traceLen += Uart.byteCnt; - if(traceLen > TRACE_SIZE) break; - //} - /* And ready to receive another command. */ + + if(!LogTrace(readerToTagCmd,Uart.byteCnt, rsamples, Uart.parityBits,TRUE)) break; + //if(!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, TRUE)) break; + + /* And ready to receive another command. */ Uart.state = STATE_UNSYNCD; /* And also reset the demod code, which might have been */ /* false-triggered by the commands from the reader. */ @@ -819,26 +793,13 @@ void RAMFUNC SnoopIClass(void) rsamples = samples - Demod.samples; LED_B_ON(); - // timestamp, as a count of samples - trace[traceLen++] = ((rsamples >> 0) & 0xff); - trace[traceLen++] = ((rsamples >> 8) & 0xff); - trace[traceLen++] = ((rsamples >> 16) & 0xff); - trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 0) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 8) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff); - trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff); - // length - trace[traceLen++] = Demod.len; - memcpy(trace+traceLen, receivedResponse, Demod.len); - traceLen += Demod.len; - if(traceLen > TRACE_SIZE) break; + if(!LogTrace(tagToReaderResponse,Demod.len, rsamples, Demod.parityBits,FALSE)) break; + //if (!LogTrace(NULL, 0, Demod.endTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, 0, FALSE)) break; - //triggered = TRUE; // And ready to receive another response. memset(&Demod, 0, sizeof(Demod)); - Demod.output = receivedResponse; + Demod.output = tagToReaderResponse; Demod.state = DEMOD_UNSYNCD; LED_C_OFF(); } @@ -1019,6 +980,7 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain } else if(simType == 2) { + Dbprintf("Going into attack mode"); // 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 // in order to obtain the keys, as in the "dismantling iclass"-paper. @@ -1131,13 +1093,13 @@ void doIClassSimulation(uint8_t csn[], int breakAfterMacReceived) } // Okay, look at the command now. - if(receivedCmd[0] == 0x0a) { + if(receivedCmd[0] == 0x0a || receivedCmd[0] == 0x26) { // Reader in anticollission phase resp = resp1; respLen = resp1Len; //order = 1; respdata = &sof; respsize = sizeof(sof); //resp = resp2; respLen = resp2Len; order = 2; - //DbpString("Hello request from reader:"); + Dbprintf("Hello request from reader, %02x, tracing=%d", receivedCmd[0], tracing); } else if(receivedCmd[0] == 0x0c) { // Reader asks for anticollission CSN resp = resp2; respLen = resp2Len; //order = 2; @@ -1180,6 +1142,7 @@ void doIClassSimulation(uint8_t csn[], int breakAfterMacReceived) respdata = NULL; respsize = 0; } else { + //#db# Unknown command received from reader (len=5): 26 1 0 f6 a 44 44 44 44 // Never seen this command before Dbprintf("Unknown command received from reader (len=%d): %x %x %x %x %x %x %x %x %x", len, @@ -1205,14 +1168,21 @@ void doIClassSimulation(uint8_t csn[], int breakAfterMacReceived) } if (tracing) { - LogTrace(receivedCmd,len, rsamples, Uart.parityBits, TRUE); - if (respdata != NULL) { - LogTrace(respdata,respsize, rsamples, SwapBits(GetParity(respdata,respsize),respsize), FALSE); - } - if(traceLen > TRACE_SIZE) { + //LogTrace(receivedCmd,len, rsamples, Uart.parityBits, TRUE); + if(!LogTrace(receivedCmd,len, rsamples, Uart.parityBits,TRUE)) + { DbpString("Trace full"); break; } + + if (respdata != NULL) { + //LogTrace(respdata,respsize, rsamples, SwapBits(GetParity(respdata,respsize),respsize), FALSE); + if(!LogTrace(respdata,respsize, rsamples,SwapBits(GetParity(respdata,respsize),respsize),FALSE)) + { + DbpString("Trace full"); + break; + } + } } memset(receivedCmd, 0x44, RECV_CMD_SIZE); } diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 9afe0788c..8e4082eab 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -190,7 +190,7 @@ void AppendCrc14443a(uint8_t* data, int len) } // The function LogTrace() is also used by the iClass implementation in iClass.c -bool RAMFUNC LogTrace(const uint8_t * btBytes, uint8_t iLen, uint32_t timestamp, uint32_t dwParity, bool bReader) +bool RAMFUNC LogTrace(const uint8_t * btBytes, uint8_t iLen, uint32_t timestamp, uint32_t dwParity, bool readerToTag) { // Return when trace is full if (traceLen + sizeof(timestamp) + sizeof(dwParity) + iLen >= TRACE_SIZE) { @@ -203,7 +203,8 @@ bool RAMFUNC LogTrace(const uint8_t * btBytes, uint8_t iLen, uint32_t timestamp, trace[traceLen++] = ((timestamp >> 8) & 0xff); trace[traceLen++] = ((timestamp >> 16) & 0xff); trace[traceLen++] = ((timestamp >> 24) & 0xff); - if (!bReader) { + + if (!readerToTag) { trace[traceLen - 1] |= 0x80; } trace[traceLen++] = ((dwParity >> 0) & 0xff); diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index f807e9721..9f6842b81 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -21,10 +21,139 @@ #include "cmdhficlass.h" #include "common.h" #include "util.h" +#include "cmdmain.h" static int CmdHelp(const char *Cmd); +int xorbits_8(uint8_t val) +{ + uint8_t res = val ^ (val >> 1); //1st pass + res = res ^ (res >> 1); // 2nd pass + res = res ^ (res >> 2); // 3rd pass + res = res ^ (res >> 4); // 4th pass + return res & 1; +} + int CmdHFiClassList(const char *Cmd) +{ + + bool ShowWaitCycles = false; + char param = param_getchar(Cmd, 0); + + if (param != 0) { + PrintAndLog("List data in trace buffer."); + PrintAndLog("Usage: hf iclass list"); + PrintAndLog("h - help"); + PrintAndLog("sample: hf iclass list"); + return 0; + } + + uint8_t got[1920]; + GetFromBigBuf(got,sizeof(got),0); + WaitForResponse(CMD_ACK,NULL); + + PrintAndLog("Recorded Activity"); + PrintAndLog(""); + PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); + PrintAndLog("All times are in carrier periods (1/13.56Mhz)"); + PrintAndLog(""); + PrintAndLog(" Start | End | Src | Data"); + PrintAndLog("-----------|-----------|-----|--------"); + + int i; + uint32_t first_timestamp = 0; + uint32_t timestamp; + bool tagToReader; + uint32_t parityBits; + uint8_t len; + uint8_t *frame; + uint32_t EndOfTransmissionTimestamp = 0; + + uint8_t empty[4] = {0x44,0x44,0x44,0x44}; + + for( i=0; i < 1900;) + { + //First 32 bits contain + // isResponse (1 bit) + // timestamp (remaining) + //Then paritybits + //Then length + timestamp = *((uint32_t *)(got+i)); + parityBits = *((uint32_t *)(got+i+4)); + len = got[i+8]; + frame = (got+i+9); + uint32_t next_timestamp = (*((uint32_t *)(got+i+9))) & 0x7fffffff; + + tagToReader = timestamp & 0x80000000; + timestamp &= 0x7fffffff; + + if(i==0) { + first_timestamp = timestamp; + } + + // Break and stick with current result if buffer + // was not completely full + if(memcmp(frame,empty,sizeof(empty))) break; + + char line[1000] = ""; + + if(len)//We have some data to display + { + int j,oddparity; + + for(j = 0; j < len ; j++) + { + oddparity = 0x01 ^ xorbits_8(frame[j] & 0xFF); + + if (tagToReader && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) { + sprintf(line+(j*4), "%02x! ", frame[j]); + } else { + sprintf(line+(j*4), "%02x ", frame[j]); + } + } + }else + { + if (ShowWaitCycles) { + sprintf(line, "fdt (Frame Delay Time): %d", (next_timestamp - timestamp)); + } + } + + char *crc = ""; + + if(len > 2) + { + uint8_t b1, b2; + if(!tagToReader && 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], len-3, &b1, &b2); + } + else { + // For other data.. CRC might not be applicable (UPDATE commands etc.) + ComputeCrc14443(CRC_ICLASS, frame, len-2, &b1, &b2); + } + + if (b1 != frame[len-2] || b2 != frame[len-1]) { + crc = (tagToReader & (len < 8)) ? "" : " !crc"; + } + } + + i += (len + 9); + EndOfTransmissionTimestamp = (*((uint32_t *)(got+i))) & 0x7fffffff; + + // Not implemented for iclass on the ARM-side + //if (!ShowWaitCycles) i += 9; + + PrintAndLog(" %9d | %9d | %s | %s %s", + (timestamp - first_timestamp), + (EndOfTransmissionTimestamp - first_timestamp), + (len?(tagToReader ? "Tag" : "Rdr"):" "), + line, crc); + } + return 0; +} + +int CmdHFiClassListOld(const char *Cmd) { uint8_t got[1920]; GetFromBigBuf(got,sizeof(got),0); @@ -50,7 +179,9 @@ int CmdHFiClassList(const char *Cmd) isResponse = 0; } + int metric = 0; + int parityBits = *((uint32_t *)(got+i+4)); // 4 bytes of additional information... // maximum of 32 additional parity bit information @@ -177,21 +308,78 @@ int CmdHFiClassSim(const char *Cmd) uint8_t simType = 0; uint8_t CSN[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - if (strlen(Cmd)<2) { - PrintAndLog("Usage: hf iclass sim "); + if (strlen(Cmd)<1) { + PrintAndLog("Usage: hf iclass sim [0 ] | x"); + PrintAndLog(" options"); + PrintAndLog(" 0 simulate the given CSN"); + PrintAndLog(" 1 simulate default CSN"); + PrintAndLog(" 2 iterate CSNs, gather MACs"); PrintAndLog(" sample: hf iclass sim 0 031FEC8AF7FF12E0"); + PrintAndLog(" sample: hf iclass sim 2"); return 0; } simType = param_get8(Cmd, 0); - if (param_gethex(Cmd, 1, CSN, 16)) { - PrintAndLog("A CSN should consist of 16 HEX symbols"); - return 1; - } - PrintAndLog("--simtype:%02x csn:%s", simType, sprint_hex(CSN, 8)); - UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType}}; + if(simType == 0) + { + if (param_gethex(Cmd, 1, CSN, 16)) { + PrintAndLog("A CSN should consist of 16 HEX symbols"); + return 1; + } + PrintAndLog("--simtype:%02x csn:%s", simType, sprint_hex(CSN, 8)); + + } + if(simType > 2) + { + PrintAndLog("Undefined simptype %d", simType); + return 1; + } + uint8_t numberOfCSNs=0; + + UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType,numberOfCSNs}}; memcpy(c.d.asBytes, CSN, 8); + + if(simType == 2) + { + c.arg[1] = 10;//10 CSNs + uint8_t csns[] ={ + /* Order Simulated CSN HASH1 Recovered key bytes */ + /* 1 */ 0x00,0x0B,0x0F,0xFF,0xF7,0xFF,0x12,0xE0,// 0101000045014545 00,01 45 + /* 2 */ 0x03,0x0B,0x0E,0xFE,0xF7,0xFF,0x12,0xE0,// 0202000045014545 02 + /* 3 */ 0x04,0x0D,0x0D,0xFD,0xF7,0xFF,0x12,0xE0,// 0303000045014545 03 + /* 4 */ 0x04,0x0F,0x0F,0xF7,0xF7,0xFF,0x12,0xE0,// 0901000045014545 09 + /* 5 */ 0x01,0x13,0x10,0xF4,0xF7,0xFF,0x12,0xE0,// 0C00000045014545 0C + /* 6 */ 0x02,0x14,0x10,0xF2,0xF7,0xFF,0x12,0xE0,// 0E00000045014545 0E + /* 7 */ 0x05,0x17,0x10,0xEC,0xF7,0xFF,0x12,0xE0,// 1400000045014545 14 + /* 8 */ 0x00,0x6B,0x6F,0xDF,0xF7,0xFF,0x12,0xE0,// 2121000045014545 21 + /* 9 */ 0x03,0x6B,0x6E,0xDE,0xF7,0xFF,0x12,0xE0,// 2222000045014545 22 + /* 10 */ 0x04,0x6D,0x6D,0xDD,0xF7,0xFF,0x12,0xE0,// 2323000045014545 23 + /* 11 */ 0x00,0x4F,0x4B,0x43,0xF7,0xFF,0x12,0xE0,// 3D45000045014545 3D + /* 12 */ 0x00,0x4B,0x4F,0x3F,0xF7,0xFF,0x12,0xE0,// 4141000045014545 41 + /* 13 */ 0x03,0x4B,0x4E,0x3E,0xF7,0xFF,0x12,0xE0,// 4242000045014545 42 + /* 14 */ 0x04,0x4D,0x4D,0x3D,0xF7,0xFF,0x12,0xE0,// 4343000045014545 43 + /* 15 */ 0x04,0x37,0x37,0x7F,0xF7,0xFF,0x12,0xE0,// 0159000045014545 59 + /* 16 */ 0x00,0x2B,0x2F,0x9F,0xF7,0xFF,0x12,0xE0,// 6161000045014545 61 + /* 17 */ 0x03,0x2B,0x2E,0x9E,0xF7,0xFF,0x12,0xE0,// 6262000045014545 62 + /* 18 */ 0x04,0x2D,0x2D,0x9D,0xF7,0xFF,0x12,0xE0,// 6363000045014545 63 + /* 19 */ 0x00,0x27,0x23,0xBB,0xF7,0xFF,0x12,0xE0,// 456D000045014545 6D + /* 20 */ 0x02,0x52,0xAA,0x80,0xF7,0xFF,0x12,0xE0,// 0066000045014545 66 + /* 21 */ 0x00,0x5C,0xA6,0x80,0xF7,0xFF,0x12,0xE0,// 006A000045014545 6A + /* 22 */ 0x01,0x5F,0xA4,0x80,0xF7,0xFF,0x12,0xE0,// 006C000045014545 6C + /* 23 */ 0x06,0x5E,0xA2,0x80,0xF7,0xFF,0x12,0xE0,// 006E000045014545 6E + /* 24 */ 0x02,0x0E,0x0E,0xFC,0xF7,0xFF,0x12,0xE0,// 0402000045014545 04 + /* 25 */ 0x05,0x0D,0x0E,0xFA,0xF7,0xFF,0x12,0xE0,// 0602000045014545 06 + /* 26 */ 0x06,0x0F,0x0D,0xF9,0xF7,0xFF,0x12,0xE0,// 0703000045014545 07 + /* 27 */ 0x00,0x01,0x05,0x1D,0xF7,0xFF,0x12,0xE0,// 630B000045014545 0B + /* 28 */ 0x02,0x07,0x01,0x1D,0xF7,0xFF,0x12,0xE0,// 630F000045014545 0F + /* 29 */ 0x04,0x7F,0x7F,0xA7,0xF7,0xFF,0x12,0xE0,// 5911000045014545 11 + /* 30 */ 0x04,0x60,0x6E,0xE8,0xF7,0xFF,0x12,0xE0,// 1822000045014545 18 + }; + memcpy(c.d.asBytes, csns, sizeof(c.d.asBytes)); + + } + SendCommand(&c); /*UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500);