X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/ff7bb4ef177ba1c680dd9af5a1e30d4f7f29c65f..16a372ab75c10b0ffb3786adc4029cd1df2f6066:/armsrc/iclass.c diff --git a/armsrc/iclass.c b/armsrc/iclass.c index bfa4a730..4d005dbc 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -41,10 +41,12 @@ #include "util.h" #include "string.h" #include "common.h" +#include "cmd.h" // Needed for CRC in emulation mode; // same construction as in ISO 14443; // different initial value (CRC_ICLASS) #include "iso14443crc.h" +#include "iso15693tools.h" static int timeout = 4096; @@ -986,71 +988,32 @@ static void CodeIClassTagSOF() ToSendMax++; } -/** - * @brief SimulateIClass simulates an iClass card. - * @param arg0 type of simulation - * - 0 uses the first 8 bytes in usb data as CSN - * - 2 "dismantling iclass"-attack. This mode iterates through all CSN's specified - * in the usb data. This mode collects MAC from the reader, in order to do an offline - * attack on the keys. For more info, see "dismantling iclass" and proxclone.com. - * - Other : Uses the default CSN (031fec8af7ff12e0) - * @param arg1 - number of CSN's contained in datain (applicable for mode 2 only) - * @param arg2 - * @param datain - */ -void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) +//----------------------------------------------------------------------------- +// Simulate iClass Card +// Only CSN (Card Serial Number) +// +//----------------------------------------------------------------------------- +void SimulateIClass(uint8_t arg0, uint8_t *datain) { - uint32_t simType = arg0; - uint32_t numberOfCSNS = arg1; - - // Enable and clear the trace - iso14a_set_tracing(TRUE); - iso14a_clear_trace(); - - uint8_t csn_crc[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 }; + uint8_t simType = arg0; - if(simType == 0) { - // Use the CSN from commandline - memcpy(csn_crc, datain, 8); - doIClassSimulation(csn_crc,0); - }else if(simType == 1) - { - doIClassSimulation(csn_crc,0); - } - else if(simType == 2) - { - // 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. - for(int i = 0 ; i < numberOfCSNS && i*8+8 < USB_CMD_DATA_SIZE; i++) - { - // The usb data is 512 bytes, fitting 65 8-byte CSNs in there. - - memcpy(csn_crc, datain+(i*8), 8); - doIClassSimulation(csn_crc,1); - } - }else{ - // We may want a mode here where we hardcode the csns to use (from proxclone). - // That will speed things up a little, but not required just yet. - Dbprintf("The mode is not implemented, reserved for future use"); - } + // Enable and clear the trace + tracing = TRUE; + traceLen = 0; + memset(trace, 0x44, TRACE_SIZE); -} -/** - * @brief Does the actual simulation - * @param csn - csn to use - * @param breakAfterMacReceived if true, returns after reader MAC has been received. - */ -void doIClassSimulation(uint8_t csn[], int breakAfterMacReceived) -{ // CSN followed by two CRC bytes 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)); + uint8_t response3[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 }; // e-Purse uint8_t response4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + if(simType == 0) { + // Use the CSN from commandline + memcpy(response3, datain, 8); + } + // Construct anticollision-CSN rotateCSN(response3,response2); @@ -1058,7 +1021,6 @@ void doIClassSimulation(uint8_t csn[], int breakAfterMacReceived) ComputeCrc14443(CRC_ICLASS, response2, 8, &response2[8], &response2[9]); ComputeCrc14443(CRC_ICLASS, response3, 8, &response3[8], &response3[9]); - int exitLoop = 0; // Reader 0a // Tag 0f // Reader 0c @@ -1092,7 +1054,7 @@ void doIClassSimulation(uint8_t csn[], int breakAfterMacReceived) int resp4Len; // + 1720.. - uint8_t *receivedCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); + uint8_t *receivedCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); memset(receivedCmd, 0x44, RECV_CMD_SIZE); int len; @@ -1123,7 +1085,7 @@ void doIClassSimulation(uint8_t csn[], int breakAfterMacReceived) int cmdsRecvd = 0; LED_A_ON(); - while(!exitLoop) { + for(;;) { LED_B_OFF(); if(!GetIClassCommandFromReader(receivedCmd, &len, 100)) { DbpString("button press"); @@ -1159,21 +1121,24 @@ void doIClassSimulation(uint8_t csn[], int breakAfterMacReceived) LED_B_ON(); } else if(receivedCmd[0] == 0x05) { // Reader random and reader MAC!!! + // Lets store this ;-) +/* + Dbprintf(" CSN: %02x %02x %02x %02x %02x %02x %02x %02x", + response3[0], response3[1], response3[2], + response3[3], response3[4], response3[5], + response3[6], response3[7]); +*/ + Dbprintf("READER AUTH (len=%02d): %02x %02x %02x %02x %02x %02x %02x %02x %02x", + len, + receivedCmd[0], receivedCmd[1], receivedCmd[2], + receivedCmd[3], receivedCmd[4], receivedCmd[5], + receivedCmd[6], receivedCmd[7], receivedCmd[8]); + // Do not respond // We do not know what to answer, so lets keep quit resp = resp1; respLen = 0; //order = 5; respdata = NULL; respsize = 0; - if (breakAfterMacReceived){ - // TODO, actually return this to the caller instead of just - // dbprintf:ing ... - Dbprintf("CSN: %02x %02x %02x %02x %02x %02x %02x %02x"); - Dbprintf("RDR: (len=%02d): %02x %02x %02x %02x %02x %02x %02x %02x %02x",len, - receivedCmd[0], receivedCmd[1], receivedCmd[2], - receivedCmd[3], receivedCmd[4], receivedCmd[5], - receivedCmd[6], receivedCmd[7], receivedCmd[8]); - exitLoop = true; - } } else if(receivedCmd[0] == 0x00 && len == 1) { // Reader ends the session resp = resp1; respLen = 0; //order = 0; @@ -1214,6 +1179,7 @@ void doIClassSimulation(uint8_t csn[], int breakAfterMacReceived) break; } } + memset(receivedCmd, 0x44, RECV_CMD_SIZE); } @@ -1458,7 +1424,7 @@ void ReaderIClass(uint8_t arg0) { uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes // Reset trace buffer - memset(trace, 0x44, RECV_CMD_OFFSET); + memset(trace, 0x44, RECV_CMD_OFFSET); traceLen = 0; // Setup SSC @@ -1512,4 +1478,245 @@ void ReaderIClass(uint8_t arg0) { LED_A_OFF(); } +void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { + uint8_t act_all[] = { 0x0a }; + uint8_t identify[] = { 0x0c }; + uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t readcheck_cc[]= { 0x88, 0x02 }; + uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 }; + + uint16_t crc = 0; + uint8_t cardsize=0; + bool read_success=false; + uint8_t mem=0; + + static struct memory_t{ + int k16; + int book; + int k2; + int lockauth; + int keyaccess; + } memory; + + uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes + + // Reset trace buffer + memset(trace, 0x44, RECV_CMD_OFFSET); + traceLen = 0; + + // Setup SSC + FpgaSetupSsc(); + // Start from off (no field generated) + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // Now give it time to spin up. + // Signal field is on with the appropriate LED + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + SpinDelay(200); + + LED_A_ON(); + + for(int i=0;i<1;i++) { + + if(traceLen > TRACE_SIZE) { + DbpString("Trace full"); + break; + } + + if (BUTTON_PRESS()) break; + + // Send act_all + ReaderTransmitIClass(act_all, 1); + // Card present? + if(ReaderReceiveIClass(resp)) { + ReaderTransmitIClass(identify, 1); + if(ReaderReceiveIClass(resp) == 10) { + // Select card + memcpy(&select[1],resp,8); + ReaderTransmitIClass(select, sizeof(select)); + + if(ReaderReceiveIClass(resp) == 10) { + Dbprintf(" Selected CSN: %02x %02x %02x %02x %02x %02x %02x %02x", + resp[0], resp[1], resp[2], + resp[3], resp[4], resp[5], + resp[6], resp[7]); + } + // Card selected + Dbprintf("Readcheck on Sector 2"); + ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); + if(ReaderReceiveIClass(resp) == 8) { + Dbprintf(" CC: %02x %02x %02x %02x %02x %02x %02x %02x", + resp[0], resp[1], resp[2], + resp[3], resp[4], resp[5], + resp[6], resp[7]); + }else return; + Dbprintf("Authenticate"); + //for now replay captured auth (as cc not updated) + memcpy(check+5,MAC,4); + Dbprintf(" AA: %02x %02x %02x %02x", + check[5], check[6], check[7],check[8]); + ReaderTransmitIClass(check, sizeof(check)); + if(ReaderReceiveIClass(resp) == 4) { + Dbprintf(" AR: %02x %02x %02x %02x", + resp[0], resp[1], resp[2],resp[3]); + }else { + Dbprintf("Error: Authentication Fail!"); + return; + } + Dbprintf("Dump Contents"); + //first get configuration block + read_success=false; + read[1]=1; + uint8_t *blockno=&read[1]; + crc = iclass_crc16((char *)blockno,1); + read[2] = crc >> 8; + read[3] = crc & 0xff; + while(!read_success){ + ReaderTransmitIClass(read, sizeof(read)); + if(ReaderReceiveIClass(resp) == 10) { + read_success=true; + mem=resp[5]; + memory.k16= (mem & 0x80); + memory.book= (mem & 0x20); + memory.k2= (mem & 0x8); + memory.lockauth= (mem & 0x2); + memory.keyaccess= (mem & 0x1); + + } + } + if (memory.k16){ + cardsize=255; + }else cardsize=32; + //then loop around remaining blocks + for(uint8_t j=0; j> 8; + read[3] = crc & 0xff; + while(!read_success){ + ReaderTransmitIClass(read, sizeof(read)); + if(ReaderReceiveIClass(resp) == 10) { + read_success=true; + Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x", + j, resp[0], resp[1], resp[2], + resp[3], resp[4], resp[5], + resp[6], resp[7]); + } + } + } + } + } + WDT_HIT(); + } + + LED_A_OFF(); +} + +//1. Create Method to Read sectors/blocks 0,1,2 and Send to client +void IClass_iso14443A_GetPublic(uint8_t arg0) { + uint8_t act_all[] = { 0x0a }; + uint8_t identify[] = { 0x0c }; + uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t readcheck_cc[]= { 0x88, 0x02 }; + //uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 }; + uint8_t card_data[24]={0}; + + //bool read_success=false; + uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes + + // Reset trace buffer + memset(trace, 0x44, RECV_CMD_OFFSET); + traceLen = 0; + + // Setup SSC + FpgaSetupSsc(); + // Start from off (no field generated) + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // Now give it time to spin up. + // Signal field is on with the appropriate LED + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + SpinDelay(200); + + LED_A_ON(); + + for(int i=0;i<1;i++) { + + if(traceLen > TRACE_SIZE) { + DbpString("Trace full"); + break; + } + + if (BUTTON_PRESS()) break; + + // Send act_all + ReaderTransmitIClass(act_all, 1); + // Card present? + if(ReaderReceiveIClass(resp)) { + ReaderTransmitIClass(identify, 1); + if(ReaderReceiveIClass(resp) == 10) { + // Select card + memcpy(&select[1],resp,8); + ReaderTransmitIClass(select, sizeof(select)); + + if(ReaderReceiveIClass(resp) == 10) { + Dbprintf(" Selected CSN: %02x %02x %02x %02x %02x %02x %02x %02x", + resp[0], resp[1], resp[2], + resp[3], resp[4], resp[5], + resp[6], resp[7]); + } + memcpy(card_data,resp,8); + // Card selected + Dbprintf("Readcheck on Sector 2"); + ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); + if(ReaderReceiveIClass(resp) == 8) { + Dbprintf(" CC: %02x %02x %02x %02x %02x %02x %02x %02x", + resp[0], resp[1], resp[2], + resp[3], resp[4], resp[5], + resp[6], resp[7]); + } + memcpy(card_data+8,resp,8); + //prep to read config block + /* read card configuration block + while(!read_success){ + uint8_t sector_config=0x01; + memcpy(read+1,§or_config,1); + ReaderTransmitIClass(read, sizeof(read)); + if(ReaderReceiveIClass(resp) == 8) { + Dbprintf(" CC: %02x %02x %02x %02x %02x %02x %02x %02x", + resp[0], resp[1], resp[2], + resp[3], resp[4], resp[5], + resp[6], resp[7]); + read_success=true; + memcpy(card_data+16,resp,8); + } + }*/ + } + } + WDT_HIT(); + } + //Dbprintf("DEBUG: %02x%02x%02x%02x%02x%02x%02x%02x",card_data[0],card_data[1],card_data[2],card_data[3],card_data[4],card_data[5],card_data[6],card_data[7]); + //Dbprintf("DEBUG: %02x%02x%02x%02x%02x%02x%02x%02x",card_data[8],card_data[9],card_data[10],card_data[11],card_data[12],card_data[13],card_data[14],card_data[15]); + LED_A_OFF(); + LED_B_ON(); + //send data back to the client + cmd_send(CMD_ACK,0,0,0,card_data,16); + LED_B_OFF(); +} + +//TODO: Create Write method