mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-08-23 22:45:27 -07:00
lf viking and iclass
add lf viking add Iclass write
This commit is contained in:
parent
b067125f98
commit
7f99524209
20 changed files with 970 additions and 400 deletions
|
@ -684,6 +684,11 @@ void UsbPacketReceived(uint8_t *packet, int len)
|
||||||
case CMD_AWID_DEMOD_FSK: // Set realtime AWID demodulation
|
case CMD_AWID_DEMOD_FSK: // Set realtime AWID demodulation
|
||||||
CmdAWIDdemodFSK(c->arg[0], 0, 0, 1);
|
CmdAWIDdemodFSK(c->arg[0], 0, 0, 1);
|
||||||
break;
|
break;
|
||||||
|
case CMD_VIKING_CLONE_TAG:
|
||||||
|
CopyViKingtoT55x7(c->arg[0],c->arg[1]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_HITAG
|
#ifdef WITH_HITAG
|
||||||
|
@ -868,6 +873,16 @@ void UsbPacketReceived(uint8_t *packet, int len)
|
||||||
case CMD_ICLASS_EML_MEMSET:
|
case CMD_ICLASS_EML_MEMSET:
|
||||||
emlSet(c->d.asBytes,c->arg[0], c->arg[1]);
|
emlSet(c->d.asBytes,c->arg[0], c->arg[1]);
|
||||||
break;
|
break;
|
||||||
|
case CMD_ICLASS_ISO14443A_WRITE:
|
||||||
|
IClass_iso14443A_write(c->arg[0],c->d.asBytes);
|
||||||
|
break;
|
||||||
|
case CMD_ICLASS_AUTHENTICATION:
|
||||||
|
IClass_Authentication(c->d.asBytes);
|
||||||
|
break;
|
||||||
|
case CMD_ICLASS_CLONE:
|
||||||
|
IClass_Clone(c->arg[0],c->arg[1],c->d.asBytes);
|
||||||
|
break;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case CMD_BUFF_CLEAR:
|
case CMD_BUFF_CLEAR:
|
||||||
|
|
|
@ -168,7 +168,10 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain
|
||||||
void ReaderIClass(uint8_t arg0);
|
void ReaderIClass(uint8_t arg0);
|
||||||
void ReaderIClass_Replay(uint8_t arg0,uint8_t *MAC);
|
void ReaderIClass_Replay(uint8_t arg0,uint8_t *MAC);
|
||||||
void IClass_iso14443A_GetPublic(uint8_t arg0);
|
void IClass_iso14443A_GetPublic(uint8_t arg0);
|
||||||
|
void IClass_Authentication(uint8_t *MAC);
|
||||||
|
void IClass_iso14443A_write(uint8_t blockno,uint8_t *data);
|
||||||
|
void IClass_Clone(uint8_t startblock,uint8_t endblock,uint8_t *data);
|
||||||
|
void CopyViKingtoT55x7(uint32_t block1,uint32_t block2);
|
||||||
// hitag2.h
|
// hitag2.h
|
||||||
void SnoopHitag(uint32_t type);
|
void SnoopHitag(uint32_t type);
|
||||||
void SimulateHitagTag(bool tag_mem_supplied, byte_t* data);
|
void SimulateHitagTag(bool tag_mem_supplied, byte_t* data);
|
||||||
|
|
164
armsrc/iclass.c
164
armsrc/iclass.c
|
@ -1903,131 +1903,57 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) {
|
||||||
|
|
||||||
LED_A_OFF();
|
LED_A_OFF();
|
||||||
}
|
}
|
||||||
|
void IClass_Authentication(uint8_t *MAC){
|
||||||
//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 check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 };
|
uint8_t resp[ICLASS_BUFFER_SIZE];
|
||||||
|
memcpy(check+5,MAC,4);
|
||||||
|
|
||||||
|
sendCmdGetResponseWithRetries(check, sizeof(check),resp, 8, 5);
|
||||||
|
// successful
|
||||||
|
}
|
||||||
|
void IClass_iso14443A_write(uint8_t blockNo, uint8_t *data) {
|
||||||
uint8_t write[] = { 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
uint8_t write[] = { 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
uint16_t crc = 0;
|
write[1] = blockNo;
|
||||||
|
memcpy(write + 2,data,8); // data
|
||||||
|
memcpy(write+10,data + 8,4); // mac no
|
||||||
|
uint8_t r[12];
|
||||||
|
|
||||||
uint8_t* resp = (((uint8_t *)BigBuf) + 3560);
|
// 0x87
|
||||||
|
sendCmdGetResponseWithRetries(write,sizeof(write),r,sizeof(r),5);
|
||||||
|
Dbprintf("reply [%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x]",r[0],r[1],r[2],r[3],r[4],r[5],r[6],r[7],r[8],r[9],r[10],r[11]);
|
||||||
|
|
||||||
// Reset trace buffer
|
if (memcmp(data,r,8) == 0)
|
||||||
memset(trace, 0x44, RECV_CMD_OFFSET);
|
Dbprintf("Write block [%02x] ok",blockNo);
|
||||||
traceLen = 0;
|
else
|
||||||
|
Dbprintf("Write block [%02x] fail",blockNo);
|
||||||
|
}
|
||||||
|
void IClass_Clone(uint8_t startblock,uint8_t endblock,uint8_t *data){
|
||||||
|
uint8_t write[] = { 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
uint8_t r[12];
|
||||||
|
int i;
|
||||||
|
int written = 0;
|
||||||
|
int total_block = (endblock - startblock) + 1;
|
||||||
|
for (i = 0; i < total_block;i++){
|
||||||
|
// block number
|
||||||
|
write[0] = 0x87;
|
||||||
|
write[1] = i + startblock;
|
||||||
|
// data
|
||||||
|
memcpy(write + 2,data + (i * 12),8);
|
||||||
|
// mac number
|
||||||
|
memcpy(write + 10,data + ((i * 12) + 8), 4);
|
||||||
|
sendCmdGetResponseWithRetries(write,sizeof(write),r,sizeof(r),5);
|
||||||
|
|
||||||
// Setup SSC
|
if (memcmp(write + 2,r,8) == 0){
|
||||||
FpgaSetupSsc();
|
Dbprintf("Write block [%02x] ok",i + 6);
|
||||||
// Start from off (no field generated)
|
written++;
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (BUTTON_PRESS()) break;
|
Dbprintf("Write block [%02x] fail",i + 6);
|
||||||
|
|
||||||
// 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
|
if (written == total_block)
|
||||||
Dbprintf("Readcheck on Sector 2");
|
Dbprintf("Clone complete");
|
||||||
ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
|
else
|
||||||
if(ReaderReceiveIClass(resp) == 8) {
|
Dbprintf("Clone incomplete");
|
||||||
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();
|
|
||||||
}*/
|
|
||||||
|
|
|
@ -2062,3 +2062,14 @@ void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
|
||||||
LED_D_OFF();
|
LED_D_OFF();
|
||||||
}
|
}
|
||||||
|
void CopyViKingtoT55x7(uint32_t block1,uint32_t block2)
|
||||||
|
{
|
||||||
|
LED_D_ON();
|
||||||
|
T55xxWriteBlock(block1,1,0,0);
|
||||||
|
T55xxWriteBlock(block2,2,0,0);
|
||||||
|
|
||||||
|
T55xxWriteBlock(T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_32 | 2 << T5555_MAXBLOCK_SHIFT,0,0,1);
|
||||||
|
LED_D_OFF();
|
||||||
|
DbpString("DONE!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
1
client/.history
Normal file
1
client/.history
Normal file
|
@ -0,0 +1 @@
|
||||||
|
lf
|
|
@ -93,6 +93,7 @@ CMDSRCS = nonce2key/crapto1.c\
|
||||||
cmdlfem4x.c \
|
cmdlfem4x.c \
|
||||||
cmdlfhitag.c \
|
cmdlfhitag.c \
|
||||||
cmdlfti.c \
|
cmdlfti.c \
|
||||||
|
cmdlfviking.c\
|
||||||
cmdparser.c \
|
cmdparser.c \
|
||||||
cmdmain.c \
|
cmdmain.c \
|
||||||
cmdlft55xx.c \
|
cmdlft55xx.c \
|
||||||
|
|
|
@ -1870,6 +1870,53 @@ int CmdRawDemod(const char *Cmd)
|
||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int AmVikingDecode(const uint8_t *id){
|
||||||
|
// searching the buffer for the id
|
||||||
|
uint8_t id_bits[32];
|
||||||
|
// convert 4 bytes of id to 32 bits present in 32 bytes data;
|
||||||
|
bytes_to_bits(id,4,id_bits,sizeof(id_bits));
|
||||||
|
printf("binary : ");
|
||||||
|
print_arraybinary(id_bits,sizeof(id_bits));
|
||||||
|
printf("\n");
|
||||||
|
size_t idx = 0;
|
||||||
|
size_t BitLen = DemodBufferLen;
|
||||||
|
uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0};
|
||||||
|
memcpy(BitStream, DemodBuffer, BitLen);
|
||||||
|
|
||||||
|
if (VikingDecode(BitStream,BitLen,&idx,id_bits,sizeof(id_bits)) == 1)
|
||||||
|
{
|
||||||
|
setDemodBuf(BitStream,64, idx);
|
||||||
|
printf("Found Viking tag\n");
|
||||||
|
CmdPrintDemodBuff("x");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Not found Viking tag\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int AMVikingDemod(const uint8_t *id){
|
||||||
|
// demod am clock 32 fail
|
||||||
|
if (!ASKDemod("32",g_debugMode,false,1))
|
||||||
|
return 0;
|
||||||
|
// search for the card id from bitstream.
|
||||||
|
return AmVikingDecode(id);
|
||||||
|
}
|
||||||
|
//by Gusto
|
||||||
|
// takes 1 argument <8 bytes of Hex number on the card
|
||||||
|
// print binary found and saves in grapbuffer for further commands
|
||||||
|
int CmdAMVikingDemod(const char *Cmd){
|
||||||
|
uint8_t id[4];
|
||||||
|
if (param_gethex(Cmd,0,id,8) == 1)
|
||||||
|
{
|
||||||
|
PrintAndLog("Usage: data vikingdemod CardID 8 bytes of hex number");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
printf("Card ID : %02X%02X%02X%02X\n",id[0],id[1],id[2],id[3]);
|
||||||
|
// try to demod AMViking
|
||||||
|
return AMVikingDemod(id);
|
||||||
|
}
|
||||||
|
|
||||||
int CmdGrid(const char *Cmd)
|
int CmdGrid(const char *Cmd)
|
||||||
{
|
{
|
||||||
sscanf(Cmd, "%i %i", &PlotGridX, &PlotGridY);
|
sscanf(Cmd, "%i %i", &PlotGridX, &PlotGridY);
|
||||||
|
@ -2279,6 +2326,7 @@ static command_t CommandTable[] =
|
||||||
{"detectclock", CmdDetectClockRate, 1, "[modulation] Detect clock rate of wave in GraphBuffer (options: 'a','f','n','p' for ask, fsk, nrz, psk respectively)"},
|
{"detectclock", CmdDetectClockRate, 1, "[modulation] Detect clock rate of wave in GraphBuffer (options: 'a','f','n','p' for ask, fsk, nrz, psk respectively)"},
|
||||||
{"fdxbdemod", CmdFDXBdemodBI , 1, "Demodulate a FDX-B ISO11784/85 Biphase tag from GraphBuffer"},
|
{"fdxbdemod", CmdFDXBdemodBI , 1, "Demodulate a FDX-B ISO11784/85 Biphase tag from GraphBuffer"},
|
||||||
{"fskawiddemod", CmdFSKdemodAWID, 1, "Demodulate an AWID FSK tag from GraphBuffer"},
|
{"fskawiddemod", CmdFSKdemodAWID, 1, "Demodulate an AWID FSK tag from GraphBuffer"},
|
||||||
|
{"vikingdemod", CmdAMVikingDemod, 1, "Demodulate a Viking AM tag from GraphBuffer"},
|
||||||
//{"fskfcdetect", CmdFSKfcDetect, 1, "Try to detect the Field Clock of an FSK wave"},
|
//{"fskfcdetect", CmdFSKfcDetect, 1, "Try to detect the Field Clock of an FSK wave"},
|
||||||
{"fskhiddemod", CmdFSKdemodHID, 1, "Demodulate a HID FSK tag from GraphBuffer"},
|
{"fskhiddemod", CmdFSKdemodHID, 1, "Demodulate a HID FSK tag from GraphBuffer"},
|
||||||
{"fskiodemod", CmdFSKdemodIO, 1, "Demodulate an IO Prox FSK tag from GraphBuffer"},
|
{"fskiodemod", CmdFSKdemodIO, 1, "Demodulate an IO Prox FSK tag from GraphBuffer"},
|
||||||
|
|
|
@ -67,7 +67,8 @@ int PSKDemod(const char *Cmd, bool verbose);
|
||||||
int NRZrawDemod(const char *Cmd, bool verbose);
|
int NRZrawDemod(const char *Cmd, bool verbose);
|
||||||
void printEM410x(uint32_t hi, uint64_t id);
|
void printEM410x(uint32_t hi, uint64_t id);
|
||||||
int getSamples(const char *Cmd, bool silent);
|
int getSamples(const char *Cmd, bool silent);
|
||||||
|
int AMVikingDemod(const uint8_t *cardid);
|
||||||
|
int CmdAMVikingDemod(const char *cmd);
|
||||||
|
|
||||||
#define MAX_DEMOD_BUF_LEN (1024*128)
|
#define MAX_DEMOD_BUF_LEN (1024*128)
|
||||||
extern uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN];
|
extern uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN];
|
||||||
|
|
703
client/cmdhficlass.c
Normal file → Executable file
703
client/cmdhficlass.c
Normal file → Executable file
|
@ -31,9 +31,14 @@
|
||||||
#include "loclass/fileutils.h"
|
#include "loclass/fileutils.h"
|
||||||
#include "protocols.h"
|
#include "protocols.h"
|
||||||
#include "usb_cmd.h"
|
#include "usb_cmd.h"
|
||||||
|
typedef struct iclass_block {
|
||||||
|
uint8_t d[8];
|
||||||
|
} iclass_block_t;
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
static uint8_t GLOBAL_KEY[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||||
|
static uint8_t HS_KEY[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||||
|
static uint8_t BLANK_KEY[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||||
|
static bool HS_KEY_LOAD = false;
|
||||||
int xorbits_8(uint8_t val)
|
int xorbits_8(uint8_t val)
|
||||||
{
|
{
|
||||||
uint8_t res = val ^ (val >> 1); //1st pass
|
uint8_t res = val ^ (val >> 1); //1st pass
|
||||||
|
@ -42,7 +47,117 @@ int xorbits_8(uint8_t val)
|
||||||
res = res ^ (res >> 4); // 4th pass
|
res = res ^ (res >> 4); // 4th pass
|
||||||
return res & 1;
|
return res & 1;
|
||||||
}
|
}
|
||||||
|
void CmdHFiClass_printkey(const char* keyname,const uint8_t *key){
|
||||||
|
printf("%s : %02X%02X%02X%02X%02X%02X%02X%02X\n",keyname,key[0],key[1],key[2],key[3],key[4],key[5],key[6],key[7]);
|
||||||
|
}
|
||||||
|
int readKeyfile(const char *filename, size_t len, uint8_t* buffer)
|
||||||
|
{
|
||||||
|
FILE *f = fopen(filename, "rb");
|
||||||
|
if(!f) {
|
||||||
|
PrintAndLog("Failed to read from file '%s'", filename);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
long fsize = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
size_t bytes_read = fread(buffer, 1, len, f);
|
||||||
|
fclose(f);
|
||||||
|
if(fsize != len)
|
||||||
|
{
|
||||||
|
PrintAndLog("Warning, file size is %d, expected %d", fsize, len);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(bytes_read != len)
|
||||||
|
{
|
||||||
|
PrintAndLog("Warning, could only read %d bytes, expected %d" ,bytes_read, len);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int usage_iclass_readkeyfile(){
|
||||||
|
printf("usage: hf iclass readkeyfile <filename>\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int CmdHFiClassReadKeyFile(const char *Cmd){
|
||||||
|
uint8_t key[8];
|
||||||
|
if ( (strlen(Cmd) < 1) || (readKeyfile(Cmd,sizeof(key),key) != 0)) {
|
||||||
|
return usage_iclass_readkeyfile();
|
||||||
|
}
|
||||||
|
CmdHFiClass_printkey("Key ",key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int usage_iclass_savekeyfile(){
|
||||||
|
printf("usage: hf iclass writekeyfile <KEY> filename\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int CmdHFiClassSaveKeyFile(const char *Cmd){
|
||||||
|
char filename[50];
|
||||||
|
uint8_t key[8];
|
||||||
|
FILE *file;
|
||||||
|
if (param_gethex(Cmd, 0, key, 16))
|
||||||
|
{
|
||||||
|
PrintAndLog("KEY must include 16 HEX symbols");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (param_getstr(Cmd,1,filename) < 1)
|
||||||
|
return usage_iclass_savekeyfile();
|
||||||
|
|
||||||
|
file = fopen(filename,"wb");
|
||||||
|
|
||||||
|
if (file == NULL) {
|
||||||
|
printf("error opening file %s\n",filename);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (fwrite(&key,sizeof(key),1,file))
|
||||||
|
printf("write key to file was successful\n");
|
||||||
|
else
|
||||||
|
printf("write key to file was fail\n");
|
||||||
|
fclose(file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CmdHFiClass_SendAuthentication(uint8_t *MAC){
|
||||||
|
UsbCommand d = {CMD_ICLASS_AUTHENTICATION, {0}};
|
||||||
|
memcpy(d.d.asBytes,MAC, 4);
|
||||||
|
SendCommand(&d);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
int CmdHFiClass_SendACK(uint8_t *CSN,uint8_t *CCNR) {
|
||||||
|
|
||||||
|
UsbCommand resp;
|
||||||
|
UsbCommand c = {CMD_READER_ICLASS, {0}};
|
||||||
|
c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE| FLAG_ICLASS_READER_CC;
|
||||||
|
SendCommand(&c);
|
||||||
|
|
||||||
|
if (!WaitForResponseTimeout(CMD_ACK,&resp,4500))
|
||||||
|
{
|
||||||
|
PrintAndLog("Command execute timeout");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t isOK = resp.arg[0] & 0xff;
|
||||||
|
uint8_t * data = resp.d.asBytes;
|
||||||
|
|
||||||
|
memcpy(CSN,data,8);
|
||||||
|
memcpy(CCNR,data+16,8);
|
||||||
|
|
||||||
|
if(isOK <= 1){
|
||||||
|
PrintAndLog("Failed to obtain CC! Aborting");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLog("CSN: %s",sprint_hex(CSN,8));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int CmdHFiClass_SendReadBlock(uint8_t blockno,uint8_t *rdata){
|
||||||
|
UsbCommand d = {CMD_ICLASS_READBLOCK, {blockno}};
|
||||||
|
memcpy(d.d.asBytes,rdata,sizeof(uint8_t *));
|
||||||
|
SendCommand(&d);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
int CmdHFiClassList(const char *Cmd)
|
int CmdHFiClassList(const char *Cmd)
|
||||||
{
|
{
|
||||||
PrintAndLog("Deprecated command, use 'hf list iclass' instead");
|
PrintAndLog("Deprecated command, use 'hf list iclass' instead");
|
||||||
|
@ -230,7 +345,12 @@ int CmdHFiClassReader_Replay(const char *Cmd)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
int usage_hf_iclass_dump(){
|
||||||
|
PrintAndLog("Usage: hf iclass dump [e]");
|
||||||
|
PrintAndLog(" Key - A 16 byte master key");
|
||||||
|
PrintAndLog(" e - If 'e' is specified, HS_KEY will be used otherwise standard key");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
int CmdHFiClassReader_Dump(const char *Cmd)
|
int CmdHFiClassReader_Dump(const char *Cmd)
|
||||||
{
|
{
|
||||||
uint8_t readerType = 0;
|
uint8_t readerType = 0;
|
||||||
|
@ -244,68 +364,27 @@ int CmdHFiClassReader_Dump(const char *Cmd)
|
||||||
int elite = 0;
|
int elite = 0;
|
||||||
uint8_t *used_key;
|
uint8_t *used_key;
|
||||||
int i;
|
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");
|
|
||||||
|
|
||||||
|
if (param_getchar(Cmd, 0) == 'e')
|
||||||
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");
|
PrintAndLog("Elite switch on");
|
||||||
elite = 1;
|
elite = 1;
|
||||||
|
memcpy(KEY,HS_KEY,sizeof(KEY));
|
||||||
//calc h2
|
//calc h2
|
||||||
hash2(KEY, keytable);
|
hash2(KEY, keytable);
|
||||||
printarr_human_readable("keytable", keytable, 128);
|
//printarr_human_readable("keytable", keytable, 128);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
memcpy(KEY,GLOBAL_KEY,sizeof(KEY));
|
||||||
|
|
||||||
UsbCommand resp;
|
UsbCommand resp;
|
||||||
uint8_t key_sel[8] = {0};
|
uint8_t key_sel[8] = {0};
|
||||||
uint8_t key_sel_p[8] = { 0 };
|
uint8_t key_sel_p[8] = { 0 };
|
||||||
|
// send ACK
|
||||||
UsbCommand c = {CMD_READER_ICLASS, {0}};
|
if (CmdHFiClass_SendACK(CSN,CCNR) != 0)
|
||||||
c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE| FLAG_ICLASS_READER_CC;
|
return 1;
|
||||||
SendCommand(&c);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK,&resp,4500))
|
|
||||||
{
|
|
||||||
PrintAndLog("Command execute timeout");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t isOK = resp.arg[0] & 0xff;
|
|
||||||
uint8_t * data = resp.d.asBytes;
|
|
||||||
|
|
||||||
memcpy(CSN,data,8);
|
|
||||||
memcpy(CCNR,data+16,8);
|
|
||||||
|
|
||||||
PrintAndLog("isOk:%02x", isOK);
|
|
||||||
|
|
||||||
if(isOK > 0)
|
|
||||||
{
|
|
||||||
PrintAndLog("CSN: %s",sprint_hex(CSN,8));
|
|
||||||
}
|
|
||||||
if(isOK <= 1){
|
|
||||||
PrintAndLog("Failed to obtain CC! Aborting");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
//Status 2 or higher
|
//Status 2 or higher
|
||||||
|
|
||||||
if(elite)
|
if(elite)
|
||||||
|
@ -314,11 +393,11 @@ int CmdHFiClassReader_Dump(const char *Cmd)
|
||||||
uint8_t key_index[8] = {0};
|
uint8_t key_index[8] = {0};
|
||||||
|
|
||||||
hash1(CSN, key_index);
|
hash1(CSN, key_index);
|
||||||
printvar("hash1", key_index,8);
|
//printvar("hash1", key_index,8);
|
||||||
for(i = 0; i < 8 ; i++)
|
for(i = 0; i < 8 ; i++)
|
||||||
key_sel[i] = keytable[key_index[i]] & 0xFF;
|
key_sel[i] = keytable[key_index[i]] & 0xFF;
|
||||||
PrintAndLog("Pre-fortified 'permuted' HS key that would be needed by an iclass reader to talk to above CSN:");
|
//PrintAndLog("Pre-fortified 'permuted' HS key that would be needed by an iclass reader to talk to above CSN:");
|
||||||
printvar("k_sel", key_sel,8);
|
//printvar("k_sel", key_sel,8);
|
||||||
//Permute from iclass format to standard format
|
//Permute from iclass format to standard format
|
||||||
permutekey_rev(key_sel,key_sel_p);
|
permutekey_rev(key_sel,key_sel_p);
|
||||||
used_key = key_sel_p;
|
used_key = key_sel_p;
|
||||||
|
@ -326,14 +405,14 @@ int CmdHFiClassReader_Dump(const char *Cmd)
|
||||||
used_key = KEY;
|
used_key = KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLog("Pre-fortified key that would be needed by the OmniKey reader to talk to above CSN:");
|
//PrintAndLog("Pre-fortified key that would be needed by the OmniKey reader to talk to above CSN:");
|
||||||
printvar("Used key",used_key,8);
|
//printvar("Used key",used_key,8);
|
||||||
diversifyKey(CSN,used_key, div_key);
|
diversifyKey(CSN,used_key, div_key);
|
||||||
PrintAndLog("Hash0, a.k.a diversified key, that is computed using Ksel and stored in the card (Block 3):");
|
//PrintAndLog("Hash0, a.k.a diversified key, that is computed using Ksel and stored in the card (Block 3):");
|
||||||
printvar("Div key", div_key, 8);
|
//printvar("Div key", div_key, 8);
|
||||||
printvar("CC_NR:",CCNR,12);
|
//printvar("CC_NR:",CCNR,12);
|
||||||
doMAC(CCNR,div_key, MAC);
|
doMAC(CCNR,div_key, MAC);
|
||||||
printvar("MAC", MAC, 4);
|
//printvar("MAC", MAC, 4);
|
||||||
|
|
||||||
uint8_t iclass_data[32000] = {0};
|
uint8_t iclass_data[32000] = {0};
|
||||||
uint32_t iclass_datalen = 0;
|
uint32_t iclass_datalen = 0;
|
||||||
|
@ -383,8 +462,6 @@ int CmdHFiClassReader_Dump(const char *Cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,31 +554,6 @@ int usage_hf_iclass_decrypt()
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int readKeyfile(const char *filename, size_t len, uint8_t* buffer)
|
|
||||||
{
|
|
||||||
FILE *f = fopen(filename, "rb");
|
|
||||||
if(!f) {
|
|
||||||
PrintAndLog("Failed to read from file '%s'", filename);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
fseek(f, 0, SEEK_END);
|
|
||||||
long fsize = ftell(f);
|
|
||||||
fseek(f, 0, SEEK_SET);
|
|
||||||
size_t bytes_read = fread(buffer, 1, len, f);
|
|
||||||
fclose(f);
|
|
||||||
if(fsize != len)
|
|
||||||
{
|
|
||||||
PrintAndLog("Warning, file size is %d, expected %d", fsize, len);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(bytes_read != len)
|
|
||||||
{
|
|
||||||
PrintAndLog("Warning, could only read %d bytes, expected %d" ,bytes_read, len);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CmdHFiClassDecrypt(const char *Cmd)
|
int CmdHFiClassDecrypt(const char *Cmd)
|
||||||
{
|
{
|
||||||
uint8_t key[16] = { 0 };
|
uint8_t key[16] = { 0 };
|
||||||
|
@ -559,82 +611,50 @@ int CmdHFiClassDecrypt(const char *Cmd)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
void Calc_wb_mac(uint8_t blockno,uint8_t *data,uint8_t *div_key,uint8_t MAC[4]){
|
||||||
|
uint8_t WB[9];
|
||||||
|
WB[0] = blockno;
|
||||||
|
memcpy(WB + 1,data,8);
|
||||||
|
// do mac 9 bytes
|
||||||
|
doMAC_N(WB,sizeof(WB),div_key,MAC);
|
||||||
|
}
|
||||||
int CmdHFiClass_iso14443A_write(const char *Cmd)
|
int CmdHFiClass_iso14443A_write(const char *Cmd)
|
||||||
{
|
{
|
||||||
uint8_t readerType = 0;
|
uint8_t blockno=0;
|
||||||
|
uint8_t bldata[8]={0};
|
||||||
uint8_t MAC[4]={0x00,0x00,0x00,0x00};
|
uint8_t MAC[4]={0x00,0x00,0x00,0x00};
|
||||||
|
|
||||||
uint8_t KEY[8]={0x00,0x00,0x00,0x00,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 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 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 div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||||
|
|
||||||
uint8_t blockNo=0;
|
if (param_gethex(Cmd, 0,&blockno, 2))
|
||||||
uint8_t bldata[8]={0};
|
|
||||||
|
|
||||||
if (strlen(Cmd)<3)
|
|
||||||
{
|
{
|
||||||
PrintAndLog("Usage: hf iclass write <Key> <Block> <Data>");
|
PrintAndLog("Block No must include 2 HEX symbols");
|
||||||
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (param_gethex(Cmd, 1, bldata, 16))
|
||||||
blockNo = param_get8(Cmd, 1);
|
|
||||||
if (blockNo>32)
|
|
||||||
{
|
{
|
||||||
PrintAndLog("Error: Maximum number of blocks is 32 for iClass 2K Cards!");
|
PrintAndLog("Block data must include 16 HEX symbols");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (param_gethex(Cmd, 2, bldata, 8))
|
// tell the reader to send ACK and get CSN + CCNR
|
||||||
{
|
if (CmdHFiClass_SendACK(CSN,CCNR) != 0)
|
||||||
PrintAndLog("Block data must include 8 HEX symbols");
|
|
||||||
return 1;
|
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
memcpy(KEY,GLOBAL_KEY,sizeof(KEY));
|
||||||
diversifyKey(CSN,KEY, div_key);
|
diversifyKey(CSN,KEY, div_key);
|
||||||
|
doMAC(CCNR,div_key, MAC);
|
||||||
|
// send authentication
|
||||||
|
CmdHFiClass_SendAuthentication(MAC);
|
||||||
|
// send write command
|
||||||
|
Calc_wb_mac(blockno,bldata,div_key,MAC);
|
||||||
|
UsbCommand w = {CMD_ICLASS_ISO14443A_WRITE, {blockno}};
|
||||||
|
memcpy(w.d.asBytes, bldata, 8);
|
||||||
|
memcpy(w.d.asBytes + 8,MAC, 4);
|
||||||
|
|
||||||
PrintAndLog("Div Key: %s",sprint_hex(div_key,8));
|
SendCommand(&w);
|
||||||
doMAC(CCNR, 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;
|
return 0;
|
||||||
}
|
}
|
||||||
int CmdHFiClass_loclass(const char *Cmd)
|
int CmdHFiClass_loclass(const char *Cmd)
|
||||||
|
@ -682,23 +702,406 @@ int CmdHFiClass_loclass(const char *Cmd)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
int usage_hf_iclass_readtagfile(){
|
||||||
|
PrintAndLog("Usage: hf iclass readtagfile <filename>");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
void printIclassDumpContents(uint8_t* iclass_dump,uint8_t startblock,uint8_t endblock,size_t filesize){
|
||||||
|
uint8_t blockdata[8];
|
||||||
|
uint8_t mem_config;
|
||||||
|
memcpy(&mem_config, iclass_dump + 13,1);
|
||||||
|
uint8_t maxmemcount;
|
||||||
|
uint8_t filemaxblock = filesize / 8;
|
||||||
|
if (mem_config == 0x80)
|
||||||
|
maxmemcount = 255;
|
||||||
|
else
|
||||||
|
maxmemcount = 32;
|
||||||
|
|
||||||
|
if (startblock == 0)
|
||||||
|
startblock = 6;
|
||||||
|
if ((endblock > maxmemcount) || (endblock == 0))
|
||||||
|
endblock = maxmemcount;
|
||||||
|
if (endblock > filemaxblock)
|
||||||
|
endblock = filemaxblock;
|
||||||
|
int i = startblock;
|
||||||
|
int j;
|
||||||
|
while (i < endblock){
|
||||||
|
printf("block[%02x]: ",i);
|
||||||
|
memcpy(blockdata,iclass_dump + (i * 8),8);
|
||||||
|
for (j = 0;j < 8;j++)
|
||||||
|
printf("%02x",blockdata[j]);
|
||||||
|
printf("\n");
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if ((i < filemaxblock) && (i < maxmemcount)){
|
||||||
|
printf("block[%02x]: ",i);
|
||||||
|
memcpy(blockdata,iclass_dump + (i * 8),8);
|
||||||
|
for (j = 0;j < 8;j++)
|
||||||
|
printf("%02x",blockdata[j]);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int CmdHFiClassReadTagFile(const char *Cmd)
|
||||||
|
{
|
||||||
|
int startblock = 0;
|
||||||
|
int endblock = 0;
|
||||||
|
char tempnum[5];
|
||||||
|
FILE *f;
|
||||||
|
char filename[FILE_PATH_SIZE];
|
||||||
|
if (param_getstr(Cmd, 0, filename) < 1)
|
||||||
|
return usage_hf_iclass_readtagfile();
|
||||||
|
if (param_getstr(Cmd,1,(char *)&tempnum) < 1)
|
||||||
|
startblock = 0;
|
||||||
|
else
|
||||||
|
sscanf(tempnum,"%d",&startblock);
|
||||||
|
|
||||||
|
if (param_getstr(Cmd,2,(char *)&tempnum) < 1)
|
||||||
|
endblock = 0;
|
||||||
|
else
|
||||||
|
sscanf(tempnum,"%d",&endblock);
|
||||||
|
// file handling and reading
|
||||||
|
f = fopen(filename,"rb");
|
||||||
|
if(!f) {
|
||||||
|
PrintAndLog("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, 1, fsize, f);
|
||||||
|
fclose(f);
|
||||||
|
uint8_t *csn = dump;
|
||||||
|
printf("CSN : %02x %02x %02x %02x %02x %02x %02x %02x\n",csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]);
|
||||||
|
// printIclassDumpInfo(dump);
|
||||||
|
printIclassDumpContents(dump,startblock,endblock,bytes_read);
|
||||||
|
free(dump);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int usage_hf_iclass_calckey(){
|
||||||
|
PrintAndLog("error please load ekey");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
uint64_t xorcheck(uint64_t sdiv,uint64_t hdiv){
|
||||||
|
uint64_t new_div = 0x00;
|
||||||
|
new_div ^= sdiv;
|
||||||
|
new_div ^= hdiv;
|
||||||
|
return new_div;
|
||||||
|
}
|
||||||
|
uint64_t hexarray_to_uint64(uint8_t *key){
|
||||||
|
char temp[17];
|
||||||
|
uint64_t uint_key;
|
||||||
|
for (int i = 0;i < 8;i++)
|
||||||
|
sprintf(&temp[(i *2)],"%02X",key[i]);
|
||||||
|
temp[16] = '\0';
|
||||||
|
if (sscanf(temp,"%016llX",&uint_key) < 1)
|
||||||
|
return 0;
|
||||||
|
return uint_key;
|
||||||
|
}
|
||||||
|
int CmdHFiClassCalcEKey(const char *Cmd){
|
||||||
|
|
||||||
|
uint8_t CSN[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||||
|
uint8_t std_div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||||
|
uint8_t elite_div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||||
|
uint8_t keytable[128] = {0};
|
||||||
|
uint8_t key_index[8] = {0};
|
||||||
|
uint64_t new_div_key;
|
||||||
|
uint64_t i_elite_div_key;
|
||||||
|
uint64_t i_std_div_key;
|
||||||
|
int i;
|
||||||
|
if (!HS_KEY_LOAD)
|
||||||
|
return usage_hf_iclass_calckey();
|
||||||
|
|
||||||
|
hash2(HS_KEY, keytable);
|
||||||
|
|
||||||
|
UsbCommand resp;
|
||||||
|
uint8_t key_sel[8] = {0};
|
||||||
|
uint8_t key_sel_p[8] = { 0 };
|
||||||
|
|
||||||
|
UsbCommand c = {CMD_READER_ICLASS, {0}};
|
||||||
|
c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE| FLAG_ICLASS_READER_CC;
|
||||||
|
SendCommand(&c);
|
||||||
|
|
||||||
|
if (!WaitForResponseTimeout(CMD_ACK,&resp,4500))
|
||||||
|
{
|
||||||
|
PrintAndLog("Command execute timeout");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t isOK = resp.arg[0] & 0xff;
|
||||||
|
uint8_t * data = resp.d.asBytes;
|
||||||
|
|
||||||
|
memcpy(CSN,data,8);
|
||||||
|
|
||||||
|
// PrintAndLog("isOk:%02x", isOK);
|
||||||
|
|
||||||
|
if(isOK > 0)
|
||||||
|
{
|
||||||
|
PrintAndLog("CSN: %s",sprint_hex(CSN,8));
|
||||||
|
}
|
||||||
|
if(isOK <= 1){
|
||||||
|
PrintAndLog("Failed to obtain CC! Aborting");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
diversifyKey(CSN, GLOBAL_KEY, std_div_key);
|
||||||
|
|
||||||
|
// printvar("(S)Div key", std_div_key, 8);
|
||||||
|
hash1(CSN, key_index);
|
||||||
|
for(i = 0; i < 8 ; i++)
|
||||||
|
key_sel[i] = keytable[key_index[i]] & 0xFF;
|
||||||
|
|
||||||
|
//Permute from iclass format to standard format
|
||||||
|
permutekey_rev(key_sel,key_sel_p);
|
||||||
|
diversifyKey(CSN,key_sel_p, elite_div_key);
|
||||||
|
// printvar("(E)Div key", elite_div_key, 8);
|
||||||
|
i_elite_div_key = hexarray_to_uint64(elite_div_key);
|
||||||
|
i_std_div_key = hexarray_to_uint64(std_div_key);
|
||||||
|
new_div_key = xorcheck(i_std_div_key,i_elite_div_key);
|
||||||
|
printf("(E)Div key : %016llx\n",new_div_key);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
int usage_hf_iclass_load(){
|
||||||
|
PrintAndLog("Usage: hf iclass load <tagfile.bin> <start block> <end block>");
|
||||||
|
PrintAndLog(" sample: hf iclass write iclass_tagdump-121345.bin 6 19");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// load data from tag file and write to another iclass tag
|
||||||
|
int CmdHFiClass_load(const char *Cmd){
|
||||||
|
|
||||||
|
if (strlen(Cmd) < 3)
|
||||||
|
return usage_hf_iclass_load();
|
||||||
|
int startblock = 0;
|
||||||
|
int endblock = 0;
|
||||||
|
char tempnum[5];
|
||||||
|
uint8_t mem_config;
|
||||||
|
FILE *f;
|
||||||
|
char filename[FILE_PATH_SIZE];
|
||||||
|
if (param_getstr(Cmd, 0, filename) < 1)
|
||||||
|
return usage_hf_iclass_load();
|
||||||
|
|
||||||
|
if (param_getstr(Cmd,1,(char *)&tempnum) < 1)
|
||||||
|
startblock = 6;
|
||||||
|
else
|
||||||
|
sscanf(tempnum,"%d",&startblock);
|
||||||
|
|
||||||
|
if (param_getstr(Cmd,2,(char *)&tempnum) < 1)
|
||||||
|
endblock = 0;
|
||||||
|
else
|
||||||
|
sscanf(tempnum,"%d",&endblock);
|
||||||
|
|
||||||
|
// file handling and reading
|
||||||
|
f = fopen(filename,"rb");
|
||||||
|
if(!f) {
|
||||||
|
PrintAndLog("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, 1, fsize, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
memcpy(&mem_config,dump + 13,1);
|
||||||
|
uint8_t maxmemcount;
|
||||||
|
|
||||||
|
uint8_t filemaxblock = bytes_read / 8;
|
||||||
|
if (mem_config == 0x80)
|
||||||
|
maxmemcount = 255;
|
||||||
|
else
|
||||||
|
maxmemcount = 32;
|
||||||
|
|
||||||
|
if (startblock == 0)
|
||||||
|
startblock = 6;
|
||||||
|
if ((endblock > maxmemcount) || (endblock == 0))
|
||||||
|
endblock = maxmemcount;
|
||||||
|
if (endblock > filemaxblock)
|
||||||
|
endblock = filemaxblock;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int CmdHFIClassReadBlock(const char *Cmd){
|
||||||
|
uint8_t blockno=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};
|
||||||
|
|
||||||
|
if (param_gethex(Cmd, 0,&blockno, 2))
|
||||||
|
{
|
||||||
|
PrintAndLog("Block No must include 2 HEX symbols");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
// tell the reader to send ACK and get CSN + CCNR
|
||||||
|
if (CmdHFiClass_SendACK(CSN,CCNR) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
memcpy(KEY,GLOBAL_KEY,sizeof(KEY));
|
||||||
|
// PrintAndLog("Pre-fortified key that would be needed by the OmniKey reader to talk to above CSN:");
|
||||||
|
// printvar("Used key",KEY,8);
|
||||||
|
diversifyKey(CSN,KEY, div_key);
|
||||||
|
// PrintAndLog("Hash0, a.k.a diversified key, that is computed using Ksel and stored in the card (Block 3):");
|
||||||
|
// printvar("Div key", div_key, 8);
|
||||||
|
// printvar("CC_NR:",CCNR,8);
|
||||||
|
doMAC(CCNR,div_key, MAC);
|
||||||
|
// printvar("MAC", MAC, 4);
|
||||||
|
CmdHFiClass_SendAuthentication(MAC);
|
||||||
|
|
||||||
|
// not yet implement
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int CmdHFiClassCloneTag_Usage(){
|
||||||
|
PrintAndLog("Usage: hf iclass clone <tagfile.bin> <start block> <end block> -e <KEY>");
|
||||||
|
PrintAndLog(" sample: hf iclass clone iclass_tagdump-121345.bin 6 19 -e 1122334455667788");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int CmdHFiClassCloneTag(const char *Cmd){
|
||||||
|
if (strlen(Cmd) < 3)
|
||||||
|
return CmdHFiClassCloneTag_Usage();
|
||||||
|
|
||||||
|
int startblock = 0;
|
||||||
|
int endblock = 0;
|
||||||
|
char tempnum[5];
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
iclass_block_t tag_data[26];
|
||||||
|
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};
|
||||||
|
|
||||||
|
char filename[FILE_PATH_SIZE];
|
||||||
|
// get tagfile parameter
|
||||||
|
if (param_getstr(Cmd, 0, filename) < 1)
|
||||||
|
return usage_hf_iclass_load();
|
||||||
|
// get start block parameter
|
||||||
|
if (param_getstr(Cmd,1,(char *)&tempnum) < 1)
|
||||||
|
startblock = 6;
|
||||||
|
else
|
||||||
|
sscanf(tempnum,"%x",&startblock);
|
||||||
|
// get end block parameter
|
||||||
|
if (param_getstr(Cmd,2,(char *)&tempnum) < 1)
|
||||||
|
endblock = 0;
|
||||||
|
else
|
||||||
|
sscanf(tempnum,"%x",&endblock);
|
||||||
|
|
||||||
|
|
||||||
|
// file handling and reading
|
||||||
|
f = fopen(filename,"rb");
|
||||||
|
if(!f) {
|
||||||
|
PrintAndLog("Failed to read from file '%s'", filename);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now read data from the file from block 6 --- 19
|
||||||
|
// ok we will use this struct [data 8 bytes][MAC 4 bytes] for each block calculate all mac number for each data
|
||||||
|
// then copy to usbcommand->asbytes; the max is 32 - 6 = 24 block 12 bytes each block 288 bytes then we can only accept to clone 21 blocks at the time,
|
||||||
|
// else we have to create a share memory
|
||||||
|
int i;
|
||||||
|
fseek(f,6*8,SEEK_SET);
|
||||||
|
fread(tag_data,sizeof(iclass_block_t),32 - 6,f);
|
||||||
|
for (i = 0;i < 32 - 6; i++){
|
||||||
|
printf("block [%02x] [%02x%02x%02x%02x%02x%02x%02x%02x]\n",i + 6,tag_data[i].d[0],tag_data[i].d[1],tag_data[i].d[2],tag_data[i].d[3],tag_data[i].d[4],tag_data[i].d[5],tag_data[i].d[6],tag_data[i].d[7]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell the reader to send ACK and get CSN + CCNR
|
||||||
|
if (CmdHFiClass_SendACK(CSN,CCNR) != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
memcpy(KEY,GLOBAL_KEY,sizeof(KEY));
|
||||||
|
// PrintAndLog("Pre-fortified key that would be needed by the OmniKey reader to talk to above CSN:");
|
||||||
|
// printvar("Used key",KEY,8);
|
||||||
|
diversifyKey(CSN,KEY, div_key);
|
||||||
|
// PrintAndLog("Hash0, a.k.a diversified key, that is computed using Ksel and stored in the card (Block 3):");
|
||||||
|
// printvar("Div key", div_key, 8);
|
||||||
|
// printvar("CC_NR:",CCNR,8);
|
||||||
|
doMAC(CCNR,div_key, MAC);
|
||||||
|
// printvar("MAC", MAC, 4);
|
||||||
|
|
||||||
|
// now authentication with the card
|
||||||
|
CmdHFiClass_SendAuthentication(MAC);
|
||||||
|
|
||||||
|
|
||||||
|
// everythings is ready now
|
||||||
|
UsbCommand w = {CMD_ICLASS_CLONE,{startblock,endblock}};
|
||||||
|
uint8_t *ptr;
|
||||||
|
// calculate all mac for every the block we will write
|
||||||
|
for (i = startblock;i <= endblock;i++){
|
||||||
|
Calc_wb_mac(i,tag_data[i - 6].d,div_key,MAC);
|
||||||
|
// usb command d start pointer = d + (i - 6) * 12
|
||||||
|
// memcpy(pointer,tag_data[i - 6],8) 8 bytes
|
||||||
|
// memcpy(pointer + 8,mac,sizoof(mac) 4 bytes;
|
||||||
|
// next one
|
||||||
|
ptr = w.d.asBytes + (i - 6) * 12;
|
||||||
|
memcpy(ptr, &(tag_data[i - 6].d[0]), 8);
|
||||||
|
memcpy(ptr + 8,MAC, 4);
|
||||||
|
}
|
||||||
|
uint8_t p[12];
|
||||||
|
for (i = 0; i <= endblock - startblock;i++){
|
||||||
|
memcpy(p,w.d.asBytes + (i * 12),12);
|
||||||
|
printf("block [%02x]",i + 6);
|
||||||
|
printf(" [%02x%02x%02x%02x%02x%02x%02x%02x]",p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7]);
|
||||||
|
printf(" MAC [%02x%02x%02x%02x]\n",p[8],p[9],p[10],p[11]);
|
||||||
|
}
|
||||||
|
SendCommand(&w);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int CmdHFiClassEKey_usage(){
|
||||||
|
PrintAndLog(" Usage: hf iclass ekey [filename] to load the key");
|
||||||
|
PrintAndLog("Sample: hf iclass ekey helloworld.key [load key from file]");
|
||||||
|
PrintAndLog("Sample: hf iclass ekey [show the current ekey]");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int CmdHFiClassEKey(const char *Cmd){
|
||||||
|
if (strlen(Cmd) > 1)
|
||||||
|
{
|
||||||
|
if (readKeyfile(Cmd,sizeof(HS_KEY),HS_KEY) != 0)
|
||||||
|
{
|
||||||
|
HS_KEY_LOAD = false;
|
||||||
|
memcpy(HS_KEY,BLANK_KEY,sizeof(BLANK_KEY));
|
||||||
|
return CmdHFiClassEKey_usage();
|
||||||
|
}
|
||||||
|
HS_KEY_LOAD = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CmdHFiClass_printkey("HS Key",HS_KEY);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
static command_t CommandTable[] =
|
static command_t CommandTable[] =
|
||||||
{
|
{
|
||||||
{"help", CmdHelp, 1, "This help"},
|
{"help", CmdHelp, 1, "This help"},
|
||||||
{"list", CmdHFiClassList, 0, "[Deprecated] List iClass history"},
|
{"list", CmdHFiClassList, 0, "[Deprecated] List iClass history"},
|
||||||
{"snoop", CmdHFiClassSnoop, 0, "Eavesdrop iClass communication"},
|
{"snoop", CmdHFiClassSnoop, 0, "Eavesdrop iClass communication"},
|
||||||
{"sim", CmdHFiClassSim, 0, "Simulate iClass tag"},
|
{"sim", CmdHFiClassSim, 0, "Simulate iClass tag"},
|
||||||
{"reader",CmdHFiClassReader, 0, "Read an iClass tag"},
|
{"reader", CmdHFiClassReader, 0, "Read an iClass tag"},
|
||||||
{"replay",CmdHFiClassReader_Replay, 0, "Read an iClass tag via Reply Attack"},
|
{"replay", CmdHFiClassReader_Replay, 0, "Read an iClass tag via Reply Attack"},
|
||||||
{"dump", CmdHFiClassReader_Dump, 0, "Authenticate and Dump iClass tag"},
|
{"dump", CmdHFiClassReader_Dump, 0, "Authenticate and Dump iClass tag"},
|
||||||
// {"write", CmdHFiClass_iso14443A_write, 0, "Authenticate and Write iClass block"},
|
{"write", CmdHFiClass_iso14443A_write, 0, "Authenticate and Write iClass block"},
|
||||||
|
{"read", CmdHFIClassReadBlock, 0, "Authenticate and Read iClass block"},
|
||||||
|
{"load", CmdHFiClass_load, 0, "Load from tagfile to iclass card"},
|
||||||
{"loclass", CmdHFiClass_loclass, 1, "Use loclass to perform bruteforce of reader attack dump"},
|
{"loclass", CmdHFiClass_loclass, 1, "Use loclass to perform bruteforce of reader attack dump"},
|
||||||
{"eload", CmdHFiClassELoad, 0, "[experimental] Load data into iclass emulator memory"},
|
{"eload", CmdHFiClassELoad, 0, "[experimental] Load data into iclass emulator memory"},
|
||||||
{"decrypt", CmdHFiClassDecrypt, 1, "Decrypt tagdump" },
|
{"decrypt", CmdHFiClassDecrypt, 1, "Decrypt tagdump" },
|
||||||
|
{"readtagfile", CmdHFiClassReadTagFile, 1, "Display Content from tagfile"},
|
||||||
|
{"ediv", CmdHFiClassCalcEKey, 0, "Give Diversify key for this card to write to block 3"},
|
||||||
|
{"readkey", CmdHFiClassReadKeyFile, 1, "Read and display key from file"},
|
||||||
|
{"savekey", CmdHFiClassSaveKeyFile, 1, "Write key to file"},
|
||||||
|
{"clone", CmdHFiClassCloneTag, 0, "Clone tag"},
|
||||||
|
{"ekey", CmdHFiClassEKey, 1, "Load HS key from file or show current HS Key"},
|
||||||
{NULL, NULL, 0, NULL}
|
{NULL, NULL, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
int CmdHFiClass(const char *Cmd)
|
int CmdHFiClass(const char *Cmd)
|
||||||
{
|
{
|
||||||
CmdsParse(CommandTable, Cmd);
|
CmdsParse(CommandTable, Cmd);
|
||||||
|
|
9
client/cmdhficlass.h
Normal file → Executable file
9
client/cmdhficlass.h
Normal file → Executable file
|
@ -1,3 +1,5 @@
|
||||||
|
// version 2.1.0
|
||||||
|
// add readkeyfile,writekeyfile,modify dump,iso write and calcEkey functions.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
|
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
|
||||||
// Copyright (C) 2011 Gerhard de Koning Gans
|
// Copyright (C) 2011 Gerhard de Koning Gans
|
||||||
|
@ -20,5 +22,10 @@ int CmdHFiClassList(const char *Cmd);
|
||||||
int HFiClassReader(const char *Cmd, bool loop, bool verbose);
|
int HFiClassReader(const char *Cmd, bool loop, bool verbose);
|
||||||
int CmdHFiClassReader(const char *Cmd);
|
int CmdHFiClassReader(const char *Cmd);
|
||||||
int CmdHFiClassReader_Replay(const char *Cmd);
|
int CmdHFiClassReader_Replay(const char *Cmd);
|
||||||
|
int CmdHFiClassReadKeyFile(const char *filename);
|
||||||
|
int CmdHFiClassWriteKeyFile(const char *Cmd);
|
||||||
|
int CmdHFiClass_iso14443A_write(const char *Cmd);
|
||||||
|
int CmdHFiClassCalcEKey(const char *Cmd);
|
||||||
|
int CmdHFiClassRestore(const char *cmd);
|
||||||
|
int CmdHFiClass_TestMac(const char *Cmd);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
#include "cmdlfpcf7931.h"
|
#include "cmdlfpcf7931.h"
|
||||||
#include "cmdlfio.h"
|
#include "cmdlfio.h"
|
||||||
#include "lfdemod.h"
|
#include "lfdemod.h"
|
||||||
|
#include "cmdlfviking.h"
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
/* send a command before reading */
|
/* send a command before reading */
|
||||||
|
@ -1148,6 +1148,7 @@ static command_t CommandTable[] =
|
||||||
{"vchdemod", CmdVchDemod, 1, "['clone'] -- Demodulate samples for VeriChip"},
|
{"vchdemod", CmdVchDemod, 1, "['clone'] -- Demodulate samples for VeriChip"},
|
||||||
{"t55xx", CmdLFT55XX, 1, "{ T55xx RFIDs... }"},
|
{"t55xx", CmdLFT55XX, 1, "{ T55xx RFIDs... }"},
|
||||||
{"pcf7931", CmdLFPCF7931, 1, "{PCF7931 RFIDs...}"},
|
{"pcf7931", CmdLFPCF7931, 1, "{PCF7931 RFIDs...}"},
|
||||||
|
{"viking", CmdLFViking, 1, "{Viking RFIDs..}"},
|
||||||
{NULL, NULL, 0, NULL}
|
{NULL, NULL, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
64
client/cmdlfviking.c
Executable file
64
client/cmdlfviking.c
Executable file
|
@ -0,0 +1,64 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "proxmark3.h"
|
||||||
|
#include "ui.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "graph.h"
|
||||||
|
#include "cmdparser.h"
|
||||||
|
#include "cmddata.h"
|
||||||
|
#include "cmdlf.h"
|
||||||
|
#include "cmdlfviking.h"
|
||||||
|
#include "lfdemod.h"
|
||||||
|
static int CmdHelp(const char *Cmd);
|
||||||
|
int CmdVikingDemod(const char *Cmd)
|
||||||
|
{
|
||||||
|
uint8_t id[4];
|
||||||
|
if (param_gethex(Cmd,0,id,8) == 1)
|
||||||
|
{
|
||||||
|
PrintAndLog("Usage: lf viking demod <CardID 8 bytes of hex number>");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_125K, {false,0,0}};
|
||||||
|
SendCommand(&c);
|
||||||
|
WaitForResponse(CMD_ACK,NULL);
|
||||||
|
getSamples("40000",true);
|
||||||
|
// try to demod AMViking
|
||||||
|
return AMVikingDemod(id);
|
||||||
|
}
|
||||||
|
int CmdVikingClone(const char *Cmd)
|
||||||
|
{
|
||||||
|
uint32_t b1,b2;
|
||||||
|
// get the tag number 64 bits (8 bytes) in hex
|
||||||
|
uint8_t id[8];
|
||||||
|
if (param_gethex(Cmd,0,id,16) == 1)
|
||||||
|
{
|
||||||
|
PrintAndLog("Usage: lf viking clone <Card ID 16 bytes of hex number>");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
b1 = bytes_to_num(id,sizeof(uint32_t));
|
||||||
|
b2 = bytes_to_num(id + sizeof(uint32_t),sizeof(uint32_t));
|
||||||
|
UsbCommand c = {CMD_VIKING_CLONE_TAG,{b1,b2}};
|
||||||
|
SendCommand(&c);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static command_t CommandTable[] =
|
||||||
|
{
|
||||||
|
{"help", CmdHelp, 1, "This help"},
|
||||||
|
{"demod",CmdVikingDemod ,1, "<8 digits tag id> -- Extract tag data"},
|
||||||
|
{"clone", CmdVikingClone, 1, "<16 digits card data> clone viking tag"},
|
||||||
|
{NULL, NULL, 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
int CmdLFViking(const char *Cmd)
|
||||||
|
{
|
||||||
|
CmdsParse(CommandTable, Cmd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CmdHelp(const char *Cmd)
|
||||||
|
{
|
||||||
|
CmdsHelp(CommandTable);
|
||||||
|
return 0;
|
||||||
|
}
|
7
client/cmdlfviking.h
Executable file
7
client/cmdlfviking.h
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef CMDLFVIKING_H__
|
||||||
|
#define CMDLFVIKING_H__
|
||||||
|
int CmdLFViking(const char *Cmd);
|
||||||
|
int CmdVikingDemod(const char *Cmd);
|
||||||
|
int CmdVikingClone(const char *Cmd);
|
||||||
|
#endif
|
||||||
|
|
|
@ -241,6 +241,27 @@ void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4])
|
||||||
//free(cc_nr);
|
//free(cc_nr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
void doMAC_N(uint8_t *cc_nr_p,uint8_t cc_nr_size, uint8_t *div_key_p, uint8_t mac[4])
|
||||||
|
{
|
||||||
|
uint8_t *cc_nr;
|
||||||
|
uint8_t div_key[8];
|
||||||
|
cc_nr = (uint8_t*) malloc(cc_nr_size);
|
||||||
|
|
||||||
|
memcpy(cc_nr,cc_nr_p,cc_nr_size);
|
||||||
|
memcpy(div_key,div_key_p,8);
|
||||||
|
|
||||||
|
reverse_arraybytes(cc_nr,cc_nr_size);
|
||||||
|
BitstreamIn bitstream = {cc_nr,cc_nr_size * 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);
|
||||||
|
free(cc_nr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef ON_DEVICE
|
#ifndef ON_DEVICE
|
||||||
int testMAC()
|
int testMAC()
|
||||||
{
|
{
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]);
|
void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]);
|
||||||
|
void doMAC_N(uint8_t *cc_nr_p,uint8_t cc_nr_size, uint8_t *div_key_p, uint8_t mac[4]);
|
||||||
|
|
||||||
#ifndef ON_DEVICE
|
#ifndef ON_DEVICE
|
||||||
int testMAC();
|
int testMAC();
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -453,3 +453,32 @@ void xor(unsigned char *dst, unsigned char *src, size_t len) {
|
||||||
int32_t le24toh (uint8_t data[3]) {
|
int32_t le24toh (uint8_t data[3]) {
|
||||||
return (data[2] << 16) | (data[1] << 8) | data[0];
|
return (data[2] << 16) | (data[1] << 8) | data[0];
|
||||||
}
|
}
|
||||||
|
size_t bytes_to_bits(const uint8_t *src,size_t src_size,uint8_t *des,size_t des_size){
|
||||||
|
int i,j,k;
|
||||||
|
int count = 0;
|
||||||
|
// check src_size and des_size
|
||||||
|
if ((src_size * 8) > des_size)
|
||||||
|
return -1;
|
||||||
|
// convert 1 bytes to 8 bits at the time
|
||||||
|
for (j = 0;j < src_size;j++){
|
||||||
|
for (i = 0;i < 8;i++){
|
||||||
|
k = src[j] >> i;
|
||||||
|
if (k & 1)
|
||||||
|
*(des + (j * 8) + (7 - i)) = 1;
|
||||||
|
else
|
||||||
|
*(des + (j * 8) + (7 - i)) = 0;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
void print_arraybinary(const uint8_t *b,size_t c){
|
||||||
|
int i;
|
||||||
|
for (i = 0;i < c;i++){
|
||||||
|
if (*(b + i) == 0)
|
||||||
|
printf("0");
|
||||||
|
else
|
||||||
|
printf("1");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
|
@ -65,3 +65,4 @@ void wiegand_add_parity(char *target, char *source, char length);
|
||||||
|
|
||||||
void xor(unsigned char *dst, unsigned char *src, size_t len);
|
void xor(unsigned char *dst, unsigned char *src, size_t len);
|
||||||
int32_t le24toh(uint8_t data[3]);
|
int32_t le24toh(uint8_t data[3]);
|
||||||
|
size_t bytes_to_bits(const uint8_t *src,size_t src_size,uint8_t *des,size_t des_size);
|
|
@ -1482,3 +1482,26 @@ int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert)
|
||||||
*size = numBits;
|
*size = numBits;
|
||||||
return errCnt;
|
return errCnt;
|
||||||
}
|
}
|
||||||
|
// on successful return 1 otherwise return 0
|
||||||
|
int VikingDecode(uint8_t *BitStream, size_t size, size_t *startIdx,uint8_t *id_bits,size_t id_bits_size)
|
||||||
|
{
|
||||||
|
//no arguments needed - built this way in case we want this to be a direct call from "data " cmds in the future
|
||||||
|
// otherwise could be a void with no arguments
|
||||||
|
//set defaults
|
||||||
|
uint32_t i = 0;
|
||||||
|
uint32_t lastcheckindex = size - (id_bits_size * 2);
|
||||||
|
int found = 0;
|
||||||
|
while (i < lastcheckindex)
|
||||||
|
{
|
||||||
|
if (memcmp(BitStream + i,id_bits,id_bits_size) == 0)
|
||||||
|
{
|
||||||
|
*startIdx = i;
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,5 +49,6 @@ int IOdemodFSK(uint8_t *dest, size_t size);
|
||||||
int indala26decode(uint8_t *bitStream, size_t *size, uint8_t *invert);
|
int indala26decode(uint8_t *bitStream, size_t *size, uint8_t *invert);
|
||||||
int PyramiddemodFSK(uint8_t *dest, size_t *size);
|
int PyramiddemodFSK(uint8_t *dest, size_t *size);
|
||||||
int ParadoxdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, uint32_t *lo);
|
int ParadoxdemodFSK(uint8_t *dest, size_t *size, uint32_t *hi2, uint32_t *hi, uint32_t *lo);
|
||||||
|
int VikingDecode(uint8_t *BitStream, size_t size, size_t *startIdx,uint8_t *id_bit,size_t id_bits_size);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -96,6 +96,8 @@ typedef struct{
|
||||||
#define CMD_ASK_SIM_TAG 0x021F
|
#define CMD_ASK_SIM_TAG 0x021F
|
||||||
#define CMD_PSK_SIM_TAG 0x0220
|
#define CMD_PSK_SIM_TAG 0x0220
|
||||||
#define CMD_AWID_DEMOD_FSK 0x0221
|
#define CMD_AWID_DEMOD_FSK 0x0221
|
||||||
|
#define CMD_VIKING_CLONE_TAG 0x0222
|
||||||
|
|
||||||
|
|
||||||
/* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */
|
/* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */
|
||||||
|
|
||||||
|
@ -135,6 +137,9 @@ typedef struct{
|
||||||
#define CMD_READER_ICLASS_REPLAY 0x0395
|
#define CMD_READER_ICLASS_REPLAY 0x0395
|
||||||
#define CMD_ICLASS_ISO14443A_WRITE 0x0397
|
#define CMD_ICLASS_ISO14443A_WRITE 0x0397
|
||||||
#define CMD_ICLASS_EML_MEMSET 0x0398
|
#define CMD_ICLASS_EML_MEMSET 0x0398
|
||||||
|
#define CMD_ICLASS_AUTHENTICATION 0x0399
|
||||||
|
#define CMD_ICLASS_READBLOCK 0x039A
|
||||||
|
#define CMD_ICLASS_CLONE 0x039B
|
||||||
|
|
||||||
// For measurements of the antenna tuning
|
// For measurements of the antenna tuning
|
||||||
#define CMD_MEASURE_ANTENNA_TUNING 0x0400
|
#define CMD_MEASURE_ANTENNA_TUNING 0x0400
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue