First check in.

This commit is contained in:
iceman1001
2014-09-11 23:23:46 +02:00
parent 4a79e52c0b
commit f38a152863
103 changed files with 10544 additions and 508 deletions

View File

@@ -13,23 +13,16 @@ CXX=g++
VPATH = ../common
OBJDIR = obj
LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread ../liblua/liblua.a
LDLIBS = -L/mingw/lib -L/opt/local/lib -L/usr/local/lib ../liblua/liblua.a -lreadline -lpthread -lcrypto -lgdi32
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 -I. -I../include -I../common -I/mingw/include -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 $(ICE_FLAGS)
LUAPLATFORM = generic
ifneq (,$(findstring MINGW,$(platform)))
CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui
QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4
CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui -I$(QTDIR)/include/QtWidgets
QTLDLIBS = -L$(QTDIR)/lib -lQt5Core -lQt5Gui -lQt5Widgets
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
LUAPLATFORM = macosx
else
CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O4
QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null)
@@ -58,6 +51,12 @@ CORESRCS = uart.c \
CMDSRCS = nonce2key/crapto1.c\
nonce2key/crypto1.c\
nonce2key/nonce2key.c\
loclass/cipher.c \
loclass/cipherutils.c \
loclass/des.c \
loclass/ikeys.c \
loclass/elite_crack.c\
loclass/fileutils.c\
mifarehost.c\
crc16.c \
iso14443crc.c \
@@ -74,6 +73,9 @@ CMDSRCS = nonce2key/crapto1.c\
cmdhflegic.c \
cmdhficlass.c \
cmdhfmf.c \
cmdhfmfu.c \
cmdhfmfdes.c \
cmdhfdes.c \
cmdhw.c \
cmdlf.c \
cmdlfhid.c \

View File

@@ -22,6 +22,9 @@
#include "cmdhflegic.h"
#include "cmdhficlass.h"
#include "cmdhfmf.h"
#include "cmdhfmfu.h"
#include "cmdhfmfdes.h"
#include "cmdhfdes.h"
static int CmdHelp(const char *Cmd);
@@ -42,6 +45,9 @@ static command_t CommandTable[] =
{"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"},
{"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"},
{"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"},
{"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"},
{"mfdes", CmdHFMFDes, 1, "{ MIFARE Desfire RFIDs... }"},
{"des", CmdHFDES, 0, "{ MIFARE DESfire}"},
{"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"},
{NULL, NULL, 0, NULL}
};

View File

@@ -14,15 +14,15 @@
#include <string.h>
#include <unistd.h>
#include "util.h"
#include "iso14443crc.h"
#include "../common/iso14443crc.h"
#include "data.h"
#include "proxmark3.h"
#include "ui.h"
#include "cmdparser.h"
#include "cmdhf14a.h"
#include "common.h"
#include "../include/common.h"
#include "cmdmain.h"
#include "mifare.h"
#include "../include/mifare.h"
static int CmdHelp(const char *Cmd);
static void waitCmd(uint8_t iLen);
@@ -183,27 +183,24 @@ void iso14a_set_timeout(uint32_t timeout) {
int CmdHF14AReader(const char *Cmd)
{
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}};
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}};
SendCommand(&c);
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
iso14a_card_select_t card;
memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t));
iso14a_card_select_t *card = (iso14a_card_select_t *)resp.d.asBytes;
uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS
if(select_status == 0) {
if(resp.arg[0] == 0) {
PrintAndLog("iso14443a card select failed");
return 0;
}
PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen));
PrintAndLog(" SAK : %02x [%d]", card.sak, resp.arg[0]);
PrintAndLog("ATQA : %02x %02x", card->atqa[0], card->atqa[1]);
PrintAndLog(" UID : %s", sprint_hex(card->uid, card->uidlen));
PrintAndLog(" SAK : %02x [%d]", card->sak, resp.arg[0]);
switch (card.sak) {
switch (card->sak) {
case 0x00: PrintAndLog("TYPE : NXP MIFARE Ultralight | Ultralight C"); break;
case 0x04: PrintAndLog("TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); break;
case 0x08: PrintAndLog("TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1"); break;
@@ -219,107 +216,67 @@ int CmdHF14AReader(const char *Cmd)
case 0x98: PrintAndLog("TYPE : Gemplus MPCOS"); break;
default: ;
}
// try to request ATS even if tag claims not to support it
if (select_status == 2) {
uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
c.arg[0] = ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT;
c.arg[1] = 2;
c.arg[2] = 0;
memcpy(c.d.asBytes, rats, 2);
SendCommand(&c);
WaitForResponse(CMD_ACK,&resp);
memcpy(&card.ats, resp.d.asBytes, resp.arg[0]);
card.ats_len = resp.arg[0]; // note: ats_len includes CRC Bytes
}
// disconnect
c.arg[0] = 0;
c.arg[1] = 0;
c.arg[2] = 0;
SendCommand(&c);
if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
if(resp.arg[0] == 1) {
bool ta1 = 0, tb1 = 0, tc1 = 0;
int pos;
if (select_status == 2) {
PrintAndLog("SAK incorrectly claims that card doesn't support RATS");
PrintAndLog(" ATS : %s", sprint_hex(card->ats, card->ats_len));
if (card->ats_len > 0) {
PrintAndLog(" - TL : length is %d bytes", card->ats[0]);
}
PrintAndLog(" ATS : %s", sprint_hex(card.ats, card.ats_len));
PrintAndLog(" - TL : length is %d bytes", card.ats[0]);
if (card.ats[0] != card.ats_len - 2) {
PrintAndLog("ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len);
}
if (card.ats[0] > 1) { // there is a format byte (T0)
ta1 = (card.ats[1] & 0x10) == 0x10;
tb1 = (card.ats[1] & 0x20) == 0x20;
tc1 = (card.ats[1] & 0x40) == 0x40;
int16_t fsci = card.ats[1] & 0x0f;
if (card->ats_len > 1) {
ta1 = (card->ats[1] & 0x10) == 0x10;
tb1 = (card->ats[1] & 0x20) == 0x20;
tc1 = (card->ats[1] & 0x40) == 0x40;
PrintAndLog(" - T0 : TA1 is%s present, TB1 is%s present, "
"TC1 is%s present, FSCI is %d (FSC = %ld)",
"TC1 is%s present, FSCI is %d",
(ta1 ? "" : " NOT"), (tb1 ? "" : " NOT"), (tc1 ? "" : " NOT"),
fsci,
fsci < 5 ? (fsci - 2) * 8 :
fsci < 8 ? (fsci - 3) * 32 :
fsci == 8 ? 256 :
-1
);
(card->ats[1] & 0x0f));
}
pos = 2;
if (ta1) {
if (ta1 && card->ats_len > pos) {
char dr[16], ds[16];
dr[0] = ds[0] = '\0';
if (card.ats[pos] & 0x10) strcat(ds, "2, ");
if (card.ats[pos] & 0x20) strcat(ds, "4, ");
if (card.ats[pos] & 0x40) strcat(ds, "8, ");
if (card.ats[pos] & 0x01) strcat(dr, "2, ");
if (card.ats[pos] & 0x02) strcat(dr, "4, ");
if (card.ats[pos] & 0x04) strcat(dr, "8, ");
if (card->ats[pos] & 0x10) strcat(ds, "2, ");
if (card->ats[pos] & 0x20) strcat(ds, "4, ");
if (card->ats[pos] & 0x40) strcat(ds, "8, ");
if (card->ats[pos] & 0x01) strcat(dr, "2, ");
if (card->ats[pos] & 0x02) strcat(dr, "4, ");
if (card->ats[pos] & 0x04) strcat(dr, "8, ");
if (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0';
if (strlen(dr) != 0) dr[strlen(dr) - 2] = '\0';
PrintAndLog(" - TA1 : different divisors are%s supported, "
"DR: [%s], DS: [%s]",
(card.ats[pos] & 0x80 ? " NOT" : ""), dr, ds);
(card->ats[pos] & 0x80 ? " NOT" : ""), dr, ds);
pos++;
}
if (tb1) {
uint32_t sfgi = card.ats[pos] & 0x0F;
uint32_t fwi = card.ats[pos] >> 4;
PrintAndLog(" - TB1 : SFGI = %d (SFGT = %s%ld/fc), FWI = %d (FWT = %ld/fc)",
(sfgi),
sfgi ? "" : "(not needed) ",
sfgi ? (1 << 12) << sfgi : 0,
fwi,
(1 << 12) << fwi
);
if (tb1 && card->ats_len > pos) {
PrintAndLog(" - TB1 : SFGI = %d, FWI = %d",
(card->ats[pos] & 0x08),
(card->ats[pos] & 0x80) >> 4);
pos++;
}
if (tc1) {
if (tc1 && card->ats_len > pos) {
PrintAndLog(" - TC1 : NAD is%s supported, CID is%s supported",
(card.ats[pos] & 0x01) ? "" : " NOT",
(card.ats[pos] & 0x02) ? "" : " NOT");
(card->ats[pos] & 0x01) ? "" : " NOT",
(card->ats[pos] & 0x02) ? "" : " NOT");
pos++;
}
if (card.ats[0] > pos) {
if (card->ats_len > pos) {
char *tip = "";
if (card.ats[0] - pos >= 7) {
if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
if (card->ats_len - pos > 7) {
if (memcmp(card->ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
tip = "-> MIFARE Plus X 2K or 4K";
} else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
} else if (memcmp(card->ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
tip = "-> MIFARE Plus S 2K or 4K";
}
}
PrintAndLog(" - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip);
if (card.ats[pos] == 0xC1) {
PrintAndLog(" - HB : %s%s", sprint_hex(card->ats + pos, card->ats_len - pos - 2), tip);
if (card->ats[pos] == 0xC1) {
PrintAndLog(" c1 -> Mifare or (multiple) virtual cards of various type");
PrintAndLog(" %02x -> Length is %d bytes",
card.ats[pos + 1], card.ats[pos + 1]);
switch (card.ats[pos + 2] & 0xf0) {
card->ats[pos + 1], card->ats[pos + 1]);
switch (card->ats[pos + 2] & 0xf0) {
case 0x10:
PrintAndLog(" 1x -> MIFARE DESFire");
break;
@@ -327,7 +284,7 @@ int CmdHF14AReader(const char *Cmd)
PrintAndLog(" 2x -> MIFARE Plus");
break;
}
switch (card.ats[pos + 2] & 0x0f) {
switch (card->ats[pos + 2] & 0x0f) {
case 0x00:
PrintAndLog(" x0 -> <1 kByte");
break;
@@ -344,7 +301,7 @@ int CmdHF14AReader(const char *Cmd)
PrintAndLog(" x0 -> 8 kByte");
break;
}
switch (card.ats[pos + 3] & 0xf0) {
switch (card->ats[pos + 3] & 0xf0) {
case 0x00:
PrintAndLog(" 0x -> Engineering sample");
break;
@@ -352,7 +309,7 @@ int CmdHF14AReader(const char *Cmd)
PrintAndLog(" 2x -> Released");
break;
}
switch (card.ats[pos + 3] & 0x0f) {
switch (card->ats[pos + 3] & 0x0f) {
case 0x00:
PrintAndLog(" x0 -> Generation 1");
break;
@@ -363,7 +320,7 @@ int CmdHF14AReader(const char *Cmd)
PrintAndLog(" x2 -> Generation 3");
break;
}
switch (card.ats[pos + 4] & 0x0f) {
switch (card->ats[pos + 4] & 0x0f) {
case 0x00:
PrintAndLog(" x0 -> Only VCSL supported");
break;
@@ -377,10 +334,10 @@ int CmdHF14AReader(const char *Cmd)
}
}
} else {
PrintAndLog("proprietary non iso14443-4 card found, RATS not supported");
PrintAndLog("proprietary non iso14443a-4 card found, RATS not supported");
}
return select_status;
return resp.arg[0];
}
// Collect ISO14443 Type A UIDs
@@ -402,17 +359,20 @@ int CmdHF14ACUIDs(const char *Cmd)
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
iso14a_card_select_t *card = (iso14a_card_select_t *) resp.d.asBytes;
uint8_t *uid = resp.d.asBytes;
iso14a_card_select_t *card = (iso14a_card_select_t *)(uid + 12);
// check if command failed
if (resp.arg[0] == 0) {
PrintAndLog("Card select failed.");
} else {
char uid_string[20];
for (uint16_t i = 0; i < card->uidlen; i++) {
sprintf(&uid_string[2*i], "%02X", card->uid[i]);
// check if UID is 4 bytes
if ((card->atqa[1] & 0xC0) == 0) {
PrintAndLog("%02X%02X%02X%02X",
*uid, *(uid + 1), *(uid + 2), *(uid + 3));
} else {
PrintAndLog("UID longer than 4 bytes");
}
PrintAndLog("%s", uid_string);
}
}
PrintAndLog("End: %u", time(NULL));
@@ -466,10 +426,6 @@ int CmdHF14ASim(const char *Cmd)
// At lease save the mandatory first part of the UID
c.arg[0] = long_uid & 0xffffffff;
// At lease save the mandatory first part of the UID
c.arg[0] = long_uid & 0xffffffff;
if (c.arg[1] == 0) {
PrintAndLog("Emulating ISO/IEC 14443 type A tag with UID %01d %08x %08x",c.arg[0],c.arg[1],c.arg[2]);
}
@@ -537,19 +493,22 @@ int CmdHF14ACmdRaw(const char *cmd) {
uint8_t active=0;
uint8_t active_select=0;
uint16_t numbits=0;
uint16_t timeout=0;
uint8_t bTimeout=0;
char buf[5]="";
int i=0;
uint8_t data[100];
uint8_t data[USB_CMD_DATA_SIZE];
unsigned int datalen=0, temp;
if (strlen(cmd)<2) {
PrintAndLog("Usage: hf 14a raw [-r] [-c] [-p] [-f] [-b] <number of bits> <0A 0B 0C ... hex>");
PrintAndLog("Usage: hf 14a raw [-r] [-c] [-p] [-f] [-b] [-t] <number of bits> <0A 0B 0C ... hex>");
PrintAndLog(" -r do not read response");
PrintAndLog(" -c calculate and append CRC");
PrintAndLog(" -p leave the signal field ON after receive");
PrintAndLog(" -a active signal field ON without select");
PrintAndLog(" -s active signal field ON with select");
PrintAndLog(" -b number of bits to send. Useful for send partial byte");
PrintAndLog(" -t timeout");
return 0;
}
@@ -582,6 +541,14 @@ int CmdHF14ACmdRaw(const char *cmd) {
while(cmd[i]!=' ' && cmd[i]!='\0') { i++; }
i-=2;
break;
case 't':
bTimeout=1;
sscanf(cmd+i+2,"%d",&temp);
timeout = temp & 0xFFFF;
i+=3;
while(cmd[i]!=' ' && cmd[i]!='\0') { i++; }
i+=2;
break;
default:
PrintAndLog("Invalid option");
return 0;
@@ -599,15 +566,19 @@ int CmdHF14ACmdRaw(const char *cmd) {
if (strlen(buf)>=2) {
sscanf(buf,"%x",&temp);
data[datalen]=(uint8_t)(temp & 0xff);
datalen++;
*buf=0;
if (++datalen>sizeof(data)){
if (crc)
PrintAndLog("Buffer is full, we can't add CRC to your data");
break;
}
}
continue;
}
PrintAndLog("Invalid char on input");
return 0;
}
if(crc && datalen>0)
if(crc && datalen>0 && datalen<sizeof(data)-2)
{
uint8_t first, second;
ComputeCrc14443(CRC_14443_A, data, datalen, &first, &second);
@@ -621,13 +592,22 @@ int CmdHF14ACmdRaw(const char *cmd) {
if(active)
c.arg[0] |= ISO14A_NO_SELECT;
}
if(bTimeout){
#define MAX_TIMEOUT 624*105 // max timeout is 624 ms
c.arg[0] |= ISO14A_SET_TIMEOUT;
c.arg[2] = timeout * 105; // each bit is about 9.4 us
if(c.arg[2]>MAX_TIMEOUT) {
c.arg[2] = MAX_TIMEOUT;
PrintAndLog("Set timeout to 624 ms. The max we can wait for response");
}
}
if(power)
c.arg[0] |= ISO14A_NO_DISCONNECT;
if(datalen>0)
c.arg[0] |= ISO14A_RAW;
c.arg[1] = datalen;
c.arg[2] = numbits;
// Max buffer is USB_CMD_DATA_SIZE
c.arg[1] = (datalen & 0xFFFF) | (numbits << 16);
memcpy(c.d.asBytes,data,datalen);
SendCommand(&c);

View File

@@ -13,8 +13,7 @@
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include "iso14443crc.h"
//#include "proxusb.h"
#include "../common/iso14443crc.h"
#include "proxmark3.h"
#include "data.h"
#include "graph.h"

View File

@@ -33,7 +33,7 @@
#include "ui.h"
#include "cmdparser.h"
#include "cmdhf15.h"
#include "iso15693tools.h"
#include "../common/iso15693tools.h"
#include "cmdmain.h"
#define FrameSOF Iso15693FrameSOF

69
client/cmdhfdes.c Normal file
View File

@@ -0,0 +1,69 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2012 nuit
//
// 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
// the license.
//-----------------------------------------------------------------------------
// High frequency MIFARE DESfire commands
//-----------------------------------------------------------------------------
#include "cmdhfdes.h"
#include "proxmark3.h"
#include "cmdmain.h"
static int CmdHelp(const char *Cmd);
int CmdHFDESReader(const char *Cmd)
{
UsbCommand c ={CMD_MIFARE_DES_READER, {3, 0x60, 0}};
SendCommand(&c);
UsbCommand resp;
WaitForResponseTimeout(CMD_ACK,&resp,2000);
return 0;
}
int CmdHFDESDbg(const char *Cmd)
{
int dbgMode = param_get32ex(Cmd, 0, 0, 10);
if (dbgMode > 4) {
PrintAndLog("Max debud mode parameter is 4 \n");
}
if (strlen(Cmd) < 1 || !param_getchar(Cmd, 0) || dbgMode > 4) {
PrintAndLog("Usage: hf des dbg <debug level>");
PrintAndLog(" 0 - no debug messages");
PrintAndLog(" 1 - error messages");
PrintAndLog(" 2 - all messages");
PrintAndLog(" 4 - extended debug mode");
return 0;
}
UsbCommand c = {CMD_MIFARE_SET_DBGMODE, {dbgMode, 0, 0}};
SendCommand(&c);
return 0;
}
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"dbg", CmdHFDESDbg, 0, "Set default debug mode"},
{"reader", CmdHFDESReader, 0, "Reader"},
{NULL, NULL, 0, NULL}
};
int CmdHFDES(const char *Cmd)
{
//flush
WaitForResponseTimeout(CMD_ACK,NULL,100);
CmdsParse(CommandTable, Cmd);
return 0;
}
int CmdHelp(const char *Cmd)
{
CmdsHelp(CommandTable);
return 0;
}

27
client/cmdhfdes.h Normal file
View File

@@ -0,0 +1,27 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2012 nuit
//
// 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
// the license.
//-----------------------------------------------------------------------------
// High frequency MIFARE DESfire commands
//-----------------------------------------------------------------------------
#ifndef CMDHFDES_H__
#define CMDHFDES_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "proxmark3.h"
#include "data.h"
#include "ui.h"
#include "cmdparser.h"
#include "common.h"
#include "util.h"
int CmdHFDES(const char *Cmd);
int CmdHFDESReader(const char *Cmd);
int CmdHFDESDbg(const char *Cmd);
#endif

View File

@@ -13,7 +13,7 @@
#include "proxmark3.h"
#include "ui.h"
#include "cmdparser.h"
#include "common.h"
#include "../include/common.h"
#include "cmdmain.h"
#include "sleep.h"
#include "cmdhfepa.h"

View File

@@ -1,6 +1,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch
// Copyright (C) 2011 Gerhard de Koning Gans
// Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
@@ -15,14 +16,19 @@
#include <sys/stat.h>
#include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type
#include "data.h"
//#include "proxusb.h"
#include "proxmark3.h"
#include "ui.h"
#include "cmdparser.h"
#include "cmdhficlass.h"
#include "common.h"
#include "../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);
@@ -290,11 +296,6 @@ int CmdHFiClassListOld(const char *Cmd)
return 0;
}
/*void iso14a_set_timeout(uint32_t timeout) {
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_SET_TIMEOUT, 0, timeout}};
SendCommand(&c);
}*/
int CmdHFiClassSnoop(const char *Cmd)
{
UsbCommand c = {CMD_SNOOP_ICLASS};
@@ -393,37 +394,255 @@ int CmdHFiClassSim(const char *Cmd)
memcpy(c.d.asBytes, CSN, 8);
SendCommand(&c);
}
return 0;
}
int CmdHFiClassReader(const char *Cmd)
{
uint8_t readerType = 0;
if (strlen(Cmd)<1) {
PrintAndLog("Usage: hf iclass reader <reader type>");
PrintAndLog(" sample: hf iclass reader 0");
return 0;
}
readerType = param_get8(Cmd, 0);
PrintAndLog("--readertype:%02x", readerType);
UsbCommand c = {CMD_READER_ICLASS, {readerType}};
//memcpy(c.d.asBytes, CSN, 8);
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;
/*UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500);
if (resp != NULL) {
uint8_t isOK = resp->arg[0] & 0xff;
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
}*/
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 replay <MAC>");
PrintAndLog(" sample: hf iclass replay 00112233");
return 0;
}
if (param_gethex(Cmd, 0, MAC, 8)) {
PrintAndLog("MAC must include 8 HEX symbols");
return 1;
}
UsbCommand c = {CMD_READER_ICLASS_REPLAY, {readerType}};
memcpy(c.d.asBytes, MAC, 4);
SendCommand(&c);
return 0;
}
int CmdHFiClassReader_Dump(const char *Cmd)
{
uint8_t readerType = 0;
uint8_t MAC[4]={0x00,0x00,0x00,0x00};
uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t CSN[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t CCNR[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
//uint8_t CC_temp[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t 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"},
@@ -431,6 +650,9 @@ static command_t CommandTable[] =
{"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}
};
@@ -443,55 +665,5 @@ int CmdHFiClass(const char *Cmd)
int CmdHelp(const char *Cmd)
{
CmdsHelp(CommandTable);
return 0;
}
/**
* @brief checks if a file exists
* @param filename
* @return
*/
int fileExists(const char *filename) {
struct stat st;
int result = stat(filename, &st);
return result == 0;
}
/**
* @brief Utility function to save data to a file. This method takes a preferred name, but if that
* file already exists, it tries with another name until it finds something suitable.
* E.g. dumpdata-15.txt
* @param preferredName
* @param suffix the file suffix. Leave out the ".".
* @param data The binary data to write to the file
* @param datalen the length of the data
* @return 0 for ok, 1 for failz
*/
int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen)
{
FILE *f = fopen(preferredName, "wb");
int size = sizeof(char) * (strlen(preferredName)+strlen(suffix)+5);
char * fileName = malloc(size);
memset(fileName,0,size);
int num = 1;
sprintf(fileName,"%s.%s", preferredName, suffix);
while(fileExists(fileName))
{
sprintf(fileName,"%s-%d.%s", preferredName, num, suffix);
num++;
}
/* We should have a valid filename now, e.g. dumpdata-3.bin */
/*Opening file for writing in binary mode*/
FILE *fileHandle=fopen(fileName,"wb");
if(!f) {
PrintAndLog("Failed to write to file '%s'", fileName);
return 0;
}
fwrite(data, 1, datalen, fileHandle);
fclose(fileHandle);
PrintAndLog("Saved data to '%s'", fileName);
free(fileName);
return 0;
}

View File

@@ -18,6 +18,6 @@ int CmdHFiClassSnoop(const char *Cmd);
int CmdHFiClassSim(const char *Cmd);
int CmdHFiClassList(const char *Cmd);
int CmdHFiClassReader(const char *Cmd);
int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen);
int CmdHFiClassReader_Replay(const char *Cmd);
#endif

View File

@@ -10,7 +10,6 @@
#include <stdio.h>
#include <string.h>
//#include "proxusb.h"
#include "proxmark3.h"
#include "data.h"
#include "ui.h"

View File

@@ -7,7 +7,7 @@
//-----------------------------------------------------------------------------
// High frequency MIFARE commands
//-----------------------------------------------------------------------------
#include "../include/mifare.h"
#include "cmdhfmf.h"
static int CmdHelp(const char *Cmd);
@@ -140,6 +140,7 @@ int CmdHF14AMfWrBl(const char *Cmd)
return 0;
}
/* dublett finns i CMDHFMFU.C
int CmdHF14AMfUWrBl(const char *Cmd)
{
uint8_t blockNo = 0;
@@ -249,8 +250,7 @@ int CmdHF14AMfUWrBl(const char *Cmd)
}
return 0;
}
*/
int CmdHF14AMfRdBl(const char *Cmd)
{
uint8_t blockNo = 0;
@@ -299,6 +299,7 @@ int CmdHF14AMfRdBl(const char *Cmd)
return 0;
}
/* dublett finns i CMDHFMFU.C
int CmdHF14AMfURdBl(const char *Cmd)
{
uint8_t blockNo = 0;
@@ -330,8 +331,9 @@ int CmdHF14AMfURdBl(const char *Cmd)
return 0;
}
*/
/* dublett finns i CMDHFMFU.C
int CmdHF14AMfURdCard(const char *Cmd)
{
int i;
@@ -422,7 +424,7 @@ int CmdHF14AMfURdCard(const char *Cmd)
}
return 0;
}
*/
int CmdHF14AMfRdSc(const char *Cmd)
{
@@ -516,7 +518,16 @@ int CmdHF14AMfDump(const char *Cmd)
UsbCommand resp;
int size = GetCardSize();
char cmdp = param_getchar(Cmd, 0);
PrintAndLog("Got %d",size);
return;
if ( size > -1)
cmdp = (char)48+size;
switch (cmdp) {
case '0' : numSectors = 5; break;
case '1' :
@@ -545,8 +556,7 @@ int CmdHF14AMfDump(const char *Cmd)
return 1;
}
// Read key file
// Read keys A from file
for (sectorNo=0; sectorNo<numSectors; sectorNo++) {
if (fread( keyA[sectorNo], 1, 6, fin ) == 0) {
PrintAndLog("File reading error.");
@@ -554,6 +564,7 @@ int CmdHF14AMfDump(const char *Cmd)
}
}
// Read keys B from file
for (sectorNo=0; sectorNo<numSectors; sectorNo++) {
if (fread( keyB[sectorNo], 1, 6, fin ) == 0) {
PrintAndLog("File reading error.");
@@ -561,8 +572,6 @@ int CmdHF14AMfDump(const char *Cmd)
}
}
// Read access rights to sectors
PrintAndLog("|-----------------------------------------|");
PrintAndLog("|------ Reading sector access bits...-----|");
PrintAndLog("|-----------------------------------------|");
@@ -588,16 +597,14 @@ int CmdHF14AMfDump(const char *Cmd)
}
}
// Read blocks and print to file
PrintAndLog("|-----------------------------------------|");
PrintAndLog("|----- Dumping all blocks to file... -----|");
PrintAndLog("|-----------------------------------------|");
for (sectorNo = 0; sectorNo < numSectors; sectorNo++) {
for (blockNo = 0; blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
bool received = false;
if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. At least the Access Conditions can always be read with key A.
UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 0, 0}};
memcpy(c.d.asBytes, keyA[sectorNo], 6);
@@ -639,7 +646,7 @@ int CmdHF14AMfDump(const char *Cmd)
}
if (isOK) {
fwrite ( data, 1, 16, fout );
PrintAndLog("Dumped block %2d of sector %2d into 'dumpdata.bin'");
PrintAndLog("Dumped block %2d of sector %2d into 'dumpdata.bin'", blockNo, sectorNo);
} else {
PrintAndLog("Could not read block %2d of sector %2d", blockNo, sectorNo);
}
@@ -648,7 +655,6 @@ int CmdHF14AMfDump(const char *Cmd)
PrintAndLog("Command execute timeout");
}
}
}
fclose(fin);
@@ -801,11 +807,15 @@ int CmdHF14AMfNested(const char *Cmd)
cmdp = param_getchar(Cmd, 0);
blockNo = param_get8(Cmd, 1);
ctmp = param_getchar(Cmd, 2);
if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {
PrintAndLog("Key type must be A or B");
return 1;
}
if (ctmp != 'A' && ctmp != 'a') keyType = 1;
if (ctmp != 'A' && ctmp != 'a')
keyType = 1;
if (param_gethex(Cmd, 3, key, 12)) {
PrintAndLog("Key must include 12 HEX symbols");
return 1;
@@ -819,8 +829,12 @@ int CmdHF14AMfNested(const char *Cmd)
PrintAndLog("Target key type must be A or B");
return 1;
}
if (ctmp != 'A' && ctmp != 'a') trgKeyType = 1;
if (ctmp != 'A' && ctmp != 'a')
trgKeyType = 1;
} else {
switch (cmdp) {
case '0': SectorsCnt = 05; break;
case '1': SectorsCnt = 16; break;
@@ -2011,30 +2025,121 @@ int CmdHF14AMfSniff(const char *Cmd){
FillFileNameByUID(logHexFileName, uid + (7 - uid_len), ".log", uid_len);
AddLogCurrentDT(logHexFileName);
}
if (wantDecrypt) mfTraceInit(uid, atqa, sak, wantSaveToEmlFile);
if (wantDecrypt)
mfTraceInit(uid, atqa, sak, wantSaveToEmlFile);
} else {
PrintAndLog("%s(%d):%s", isTag ? "TAG":"RDR", num, sprint_hex(bufPtr, len));
if (wantLogToFile) AddLogHex(logHexFileName, isTag ? "TAG: ":"RDR: ", bufPtr, len);
if (wantDecrypt) mfTraceDecode(bufPtr, len, parity, wantSaveToEmlFile);
if (wantLogToFile)
AddLogHex(logHexFileName, isTag ? "TAG: ":"RDR: ", bufPtr, len);
if (wantDecrypt)
mfTraceDecode(bufPtr, len, parity, wantSaveToEmlFile);
}
bufPtr += len;
num++;
}
}
} // resp not NILL
} // resp not NULL
} // while (true)
return 0;
}
// Tries to identify cardsize.
// Returns <num> where num is:
// -1 unidentified
// 0 - MINI (320bytes)
// 1 - 1K
// 2 - 2K
// 4 - 4K
int GetCardSize()
{
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}};
SendCommand(&c);
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
if(resp.arg[0] == 0) {
PrintAndLog("iso14443a card select failed");
return -1;
}
iso14a_card_select_t *card = (iso14a_card_select_t *)resp.d.asBytes;
PrintAndLog("Trying to detect card size.");
uint16_t atqa = 0;
uint8_t sak = 0;
atqa = (card->atqa[1] & 0xff) << 8;
atqa += card->atqa[0] & 0xff;
sak = card->sak;
// https://code.google.com/p/libnfc/source/browse/libnfc/target-subr.c
PrintAndLog("found ATAQ: %04X SAK: %02X", atqa, sak);
// NXP MIFARE Mini 0.3k
if ( (atqa && 0xff0f == 0x0004) && (sak == 0x09) ) return 0;
// MIFARE Classic 1K
if ( (atqa && 0xff0f == 0x0004) && (sak == 0x08) ) return 1;
// MIFARE Classik 4K
if ( (atqa && 0xff0f == 0x0002) && (sak == 0x18) ) return 4;
// SmartMX with MIFARE 1K emulation
if ( (atqa && 0xf0ff == 0x0004) ) return 1;
// SmartMX with MIFARE 4K emulation
if ( (atqa && 0xf0ff == 0x0002) ) return 4;
// Infineon MIFARE CLASSIC 1K
if ( (atqa && 0xffff == 0x0004) && (sak == 0x88) ) return 1;
// MFC 4K emulated by Nokia 6212 Classic
if ( (atqa && 0xffff == 0x0002) && (sak == 0x38) ) return 4;
// MFC 4K emulated by Nokia 6131 NFC
if ( (atqa && 0xffff == 0x0008) && (sak == 0x38) ) return 4;
// MIFARE Plus (4 Byte UID or 4 Byte RID)
// MIFARE Plus (7 Byte UID)
if (
(atqa && 0xffff == 0x0002) ||
(atqa && 0xffff == 0x0004) ||
(atqa && 0xffff == 0x0042) ||
(atqa && 0xffff == 0x0044)
)
{
switch(sak){
case 0x08:
case 0x10:
//case 0x20:
return 2;
break;
case 0x11:
case 0x18:
//case 0x20:
return 4;
break;
}
}
return -1;
}
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"},
{"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"},
{"urdbl", CmdHF14AMfURdBl, 0, "Read MIFARE Ultralight block"},
{"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"},
{"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"},
//{"urdbl", CmdHF14AMfURdBl, 0, "Read MIFARE Ultralight block"},
//{"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"},
//{"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"},
{"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"},
{"dump", CmdHF14AMfDump, 0, "Dump MIFARE classic tag to binary file"},
{"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"},

View File

@@ -16,12 +16,11 @@
#include <string.h>
#include <ctype.h>
#include "proxmark3.h"
#include "iso14443crc.h"
#include "../common/iso14443crc.h"
#include "data.h"
//#include "proxusb.h"
#include "ui.h"
#include "cmdparser.h"
#include "common.h"
#include "../include/common.h"
#include "util.h"
#include "mifarehost.h"
@@ -54,5 +53,5 @@ int CmdHF14AMfCGetBlk(const char* cmd);
int CmdHF14AMfCGetSc(const char* cmd);
int CmdHF14AMfCLoad(const char* cmd);
int CmdHF14AMfCSave(const char* cmd);
int GetCardSize();
#endif

436
client/cmdhfmfdes.c Normal file
View File

@@ -0,0 +1,436 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2014 Iceman
//
// 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
// the license.
//-----------------------------------------------------------------------------
// High frequency MIFARE Desfire commands
//-----------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <openssl/des.h>
#include "cmdmain.h"
#include "proxmark3.h"
#include "../include/common.h"
#include "../include/mifare.h"
#include "../common/iso14443crc.h"
#include "data.h"
#include "ui.h"
#include "cmdparser.h"
#include "util.h"
#include "cmdhfmfdes.h"
uint8_t key_zero_data[16] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
uint8_t key_defa_data[16] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f };
uint8_t key_ones_data[16] = { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 };
static int CmdHelp(const char *Cmd);
static void xor(unsigned char * dst, unsigned char * src, size_t len);
static int32_t le24toh (uint8_t data[3]);
int CmdHF14ADesWb(const char *Cmd)
{
/* uint8_t blockNo = 0;
uint8_t keyType = 0;
uint8_t key[6] = {0, 0, 0, 0, 0, 0};
uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
char cmdp = 0x00;
if (strlen(Cmd)<3) {
PrintAndLog("Usage: hf mf wrbl <block number> <key A/B> <key (12 hex symbols)> <block data (32 hex symbols)>");
PrintAndLog(" sample: hf mf wrbl 0 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F");
return 0;
}
blockNo = param_get8(Cmd, 0);
cmdp = param_getchar(Cmd, 1);
if (cmdp == 0x00) {
PrintAndLog("Key type must be A or B");
return 1;
}
if (cmdp != 'A' && cmdp != 'a') keyType = 1;
if (param_gethex(Cmd, 2, key, 12)) {
PrintAndLog("Key must include 12 HEX symbols");
return 1;
}
if (param_gethex(Cmd, 3, bldata, 32)) {
PrintAndLog("Block data must include 32 HEX symbols");
return 1;
}
PrintAndLog("--block no:%02x key type:%02x key:%s", blockNo, keyType, sprint_hex(key, 6));
PrintAndLog("--data: %s", sprint_hex(bldata, 16));
UsbCommand c = {CMD_MIFARE_WRITEBL, {blockNo, keyType, 0}};
memcpy(c.d.asBytes, key, 6);
memcpy(c.d.asBytes + 10, bldata, 16);
SendCommand(&c);
UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
uint8_t isOK = resp.arg[0] & 0xff;
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
}
*/
return 0;
}
int CmdHF14ADesRb(const char *Cmd)
{
// uint8_t blockNo = 0;
// uint8_t keyType = 0;
// uint8_t key[6] = {0, 0, 0, 0, 0, 0};
// char cmdp = 0x00;
// if (strlen(Cmd)<3) {
// PrintAndLog("Usage: hf mf rdbl <block number> <key A/B> <key (12 hex symbols)>");
// PrintAndLog(" sample: hf mf rdbl 0 A FFFFFFFFFFFF ");
// return 0;
// }
// blockNo = param_get8(Cmd, 0);
// cmdp = param_getchar(Cmd, 1);
// if (cmdp == 0x00) {
// PrintAndLog("Key type must be A or B");
// return 1;
// }
// if (cmdp != 'A' && cmdp != 'a') keyType = 1;
// if (param_gethex(Cmd, 2, key, 12)) {
// PrintAndLog("Key must include 12 HEX symbols");
// return 1;
// }
// PrintAndLog("--block no:%02x key type:%02x key:%s ", blockNo, keyType, sprint_hex(key, 6));
// UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}};
// memcpy(c.d.asBytes, key, 6);
// SendCommand(&c);
// UsbCommand resp;
// 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, 16));
// else
// PrintAndLog("isOk:%02x", isOK);
// } else {
// PrintAndLog("Command execute timeout");
// }
return 0;
}
int CmdHF14ADesInfo(const char *Cmd){
UsbCommand c = {CMD_MIFARE_DESFIRE_INFO, { 0x00 }};
SendCommand(&c);
UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
uint8_t isOK = resp.arg[0] & 0xff;
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
return 0;
}
PrintAndLog("---Desfire Information---------------------------------------");
PrintAndLog("-------------------------------------------------------------");
PrintAndLog(" UID : %s",sprint_hex(resp.d.asBytes, 7));
PrintAndLog(" Batch number : %s",sprint_hex(resp.d.asBytes+28,5));
PrintAndLog(" Production date : week %02x, 20%02x",resp.d.asBytes[33], resp.d.asBytes[34]);
PrintAndLog("-------------------------------------------------------------");
PrintAndLog(" Hardware Information");
PrintAndLog(" Vendor Id : %s", GetVendorStr(resp.d.asBytes[7]));
PrintAndLog(" Type : 0x%02X",resp.d.asBytes[8]);
PrintAndLog(" Subtype : 0x%02X",resp.d.asBytes[9]);
PrintAndLog(" Version : %d.%d",resp.d.asBytes[10], resp.d.asBytes[11]);
PrintAndLog(" Storage size : %s",GetCardSizeStr(resp.d.asBytes[12]));
PrintAndLog(" Protocol : %s",GetProtocolStr(resp.d.asBytes[13]));
PrintAndLog("-------------------------------------------------------------");
PrintAndLog(" Software Information");
PrintAndLog(" Vendor Id : %s",GetVendorStr(resp.d.asBytes[14]));
PrintAndLog(" Type : 0x%02X",resp.d.asBytes[15]);
PrintAndLog(" Subtype : 0x%02X",resp.d.asBytes[16]);
PrintAndLog(" Version : %d.%d",resp.d.asBytes[17], resp.d.asBytes[18]);
PrintAndLog(" storage size : %s", GetCardSizeStr(resp.d.asBytes[19]));
PrintAndLog(" Protocol : %s", GetProtocolStr(resp.d.asBytes[20]));
PrintAndLog("-------------------------------------------------------------");
PrintAndLog(" Master Key settings");
if ( resp.d.asBytes[35] & (1 << 3 ) )
PrintAndLog(" 0x08 Configuration changeable;");
else
PrintAndLog(" 0x08 Configuration NOT changeable;");
if ( resp.d.asBytes[35] & (1 << 2 ) )
PrintAndLog(" 0x04 PICC Master Key not required for create / delete;");
else
PrintAndLog(" 0x04 PICC Master Key required for create / delete;");
if ( resp.d.asBytes[35] & (1 << 1 ) )
PrintAndLog(" 0x02 Free directory list access without PICC Master Key;");
else
PrintAndLog(" 0x02 Directory list access with PICC Master Key;");
if ( resp.d.asBytes[35] & (1 << 0 ) )
PrintAndLog(" 0x01 Allow changing the Master Key;");
else
PrintAndLog(" 0x01 Master Key is not changeable anymore;");
PrintAndLog("");
PrintAndLog(" Max number of keys : %d", resp.d.asBytes[36]);
PrintAndLog(" Master key Version : %d (0x%02x)", resp.d.asBytes[37], resp.d.asBytes[37]);
PrintAndLog("-------------------------------------------------------------");
uint8_t tmp[3];
memcpy(tmp, resp.d.asBytes+38,3);
PrintAndLog(" Free memory on card : %d bytes", le24toh( tmp ));
PrintAndLog("-------------------------------------------------------------");
/*
Card Master key (CMK) 0x00 on AID = 00 00 00 (card level)
0x1
Application Master Key (AMK) 0x00 on AID != 00 00 00
Application keys (APK) = 0x01-0x0D
Application free = 0x0E
Application never = 0x0F
ACCESS RIGHTS:
keys 0,1,2,3 C
keys 4,5,6,7 RW
keys 8,9,10,11 W
keys 12,13,14,15 R
KEY Versioning.
Se GetKeyVersion (samma nyckel kan ha olika versionen?)
Session key:
16 : RndA(byte0-byte3) + RndB(byte0-byte3) + RndA(byte4-byte7) + RndB(byte4-byte7)
8 : RndA(byte0-byte3) + RndB(byte0-byte3)
AES 16 : RndA(byte0-byte3) + RndB(byte0-byte3) + RndA(byte12-byte15) + RndB(byte12-byte15)
*/
PrintAndLog(" RX :%s",sprint_hex(resp.d.asBytes, 40));
return 1;
}
char * GetVendorStr( uint8_t id){
static char buf[30];
char *retStr = buf;
if ( id == 0x04 )
sprintf(retStr, "0x%02X (NXP)",id);
else
sprintf(retStr,"0x%02X (Unknown)",id);
return buf;
}
/*
The 7 MSBits (= n) code the storage size itself based on 2^n,
the LSBit is set to '0' if the size is exactly 2^n
and set to '1' if the storage size is between 2^n and 2^(n+1).
For this version of DESFire the 7 MSBits are set to 0x0C (2^12 = 4096) and the LSBit is '0'.
*/
char * GetCardSizeStr( uint8_t fsize ){
static char buf[30];
char *retStr = buf;
uint16_t usize = 1 << ((fsize >>1) + 1);
uint16_t lsize = 1 << (fsize >>1);
// is LSB set?
if ( fsize & (1 << 0 ) )
sprintf(retStr, "0x%02X (%d - %d bytes)",fsize, usize, lsize);
else
sprintf(retStr, "0x%02X (%d bytes)", fsize, lsize);
return buf;
}
char * GetProtocolStr(uint8_t id){
static char buf[30];
char *retStr = buf;
if ( id == 0x05)
sprintf(retStr,"0x%02X (ISO 14443-3, 14443-4)", id);
else
sprintf(retStr,"0x%02X", id);
return buf;
}
int CmdHF14ADesEnumApplications(const char *Cmd){
return 1;
}
int CmdHF14ADesNonces(const char *Cmd){
return 1;
}
//
// MIAFRE DesFire Authentication
//
#define BUFSIZE 64
int CmdHF14ADesAuth(const char *Cmd){
// NR DESC KEYLENGHT
// ------------------------
// 1 = DES 8
// 2 = 3DES 16
// 3 = 3K 3DES 24
// 4 = AES 16
// AUTHENTICTION MODES:
// 1 Normal
// 2 ISO
// 3 AES
uint8_t keylength = 8;
//unsigned char testinput[] = { 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff,0x00};
unsigned char key[24]; // = { 0x75,0x28,0x78,0x39,0x74,0x93,0xCB,0x70};
if (strlen(Cmd)<3) {
PrintAndLog("Usage: hf mfdes auth <1|2|3> <1|2|3|4> <keyno> <key> ");
PrintAndLog(" AUTH modes 1 = normal, 2 = iso, 3 = aes");
PrintAndLog(" Crypto: 1 = DES 2 = 3DES 3 = 3K3DES 4 = AES");
PrintAndLog(" keynumber");
PrintAndLog(" sample: hf mfdes auth 1 1 0 11223344");
return 0;
}
uint8_t cmdAuthMode = param_get8(Cmd,0);
uint8_t cmdAuthAlgo = param_get8(Cmd,1);
uint8_t cmdKeyNo = param_get8(Cmd,2);
switch (cmdAuthMode)
{
case 1:
if ( cmdAuthAlgo != 1 && cmdAuthAlgo != 2) {
PrintAndLog("Crypto algo not valid for the auth mode");
return 1;
}
break;
case 2:
if ( cmdAuthAlgo != 1 && cmdAuthAlgo != 2 && cmdAuthAlgo != 3) {
PrintAndLog("Crypto algo not valid for the auth mode");
return 1;
}
break;
case 3:
if ( cmdAuthAlgo != 4) {
PrintAndLog("Crypto algo not valid for the auth mode");
return 1;
}
break;
default:
PrintAndLog("Wrong Auth mode");
return 1;
break;
}
switch (cmdAuthAlgo){
case 2:
keylength = 16;
PrintAndLog("3DES selected");
break;
case 3:
keylength = 24;
PrintAndLog("3 key 3DES selected");
break;
case 4:
keylength = 16;
PrintAndLog("AES selected");
break;
default:
cmdAuthAlgo = 1;
keylength = 8;
PrintAndLog("DES selected");
break;
}
// key
if (param_gethex(Cmd, 3, key, keylength*2)) {
PrintAndLog("Key must include %d HEX symbols", keylength);
return 1;
}
// algo, nyckellängd,
UsbCommand c = {CMD_MIFARE_DESFIRE_AUTH1, { cmdAuthMode, cmdAuthAlgo, cmdKeyNo }};
c.d.asBytes[0] = keylength;
memcpy(c.d.asBytes+1, key, keylength);
//memcpy(c.d.asBytes + 30, testinput, keylength);
SendCommand(&c);
UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK,&resp,3000)) {
uint8_t isOK = resp.arg[0] & 0xff;
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
return 0;
}
uint8_t * data= resp.d.asBytes;
// PrintAndLog("-------------------------------------------------------------");
PrintAndLog(" Key :%s",sprint_hex(key, keylength));
// PrintAndLog(" Plain :%s",sprint_hex(testinput, keylength));
PrintAndLog(" Encoded :%s",sprint_hex(data, keylength));
PrintAndLog("-------------------------------------------------------------");
//PrintAndLog(" Expected :B5 21 9E E8 1A A7 49 9D 21 96 68 7E 13 97 38 56");
return 1;
}
static void xor(unsigned char * dst, unsigned char * src, size_t len) {
for( ; len > 0; len--,dst++,src++)
*dst ^= *src;
}
static int32_t le24toh (uint8_t data[3]) {
return (data[2] << 16) | (data[1] << 8) | data[0];
}
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"auth", CmdHF14ADesAuth, 0, "Tries a MIFARE DesFire Authentication"},
{"rb", CmdHF14ADesRb, 0, "Read MIFARE DesFire block"},
{"wb", CmdHF14ADesWb, 0, "write MIFARE DesFire block"},
{"info", CmdHF14ADesInfo, 0, "Get MIFARE DesFire information"},
{"enum", CmdHF14ADesEnumApplications,0, "Tries enumerate all applications"},
{"nonce", CmdHF14ADesNonces, 0, "<n> Collect n>0 nonces"},
{NULL, NULL, 0, NULL}
};
int CmdHFMFDes(const char *Cmd)
{
// flush
WaitForResponseTimeout(CMD_ACK,NULL,100);
CmdsParse(CommandTable, Cmd);
return 0;
}
int CmdHelp(const char *Cmd)
{
CmdsHelp(CommandTable);
return 0;
}

20
client/cmdhfmfdes.h Normal file
View File

@@ -0,0 +1,20 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2014 Iceman
//
// 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
// the license.
//-----------------------------------------------------------------------------
// High frequency MIFARE Desfire commands
//-----------------------------------------------------------------------------
int CmdHFMFDes(const char *Cmd);
int CmdHF14ADesAuth(const char* cmd);
int CmdHF14ADesRb(const char* cmd);
int CmdHF14ADesWb(const char* cmd);
int CmdHF14ADesInfo(const char *Cmd);
int CmdHF14ADesEnumApplications(const char *Cmd);
int CmdHF14ADesNonces(const char *Cmd);
char * GetCardSizeStr( uint8_t fsize );
char * GetVendorStr( uint8_t id);
char * GetProtocolStr(uint8_t id);

1159
client/cmdhfmfu.c Normal file

File diff suppressed because it is too large Load Diff

16
client/cmdhfmfu.h Normal file
View File

@@ -0,0 +1,16 @@
#include "cmdhfmf.h"
//standard ultralight
int CmdHF14AMfUWrBl(const char *Cmd);
int CmdHF14AMfURdBl(const char *Cmd);
int CmdHF14AMfURdCard(const char *Cmd);
int CmdHF14AMfUDump(const char *Cmd);
//Crypto Cards
int CmdHF14AMfUCRdBl(const char *Cmd);
int CmdHF14AMfUCRdCard(const char *Cmd);
int CmdHF14AMfUCDump(const char *Cmd);
int CmdHF14AMfucAuth(const char *Cmd);
void rol (uint8_t *data, const size_t len);
//general stuff
int CmdHFMFUltra(const char *Cmd);

View File

@@ -13,7 +13,6 @@
#include <string.h>
#include <limits.h>
#include "ui.h"
//#include "proxusb.h"
#include "proxmark3.h"
#include "cmdparser.h"
#include "cmdhw.h"

View File

@@ -12,7 +12,6 @@
#include <stdlib.h>
#include <string.h>
#include <limits.h>
//#include "proxusb.h"
#include "proxmark3.h"
#include "data.h"
#include "graph.h"

View File

@@ -11,14 +11,18 @@
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
//#include "proxusb.h"
#include "proxmark3.h"
#include "ui.h"
#include "graph.h"
#include "cmdmain.h"
#include "cmdparser.h"
#include "cmddata.h"
#include "cmdlf.h"
#include "cmdlfem4x.h"
#include "util.h"
#include "data.h"
char *global_em410xId;
static int CmdHelp(const char *Cmd);
@@ -139,6 +143,8 @@ retest:
PrintAndLog("EM410x Tag ID: %s", id);
PrintAndLog("Unique Tag ID: %s", id2);
global_em410xId = id;
/* Stop any loops */
return 1;
}
@@ -167,8 +173,9 @@ retest:
}
/* if we've already retested after flipping bits, return */
if (retested++)
if (retested++){
return 0;
}
/* if this didn't work, try flipping bits */
for (i = 0; i < bit2idx; i++)
@@ -252,6 +259,7 @@ int CmdEM410xSim(const char *Cmd)
int CmdEM410xWatch(const char *Cmd)
{
int read_h = (*Cmd == 'h');
//char k;
do
{
CmdLFRead(read_h ? "h" : "");
@@ -264,7 +272,22 @@ int CmdEM410xWatch(const char *Cmd)
// Changed by martin, 4000 x 4 = 16000,
// see http://www.proxmark.org/forum/viewtopic.php?pid=7235#p7235
CmdSamples("16000");
} while (
!CmdEM410xRead("")
);
return 0;
}
int CmdEM410xWatchnSpoof(const char *Cmd)
{
int read_h = (*Cmd == 'h');
do
{
CmdLFRead(read_h ? "h" : "");
CmdSamples("16000");
} while ( ! CmdEM410xRead(""));
PrintAndLog("# Replaying : %s",global_em410xId);
CmdEM410xSim(global_em410xId);
return 0;
}
@@ -482,12 +505,12 @@ int CmdEM410xWrite(const char *Cmd)
int CmdReadWord(const char *Cmd)
{
int Word = 16; //default to invalid word
int Word = -1; //default to invalid word
UsbCommand c;
sscanf(Cmd, "%d", &Word);
if (Word > 15) {
if ( (Word > 15) | (Word < 0) ) {
PrintAndLog("Word must be between 0 and 15");
return 1;
}
@@ -500,18 +523,37 @@ int CmdReadWord(const char *Cmd)
c.arg[1] = Word;
c.arg[2] = 0;
SendCommand(&c);
WaitForResponse(CMD_ACK, NULL);
size_t bytelength = 4096;
uint8_t data[bytelength];
memset(data, 0x00, bytelength);
GetFromBigBuf(data,bytelength,3560); //3560 -- should be offset..
WaitForResponseTimeout(CMD_ACK,NULL, 1500);
for (int j = 0; j < bytelength; j++) {
GraphBuffer[j] = ((int)data[j]) - 128;
}
GraphTraceLen = bytelength;
RepaintGraphWindow();
manchester_decode(data, bytelength);
free(data);
return 0;
}
int CmdReadWordPWD(const char *Cmd)
{
int Word = 16; //default to invalid word
int Word = -1; //default to invalid word
int Password = 0xFFFFFFFF; //default to blank password
UsbCommand c;
sscanf(Cmd, "%d %x", &Word, &Password);
if (Word > 15) {
if ( (Word > 15) | (Word < 0) ) {
PrintAndLog("Word must be between 0 and 15");
return 1;
}
@@ -524,6 +566,24 @@ int CmdReadWordPWD(const char *Cmd)
c.arg[1] = Word;
c.arg[2] = Password;
SendCommand(&c);
WaitForResponse(CMD_ACK, NULL);
size_t bytelength = 4096;
uint8_t data[bytelength];
memset(data, 0x00, bytelength);
GetFromBigBuf(data,bytelength,3560); //3560 -- should be offset..
WaitForResponseTimeout(CMD_ACK,NULL, 1500);
for (int j = 0; j < bytelength; j++) {
GraphBuffer[j] = ((int)data[j]) - 128;
}
GraphTraceLen = bytelength;
RepaintGraphWindow();
manchester_decode(data, bytelength);
free(data);
return 0;
}
@@ -581,15 +641,16 @@ int CmdWriteWordPWD(const char *Cmd)
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"em410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"},
{"em410xsim", CmdEM410xSim, 0, "<UID> -- Simulate EM410x tag"},
{"em410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"},
{"em410xwrite", CmdEM410xWrite, 1, "<UID> <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"},
{"em4x50read", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"},
{"readword", CmdReadWord, 1, "<Word> -- Read EM4xxx word data"},
{"readwordPWD", CmdReadWordPWD, 1, "<Word> <Password> -- Read EM4xxx word data in password mode"},
{"writeword", CmdWriteWord, 1, "<Data> <Word> -- Write EM4xxx word data"},
{"writewordPWD", CmdWriteWordPWD, 1, "<Data> <Word> <Password> -- Write EM4xxx word data in password mode"},
{"410read", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"},
{"410sim", CmdEM410xSim, 0, "<UID> -- Simulate EM410x tag"},
{"410watch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"},
{"410spoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
{"410write", CmdEM410xWrite, 1, "<UID> <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"},
{"4xread", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"},
{"rd", CmdReadWord, 1, "<Word 1-15> -- Read EM4xxx word data"},
{"rdpwd", CmdReadWordPWD, 1, "<Word 1-15> <Password> -- Read EM4xxx word data in password mode "},
{"wr", CmdWriteWord, 1, "<Data> <Word 1-15> -- Write EM4xxx word data"},
{"wrpwd", CmdWriteWordPWD, 1, "<Data> <Word 1-15> <Password> -- Write EM4xxx word data in password mode"},
{NULL, NULL, 0, NULL}
};

View File

@@ -10,7 +10,6 @@
#include <stdio.h>
#include <string.h>
//#include "proxusb.h"
#include "proxmark3.h"
#include "ui.h"
#include "graph.h"

View File

@@ -12,13 +12,12 @@
#include <stdlib.h>
#include <string.h>
#include "data.h"
//#include "proxusb.h"
#include "proxmark3.h"
#include "ui.h"
#include "cmdparser.h"
#include "common.h"
#include "../include/common.h"
#include "util.h"
#include "hitag2.h"
#include "../include/hitag2.h"
#include "sleep.h"
#include "cmdmain.h"

View File

@@ -3,7 +3,6 @@
#include <string.h>
#include <inttypes.h>
#include <limits.h>
//#include "proxusb.h"
#include "proxmark3.h"
#include "data.h"
#include "graph.h"

View File

@@ -10,7 +10,6 @@
#include <stdio.h>
#include <string.h>
//#include "proxusb.h"
#include "proxmark3.h"
#include "ui.h"
#include "graph.h"

View File

@@ -10,55 +10,88 @@
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
//#include "proxusb.h"
#include "proxmark3.h"
#include "ui.h"
#include "graph.h"
#include "cmdmain.h"
#include "cmdparser.h"
#include "cmddata.h"
#include "cmdlf.h"
#include "cmdlft55xx.h"
#include "util.h"
#include "data.h"
#define LF_TRACE_BUFF_SIZE 16000
static int CmdHelp(const char *Cmd);
int CmdReadBlk(const char *Cmd)
{
int Block = 8; //default to invalid block
//default to invalid block
int Block = -1;
UsbCommand c;
sscanf(Cmd, "%d", &Block);
if (Block > 7) {
if ((Block > 7) | (Block < 0)) {
PrintAndLog("Block must be between 0 and 7");
return 1;
}
PrintAndLog("Reading block %d", Block);
PrintAndLog(" Reading page 0 block : %d", Block);
// this command fills up BigBuff
//
c.cmd = CMD_T55XX_READ_BLOCK;
c.d.asBytes[0] = 0x0; //Normal mode
c.d.asBytes[0] = 0x00;
c.arg[0] = 0;
c.arg[1] = Block;
c.arg[2] = 0;
SendCommand(&c);
WaitForResponse(CMD_ACK, NULL);
uint8_t data[LF_TRACE_BUFF_SIZE];
memset(data, 0x00, LF_TRACE_BUFF_SIZE);
GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset..
WaitForResponseTimeout(CMD_ACK,NULL, 1500);
for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) {
GraphBuffer[j] = ((int)data[j]) - 128;
}
GraphTraceLen = LF_TRACE_BUFF_SIZE;
// BiDirectional
CmdDirectionalThreshold("70 -60");
// Askdemod
Cmdaskdemod("1");
uint8_t bits[1000];
uint8_t * bitstream = bits;
uint8_t len = 0;
len = manchester_decode(data, LF_TRACE_BUFF_SIZE, bitstream);
if ( len > 0 )
PrintPaddedManchester(bitstream, len, 32);
return 0;
}
int CmdReadBlkPWD(const char *Cmd)
{
int Block = 8; //default to invalid block
int Block = -1; //default to invalid block
int Password = 0xFFFFFFFF; //default to blank Block 7
UsbCommand c;
sscanf(Cmd, "%d %x", &Block, &Password);
if (Block > 7) {
if ((Block > 7) | (Block < 0)) {
PrintAndLog("Block must be between 0 and 7");
return 1;
}
PrintAndLog("Reading block %d with password %08X", Block, Password);
PrintAndLog("Reading page 0 block %d pwd %08X", Block, Password);
c.cmd = CMD_T55XX_READ_BLOCK;
c.d.asBytes[0] = 0x1; //Password mode
@@ -66,9 +99,35 @@ int CmdReadBlkPWD(const char *Cmd)
c.arg[1] = Block;
c.arg[2] = Password;
SendCommand(&c);
WaitForResponse(CMD_ACK, NULL);
uint8_t data[LF_TRACE_BUFF_SIZE];
memset(data, 0x00, LF_TRACE_BUFF_SIZE);
GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset..
WaitForResponseTimeout(CMD_ACK,NULL, 1500);
for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) {
GraphBuffer[j] = ((int)data[j]) - 128;
}
GraphTraceLen = LF_TRACE_BUFF_SIZE;
// BiDirectional
CmdDirectionalThreshold("70 -60");
// Askdemod
Cmdaskdemod("1");
uint8_t bits[1000];
uint8_t len = 0;
len = manchester_decode(data, LF_TRACE_BUFF_SIZE, bits);
if ( len > 0 )
PrintPaddedManchester(bits, len, 32);
return 0;
}
int CmdWriteBlk(const char *Cmd)
{
int Block = 8; //default to invalid block
@@ -120,11 +179,35 @@ int CmdWriteBlkPWD(const char *Cmd)
int CmdReadTrace(const char *Cmd)
{
PrintAndLog("Reading traceability data");
PrintAndLog(" Reading page 1 - tracedata");
UsbCommand c = {CMD_T55XX_READ_TRACE, {0, 0, 0}};
SendCommand(&c);
WaitForResponse(CMD_ACK, NULL);
uint8_t data[LF_TRACE_BUFF_SIZE];
memset(data, 0x00, LF_TRACE_BUFF_SIZE);
GetFromBigBuf(data,LF_TRACE_BUFF_SIZE,3560); //3560 -- should be offset..
WaitForResponseTimeout(CMD_ACK,NULL, 1500);
for (int j = 0; j < LF_TRACE_BUFF_SIZE; j++) {
GraphBuffer[j] = ((int)data[j]) - 128;
}
GraphTraceLen = LF_TRACE_BUFF_SIZE;
// BiDirectional
CmdDirectionalThreshold("70 -60");
// Askdemod
Cmdaskdemod("1");
uint8_t bits[512];
uint8_t len = 0;
len = manchester_decode(data,LF_TRACE_BUFF_SIZE,bits);
if ( len > 0 )
PrintPaddedManchester(bits, len, 64);
return 0;
}

View File

@@ -11,7 +11,6 @@
#include <stdio.h>
#include <stdlib.h>
#include "crc16.h"
//#include "proxusb.h"
#include "proxmark3.h"
#include "data.h"
#include "ui.h"

View File

@@ -16,7 +16,7 @@
#include "cmdparser.h"
#include "proxmark3.h"
#include "data.h"
#include "usb_cmd.h"
#include "../include/usb_cmd.h"
#include "ui.h"
#include "cmdhf.h"
#include "cmddata.h"

View File

@@ -11,7 +11,7 @@
#ifndef CMDMAIN_H__
#define CMDMAIN_H__
#include "usb_cmd.h"
#include "../include/usb_cmd.h"
#include "cmdparser.h"
void UsbCommandReceived(UsbCommand *UC);
void CommandReceived(char *Cmd);

View File

@@ -12,7 +12,6 @@
#include <stdint.h>
#include "data.h"
#include "ui.h"
//#include "proxusb.h"
#include "proxmark3.h"
#include "cmdmain.h"

View File

@@ -13,11 +13,10 @@
#include <stdlib.h>
#include "proxmark3.h"
#include "sleep.h"
//#include "proxusb.h"
#include "flash.h"
#include "elf.h"
#include "proxendian.h"
#include "usb_cmd.h"
#include "../include/usb_cmd.h"
void SendCommand(UsbCommand* txcmd);
void ReceiveCommand(UsbCommand* rxcmd);

View File

@@ -13,7 +13,7 @@
#include "proxmark3.h"
#include "flash.h"
#include "uart.h"
#include "usb_cmd.h"
#include "../include/usb_cmd.h"
#ifdef _WIN32
# define unlink(x)

255
client/loclass/cipher.c Normal file
View File

@@ -0,0 +1,255 @@
/*****************************************************************************
* This file is part of iClassCipher. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with IClassCipher. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "cipher.h"
#include "cipherutils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <time.h>
#include "fileutils.h"
uint8_t keytable[] = { 0,0,0,0,0,0,0,0};
/**
* Definition 1 (Cipher state). A cipher state of iClass s is an element of F 40/2
* consisting of the following four components:
* 1. the left register l = (l 0 . . . l 7 ) ∈ F 8/2 ;
* 2. the right register r = (r 0 . . . r 7 ) ∈ F 8/2 ;
* 3. the top register t = (t 0 . . . t 15 ) ∈ F 16/2 .
* 4. the bottom register b = (b 0 . . . b 7 ) ∈ F 8/2 .
**/
typedef struct {
uint8_t l;
uint8_t r;
uint8_t b;
uint16_t t;
} State;
/**
* Definition 2. The feedback function for the top register T : F 16/2 → F 2
* is defined as
* T (x 0 x 1 . . . . . . x 15 ) = x 0 ⊕ x 1 ⊕ x 5 ⊕ x 7 ⊕ x 10 ⊕ x 11 ⊕ x 14 ⊕ x 15 .
**/
bool T(State state)
{
bool x0 = state.t & 0x8000;
bool x1 = state.t & 0x4000;
bool x5 = state.t & 0x0400;
bool x7 = state.t & 0x0100;
bool x10 = state.t & 0x0020;
bool x11 = state.t & 0x0010;
bool x14 = state.t & 0x0002;
bool x15 = state.t & 0x0001;
return x0 ^ x1 ^ x5 ^ x7 ^ x10 ^ x11 ^ x14 ^ x15;
}
/**
* Similarly, the feedback function for the bottom register B : F 8/2 → F 2 is defined as
* B(x 0 x 1 . . . x 7 ) = x 1 ⊕ x 2 ⊕ x 3 ⊕ x 7 .
**/
bool B(State state)
{
bool x1 = state.b & 0x40;
bool x2 = state.b & 0x20;
bool x3 = state.b & 0x10;
bool x7 = state.b & 0x01;
return x1 ^ x2 ^ x3 ^ x7;
}
/**
* Definition 3 (Selection function). The selection function select : F 2 × F 2 ×
* F 8/2 → F 3/2 is defined as select(x, y, r) = z 0 z 1 z 2 where
* z 0 = (r 0 ∧ r 2 ) ⊕ (r 1 ∧ r 3 ) ⊕ (r 2 r 4 )
* z 1 = (r 0 r 2 ) ⊕ (r 5 r 7 ) ⊕ r 1 ⊕ r 6 ⊕ x ⊕ y
* z 2 = (r 3 ∧ r 5 ) ⊕ (r 4 ∧ r 6 ) ⊕ r 7 ⊕ x
**/
uint8_t _select(bool x, bool y, uint8_t r)
{
bool r0 = r >> 7 & 0x1;
bool r1 = r >> 6 & 0x1;
bool r2 = r >> 5 & 0x1;
bool r3 = r >> 4 & 0x1;
bool r4 = r >> 3 & 0x1;
bool r5 = r >> 2 & 0x1;
bool r6 = r >> 1 & 0x1;
bool r7 = r & 0x1;
bool z0 = (r0 & r2) ^ (r1 & ~r3) ^ (r2 | r4);
bool z1 = (r0 | r2) ^ ( r5 | r7) ^ r1 ^ r6 ^ x ^ y;
bool z2 = (r3 & ~r5) ^ (r4 & r6 ) ^ r7 ^ x;
// The three bitz z0.. z1 are packed into a uint8_t:
// 00000ZZZ
//Return value is a uint8_t
uint8_t retval = 0;
retval |= (z0 << 2) & 4;
retval |= (z1 << 1) & 2;
retval |= z2 & 1;
// Return value 0 <= retval <= 7
return retval;
}
/**
* Definition 4 (Successor state). Let s = l, r, t, b be a cipher state, k ∈ (F 82 ) 8
* be a key and y ∈ F 2 be the input bit. Then, the successor cipher state s =
* l , r , t , b is defined as
* t := (T (t) ⊕ r 0 ⊕ r 4 )t 0 . . . t 14 l := (k [select(T (t),y,r)] ⊕ b ) ⊞ l ⊞ r
* b := (B(b) ⊕ r 7 )b 0 . . . b 6 r := (k [select(T (t),y,r)] ⊕ b ) ⊞ l
*
* @param s - state
* @param k - array containing 8 bytes
**/
State successor(uint8_t* k, State s, bool y)
{
bool r0 = s.r >> 7 & 0x1;
bool r4 = s.r >> 3 & 0x1;
bool r7 = s.r & 0x1;
State successor = {0,0,0,0};
successor.t = s.t >> 1;
successor.t |= (T(s) ^ r0 ^ r4) << 15;
successor.b = s.b >> 1;
successor.b |= (B(s) ^ r7) << 7;
bool Tt = T(s);
successor.l = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l+s.r ) & 0xFF;
successor.r = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l ) & 0xFF;
return successor;
}
/**
* We define the successor function suc which takes a key k ∈ (F 82 ) 8 , a state s and
* an input y ∈ F 2 and outputs the successor state s . We overload the function suc
* to multiple bit input x ∈ F n 2 which we define as
* @param k - array containing 8 bytes
**/
State suc(uint8_t* k,State s, BitstreamIn *bitstream)
{
if(bitsLeft(bitstream) == 0)
{
return s;
}
bool lastbit = tailBit(bitstream);
return successor(k,suc(k,s,bitstream), lastbit);
}
/**
* Definition 5 (Output). Define the function output which takes an internal
* state s =< l, r, t, b > and returns the bit r 5 . We also define the function output
* on multiple bits input which takes a key k, a state s and an input x ∈ F n 2 as
* output(k, s, ǫ) = ǫ
* output(k, s, x 0 . . . x n ) = output(s) · output(k, s , x 1 . . . x n )
* where s = suc(k, s, x 0 ).
**/
void output(uint8_t* k,State s, BitstreamIn* in, BitstreamOut* out)
{
if(bitsLeft(in) == 0)
{
return;
}
pushBit(out,(s.r >> 2) & 1);
//Remove first bit
uint8_t x0 = headBit(in);
State ss = successor(k,s,x0);
output(k,ss,in, out);
}
/**
* Definition 6 (Initial state). Define the function init which takes as input a
* key k ∈ (F 82 ) 8 and outputs the initial cipher state s =< l, r, t, b >
**/
State init(uint8_t* k)
{
State s = {
((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l
((k[0] ^ 0x4c) + 0x21) & 0xFF,// r
0x4c, // b
0xE012 // t
};
return s;
}
void MAC(uint8_t* k, BitstreamIn input, BitstreamOut out)
{
uint8_t zeroes_32[] = {0,0,0,0};
BitstreamIn input_32_zeroes = {zeroes_32,sizeof(zeroes_32)*8,0};
State initState = suc(k,init(k),&input);
output(k,initState,&input_32_zeroes,&out);
}
void doMAC(uint8_t *cc_nr_p, int length, uint8_t *div_key_p, uint8_t mac[4])
{
uint8_t *cc_nr;
uint8_t div_key[8];
cc_nr=(uint8_t*)malloc(length+1);
memcpy(cc_nr,cc_nr_p,length);
memcpy(div_key,div_key_p,8);
reverse_arraybytes(cc_nr,length);
BitstreamIn bitstream = {cc_nr,length * 8,0};
uint8_t dest []= {0,0,0,0,0,0,0,0};
BitstreamOut out = { dest, sizeof(dest)*8, 0 };
MAC(div_key,bitstream, out);
//The output MAC must also be reversed
reverse_arraybytes(dest, sizeof(dest));
memcpy(mac,dest,4);
//printf("Calculated_MAC\t%02x%02x%02x%02x\n", dest[0],dest[1],dest[2],dest[3]);
free(cc_nr);
return;
}
int testMAC()
{
prnlog("[+] Testing MAC calculation...");
//From the "dismantling.IClass" paper:
uint8_t cc_nr[] = {0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0,0,0,0};
//From the paper
uint8_t div_key[8] = {0xE0,0x33,0xCA,0x41,0x9A,0xEE,0x43,0xF9};
uint8_t correct_MAC[4] = {0x1d,0x49,0xC9,0xDA};
uint8_t calculated_mac[4] = {0};
doMAC(cc_nr, 12,div_key, calculated_mac);
if(memcmp(calculated_mac, correct_MAC,4) == 0)
{
prnlog("[+] MAC calculation OK!");
}else
{
prnlog("[+] FAILED: MAC calculation failed:");
printarr(" Calculated_MAC", calculated_mac, 4);
printarr(" Correct_MAC ", correct_MAC, 4);
return 1;
}
return 0;
}

31
client/loclass/cipher.h Normal file
View File

@@ -0,0 +1,31 @@
/*****************************************************************************
* This file is part of iClassCipher. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with IClassCipher. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef CIPHER_H
#define CIPHER_H
#include <stdint.h>
void doMAC(uint8_t *cc_nr_p, int length, uint8_t *div_key_p, uint8_t mac[4]);
int testMAC();
#endif // CIPHER_H

View File

@@ -0,0 +1,273 @@
/*****************************************************************************
* This file is part of iClassCipher. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with IClassCipher. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "fileutils.h"
#include "cipherutils.h"
/**
*
* @brief Return and remove the first bit (x0) in the stream : <x0 x1 x2 x3 ... xn >
* @param stream
* @return
*/
bool headBit( BitstreamIn *stream)
{
int bytepos = stream->position >> 3; // divide by 8
int bitpos = (stream->position++) & 7; // mask out 00000111
return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
}
/**
* @brief Return and remove the last bit (xn) in the stream: <x0 x1 x2 ... xn>
* @param stream
* @return
*/
bool tailBit( BitstreamIn *stream)
{
int bitpos = stream->numbits -1 - (stream->position++);
int bytepos= bitpos >> 3;
bitpos &= 7;
return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
}
/**
* @brief Pushes bit onto the stream
* @param stream
* @param bit
*/
void pushBit( BitstreamOut* stream, bool bit)
{
int bytepos = stream->position >> 3; // divide by 8
int bitpos = stream->position & 7;
*(stream->buffer+bytepos) |= (bit & 1) << (7 - bitpos);
stream->position++;
stream->numbits++;
}
/**
* @brief Pushes the lower six bits onto the stream
* as b0 b1 b2 b3 b4 b5 b6
* @param stream
* @param bits
*/
void push6bits( BitstreamOut* stream, uint8_t bits)
{
pushBit(stream, bits & 0x20);
pushBit(stream, bits & 0x10);
pushBit(stream, bits & 0x08);
pushBit(stream, bits & 0x04);
pushBit(stream, bits & 0x02);
pushBit(stream, bits & 0x01);
}
/**
* @brief bitsLeft
* @param stream
* @return number of bits left in stream
*/
int bitsLeft( BitstreamIn *stream)
{
return stream->numbits - stream->position;
}
/**
* @brief numBits
* @param stream
* @return Number of bits stored in stream
*/
int numBits(BitstreamOut *stream)
{
return stream->numbits;
}
void x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest)
{
while (len--) {
dest[len] = (uint8_t) n;
n >>= 8;
}
}
uint64_t x_bytes_to_num(uint8_t* src, size_t len)
{
uint64_t num = 0;
while (len--)
{
num = (num << 8) | (*src);
src++;
}
return num;
}
uint8_t reversebytes(uint8_t b) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
void reverse_arraybytes(uint8_t* arr, size_t len)
{
uint8_t i;
for( i =0; i< len ; i++)
{
arr[i] = reversebytes(arr[i]);
}
}
void reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len)
{
uint8_t i;
for( i =0; i< len ; i++)
{
dest[i] = reversebytes(arr[i]);
}
}
void printarr(char * name, uint8_t* arr, int len)
{
int cx;
size_t outsize = 40+strlen(name)+len*5;
char* output = malloc(outsize);
memset(output, 0,outsize);
int i ;
cx = snprintf(output,outsize, "uint8_t %s[] = {", name);
for(i =0 ; i< len ; i++)
{
cx += snprintf(output+cx,outsize-cx,"0x%02x,",*(arr+i));//5 bytes per byte
}
cx += snprintf(output+cx,outsize-cx,"};");
prnlog(output);
}
void printvar(char * name, uint8_t* arr, int len)
{
int cx;
size_t outsize = 40+strlen(name)+len*2;
char* output = malloc(outsize);
memset(output, 0,outsize);
int i ;
cx = snprintf(output,outsize,"%s = ", name);
for(i =0 ; i< len ; i++)
{
cx += snprintf(output+cx,outsize-cx,"%02x",*(arr+i));//2 bytes per byte
}
prnlog(output);
}
void printarr_human_readable(char * title, uint8_t* arr, int len)
{
int cx;
size_t outsize = 100+strlen(title)+len*4;
char* output = malloc(outsize);
memset(output, 0,outsize);
int i;
cx = snprintf(output,outsize, "\n\t%s\n", title);
for(i =0 ; i< len ; i++)
{
if(i % 16 == 0)
cx += snprintf(output+cx,outsize-cx,"\n%02x| ", i );
cx += snprintf(output+cx,outsize-cx, "%02x ",*(arr+i));
}
prnlog(output);
}
//-----------------------------
// Code for testing below
//-----------------------------
int testBitStream()
{
uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF};
uint8_t output [] = {0,0,0,0,0,0,0,0};
BitstreamIn in = { input, sizeof(input) * 8,0};
BitstreamOut out ={ output, 0,0}
;
while(bitsLeft(&in) > 0)
{
pushBit(&out, headBit(&in));
//printf("Bits left: %d\n", bitsLeft(&in));
//printf("Bits out: %d\n", numBits(&out));
}
if(memcmp(input, output, sizeof(input)) == 0)
{
prnlog(" Bitstream test 1 ok");
}else
{
prnlog(" Bitstream test 1 failed");
uint8_t i;
for(i = 0 ; i < sizeof(input) ; i++)
{
prnlog(" IN %02x, OUT %02x", input[i], output[i]);
}
return 1;
}
return 0;
}
int testReversedBitstream()
{
uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF};
uint8_t reverse [] = {0,0,0,0,0,0,0,0};
uint8_t output [] = {0,0,0,0,0,0,0,0};
BitstreamIn in = { input, sizeof(input) * 8,0};
BitstreamOut out ={ output, 0,0};
BitstreamIn reversed_in ={ reverse, sizeof(input)*8,0};
BitstreamOut reversed_out ={ reverse,0 ,0};
while(bitsLeft(&in) > 0)
{
pushBit(&reversed_out, tailBit(&in));
}
while(bitsLeft(&reversed_in) > 0)
{
pushBit(&out, tailBit(&reversed_in));
}
if(memcmp(input, output, sizeof(input)) == 0)
{
prnlog(" Bitstream test 2 ok");
}else
{
prnlog(" Bitstream test 2 failed");
uint8_t i;
for(i = 0 ; i < sizeof(input) ; i++)
{
prnlog(" IN %02x, MIDDLE: %02x, OUT %02x", input[i],reverse[i], output[i]);
}
return 1;
}
return 0;
}
int testCipherUtils(void)
{
prnlog("[+] Testing some internals...");
int retval = 0;
retval |= testBitStream();
retval |= testReversedBitstream();
return retval;
}

View File

@@ -0,0 +1,59 @@
/*****************************************************************************
* This file is part of iClassCipher. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with IClassCipher. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef CIPHERUTILS_H
#define CIPHERUTILS_H
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
typedef struct {
uint8_t * buffer;
uint8_t numbits;
uint8_t position;
} BitstreamIn;
typedef struct {
uint8_t * buffer;
uint8_t numbits;
uint8_t position;
}BitstreamOut;
bool headBit( BitstreamIn *stream);
bool tailBit( BitstreamIn *stream);
void pushBit( BitstreamOut *stream, bool bit);
int bitsLeft( BitstreamIn *stream);
int testCipherUtils(void);
int testMAC();
void push6bits( BitstreamOut* stream, uint8_t bits);
void EncryptDES(bool key[56], bool outBlk[64], bool inBlk[64], int verbose) ;
void x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
uint64_t x_bytes_to_num(uint8_t* src, size_t len);
uint8_t reversebytes(uint8_t b);
void reverse_arraybytes(uint8_t* arr, size_t len);
void reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len);
void printarr(char * name, uint8_t* arr, int len);
void printvar(char * name, uint8_t* arr, int len);
void printarr_human_readable(char * title, uint8_t* arr, int len);
#endif // CIPHERUTILS_H

1014
client/loclass/des.c Normal file

File diff suppressed because it is too large Load Diff

256
client/loclass/des.h Normal file
View File

@@ -0,0 +1,256 @@
/**
* \file des.h
*
* \brief DES block cipher
*
* Copyright (C) 2006-2013, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef POLARSSL_DES_H
#define POLARSSL_DES_H
//#include "config.h"
#include <string.h>
#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32)
#include <basetsd.h>
typedef UINT32 uint32_t;
#else
#include <inttypes.h>
#endif
#define DES_ENCRYPT 1
#define DES_DECRYPT 0
#define POLARSSL_ERR_DES_INVALID_INPUT_LENGTH -0x0032 /**< The data input has an invalid length. */
#define DES_KEY_SIZE 8
#if !defined(POLARSSL_DES_ALT)
// Regular implementation
//
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief DES context structure
*/
typedef struct
{
int mode; /*!< encrypt/decrypt */
uint32_t sk[32]; /*!< DES subkeys */
}
des_context;
/**
* \brief Triple-DES context structure
*/
typedef struct
{
int mode; /*!< encrypt/decrypt */
uint32_t sk[96]; /*!< 3DES subkeys */
}
des3_context;
/**
* \brief Set key parity on the given key to odd.
*
* DES keys are 56 bits long, but each byte is padded with
* a parity bit to allow verification.
*
* \param key 8-byte secret key
*/
void des_key_set_parity( unsigned char key[DES_KEY_SIZE] );
/**
* \brief Check that key parity on the given key is odd.
*
* DES keys are 56 bits long, but each byte is padded with
* a parity bit to allow verification.
*
* \param key 8-byte secret key
*
* \return 0 is parity was ok, 1 if parity was not correct.
*/
int des_key_check_key_parity( const unsigned char key[DES_KEY_SIZE] );
/**
* \brief Check that key is not a weak or semi-weak DES key
*
* \param key 8-byte secret key
*
* \return 0 if no weak key was found, 1 if a weak key was identified.
*/
int des_key_check_weak( const unsigned char key[DES_KEY_SIZE] );
/**
* \brief DES key schedule (56-bit, encryption)
*
* \param ctx DES context to be initialized
* \param key 8-byte secret key
*
* \return 0
*/
int des_setkey_enc( des_context *ctx, const unsigned char key[DES_KEY_SIZE] );
/**
* \brief DES key schedule (56-bit, decryption)
*
* \param ctx DES context to be initialized
* \param key 8-byte secret key
*
* \return 0
*/
int des_setkey_dec( des_context *ctx, const unsigned char key[DES_KEY_SIZE] );
/**
* \brief Triple-DES key schedule (112-bit, encryption)
*
* \param ctx 3DES context to be initialized
* \param key 16-byte secret key
*
* \return 0
*/
int des3_set2key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] );
/**
* \brief Triple-DES key schedule (112-bit, decryption)
*
* \param ctx 3DES context to be initialized
* \param key 16-byte secret key
*
* \return 0
*/
int des3_set2key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] );
/**
* \brief Triple-DES key schedule (168-bit, encryption)
*
* \param ctx 3DES context to be initialized
* \param key 24-byte secret key
*
* \return 0
*/
int des3_set3key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] );
/**
* \brief Triple-DES key schedule (168-bit, decryption)
*
* \param ctx 3DES context to be initialized
* \param key 24-byte secret key
*
* \return 0
*/
int des3_set3key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] );
/**
* \brief DES-ECB block encryption/decryption
*
* \param ctx DES context
* \param input 64-bit input block
* \param output 64-bit output block
*
* \return 0 if successful
*/
int des_crypt_ecb( des_context *ctx,
const unsigned char input[8],
unsigned char output[8] );
#if defined(POLARSSL_CIPHER_MODE_CBC)
/**
* \brief DES-CBC buffer encryption/decryption
*
* \param ctx DES context
* \param mode DES_ENCRYPT or DES_DECRYPT
* \param length length of the input data
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*/
int des_crypt_cbc( des_context *ctx,
int mode,
size_t length,
unsigned char iv[8],
const unsigned char *input,
unsigned char *output );
#endif /* POLARSSL_CIPHER_MODE_CBC */
/**
* \brief 3DES-ECB block encryption/decryption
*
* \param ctx 3DES context
* \param input 64-bit input block
* \param output 64-bit output block
*
* \return 0 if successful
*/
int des3_crypt_ecb( des3_context *ctx,
const unsigned char input[8],
unsigned char output[8] );
#if defined(POLARSSL_CIPHER_MODE_CBC)
/**
* \brief 3DES-CBC buffer encryption/decryption
*
* \param ctx 3DES context
* \param mode DES_ENCRYPT or DES_DECRYPT
* \param length length of the input data
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*
* \return 0 if successful, or POLARSSL_ERR_DES_INVALID_INPUT_LENGTH
*/
int des3_crypt_cbc( des3_context *ctx,
int mode,
size_t length,
unsigned char iv[8],
const unsigned char *input,
unsigned char *output );
#endif /* POLARSSL_CIPHER_MODE_CBC */
#ifdef __cplusplus
}
#endif
#else /* POLARSSL_DES_ALT */
#include "des_alt.h"
#endif /* POLARSSL_DES_ALT */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int des_self_test( int verbose );
#ifdef __cplusplus
}
#endif
#endif /* des.h */

View File

@@ -0,0 +1,656 @@
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include "cipherutils.h"
#include "cipher.h"
#include "ikeys.h"
#include "elite_crack.h"
#include "fileutils.h"
#include "des.h"
/**
* @brief Permutes a key from standard NIST format to Iclass specific format
* from http://www.proxmark.org/forum/viewtopic.php?pid=11220#p11220
*
* If you permute [6c 8d 44 f9 2a 2d 01 bf] you get [8a 0d b9 88 bb a7 90 ea] as shown below.
*
* 1 0 1 1 1 1 1 1 bf
* 0 0 0 0 0 0 0 1 01
* 0 0 1 0 1 1 0 1 2d
* 0 0 1 0 1 0 1 0 2a
* 1 1 1 1 1 0 0 1 f9
* 0 1 0 0 0 1 0 0 44
* 1 0 0 0 1 1 0 1 8d
* 0 1 1 0 1 1 0 0 6c
*
* 8 0 b 8 b a 9 e
* a d 9 8 b 7 0 a
*
* @param key
* @param dest
*/
void permutekey(uint8_t key[8], uint8_t dest[8])
{
int i;
for(i = 0 ; i < 8 ; i++)
{
dest[i] = (((key[7] & (0x80 >> i)) >> (7-i)) << 7) |
(((key[6] & (0x80 >> i)) >> (7-i)) << 6) |
(((key[5] & (0x80 >> i)) >> (7-i)) << 5) |
(((key[4] & (0x80 >> i)) >> (7-i)) << 4) |
(((key[3] & (0x80 >> i)) >> (7-i)) << 3) |
(((key[2] & (0x80 >> i)) >> (7-i)) << 2) |
(((key[1] & (0x80 >> i)) >> (7-i)) << 1) |
(((key[0] & (0x80 >> i)) >> (7-i)) << 0);
}
return;
}
/**
* Permutes a key from iclass specific format to NIST format
* @brief permutekey_rev
* @param key
* @param dest
*/
void permutekey_rev(uint8_t key[8], uint8_t dest[8])
{
int i;
for(i = 0 ; i < 8 ; i++)
{
dest[7-i] = (((key[0] & (0x80 >> i)) >> (7-i)) << 7) |
(((key[1] & (0x80 >> i)) >> (7-i)) << 6) |
(((key[2] & (0x80 >> i)) >> (7-i)) << 5) |
(((key[3] & (0x80 >> i)) >> (7-i)) << 4) |
(((key[4] & (0x80 >> i)) >> (7-i)) << 3) |
(((key[5] & (0x80 >> i)) >> (7-i)) << 2) |
(((key[6] & (0x80 >> i)) >> (7-i)) << 1) |
(((key[7] & (0x80 >> i)) >> (7-i)) << 0);
}
}
/**
* Helper function for hash1
* @brief rr
* @param val
* @return
*/
uint8_t rr(uint8_t val)
{
return val >> 1 | (( val & 1) << 7);
}
/**
* Helper function for hash1
* @brief rl
* @param val
* @return
*/
uint8_t rl(uint8_t val)
{
return val << 1 | (( val & 0x80) >> 7);
}
/**
* Helper function for hash1
* @brief swap
* @param val
* @return
*/
uint8_t swap(uint8_t val)
{
return ((val >> 4) & 0xFF) | ((val &0xFF) << 4);
}
/**
* Hash1 takes CSN as input, and determines what bytes in the keytable will be used
* when constructing the K_sel.
* @param csn the CSN used
* @param k output
*/
void hash1(uint8_t csn[] , uint8_t k[])
{
k[0] = csn[0]^csn[1]^csn[2]^csn[3]^csn[4]^csn[5]^csn[6]^csn[7];
k[1] = csn[0]+csn[1]+csn[2]+csn[3]+csn[4]+csn[5]+csn[6]+csn[7];
k[2] = rr(swap( csn[2]+k[1] ));
k[3] = rr(swap( csn[3]+k[0] ));
k[4] = ~rr(swap( csn[4]+k[2] ))+1;
k[5] = ~rr(swap( csn[5]+k[3] ))+1;
k[6] = rr( csn[6]+(k[4]^0x3c) );
k[7] = rl( csn[7]+(k[5]^0xc3) );
int i;
for(i = 7; i >=0; i--)
k[i] = k[i] & 0x7F;
}
/**
Definition 14. Define the rotate key function rk : (F 82 ) 8 × N → (F 82 ) 8 as
rk(x [0] . . . x [7] , 0) = x [0] . . . x [7]
rk(x [0] . . . x [7] , n + 1) = rk(rl(x [0] ) . . . rl(x [7] ), n)
**/
void rk(uint8_t *key, uint8_t n, uint8_t *outp_key)
{
memcpy(outp_key, key, 8);
uint8_t j;
while(n-- > 0)
for(j=0; j < 8 ; j++)
outp_key[j] = rl(outp_key[j]);
return;
}
static des_context ctx_enc = {DES_ENCRYPT,{0}};
static des_context ctx_dec = {DES_DECRYPT,{0}};
void desdecrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output)
{
uint8_t key_std_format[8] = {0};
permutekey_rev(iclass_key, key_std_format);
des_setkey_dec( &ctx_dec, key_std_format);
des_crypt_ecb(&ctx_dec,input,output);
}
void desencrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output)
{
uint8_t key_std_format[8] = {0};
permutekey_rev(iclass_key, key_std_format);
des_setkey_enc( &ctx_enc, key_std_format);
des_crypt_ecb(&ctx_enc,input,output);
}
/**
* @brief Insert uint8_t[8] custom master key to calculate hash2 and return key_select.
* @param key unpermuted custom key
* @param hash1 hash1
* @param key_sel output key_sel=h[hash1[i]]
*/
void hash2(uint8_t *key64, uint8_t *outp_keytable)
{
/**
*Expected:
* High Security Key Table
00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1
10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21
20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2
30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C
40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6
50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42
60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95
70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB
**** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ******/
uint8_t key64_negated[8] = {0};
uint8_t z[8][8]={{0},{0}};
uint8_t temp_output[8]={0};
//calculate complement of key
int i;
for(i=0;i<8;i++)
key64_negated[i]= ~key64[i];
// Once again, key is on iclass-format
desencrypt_iclass(key64, key64_negated, z[0]);
prnlog("\nHigh security custom key (Kcus):");
printvar("z0 ", z[0],8);
uint8_t y[8][8]={{0},{0}};
// y[0]=DES_dec(z[0],~key)
// Once again, key is on iclass-format
desdecrypt_iclass(z[0], key64_negated, y[0]);
printvar("y0 ", y[0],8);
for(i=1; i<8; i++)
{
// z [i] = DES dec (rk(K cus , i), z [i1] )
rk(key64, i, temp_output);
//y [i] = DES enc (rk(K cus , i), y [i1] )
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;
}

View File

@@ -0,0 +1,108 @@
#ifndef ELITE_CRACK_H
#define ELITE_CRACK_H
void permutekey(uint8_t key[8], uint8_t dest[8]);
/**
* Permutes a key from iclass specific format to NIST format
* @brief permutekey_rev
* @param key
* @param dest
*/
void permutekey_rev(uint8_t key[8], uint8_t dest[8]);
//Crack status, see below
#define CRACKED 0x0100
#define BEING_CRACKED 0x0200
#define CRACK_FAILED 0x0400
/**
* Perform a bruteforce against a file which has been saved by pm3
*
* @brief bruteforceFile
* @param filename
* @param keytable an arrah (128 x 16 bit ints). This is where the keydata is stored.
* OBS! the upper part of the 16 bits store crack-status,
* @return
*/
int bruteforceFile(const char *filename, uint16_t keytable[]);
/**
*
* @brief Same as above, if you don't care about the returned keytable (results only printed on screen)
* @param filename
* @return
*/
int bruteforceFileNoKeys(const char *filename);
/**
* @brief Same as bruteforcefile, but uses a an array of dumpdata instead
* @param dump
* @param dumpsize
* @param keytable
* @return
*/
int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]);
/**
This is how we expect each 'entry' in a dumpfile to look
**/
typedef struct {
uint8_t csn[8];
uint8_t cc_nr[12];
uint8_t mac[4];
}dumpdata;
/**
* @brief Performs brute force attack against a dump-data item, containing csn, cc_nr and mac.
*This method calculates the hash1 for the CSN, and determines what bytes need to be bruteforced
*on the fly. If it finds that more than three bytes need to be bruteforced, it aborts.
*It updates the keytable with the findings, also using the upper half of the 16-bit ints
*to signal if the particular byte has been cracked or not.
*
* @param dump The dumpdata from iclass reader attack.
* @param keytable where to write found values.
* @return
*/
int bruteforceItem(dumpdata item, uint16_t keytable[]);
/**
* Hash1 takes CSN as input, and determines what bytes in the keytable will be used
* when constructing the K_sel.
* @param csn the CSN used
* @param k output
*/
void hash1(uint8_t csn[] , uint8_t k[]);
void hash2(uint8_t *key64, uint8_t *outp_keytable);
/**
* From dismantling iclass-paper:
* Assume that an adversary somehow learns the first 16 bytes of hash2(K_cus ), i.e., y [0] and z [0] .
* Then he can simply recover the master custom key K_cus by computing
* K_cus = ~DES(z[0] , y[0] ) .
*
* Furthermore, the adversary is able to verify that he has the correct K cus by
* checking whether z [0] = DES enc (K_cus , ~K_cus ).
* @param keytable an array (128 bytes) of hash2(kcus)
* @param master_key where to put the master key
* @return 0 for ok, 1 for failz
*/
int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[] );
/**
* @brief Test function
* @return
*/
int testElite();
/**
Here are some pretty optimal values that can be used to recover necessary data in only
eight auth attempts.
// CSN HASH1 Bytes recovered //
{ {0x00,0x0B,0x0F,0xFF,0xF7,0xFF,0x12,0xE0} , {0x01,0x01,0x00,0x00,0x45,0x01,0x45,0x45 } ,{0,1 }},
{ {0x00,0x13,0x94,0x7e,0x76,0xff,0x12,0xe0} , {0x02,0x0c,0x01,0x00,0x45,0x01,0x45,0x45} , {2,12}},
{ {0x2a,0x99,0xac,0x79,0xec,0xff,0x12,0xe0} , {0x07,0x45,0x0b,0x00,0x45,0x01,0x45,0x45} , {7,11}},
{ {0x17,0x12,0x01,0xfd,0xf7,0xff,0x12,0xe0} , {0x03,0x0f,0x00,0x00,0x45,0x01,0x45,0x45} , {3,15}},
{ {0xcd,0x56,0x01,0x7c,0x6f,0xff,0x12,0xe0} , {0x04,0x00,0x08,0x00,0x45,0x01,0x45,0x45} , {4,8}},
{ {0x4b,0x5e,0x0b,0x72,0xef,0xff,0x12,0xe0} , {0x0e,0x06,0x08,0x00,0x45,0x01,0x45,0x45} , {6,14}},
{ {0x00,0x73,0xd8,0x75,0x58,0xff,0x12,0xe0} , {0x0b,0x09,0x0f,0x00,0x45,0x01,0x05,0x45} , {9,5}},
{ {0x0c,0x90,0x32,0xf3,0x5d,0xff,0x12,0xe0} , {0x0d,0x0f,0x0a,0x00,0x45,0x01,0x05,0x45} , {10,13}},
**/
#endif

View File

@@ -0,0 +1,65 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <stdarg.h>
#include "fileutils.h"
#include "ui.h"
/**
* @brief checks if a file exists
* @param filename
* @return
*/
int fileExists(const char *filename) {
struct _stat st;
int result = stat(filename, &st);
return result == 0;
}
int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen)
{
int size = sizeof(char) * (strlen(preferredName)+strlen(suffix)+5);
char * fileName = malloc(size);
memset(fileName,0,size);
int num = 1;
sprintf(fileName,"%s.%s", preferredName, suffix);
while(fileExists(fileName))
{
sprintf(fileName,"%s-%d.%s", preferredName, num, suffix);
num++;
}
/* We should have a valid filename now, e.g. dumpdata-3.bin */
/*Opening file for writing in binary mode*/
FILE *fileHandle=fopen(fileName,"wb");
if(!fileHandle) {
prnlog("Failed to write to file '%s'", fileName);
return 1;
}
fwrite(data, 1, datalen, fileHandle);
fclose(fileHandle);
prnlog("Saved data to '%s'", fileName);
free(fileName);
return 0;
}
/**
* Utility function to print to console. This is used consistently within the library instead
* of printf, but it actually only calls printf (and adds a linebreak).
* The reason to have this method is to
* make it simple to plug this library into proxmark, which has this function already to
* write also to a logfile. When doing so, just delete this function.
* @param fmt
*/
void prnlog(char *fmt, ...)
{
va_list args;
va_start(args,fmt);
PrintAndLog(fmt, args);
//vprintf(fmt,args);
va_end(args);
//printf("\n");
}

View File

@@ -0,0 +1,24 @@
#ifndef FILEUTILS_H
#define FILEUTILS_H
/**
* @brief Utility function to save data to a file. This method takes a preferred name, but if that
* file already exists, it tries with another name until it finds something suitable.
* E.g. dumpdata-15.txt
* @param preferredName
* @param suffix the file suffix. Leave out the ".".
* @param data The binary data to write to the file
* @param datalen the length of the data
* @return 0 for ok, 1 for failz
*/
int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen);
/**
* Utility function to print to console. This is used consistently within the library instead
* of printf, but it actually only calls printf. The reason to have this method is to
*make it simple to plug this library into proxmark, which has this function already to
* write also to a logfile. When doing so, just point this function to use PrintAndLog
* @param fmt
*/
void prnlog(char *fmt, ...);
#endif // FILEUTILS_H

878
client/loclass/ikeys.c Normal file
View File

@@ -0,0 +1,878 @@
/*****************************************************************************
* This file is part of iClassCipher. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* This is a reference implementation of iclass key diversification. I'm sure it can be
* optimized heavily. It is written for ease of understanding and correctness, please take it
* and tweak it and make a super fast version instead, using this for testing and verification.
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with IClassCipher. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
/**
From "Dismantling iclass":
This section describes in detail the built-in key diversification algorithm of iClass.
Besides the obvious purpose of deriving a card key from a master key, this
algorithm intends to circumvent weaknesses in the cipher by preventing the
usage of certain weak keys. In order to compute a diversified key, the iClass
reader first encrypts the card identity id with the master key K, using single
DES. The resulting ciphertext is then input to a function called hash0 which
outputs the diversified key k.
k = hash0(DES enc (id, K))
Here the DES encryption of id with master key K outputs a cryptogram c
of 64 bits. These 64 bits are divided as c = x, y, z [0] , . . . , z [7] ∈ F 82 × F 82 × (F 62 ) 8
which is used as input to the hash0 function. This function introduces some
obfuscation by performing a number of permutations, complement and modulo
operations, see Figure 2.5. Besides that, it checks for and removes patterns like
similar key bytes, which could produce a strong bias in the cipher. Finally, the
output of hash0 is the diversified card key k = k [0] , . . . , k [7] ∈ (F 82 ) 8 .
**/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
#include "fileutils.h"
#include "cipherutils.h"
#include "des.h"
uint8_t pi[35] = {0x0F,0x17,0x1B,0x1D,0x1E,0x27,0x2B,0x2D,0x2E,0x33,0x35,0x39,0x36,0x3A,0x3C,0x47,0x4B,0x4D,0x4E,0x53,0x55,0x56,0x59,0x5A,0x5C,0x63,0x65,0x66,0x69,0x6A,0x6C,0x71,0x72,0x74,0x78};
static des_context ctx_enc = {DES_ENCRYPT,{0}};
static des_context ctx_dec = {DES_DECRYPT,{0}};
static int debug_print = 0;
/**
* @brief The key diversification algorithm uses 6-bit bytes.
* This implementation uses 64 bit uint to pack seven of them into one
* variable. When they are there, they are placed as follows:
* XXXX XXXX N0 .... N7, occupying the lsat 48 bits.
*
* This function picks out one from such a collection
* @param all
* @param n bitnumber
* @return
*/
uint8_t getSixBitByte(uint64_t c, int n)
{
return (c >> (42-6*n)) & 0x3F;
}
/**
* @brief Puts back a six-bit 'byte' into a uint64_t.
* @param c buffer
* @param z the value to place there
* @param n bitnumber.
*/
void pushbackSixBitByte(uint64_t *c, uint8_t z, int n)
{
//0x XXXX YYYY ZZZZ ZZZZ ZZZZ
// ^z0 ^z7
//z0: 1111 1100 0000 0000
uint64_t masked = z & 0x3F;
uint64_t eraser = 0x3F;
masked <<= 42-6*n;
eraser <<= 42-6*n;
//masked <<= 6*n;
//eraser <<= 6*n;
eraser = ~eraser;
(*c) &= eraser;
(*c) |= masked;
}
/**
* @brief Swaps the z-values.
* If the input value has format XYZ0Z1...Z7, the output will have the format
* XYZ7Z6...Z0 instead
* @param c
* @return
*/
uint64_t swapZvalues(uint64_t c)
{
uint64_t newz = 0;
pushbackSixBitByte(&newz, getSixBitByte(c,0),7);
pushbackSixBitByte(&newz, getSixBitByte(c,1),6);
pushbackSixBitByte(&newz, getSixBitByte(c,2),5);
pushbackSixBitByte(&newz, getSixBitByte(c,3),4);
pushbackSixBitByte(&newz, getSixBitByte(c,4),3);
pushbackSixBitByte(&newz, getSixBitByte(c,5),2);
pushbackSixBitByte(&newz, getSixBitByte(c,6),1);
pushbackSixBitByte(&newz, getSixBitByte(c,7),0);
newz |= (c & 0xFFFF000000000000);
return newz;
}
/**
* @return 4 six-bit bytes chunked into a uint64_t,as 00..00a0a1a2a3
*/
uint64_t ck(int i, int j, uint64_t z)
{
if(i == 1 && j == -1)
{
// ck(1, 1, z [0] . . . z [3] ) = z [0] . . . z [3]
return z;
}else if( j == -1)
{
// ck(i, 1, z [0] . . . z [3] ) = ck(i 1, i 2, z [0] . . . z [3] )
return ck(i-1,i-2, z);
}
if(getSixBitByte(z,i) == getSixBitByte(z,j))
{
//ck(i, j 1, z [0] . . . z [i] ← j . . . z [3] )
uint64_t newz = 0;
int c;
for(c = 0; c < 4 ;c++)
{
uint8_t val = getSixBitByte(z,c);
if(c == i)
{
pushbackSixBitByte(&newz, j, c);
}else
{
pushbackSixBitByte(&newz, val, c);
}
}
return ck(i,j-1,newz);
}else
{
return ck(i,j-1,z);
}
}
/**
Definition 8.
Let the function check : (F 62 ) 8 → (F 62 ) 8 be defined as
check(z [0] . . . z [7] ) = ck(3, 2, z [0] . . . z [3] ) · ck(3, 2, z [4] . . . z [7] )
where ck : N × N × (F 62 ) 4 → (F 62 ) 4 is defined as
ck(1, 1, z [0] . . . z [3] ) = z [0] . . . z [3]
ck(i, 1, z [0] . . . z [3] ) = ck(i 1, i 2, z [0] . . . z [3] )
ck(i, j, z [0] . . . z [3] ) =
ck(i, j 1, z [0] . . . z [i] ← j . . . z [3] ), if z [i] = z [j] ;
ck(i, j 1, z [0] . . . z [3] ), otherwise
otherwise.
**/
uint64_t check(uint64_t z)
{
//These 64 bits are divided as c = x, y, z [0] , . . . , z [7]
// ck(3, 2, z [0] . . . z [3] )
uint64_t ck1 = ck(3,2, z );
// ck(3, 2, z [4] . . . z [7] )
uint64_t ck2 = ck(3,2, z << 24);
//The ck function will place the values
// in the middle of z.
ck1 &= 0x00000000FFFFFF000000;
ck2 &= 0x00000000FFFFFF000000;
return ck1 | ck2 >> 24;
}
void permute(BitstreamIn *p_in, uint64_t z,int l,int r, BitstreamOut* out)
{
if(bitsLeft(p_in) == 0)
{
return;
}
bool pn = tailBit(p_in);
if( pn ) // pn = 1
{
uint8_t zl = getSixBitByte(z,l);
push6bits(out, zl+1);
permute(p_in, z, l+1,r, out);
}else // otherwise
{
uint8_t zr = getSixBitByte(z,r);
push6bits(out, zr);
permute(p_in,z,l,r+1,out);
}
}
void printbegin()
{
if(debug_print <2)
return ;
prnlog(" | x| y|z0|z1|z2|z3|z4|z5|z6|z7|");
}
void printState(char* desc, uint64_t c)
{
if(debug_print < 2)
return ;
printf("%s : ", desc);
uint8_t x = (c & 0xFF00000000000000 ) >> 56;
uint8_t y = (c & 0x00FF000000000000 ) >> 48;
printf(" %02x %02x", x,y);
int i ;
for(i =0 ; i < 8 ; i++)
{
printf(" %02x", getSixBitByte(c,i));
}
printf("\n");
}
/**
* @brief
*Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 → (F 82 ) 8 be defined as
* hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where
* z'[i] = (z[i] mod (63-i)) + i i = 0...3
* z'[i+4] = (z[i+4] mod (64-i)) + i i = 0...3
* ẑ = check(z');
* @param c
* @param k this is where the diversified key is put (should be 8 bytes)
* @return
*/
void hash0(uint64_t c, uint8_t k[8])
{
c = swapZvalues(c);
printbegin();
printState("origin",c);
//These 64 bits are divided as c = x, y, z [0] , . . . , z [7]
// x = 8 bits
// y = 8 bits
// z0-z7 6 bits each : 48 bits
uint8_t x = (c & 0xFF00000000000000 ) >> 56;
uint8_t y = (c & 0x00FF000000000000 ) >> 48;
int n;
uint8_t zn, zn4, _zn, _zn4;
uint64_t zP = 0;
for(n = 0; n < 4 ; n++)
{
zn = getSixBitByte(c,n);
zn4 = getSixBitByte(c,n+4);
_zn = (zn % (63-n)) + n;
_zn4 = (zn4 % (64-n)) + n;
pushbackSixBitByte(&zP, _zn,n);
pushbackSixBitByte(&zP, _zn4,n+4);
}
printState("0|0|z'",zP);
uint64_t zCaret = check(zP);
printState("0|0|z^",zP);
uint8_t p = pi[x % 35];
if(x & 1) //Check if x7 is 1
{
p = ~p;
}
if(debug_print >= 2) prnlog("p:%02x", p);
BitstreamIn p_in = { &p, 8,0 };
uint8_t outbuffer[] = {0,0,0,0,0,0,0,0};
BitstreamOut out = {outbuffer,0,0};
permute(&p_in,zCaret,0,4,&out);//returns 48 bits? or 6 8-bytes
//Out is now a buffer containing six-bit bytes, should be 48 bits
// if all went well
//Shift z-values down onto the lower segment
uint64_t zTilde = x_bytes_to_num(outbuffer,8);
zTilde >>= 16;
printState("0|0|z~", zTilde);
int i;
int zerocounter =0 ;
for(i =0 ; i < 8 ; i++)
{
// the key on index i is first a bit from y
// then six bits from z,
// then a bit from p
// Init with zeroes
k[i] = 0;
// First, place yi leftmost in k
//k[i] |= (y << i) & 0x80 ;
// First, place y(7-i) leftmost in k
k[i] |= (y << (7-i)) & 0x80 ;
uint8_t zTilde_i = getSixBitByte(zTilde, i);
// zTildeI is now on the form 00XXXXXX
// with one leftshift, it'll be
// 0XXXXXX0
// So after leftshift, we can OR it into k
// However, when doing complement, we need to
// again MASK 0XXXXXX0 (0x7E)
zTilde_i <<= 1;
//Finally, add bit from p or p-mod
//Shift bit i into rightmost location (mask only after complement)
uint8_t p_i = p >> i & 0x1;
if( k[i] )// yi = 1
{
//printf("k[%d] +1\n", i);
k[i] |= ~zTilde_i & 0x7E;
k[i] |= p_i & 1;
k[i] += 1;
}else // otherwise
{
k[i] |= zTilde_i & 0x7E;
k[i] |= (~p_i) & 1;
}
if((k[i] & 1 )== 0)
{
zerocounter ++;
}
}
}
/**
* @brief Performs Elite-class key diversification
* @param csn
* @param key
* @param div_key
*/
void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8])
{
// Prepare the DES key
des_setkey_enc( &ctx_enc, key);
uint8_t crypted_csn[8] = {0};
// Calculate DES(CSN, KEY)
des_crypt_ecb(&ctx_enc,csn, crypted_csn);
//Calculate HASH0(DES))
uint64_t crypt_csn = x_bytes_to_num(crypted_csn, 8);
//uint64_t crypted_csn_swapped = swapZvalues(crypt_csn);
hash0(crypt_csn,div_key);
}
void testPermute()
{
uint64_t x = 0;
pushbackSixBitByte(&x,0x00,0);
pushbackSixBitByte(&x,0x01,1);
pushbackSixBitByte(&x,0x02,2);
pushbackSixBitByte(&x,0x03,3);
pushbackSixBitByte(&x,0x04,4);
pushbackSixBitByte(&x,0x05,5);
pushbackSixBitByte(&x,0x06,6);
pushbackSixBitByte(&x,0x07,7);
uint8_t mres[8] = { getSixBitByte(x, 0),
getSixBitByte(x, 1),
getSixBitByte(x, 2),
getSixBitByte(x, 3),
getSixBitByte(x, 4),
getSixBitByte(x, 5),
getSixBitByte(x, 6),
getSixBitByte(x, 7)};
printarr("input_perm", mres,8);
uint8_t p = ~pi[0];
BitstreamIn p_in = { &p, 8,0 };
uint8_t outbuffer[] = {0,0,0,0,0,0,0,0};
BitstreamOut out = {outbuffer,0,0};
permute(&p_in, x,0,4, &out);
uint64_t permuted = x_bytes_to_num(outbuffer,8);
//printf("zTilde 0x%"PRIX64"\n", zTilde);
permuted >>= 16;
uint8_t res[8] = { getSixBitByte(permuted, 0),
getSixBitByte(permuted, 1),
getSixBitByte(permuted, 2),
getSixBitByte(permuted, 3),
getSixBitByte(permuted, 4),
getSixBitByte(permuted, 5),
getSixBitByte(permuted, 6),
getSixBitByte(permuted, 7)};
printarr("permuted", res, 8);
}
//These testcases are
//{ UID , TEMP_KEY, DIV_KEY} using the specific key
typedef struct
{
uint8_t uid[8];
uint8_t t_key[8];
uint8_t div_key[8];
} Testcase;
int testDES(Testcase testcase, des_context ctx_enc, des_context ctx_dec)
{
uint8_t des_encrypted_csn[8] = {0};
uint8_t decrypted[8] = {0};
uint8_t div_key[8] = {0};
int retval = des_crypt_ecb(&ctx_enc,testcase.uid,des_encrypted_csn);
retval |= des_crypt_ecb(&ctx_dec,des_encrypted_csn,decrypted);
if(memcmp(testcase.uid,decrypted,8) != 0)
{
//Decryption fail
prnlog("Encryption <-> Decryption FAIL");
printarr("Input", testcase.uid, 8);
printarr("Decrypted", decrypted, 8);
retval = 1;
}
if(memcmp(des_encrypted_csn,testcase.t_key,8) != 0)
{
//Encryption fail
prnlog("Encryption != Expected result");
printarr("Output", des_encrypted_csn, 8);
printarr("Expected", testcase.t_key, 8);
retval = 1;
}
uint64_t crypted_csn = x_bytes_to_num(des_encrypted_csn,8);
hash0(crypted_csn, div_key);
if(memcmp(div_key, testcase.div_key ,8) != 0)
{
//Key diversification fail
prnlog("Div key != expected result");
printarr(" csn ", testcase.uid,8);
printarr("{csn} ", des_encrypted_csn,8);
printarr("hash0 ", div_key, 8);
printarr("Expected", testcase.div_key, 8);
retval = 1;
}
return retval;
}
bool des_getParityBitFromKey(uint8_t key)
{//The top 7 bits is used
bool parity = ((key & 0x80) >> 7)
^ ((key & 0x40) >> 6) ^ ((key & 0x20) >> 5)
^ ((key & 0x10) >> 4) ^ ((key & 0x08) >> 3)
^ ((key & 0x04) >> 2) ^ ((key & 0x02) >> 1);
return !parity;
}
void des_checkParity(uint8_t* key)
{
int i;
int fails =0;
for(i =0 ; i < 8 ; i++)
{
bool parity = des_getParityBitFromKey(key[i]);
if(parity != (key[i] & 0x1))
{
fails++;
prnlog("[+] parity1 fail, byte %d [%02x] was %d, should be %d",i,key[i],(key[i] & 0x1),parity);
}
}
if(fails)
{
prnlog("[+] parity fails: %d", fails);
}else
{
prnlog("[+] Key syntax is with parity bits inside each byte");
}
}
Testcase testcases[] ={
{{0x8B,0xAC,0x60,0x1F,0x53,0xB8,0xED,0x11},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0xAE,0x51,0xE5,0x62,0xE7,0x9A,0x99,0x39},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01},{0x04,0x02,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x9B,0x21,0xE4,0x31,0x6A,0x00,0x29,0x62},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02},{0x06,0x04,0x02,0x08,0x01,0x03,0x05,0x07}},
{{0x65,0x24,0x0C,0x41,0x4F,0xC2,0x21,0x93},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04},{0x0A,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x7F,0xEB,0xAE,0x93,0xE5,0x30,0x08,0xBD},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08},{0x12,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x49,0x7B,0x70,0x74,0x9B,0x35,0x1B,0x83},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10},{0x22,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x02,0x3C,0x15,0x6B,0xED,0xA5,0x64,0x6C},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20},{0x42,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0xE8,0x37,0xE0,0xE2,0xC6,0x45,0x24,0xF3},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40},{0x02,0x06,0x04,0x08,0x01,0x03,0x05,0x07}},
{{0xAB,0xBD,0x30,0x05,0x29,0xC8,0xF7,0x12},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80},{0x02,0x08,0x06,0x04,0x01,0x03,0x05,0x07}},
{{0x17,0xE8,0x97,0xF0,0x99,0xB6,0x79,0x31},{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00},{0x02,0x0C,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x49,0xA4,0xF0,0x8F,0x5F,0x96,0x83,0x16},{0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00},{0x02,0x14,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x60,0xF5,0x7E,0x54,0xAA,0x41,0x83,0xD4},{0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00},{0x02,0x24,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x1D,0xF6,0x3B,0x6B,0x85,0x55,0xF0,0x4B},{0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00},{0x02,0x44,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x1F,0xDC,0x95,0x1A,0xEA,0x6B,0x4B,0xB4},{0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00},{0x02,0x04,0x08,0x06,0x01,0x03,0x05,0x07}},
{{0xEC,0x93,0x72,0xF0,0x3B,0xA9,0xF5,0x0B},{0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00},{0x02,0x04,0x0A,0x08,0x01,0x03,0x05,0x07}},
{{0xDE,0x57,0x5C,0xBE,0x2D,0x55,0x03,0x12},{0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00},{0x02,0x04,0x0E,0x08,0x01,0x03,0x05,0x07}},
{{0x1E,0xD2,0xB5,0xCE,0x90,0xC9,0xC1,0xCC},{0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00},{0x02,0x04,0x16,0x08,0x01,0x03,0x05,0x07}},
{{0xD8,0x65,0x96,0x4E,0xE7,0x74,0x99,0xB8},{0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00},{0x02,0x04,0x26,0x08,0x01,0x03,0x05,0x07}},
{{0xE3,0x7A,0x29,0x83,0x31,0xD5,0x3A,0x54},{0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00},{0x02,0x04,0x46,0x08,0x01,0x03,0x05,0x07}},
{{0x3A,0xB5,0x1A,0x34,0x34,0x25,0x12,0xF0},{0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00},{0x02,0x04,0x06,0x0A,0x01,0x03,0x05,0x07}},
{{0xF2,0x88,0xEE,0x6F,0x70,0x6F,0xC2,0x52},{0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00},{0x02,0x04,0x06,0x0C,0x01,0x03,0x05,0x07}},
{{0x76,0xEF,0xEB,0x80,0x52,0x43,0x83,0x57},{0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00},{0x02,0x04,0x06,0x10,0x01,0x03,0x05,0x07}},
{{0x1C,0x09,0x8E,0x3B,0x23,0x23,0x52,0xB5},{0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00},{0x02,0x04,0x06,0x18,0x01,0x03,0x05,0x07}},
{{0xA9,0x13,0xA2,0xBE,0xCF,0x1A,0xC4,0x9A},{0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00},{0x02,0x04,0x06,0x28,0x01,0x03,0x05,0x07}},
{{0x25,0x56,0x4B,0xB0,0xC8,0x2A,0xD4,0x27},{0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00},{0x02,0x04,0x06,0x48,0x01,0x03,0x05,0x07}},
{{0xB1,0x04,0x57,0x3F,0xA7,0x16,0x62,0xD4},{0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x03,0x01,0x05,0x07}},
{{0x45,0x46,0xED,0xCC,0xE7,0xD3,0x8E,0xA3},{0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x05,0x03,0x01,0x07}},
{{0x22,0x6D,0xB5,0x35,0xE0,0x5A,0xE0,0x90},{0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x09,0x03,0x05,0x07}},
{{0xB8,0xF5,0xE5,0x44,0xC5,0x98,0x4A,0xBD},{0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x11,0x03,0x05,0x07}},
{{0xAC,0x78,0x0A,0x23,0x9E,0xF6,0xBC,0xA0},{0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x21,0x03,0x05,0x07}},
{{0x46,0x6B,0x2D,0x70,0x41,0x17,0xBF,0x3D},{0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x41,0x03,0x05,0x07}},
{{0x64,0x44,0x24,0x71,0xA2,0x56,0xDF,0xB5},{0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x05,0x03,0x07}},
{{0xC4,0x00,0x52,0x24,0xA2,0xD6,0x16,0x7A},{0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x07,0x05,0x03}},
{{0xD8,0x4A,0x80,0x1E,0x95,0x5B,0x70,0xC4},{0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x0B,0x05,0x07}},
{{0x08,0x56,0x6E,0xB5,0x64,0xD6,0x47,0x4E},{0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x13,0x05,0x07}},
{{0x41,0x6F,0xBA,0xA4,0xEB,0xAE,0xA0,0x55},{0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x23,0x05,0x07}},
{{0x62,0x9D,0xDE,0x72,0x84,0x4A,0x53,0xD5},{0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x43,0x05,0x07}},
{{0x39,0xD3,0x2B,0x66,0xB8,0x08,0x40,0x2E},{0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x07,0x05}},
{{0xAF,0x67,0xA9,0x18,0x57,0x21,0xAF,0x8D},{0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x09,0x07}},
{{0x34,0xBC,0x9D,0xBC,0xC4,0xC2,0x3B,0xC8},{0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x0D,0x07}},
{{0xB6,0x50,0xF9,0x81,0xF6,0xBF,0x90,0x3C},{0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x15,0x07}},
{{0x71,0x41,0x93,0xA1,0x59,0x81,0xA5,0x52},{0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x25,0x07}},
{{0x6B,0x00,0xBD,0x74,0x1C,0x3C,0xE0,0x1A},{0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x45,0x07}},
{{0x76,0xFD,0x0B,0xD0,0x41,0xD2,0x82,0x5D},{0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x09}},
{{0xC6,0x3A,0x1C,0x25,0x63,0x5A,0x2F,0x0E},{0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x0B}},
{{0xD9,0x0E,0xD7,0x30,0xE2,0xAD,0xA9,0x87},{0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x0F}},
{{0x6B,0x81,0xC6,0xD1,0x05,0x09,0x87,0x1E},{0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x17}},
{{0xB4,0xA7,0x1E,0x02,0x54,0x37,0x43,0x35},{0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x27}},
{{0x45,0x14,0x7C,0x7F,0xE0,0xDE,0x09,0x65},{0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0x47}},
{{0x78,0xB0,0xF5,0x20,0x8B,0x7D,0xF3,0xDD},{0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00},{0xFE,0x04,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x88,0xB3,0x3C,0xE1,0xF7,0x87,0x42,0xA1},{0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0xFC,0x06,0x08,0x01,0x03,0x05,0x07}},
{{0x11,0x2F,0xB2,0xF7,0xE2,0xB2,0x4F,0x6E},{0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0xFA,0x08,0x01,0x03,0x05,0x07}},
{{0x25,0x56,0x4E,0xC6,0xEB,0x2D,0x74,0x5B},{0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0xF8,0x01,0x03,0x05,0x07}},
{{0x7E,0x98,0x37,0xF9,0x80,0x8F,0x09,0x82},{0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0xFF,0x03,0x05,0x07}},
{{0xF9,0xB5,0x62,0x3B,0xD8,0x7B,0x3C,0x3F},{0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0xFD,0x05,0x07}},
{{0x29,0xC5,0x2B,0xFA,0xD1,0xFC,0x5C,0xC7},{0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0xFB,0x07}},
{{0xC1,0xA3,0x09,0x71,0xBD,0x8E,0xAF,0x2F},{0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x06,0x08,0x01,0x03,0x05,0xF9}},
{{0xB6,0xDD,0xD1,0xAD,0xAA,0x15,0x6F,0x29},{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x03,0x05,0x02,0x07,0x04,0x06,0x08}},
{{0x65,0x34,0x03,0x19,0x17,0xB3,0xA3,0x96},{0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x01,0x06,0x08,0x03,0x05,0x07}},
{{0xF9,0x38,0x43,0x56,0x52,0xE5,0xB1,0xA9},{0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x04,0x06,0x08,0x03,0x05,0x07}},
{{0xA4,0xA0,0xAF,0xDA,0x48,0xB0,0xA1,0x10},{0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x04,0x06,0x03,0x08,0x05,0x07}},
{{0x55,0x15,0x8A,0x0D,0x48,0x29,0x01,0xD8},{0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x04,0x01,0x06,0x03,0x05,0x08,0x07}},
{{0xC4,0x81,0x96,0x7D,0xA3,0xB7,0x73,0x50},{0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x03,0x05,0x04,0x06,0x08,0x07}},
{{0x36,0x73,0xDF,0xC1,0x1B,0x98,0xA8,0x1D},{0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x03,0x04,0x05,0x06,0x08,0x07}},
{{0xCE,0xE0,0xB3,0x1B,0x41,0xEB,0x15,0x12},{0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x01,0x02,0x03,0x04,0x06,0x05,0x08,0x07}},
{{0},{0},{0}}
};
int testKeyDiversificationWithMasterkeyTestcases()
{
int error = 0;
int i;
uint8_t empty[8]={0};
prnlog("[+} Testing encryption/decryption");
for (i = 0; memcmp(testcases+i,empty,8) ; i++) {
error += testDES(testcases[i],ctx_enc, ctx_dec);
}
if(error)
{
prnlog("[+] %d errors occurred (%d testcases)", error, i);
}else
{
prnlog("[+] Hashing seems to work (%d testcases)", i);
}
return error;
}
void print64bits(char*name, uint64_t val)
{
printf("%s%08x%08x\n",name,(uint32_t) (val >> 32) ,(uint32_t) (val & 0xFFFFFFFF));
}
uint64_t testCryptedCSN(uint64_t crypted_csn, uint64_t expected)
{
int retval = 0;
uint8_t result[8] = {0};
if(debug_print) prnlog("debug_print %d", debug_print);
if(debug_print) print64bits(" {csn} ", crypted_csn );
uint64_t crypted_csn_swapped = swapZvalues(crypted_csn);
if(debug_print) print64bits(" {csn-revz} ", crypted_csn_swapped);
hash0(crypted_csn, result);
uint64_t resultbyte = x_bytes_to_num(result,8 );
if(debug_print) print64bits(" hash0 " , resultbyte );
if(resultbyte != expected )
{
if(debug_print) {
prnlog("\n[+] FAIL!");
print64bits(" expected " , expected );
}
retval = 1;
}else
{
if(debug_print) prnlog(" [OK]");
}
return retval;
}
int testDES2(uint64_t csn, uint64_t expected)
{
uint8_t result[8] = {0};
uint8_t input[8] = {0};
print64bits(" csn ", csn);
x_num_to_bytes(csn, 8,input);
des_crypt_ecb(&ctx_enc,input, result);
uint64_t crypt_csn = x_bytes_to_num(result, 8);
print64bits(" {csn} ", crypt_csn );
print64bits(" expected ", expected );
if( expected == crypt_csn )
{
prnlog("[+] OK");
return 0;
}else
{
return 1;
}
}
/**
* These testcases come from http://www.proxmark.org/forum/viewtopic.php?pid=10977#p10977
* @brief doTestsWithKnownInputs
* @return
*/
int doTestsWithKnownInputs()
{
// KSel from http://www.proxmark.org/forum/viewtopic.php?pid=10977#p10977
int errors = 0;
prnlog("[+] Testing DES encryption");
// uint8_t key[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf};
prnlog("[+] Testing foo");
uint8_t key[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf};
des_setkey_enc( &ctx_enc, key);
testDES2(0xbbbbaaaabbbbeeee,0xd6ad3ca619659e6b);
prnlog("[+] Testing hashing algorithm");
errors += testCryptedCSN(0x0102030405060708,0x0bdd6512073c460a);
errors += testCryptedCSN(0x1020304050607080,0x0208211405f3381f);
errors += testCryptedCSN(0x1122334455667788,0x2bee256d40ac1f3a);
errors += testCryptedCSN(0xabcdabcdabcdabcd,0xa91c9ec66f7da592);
errors += testCryptedCSN(0xbcdabcdabcdabcda,0x79ca5796a474e19b);
errors += testCryptedCSN(0xcdabcdabcdabcdab,0xa8901b9f7ec76da4);
errors += testCryptedCSN(0xdabcdabcdabcdabc,0x357aa8e0979a5b8d);
errors += testCryptedCSN(0x21ba6565071f9299,0x34e80f88d5cf39ea);
errors += testCryptedCSN(0x14e2adfc5bb7e134,0x6ac90c6508bd9ea3);
if(errors)
{
prnlog("[+] %d errors occurred (9 testcases)", errors);
}else
{
prnlog("[+] Hashing seems to work (9 testcases)" );
}
return errors;
}
int readKeyFile(uint8_t key[8])
{
FILE *f;
f = fopen("iclass_key.bin", "rb");
if (f)
{
if(fread(key, sizeof(key), 1, f) == 1) return 0;
}
return 1;
}
int doKeyTests(uint8_t debuglevel)
{
debug_print = debuglevel;
prnlog("[+] Checking if the master key is present (iclass_key.bin)...");
uint8_t key[8] = {0};
if(readKeyFile(key))
{
prnlog("[+] Master key not present, will not be able to do all testcases");
}else
{
//Test if it's the right key...
uint8_t i;
uint8_t j = 0;
for(i =0 ; i < sizeof(key) ; i++)
j += key[i];
if(j != 185)
{
prnlog("[+] A key was loaded, but it does not seem to be the correct one. Aborting these tests");
}else
{
prnlog("[+] Key present");
prnlog("[+] Checking key parity...");
des_checkParity(key);
des_setkey_enc( &ctx_enc, key);
des_setkey_dec( &ctx_dec, key);
// Test hashing functions
prnlog("[+] The following tests require the correct 8-byte master key");
testKeyDiversificationWithMasterkeyTestcases();
}
}
prnlog("[+] Testing key diversification with non-sensitive keys...");
doTestsWithKnownInputs();
return 0;
}
/**
void checkParity2(uint8_t* key)
{
uint8_t stored_parity = key[7];
printf("Parity byte: 0x%02x\n", stored_parity);
int i;
int byte;
int fails =0;
BitstreamIn bits = {key, 56, 0};
bool parity = 0;
for(i =0 ; i < 56; i++)
{
if ( i > 0 && i % 7 == 0)
{
parity = !parity;
bool pbit = stored_parity & (0x80 >> (byte));
if(parity != pbit)
{
printf("parity2 fail byte %d, should be %d, was %d\n", (i / 7), parity, pbit);
fails++;
}
parity =0 ;
byte = i / 7;
}
parity = parity ^ headBit(&bits);
}
if(fails)
{
printf("parity2 fails: %d\n", fails);
}else
{
printf("Key syntax is with parity bits grouped in the last byte!\n");
}
}
void modifyKey_put_parity_last(uint8_t * key, uint8_t* output)
{
uint8_t paritybits = 0;
bool parity =0;
BitstreamOut out = { output, 0,0};
unsigned int bbyte, bbit;
for(bbyte=0; bbyte <8 ; bbyte++ )
{
for(bbit =0 ; bbit< 7 ; bbit++)
{
bool bit = *(key+bbyte) & (1 << (7-bbit));
pushBit(&out,bit);
parity ^= bit;
}
bool paritybit = *(key+bbyte) & 1;
paritybits |= paritybit << (7-bbyte);
parity = 0;
}
output[7] = paritybits;
printf("Parity byte: %02x\n", paritybits);
}
* @brief Modifies a key with parity bits last, so that it is formed with parity
* bits inside each byte
* @param key
* @param output
void modifyKey_put_parity_allover(uint8_t * key, uint8_t* output)
{
bool parity =0;
BitstreamOut out = { output, 0,0};
BitstreamIn in = {key, 0,0};
unsigned int bbyte, bbit;
for(bbit =0 ; bbit < 56 ; bbit++)
{
if( bbit > 0 && bbit % 7 == 0)
{
pushBit(&out,!parity);
parity = 0;
}
bool bit = headBit(&in);
pushBit(&out,bit );
parity ^= bit;
}
pushBit(&out, !parity);
if( des_key_check_key_parity(output))
{
printf("modifyKey_put_parity_allover fail, DES key invalid parity!");
}
}
*/

32
client/loclass/ikeys.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef IKEYS_H
#define IKEYS_H
/**
* @brief
*Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 ? (F 82 ) 8 be defined as
* hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where
* z'[i] = (z[i] mod (63-i)) + i i = 0...3
* z'[i+4] = (z[i+4] mod (64-i)) + i i = 0...3
* ? = check(z');
* @param c
* @param k this is where the diversified key is put (should be 8 bytes)
* @return
*/
void hash0(uint64_t c, uint8_t k[8]);
int doKeyTests(uint8_t debuglevel);
/**
* @brief Performs Elite-class key diversification
* @param csn
* @param key
* @param div_key
*/
void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8]);
/**
* @brief Permutes a key from standard NIST format to Iclass specific format
* @param key
* @param dest
*/
#endif // IKEYS_H

96
client/loclass/main.c Normal file
View File

@@ -0,0 +1,96 @@
/*****************************************************************************
* This file is part of iClassCipher. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with IClassCipher. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include <stdio.h>
#include <cipherutils.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include "cipherutils.h"
#include "cipher.h"
#include "ikeys.h"
#include "fileutils.h"
#include "elite_crack.h"
int unitTests()
{
int errors = testCipherUtils();
errors += testMAC();
errors += doKeyTests(0);
errors += testElite();
return errors;
}
int showHelp()
{
prnlog("Usage: iclazz [options]");
prnlog("Options:");
prnlog("-t Perform self-test");
prnlog("-h Show this help");
prnlog("-f <filename> Bruteforce iclass dumpfile");
prnlog(" An iclass dumpfile is assumed to consist of an arbitrary number of malicious CSNs, and their protocol responses");
prnlog(" The the binary format of the file is expected to be as follows: ");
prnlog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
prnlog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
prnlog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
prnlog(" ... totalling N*24 bytes");
prnlog(" Check iclass_dump.bin for an example");
return 0;
}
int main (int argc, char **argv)
{
prnlog("IClass Cipher version 1.2, Copyright (C) 2014 Martin Holst Swende\n");
prnlog("Comes with ABSOLUTELY NO WARRANTY");
prnlog("This is free software, and you are welcome to use, abuse and repackage, please keep the credits\n");
char *fileName = NULL;
int c;
while ((c = getopt (argc, argv, "thf:")) != -1)
switch (c)
{
case 't':
return unitTests();
case 'h':
return showHelp();
case 'f':
fileName = optarg;
return bruteforceFileNoKeys(fileName);
case '?':
if (optopt == 'f')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
//default:
//showHelp();
}
showHelp();
return 0;
}

View File

@@ -15,7 +15,6 @@
#include "cmdmain.h"
#include "ui.h"
#include "data.h"
//#include "proxusb.h"
#include "util.h"
#include "nonce2key/nonce2key.h"
#include "nonce2key/crapto1.h"

View File

@@ -62,21 +62,6 @@ struct main_loop_arg {
char *script_cmds_file;
};
//static void *usb_receiver(void *targ) {
// struct receiver_arg *arg = (struct receiver_arg*)targ;
// UsbCommand cmdbuf;
//
// while (arg->run) {
// if (ReceiveCommandPoll(&cmdbuf)) {
// UsbCommandReceived(&cmdbuf);
// fflush(NULL);
// }
// }
//
// pthread_exit(NULL);
// return NULL;
//}
byte_t rx[0x1000000];
byte_t* prx = rx;
@@ -207,14 +192,6 @@ static void *main_loop(void *targ) {
return NULL;
}
//static void dumpHelp(char *parent, ...)
//{
// printf("## %s\n\n", parent);
// CommandReceived(parent);
//
// printf("\n");
//}
static void dumpAllHelp(int markdown)
{
printf("\n%sProxmark3 command dump%s\n\n",markdown?"# ":"",markdown?"":"\n======================");
@@ -254,17 +231,6 @@ int main(int argc, char* argv[]) {
};
pthread_t main_loop_t;
/*
usb_init();
if (!OpenProxmark(1)) {
fprintf(stderr,"PROXMARK3: NOT FOUND!\n");
marg.usb_present = 0;
offline = 1;
} else {
marg.usb_present = 1;
offline = 0;
}
*/
sp = uart_open(argv[1]);
if (sp == INVALID_SERIAL_PORT) {
@@ -305,10 +271,6 @@ int main(int argc, char* argv[]) {
pthread_join(main_loop_t, NULL);
// if (marg.usb_present == 1) {
// CloseProxmark();
// }
// Clean up the port
uart_close(sp);

View File

@@ -20,7 +20,7 @@
#include "usb_cmd.h"
#define PROXPROMPT "proxmark3> "
#define PROXPROMPT "pm3 --> "
void SendCommand(UsbCommand *c);

View File

@@ -90,3 +90,195 @@ void SetLogFilename(char *fn)
{
logfilename = fn;
}
uint8_t manchester_decode(const uint8_t * data, const size_t len, uint8_t * dataout){
size_t bytelength = len;
uint8_t bitStream[bytelength];
memset(bitStream, 0x00, bytelength);
int clock,high, low, bit, hithigh, hitlow, first, bit2idx, lastpeak;
int i,invert, lastval;
int bitidx = 0;
int lc = 0;
int warnings = 0;
high = 1;
low = bit = bit2idx = lastpeak = invert = lastval = hithigh = hitlow = first = 0;
clock = 0xFFFF;
/* Detect high and lows */
for (i = 0; i < bytelength; i++) {
if (data[i] > high)
high = data[i];
else if (data[i] < low)
low = data[i];
}
/* get clock */
int j=0;
for (i = 1; i < bytelength; i++) {
/* if this is the beginning of a peak */
j = i-1;
if ( data[j] != data[i] &&
data[i] == high)
{
/* find lowest difference between peaks */
if (lastpeak && i - lastpeak < clock)
clock = i - lastpeak;
lastpeak = i;
}
}
int tolerance = clock/4;
PrintAndLog(" Detected clock: %d",clock);
/* Detect first transition */
/* Lo-Hi (arbitrary) */
/* skip to the first high */
for (i= 0; i < bytelength; i++)
if (data[i] == high)
break;
/* now look for the first low */
for (; i < bytelength; i++) {
if (data[i] == low) {
lastval = i;
break;
}
}
/* If we're not working with 1/0s, demod based off clock */
if (high != 1)
{
bit = 0; /* We assume the 1st bit is zero, it may not be
* the case: this routine (I think) has an init problem.
* Ed.
*/
for (; i < (int)(bytelength / clock); i++)
{
hithigh = 0;
hitlow = 0;
first = 1;
/* Find out if we hit both high and low peaks */
for (j = 0; j < clock; j++)
{
if (data[(i * clock) + j] == high)
hithigh = 1;
else if (data[(i * clock) + j] == low)
hitlow = 1;
/* it doesn't count if it's the first part of our read
because it's really just trailing from the last sequence */
if (first && (hithigh || hitlow))
hithigh = hitlow = 0;
else
first = 0;
if (hithigh && hitlow)
break;
}
/* If we didn't hit both high and low peaks, we had a bit transition */
if (!hithigh || !hitlow)
bit ^= 1;
bitStream[bit2idx++] = bit ^ invert;
}
}
/* standard 1/0 bitstream */
else {
/* Then detect duration between 2 successive transitions */
for (bitidx = 1; i < bytelength; i++) {
if (data[i-1] != data[i]) {
lc = i-lastval;
lastval = i;
// Error check: if bitidx becomes too large, we do not
// have a Manchester encoded bitstream or the clock is really
// wrong!
if (bitidx > (bytelength*2/clock+8) ) {
PrintAndLog("Error: the clock you gave is probably wrong, aborting.");
return 0;
}
// Then switch depending on lc length:
// Tolerance is 1/4 of clock rate (arbitrary)
if (abs(lc-clock/2) < tolerance) {
// Short pulse : either "1" or "0"
bitStream[bitidx++] = data[i-1];
} else if (abs(lc-clock) < tolerance) {
// Long pulse: either "11" or "00"
bitStream[bitidx++] = data[i-1];
bitStream[bitidx++] = data[i-1];
} else {
// Error
warnings++;
PrintAndLog("Warning: Manchester decode error for pulse width detection.");
if (warnings > 10) {
PrintAndLog("Error: too many detection errors, aborting.");
return 0;
}
}
}
}
}
// At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream
// Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful
// to stop output at the final bitidx2 value, not bitidx
for (i = 0; i < bitidx; i += 2) {
if ((bitStream[i] == 0) && (bitStream[i+1] == 1)) {
bitStream[bit2idx++] = 1 ^ invert;
}
else if ((bitStream[i] == 1) && (bitStream[i+1] == 0)) {
bitStream[bit2idx++] = 0 ^ invert;
}
else {
// We cannot end up in this state, this means we are unsynchronized,
// move up 1 bit:
i++;
warnings++;
PrintAndLog("Unsynchronized, resync...");
if (warnings > 10) {
PrintAndLog("Error: too many decode errors, aborting.");
return 0;
}
}
}
// PrintAndLog(" Manchester decoded bitstream : %d bits", (bit2idx-16));
// uint8_t mod = (bit2idx-16) % blocksize;
// uint8_t div = (bit2idx-16) / blocksize;
// // Now output the bitstream to the scrollback by line of 16 bits
// for (i = 0; i < div*blocksize; i+=blocksize) {
// PrintAndLog(" %s", sprint_bin(bitStream+i,blocksize) );
// }
// if ( mod > 0 ){
// PrintAndLog(" %s", sprint_bin(bitStream+i, mod) );
// }
if ( bit2idx > 0 )
memcpy(dataout, bitStream, bit2idx);
free(bitStream);
return bit2idx;
}
void PrintPaddedManchester( uint8_t* bitStream, size_t len, size_t blocksize){
PrintAndLog(" Manchester decoded bitstream : %d bits", len);
uint8_t mod = len % blocksize;
uint8_t div = len / blocksize;
int i;
// Now output the bitstream to the scrollback by line of 16 bits
for (i = 0; i < div*blocksize; i+=blocksize) {
PrintAndLog(" %s", sprint_bin(bitStream+i,blocksize) );
}
if ( mod > 0 ){
PrintAndLog(" %s", sprint_bin(bitStream+i, mod) );
}
}

View File

@@ -11,6 +11,8 @@
#ifndef UI_H__
#define UI_H__
#include "util.h"
void ShowGui(void);
void HideGraphWindow(void);
void ShowGraphWindow(void);
@@ -23,4 +25,6 @@ extern int PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault;
extern int offline;
extern int flushAfterWrite; //buzzy
uint8_t manchester_decode(const uint8_t * data, const size_t len, uint8_t * dataout);
void PrintPaddedManchester( uint8_t * bitStream, size_t len, size_t blocksize);
#endif

View File

@@ -13,6 +13,7 @@
#ifndef _WIN32
#include <termios.h>
#include <sys/ioctl.h>
int ukbhit(void)
{
int cnt = 0;
@@ -112,6 +113,17 @@ char * sprint_hex(const uint8_t * data, const size_t len) {
return buf;
}
char * sprint_bin(const uint8_t * data, const size_t len) {
static char buf[1024];
char * tmp = buf;
size_t i;
for (i=0; i < len && i < 1024; i++, tmp++)
sprintf(tmp, "%u", data[i]);
return buf;
}
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest)
{
while (len--) {
@@ -131,6 +143,28 @@ uint64_t bytes_to_num(uint8_t* src, size_t len)
return num;
}
//assumes little endian
char * printBits(size_t const size, void const * const ptr)
{
unsigned char *b = (unsigned char*) ptr;
unsigned char byte;
static char buf[1024];
char * tmp = buf;
int i, j;
for (i=size-1;i>=0;i--)
{
for (j=7;j>=0;j--)
{
byte = b[i] & (1<<j);
byte >>= j;
sprintf(tmp, "%u", byte);
tmp++;
}
}
return buf;
}
// -------------------------------------------------------------------------
// string parameters lib
// -------------------------------------------------------------------------

View File

@@ -33,9 +33,11 @@ void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount);
void print_hex(const uint8_t * data, const size_t len);
char * sprint_hex(const uint8_t * data, const size_t len);
char * sprint_bin(const uint8_t * data, const size_t len);
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
uint64_t bytes_to_num(uint8_t* src, size_t len);
char * printBits(size_t const size, void const * const ptr);
char param_getchar(const char *line, int paramnum);
uint8_t param_get8(const char *line, int paramnum);
@@ -45,3 +47,4 @@ uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base);
int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt);
int param_getstr(const char *line, int paramnum, char * str);