First try att merging with head

This commit is contained in:
Martin Holst Swende 2014-10-24 20:46:02 +02:00
commit f97d4e2378
105 changed files with 7541 additions and 1686 deletions

4
.gitattributes vendored Normal file
View file

@ -0,0 +1,4 @@
# .gitattributes
# prevent binary files from CRLF handling, diff and merge:
fpga/fpga.bit -crlf -diff

12
.gitignore vendored
View file

@ -1,6 +1,8 @@
# .gitignore
# don't push these files to the repository
*.log
*.eml
*.o
*.a
*.d
@ -12,15 +14,21 @@
*.moc.cpp
*.exe
proxmark
proxmark3
flasher
version.c
lua
luac
fpga/*
!fpga/fpga.bit
!fpga/tests
!fpga/fpga_lf.bit
!fpga/fpga_hf.bit
!fpga/*.v
!fpga/Makefile
!fpga/fpga.ucf
!fpga/xst.scr
!fpga/xst_lf.scr
!fpga/xst_hf.scr
!fpga/go.bat
!fpga/sim.tcl

View file

@ -85,4 +85,3 @@ Jonathan Westhues
user jwesthues, at host cq.cx
May 2007, Cambridge MA

View file

@ -1,10 +0,0 @@
# Proxmark Wiki
* [Home Page](HomePage)
* [Getting Started](GettingStarted)
* [Hardware](Hardware)
* *Software / firmware*
* [Linux (Gentoo)](Gentoo Linux)
* [Windows](Windows)
* *Usage*
* [EM4102 Walk through](EM4102 1.pm3 Walkthrough)
* [Command Reference](commands)

View file

@ -52,10 +52,13 @@ OBJS = $(OBJDIR)/osimage.s19 $(OBJDIR)/fpgaimage.s19
all: $(OBJS)
$(OBJDIR)/fpga.o: fpga.bit
$(OBJCOPY) -O elf32-littlearm -I binary -B arm --redefine-sym _binary____fpga_fpga_bit_start=_binary_fpga_bit_start --redefine-sym _binary____fpga_fpga_bit_end=_binary_fpga_bit_end --prefix-sections=fpga_bit $^ $@
$(OBJDIR)/fpga_lf.o: fpga_lf.bit
$(OBJCOPY) -O elf32-littlearm -I binary -B arm --redefine-sym _binary____fpga_fpga_lf_bit_start=_binary_fpga_lf_bit_start --redefine-sym _binary____fpga_fpga_lf_bit_end=_binary_fpga_lf_bit_end --prefix-sections=fpga_lf_bit $^ $@
$(OBJDIR)/fullimage.elf: $(VERSIONOBJ) $(OBJDIR)/fpga.o $(THUMBOBJ) $(ARMOBJ)
$(OBJDIR)/fpga_hf.o: fpga_hf.bit
$(OBJCOPY) -O elf32-littlearm -I binary -B arm --redefine-sym _binary____fpga_fpga_hf_bit_start=_binary_fpga_hf_bit_start --redefine-sym _binary____fpga_fpga_hf_bit_end=_binary_fpga_hf_bit_end --prefix-sections=fpga_hf_bit $^ $@
$(OBJDIR)/fullimage.elf: $(VERSIONOBJ) $(OBJDIR)/fpga_lf.o $(OBJDIR)/fpga_hf.o $(THUMBOBJ) $(ARMOBJ)
$(CC) $(LDFLAGS) -Wl,-T,ldscript,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ $(LIBS)
$(OBJDIR)/fpgaimage.elf: $(OBJDIR)/fullimage.elf

View file

@ -214,7 +214,8 @@ void MeasureAntennaTuning(void)
* ( hopefully around 95 if it is tuned to 125kHz!)
*/
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
for (i=255; i>19; i--) {
WDT_HIT();
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i);
@ -236,6 +237,7 @@ void MeasureAntennaTuning(void)
LED_A_ON();
// Let the FPGA drive the high-frequency antenna around 13.56 MHz.
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
SpinDelay(20);
// Vref = 3300mV, and an 10:1 voltage divider on the input
@ -264,6 +266,7 @@ void MeasureAntennaTuningHf(void)
for (;;) {
// Let the FPGA drive the high-frequency antenna around 13.56 MHz.
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
SpinDelay(20);
// Vref = 3300mV, and an 10:1 voltage divider on the input
@ -286,6 +289,7 @@ void SimulateTagHfListen(void)
// We're using this mode just so that I can test it out; the simulated
// tag mode would work just as well and be simpler.
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP);
// We need to listen to the high-frequency, peak-detected path.
@ -336,7 +340,7 @@ extern struct version_information version_information;
extern char *_bootphase1_version_pointer, _flash_start, _flash_end;
void SendVersion(void)
{
char temp[48]; /* Limited data payload in USB packets */
char temp[256]; /* Limited data payload in USB packets */
DbpString("Prox/RFID mark3 RFID instrument");
/* Try to find the bootrom version information. Expect to find a pointer at
@ -365,6 +369,7 @@ void SendVersion(void)
void SamyRun()
{
DbpString("Stand-alone mode! No PC necessary.");
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
// 3 possible options? no just 2 for now
#define OPTS 2
@ -633,6 +638,10 @@ void UsbPacketReceived(uint8_t *packet, int len)
case CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K:
ModThenAcquireRawAdcSamples125k(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes);
break;
case CMD_LF_SNOOP_RAW_ADC_SAMPLES:
SnoopLFRawAdcSamples(c->arg[0], c->arg[1]);
cmd_send(CMD_ACK,0,0,0,0,0);
break;
case CMD_HID_DEMOD_FSK:
CmdHIDdemodFSK(0, 0, 0, 1); // Demodulate HID tag
break;
@ -853,11 +862,14 @@ void UsbPacketReceived(uint8_t *packet, int len)
SnoopIClass();
break;
case CMD_SIMULATE_TAG_ICLASS:
SimulateIClass(c->arg[0], c->d.asBytes);
SimulateIClass(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
break;
case CMD_READER_ICLASS:
ReaderIClass(c->arg[0]);
break;
case CMD_READER_ICLASS_REPLAY:
ReaderIClass_Replay(c->arg[0], c->d.asBytes);
break;
#endif
case CMD_SIMULATE_TAG_HF_LISTEN:
@ -923,6 +935,7 @@ void UsbPacketReceived(uint8_t *packet, int len)
break;
case CMD_SET_LF_DIVISOR:
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, c->arg[0]);
break;
@ -1017,7 +1030,8 @@ void __attribute__((noreturn)) AppMain(void)
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;
// Load the FPGA image, which we have stored in our flash.
FpgaDownloadAndGo();
// (the HF version by default)
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
StartTickCount();

View file

@ -59,7 +59,8 @@ void ToSendStuffBit(int b);
void ToSendReset(void);
void ListenReaderField(int limit);
void AcquireRawAdcSamples125k(int at134khz);
void DoAcquisition125k(void);
void SnoopLFRawAdcSamples(int divisor, int trigger_threshold);
void DoAcquisition125k(int trigger_threshold);
extern int ToSendMax;
extern uint8_t ToSend[];
extern uint32_t BigBuf[];
@ -67,7 +68,8 @@ extern uint32_t BigBuf[];
/// fpga.h
void FpgaSendCommand(uint16_t cmd, uint16_t v);
void FpgaWriteConfWord(uint8_t v);
void FpgaDownloadAndGo(void);
void FpgaDownloadAndGo(int bitstream_version);
int FpgaGatherBitstreamVersion();
void FpgaGatherVersion(char *dst, int len);
void FpgaSetupSsc(void);
void SetupSpi(int mode);
@ -77,31 +79,40 @@ bool FpgaSetupSscDma(uint8_t *buf, int len);
void SetAdcMuxFor(uint32_t whichGpio);
// Definitions for the FPGA commands.
#define FPGA_CMD_SET_CONFREG (1<<12)
#define FPGA_CMD_SET_DIVISOR (2<<12)
#define FPGA_CMD_SET_CONFREG (1<<12)
#define FPGA_CMD_SET_DIVISOR (2<<12)
#define FPGA_CMD_SET_USER_BYTE1 (3<<12)
// Definitions for the FPGA configuration word.
#define FPGA_MAJOR_MODE_LF_READER (0<<5)
#define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<5)
#define FPGA_MAJOR_MODE_HF_READER_TX (2<<5)
#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (3<<5)
#define FPGA_MAJOR_MODE_HF_SIMULATOR (4<<5)
#define FPGA_MAJOR_MODE_HF_ISO14443A (5<<5)
#define FPGA_MAJOR_MODE_LF_PASSTHRU (6<<5)
#define FPGA_MAJOR_MODE_OFF (7<<5)
// LF
#define FPGA_MAJOR_MODE_LF_ADC (0<<5)
#define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<5)
#define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<5)
// HF
#define FPGA_MAJOR_MODE_HF_READER_TX (0<<5)
#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (1<<5)
#define FPGA_MAJOR_MODE_HF_SIMULATOR (2<<5)
#define FPGA_MAJOR_MODE_HF_ISO14443A (3<<5)
// BOTH
#define FPGA_MAJOR_MODE_OFF (7<<5)
// Options for LF_ADC
#define FPGA_LF_ADC_READER_FIELD (1<<0)
// Options for LF_EDGE_DETECT
#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD FPGA_CMD_SET_USER_BYTE1
#define FPGA_LF_EDGE_DETECT_READER_FIELD (1<<0)
#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE (1<<1)
// Options for the HF reader, tx to tag
#define FPGA_HF_READER_TX_SHALLOW_MOD (1<<0)
// Options for the HF reader, correlating against rx from tag
#define FPGA_HF_READER_RX_XCORR_848_KHZ (1<<0)
#define FPGA_HF_READER_RX_XCORR_SNOOP (1<<1)
#define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ (1<<2)
#define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ (1<<2)
// Options for the HF simulated tag, how to modulate
#define FPGA_HF_SIMULATOR_NO_MODULATION (0<<0)
#define FPGA_HF_SIMULATOR_MODULATE_BPSK (1<<0)
#define FPGA_HF_SIMULATOR_MODULATE_212K (2<<0)
#define FPGA_HF_SIMULATOR_MODULATE_424K (4<<0)
// Options for ISO14443A
#define FPGA_HF_ISO14443A_SNIFFER (0<<0)
#define FPGA_HF_ISO14443A_SNIFFER (0<<0)
#define FPGA_HF_ISO14443A_TAGSIM_LISTEN (1<<0)
#define FPGA_HF_ISO14443A_TAGSIM_MOD (2<<0)
#define FPGA_HF_ISO14443A_READER_LISTEN (3<<0)
@ -146,7 +157,7 @@ void RAMFUNC SnoopIso14443a(uint8_t param);
void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data);
void ReaderIso14443a(UsbCommand * c);
// Also used in iclass.c
bool RAMFUNC LogTrace(const uint8_t * btBytes, uint8_t iLen, uint32_t iSamples, uint32_t dwParity, bool bReader);
bool RAMFUNC LogTrace(const uint8_t * btBytes, uint8_t iLen, uint32_t iSamples, uint32_t dwParity, bool readerToTag);
uint32_t GetParity(const uint8_t * pbtCmd, int iLen);
void iso14a_set_trigger(bool enable);
void iso14a_clear_trace();
@ -188,8 +199,10 @@ void SetDebugIso15693(uint32_t flag);
/// iclass.h
void RAMFUNC SnoopIClass(void);
void SimulateIClass(uint8_t arg0, uint8_t *datain);
void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void ReaderIClass(uint8_t arg0);
void ReaderIClass_Replay(uint8_t arg0,uint8_t *MAC);
void IClass_iso14443A_GetPublic(uint8_t arg0);
// hitag2.h
void SnoopHitag(uint32_t type);

View file

@ -1,5 +1,6 @@
//-----------------------------------------------------------------------------
// Jonathan Westhues, April 2006
// iZsh <izsh at fail0verflow.com>, 2014
//
// 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
@ -8,7 +9,6 @@
// Routines to load the FPGA image, and then to configure the FPGA's major
// mode once it is configured.
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
@ -252,7 +252,7 @@ static void DownloadFPGA(const char *FpgaImage, int FpgaImageLen, int byterevers
static char *bitparse_headers_start;
static char *bitparse_bitstream_end;
static int bitparse_initialized;
static int bitparse_initialized = 0;
/* Simple Xilinx .bit parser. The file starts with the fixed opaque byte sequence
* 00 09 0f f0 0f f0 0f f0 0f f0 00 00 01
* After that the format is 1 byte section type (ASCII character), 2 byte length
@ -322,12 +322,28 @@ int bitparse_find_section(char section_name, char **section_start, unsigned int
// Find out which FPGA image format is stored in flash, then call DownloadFPGA
// with the right parameters to download the image
//-----------------------------------------------------------------------------
extern char _binary_fpga_bit_start, _binary_fpga_bit_end;
void FpgaDownloadAndGo(void)
extern char _binary_fpga_lf_bit_start, _binary_fpga_lf_bit_end;
extern char _binary_fpga_hf_bit_start, _binary_fpga_hf_bit_end;
void FpgaDownloadAndGo(int bitstream_version)
{
void *bit_start;
void *bit_end;
// check whether or not the bitstream is already loaded
if (FpgaGatherBitstreamVersion() == bitstream_version)
return;
if (bitstream_version == FPGA_BITSTREAM_LF) {
bit_start = &_binary_fpga_lf_bit_start;
bit_end = &_binary_fpga_lf_bit_end;
} else if (bitstream_version == FPGA_BITSTREAM_HF) {
bit_start = &_binary_fpga_hf_bit_start;
bit_end = &_binary_fpga_hf_bit_end;
} else
return;
/* Check for the new flash image format: Should have the .bit file at &_binary_fpga_bit_start
*/
if(bitparse_init(&_binary_fpga_bit_start, &_binary_fpga_bit_end)) {
if(bitparse_init(bit_start, bit_end)) {
/* Successfully initialized the .bit parser. Find the 'e' section and
* send its contents to the FPGA.
*/
@ -351,6 +367,17 @@ void FpgaDownloadAndGo(void)
DownloadFPGA((char*)0x102000, 10524*4, 1);
}
int FpgaGatherBitstreamVersion()
{
char temp[256];
FpgaGatherVersion(temp, sizeof (temp));
if (!memcmp("LF", temp, 2))
return FPGA_BITSTREAM_LF;
else if (!memcmp("HF", temp, 2))
return FPGA_BITSTREAM_HF;
return FPGA_BITSTREAM_ERR;
}
void FpgaGatherVersion(char *dst, int len)
{
char *fpga_info;
@ -359,13 +386,15 @@ void FpgaGatherVersion(char *dst, int len)
if(!bitparse_find_section('e', &fpga_info, &fpga_info_len)) {
strncat(dst, "FPGA image: legacy image without version information", len-1);
} else {
strncat(dst, "FPGA image built", len-1);
/* USB packets only have 48 bytes data payload, so be terse */
#if 0
if(bitparse_find_section('a', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) {
strncat(dst, " from ", len-1);
strncat(dst, fpga_info, len-1);
if (!memcmp("fpga_lf", fpga_info, 7))
strncat(dst, "LF ", len-1);
else if (!memcmp("fpga_hf", fpga_info, 7))
strncat(dst, "HF ", len-1);
}
strncat(dst, "FPGA image built", len-1);
#if 0
if(bitparse_find_section('b', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) {
strncat(dst, " for ", len-1);
strncat(dst, fpga_info, len-1);

View file

@ -743,6 +743,7 @@ void SnoopHitag(uint32_t type) {
// Set up eavesdropping mode, frequency divisor which will drive the FPGA
// and analog mux selection.
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
@ -966,6 +967,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) {
// Set up simulator mode, frequency divisor which will drive the FPGA
// and analog mux selection.
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
@ -1124,6 +1126,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
bool bStop;
bool bQuitTraceFull = false;
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
// Reset the return status
bSuccessful = false;

View file

@ -41,24 +41,15 @@
#include "util.h"
#include "string.h"
#include "common.h"
#include "cmd.h"
// Needed for CRC in emulation mode;
// same construction as in ISO 14443;
// different initial value (CRC_ICLASS)
#include "iso14443crc.h"
#include "iso15693tools.h"
static int timeout = 4096;
// CARD TO READER
// Sequence D: 11110000 modulation with subcarrier during first half
// Sequence E: 00001111 modulation with subcarrier during second half
// Sequence F: 00000000 no modulation with subcarrier
// READER TO CARD
// Sequence X: 00001100 drop after half a period
// Sequence Y: 00000000 no drop
// Sequence Z: 11000000 drop at start
#define SEC_X 0x0c
#define SEC_Y 0x00
#define SEC_Z 0xc0
static int SendIClassAnswer(uint8_t *resp, int respLen, int delay);
@ -666,12 +657,7 @@ static RAMFUNC int ManchesterDecoding(int v)
//-----------------------------------------------------------------------------
void RAMFUNC SnoopIClass(void)
{
// DEFINED ABOVE
// #define RECV_CMD_OFFSET 3032
// #define RECV_RES_OFFSET 3096
// #define DMA_BUFFER_OFFSET 3160
// #define DMA_BUFFER_SIZE 4096
// #define TRACE_SIZE 3000
// We won't start recording the frames that we acquire until we trigger;
// a good trigger condition to get started is probably when we see a
@ -681,14 +667,12 @@ void RAMFUNC SnoopIClass(void)
// The command (reader -> tag) that we're receiving.
// The length of a received command will in most cases be no more than 18 bytes.
// So 32 should be enough!
uint8_t *receivedCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET);
uint8_t *readerToTagCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET);
// The response (tag -> reader) that we're receiving.
uint8_t *receivedResponse = (((uint8_t *)BigBuf) + RECV_RES_OFFSET);
uint8_t *tagToReaderResponse = (((uint8_t *)BigBuf) + RECV_RES_OFFSET);
// As we receive stuff, we copy it from receivedCmd or receivedResponse
// into trace, along with its length and other annotations.
//uint8_t *trace = (uint8_t *)BigBuf;
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// reset traceLen to 0
iso14a_set_tracing(TRUE);
iso14a_clear_trace();
@ -706,10 +690,8 @@ void RAMFUNC SnoopIClass(void)
int samples = 0;
rsamples = 0;
memset(trace, 0x44, RECV_CMD_OFFSET);
// Set up the demodulator for tag -> reader responses.
Demod.output = receivedResponse;
Demod.output = tagToReaderResponse;
Demod.len = 0;
Demod.state = DEMOD_UNSYNCD;
@ -721,7 +703,7 @@ void RAMFUNC SnoopIClass(void)
// And the reader -> tag commands
memset(&Uart, 0, sizeof(Uart));
Uart.output = receivedCmd;
Uart.output = readerToTagCmd;
Uart.byteCntMax = 32; // was 100 (greg)////////////////////////////////////////////////////////////////////////
Uart.state = STATE_UNSYNCD;
@ -731,6 +713,9 @@ void RAMFUNC SnoopIClass(void)
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_SNIFFER);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
uint32_t time_0 = GetCountSspClk();
int div = 0;
//int div2 = 0;
int decbyte = 0;
@ -764,20 +749,13 @@ void RAMFUNC SnoopIClass(void)
//samples += 4;
samples += 1;
//div2++;
//if(div2 > 3) {
//div2 = 0;
//decbyte ^= ((smpl & 0x01) << (3 - div));
//decbyte ^= (((smpl & 0x01) | ((smpl & 0x02) >> 1)) << (3 - div)); // better already...
//decbyte ^= (((smpl & 0x01) | ((smpl & 0x02) >> 1) | ((smpl & 0x04) >> 2)) << (3 - div)); // even better...
if(smpl & 0xF) {
decbyte ^= (1 << (3 - div));
}
//decbyte ^= (MajorityNibble[(smpl & 0x0F)] << (3 - div));
// FOR READER SIDE COMMUMICATION...
//decbyte ^= ((smpl & 0x10) << (3 - div));
decbyter <<= 2;
decbyter ^= (smpl & 0x30);
@ -788,21 +766,17 @@ void RAMFUNC SnoopIClass(void)
if(OutOfNDecoding((smpl & 0xF0) >> 4)) {
rsamples = samples - Uart.samples;
LED_C_ON();
//if(triggered) {
trace[traceLen++] = ((rsamples >> 0) & 0xff);
trace[traceLen++] = ((rsamples >> 8) & 0xff);
trace[traceLen++] = ((rsamples >> 16) & 0xff);
trace[traceLen++] = ((rsamples >> 24) & 0xff);
trace[traceLen++] = ((Uart.parityBits >> 0) & 0xff);
trace[traceLen++] = ((Uart.parityBits >> 8) & 0xff);
trace[traceLen++] = ((Uart.parityBits >> 16) & 0xff);
trace[traceLen++] = ((Uart.parityBits >> 24) & 0xff);
trace[traceLen++] = Uart.byteCnt;
memcpy(trace+traceLen, receivedCmd, Uart.byteCnt);
traceLen += Uart.byteCnt;
if(traceLen > TRACE_SIZE) break;
//}
/* And ready to receive another command. */
//if(!LogTrace(Uart.output,Uart.byteCnt, rsamples, Uart.parityBits,TRUE)) break;
//if(!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, TRUE)) break;
if(tracing)
{
LogTrace(Uart.output,Uart.byteCnt, (GetCountSspClk()-time_0) << 4, Uart.parityBits,TRUE);
LogTrace(NULL, 0, (GetCountSspClk()-time_0) << 4, 0, TRUE);
}
/* And ready to receive another command. */
Uart.state = STATE_UNSYNCD;
/* And also reset the demod code, which might have been */
/* false-triggered by the commands from the reader. */
@ -819,26 +793,16 @@ void RAMFUNC SnoopIClass(void)
rsamples = samples - Demod.samples;
LED_B_ON();
// timestamp, as a count of samples
trace[traceLen++] = ((rsamples >> 0) & 0xff);
trace[traceLen++] = ((rsamples >> 8) & 0xff);
trace[traceLen++] = ((rsamples >> 16) & 0xff);
trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff);
trace[traceLen++] = ((Demod.parityBits >> 0) & 0xff);
trace[traceLen++] = ((Demod.parityBits >> 8) & 0xff);
trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff);
trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff);
// length
trace[traceLen++] = Demod.len;
memcpy(trace+traceLen, receivedResponse, Demod.len);
traceLen += Demod.len;
if(traceLen > TRACE_SIZE) break;
if(tracing)
{
LogTrace(Demod.output,Demod.len, (GetCountSspClk()-time_0) << 4 , Demod.parityBits,FALSE);
LogTrace(NULL, 0, (GetCountSspClk()-time_0) << 4, 0, FALSE);
}
//triggered = TRUE;
// And ready to receive another response.
memset(&Demod, 0, sizeof(Demod));
Demod.output = receivedResponse;
Demod.output = tagToReaderResponse;
Demod.state = DEMOD_UNSYNCD;
LED_C_OFF();
}
@ -922,6 +886,8 @@ static int GetIClassCommandFromReader(uint8_t *received, int *len, int maxLen)
//-----------------------------------------------------------------------------
static void CodeIClassTagAnswer(const uint8_t *cmd, int len)
{
//So far a dummy implementation, not used
//int lastProxToAirDuration =0;
int i;
ToSendReset();
@ -930,7 +896,7 @@ static void CodeIClassTagAnswer(const uint8_t *cmd, int len)
ToSend[++ToSendMax] = 0x00;
ToSend[++ToSendMax] = 0x00;
ToSend[++ToSendMax] = 0x00;
ToSend[++ToSendMax] = 0xff;
ToSend[++ToSendMax] = 0xff;//Proxtoair duration starts here
ToSend[++ToSendMax] = 0xff;
ToSend[++ToSendMax] = 0xff;
ToSend[++ToSendMax] = 0x00;
@ -958,11 +924,13 @@ static void CodeIClassTagAnswer(const uint8_t *cmd, int len)
ToSend[++ToSendMax] = 0x00;
ToSend[++ToSendMax] = 0xff;
ToSend[++ToSendMax] = 0xff;
ToSend[++ToSendMax] = 0xff;
ToSend[++ToSendMax] = 0xff;
ToSend[++ToSendMax] = 0x00;
ToSend[++ToSendMax] = 0x00;
ToSend[++ToSendMax] = 0x00;
//lastProxToAirDuration = 8*ToSendMax - 3*8 - 3*8;//Not counting zeroes in the beginning or end
// Convert from last byte pos to length
ToSendMax++;
}
@ -970,8 +938,10 @@ static void CodeIClassTagAnswer(const uint8_t *cmd, int len)
// Only SOF
static void CodeIClassTagSOF()
{
ToSendReset();
//So far a dummy implementation, not used
//int lastProxToAirDuration =0;
ToSendReset();
// Send SOF
ToSend[++ToSendMax] = 0x00;
ToSend[++ToSendMax] = 0x00;
@ -981,37 +951,92 @@ static void CodeIClassTagSOF()
ToSend[++ToSendMax] = 0xff;
ToSend[++ToSendMax] = 0x00;
ToSend[++ToSendMax] = 0xff;
// lastProxToAirDuration = 8*ToSendMax - 3*8;//Not counting zeroes in the beginning
// Convert from last byte pos to length
ToSendMax++;
}
//-----------------------------------------------------------------------------
// Simulate iClass Card
// Only CSN (Card Serial Number)
//
//-----------------------------------------------------------------------------
void SimulateIClass(uint8_t arg0, uint8_t *datain)
int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader_mac_buf);
/**
* @brief SimulateIClass simulates an iClass card.
* @param arg0 type of simulation
* - 0 uses the first 8 bytes in usb data as CSN
* - 2 "dismantling iclass"-attack. This mode iterates through all CSN's specified
* in the usb data. This mode collects MAC from the reader, in order to do an offline
* attack on the keys. For more info, see "dismantling iclass" and proxclone.com.
* - Other : Uses the default CSN (031fec8af7ff12e0)
* @param arg1 - number of CSN's contained in datain (applicable for mode 2 only)
* @param arg2
* @param datain
*/
void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain)
{
uint32_t simType = arg0;
uint32_t numberOfCSNS = arg1;
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Enable and clear the trace
iso14a_set_tracing(TRUE);
iso14a_clear_trace();
uint8_t csn_crc[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 };
if(simType == 0) {
// Use the CSN from commandline
memcpy(csn_crc, datain, 8);
doIClassSimulation(csn_crc,0,NULL);
}else if(simType == 1)
{
doIClassSimulation(csn_crc,0,NULL);
}
else if(simType == 2)
{
uint8_t mac_responses[64] = { 0 };
Dbprintf("Going into attack mode");
// In this mode, a number of csns are within datain. We'll simulate each one, one at a time
// in order to collect MAC's from the reader. This can later be used in an offlne-attack
// in order to obtain the keys, as in the "dismantling iclass"-paper.
int i = 0;
for( ; i < numberOfCSNS && i*8+8 < USB_CMD_DATA_SIZE; i++)
{
// The usb data is 512 bytes, fitting 65 8-byte CSNs in there.
memcpy(csn_crc, datain+(i*8), 8);
if(doIClassSimulation(csn_crc,1,mac_responses))
{
return; // Button pressed
}
}
cmd_send(CMD_ACK,CMD_SIMULATE_TAG_ICLASS,i,0,mac_responses,i*8);
}
else{
// We may want a mode here where we hardcode the csns to use (from proxclone).
// That will speed things up a little, but not required just yet.
Dbprintf("The mode is not implemented, reserved for future use");
}
Dbprintf("Done...");
}
/**
* @brief Does the actual simulation
* @param csn - csn to use
* @param breakAfterMacReceived if true, returns after reader MAC has been received.
*/
int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived, uint8_t *reader_mac_buf)
{
uint8_t simType = arg0;
// Enable and clear the trace
tracing = TRUE;
traceLen = 0;
memset(trace, 0x44, TRACE_SIZE);
// CSN followed by two CRC bytes
uint8_t response2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t response3[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 };
uint8_t response3[] = { 0,0,0,0,0,0,0,0,0,0};
memcpy(response3,csn,sizeof(response3));
Dbprintf("Simulating CSN %02x%02x%02x%02x%02x%02x%02x%02x",csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]);
// e-Purse
uint8_t response4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
if(simType == 0) {
// Use the CSN from commandline
memcpy(response3, datain, 8);
}
// Construct anticollision-CSN
rotateCSN(response3,response2);
@ -1019,6 +1044,7 @@ void SimulateIClass(uint8_t arg0, uint8_t *datain)
ComputeCrc14443(CRC_ICLASS, response2, 8, &response2[8], &response2[9]);
ComputeCrc14443(CRC_ICLASS, response3, 8, &response3[8], &response3[9]);
int exitLoop = 0;
// Reader 0a
// Tag 0f
// Reader 0c
@ -1052,7 +1078,7 @@ void SimulateIClass(uint8_t arg0, uint8_t *datain)
int resp4Len;
// + 1720..
uint8_t *receivedCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET);
uint8_t *receivedCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET);
memset(receivedCmd, 0x44, RECV_CMD_SIZE);
int len;
@ -1075,29 +1101,52 @@ void SimulateIClass(uint8_t arg0, uint8_t *datain)
CodeIClassTagAnswer(response4, sizeof(response4));
memcpy(resp4, ToSend, ToSendMax); resp4Len = ToSendMax;
// Start from off (no field generated)
//FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
//SpinDelay(200);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN);
SpinDelay(100);
StartCountSspClk();
// We need to listen to the high-frequency, peak-detected path.
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc();
// To control where we are in the protocol
int cmdsRecvd = 0;
uint32_t time_0 = GetCountSspClk();
uint32_t t2r_time =0;
uint32_t r2t_time =0;
LED_A_ON();
for(;;) {
bool buttonPressed = false;
/** Hack for testing
memcpy(reader_mac_buf,csn,8);
exitLoop = true;
end hack **/
while(!exitLoop) {
LED_B_OFF();
//Signal tracer
// Can be used to get a trigger for an oscilloscope..
LED_C_OFF();
if(!GetIClassCommandFromReader(receivedCmd, &len, 100)) {
DbpString("button press");
buttonPressed = true;
break;
}
r2t_time = GetCountSspClk();
//Signal tracer
LED_C_ON();
// Okay, look at the command now.
if(receivedCmd[0] == 0x0a) {
if(receivedCmd[0] == 0x0a ) {
// Reader in anticollission phase
resp = resp1; respLen = resp1Len; //order = 1;
respdata = &sof;
respsize = sizeof(sof);
//resp = resp2; respLen = resp2Len; order = 2;
//DbpString("Hello request from reader:");
} else if(receivedCmd[0] == 0x0c) {
// Reader asks for anticollission CSN
resp = resp2; respLen = resp2Len; //order = 2;
@ -1119,30 +1168,31 @@ void SimulateIClass(uint8_t arg0, uint8_t *datain)
LED_B_ON();
} else if(receivedCmd[0] == 0x05) {
// Reader random and reader MAC!!!
// Lets store this ;-)
/*
Dbprintf(" CSN: %02x %02x %02x %02x %02x %02x %02x %02x",
response3[0], response3[1], response3[2],
response3[3], response3[4], response3[5],
response3[6], response3[7]);
*/
Dbprintf("READER AUTH (len=%02d): %02x %02x %02x %02x %02x %02x %02x %02x %02x",
len,
receivedCmd[0], receivedCmd[1], receivedCmd[2],
receivedCmd[3], receivedCmd[4], receivedCmd[5],
receivedCmd[6], receivedCmd[7], receivedCmd[8]);
// Do not respond
// We do not know what to answer, so lets keep quit
// We do not know what to answer, so lets keep quiet
resp = resp1; respLen = 0; //order = 5;
respdata = NULL;
respsize = 0;
if (breakAfterMacReceived){
// dbprintf:ing ...
Dbprintf("CSN: %02x %02x %02x %02x %02x %02x %02x %02x",csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]);
Dbprintf("RDR: (len=%02d): %02x %02x %02x %02x %02x %02x %02x %02x %02x",len,
receivedCmd[0], receivedCmd[1], receivedCmd[2],
receivedCmd[3], receivedCmd[4], receivedCmd[5],
receivedCmd[6], receivedCmd[7], receivedCmd[8]);
if (reader_mac_buf != NULL)
{
memcpy(reader_mac_buf,receivedCmd+1,8);
}
exitLoop = true;
}
} else if(receivedCmd[0] == 0x00 && len == 1) {
// Reader ends the session
resp = resp1; respLen = 0; //order = 0;
respdata = NULL;
respsize = 0;
} else {
//#db# Unknown command received from reader (len=5): 26 1 0 f6 a 44 44 44 44
// Never seen this command before
Dbprintf("Unknown command received from reader (len=%d): %x %x %x %x %x %x %x %x %x",
len,
@ -1155,9 +1205,9 @@ void SimulateIClass(uint8_t arg0, uint8_t *datain)
respsize = 0;
}
if(cmdsRecvd > 999) {
DbpString("1000 commands later...");
break;
if(cmdsRecvd > 100) {
//DbpString("100 commands later...");
//break;
}
else {
cmdsRecvd++;
@ -1165,64 +1215,68 @@ void SimulateIClass(uint8_t arg0, uint8_t *datain)
if(respLen > 0) {
SendIClassAnswer(resp, respLen, 21);
}
if (tracing) {
LogTrace(receivedCmd,len, rsamples, Uart.parityBits, TRUE);
if (respdata != NULL) {
LogTrace(respdata,respsize, rsamples, SwapBits(GetParity(respdata,respsize),respsize), FALSE);
}
if(traceLen > TRACE_SIZE) {
DbpString("Trace full");
break;
}
t2r_time = GetCountSspClk();
}
if (tracing) {
LogTrace(receivedCmd,len, (r2t_time-time_0)<< 4, Uart.parityBits,TRUE);
LogTrace(NULL,0, (r2t_time-time_0) << 4, 0,TRUE);
if (respdata != NULL) {
LogTrace(respdata,respsize, (t2r_time-time_0) << 4,SwapBits(GetParity(respdata,respsize),respsize),FALSE);
LogTrace(NULL,0, (t2r_time-time_0) << 4,0,FALSE);
}
if(!tracing) {
DbpString("Trace full");
//break;
}
}
memset(receivedCmd, 0x44, RECV_CMD_SIZE);
}
Dbprintf("%x", cmdsRecvd);
//Dbprintf("%x", cmdsRecvd);
LED_A_OFF();
LED_B_OFF();
if(buttonPressed)
{
DbpString("Button pressed");
}
return buttonPressed;
}
static int SendIClassAnswer(uint8_t *resp, int respLen, int delay)
{
int i = 0, u = 0, d = 0;
int i = 0, d=0;//, u = 0, d = 0;
uint8_t b = 0;
// return 0;
// Modulate Manchester
// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD424);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K);
AT91C_BASE_SSC->SSC_THR = 0x00;
FpgaSetupSsc();
// send cycle
for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
volatile uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
(void)b;
while(!BUTTON_PRESS()) {
if((AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)){
b = AT91C_BASE_SSC->SSC_RHR; (void) b;
}
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)){
b = 0x00;
if(d < delay) {
b = 0x00;
d++;
}
else if(i >= respLen) {
b = 0x00;
u++;
} else {
b = resp[i];
u++;
if(u > 1) { i++; u = 0; }
else {
if( i < respLen){
b = resp[i];
//Hack
//b = 0xAC;
}
i++;
}
AT91C_BASE_SSC->SSC_THR = b;
}
if(u > 4) break;
}
if(BUTTON_PRESS()) {
break;
}
if (i > respLen +4) break;
}
return 0;
@ -1236,7 +1290,6 @@ static int SendIClassAnswer(uint8_t *resp, int respLen, int delay)
static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int *wait)
{
int c;
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
AT91C_BASE_SSC->SSC_THR = 0x00;
FpgaSetupSsc();
@ -1312,12 +1365,12 @@ void CodeIClassCommand(const uint8_t * cmd, int len)
b = cmd[i];
for(j = 0; j < 4; j++) {
for(k = 0; k < 4; k++) {
if(k == (b & 3)) {
ToSend[++ToSendMax] = 0x0f;
}
else {
ToSend[++ToSendMax] = 0x00;
}
if(k == (b & 3)) {
ToSend[++ToSendMax] = 0x0f;
}
else {
ToSend[++ToSendMax] = 0x00;
}
}
b >>= 2;
}
@ -1413,36 +1466,138 @@ int ReaderReceiveIClass(uint8_t* receivedAnswer)
return Demod.len;
}
void setupIclassReader()
{
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Reset trace buffer
iso14a_set_tracing(TRUE);
iso14a_clear_trace();
// Setup SSC
FpgaSetupSsc();
// Start from off (no field generated)
// Signal field is off with the appropriate LED
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(200);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Now give it time to spin up.
// Signal field is on with the appropriate LED
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
SpinDelay(200);
LED_A_ON();
}
// Reader iClass Anticollission
void ReaderIClass(uint8_t arg0) {
uint8_t act_all[] = { 0x0a };
uint8_t identify[] = { 0x0c };
uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t readcheck_cc[]= { 0x88, 0x02 };
uint8_t card_data[24]={0};
uint8_t last_csn[8]={0};
uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes
int read_status= 0;
bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE;
setupIclassReader();
size_t datasize = 0;
while(!BUTTON_PRESS())
{
WDT_HIT();
// Send act_all
ReaderTransmitIClass(act_all, 1);
// Card present?
if(ReaderReceiveIClass(resp)) {
ReaderTransmitIClass(identify, 1);
if(ReaderReceiveIClass(resp) == 10) {
//Copy the Anti-collision CSN to our select-packet
memcpy(&select[1],resp,8);
//Dbprintf("Anti-collision CSN: %02x %02x %02x %02x %02x %02x %02x %02x",resp[0], resp[1], resp[2],
// resp[3], resp[4], resp[5],
// resp[6], resp[7]);
//Select the card
ReaderTransmitIClass(select, sizeof(select));
if(ReaderReceiveIClass(resp) == 10) {
//Save CSN in response data
memcpy(card_data,resp,8);
datasize += 8;
//Flag that we got to at least stage 1, read CSN
read_status = 1;
// Card selected
//Dbprintf("Readcheck on Sector 2");
ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
if(ReaderReceiveIClass(resp) == 8) {
//Save CC (e-purse) in response data
memcpy(card_data+8,resp,8);
datasize += 8;
//Got both
read_status = 2;
}
LED_B_ON();
//Send back to client, but don't bother if we already sent this
if(memcmp(last_csn, card_data, 8) != 0)
cmd_send(CMD_ACK,read_status,0,0,card_data,datasize);
//Save that we already sent this....
if(read_status == 2)
memcpy(last_csn, card_data, 8);
LED_B_OFF();
if(abort_after_read) break;
}
}
}
if(traceLen > TRACE_SIZE) {
DbpString("Trace full");
break;
}
}
LED_A_OFF();
}
void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) {
uint8_t act_all[] = { 0x0a };
uint8_t identify[] = { 0x0c };
uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t readcheck_cc[]= { 0x88, 0x02 };
uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 };
uint16_t crc = 0;
uint8_t cardsize=0;
bool read_success=false;
uint8_t mem=0;
static struct memory_t{
int k16;
int book;
int k2;
int lockauth;
int keyaccess;
} memory;
uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes
// Reset trace buffer
memset(trace, 0x44, RECV_CMD_OFFSET);
traceLen = 0;
setupIclassReader();
// Setup SSC
FpgaSetupSsc();
// Start from off (no field generated)
// Signal field is off with the appropriate LED
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(200);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Now give it time to spin up.
// Signal field is on with the appropriate LED
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
SpinDelay(200);
LED_A_ON();
for(;;) {
for(int i=0;i<1;i++) {
if(traceLen > TRACE_SIZE) {
DbpString("Trace full");
@ -1467,7 +1622,72 @@ void ReaderIClass(uint8_t arg0) {
resp[3], resp[4], resp[5],
resp[6], resp[7]);
}
// Card selected, whats next... ;-)
// Card selected
Dbprintf("Readcheck on Sector 2");
ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
if(ReaderReceiveIClass(resp) == 8) {
Dbprintf(" CC: %02x %02x %02x %02x %02x %02x %02x %02x",
resp[0], resp[1], resp[2],
resp[3], resp[4], resp[5],
resp[6], resp[7]);
}else return;
Dbprintf("Authenticate");
//for now replay captured auth (as cc not updated)
memcpy(check+5,MAC,4);
//Dbprintf(" AA: %02x %02x %02x %02x",
// check[5], check[6], check[7],check[8]);
ReaderTransmitIClass(check, sizeof(check));
if(ReaderReceiveIClass(resp) == 4) {
Dbprintf(" AR: %02x %02x %02x %02x",
resp[0], resp[1], resp[2],resp[3]);
}else {
Dbprintf("Error: Authentication Fail!");
return;
}
Dbprintf("Dump Contents");
//first get configuration block
read_success=false;
read[1]=1;
uint8_t *blockno=&read[1];
crc = iclass_crc16((char *)blockno,1);
read[2] = crc >> 8;
read[3] = crc & 0xff;
while(!read_success){
ReaderTransmitIClass(read, sizeof(read));
if(ReaderReceiveIClass(resp) == 10) {
read_success=true;
mem=resp[5];
memory.k16= (mem & 0x80);
memory.book= (mem & 0x20);
memory.k2= (mem & 0x8);
memory.lockauth= (mem & 0x2);
memory.keyaccess= (mem & 0x1);
}
}
if (memory.k16){
cardsize=255;
}else cardsize=32;
//then loop around remaining blocks
for(uint8_t j=0; j<cardsize; j++){
read_success=false;
uint8_t *blockno=&j;
//crc_data[0]=j;
read[1]=j;
crc = iclass_crc16((char *)blockno,1);
read[2] = crc >> 8;
read[3] = crc & 0xff;
while(!read_success){
ReaderTransmitIClass(read, sizeof(read));
if(ReaderReceiveIClass(resp) == 10) {
read_success=true;
Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x",
j, resp[0], resp[1], resp[2],
resp[3], resp[4], resp[5],
resp[6], resp[7]);
}
}
}
}
}
WDT_HIT();
@ -1476,4 +1696,130 @@ void ReaderIClass(uint8_t arg0) {
LED_A_OFF();
}
//2. Create Read method (cut-down from above) based off responses from 1.
// Since we have the MAC could continue to use replay function.
//3. Create Write method
/*
void IClass_iso14443A_write(uint8_t arg0, uint8_t blockNo, uint8_t *data, uint8_t *MAC) {
uint8_t act_all[] = { 0x0a };
uint8_t identify[] = { 0x0c };
uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t readcheck_cc[]= { 0x88, 0x02 };
uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 };
uint8_t write[] = { 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint16_t crc = 0;
uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes
// Reset trace buffer
memset(trace, 0x44, RECV_CMD_OFFSET);
traceLen = 0;
// Setup SSC
FpgaSetupSsc();
// Start from off (no field generated)
// Signal field is off with the appropriate LED
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(200);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Now give it time to spin up.
// Signal field is on with the appropriate LED
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
SpinDelay(200);
LED_A_ON();
for(int i=0;i<1;i++) {
if(traceLen > TRACE_SIZE) {
DbpString("Trace full");
break;
}
if (BUTTON_PRESS()) break;
// Send act_all
ReaderTransmitIClass(act_all, 1);
// Card present?
if(ReaderReceiveIClass(resp)) {
ReaderTransmitIClass(identify, 1);
if(ReaderReceiveIClass(resp) == 10) {
// Select card
memcpy(&select[1],resp,8);
ReaderTransmitIClass(select, sizeof(select));
if(ReaderReceiveIClass(resp) == 10) {
Dbprintf(" Selected CSN: %02x %02x %02x %02x %02x %02x %02x %02x",
resp[0], resp[1], resp[2],
resp[3], resp[4], resp[5],
resp[6], resp[7]);
}
// Card selected
Dbprintf("Readcheck on Sector 2");
ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
if(ReaderReceiveIClass(resp) == 8) {
Dbprintf(" CC: %02x %02x %02x %02x %02x %02x %02x %02x",
resp[0], resp[1], resp[2],
resp[3], resp[4], resp[5],
resp[6], resp[7]);
}else return;
Dbprintf("Authenticate");
//for now replay captured auth (as cc not updated)
memcpy(check+5,MAC,4);
Dbprintf(" AA: %02x %02x %02x %02x",
check[5], check[6], check[7],check[8]);
ReaderTransmitIClass(check, sizeof(check));
if(ReaderReceiveIClass(resp) == 4) {
Dbprintf(" AR: %02x %02x %02x %02x",
resp[0], resp[1], resp[2],resp[3]);
}else {
Dbprintf("Error: Authentication Fail!");
return;
}
Dbprintf("Write Block");
//read configuration for max block number
read_success=false;
read[1]=1;
uint8_t *blockno=&read[1];
crc = iclass_crc16((char *)blockno,1);
read[2] = crc >> 8;
read[3] = crc & 0xff;
while(!read_success){
ReaderTransmitIClass(read, sizeof(read));
if(ReaderReceiveIClass(resp) == 10) {
read_success=true;
mem=resp[5];
memory.k16= (mem & 0x80);
memory.book= (mem & 0x20);
memory.k2= (mem & 0x8);
memory.lockauth= (mem & 0x2);
memory.keyaccess= (mem & 0x1);
}
}
if (memory.k16){
cardsize=255;
}else cardsize=32;
//check card_size
memcpy(write+1,blockNo,1);
memcpy(write+2,data,8);
memcpy(write+10,mac,4);
while(!send_success){
ReaderTransmitIClass(write, sizeof(write));
if(ReaderReceiveIClass(resp) == 10) {
write_success=true;
}
}//
}
WDT_HIT();
}
LED_A_OFF();
}*/

View file

@ -350,6 +350,7 @@ void SimulateIso14443Tag(void)
int cmdsRecvd = 0;
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
memset(receivedCmd, 0x44, 400);
CodeIso14443bAsTag(response1, sizeof(response1));
@ -867,6 +868,7 @@ void ReadSTMemoryIso14443(uint32_t dwLast)
{
uint8_t i = 0x00;
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Make sure that we start from off, since the tags are stateful;
// confusing things will happen if we don't reset them between reads.
LED_D_OFF();
@ -1011,6 +1013,7 @@ void RAMFUNC SnoopIso14443(void)
// response from the tag.
int triggered = TRUE;
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// The command (reader -> tag) that we're working on receiving.
uint8_t *receivedCmd = (uint8_t *)(BigBuf) + DEMOD_TRACE_SIZE;
// The response (tag -> reader) that we're working on receiving.
@ -1196,6 +1199,7 @@ done:
void SendRawCommand14443B(uint32_t datalen, uint32_t recv,uint8_t powerfield, uint8_t data[])
{
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
if(!powerfield)
{
// Make sure that we start from off, since the tags are stateful;

View file

@ -190,8 +190,9 @@ void AppendCrc14443a(uint8_t* data, int len)
}
// The function LogTrace() is also used by the iClass implementation in iClass.c
bool RAMFUNC LogTrace(const uint8_t * btBytes, uint8_t iLen, uint32_t timestamp, uint32_t dwParity, bool bReader)
bool RAMFUNC LogTrace(const uint8_t * btBytes, uint8_t iLen, uint32_t timestamp, uint32_t dwParity, bool readerToTag)
{
if (!tracing) return FALSE;
// Return when trace is full
if (traceLen + sizeof(timestamp) + sizeof(dwParity) + iLen >= TRACE_SIZE) {
tracing = FALSE; // don't trace any more
@ -203,7 +204,8 @@ bool RAMFUNC LogTrace(const uint8_t * btBytes, uint8_t iLen, uint32_t timestamp,
trace[traceLen++] = ((timestamp >> 8) & 0xff);
trace[traceLen++] = ((timestamp >> 16) & 0xff);
trace[traceLen++] = ((timestamp >> 24) & 0xff);
if (!bReader) {
if (!readerToTag) {
trace[traceLen - 1] |= 0x80;
}
trace[traceLen++] = ((dwParity >> 0) & 0xff);
@ -505,6 +507,7 @@ void RAMFUNC SnoopIso14443a(uint8_t param) {
LEDsoff();
// init trace buffer
iso14a_clear_trace();
iso14a_set_tracing(TRUE);
// We won't start recording the frames that we acquire until we trigger;
// a good trigger condition to get started is probably when we see a
@ -1763,6 +1766,7 @@ int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, u
}
void iso14443a_setup(uint8_t fpga_minor_mode) {
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Set up the synchronous serial port
FpgaSetupSsc();
// connect Demodulated Signal to ADC:
@ -1858,6 +1862,7 @@ void ReaderIso14443a(UsbCommand *c)
if(param & ISO14A_APPEND_CRC) {
AppendCrc14443a(cmd,len);
len += 2;
if (lenbits) lenbits += 16;
}
if(lenbits>0) {
ReaderTransmitBitsPar(cmd,lenbits,GetParity(cmd,lenbits/8), NULL);
@ -2201,9 +2206,12 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
if (MF_DBGLEVEL >= 1) {
if (!_7BUID) {
Dbprintf("4B UID: %02x%02x%02x%02x",rUIDBCC1[0] , rUIDBCC1[1] , rUIDBCC1[2] , rUIDBCC1[3]);
Dbprintf("4B UID: %02x%02x%02x%02x",
rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3]);
} else {
Dbprintf("7B UID: (%02x)%02x%02x%02x%02x%02x%02x%02x",rUIDBCC1[0] , rUIDBCC1[1] , rUIDBCC1[2] , rUIDBCC1[3],rUIDBCC2[0],rUIDBCC2[1] ,rUIDBCC2[2] , rUIDBCC2[3]);
Dbprintf("7B UID: (%02x)%02x%02x%02x%02x%02x%02x%02x",
rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3],
rUIDBCC2[0], rUIDBCC2[1] ,rUIDBCC2[2], rUIDBCC2[3]);
}
}
@ -2271,7 +2279,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
// select card
if (len == 9 &&
(receivedCmd[0] == 0x93 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC1, 4) == 0)) {
EmSendCmd(_7BUID?rSAK1:rSAK, sizeof(_7BUID?rSAK1:rSAK));
EmSendCmd(_7BUID?rSAK1:rSAK, _7BUID?sizeof(rSAK1):sizeof(rSAK));
cuid = bytes_to_num(rUIDBCC1, 4);
if (!_7BUID) {
cardSTATE = MFEMUL_WORK;
@ -2313,10 +2321,13 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
// test if auth OK
if (cardRr != prng_successor(nonce, 64)){
if (MF_DBGLEVEL >= 2) Dbprintf("AUTH FAILED. cardRr=%08x, succ=%08x",cardRr, prng_successor(nonce, 64));
if (MF_DBGLEVEL >= 2) Dbprintf("AUTH FAILED for sector %d with key %c. cardRr=%08x, succ=%08x",
cardAUTHSC, cardAUTHKEY == 0 ? 'A' : 'B',
cardRr, prng_successor(nonce, 64));
// Shouldn't we respond anything here?
// Right now, we don't nack or anything, which causes the
// reader to do a WUPA after a while. /Martin
// -- which is the correct response. /piwi
cardSTATE_TO_IDLE();
LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE);
LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE);
@ -2330,7 +2341,9 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT));
LED_C_ON();
cardSTATE = MFEMUL_WORK;
if (MF_DBGLEVEL >= 4) Dbprintf("AUTH COMPLETED. sector=%d, key=%d time=%d", cardAUTHSC, cardAUTHKEY, GetTickCount() - authTimer);
if (MF_DBGLEVEL >= 4) Dbprintf("AUTH COMPLETED for sector %d with key %c. time=%d",
cardAUTHSC, cardAUTHKEY == 0 ? 'A' : 'B',
GetTickCount() - authTimer);
break;
}
case MFEMUL_SELECT2:{
@ -2388,12 +2401,12 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
crypto1_create(pcs, emlGetKey(cardAUTHSC, cardAUTHKEY));
if (!encrypted_data) { // first authentication
if (MF_DBGLEVEL >= 2) Dbprintf("Reader authenticating for block %d (0x%02x) with key %d",receivedCmd[1] ,receivedCmd[1],cardAUTHKEY );
if (MF_DBGLEVEL >= 4) Dbprintf("Reader authenticating for block %d (0x%02x) with key %d",receivedCmd[1] ,receivedCmd[1],cardAUTHKEY );
crypto1_word(pcs, cuid ^ nonce, 0);//Update crypto state
num_to_bytes(nonce, 4, rAUTH_AT); // Send nonce
} else { // nested authentication
if (MF_DBGLEVEL >= 2) Dbprintf("Reader doing nested authentication for block %d (0x%02x) with key %d",receivedCmd[1] ,receivedCmd[1],cardAUTHKEY );
if (MF_DBGLEVEL >= 4) Dbprintf("Reader doing nested authentication for block %d (0x%02x) with key %d",receivedCmd[1] ,receivedCmd[1],cardAUTHKEY );
ans = nonce ^ crypto1_word(pcs, cuid ^ nonce, 0);
num_to_bytes(ans, 4, rAUTH_AT);
}
@ -2424,9 +2437,9 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
if(receivedCmd[0] == 0x30 // read block
|| receivedCmd[0] == 0xA0 // write block
|| receivedCmd[0] == 0xC0
|| receivedCmd[0] == 0xC1
|| receivedCmd[0] == 0xC2 // inc dec restore
|| receivedCmd[0] == 0xC0 // inc
|| receivedCmd[0] == 0xC1 // dec
|| receivedCmd[0] == 0xC2 // restore
|| receivedCmd[0] == 0xB0) { // transfer
if (receivedCmd[1] >= 16 * 4) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
@ -2442,7 +2455,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
}
// read block
if (receivedCmd[0] == 0x30) {
if (MF_DBGLEVEL >= 2) {
if (MF_DBGLEVEL >= 4) {
Dbprintf("Reader reading block %d (0x%02x)",receivedCmd[1],receivedCmd[1]);
}
emlGetMem(response, receivedCmd[1], 1);
@ -2458,7 +2471,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
}
// write block
if (receivedCmd[0] == 0xA0) {
if (MF_DBGLEVEL >= 2) Dbprintf("RECV 0xA0 write block %d (%02x)",receivedCmd[1],receivedCmd[1]);
if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0xA0 write block %d (%02x)",receivedCmd[1],receivedCmd[1]);
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK));
cardSTATE = MFEMUL_WRITEBL2;
cardWRBL = receivedCmd[1];
@ -2466,7 +2479,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
}
// increment, decrement, restore
if (receivedCmd[0] == 0xC0 || receivedCmd[0] == 0xC1 || receivedCmd[0] == 0xC2) {
if (MF_DBGLEVEL >= 2) Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd[0],receivedCmd[1],receivedCmd[1]);
if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd[0],receivedCmd[1],receivedCmd[1]);
if (emlCheckValBl(receivedCmd[1])) {
if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate on block, but emlCheckValBl failed, nacking");
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
@ -2484,7 +2497,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
}
// transfer
if (receivedCmd[0] == 0xB0) {
if (MF_DBGLEVEL >= 2) Dbprintf("RECV 0x%02x transfer block %d (%02x)",receivedCmd[0],receivedCmd[1],receivedCmd[1]);
if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0x%02x transfer block %d (%02x)",receivedCmd[0],receivedCmd[1],receivedCmd[1]);
if (emlSetValBl(cardINTREG, cardINTBLOCK, receivedCmd[1]))
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
else
@ -2619,7 +2632,8 @@ void RAMFUNC SniffMifare(uint8_t param) {
// C(red) A(yellow) B(green)
LEDsoff();
// init trace buffer
iso14a_clear_trace();
iso14a_clear_trace();
iso14a_set_tracing(TRUE);
// The command (reader -> tag) that we're receiving.
// The length of a received command will in most cases be no more than 18 bytes.

View file

@ -606,6 +606,7 @@ void AcquireRawAdcSamplesIso15693(void)
int8_t prev = 0;
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
BuildIdentifyRequest();
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
@ -687,6 +688,7 @@ void RecordRawAdcSamplesIso15693(void)
int8_t prev = 0;
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Setup SSC
FpgaSetupSsc();
@ -753,6 +755,7 @@ void Iso15693InitReader() {
LED_C_OFF();
LED_D_OFF();
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Setup SSC
// FpgaSetupSsc();
@ -1015,6 +1018,7 @@ void ReaderIso15693(uint32_t parameter)
// Blank arrays
memset(BigBuf + 3660, 0, 300);
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Setup SSC
FpgaSetupSsc();
@ -1165,6 +1169,7 @@ void SimTagIso15693(uint32_t parameter)
// Blank arrays
memset(answer1, 0, 100);
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Setup SSC
FpgaSetupSsc();

View file

@ -21,7 +21,8 @@ ENTRY(Vector)
SECTIONS
{
.fpgaimage : {
*(fpga_bit.data)
*(fpga_lf_bit.data)
*(fpga_hf_bit.data)
} >fpgaimage :fpgaimage
.start : {

View file

@ -310,6 +310,7 @@ static uint32_t perform_setup_phase_rwd(int iv)
}
static void LegicCommonInit(void) {
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
@ -687,6 +688,7 @@ void LegicRfSimulate(int phase, int frame, int reqresp)
legic_frame_drift = frame;
legic_reqresp_drift = reqresp;
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_212K);

View file

@ -16,7 +16,7 @@
#include "string.h"
// split into two routines so we can avoid timing issues after sending commands //
void DoAcquisition125k_internal(bool silent)
void DoAcquisition125k_internal(int trigger_threshold,bool silent)
{
uint8_t *dest = (uint8_t *)BigBuf;
int n = sizeof(BigBuf);
@ -31,25 +31,30 @@ void DoAcquisition125k_internal(bool silent)
}
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
i++;
LED_D_OFF();
if (i >= n) break;
if (trigger_threshold != -1 && dest[i] < trigger_threshold)
continue;
else
trigger_threshold = -1;
if (++i >= n) break;
}
}
if( ! silent)
if(!silent)
{
Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...",
dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
}
}
void DoAcquisition125k(void)
void DoAcquisition125k(int trigger_threshold)
{
DoAcquisition125k_internal(false);
DoAcquisition125k_internal(trigger_threshold, false);
}
void SetupToAcquireRawAdcSamples(int divisor)
//void SetupToAcquireRawAdcSamples(int divisor)
void LFSetupFPGAForADC(int divisor, bool lf_field)
{
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
if ( (divisor == 1) || (divisor < 0) || (divisor > 255) )
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
else if (divisor == 0)
@ -57,23 +62,29 @@ void SetupToAcquireRawAdcSamples(int divisor)
else
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | (lf_field ? FPGA_LF_ADC_READER_FIELD : 0));
// Connect the A/D to the peak-detected low-frequency path.
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// Give it a bit of time for the resonant antenna to settle.
SpinDelay(50);
// Now set up the SSC to get the ADC samples that are now streaming at us.
FpgaSetupSsc();
}
void AcquireRawAdcSamples125k(int divisor)
{
SetupToAcquireRawAdcSamples(divisor);
LFSetupFPGAForADC(divisor, true);
// Now call the acquisition routine
DoAcquisition125k_internal(false);
DoAcquisition125k_internal(-1,false);
}
void SnoopLFRawAdcSamples(int divisor, int trigger_threshold)
{
LFSetupFPGAForADC(divisor, false);
DoAcquisition125k(trigger_threshold, false);
}
}
void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, uint8_t *command)
@ -81,6 +92,7 @@ void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1,
int at134khz;
/* Make sure the tag is reset */
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(2500);
@ -95,7 +107,7 @@ void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1,
else
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
// Give it a bit of time for the resonant antenna to settle.
SpinDelay(50);
@ -115,7 +127,7 @@ void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1,
else
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
LED_D_ON();
if(*(command++) == '0')
SpinDelayUs(period_0);
@ -130,10 +142,10 @@ void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1,
else
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
// now do the read
DoAcquisition125k();
DoAcquisition125k(-1);
}
/* blank r/w tag data stream
@ -170,6 +182,7 @@ void ReadTItag(void)
uint32_t threshold = (sampleslo - sampleshi + 1)>>1;
// TI tags charge at 134.2Khz
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
// Place FPGA in passthrough mode, in this mode the CROSS_LO line
@ -377,6 +390,7 @@ void AcquireTiType(void)
// if not provided a valid crc will be computed from the data and written.
void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc)
{
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
if(crc == 0) {
crc = update_crc16(crc, (idlo)&0xff);
crc = update_crc16(crc, (idlo>>8)&0xff);
@ -448,6 +462,7 @@ void SimulateTagLowFrequency(int period, int gap, int ledcontrol)
int i;
uint8_t *tab = (uint8_t *)BigBuf;
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT);
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK;
@ -615,7 +630,6 @@ size_t fsk_demod(uint8_t * dest, size_t size)
// threshold essentially we capture zero crossings for later analysis
uint8_t threshold_value = 127;
// sync to first lo-hi transition, and threshold
//Need to threshold first sample
@ -692,7 +706,7 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol)
while(!BUTTON_PRESS()) {
// Configure to go in 125Khz listen mode
SetupToAcquireRawAdcSamples(0);
LFSetupFPGAForADC(0, true)
WDT_HIT();
if (ledcontrol) LED_A_ON();
@ -788,7 +802,7 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol)
while(!BUTTON_PRESS()) {
// Configure to go in 125Khz listen mode
SetupToAcquireRawAdcSamples(0);
LFSetupFPGAForADC(0, true);
WDT_HIT();
if (ledcontrol) LED_A_ON();
@ -911,8 +925,9 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol)
// Write one bit to card
void T55xxWriteBit(int bit)
{
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
if (bit == 0)
SpinDelayUs(WRITE_0);
else
@ -926,8 +941,9 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t PwdMod
{
unsigned int i;
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
// Give it a bit of time for the resonant antenna to settle.
// And for the tag to fully power up
@ -959,7 +975,7 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t PwdMod
// Now perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550,
// so wait a little more)
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
SpinDelay(20);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
}
@ -970,6 +986,7 @@ void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode)
uint8_t *dest = (uint8_t *)BigBuf;
int m=0, i=0;
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
m = sizeof(BigBuf);
// Clear destination buffer before sending the command
memset(dest, 128, m);
@ -980,7 +997,7 @@ void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode)
LED_D_ON();
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
// Give it a bit of time for the resonant antenna to settle.
// And for the tag to fully power up
@ -1006,7 +1023,7 @@ void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode)
// Turn field on to read the response
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
// Now do the acquisition
i = 0;
@ -1034,6 +1051,7 @@ void T55xxReadTrace(void){
uint8_t *dest = (uint8_t *)BigBuf;
int m=0, i=0;
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
m = sizeof(BigBuf);
// Clear destination buffer before sending the command
memset(dest, 128, m);
@ -1044,7 +1062,7 @@ void T55xxReadTrace(void){
LED_D_ON();
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
// Give it a bit of time for the resonant antenna to settle.
// And for the tag to fully power up
@ -1060,7 +1078,7 @@ void T55xxReadTrace(void){
// Turn field on to read the response
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
// Now do the acquisition
i = 0;
@ -1749,8 +1767,9 @@ void SendForward(uint8_t fwd_bit_count) {
LED_D_ON();
//Field on
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
// Give it a bit of time for the resonant antenna to settle.
// And for the tag to fully power up
@ -1762,7 +1781,7 @@ void SendForward(uint8_t fwd_bit_count) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
SpinDelayUs(55*8); //55 cycles off (8us each)for 4305
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);//field on
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on
SpinDelayUs(16*8); //16 cycles on (8us each)
// now start writting
@ -1774,7 +1793,7 @@ void SendForward(uint8_t fwd_bit_count) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
SpinDelayUs(23*8); //16-4 cycles off (8us each)
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);//field on
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on
SpinDelayUs(9*8); //16 cycles on (8us each)
}
}

View file

@ -14,7 +14,7 @@
#include "apps.h"
//-----------------------------------------------------------------------------
// Select, Authenticaate, Read an MIFARE tag.
// Select, Authenticate, Read a MIFARE tag.
// read block
//-----------------------------------------------------------------------------
void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
@ -35,7 +35,7 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
pcs = &mpcs;
// clear trace
iso14a_clear_trace();
iso14a_clear_trace();
// iso14a_set_tracing(false);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
@ -46,22 +46,22 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
};
if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
break;
};
if(mifare_classic_readblock(pcs, cuid, blockNo, dataoutbuf)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Read block error");
if (MF_DBGLEVEL >= 1) Dbprintf("Read block error");
break;
};
if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break;
};
@ -74,83 +74,75 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED");
// add trace trailer
memset(uid, 0x44, 4);
LogTrace(uid, 4, 0, 0, TRUE);
// UsbCommand ack = {CMD_ACK, {isOK, 0, 0}};
// memcpy(ack.d.asBytes, dataoutbuf, 16);
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16);
// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand));
cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16);
LED_B_OFF();
// Thats it...
// Thats it...
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
// iso14a_set_tracing(TRUE);
}
void MifareUReadBlock(uint8_t arg0,uint8_t *datain)
{
// params
uint8_t blockNo = arg0;
// variables
byte_t isOK = 0;
byte_t dataoutbuf[16];
uint8_t uid[10];
uint32_t cuid;
// clear trace
iso14a_clear_trace();
}
void MifareUReadBlock(uint8_t arg0,uint8_t *datain)
{
// params
uint8_t blockNo = arg0;
// variables
byte_t isOK = 0;
byte_t dataoutbuf[16];
uint8_t uid[10];
uint32_t cuid;
// clear trace
iso14a_clear_trace();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
};
if(mifare_ultra_readblock(cuid, blockNo, dataoutbuf)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Read block error");
break;
};
if(mifare_ultra_halt(cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break;
};
isOK = 1;
break;
}
if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED");
// add trace trailer
memset(uid, 0x44, 4);
LogTrace(uid, 4, 0, 0, TRUE);
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16);
LED_B_OFF();
// Thats it...
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
//-----------------------------------------------------------------------------
// Select, Authenticaate, Read an MIFARE tag.
// read sector (data = 4 x 16 bytes = 64 bytes)
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
};
if(mifare_ultra_readblock(cuid, blockNo, dataoutbuf)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Read block error");
break;
};
if(mifare_ultra_halt(cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break;
};
isOK = 1;
break;
}
if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED");
// add trace trailer
memset(uid, 0x44, 4);
LogTrace(uid, 4, 0, 0, TRUE);
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16);
LED_B_OFF();
// Thats it...
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
//-----------------------------------------------------------------------------
// Select, Authenticate, Read a MIFARE tag.
// read sector (data = 4 x 16 bytes = 64 bytes, or 16 x 16 bytes = 256 bytes)
//-----------------------------------------------------------------------------
void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
{
@ -161,8 +153,8 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
ui64Key = bytes_to_num(datain, 6);
// variables
byte_t isOK = 0;
byte_t dataoutbuf[16 * 4];
byte_t isOK;
byte_t dataoutbuf[16 * 16];
uint8_t uid[10];
uint32_t cuid;
struct Crypto1State mpcs = {0, 0};
@ -170,7 +162,7 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
pcs = &mpcs;
// clear trace
iso14a_clear_trace();
iso14a_clear_trace();
// iso14a_set_tracing(false);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
@ -179,135 +171,104 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
LED_B_OFF();
LED_C_OFF();
while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid)) {
isOK = 1;
if(!iso14443a_select_card(uid, NULL, &cuid)) {
isOK = 0;
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
};
if(mifare_classic_auth(pcs, cuid, sectorNo * 4, keyType, ui64Key, AUTH_FIRST)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
break;
};
if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 0, dataoutbuf + 16 * 0)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Read block 0 error");
break;
};
if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 1, dataoutbuf + 16 * 1)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Read block 1 error");
break;
};
if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 2, dataoutbuf + 16 * 2)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Read block 2 error");
break;
};
if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 3, dataoutbuf + 16 * 3)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Read block 3 error");
break;
};
if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break;
};
isOK = 1;
break;
}
if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) {
isOK = 0;
if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
}
for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
if(mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf + 16 * blockNo)) {
isOK = 0;
if (MF_DBGLEVEL >= 1) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo);
break;
}
}
if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
}
// ----------------------------- crypto1 destroy
crypto1_destroy(pcs);
if (MF_DBGLEVEL >= 2) DbpString("READ SECTOR FINISHED");
// add trace trailer
memset(uid, 0x44, 4);
LogTrace(uid, 4, 0, 0, TRUE);
// UsbCommand ack = {CMD_ACK, {isOK, 0, 0}};
// memcpy(ack.d.asBytes, dataoutbuf, 16 * 2);
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,32);
// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand));
// SpinDelay(100);
// memcpy(ack.d.asBytes, dataoutbuf + 16 * 2, 16 * 2);
// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand));
cmd_send(CMD_ACK,isOK,0,0,dataoutbuf+32, 32);
cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16*NumBlocksPerSector(sectorNo));
LED_B_OFF();
// Thats it...
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
// iso14a_set_tracing(TRUE);
}
void MifareUReadCard(uint8_t arg0, uint8_t *datain)
{
// params
uint8_t sectorNo = arg0;
// variables
byte_t isOK = 0;
byte_t dataoutbuf[16 * 4];
uint8_t uid[10];
uint32_t cuid;
// clear trace
iso14a_clear_trace();
// iso14a_set_tracing(false);
}
void MifareUReadCard(uint8_t arg0, uint8_t *datain)
{
// params
uint8_t sectorNo = arg0;
// variables
byte_t isOK = 0;
byte_t dataoutbuf[16 * 4];
uint8_t uid[10];
uint32_t cuid;
// clear trace
iso14a_clear_trace();
// iso14a_set_tracing(false);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
};
for(int sec=0;sec<16;sec++){
if(mifare_ultra_readblock(cuid, sectorNo * 4 + sec, dataoutbuf + 4 * sec)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Read block %d error",sec);
break;
};
}
if(mifare_ultra_halt(cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break;
};
isOK = 1;
break;
}
if (MF_DBGLEVEL >= 2) DbpString("READ CARD FINISHED");
// add trace trailer
memset(uid, 0x44, 4);
LogTrace(uid, 4, 0, 0, TRUE);
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64);
//cmd_send(CMD_ACK,isOK,0,0,dataoutbuf+32, 32);
LED_B_OFF();
// Thats it...
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
// iso14a_set_tracing(TRUE);
}
//-----------------------------------------------------------------------------
// Select, Authenticaate, Read an MIFARE tag.
// read block
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
};
for(int sec=0;sec<16;sec++){
if(mifare_ultra_readblock(cuid, sectorNo * 4 + sec, dataoutbuf + 4 * sec)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Read block %d error",sec);
break;
};
}
if(mifare_ultra_halt(cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break;
};
isOK = 1;
break;
}
if (MF_DBGLEVEL >= 2) DbpString("READ CARD FINISHED");
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64);
LED_B_OFF();
// Thats it...
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
//-----------------------------------------------------------------------------
// Select, Authenticate, Write a MIFARE tag.
// read block
//-----------------------------------------------------------------------------
void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
{
@ -368,15 +329,8 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
// add trace trailer
memset(uid, 0x44, 4);
LogTrace(uid, 4, 0, 0, TRUE);
// UsbCommand ack = {CMD_ACK, {isOK, 0, 0}};
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,0,0);
// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand));
LED_B_OFF();
@ -384,143 +338,134 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
// iso14a_set_tracing(TRUE);
}
void MifareUWriteBlock(uint8_t arg0, uint8_t *datain)
{
// params
uint8_t blockNo = arg0;
byte_t blockdata[16];
memset(blockdata,'\0',16);
memcpy(blockdata, datain,16);
// variables
byte_t isOK = 0;
uint8_t uid[10];
uint32_t cuid;
// clear trace
iso14a_clear_trace();
// iso14a_set_tracing(false);
}
void MifareUWriteBlock(uint8_t arg0, uint8_t *datain)
{
// params
uint8_t blockNo = arg0;
byte_t blockdata[16];
memset(blockdata,'\0',16);
memcpy(blockdata, datain,16);
// variables
byte_t isOK = 0;
uint8_t uid[10];
uint32_t cuid;
// clear trace
iso14a_clear_trace();
// iso14a_set_tracing(false);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
};
if(mifare_ultra_writeblock(cuid, blockNo, blockdata)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
break;
};
if(mifare_ultra_halt(cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break;
};
isOK = 1;
break;
}
if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
// add trace trailer
memset(uid, 0x44, 4);
LogTrace(uid, 4, 0, 0, TRUE);
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,0,0);
// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand));
LED_B_OFF();
// Thats it...
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
// iso14a_set_tracing(TRUE);
}
void MifareUWriteBlock_Special(uint8_t arg0, uint8_t *datain)
{
// params
uint8_t blockNo = arg0;
byte_t blockdata[4];
memcpy(blockdata, datain,4);
// variables
byte_t isOK = 0;
uint8_t uid[10];
uint32_t cuid;
// clear trace
iso14a_clear_trace();
// iso14a_set_tracing(false);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
};
if(mifare_ultra_special_writeblock(cuid, blockNo, blockdata)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
break;
};
if(mifare_ultra_halt(cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break;
};
isOK = 1;
break;
}
if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
// add trace trailer
memset(uid, 0x44, 4);
LogTrace(uid, 4, 0, 0, TRUE);
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,0,0);
// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand));
LED_B_OFF();
// Thats it...
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
// iso14a_set_tracing(TRUE);
}
// Return 1 if the nonce is invalid else return 0
int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, byte_t * parity) {
return ((oddparity((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
};
if(mifare_ultra_writeblock(cuid, blockNo, blockdata)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
break;
};
if(mifare_ultra_halt(cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break;
};
isOK = 1;
break;
}
if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,0,0);
LED_B_OFF();
// Thats it...
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
// iso14a_set_tracing(TRUE);
}
void MifareUWriteBlock_Special(uint8_t arg0, uint8_t *datain)
{
// params
uint8_t blockNo = arg0;
byte_t blockdata[4];
memcpy(blockdata, datain,4);
// variables
byte_t isOK = 0;
uint8_t uid[10];
uint32_t cuid;
// clear trace
iso14a_clear_trace();
// iso14a_set_tracing(false);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
};
if(mifare_ultra_special_writeblock(cuid, blockNo, blockdata)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
break;
};
if(mifare_ultra_halt(cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break;
};
isOK = 1;
break;
}
if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,0,0);
LED_B_OFF();
// Thats it...
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
// iso14a_set_tracing(TRUE);
}
// Return 1 if the nonce is invalid else return 0
int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, byte_t * parity) {
return ((oddparity((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \
(oddparity((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \
(oddparity((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0;
}
//-----------------------------------------------------------------------------
// MIFARE nested authentication.
//
@ -769,18 +714,11 @@ void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
LED_B_OFF();
LED_C_OFF();
// SpinDelay(300);
for (i = 0; i < keyCount; i++) {
// FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
// SpinDelay(100);
// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
// prepare next select by sending a HALT. There is no need to power down the card.
if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Halt error");
}
// SpinDelay(50);
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (OLD_MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card");
break;
@ -798,10 +736,6 @@ void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
// ----------------------------- crypto1 destroy
crypto1_destroy(pcs);
// add trace trailer
memset(uid, 0x44, 4);
LogTrace(uid, 4, 0, 0, TRUE);
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,datain + i * 6,6);
LED_B_OFF();
@ -823,6 +757,7 @@ void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
Dbprintf("Debug level: %d", MF_DBGLEVEL);
}
//-----------------------------------------------------------------------------
// Work with emulator memory
//
@ -831,29 +766,29 @@ void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain)
emlClearMem();
}
void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
emlSetMem(datain, arg0, arg1); // data, block num, blocks count
}
void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
// UsbCommand ack = {CMD_ACK, {arg0, arg1, 0}};
byte_t buf[48];
emlGetMem(buf, arg0, arg1); // data, block num, blocks count
void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
byte_t buf[48];
emlGetMem(buf, arg0, arg1); // data, block num, blocks count (max 4)
LED_B_ON();
cmd_send(CMD_ACK,arg0,arg1,0,buf,48);
// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand));
cmd_send(CMD_ACK,arg0,arg1,0,buf,48);
LED_B_OFF();
}
//-----------------------------------------------------------------------------
// Load a card into the emulator memory
//
//-----------------------------------------------------------------------------
void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
int i;
uint8_t sectorNo = 0;
uint8_t numSectors = arg0;
uint8_t keyType = arg1;
uint64_t ui64Key = 0;
uint32_t cuid;
@ -876,63 +811,51 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
LED_B_OFF();
LED_C_OFF();
while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
};
bool isOK = true;
if(!iso14443a_select_card(uid, NULL, &cuid)) {
isOK = false;
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
}
for (i = 0; i < 16; i++) {
sectorNo = i;
ui64Key = emlGetKey(sectorNo, keyType);
if (!i){
if(mifare_classic_auth(pcs, cuid, sectorNo * 4, keyType, ui64Key, AUTH_FIRST)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%d]. Auth error", i);
break;
}
} else {
if(mifare_classic_auth(pcs, cuid, sectorNo * 4, keyType, ui64Key, AUTH_NESTED)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%d]. Auth nested error", i);
break;
for (uint8_t sectorNo = 0; isOK && sectorNo < numSectors; sectorNo++) {
ui64Key = emlGetKey(sectorNo, keyType);
if (sectorNo == 0){
if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) {
isOK = false;
if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth error", sectorNo);
break;
}
} else {
if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED)) {
isOK = false;
if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth nested error", sectorNo);
break;
}
}
for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
if(isOK && mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) {
isOK = false;
if (MF_DBGLEVEL >= 1) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo);
break;
};
if (isOK) {
if (blockNo < NumBlocksPerSector(sectorNo) - 1) {
emlSetMem(dataoutbuf, FirstBlockOfSector(sectorNo) + blockNo, 1);
} else { // sector trailer, keep the keys, set only the AC
emlGetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);
memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4);
emlSetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);
}
}
if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 0, dataoutbuf)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Read block 0 error");
break;
};
emlSetMem(dataoutbuf, sectorNo * 4 + 0, 1);
if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 1, dataoutbuf)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Read block 1 error");
break;
};
emlSetMem(dataoutbuf, sectorNo * 4 + 1, 1);
if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 2, dataoutbuf)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Read block 2 error");
break;
};
emlSetMem(dataoutbuf, sectorNo * 4 + 2, 1);
// get block 3 bytes 6-9
if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 3, dataoutbuf)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Read block 3 error");
break;
};
emlGetMem(dataoutbuf2, sectorNo * 4 + 3, 1);
memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4);
emlSetMem(dataoutbuf2, sectorNo * 4 + 3, 1);
}
if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break;
};
break;
}
}
if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
};
// ----------------------------- crypto1 destroy
crypto1_destroy(pcs);
@ -942,16 +865,8 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
if (MF_DBGLEVEL >= 2) DbpString("EMUL FILL SECTORS FINISHED");
// add trace trailer
memset(uid, 0x44, 4);
LogTrace(uid, 4, 0, 0, TRUE);
}
//-----------------------------------------------------------------------------
// MIFARE 1k emulator
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Work with "magic Chinese" card (email him: ouyangweidaxian@live.cn)
@ -1074,22 +989,8 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
break;
}
// UsbCommand ack = {CMD_ACK, {isOK, 0, 0}};
// if (isOK) memcpy(ack.d.asBytes, uid, 4);
// add trace trailer
/**
* Removed by Martin, the uid is overwritten with 0x44,
* which can 't be intended.
*
* memset(uid, 0x44, 4);
* LogTrace(uid, 4, 0, 0, TRUE);
**/
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,uid,4);
// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand));
cmd_send(CMD_ACK,isOK,0,0,uid,4);
LED_B_OFF();
if ((workFlags & 0x10) || (!isOK)) {
@ -1099,6 +1000,7 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
}
}
void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
// params
@ -1171,20 +1073,8 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
break;
}
// UsbCommand ack = {CMD_ACK, {isOK, 0, 0}};
// if (isOK) memcpy(ack.d.asBytes, data, 18);
// add trace trailer
/*
* Removed by Martin, this piece of overwrites the 'data' variable
* which is sent two lines down, and is obviously not correct.
*
* memset(data, 0x44, 4);
* LogTrace(data, 4, 0, 0, TRUE);
*/
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,data,18);
// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand));
cmd_send(CMD_ACK,isOK,0,0,data,18);
LED_B_OFF();
if ((workFlags & 0x10) || (!isOK)) {

View file

@ -453,6 +453,27 @@ int mifare_ultra_halt(uint32_t uid)
return 0;
}
// Mifare Memory Structure: up to 32 Sectors with 4 blocks each (1k and 2k cards),
// plus evtl. 8 sectors with 16 blocks each (4k cards)
uint8_t NumBlocksPerSector(uint8_t sectorNo)
{
if (sectorNo < 32)
return 4;
else
return 16;
}
uint8_t FirstBlockOfSector(uint8_t sectorNo)
{
if (sectorNo < 32)
return sectorNo * 4;
else
return 32*4 + (sectorNo - 32) * 16;
}
// work with emulator memory
void emlSetMem(uint8_t *data, int blockNum, int blocksCount) {
uint8_t* emCARD = eml_get_bigbufptr_cardmem();
@ -522,7 +543,7 @@ uint64_t emlGetKey(int sectorNum, int keyType) {
uint8_t key[6];
uint8_t* emCARD = eml_get_bigbufptr_cardmem();
memcpy(key, emCARD + 3 * 16 + sectorNum * 4 * 16 + keyType * 10, 6);
memcpy(key, emCARD + 16 * (FirstBlockOfSector(sectorNum) + NumBlocksPerSector(sectorNum) - 1) + keyType * 10, 6);
return bytes_to_num(key, 6);
}

View file

@ -80,6 +80,10 @@ uint8_t* mifare_get_bigbufptr(void);
uint8_t* eml_get_bigbufptr_sendbuf(void);
uint8_t* eml_get_bigbufptr_recbuf(void);
// Mifare memory structure
uint8_t NumBlocksPerSector(uint8_t sectorNo);
uint8_t FirstBlockOfSector(uint8_t sectorNo);
// emulator functions
void emlClearMem(void);
void emlSetMem(uint8_t *data, int blockNum, int blocksCount);

View file

@ -227,27 +227,27 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers
dst[0] = 0;
strncat(dst, prefix, len);
if(v->magic != VERSION_INFORMATION_MAGIC) {
strncat(dst, "Missing/Invalid version information", len);
strncat(dst, "Missing/Invalid version information", len - strlen(dst) - 1);
return;
}
if(v->versionversion != 1) {
strncat(dst, "Version information not understood", len);
strncat(dst, "Version information not understood", len - strlen(dst) - 1);
return;
}
if(!v->present) {
strncat(dst, "Version information not available", len);
strncat(dst, "Version information not available", len - strlen(dst) - 1);
return;
}
strncat(dst, v->svnversion, len);
strncat(dst, v->gitversion, len - strlen(dst) - 1);
if(v->clean == 0) {
strncat(dst, "-unclean", len);
strncat(dst, "-unclean", len - strlen(dst) - 1);
} else if(v->clean == 2) {
strncat(dst, "-suspect", len);
strncat(dst, "-suspect", len - strlen(dst) - 1);
}
strncat(dst, " ", len);
strncat(dst, v->buildtime, len);
strncat(dst, " ", len - strlen(dst) - 1);
strncat(dst, v->buildtime, len - strlen(dst) - 1);
}
// -------------------------------------------------------------------------

View file

@ -15,7 +15,7 @@ OBJDIR = obj
LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread ../liblua/liblua.a
LDFLAGS = $(COMMON_FLAGS)
CFLAGS = -std=c99 -I. -I../include -I../common -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4
CFLAGS = -std=c99 -lcrypto -I. -I../include -I../common -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4
LUAPLATFORM = generic
ifneq (,$(findstring MINGW,$(platform)))
@ -24,9 +24,9 @@ QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4
MOC = $(QTDIR)/bin/moc
LUAPLATFORM = mingw
else ifeq ($(platform),Darwin)
CXXFLAGS = -I/Library/Frameworks/QtGui.framework/Versions/Current/Headers -I/Library/Frameworks/QtCore.framework/Versions/Current/Headers
QTLDLIBS = -framework QtGui -framework QtCore
MOC = moc
CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O4
QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null)
MOC = $(shell pkg-config --variable=moc_location QtCore)
LUAPLATFORM = macosx
else
CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O4
@ -56,6 +56,12 @@ CORESRCS = uart.c \
CMDSRCS = nonce2key/crapto1.c\
nonce2key/crypto1.c\
nonce2key/nonce2key.c\
loclass/cipher.c \
loclass/cipherutils.c \
loclass/des.c \
loclass/ikeys.c \
loclass/elite_crack.c\
loclass/fileutils.c\
mifarehost.c\
crc16.c \
iso14443crc.c \
@ -74,8 +80,8 @@ CMDSRCS = nonce2key/crapto1.c\
cmdhfmf.c \
cmdhw.c \
cmdlf.c \
cmdlfhid.c \
cmdlfio.c \
cmdlfhid.c \
cmdlfem4x.c \
cmdlfhitag.c \
cmdlfti.c \

View file

@ -17,6 +17,7 @@
#include "ui.h"
#include "graph.h"
#include "cmdparser.h"
#include "util.h"
#include "cmdmain.h"
#include "cmddata.h"
@ -818,6 +819,41 @@ int CmdThreshold(const char *Cmd)
return 0;
}
int CmdDirectionalThreshold(const char *Cmd)
{
int8_t upThres = param_get8(Cmd, 0);
int8_t downThres = param_get8(Cmd, 1);
printf("Applying Up Threshold: %d, Down Threshold: %d\n", upThres, downThres);
int lastValue = GraphBuffer[0];
GraphBuffer[0] = 0; // Will be changed at the end, but init 0 as we adjust to last samples value if no threshold kicks in.
for (int i = 1; i < GraphTraceLen; ++i) {
// Apply first threshold to samples heading up
if (GraphBuffer[i] >= upThres && GraphBuffer[i] > lastValue)
{
lastValue = GraphBuffer[i]; // Buffer last value as we overwrite it.
GraphBuffer[i] = 1;
}
// Apply second threshold to samples heading down
else if (GraphBuffer[i] <= downThres && GraphBuffer[i] < lastValue)
{
lastValue = GraphBuffer[i]; // Buffer last value as we overwrite it.
GraphBuffer[i] = -1;
}
else
{
lastValue = GraphBuffer[i]; // Buffer last value as we overwrite it.
GraphBuffer[i] = GraphBuffer[i-1];
}
}
GraphBuffer[0] = GraphBuffer[1]; // Aline with first edited sample.
RepaintGraphWindow();
return 0;
}
int CmdZerocrossings(const char *Cmd)
{
// Zero-crossings aren't meaningful unless the signal is zero-mean.
@ -874,6 +910,7 @@ static command_t CommandTable[] =
{"scale", CmdScale, 1, "<int> -- Set cursor display scale"},
{"threshold", CmdThreshold, 1, "<threshold> -- Maximize/minimize every value in the graph window depending on threshold"},
{"zerocrossings", CmdZerocrossings, 1, "Count time between zero-crossings"},
{"dirthreshold", CmdDirectionalThreshold, 1, "<thres up> <thres down> -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."},
{NULL, NULL, 0, NULL}
};

View file

@ -38,6 +38,7 @@ int CmdSamples(const char *Cmd);
int CmdSave(const char *Cmd);
int CmdScale(const char *Cmd);
int CmdThreshold(const char *Cmd);
int CmdDirectionalThreshold(const char *Cmd);
int CmdZerocrossings(const char *Cmd);
#endif

View file

@ -183,27 +183,29 @@ void iso14a_set_timeout(uint32_t timeout) {
int CmdHF14AReader(const char *Cmd)
{
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}};
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}};
SendCommand(&c);
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
iso14a_card_select_t *card = (iso14a_card_select_t *)resp.d.asBytes;
iso14a_card_select_t card;
memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t));
if(resp.arg[0] == 0) {
uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS
if(select_status == 0) {
PrintAndLog("iso14443a card select failed");
return 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]);
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]);
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;
case 0x09: PrintAndLog("TYPE : NXP MIFARE Mini 0.3k"); break;
case 0x10: PrintAndLog("TYPE : NXP MIFARE Plus 2k SL2"); break;
@ -217,67 +219,107 @@ int CmdHF14AReader(const char *Cmd)
case 0x98: PrintAndLog("TYPE : Gemplus MPCOS"); break;
default: ;
}
if(resp.arg[0] == 1) {
// 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
bool ta1 = 0, tb1 = 0, tc1 = 0;
int pos;
PrintAndLog(" ATS : %s", sprint_hex(card->ats, card->ats_len));
if (card->ats_len > 0) {
PrintAndLog(" - TL : length is %d bytes", card->ats[0]);
if (select_status == 2) {
PrintAndLog("SAK incorrectly claims that card doesn't support RATS");
}
if (card->ats_len > 1) {
ta1 = (card->ats[1] & 0x10) == 0x10;
tb1 = (card->ats[1] & 0x20) == 0x20;
tc1 = (card->ats[1] & 0x40) == 0x40;
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;
PrintAndLog(" - T0 : TA1 is%s present, TB1 is%s present, "
"TC1 is%s present, FSCI is %d",
"TC1 is%s present, FSCI is %d (FSC = %ld)",
(ta1 ? "" : " NOT"), (tb1 ? "" : " NOT"), (tc1 ? "" : " NOT"),
(card->ats[1] & 0x0f));
fsci,
fsci < 5 ? (fsci - 2) * 8 :
fsci < 8 ? (fsci - 3) * 32 :
fsci == 8 ? 256 :
-1
);
}
pos = 2;
if (ta1 && card->ats_len > pos) {
if (ta1) {
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 && card->ats_len > pos) {
PrintAndLog(" - TB1 : SFGI = %d, FWI = %d",
(card->ats[pos] & 0x08),
(card->ats[pos] & 0x80) >> 4);
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
);
pos++;
}
if (tc1 && card->ats_len > pos) {
if (tc1) {
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_len > pos) {
if (card.ats[0] > pos) {
char *tip = "";
if (card->ats_len - pos > 7) {
if (memcmp(card->ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
if (card.ats[0] - 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_len - pos - 2), tip);
if (card->ats[pos] == 0xC1) {
PrintAndLog(" - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), 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;
@ -285,7 +327,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;
@ -302,7 +344,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;
@ -310,7 +352,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;
@ -321,7 +363,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;
@ -335,10 +377,10 @@ int CmdHF14AReader(const char *Cmd)
}
}
} else {
PrintAndLog("proprietary non iso14443a-4 card found, RATS not supported");
}
PrintAndLog("proprietary non iso14443-4 card found, RATS not supported");
}
return resp.arg[0];
return select_status;
}
// Collect ISO14443 Type A UIDs
@ -357,23 +399,20 @@ int CmdHF14ACUIDs(const char *Cmd)
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}};
SendCommand(&c);
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
uint8_t *uid = resp.d.asBytes;
iso14a_card_select_t *card = (iso14a_card_select_t *)(uid + 12);
iso14a_card_select_t *card = (iso14a_card_select_t *) resp.d.asBytes;
// check if command failed
if (resp.arg[0] == 0) {
PrintAndLog("Card select failed.");
} else {
// 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");
char uid_string[20];
for (uint16_t i = 0; i < card->uidlen; i++) {
sprintf(&uid_string[2*i], "%02X", card->uid[i]);
}
PrintAndLog("%s", uid_string);
}
}
PrintAndLog("End: %u", time(NULL));

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
@ -12,6 +13,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type
#include "data.h"
//#include "proxusb.h"
@ -21,10 +23,143 @@
#include "cmdhficlass.h"
#include "common.h"
#include "util.h"
#include "cmdmain.h"
#include "loclass/des.h"
#include "loclass/cipherutils.h"
#include "loclass/cipher.h"
#include "loclass/ikeys.h"
#include "loclass/elite_crack.h"
#include "loclass/fileutils.h"
static int CmdHelp(const char *Cmd);
int xorbits_8(uint8_t val)
{
uint8_t res = val ^ (val >> 1); //1st pass
res = res ^ (res >> 1); // 2nd pass
res = res ^ (res >> 2); // 3rd pass
res = res ^ (res >> 4); // 4th pass
return res & 1;
}
int CmdHFiClassList(const char *Cmd)
{
bool ShowWaitCycles = false;
char param = param_getchar(Cmd, 0);
if (param != 0) {
PrintAndLog("List data in trace buffer.");
PrintAndLog("Usage: hf iclass list");
PrintAndLog("h - help");
PrintAndLog("sample: hf iclass list");
return 0;
}
uint8_t got[1920];
GetFromBigBuf(got,sizeof(got),0);
WaitForResponse(CMD_ACK,NULL);
PrintAndLog("Recorded Activity");
PrintAndLog("");
PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer");
PrintAndLog("All times are in carrier periods (1/13.56Mhz)");
PrintAndLog("");
PrintAndLog(" Start | End | Src | Data");
PrintAndLog("-----------|-----------|-----|--------");
int i;
uint32_t first_timestamp = 0;
uint32_t timestamp;
bool tagToReader;
uint32_t parityBits;
uint8_t len;
uint8_t *frame;
uint32_t EndOfTransmissionTimestamp = 0;
for( i=0; i < 1900;)
{
//First 32 bits contain
// isResponse (1 bit)
// timestamp (remaining)
//Then paritybits
//Then length
timestamp = *((uint32_t *)(got+i));
parityBits = *((uint32_t *)(got+i+4));
len = got[i+8];
frame = (got+i+9);
uint32_t next_timestamp = (*((uint32_t *)(got+i+9))) & 0x7fffffff;
tagToReader = timestamp & 0x80000000;
timestamp &= 0x7fffffff;
if(i==0) {
first_timestamp = timestamp;
}
// Break and stick with current result idf buffer was not completely full
if (frame[0] == 0x44 && frame[1] == 0x44 && frame[2] == 0x44 && frame[3] == 0x44) break;
char line[1000] = "";
if(len)//We have some data to display
{
int j,oddparity;
for(j = 0; j < len ; j++)
{
oddparity = 0x01 ^ xorbits_8(frame[j] & 0xFF);
if (tagToReader && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) {
sprintf(line+(j*4), "%02x! ", frame[j]);
} else {
sprintf(line+(j*4), "%02x ", frame[j]);
}
}
}else
{
if (ShowWaitCycles) {
sprintf(line, "fdt (Frame Delay Time): %d", (next_timestamp - timestamp));
}
}
char *crc = "";
if(len > 2)
{
uint8_t b1, b2;
if(!tagToReader && len == 4) {
// Rough guess that this is a command from the reader
// For iClass the command byte is not part of the CRC
ComputeCrc14443(CRC_ICLASS, &frame[1], len-3, &b1, &b2);
}
else {
// For other data.. CRC might not be applicable (UPDATE commands etc.)
ComputeCrc14443(CRC_ICLASS, frame, len-2, &b1, &b2);
}
if (b1 != frame[len-2] || b2 != frame[len-1]) {
crc = (tagToReader & (len < 8)) ? "" : " !crc";
}
}
i += (len + 9);
EndOfTransmissionTimestamp = (*((uint32_t *)(got+i))) & 0x7fffffff;
// Not implemented for iclass on the ARM-side
//if (!ShowWaitCycles) i += 9;
PrintAndLog(" %9d | %9d | %s | %s %s",
(timestamp - first_timestamp),
(EndOfTransmissionTimestamp - first_timestamp),
(len?(tagToReader ? "Tag" : "Rdr"):" "),
line, crc);
}
return 0;
}
int CmdHFiClassListOld(const char *Cmd)
{
uint8_t got[1920];
GetFromBigBuf(got,sizeof(got),0);
@ -50,7 +185,9 @@ int CmdHFiClassList(const char *Cmd)
isResponse = 0;
}
int metric = 0;
int parityBits = *((uint32_t *)(got+i+4));
// 4 bytes of additional information...
// maximum of 32 additional parity bit information
@ -160,11 +297,6 @@ int CmdHFiClassList(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};
@ -177,69 +309,352 @@ int CmdHFiClassSim(const char *Cmd)
uint8_t simType = 0;
uint8_t CSN[8] = {0, 0, 0, 0, 0, 0, 0, 0};
if (strlen(Cmd)<2) {
PrintAndLog("Usage: hf iclass sim <sim type> <CSN (16 hex symbols)>");
if (strlen(Cmd)<1) {
PrintAndLog("Usage: hf iclass sim [0 <CSN>] | x");
PrintAndLog(" options");
PrintAndLog(" 0 <CSN> simulate the given CSN");
PrintAndLog(" 1 simulate default CSN");
PrintAndLog(" 2 iterate CSNs, gather MACs");
PrintAndLog(" sample: hf iclass sim 0 031FEC8AF7FF12E0");
PrintAndLog(" sample: hf iclass sim 2");
return 0;
}
simType = param_get8(Cmd, 0);
if (param_gethex(Cmd, 1, CSN, 16)) {
PrintAndLog("A CSN should consist of 16 HEX symbols");
return 1;
if(simType == 0)
{
if (param_gethex(Cmd, 1, CSN, 16)) {
PrintAndLog("A CSN should consist of 16 HEX symbols");
return 1;
}
PrintAndLog("--simtype:%02x csn:%s", simType, sprint_hex(CSN, 8));
}
PrintAndLog("--simtype:%02x csn:%s", simType, sprint_hex(CSN, 8));
if(simType > 2)
{
PrintAndLog("Undefined simptype %d", simType);
return 1;
}
uint8_t numberOfCSNs=0;
UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType}};
memcpy(c.d.asBytes, CSN, 8);
SendCommand(&c);
if(simType == 2)
{
UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType,63}};
UsbCommand resp = {0};
/*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");
}*/
uint8_t csns[64] = {
0x00,0x0B,0x0F,0xFF,0xF7,0xFF,0x12,0xE0 ,
0x00,0x13,0x94,0x7e,0x76,0xff,0x12,0xe0 ,
0x2a,0x99,0xac,0x79,0xec,0xff,0x12,0xe0 ,
0x17,0x12,0x01,0xfd,0xf7,0xff,0x12,0xe0 ,
0xcd,0x56,0x01,0x7c,0x6f,0xff,0x12,0xe0 ,
0x4b,0x5e,0x0b,0x72,0xef,0xff,0x12,0xe0 ,
0x00,0x73,0xd8,0x75,0x58,0xff,0x12,0xe0 ,
0x0c,0x90,0x32,0xf3,0x5d,0xff,0x12,0xe0 };
memcpy(c.d.asBytes, csns, 64);
SendCommand(&c);
if (!WaitForResponseTimeout(CMD_ACK, &resp, -1)) {
PrintAndLog("Command timed out");
return 0;
}
uint8_t num_mac_responses = resp.arg[1];
PrintAndLog("Mac responses: %d MACs obtained (should be 8)", num_mac_responses);
size_t datalen = 8*24;
/*
* Now, time to dump to file. We'll use this format:
* <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
* So, it should wind up as
* 8 * 24 bytes.
*
* The returndata from the pm3 is on the following format
* <4 byte NR><4 byte MAC>
* CC are all zeroes, CSN is the same as was sent in
**/
void* dump = malloc(datalen);
memset(dump,0,datalen);//<-- Need zeroes for the CC-field
uint8_t i = 0;
for(i = 0 ; i < 8 ; i++)
{
memcpy(dump+i*24, csns+i*8,8); //CSN
//8 zero bytes here...
//Then comes NR_MAC (eight bytes from the response)
memcpy(dump+i*24+16,resp.d.asBytes+i*8,8);
}
/** Now, save to dumpfile **/
saveFile("iclass_mac_attack", "bin", dump,datalen);
free(dump);
}else
{
UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType,numberOfCSNs}};
memcpy(c.d.asBytes, CSN, 8);
SendCommand(&c);
}
return 0;
}
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"},
{"list", CmdHFiClassList, 0, "List iClass history"},
{"snoop", CmdHFiClassSnoop, 0, "Eavesdrop iClass communication"},
{"sim", CmdHFiClassSim, 0, "Simulate iClass tag"},
{"reader", CmdHFiClassReader, 0, "Read an iClass tag"},
{"help", CmdHelp, 1, "This help"},
{"list", CmdHFiClassList, 0, "List iClass history"},
{"snoop", CmdHFiClassSnoop, 0, "Eavesdrop iClass communication"},
{"sim", CmdHFiClassSim, 0, "Simulate iClass tag"},
{"reader",CmdHFiClassReader, 0, "Read an iClass tag"},
{"replay",CmdHFiClassReader_Replay, 0, "Read an iClass tag via Reply Attack"},
{"dump", CmdHFiClassReader_Dump, 0, "Authenticate and Dump iClass tag"},
{"write", CmdHFiClass_iso14443A_write, 0, "Authenticate and Write iClass block"},
{NULL, NULL, 0, NULL}
};

View file

@ -18,5 +18,6 @@ int CmdHFiClassSnoop(const char *Cmd);
int CmdHFiClassSim(const char *Cmd);
int CmdHFiClassList(const char *Cmd);
int CmdHFiClassReader(const char *Cmd);
int CmdHFiClassReader_Replay(const char *Cmd);
#endif

File diff suppressed because it is too large Load diff

View file

@ -450,6 +450,28 @@ int CmdLFSimManchester(const char *Cmd)
return 0;
}
int CmdLFSnoop(const char *Cmd)
{
UsbCommand c = {CMD_LF_SNOOP_RAW_ADC_SAMPLES};
// 'h' means higher-low-frequency, 134 kHz
c.arg[0] = 0;
c.arg[1] = -1;
if (*Cmd == 0) {
// empty
} else if (*Cmd == 'l') {
sscanf(Cmd, "l %"lli, &c.arg[1]);
} else if(*Cmd == 'h') {
c.arg[0] = 1;
sscanf(Cmd, "h %"lli, &c.arg[1]);
} else if (sscanf(Cmd, "%"lli" %"lli, &c.arg[0], &c.arg[1]) < 1) {
PrintAndLog("use 'snoop' or 'snoop {l,h} [trigger threshold]', or 'snoop <divisor> [trigger threshold]'");
return 0;
}
SendCommand(&c);
WaitForResponse(CMD_ACK,NULL);
return 0;
}
int CmdVchDemod(const char *Cmd)
{
// Is this the entire sync pattern, or does this also include some
@ -540,6 +562,7 @@ static command_t CommandTable[] =
{"sim", CmdLFSim, 0, "[GAP] -- Simulate LF tag from buffer with optional GAP (in microseconds)"},
{"simbidir", CmdLFSimBidir, 0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"},
{"simman", CmdLFSimManchester, 0, "<Clock> <Bitstream> [GAP] Simulate arbitrary Manchester LF tag"},
{"snoop", CmdLFSnoop, 0, "['l'|'h'|<divisor>] [trigger threshold]-- Snoop LF (l:125khz, h:134khz)"},
{"ti", CmdLFTI, 1, "{ TI RFIDs... }"},
{"hitag", CmdLFHitag, 1, "{ Hitag tags and transponders... }"},
{"vchdemod", CmdVchDemod, 1, "['clone'] -- Demodulate samples for VeriChip"},

View file

@ -21,6 +21,7 @@ int CmdLFRead(const char *Cmd);
int CmdLFSim(const char *Cmd);
int CmdLFSimBidir(const char *Cmd);
int CmdLFSimManchester(const char *Cmd);
int CmdLFSnoop(const char *Cmd);
int CmdVchDemod(const char *Cmd);
#endif

79
client/default_keys.dic Normal file
View file

@ -0,0 +1,79 @@
# Default Keys as already in Proxmark.exe:
ffffffffffff,//Defaultkey(firstkeyusedbyprogramifnouserdefinedkey)
000000000000,//Blankkey
a0a1a2a3a4a5,//NFCForumMADkey
b0b1b2b3b4b5,
aabbccddeeff,
4d3a99c351dd,
1a982c7e459a,
d3f7d3f7d3f7,
714c5c886e97,
587ee5f9350f,
a0478cc39091,
533cb6c723f6,
8fd0a4f256e9
# more Keys from mf_default_keys.lua
000000000001,
000000000002,
00000000000a,
00000000000b,
00000ffe2488,--VästtrafikenKeyB
010203040506,
0123456789ab,
0297927c0f77,--VästtrafikenKeyA
100000000000,
111111111111,
123456789abc,
12f2ee3478c1,
14d446e33363,
1999a3554a55,
200000000000,
222222222222,
26940b21ff5d,--RKFSLKeyA
27dd91f1fcf1,
2BA9621E0A36,--DirectoryandeventlogKeyB
333333333333,
33f974b42769,
34d1df9934c5,
434f4d4d4f41,--RKFJOJOGROUPKeyA
434f4d4d4f42,--RKFJOJOGROUPKeyB
43ab19ef5c31,
444444444444,
47524f555041,--RKFJOJOGROUPKeyA
47524f555042,--RKFJOJOGROUPKeyB
4AF9D7ADEBE4,--DirectoryandeventlogKeyA
505249564141,--RKFJOJOPRIVAKeyA
505249564142,--RKFJOJOPRIVAKeyB
505249565441,
505249565442,
54726176656c,--VästtrafikenKeyA
555555555555,
55f5a5dd38c9,
5c598c9c58b5,--RKFSLKeyB
666666666666,
722bfcc5375f,--RKFRejskortDanmarkKeyA
776974687573,--VästtrafikenKeyB
777777777777,
888888888888,
999999999999,
99c636334433,
a00000000000,
a053a292a4af,
a64598a77478,--RKFSLKeyA
a94133013401,
aaaaaaaaaaaa,
abcdef123456,--Keyfromladyada.net
b00000000000,
b127c6f41436,
bbbbbbbbbbbb,
bd493a3962b6,
c934fe34d934,
cccccccccccc,
dddddddddddd,
e4d2770a89be,--RKFSLKeyB
ee0042f88840,--VästtrafikenKeyB
eeeeeeeeeeee,
f1a97341a9fc,
f1d83f964314,--RKFRejskortDanmarkKeyB
fc00018778f7,--VästtrafikenKeyA
fc0001877bf7,--RKFÖstgötaTrafikenKeyA

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

@ -8,10 +8,17 @@ bin = require('bin')
---
-- A debug printout-function
local function dbg(args)
if DEBUG then
if type(args) == "table" then
local i = 1
while args[i] do
print("###", args[i])
i = i+1
end
else
print("###", args)
end
end
end
end
---
-- This is only meant to be used when errors occur
local function oops(err)
@ -40,20 +47,38 @@ local function save_HTML(javascript, filename)
end
local function save_BIN(data, filename)
-- Open the output file
local outfile = io.open(filename, "wb")
if outfile == nil then
return oops(string.format("Could not write to file %s",tostring(filename)))
end
-- Write the data into it
local i = 1
while data[i] do
outfile:write(data[i])
i = i+1
end
io.close(outfile)
return filename
end
local function convert_ascii_dump_to_JS(infile)
local t = infile:read("*all")
local output = "[";
for line in string.gmatch(t, "[^\n]+") do
output = output .. "'"..line.."',\n"
if string.byte(line,1) ~= string.byte("+",1) then
output = output .. "'"..line.."',\n"
end
end
output = output .. "]"
return output
end
local function convert_binary_dump_to_JS(infile, blockLen)
local bindata = infile:read("*all")
len = string.len(bindata)
@ -78,6 +103,21 @@ local function convert_binary_dump_to_JS(infile, blockLen)
return js
end
local function convert_ascii_dump_to_BIN(infile)
local t = infile:read("*all")
local output = {};
for line in string.gmatch(t, "[^\n]+") do
if string.byte(line) ~= string.byte("+") then
for c in (line or ''):gmatch('..') do
output[#output+1] = string.char( tonumber(c,16) )
end
end
end
return output
end
---
-- Converts a .eml-file into a HTML/Javascript file.
-- @param input the file to convert
@ -118,7 +158,27 @@ local function convert_bin_to_html(input, output, blockLen)
return save_HTML(javascript, output )
end
--- Converts a eml dump into a binary file
-- @param input the file containing the eml-dump (defaults to dumpdata.eml)
-- @param output the file to write to ( defaults to dumpdata.bin)
local function convert_eml_to_bin(input, output)
input = input or 'dumpdata.eml'
output = output or 'dumpdata.bin'
local infile = io.open(input, "rb")
if infile == nil then
return oops(string.format("Could not read file %s",tostring(input)))
end
-- Read file, get BIN
local data = convert_ascii_dump_to_BIN(infile)
io.close(infile)
return save_BIN(data, output )
end
return {
convert_bin_to_html = convert_bin_to_html,
convert_eml_to_html = convert_eml_to_html,
convert_eml_to_html = convert_eml_to_html,
convert_eml_to_bin = convert_eml_to_bin,
}

View file

@ -126,6 +126,21 @@ local _keys = {
'eeeeeeeeeeee',
'0123456789ab',
'123456789abc',
--[[
The keys below are taken from from https://github.com/4ZM/mfterm/blob/master/dictionary.txt
--]]
'abcdef123456', -- Key from ladyada.net
'000000000001',
'000000000002',
'00000000000a',
'00000000000b',
'100000000000',
'200000000000',
'a00000000000',
'b00000000000',
}
---
@ -148,4 +163,4 @@ local function uniq(list)
return foobar
end
return uniq(_keys)
return uniq(_keys)

57
client/lualibs/utils.lua Normal file
View file

@ -0,0 +1,57 @@
--[[
This may be moved to a separate library at some point (Holiman)
--]]
local Utils =
{
-- Asks the user for Yes or No
confirm = function(message, ...)
local answer
message = message .. " [y/n] ?"
repeat
io.write(message)
io.flush()
answer=io.read()
if answer == 'Y' or answer == "y" then
return true
elseif answer == 'N' or answer == 'n' then
return false
end
until false
end,
---
-- Asks the user for input
input = function (message , default)
local answer
if default ~= nil then
message = message .. " (default: ".. default.. " )"
end
message = message .." \n > "
io.write(message)
io.flush()
answer=io.read()
if answer == '' then answer = default end
return answer
end,
--
-- Converts DECIMAL to HEX
ConvertDec2Hex = function(IN)
local B,K,OUT,I,D=16,"0123456789ABCDEF","",0
while IN>0 do
I=I+1
IN,D=math.floor(IN/B),math.mod(IN,B)+1
OUT=string.sub(K,D,D)..OUT
end
return OUT
end,
---
-- Convert Byte array to string of hex
ConvertBytes2String = function(bytes)
s = {}
for i = 1, #(bytes) do
s[i] = string.format("%02X",bytes[i])
end
return table.concat(s)
end,
}
return Utils

View file

View file

@ -13,7 +13,7 @@ by the emulator
Arguments:
-h This help
-i <file> Specifies the dump-file (input). If omitted, 'dumpdata.bin' is used
-o <filename> Speciies the output file. If omitted, <uid>.eml is used.
-o <filename> Specifies the output file. If omitted, <uid>.eml is used.
]]

View file

@ -0,0 +1,60 @@
local getopt = require('getopt')
local bin = require('bin')
local dumplib = require('html_dumplib')
example =[[
1. script run emul2dump
2. script run emul2dump -i myfile.eml
3. script run emul2dump -i myfile.eml -o myfile.bin
]]
author = "Iceman"
usage = "script run emul2dump [-i <file>] [-o <file>]"
desc =[[
This script takes an dumpfile on EML (ASCII) format and converts it to the PM3 dumpbin file to be used with "hf mf restore"
Arguments:
-h This help
-i <filename> Specifies the dump-file (input). If omitted, 'dumpdata.eml' is used
-o <filename> Specifies the output file. If omitted, <currdate>.bin is used.
]]
---
-- This is only meant to be used when errors occur
function oops(err)
print("ERROR: ",err)
end
---
-- Usage help
function help()
print(desc)
print("Example usage")
print(example)
end
--
-- Exit message
function ExitMsg(msg)
print( string.rep('--',20) )
print( string.rep('--',20) )
print(msg)
print()
end
local function main(args)
local input = "dumpdata.eml"
local output = os.date("%Y-%m-%d_%H%M%S.bin");
-- Arguments for the script
for o, a in getopt.getopt(args, 'hi:o:') do
if o == "h" then return help() end
if o == "i" then input = a end
if o == "o" then output = a end
end
local filename, err = dumplib.convert_eml_to_bin(input,output)
if err then return oops(err) end
ExitMsg(("Wrote a BIN dump to the file %s"):format(filename))
end
main(args)

View file

@ -0,0 +1,196 @@
local cmds = require('commands')
local getopt = require('getopt')
local bin = require('bin')
local lib14a = require('read14a')
local utils = require('utils')
example =[[
1. script run formatMifare
2. script run formatMifare -k aabbccddeeff -n 112233445566 -a FF0780
]]
author = "Iceman"
usage = "script run formatMifare -k <key>"
desc =[[
This script will generate 'hf mf wrbl' commands for each block to format a Mifare card.
Alla datablocks gets 0x00
As default the script sets the keys A/B to 0xFFFFFFFFFFFF
and the access bytes will become 0x78,0x77,0x88
The GDB will become 0x00
The script will skip the manufactoring block 0.
Arguments:
-h - this help
-k <key> - the current six byte key with write access
-n <key> - the new key that will be written to the card
-a <access> - the new access bytes that will be written to the card
]]
local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds
local DEBUG = true -- the debug flag
local CmdString = 'hf mf wrbl %d B %s %s'
local numBlocks = 64
local numSectors = 16
---
-- A debug printout-function
function dbg(args)
if not DEBUG then
return
end
if type(args) == "table" then
local i = 1
while result[i] do
dbg(result[i])
i = i+1
end
else
print("###", args)
end
end
---
-- This is only meant to be used when errors occur
function oops(err)
print("ERROR: ",err)
end
---
-- Usage help
function help()
print(desc)
print("Example usage")
print(example)
end
--
-- Exit message
function ExitMsg(msg)
print( string.rep('--',20) )
print( string.rep('--',20) )
print(msg)
print()
end
--
-- Read information from a card
function GetCardInfo()
result, err = lib14a.read1443a(false)
if not result then
print(err)
return
end
print(("Found: %s"):format(result.name))
core.clearCommandBuffer()
if 0x18 == result.sak then --NXP MIFARE Classic 4k | Plus 4k
-- IFARE Classic 4K offers 4096 bytes split into forty sectors,
-- of which 32 are same size as in the 1K with eight more that are quadruple size sectors.
numSectors = 40
elseif 0x08 == result.sak then -- NXP MIFARE CLASSIC 1k | Plus 2k
-- 1K offers 1024 bytes of data storage, split into 16 sector
numSectors = 16
elseif 0x09 == result.sak then -- NXP MIFARE Mini 0.3k
-- MIFARE Classic mini offers 320 bytes split into five sectors.
numSectors = 5
elseif 0x10 == result.sak then-- "NXP MIFARE Plus 2k"
numSectors = 32
else
print("I don't know how many sectors there are on this type of card, defaulting to 16")
end
--[[
The mifare Classic 1k card has 16 sectors of 4 data blocks each.
The first 32 sectors of a mifare Classic 4k card consists of 4 data blocks and the remaining
8 sectors consist of 16 data blocks.
--]]
-- Defaults to 16 * 4 = 64 - 1 = 63
numBlocks = numSectors * 4 - 1
if numSectors > 32 then
numBlocks = 32*4+ (numSectors-32)*16 -1
end
end
local function main(args)
print( string.rep('--',20) )
print( string.rep('--',20) )
print()
local OldKey
local NewKey
local Accessbytes
-- Arguments for the script
for o, a in getopt.getopt(args, 'hk:n:a:') do
if o == "h" then return help() end
if o == "k" then OldKey = a end
if o == "n" then NewKey = a end
if o == "a" then Accessbytes = a end
end
-- validate input args.
OldKey = OldKey or 'FFFFFFFFFFFF'
if #(OldKey) ~= 12 then
return oops( string.format('Wrong length of write key (was %d) expected 12', #OldKey))
end
NewKey = NewKey or 'FFFFFFFFFFFF'
if #(NewKey) ~= 12 then
return oops( string.format('Wrong length of new key (was %d) expected 12', #NewKey))
end
--Accessbytes = Accessbytes or '787788'
Accessbytes = Accessbytes or 'FF0780'
if #(Accessbytes) ~= 6 then
return oops( string.format('Wrong length of accessbytes (was %d) expected 12', #Accessbytes))
end
GetCardInfo()
-- Show info
print( string.format('Estimating number of blocks: %d', numBlocks))
print( string.format('Old key: %s', OldKey))
print( string.format('New key: %s', NewKey))
print( string.format('New Access: %s', Accessbytes))
print( string.rep('--',20) )
-- Set new block data
local EMPTY_BL = string.rep('00',16)
local EMPTY_SECTORTRAIL = string.format('%s%s%s%s',NewKey,Accessbytes,'00',NewKey)
dbg( string.format('New sector-trailer : %s',EMPTY_SECTORTRAIL))
dbg( string.format('New emptyblock: %s',EMPTY_BL))
dbg('')
-- Ask
local dialogResult = utils.confirm("Do you want to erase this card")
if dialogResult == false then
return ExitMsg('Quiting it is then. Your wish is my command...')
end
print( string.rep('--',20) )
-- main loop
for block=0,numBlocks,1 do
local reminder = (block+1) % 4
local cmd
if reminder == 0 then
cmd = CmdString:format(block, OldKey , EMPTY_SECTORTRAIL)
else
cmd = CmdString:format(block, OldKey , EMPTY_BL)
end
if block ~= 0 then
print(cmd)
--core.console(cmd)
end
if core.ukbhit() then
print("aborted by user")
break
end
end
end
main(args)

View file

@ -12,6 +12,9 @@
#include <stdlib.h>
//#include "iso15693tools.h"
#define POLY 0x8408
// The CRC as described in ISO 15693-Part 3-Annex C
// v buffer with data
// n length
@ -63,5 +66,31 @@ char* Iso15693sprintUID(char *target,uint8_t *uid) {
return target;
}
unsigned short iclass_crc16(char *data_p, unsigned short length)
{
unsigned char i;
unsigned int data;
unsigned int crc = 0xffff;
if (length == 0)
return (~crc);
do
{
for (i=0, data=(unsigned int)0xff & *data_p++;
i < 8;
i++, data >>= 1)
{
if ((crc & 0x0001) ^ (data & 0x0001))
crc = (crc >> 1) ^ POLY;
else crc >>= 1;
}
} while (--length);
crc = ~crc;
data = crc;
crc = (crc << 8) | (data >> 8 & 0xff);
crc = crc ^ 0xBC3;
return (crc);
}

View file

@ -70,6 +70,7 @@
uint16_t Iso15693Crc(uint8_t *v, int n);
int Iso15693AddCrc(uint8_t *req, int n);
char* Iso15693sprintUID(char *target,uint8_t *uid);
unsigned short iclass_crc16(char *data_p, unsigned short length);
//-----------------------------------------------------------------------------
// Map a sequence of octets (~layer 2 command) into the set of bits to feed

View file

@ -13,8 +13,8 @@ MEMORY
{
bootphase1 : ORIGIN = 0x00100000, LENGTH = 0x200 /* Phase 1 bootloader: Copies real bootloader to RAM */
bootphase2 : ORIGIN = 0x00100200, LENGTH = 0x2000 - 0x200 /* Main bootloader code, stored in Flash, executed from RAM */
fpgaimage : ORIGIN = 0x00102000, LENGTH = 64k - 0x2000 /* Place where the FPGA image will end up */
osimage : ORIGIN = 0x00110000, LENGTH = 256K - 64k /* Place where the main OS will end up */
fpgaimage : ORIGIN = 0x00102000, LENGTH = 96k - 0x2000 /* Place where the FPGA image will end up */
osimage : ORIGIN = 0x00118000, LENGTH = 256K - 96k /* Place where the main OS will end up */
ram : ORIGIN = 0x00200000, LENGTH = 64K - 0x20 /* RAM, minus small common area */
commonarea : ORIGIN = 0x00200000 + 64K - 0x20, LENGTH = 0x20 /* Communication between bootloader and main OS */
}

View file

@ -1,31 +1,33 @@
include ../common/Makefile.common
all: fpga.ngc fpga.ngd fpga.ncd fpga-placed.ncd fpga.bit
all: fpga_lf.bit fpga_hf.bit
clean:
$(DELETE) fpga.bgn fpga.drc fpga.ncd fpga.ngd fpga_par.xrpt fpga-placed.pad fpga-placed.par fpga-placed.xpi fpga_usage.xml xlnx_auto_0.ise xst.srp
$(DELETE) fpga.map fpga.ngc fpga_ngdbuild.xrpt fpga.pcf fpga-placed_pad.csv fpga-placed.ptwx fpga.rbt xlnx_auto_0_xdb
$(DELETE) fpga.bld fpga.mrp fpga.ngc_xst.xrpt fpga.ngm fpga-placed.ncd fpga-placed_pad.txt fpga-placed.unroutes fpga_summary.xml netlist.lst xst
$(DELETE) *.bgn *.drc *.ncd *.ngd *_par.xrpt *-placed.* *-placed_pad.* *_usage.xml xst_hf.srp xst_lf.srp
$(DELETE) *.map *.ngc *.xrpt *.pcf *.rbt *_auto_* *.bld *.mrp *.ngm *.unroutes *_summary.xml netlist.lst xst
fpga.ngc: fpga.v fpga.ucf xst.scr util.v lo_edge_detect.v lo_read.v lo_passthru.v hi_simulate.v hi_read_tx.v hi_read_rx_xcorr.v hi_iso14443a.v
$(DELETE) fpga.ngc
$(XILINX_TOOLS_PREFIX)xst -ifn xst.scr
fpga_hf.ngc: fpga_hf.v fpga.ucf xst_hf.scr util.v hi_simulate.v hi_read_tx.v hi_read_rx_xcorr.v hi_iso14443a.v
$(DELETE) $@
$(XILINX_TOOLS_PREFIX)xst -ifn xst_hf.scr
fpga.ngd: fpga.ngc
$(DELETE) fpga.ngd
$(XILINX_TOOLS_PREFIX)ngdbuild -aul -p xc2s30-5-vq100 -nt timestamp -uc fpga.ucf fpga.ngc fpga.ngd
fpga_lf.ngc: fpga_lf.v fpga.ucf xst_lf.scr util.v clk_divider.v lo_edge_detect.v lo_read.v lo_passthru.v lp20khz_1MSa_iir_filter.v min_max_tracker.v lf_edge_detect.v
$(DELETE) $@
$(XILINX_TOOLS_PREFIX)xst -ifn xst_lf.scr
fpga.ncd: fpga.ngd
$(DELETE) fpga.ncd
$(XILINX_TOOLS_PREFIX)map -p xc2s30-5-vq100 fpga.ngd
%.ngd: %.ngc
$(DELETE) $@
$(XILINX_TOOLS_PREFIX)ngdbuild -aul -p xc2s30-5-vq100 -nt timestamp -uc fpga.ucf $< $@
fpga-placed.ncd: fpga.ncd
$(DELETE) fpga-placed.ncd
$(XILINX_TOOLS_PREFIX)par fpga.ncd fpga-placed.ncd
%.ncd: %.ngd
$(DELETE) $@
$(XILINX_TOOLS_PREFIX)map -p xc2s30-5-vq100 $<
fpga.bit: fpga-placed.ncd
$(DELETE) fpga.bit fpga.drc fpga.rbt
$(XILINX_TOOLS_PREFIX)bitgen fpga-placed.ncd fpga.bit
%-placed.ncd: %.ncd
$(DELETE) $@
$(XILINX_TOOLS_PREFIX)par $< $@
%.bit: %-placed.ncd
$(DELETE) $@ $*.drc $*.rbt
$(XILINX_TOOLS_PREFIX)bitgen $< $@
.PHONY: all clean help
help:

25
fpga/clk_divider.v Normal file
View file

@ -0,0 +1,25 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
//
// 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.
//-----------------------------------------------------------------------------
module clk_divider(input clk, input [7:0] divisor, output [7:0] div_cnt, output div_clk);
reg [7:0] div_cnt_ = 0;
reg div_clk_;
assign div_cnt = div_cnt_;
assign div_clk = div_clk_;
always @(posedge clk)
begin
if(div_cnt == divisor) begin
div_cnt_ <= 8'd0;
div_clk_ = !div_clk_;
end else
div_cnt_ <= div_cnt_ + 1;
end
endmodule

Binary file not shown.

View file

@ -1,220 +0,0 @@
//-----------------------------------------------------------------------------
// The FPGA is responsible for interfacing between the A/D, the coil drivers,
// and the ARM. In the low-frequency modes it passes the data straight
// through, so that the ARM gets raw A/D samples over the SSP. In the high-
// frequency modes, the FPGA might perform some demodulation first, to
// reduce the amount of data that we must send to the ARM.
//
// I am not really an FPGA/ASIC designer, so I am sure that a lot of this
// could be improved.
//
// Jonathan Westhues, March 2006
// Added ISO14443-A support by Gerhard de Koning Gans, April 2008
//-----------------------------------------------------------------------------
`include "lo_read.v"
`include "lo_passthru.v"
`include "lo_edge_detect.v"
`include "hi_read_tx.v"
`include "hi_read_rx_xcorr.v"
`include "hi_simulate.v"
`include "hi_iso14443a.v"
`include "util.v"
module fpga(
spck, miso, mosi, ncs,
pck0, ck_1356meg, ck_1356megb,
pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
adc_d, adc_clk, adc_noe,
ssp_frame, ssp_din, ssp_dout, ssp_clk,
cross_hi, cross_lo,
dbg
);
input spck, mosi, ncs;
output miso;
input pck0, ck_1356meg, ck_1356megb;
output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;
input [7:0] adc_d;
output adc_clk, adc_noe;
input ssp_dout;
output ssp_frame, ssp_din, ssp_clk;
input cross_hi, cross_lo;
output dbg;
//assign pck0 = pck0i;
// IBUFG #(.IOSTANDARD("DEFAULT") ) pck0b(
// .O(pck0),
// .I(pck0i)
// );
//assign spck = spcki;
// IBUFG #(.IOSTANDARD("DEFAULT") ) spckb(
// .O(spck),
// .I(spcki)
// );
//-----------------------------------------------------------------------------
// The SPI receiver. This sets up the configuration word, which the rest of
// the logic looks at to determine how to connect the A/D and the coil
// drivers (i.e., which section gets it). Also assign some symbolic names
// to the configuration bits, for use below.
//-----------------------------------------------------------------------------
reg [15:0] shift_reg;
reg [7:0] divisor;
reg [7:0] conf_word;
// We switch modes between transmitting to the 13.56 MHz tag and receiving
// from it, which means that we must make sure that we can do so without
// glitching, or else we will glitch the transmitted carrier.
always @(posedge ncs)
begin
case(shift_reg[15:12])
4'b0001: conf_word <= shift_reg[7:0]; // FPGA_CMD_SET_CONFREG
4'b0010: divisor <= shift_reg[7:0]; // FPGA_CMD_SET_DIVISOR
endcase
end
always @(posedge spck)
begin
if(~ncs)
begin
shift_reg[15:1] <= shift_reg[14:0];
shift_reg[0] <= mosi;
end
end
wire [2:0] major_mode;
assign major_mode = conf_word[7:5];
// For the low-frequency configuration:
wire lo_is_125khz;
assign lo_is_125khz = conf_word[3];
// For the high-frequency transmit configuration: modulation depth, either
// 100% (just quite driving antenna, steady LOW), or shallower (tri-state
// some fraction of the buffers)
wire hi_read_tx_shallow_modulation;
assign hi_read_tx_shallow_modulation = conf_word[0];
// For the high-frequency receive correlator: frequency against which to
// correlate.
wire hi_read_rx_xcorr_848;
assign hi_read_rx_xcorr_848 = conf_word[0];
// and whether to drive the coil (reader) or just short it (snooper)
wire hi_read_rx_xcorr_snoop;
assign hi_read_rx_xcorr_snoop = conf_word[1];
// Divide the expected subcarrier frequency for hi_read_rx_xcorr by 4
wire hi_read_rx_xcorr_quarter;
assign hi_read_rx_xcorr_quarter = conf_word[2];
// For the high-frequency simulated tag: what kind of modulation to use.
wire [2:0] hi_simulate_mod_type;
assign hi_simulate_mod_type = conf_word[2:0];
// For the high-frequency simulated tag: what kind of modulation to use.
wire lf_field;
assign lf_field = conf_word[0];
//-----------------------------------------------------------------------------
// And then we instantiate the modules corresponding to each of the FPGA's
// major modes, and use muxes to connect the outputs of the active mode to
// the output pins.
//-----------------------------------------------------------------------------
lo_read lr(
pck0, ck_1356meg, ck_1356megb,
lr_pwr_lo, lr_pwr_hi, lr_pwr_oe1, lr_pwr_oe2, lr_pwr_oe3, lr_pwr_oe4,
adc_d, lr_adc_clk,
lr_ssp_frame, lr_ssp_din, ssp_dout, lr_ssp_clk,
cross_hi, cross_lo,
lr_dbg,
lo_is_125khz, divisor
);
lo_passthru lp(
pck0, ck_1356meg, ck_1356megb,
lp_pwr_lo, lp_pwr_hi, lp_pwr_oe1, lp_pwr_oe2, lp_pwr_oe3, lp_pwr_oe4,
adc_d, lp_adc_clk,
lp_ssp_frame, lp_ssp_din, ssp_dout, lp_ssp_clk,
cross_hi, cross_lo,
lp_dbg, divisor
);
lo_edge_detect ls(
pck0, ck_1356meg, ck_1356megb,
ls_pwr_lo, ls_pwr_hi, ls_pwr_oe1, ls_pwr_oe2, ls_pwr_oe3, ls_pwr_oe4,
adc_d, ls_adc_clk,
ls_ssp_frame, ls_ssp_din, ssp_dout, ls_ssp_clk,
cross_hi, cross_lo,
ls_dbg, divisor,
lf_field
);
hi_read_tx ht(
pck0, ck_1356meg, ck_1356megb,
ht_pwr_lo, ht_pwr_hi, ht_pwr_oe1, ht_pwr_oe2, ht_pwr_oe3, ht_pwr_oe4,
adc_d, ht_adc_clk,
ht_ssp_frame, ht_ssp_din, ssp_dout, ht_ssp_clk,
cross_hi, cross_lo,
ht_dbg,
hi_read_tx_shallow_modulation
);
hi_read_rx_xcorr hrxc(
pck0, ck_1356meg, ck_1356megb,
hrxc_pwr_lo, hrxc_pwr_hi, hrxc_pwr_oe1, hrxc_pwr_oe2, hrxc_pwr_oe3, hrxc_pwr_oe4,
adc_d, hrxc_adc_clk,
hrxc_ssp_frame, hrxc_ssp_din, ssp_dout, hrxc_ssp_clk,
cross_hi, cross_lo,
hrxc_dbg,
hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop, hi_read_rx_xcorr_quarter
);
hi_simulate hs(
pck0, ck_1356meg, ck_1356megb,
hs_pwr_lo, hs_pwr_hi, hs_pwr_oe1, hs_pwr_oe2, hs_pwr_oe3, hs_pwr_oe4,
adc_d, hs_adc_clk,
hs_ssp_frame, hs_ssp_din, ssp_dout, hs_ssp_clk,
cross_hi, cross_lo,
hs_dbg,
hi_simulate_mod_type
);
hi_iso14443a hisn(
pck0, ck_1356meg, ck_1356megb,
hisn_pwr_lo, hisn_pwr_hi, hisn_pwr_oe1, hisn_pwr_oe2, hisn_pwr_oe3, hisn_pwr_oe4,
adc_d, hisn_adc_clk,
hisn_ssp_frame, hisn_ssp_din, ssp_dout, hisn_ssp_clk,
cross_hi, cross_lo,
hisn_dbg,
hi_simulate_mod_type
);
// Major modes:
// 000 -- LF reader (generic)
// 001 -- LF simulated tag (generic)
// 010 -- HF reader, transmitting to tag; modulation depth selectable
// 011 -- HF reader, receiving from tag, correlating as it goes; frequency selectable
// 100 -- HF simulated tag
// 101 -- HF ISO14443-A
// 110 -- LF passthrough
// 111 -- everything off
mux8 mux_ssp_clk (major_mode, ssp_clk, lr_ssp_clk, ls_ssp_clk, ht_ssp_clk, hrxc_ssp_clk, hs_ssp_clk, hisn_ssp_clk, lp_ssp_clk, 1'b0);
mux8 mux_ssp_din (major_mode, ssp_din, lr_ssp_din, ls_ssp_din, ht_ssp_din, hrxc_ssp_din, hs_ssp_din, hisn_ssp_din, lp_ssp_din, 1'b0);
mux8 mux_ssp_frame (major_mode, ssp_frame, lr_ssp_frame, ls_ssp_frame, ht_ssp_frame, hrxc_ssp_frame, hs_ssp_frame, hisn_ssp_frame, lp_ssp_frame, 1'b0);
mux8 mux_pwr_oe1 (major_mode, pwr_oe1, lr_pwr_oe1, ls_pwr_oe1, ht_pwr_oe1, hrxc_pwr_oe1, hs_pwr_oe1, hisn_pwr_oe1, lp_pwr_oe1, 1'b0);
mux8 mux_pwr_oe2 (major_mode, pwr_oe2, lr_pwr_oe2, ls_pwr_oe2, ht_pwr_oe2, hrxc_pwr_oe2, hs_pwr_oe2, hisn_pwr_oe2, lp_pwr_oe2, 1'b0);
mux8 mux_pwr_oe3 (major_mode, pwr_oe3, lr_pwr_oe3, ls_pwr_oe3, ht_pwr_oe3, hrxc_pwr_oe3, hs_pwr_oe3, hisn_pwr_oe3, lp_pwr_oe3, 1'b0);
mux8 mux_pwr_oe4 (major_mode, pwr_oe4, lr_pwr_oe4, ls_pwr_oe4, ht_pwr_oe4, hrxc_pwr_oe4, hs_pwr_oe4, hisn_pwr_oe4, lp_pwr_oe4, 1'b0);
mux8 mux_pwr_lo (major_mode, pwr_lo, lr_pwr_lo, ls_pwr_lo, ht_pwr_lo, hrxc_pwr_lo, hs_pwr_lo, hisn_pwr_lo, lp_pwr_lo, 1'b0);
mux8 mux_pwr_hi (major_mode, pwr_hi, lr_pwr_hi, ls_pwr_hi, ht_pwr_hi, hrxc_pwr_hi, hs_pwr_hi, hisn_pwr_hi, lp_pwr_hi, 1'b0);
mux8 mux_adc_clk (major_mode, adc_clk, lr_adc_clk, ls_adc_clk, ht_adc_clk, hrxc_adc_clk, hs_adc_clk, hisn_adc_clk, lp_adc_clk, 1'b0);
mux8 mux_dbg (major_mode, dbg, lr_dbg, ls_dbg, ht_dbg, hrxc_dbg, hs_dbg, hisn_dbg, lp_dbg, 1'b0);
// In all modes, let the ADC's outputs be enabled.
assign adc_noe = 1'b0;
endmodule

BIN
fpga/fpga_hf.bit Normal file

Binary file not shown.

151
fpga/fpga_hf.v Normal file
View file

@ -0,0 +1,151 @@
//-----------------------------------------------------------------------------
// The FPGA is responsible for interfacing between the A/D, the coil drivers,
// and the ARM. In the low-frequency modes it passes the data straight
// through, so that the ARM gets raw A/D samples over the SSP. In the high-
// frequency modes, the FPGA might perform some demodulation first, to
// reduce the amount of data that we must send to the ARM.
//
// I am not really an FPGA/ASIC designer, so I am sure that a lot of this
// could be improved.
//
// Jonathan Westhues, March 2006
// Added ISO14443-A support by Gerhard de Koning Gans, April 2008
// iZsh <izsh at fail0verflow.com>, June 2014
//-----------------------------------------------------------------------------
`include "hi_read_tx.v"
`include "hi_read_rx_xcorr.v"
`include "hi_simulate.v"
`include "hi_iso14443a.v"
`include "util.v"
module fpga_hf(
input spck, output miso, input mosi, input ncs,
input pck0, input ck_1356meg, input ck_1356megb,
output pwr_lo, output pwr_hi,
output pwr_oe1, output pwr_oe2, output pwr_oe3, output pwr_oe4,
input [7:0] adc_d, output adc_clk, output adc_noe,
output ssp_frame, output ssp_din, input ssp_dout, output ssp_clk,
input cross_hi, input cross_lo,
output dbg
);
//-----------------------------------------------------------------------------
// The SPI receiver. This sets up the configuration word, which the rest of
// the logic looks at to determine how to connect the A/D and the coil
// drivers (i.e., which section gets it). Also assign some symbolic names
// to the configuration bits, for use below.
//-----------------------------------------------------------------------------
reg [15:0] shift_reg;
reg [7:0] conf_word;
// We switch modes between transmitting to the 13.56 MHz tag and receiving
// from it, which means that we must make sure that we can do so without
// glitching, or else we will glitch the transmitted carrier.
always @(posedge ncs)
begin
case(shift_reg[15:12])
4'b0001: conf_word <= shift_reg[7:0]; // FPGA_CMD_SET_CONFREG
endcase
end
always @(posedge spck)
begin
if(~ncs)
begin
shift_reg[15:1] <= shift_reg[14:0];
shift_reg[0] <= mosi;
end
end
wire [2:0] major_mode;
assign major_mode = conf_word[7:5];
// For the high-frequency transmit configuration: modulation depth, either
// 100% (just quite driving antenna, steady LOW), or shallower (tri-state
// some fraction of the buffers)
wire hi_read_tx_shallow_modulation = conf_word[0];
// For the high-frequency receive correlator: frequency against which to
// correlate.
wire hi_read_rx_xcorr_848 = conf_word[0];
// and whether to drive the coil (reader) or just short it (snooper)
wire hi_read_rx_xcorr_snoop = conf_word[1];
// Divide the expected subcarrier frequency for hi_read_rx_xcorr by 4
wire hi_read_rx_xcorr_quarter = conf_word[2];
// For the high-frequency simulated tag: what kind of modulation to use.
wire [2:0] hi_simulate_mod_type = conf_word[2:0];
//-----------------------------------------------------------------------------
// And then we instantiate the modules corresponding to each of the FPGA's
// major modes, and use muxes to connect the outputs of the active mode to
// the output pins.
//-----------------------------------------------------------------------------
hi_read_tx ht(
pck0, ck_1356meg, ck_1356megb,
ht_pwr_lo, ht_pwr_hi, ht_pwr_oe1, ht_pwr_oe2, ht_pwr_oe3, ht_pwr_oe4,
adc_d, ht_adc_clk,
ht_ssp_frame, ht_ssp_din, ssp_dout, ht_ssp_clk,
cross_hi, cross_lo,
ht_dbg,
hi_read_tx_shallow_modulation
);
hi_read_rx_xcorr hrxc(
pck0, ck_1356meg, ck_1356megb,
hrxc_pwr_lo, hrxc_pwr_hi, hrxc_pwr_oe1, hrxc_pwr_oe2, hrxc_pwr_oe3, hrxc_pwr_oe4,
adc_d, hrxc_adc_clk,
hrxc_ssp_frame, hrxc_ssp_din, ssp_dout, hrxc_ssp_clk,
cross_hi, cross_lo,
hrxc_dbg,
hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop, hi_read_rx_xcorr_quarter
);
hi_simulate hs(
pck0, ck_1356meg, ck_1356megb,
hs_pwr_lo, hs_pwr_hi, hs_pwr_oe1, hs_pwr_oe2, hs_pwr_oe3, hs_pwr_oe4,
adc_d, hs_adc_clk,
hs_ssp_frame, hs_ssp_din, ssp_dout, hs_ssp_clk,
cross_hi, cross_lo,
hs_dbg,
hi_simulate_mod_type
);
hi_iso14443a hisn(
pck0, ck_1356meg, ck_1356megb,
hisn_pwr_lo, hisn_pwr_hi, hisn_pwr_oe1, hisn_pwr_oe2, hisn_pwr_oe3, hisn_pwr_oe4,
adc_d, hisn_adc_clk,
hisn_ssp_frame, hisn_ssp_din, ssp_dout, hisn_ssp_clk,
cross_hi, cross_lo,
hisn_dbg,
hi_simulate_mod_type
);
// Major modes:
// 000 -- HF reader, transmitting to tag; modulation depth selectable
// 001 -- HF reader, receiving from tag, correlating as it goes; frequency selectable
// 010 -- HF simulated tag
// 011 -- HF ISO14443-A
// 111 -- everything off
mux8 mux_ssp_clk (major_mode, ssp_clk, ht_ssp_clk, hrxc_ssp_clk, hs_ssp_clk, hisn_ssp_clk, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_ssp_din (major_mode, ssp_din, ht_ssp_din, hrxc_ssp_din, hs_ssp_din, hisn_ssp_din, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_ssp_frame (major_mode, ssp_frame, ht_ssp_frame, hrxc_ssp_frame, hs_ssp_frame, hisn_ssp_frame, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_pwr_oe1 (major_mode, pwr_oe1, ht_pwr_oe1, hrxc_pwr_oe1, hs_pwr_oe1, hisn_pwr_oe1, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_pwr_oe2 (major_mode, pwr_oe2, ht_pwr_oe2, hrxc_pwr_oe2, hs_pwr_oe2, hisn_pwr_oe2, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_pwr_oe3 (major_mode, pwr_oe3, ht_pwr_oe3, hrxc_pwr_oe3, hs_pwr_oe3, hisn_pwr_oe3, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_pwr_oe4 (major_mode, pwr_oe4, ht_pwr_oe4, hrxc_pwr_oe4, hs_pwr_oe4, hisn_pwr_oe4, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_pwr_lo (major_mode, pwr_lo, ht_pwr_lo, hrxc_pwr_lo, hs_pwr_lo, hisn_pwr_lo, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_pwr_hi (major_mode, pwr_hi, ht_pwr_hi, hrxc_pwr_hi, hs_pwr_hi, hisn_pwr_hi, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_adc_clk (major_mode, adc_clk, ht_adc_clk, hrxc_adc_clk, hs_adc_clk, hisn_adc_clk, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_dbg (major_mode, dbg, ht_dbg, hrxc_dbg, hs_dbg, hisn_dbg, 1'b0, 1'b0, 1'b0, 1'b0);
// In all modes, let the ADC's outputs be enabled.
assign adc_noe = 1'b0;
endmodule

BIN
fpga/fpga_lf.bit Normal file

Binary file not shown.

123
fpga/fpga_lf.v Normal file
View file

@ -0,0 +1,123 @@
//-----------------------------------------------------------------------------
// Jonathan Westhues, March 2006
// iZsh <izsh at fail0verflow.com>, June 2014
//-----------------------------------------------------------------------------
`include "lo_read.v"
`include "lo_passthru.v"
`include "lo_edge_detect.v"
`include "util.v"
`include "clk_divider.v"
module fpga_lf(
input spck, output miso, input mosi, input ncs,
input pck0, input ck_1356meg, input ck_1356megb,
output pwr_lo, output pwr_hi,
output pwr_oe1, output pwr_oe2, output pwr_oe3, output pwr_oe4,
input [7:0] adc_d, output adc_clk, output adc_noe,
output ssp_frame, output ssp_din, input ssp_dout, output ssp_clk,
input cross_hi, input cross_lo,
output dbg
);
//-----------------------------------------------------------------------------
// The SPI receiver. This sets up the configuration word, which the rest of
// the logic looks at to determine how to connect the A/D and the coil
// drivers (i.e., which section gets it). Also assign some symbolic names
// to the configuration bits, for use below.
//-----------------------------------------------------------------------------
reg [15:0] shift_reg;
reg [7:0] divisor;
reg [7:0] conf_word;
reg [7:0] user_byte1;
always @(posedge ncs)
begin
case(shift_reg[15:12])
4'b0001:
begin
conf_word <= shift_reg[7:0];
if (shift_reg[7:0] == 8'b00000001) begin // LF edge detect
user_byte1 <= 127; // default threshold
end
end
4'b0010: divisor <= shift_reg[7:0]; // FPGA_CMD_SET_DIVISOR
4'b0011: user_byte1 <= shift_reg[7:0]; // FPGA_CMD_SET_USER_BYTE1
endcase
end
always @(posedge spck)
begin
if(~ncs)
begin
shift_reg[15:1] <= shift_reg[14:0];
shift_reg[0] <= mosi;
end
end
wire [2:0] major_mode = conf_word[7:5];
// For the low-frequency configuration:
wire lf_field = conf_word[0];
wire lf_ed_toggle_mode = conf_word[1]; // for lo_edge_detect
wire [7:0] lf_ed_threshold = user_byte1;
//-----------------------------------------------------------------------------
// And then we instantiate the modules corresponding to each of the FPGA's
// major modes, and use muxes to connect the outputs of the active mode to
// the output pins.
//-----------------------------------------------------------------------------
wire [7:0] pck_cnt;
wire pck_divclk;
clk_divider div_clk(pck0, divisor, pck_cnt, pck_divclk);
lo_read lr(
pck0, pck_cnt, pck_divclk,
lr_pwr_lo, lr_pwr_hi, lr_pwr_oe1, lr_pwr_oe2, lr_pwr_oe3, lr_pwr_oe4,
adc_d, lr_adc_clk,
lr_ssp_frame, lr_ssp_din, lr_ssp_clk,
lr_dbg, lf_field
);
lo_passthru lp(
pck_divclk,
lp_pwr_lo, lp_pwr_hi, lp_pwr_oe1, lp_pwr_oe2, lp_pwr_oe3, lp_pwr_oe4,
lp_adc_clk,
lp_ssp_din, ssp_dout,
cross_lo,
lp_dbg
);
lo_edge_detect le(
pck0, pck_divclk,
le_pwr_lo, le_pwr_hi, le_pwr_oe1, le_pwr_oe2, le_pwr_oe3, le_pwr_oe4,
adc_d, le_adc_clk,
le_ssp_frame, ssp_dout, le_ssp_clk,
cross_lo,
le_dbg,
lf_field,
lf_ed_toggle_mode, lf_ed_threshold
);
// Major modes:
// 000 -- LF reader (generic)
// 001 -- LF edge detect (generic)
// 010 -- LF passthrough
mux8 mux_ssp_clk (major_mode, ssp_clk, lr_ssp_clk, le_ssp_clk, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_ssp_din (major_mode, ssp_din, lr_ssp_din, 1'b0, lp_ssp_din, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_ssp_frame (major_mode, ssp_frame, lr_ssp_frame, le_ssp_frame, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_pwr_oe1 (major_mode, pwr_oe1, lr_pwr_oe1, le_pwr_oe1, lp_pwr_oe1, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_pwr_oe2 (major_mode, pwr_oe2, lr_pwr_oe2, le_pwr_oe2, lp_pwr_oe2, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_pwr_oe3 (major_mode, pwr_oe3, lr_pwr_oe3, le_pwr_oe3, lp_pwr_oe3, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_pwr_oe4 (major_mode, pwr_oe4, lr_pwr_oe4, le_pwr_oe4, lp_pwr_oe4, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_pwr_lo (major_mode, pwr_lo, lr_pwr_lo, le_pwr_lo, lp_pwr_lo, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_pwr_hi (major_mode, pwr_hi, lr_pwr_hi, le_pwr_hi, lp_pwr_hi, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_adc_clk (major_mode, adc_clk, lr_adc_clk, le_adc_clk, lp_adc_clk, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0);
mux8 mux_dbg (major_mode, dbg, lr_dbg, le_dbg, lp_dbg, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0);
// In all modes, let the ADC's outputs be enabled.
assign adc_noe = 1'b0;
endmodule

View file

@ -2,37 +2,67 @@
rmdir/s/q xst
del fpga.ngc
xst -ifn xst.scr
del fpga_lf.ngc
xst -ifn xst_lf.scr
if errorlevel 0 goto ok1
goto done
:ok1
del fpga.ngd
ngdbuild -aul -p xc2s30-6vq100 -nt timestamp -uc fpga.ucf fpga.ngc fpga.ngd
del fpga_lf.ngd
ngdbuild -aul -p xc2s30-6vq100 -nt timestamp -uc fpga.ucf fpga_lf.ngc fpga_lf.ngd
if errorlevel 0 goto ok2
goto done
:ok2
del fpga.ncd
map -p xc2s30-6vq100 fpga.ngd
del fpga_lf.ncd
map -p xc2s30-6vq100 fpga_lf.ngd
if errorlevel 0 goto ok3
goto done
:ok3
del fpga-placed.ncd
par fpga.ncd fpga-placed.ncd
del fpga_lf-placed.ncd
par fpga_lf.ncd fpga_lf-placed.ncd
if errorlevel 0 goto ok4
goto done
:ok4
del fpga.bit fpga.drc fpga.rbt
bitgen -b fpga-placed.ncd fpga.bit
del fpga_lf.bit fpga_lf.drc fpga_lf.rbt
bitgen -b fpga_lf-placed.ncd fpga_lf.bit
if errorlevel 0 goto ok5
goto done
:ok5
del fpga_hf.ngc
xst -ifn xst_hf.scr
if errorlevel 0 goto ok6
goto done
:ok6
del fpga_hf.ngd
ngdbuild -aul -p xc2s30-6vq100 -nt timestamp -uc fpga.ucf fpga_hf.ngc fpga_hf.ngd
if errorlevel 0 goto ok7
goto done
:ok7
del fpga_hf.ncd
map -p xc2s30-6vq100 fpga_hf.ngd
if errorlevel 0 goto ok8
goto done
:ok8
del fpga_hf-placed.ncd
par fpga_hf.ncd fpga_hf-placed.ncd
if errorlevel 0 goto ok9
goto done
:ok9
del fpga_hf.bit fpga_hf.drc fpga_hf.rbt
bitgen -b fpga_hf-placed.ncd fpga_hf.bit
if errorlevel 0 goto ok10
goto done
:ok10
echo okay
perl ..\tools\rbt2c.pl fpga.rbt > ..\armsrc\fpgaimg.c
perl ..\tools\rbt2c.pl fpga_lf.rbt > ..\armsrc\fpgaimg.c
:done

View file

@ -89,7 +89,9 @@ always @(mod_type or ssp_clk or ssp_dout)
else if(mod_type == 3'b001)
modulating_carrier <= ssp_dout ^ ssp_clk_divider[3]; // XOR means BPSK
else if(mod_type == 3'b010)
modulating_carrier <= ssp_dout & ssp_clk_divider[5]; // switch 212kHz subcarrier on/off
modulating_carrier <= ssp_dout & ssp_clk_divider[5]; // switch 212kHz subcarrier on/off
else if(mod_type == 3'b100)
modulating_carrier <= ssp_dout & ssp_clk_divider[4]; // switch 424kHz modulation on/off
else
modulating_carrier <= 1'b0; // yet unused
@ -105,5 +107,8 @@ assign pwr_oe4 = modulating_carrier;
assign pwr_oe3 = 1'b0;
assign dbg = after_hysteresis;
//reg dbg;
//always @(ssp_dout)
// dbg <= ssp_dout;
endmodule

77
fpga/lf_edge_detect.v Normal file
View file

@ -0,0 +1,77 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
//
// 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.
//-----------------------------------------------------------------------------
// input clk is 24Mhz
`include "min_max_tracker.v"
module lf_edge_detect(input clk, input [7:0] adc_d, input [7:0] lf_ed_threshold,
output [7:0] max, output [7:0] min,
output [7:0] high_threshold, output [7:0] highz_threshold,
output [7:0] lowz_threshold, output [7:0] low_threshold,
output edge_state, output edge_toggle);
min_max_tracker tracker(clk, adc_d, lf_ed_threshold, min, max);
// auto-tune
assign high_threshold = (max + min) / 2 + (max - min) / 4;
assign highz_threshold = (max + min) / 2 + (max - min) / 8;
assign lowz_threshold = (max + min) / 2 - (max - min) / 8;
assign low_threshold = (max + min) / 2 - (max - min) / 4;
// heuristic to see if it makes sense to try to detect an edge
wire enabled =
(high_threshold > highz_threshold)
& (highz_threshold > lowz_threshold)
& (lowz_threshold > low_threshold)
& ((high_threshold - highz_threshold) > 8)
& ((highz_threshold - lowz_threshold) > 16)
& ((lowz_threshold - low_threshold) > 8);
// Toggle the output with hysteresis
// Set to high if the ADC value is above the threshold
// Set to low if the ADC value is below the threshold
reg is_high = 0;
reg is_low = 0;
reg is_zero = 0;
reg trigger_enabled = 1;
reg output_edge = 0;
reg output_state;
always @(posedge clk)
begin
is_high <= (adc_d >= high_threshold);
is_low <= (adc_d <= low_threshold);
is_zero <= ((adc_d > lowz_threshold) & (adc_d < highz_threshold));
end
// all edges detection
always @(posedge clk)
if (enabled) begin
// To enable detecting two consecutive peaks at the same level
// (low or high) we check whether or not we went back near 0 in-between.
// This extra check is necessary to prevent from noise artifacts
// around the threshold values.
if (trigger_enabled & (is_high | is_low)) begin
output_edge <= ~output_edge;
trigger_enabled <= 0;
end else
trigger_enabled <= trigger_enabled | is_zero;
end
// edge states
always @(posedge clk)
if (enabled) begin
if (is_high)
output_state <= 1'd1;
else if (is_low)
output_state <= 1'd0;
end
assign edge_state = output_state;
assign edge_toggle = output_edge;
endmodule

View file

@ -1,40 +1,38 @@
//-----------------------------------------------------------------------------
// The way that we connect things in low-frequency simulation mode. In this
// case just pass everything through to the ARM, which can bit-bang this
// (because it is so slow).
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
//
// Jonathan Westhues, April 2006
// 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.
//-----------------------------------------------------------------------------
//
// There are two modes:
// - lf_ed_toggle_mode == 0: the output is set low (resp. high) when a low
// (resp. high) edge/peak is detected, with hysteresis
// - lf_ed_toggle_mode == 1: the output is toggling whenever an edge/peak
// is detected.
// That way you can detect two consecutive edges/peaks at the same level (L/H)
//
// Output:
// - ssp_frame (wired to TIOA1 on the arm) for the edge detection/state
// - ssp_clk: cross_lo
`include "lp20khz_1MSa_iir_filter.v"
`include "lf_edge_detect.v"
module lo_edge_detect(
pck0, ck_1356meg, ck_1356megb,
pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
adc_d, adc_clk,
ssp_frame, ssp_din, ssp_dout, ssp_clk,
cross_hi, cross_lo,
dbg,
divisor,
lf_field
input pck0, input pck_divclk,
output pwr_lo, output pwr_hi,
output pwr_oe1, output pwr_oe2, output pwr_oe3, output pwr_oe4,
input [7:0] adc_d, output adc_clk,
output ssp_frame, input ssp_dout, output ssp_clk,
input cross_lo,
output dbg,
input lf_field,
input lf_ed_toggle_mode, input [7:0] lf_ed_threshold
);
input pck0, ck_1356meg, ck_1356megb;
output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;
input [7:0] adc_d;
output adc_clk;
input ssp_dout;
output ssp_frame, ssp_din, ssp_clk;
input cross_hi, cross_lo;
output dbg;
input [7:0] divisor;
input lf_field;
// Divide the clock to be used for the ADC
reg [7:0] pck_divider;
reg clk_state;
wire tag_modulation;
assign tag_modulation = ssp_dout & !lf_field;
wire reader_modulation;
assign reader_modulation = !ssp_dout & lf_field & clk_state;
wire tag_modulation = ssp_dout & !lf_field;
wire reader_modulation = !ssp_dout & lf_field & pck_divclk;
// No logic, straight through.
assign pwr_oe1 = 1'b0; // not used in LF mode
@ -44,47 +42,25 @@ assign pwr_oe4 = tag_modulation;
assign ssp_clk = cross_lo;
assign pwr_lo = reader_modulation;
assign pwr_hi = 1'b0;
assign dbg = ssp_frame;
always @(posedge pck0)
begin
if(pck_divider == divisor[7:0])
begin
pck_divider <= 8'd0;
clk_state = !clk_state;
end
else
begin
pck_divider <= pck_divider + 1;
end
end
// filter the ADC values
wire data_rdy;
wire [7:0] adc_filtered;
assign adc_clk = pck0;
lp20khz_1MSa_iir_filter adc_filter(pck0, adc_d, data_rdy, adc_filtered);
assign adc_clk = ~clk_state;
// detect edges
wire [7:0] high_threshold, highz_threshold, lowz_threshold, low_threshold;
wire [7:0] max, min;
wire edge_state, edge_toggle;
lf_edge_detect lf_ed(pck0, adc_filtered, lf_ed_threshold,
max, min,
high_threshold, highz_threshold, lowz_threshold, low_threshold,
edge_state, edge_toggle);
// Toggle the output with hysteresis
// Set to high if the ADC value is above 200
// Set to low if the ADC value is below 64
reg is_high;
reg is_low;
reg output_state;
assign dbg = lf_ed_toggle_mode ? edge_toggle : edge_state;
always @(posedge pck0)
begin
if((pck_divider == 8'd7) && !clk_state) begin
is_high = (adc_d >= 8'd190);
is_low = (adc_d <= 8'd70);
end
end
always @(posedge is_high or posedge is_low)
begin
if(is_high)
output_state <= 1'd1;
else if(is_low)
output_state <= 1'd0;
end
assign ssp_frame = output_state;
assign ssp_frame = lf_ed_toggle_mode ? edge_toggle : edge_state;
endmodule

View file

@ -2,44 +2,17 @@
// For reading TI tags, we need to place the FPGA in pass through mode
// and pass everything through to the ARM
//-----------------------------------------------------------------------------
// iZsh <izsh at fail0verflow.com>, June 2014
module lo_passthru(
pck0, ck_1356meg, ck_1356megb,
pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
adc_d, adc_clk,
ssp_frame, ssp_din, ssp_dout, ssp_clk,
cross_hi, cross_lo,
dbg, divisor
input pck_divclk,
output pwr_lo, output pwr_hi,
output pwr_oe1, output pwr_oe2, output pwr_oe3, output pwr_oe4,
output adc_clk,
output ssp_din, input ssp_dout,
input cross_lo,
output dbg
);
input pck0, ck_1356meg, ck_1356megb;
output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;
input [7:0] adc_d;
output adc_clk;
input ssp_dout;
output ssp_frame, ssp_din, ssp_clk;
input cross_hi, cross_lo;
output dbg;
input [7:0] divisor;
reg [7:0] pck_divider;
reg ant_lo;
// this task runs on the rising egde of pck0 clock (24Mhz) and creates ant_lo
// which is high for (divisor+1) pck0 cycles and low for the same duration
// ant_lo is therefore a 50% duty cycle clock signal with a frequency of
// 12Mhz/(divisor+1) which drives the antenna as well as the ADC clock adc_clk
always @(posedge pck0)
begin
if(pck_divider == divisor[7:0])
begin
pck_divider <= 8'd0;
ant_lo = !ant_lo;
end
else
begin
pck_divider <= pck_divider + 1;
end
end
// the antenna is modulated when ssp_dout = 1, when 0 the
// antenna drivers stop modulating and go into listen mode
@ -47,7 +20,7 @@ assign pwr_oe3 = 1'b0;
assign pwr_oe1 = ssp_dout;
assign pwr_oe2 = ssp_dout;
assign pwr_oe4 = ssp_dout;
assign pwr_lo = ant_lo && ssp_dout;
assign pwr_lo = pck_divclk && ssp_dout;
assign pwr_hi = 1'b0;
assign adc_clk = 1'b0;
assign ssp_din = cross_lo;

View file

@ -4,68 +4,39 @@
// The A/D samples at that same rate and the result is serialized.
//
// Jonathan Westhues, April 2006
// iZsh <izsh at fail0verflow.com>, June 2014
//-----------------------------------------------------------------------------
module lo_read(
pck0, ck_1356meg, ck_1356megb,
pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4,
adc_d, adc_clk,
ssp_frame, ssp_din, ssp_dout, ssp_clk,
cross_hi, cross_lo,
dbg,
lo_is_125khz, divisor
input pck0, input [7:0] pck_cnt, input pck_divclk,
output pwr_lo, output pwr_hi,
output pwr_oe1, output pwr_oe2, output pwr_oe3, output pwr_oe4,
input [7:0] adc_d, output adc_clk,
output ssp_frame, output ssp_din, output ssp_clk,
output dbg,
input lf_field
);
input pck0, ck_1356meg, ck_1356megb;
output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4;
input [7:0] adc_d;
output adc_clk;
input ssp_dout;
output ssp_frame, ssp_din, ssp_clk;
input cross_hi, cross_lo;
output dbg;
input lo_is_125khz; // redundant signal, no longer used anywhere
input [7:0] divisor;
reg [7:0] to_arm_shiftreg;
reg [7:0] pck_divider;
reg ant_lo;
// this task runs on the rising egde of pck0 clock (24Mhz) and creates ant_lo
// which is high for (divisor+1) pck0 cycles and low for the same duration
// ant_lo is therefore a 50% duty cycle clock signal with a frequency of
// 12Mhz/(divisor+1) which drives the antenna as well as the ADC clock adc_clk
always @(posedge pck0)
begin
if(pck_divider == divisor[7:0])
begin
pck_divider <= 8'd0;
ant_lo = !ant_lo;
end
else
begin
pck_divider <= pck_divider + 1;
end
end
// this task also runs at pck0 frequency (24Mhz) and is used to serialize
// the ADC output which is then clocked into the ARM SSP.
// because ant_lo always transitions when pck_divider = 0 we use the
// pck_divider counter to sync our other signals off it
// we read the ADC value when pck_divider=7 and shift it out on counts 8..15
// because pck_divclk always transitions when pck_cnt = 0 we use the
// pck_div counter to sync our other signals off it
// we read the ADC value when pck_cnt=7 and shift it out on counts 8..15
always @(posedge pck0)
begin
if((pck_divider == 8'd7) && !ant_lo)
to_arm_shiftreg <= adc_d;
else
begin
to_arm_shiftreg[7:1] <= to_arm_shiftreg[6:0];
if((pck_cnt == 8'd7) && !pck_divclk)
to_arm_shiftreg <= adc_d;
else begin
to_arm_shiftreg[7:1] <= to_arm_shiftreg[6:0];
// simulation showed a glitch occuring due to the LSB of the shifter
// not being set as we shift bits out
// this ensures the ssp_din remains low after a transfer and suppresses
// the glitch that would occur when the last data shifted out ended in
// a 1 bit and the next data shifted out started with a 0 bit
to_arm_shiftreg[0] <= 1'b0;
to_arm_shiftreg[0] <= 1'b0;
end
end
@ -83,11 +54,11 @@ end
// ssp_clk |_| |_| |_| |_| |_| |_| |_| |_| |_| |_
// serialized SSP data is gated by ant_lo to suppress unwanted signal
assign ssp_din = to_arm_shiftreg[7] && !ant_lo;
assign ssp_din = to_arm_shiftreg[7] && !pck_divclk;
// SSP clock always runs at 24Mhz
assign ssp_clk = pck0;
// SSP frame is gated by ant_lo and goes high when pck_divider=8..15
assign ssp_frame = (pck_divider[7:3] == 5'd1) && !ant_lo;
assign ssp_frame = (pck_cnt[7:3] == 5'd1) && !pck_divclk;
// unused signals tied low
assign pwr_hi = 1'b0;
assign pwr_oe1 = 1'b0;
@ -95,9 +66,9 @@ assign pwr_oe2 = 1'b0;
assign pwr_oe3 = 1'b0;
assign pwr_oe4 = 1'b0;
// this is the antenna driver signal
assign pwr_lo = ant_lo;
assign pwr_lo = lf_field & pck_divclk;
// ADC clock out of phase with antenna driver
assign adc_clk = ~ant_lo;
assign adc_clk = ~pck_divclk;
// ADC clock also routed to debug pin
assign dbg = adc_clk;
endmodule

View file

@ -0,0 +1,81 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
//
// 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.
//-----------------------------------------------------------------------------
// Butterworth low pass IIR filter
// input: 8bit ADC signal, 1MS/s
// output: 8bit value, Fc=20khz
//
// coef: (using http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html)
// Recurrence relation:
// y[n] = ( 1 * x[n- 2])
// + ( 2 * x[n- 1])
// + ( 1 * x[n- 0])
// + ( -0.8371816513 * y[n- 2])
// + ( 1.8226949252 * y[n- 1])
//
// therefore:
// a = [1,2,1]
// b = [-0.8371816513, 1.8226949252]
// b is approximated to b = [-0xd6/0x100, 0x1d3 / 0x100] (for optimization)
// gain = 2.761139367e2
//
// See details about its design see
// https://fail0verflow.com/blog/2014/proxmark3-fpga-iir-filter.html
module lp20khz_1MSa_iir_filter(input clk, input [7:0] adc_d, output rdy, output [7:0] out);
// clk is 24Mhz, the IIR filter is designed for 1MS/s
// hence we need to divide it by 24
// using a shift register takes less area than a counter
reg [23:0] cnt = 1;
assign rdy = cnt[0];
always @(posedge clk)
cnt <= {cnt[22:0], cnt[23]};
reg [7:0] x0 = 0;
reg [7:0] x1 = 0;
reg [16:0] y0 = 0;
reg [16:0] y1 = 0;
always @(posedge clk)
begin
if (rdy)
begin
x0 <= x1;
x1 <= adc_d;
y0 <= y1;
y1 <=
// center the signal:
// input range is [0; 255]
// We want "128" to be at the center of the 17bit register
// (128+z)*gain = 17bit center
// z = (1<<16)/gain - 128 = 109
// We could use 9bit x registers for that, but that would be
// a waste, let's just add the constant during the computation
// (x0+109) + 2*(x1+109) + (x2+109) = x0 + 2*x1 + x2 + 436
x0 + {x1, 1'b0} + adc_d + 436
// we want "- y0 * 0xd6 / 0x100" using only shift and add
// 0xd6 == 0b11010110
// so *0xd6/0x100 is equivalent to
// ((x << 1) + (x << 2) + (x << 4) + (x << 6) + (x << 7)) >> 8
// which is also equivalent to
// (x >> 7) + (x >> 6) + (x >> 4) + (x >> 2) + (x >> 1)
- ((y0 >> 7) + (y0 >> 6) + (y0 >> 4) + (y0 >> 2) + (y0 >> 1)) // - y0 * 0xd6 / 0x100
// we want "+ y1 * 0x1d3 / 0x100"
// 0x1d3 == 0b111010011
// so this is equivalent to
// ((x << 0) + (x << 1) + (x << 4) + (x << 6) + (x << 7) + (x << 8)) >> 8
// which is also equivalent to
// (x >> 8) + (x >> 7) + (x >> 4) + (x >> 2) + (x >> 1) + (x >> 0)
+ ((y1 >> 8) + (y1 >> 7) + (y1 >> 4) + (y1 >> 2) + (y1 >> 1) + y1);
end
end
// output: reduce to 8bit
assign out = y1[16:9];
endmodule

65
fpga/min_max_tracker.v Normal file
View file

@ -0,0 +1,65 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
//
// 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.
//-----------------------------------------------------------------------------
// track min and max peak values (envelope follower)
//
// NB: the min value (resp. max value) is updated only when the next high peak
// (resp. low peak) is reached/detected, since you can't know it isn't a
// local minima (resp. maxima) until then.
// This also means the peaks are detected with an unpredictable delay.
// This algorithm therefore can't be used directly for realtime peak detections,
// but it can be used as a simple envelope follower.
module min_max_tracker(input clk, input [7:0] adc_d, input [7:0] threshold,
output [7:0] min, output [7:0] max);
reg [7:0] min_val = 255;
reg [7:0] max_val = 0;
reg [7:0] cur_min_val = 255;
reg [7:0] cur_max_val = 0;
reg [1:0] state = 0;
always @(posedge clk)
begin
case (state)
0:
begin
if (cur_max_val >= ({1'b0, adc_d} + threshold))
state <= 2;
else if (adc_d >= ({1'b0, cur_min_val} + threshold))
state <= 1;
if (cur_max_val <= adc_d)
cur_max_val <= adc_d;
else if (adc_d <= cur_min_val)
cur_min_val <= adc_d;
end
1:
begin
if (cur_max_val <= adc_d)
cur_max_val <= adc_d;
else if (({1'b0, adc_d} + threshold) <= cur_max_val) begin
state <= 2;
cur_min_val <= adc_d;
max_val <= cur_max_val;
end
end
2:
begin
if (adc_d <= cur_min_val)
cur_min_val <= adc_d;
else if (adc_d >= ({1'b0, cur_min_val} + threshold)) begin
state <= 1;
cur_max_val <= adc_d;
min_val <= cur_min_val;
end
end
endcase
end
assign min = min_val;
assign max = max_val;
endmodule

87
fpga/tests/Makefile Normal file
View file

@ -0,0 +1,87 @@
#-----------------------------------------------------------------------------
# Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
#
# 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.
#-----------------------------------------------------------------------------
TEST_OUTDIR = tb_tmp
TB_SOURCES = \
tb_lp20khz_1MSa_iir_filter.v \
tb_min_max_tracker.v \
tb_lf_edge_detect.v
TBS = $(TB_SOURCES:.v=.vvp)
TB_DATA = \
pcf7931_write1byte_1MSA_data \
pcf7931_read_1MSA_data
all: $(TBS) tests
%.vvp: %.v
iverilog -I .. -o $@ $<
clean:
rm -rf *.vvp $(TEST_OUTDIR)
tests: tb_lp20khz_1MSa_iir_filter tb_min_max_tracker tb_lf_edge_detect
tb_lp20khz_1MSa_iir_filter: tb_lp20khz_1MSa_iir_filter.vvp | test_dir
@printf "Testing $@\n"
@for d in $(TB_DATA); do \
$(call run_test,$@.vvp,$$d,in); \
$(call check_golden,$$d,filtered); \
done; \
rm -f $(TEST_OUTDIR)/data.*
tb_min_max_tracker: tb_min_max_tracker.vvp | test_dir
@printf "Testing $@\n"
@for d in $(TB_DATA); do \
$(call run_test,$@.vvp,$$d,in filtered.gold); \
$(call check_golden,$$d,min); \
$(call check_golden,$$d,max); \
done; \
rm -f $(TEST_OUTDIR)/data.*
tb_lf_edge_detect: tb_lf_edge_detect.vvp | test_dir
@printf "Testing $@\n"
@for d in $(TB_DATA); do \
$(call run_test,$@.vvp,$$d,in filtered.gold); \
$(call check_golden,$$d,min); \
$(call check_golden,$$d,max); \
$(call check_golden,$$d,state); \
$(call check_golden,$$d,toggle); \
$(call check_golden,$$d,high); \
$(call check_golden,$$d,highz); \
$(call check_golden,$$d,lowz); \
$(call check_golden,$$d,low); \
done; \
rm -f $(TEST_OUTDIR)/data.*
test_dir:
@if [ ! -d $(TEST_OUTDIR) ] ; then mkdir $(TEST_OUTDIR) ; fi
.PHONY: all clean
# $(1) = basename
# $(2) = extension to check
check_golden = \
printf " Checking $(1).$(2)... "; \
mv $(TEST_OUTDIR)/data.$(2) $(TEST_OUTDIR)/$(1).$(2); \
if cmp -s tb_data/$(1).$(2).gold $(TEST_OUTDIR)/$(1).$(2); then \
printf "OK\n"; \
else \
printf "ERROR\n"; \
fi
# $(1) = vvp file
# $(2) = data basename
# $(3) = data extensions to copy
run_test = \
env echo " With $(2)... "; \
cp tb_data/$(2).time $(TEST_OUTDIR); \
for e in $(3); do cp tb_data/$(2).$$e $(TEST_OUTDIR)/data.$$e; done; \
./$(1)

58
fpga/tests/plot_edgedetect.py Executable file
View file

@ -0,0 +1,58 @@
#!/usr/bin/env python
#-----------------------------------------------------------------------------
# Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
#
# 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.
#-----------------------------------------------------------------------------
import numpy
import matplotlib.pyplot as plt
import sys
if len(sys.argv) != 2:
print "Usage: %s <basename>" % sys.argv[0]
sys.exit(1)
BASENAME = sys.argv[1]
nx = numpy.fromfile(BASENAME + ".time")
def plot_time(dat1):
plt.plot(nx, dat1)
sig = open(BASENAME + ".filtered").read()
sig = map(lambda x: ord(x), sig)
min_vals = open(BASENAME + ".min").read()
min_vals = map(lambda x: ord(x), min_vals)
max_vals = open(BASENAME + ".max").read()
max_vals = map(lambda x: ord(x), max_vals)
states = open(BASENAME + ".state").read()
states = map(lambda x: ord(x) * 10 + 65, states)
toggles = open(BASENAME+ ".toggle").read()
toggles = map(lambda x: ord(x) * 10 + 80, toggles)
high = open(BASENAME + ".high").read()
high = map(lambda x: ord(x), high)
highz = open(BASENAME + ".highz").read()
highz = map(lambda x: ord(x), highz)
lowz = open(BASENAME + ".lowz").read()
lowz = map(lambda x: ord(x), lowz)
low = open(BASENAME + ".low").read()
low = map(lambda x: ord(x), low)
plot_time(sig)
plot_time(min_vals)
plot_time(max_vals)
plot_time(states)
plot_time(toggles)
plot_time(high)
plot_time(highz)
plot_time(lowz)
plot_time(low)
plt.show()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

View file

@ -0,0 +1,111 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
//
// 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.
//-----------------------------------------------------------------------------
// testbench for lf_edge_detect
`include "lf_edge_detect.v"
`define FIN "tb_tmp/data.filtered.gold"
`define FOUT_MIN "tb_tmp/data.min"
`define FOUT_MAX "tb_tmp/data.max"
`define FOUT_STATE "tb_tmp/data.state"
`define FOUT_TOGGLE "tb_tmp/data.toggle"
`define FOUT_HIGH "tb_tmp/data.high"
`define FOUT_HIGHZ "tb_tmp/data.highz"
`define FOUT_LOWZ "tb_tmp/data.lowz"
`define FOUT_LOW "tb_tmp/data.low"
module lf_edge_detect_tb;
integer fin, fout_state, fout_toggle;
integer fout_high, fout_highz, fout_lowz, fout_low, fout_min, fout_max;
integer r;
reg clk = 0;
reg [7:0] adc_d;
wire adc_clk;
wire data_rdy;
wire edge_state;
wire edge_toggle;
wire [7:0] high_threshold;
wire [7:0] highz_threshold;
wire [7:0] lowz_threshold;
wire [7:0] low_threshold;
wire [7:0] max;
wire [7:0] min;
initial
begin
clk = 0;
fin = $fopen(`FIN, "r");
if (!fin) begin
$display("ERROR: can't open the data file");
$finish;
end
fout_min = $fopen(`FOUT_MIN, "w+");
fout_max = $fopen(`FOUT_MAX, "w+");
fout_state = $fopen(`FOUT_STATE, "w+");
fout_toggle = $fopen(`FOUT_TOGGLE, "w+");
fout_high = $fopen(`FOUT_HIGH, "w+");
fout_highz = $fopen(`FOUT_HIGHZ, "w+");
fout_lowz = $fopen(`FOUT_LOWZ, "w+");
fout_low = $fopen(`FOUT_LOW, "w+");
if (!$feof(fin))
adc_d = $fgetc(fin); // read the first value
end
always
# 1 clk = !clk;
// input
initial
begin
while (!$feof(fin)) begin
@(negedge clk) adc_d <= $fgetc(fin);
end
if ($feof(fin))
begin
# 3 $fclose(fin);
$fclose(fout_state);
$fclose(fout_toggle);
$fclose(fout_high);
$fclose(fout_highz);
$fclose(fout_lowz);
$fclose(fout_low);
$fclose(fout_min);
$fclose(fout_max);
$finish;
end
end
initial
begin
// $monitor("%d\t S: %b, E: %b", $time, edge_state, edge_toggle);
end
// output
always @(negedge clk)
if ($time > 2) begin
r = $fputc(min, fout_min);
r = $fputc(max, fout_max);
r = $fputc(edge_state, fout_state);
r = $fputc(edge_toggle, fout_toggle);
r = $fputc(high_threshold, fout_high);
r = $fputc(highz_threshold, fout_highz);
r = $fputc(lowz_threshold, fout_lowz);
r = $fputc(low_threshold, fout_low);
end
// module to test
lf_edge_detect detect(clk, adc_d, 8'd127,
max, min,
high_threshold, highz_threshold,
lowz_threshold, low_threshold,
edge_state, edge_toggle);
endmodule

View file

@ -0,0 +1,55 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
//
// 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.
//-----------------------------------------------------------------------------
// testbench for lp20khz_1MSa_iir_filter
`include "lp20khz_1MSa_iir_filter.v"
`define FIN "tb_tmp/data.in"
`define FOUT "tb_tmp/data.filtered"
module lp20khz_1MSa_iir_filter_tb;
integer fin, fout, r;
reg clk;
reg [7:0] adc_d;
wire data_rdy;
wire [7:0] adc_filtered;
initial
begin
clk = 0;
fin = $fopen(`FIN, "r");
if (!fin) begin
$display("ERROR: can't open the data file");
$finish;
end
fout = $fopen(`FOUT, "w+");
if (!$feof(fin))
adc_d = $fgetc(fin); // read the first value
end
always
# 1 clk = !clk;
always @(posedge clk)
if (data_rdy) begin
if ($time > 1)
r = $fputc(adc_filtered, fout);
if (!$feof(fin))
adc_d <= $fgetc(fin);
else begin
$fclose(fin);
$fclose(fout);
$finish;
end
end
// module to test
lp20khz_1MSa_iir_filter filter(clk, adc_d, data_rdy, adc_filtered);
endmodule

View file

@ -0,0 +1,74 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2014 iZsh <izsh at fail0verflow.com>
//
// 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.
//-----------------------------------------------------------------------------
// testbench for min_max_tracker
`include "min_max_tracker.v"
`define FIN "tb_tmp/data.filtered.gold"
`define FOUT_MIN "tb_tmp/data.min"
`define FOUT_MAX "tb_tmp/data.max"
module min_max_tracker_tb;
integer fin;
integer fout_min, fout_max;
integer r;
reg clk;
reg [7:0] adc_d;
wire [7:0] min;
wire [7:0] max;
initial
begin
clk = 0;
fin = $fopen(`FIN, "r");
if (!fin) begin
$display("ERROR: can't open the data file");
$finish;
end
fout_min = $fopen(`FOUT_MIN, "w+");
fout_max = $fopen(`FOUT_MAX, "w+");
if (!$feof(fin))
adc_d = $fgetc(fin); // read the first value
end
always
# 1 clk = !clk;
// input
initial
begin
while (!$feof(fin)) begin
@(negedge clk) adc_d <= $fgetc(fin);
end
if ($feof(fin))
begin
# 3 $fclose(fin);
$fclose(fout_min);
$fclose(fout_max);
$finish;
end
end
initial
begin
// $monitor("%d\t min: %x, max: %x", $time, min, max);
end
// output
always @(negedge clk)
if ($time > 2) begin
r = $fputc(min, fout_min);
r = $fputc(max, fout_max);
end
// module to test
min_max_tracker tracker(clk, adc_d, 8'd127, min, max);
endmodule

View file

@ -1 +0,0 @@
run -ifn fpga.v -ifmt Verilog -ofn fpga.ngc -ofmt NGC -p xc2s30-5-vq100 -opt_mode Speed -opt_level 1 -ent fpga

1
fpga/xst_hf.scr Normal file
View file

@ -0,0 +1 @@
run -ifn fpga_hf.v -ifmt Verilog -ofn fpga_hf.ngc -ofmt NGC -p xc2s30-5-vq100 -top fpga_hf -opt_mode area -opt_level 2 -resource_sharing yes -fsm_style bram -fsm_encoding compact

1
fpga/xst_lf.scr Normal file
View file

@ -0,0 +1 @@
run -ifn fpga_lf.v -ifmt Verilog -ofn fpga_lf.ngc -ofmt NGC -p xc2s30-5-vq100 -top fpga_lf -opt_mode area -opt_level 2 -resource_sharing yes -fsm_style bram -fsm_encoding compact

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Some files were not shown because too many files have changed in this diff Show more