]> cvs.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 --cc 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
Simple merge
diff --cc armsrc/apps.h
index 1ef0e472969d8d63fd255305f603762ef664cf26,237c52917685627795ff20e12b600f0b412b1e58..011ad6953b27796587ad3d62750a037c499898ba
@@@ -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 --cc armsrc/iclass.c
Simple merge
diff --cc client/Makefile
index e4a3580b8814ee0b33da32693f59abea3b073413,c47e8526e69c79d459c2bda02763d4bd80cfa913..05ffc66710657df664a3ec71b8dd7db1e5fa1eec
@@@ -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 \
index b8e1e0989f62abc5bca9d409f2fe53b43500c83e,e68fdc4f1b0bc89a398e90554840865c69b3b4f4..91b5d8980f40dfed3d4ee66ddecd302842a3cd5f
  #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);
@@@ -319,80 -184,16 +321,81 @@@ int CmdHFiClassSim(const char *Cmd
    }   
  
    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}
  };
  
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;
+ }
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
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!");
++      }
++
++}
++
++*/
++
++
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
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
Simple merge
Impressum, Datenschutz