user jwesthues, at host cq.cx
May 2007, Cambridge MA
-
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:
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);
#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;
} 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,
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
LED_A_ON();
- for(;;) {
+ for(int i=0;i<1;i++) {
if(traceLen > TRACE_SIZE) {
DbpString("Trace full");
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();
-}
-
-
+}*/
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)))
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
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 \
cmdhfmf.c \
cmdhw.c \
cmdlf.c \
- cmdlfhid.c \
cmdlfio.c \
+ cmdlfhid.c \
cmdlfem4x.c \
cmdlfhitag.c \
cmdlfti.c \
//-----------------------------------------------------------------------------
// 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)
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;
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] = "";
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};
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}
};
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;
-}
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
--- /dev/null
+/*****************************************************************************
+ * 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;
+}
--- /dev/null
+/*****************************************************************************
+ * 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
--- /dev/null
+/*****************************************************************************
+ * 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;
+}
--- /dev/null
+/*****************************************************************************
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/**
+ * \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 */
--- /dev/null
+#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;
+
+}
+
--- /dev/null
+#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
--- /dev/null
+#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");
+}
--- /dev/null
+#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
--- /dev/null
+/*****************************************************************************
+ * 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!");
+ }
+
+}
+
+*/
+
+
--- /dev/null
+#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
--- /dev/null
+/*****************************************************************************
+ * 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;
+}
+
#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
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);
+}
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
#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
#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 */