From aa53efc340d9f2dc382e4bb98d49bede5a18e920 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Mon, 20 Jul 2015 13:41:40 -0400 Subject: [PATCH] iclass additions multiple contributors - thanks! --- armsrc/appmain.c | 19 +- armsrc/apps.h | 9 +- armsrc/iclass.c | 279 +++--- client/cmdhf.c | 8 +- client/cmdhficlass.c | 1594 ++++++++++++++++++++++++++++------ client/cmdhficlass.h | 6 + client/cmdlf.c | 2 +- client/hid-flasher/usb_cmd.h | 7 + client/loclass/cipher.c | 21 + client/loclass/cipher.h | 2 + client/lualibs/commands.lua | 9 +- common/protocols.c | 28 +- include/usb_cmd.h | 7 +- 13 files changed, 1578 insertions(+), 413 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 0cbfa249..906379a7 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -860,11 +860,26 @@ void UsbPacketReceived(uint8_t *packet, int len) ReaderIClass(c->arg[0]); break; case CMD_READER_ICLASS_REPLAY: - ReaderIClass_Replay(c->arg[0], c->d.asBytes); + ReaderIClass_Replay(c->arg[0], c->d.asBytes); break; - case CMD_ICLASS_EML_MEMSET: + case CMD_ICLASS_EML_MEMSET: emlSet(c->d.asBytes,c->arg[0], c->arg[1]); break; + case CMD_ICLASS_WRITEBLOCK: + iClass_WriteBlock(c->arg[0], c->arg[1], c->d.asBytes); + break; + case CMD_ICLASS_READBLOCK: + iClass_ReadBlk(c->arg[0], c->arg[1]); + break; + case CMD_ICLASS_AUTHENTICATION: + iClass_Authentication(c->d.asBytes); + break; + case CMD_ICLASS_DUMP: + iClass_Dump(c->arg[0], c->arg[1], c->arg[2]); + break; + case CMD_ICLASS_CLONE: + iClass_Clone(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); + break; #endif case CMD_BUFF_CLEAR: diff --git a/armsrc/apps.h b/armsrc/apps.h index 42efd118..e8b43e9b 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -149,9 +149,6 @@ void OnSuccess(); void OnError(uint8_t reason); - - - /// iso15693.h void RecordRawAdcSamplesIso15693(void); void AcquireRawAdcSamplesIso15693(void); @@ -167,6 +164,12 @@ 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); +void iClass_Authentication(uint8_t *MAC); +void iClass_WriteBlock(uint8_t blockNo, uint8_t keyType, uint8_t *data); +void iClass_ReadBlk(uint8_t blockNo, uint8_t keyType); +bool iClass_ReadBlock(uint8_t blockNo, uint8_t keyType, uint8_t *readdata); +void iClass_Dump(uint8_t blockno, uint8_t numblks, uint8_t keyType); +void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t keyType, uint8_t *data); // hitag2.h void SnoopHitag(uint32_t type); diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 97c62bb6..a27fb970 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1601,16 +1601,16 @@ void setupIclassReader() } -size_t sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, uint8_t expected_size, uint8_t retries) +bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, uint8_t expected_size, uint8_t retries) { while(retries-- > 0) { ReaderTransmitIClass(command, cmdsize); if(expected_size == ReaderReceiveIClass(resp)){ - return 0; + return true; } } - return 1;//Error + return false;//Error } /** @@ -1620,14 +1620,17 @@ size_t sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* * 1 = Got CSN * 2 = Got CSN and CC */ -uint8_t handshakeIclassTag(uint8_t *card_data) +uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) { static uint8_t act_all[] = { 0x0a }; - static uint8_t identify[] = { 0x0c }; + //static uint8_t identify[] = { 0x0c }; + static uint8_t identify[] = { 0x0c, 0x00, 0x73, 0x33 }; static uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - - static uint8_t readcheck_cc[]= { 0x88, 0x02,}; + static uint8_t readcheck_cc[]= { 0x88, 0x02 }; + if (use_credit_key) + readcheck_cc[0] = 0x18; + else + readcheck_cc[0] = 0x88; uint8_t resp[ICLASS_BUFFER_SIZE]; @@ -1668,6 +1671,9 @@ uint8_t handshakeIclassTag(uint8_t *card_data) return read_status; } +uint8_t handshakeIclassTag(uint8_t *card_data){ + return handshakeIclassTag_ext(card_data, false); +} // Reader iClass Anticollission @@ -1687,6 +1693,9 @@ void ReaderIClass(uint8_t arg0) { uint8_t result_status = 0; bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE; bool try_once = arg0 & FLAG_ICLASS_READER_ONE_TRY; + bool use_credit_key = false; + if (arg0 & FLAG_ICLASS_READER_CEDITKEY) + use_credit_key = true; set_tracing(TRUE); setupIclassReader(); @@ -1701,7 +1710,7 @@ void ReaderIClass(uint8_t arg0) { } WDT_HIT(); - read_status = handshakeIclassTag(card_data); + read_status = handshakeIclassTag_ext(card_data, use_credit_key); if(read_status == 0) continue; if(read_status == 1) result_status = FLAG_ICLASS_READER_CSN; @@ -1715,11 +1724,10 @@ void ReaderIClass(uint8_t arg0) { if(arg0 & FLAG_ICLASS_READER_CONF) { if(sendCmdGetResponseWithRetries(readConf, sizeof(readConf),card_data+8, 10, 10)) - { - Dbprintf("Failed to dump config block"); - }else { result_status |= FLAG_ICLASS_READER_CONF; + } else { + Dbprintf("Failed to dump config block"); } } @@ -1727,10 +1735,9 @@ void ReaderIClass(uint8_t arg0) { if(arg0 & FLAG_ICLASS_READER_AA){ if(sendCmdGetResponseWithRetries(readAA, sizeof(readAA),card_data+(8*4), 10, 10)) { -// Dbprintf("Failed to dump AA block"); - }else - { result_status |= FLAG_ICLASS_READER_AA; + } else { + //Dbprintf("Failed to dump AA block"); } } @@ -1814,7 +1821,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { //for now replay captured auth (as cc not updated) memcpy(check+5,MAC,4); - if(sendCmdGetResponseWithRetries(check, sizeof(check),resp, 4, 5)) + if(!sendCmdGetResponseWithRetries(check, sizeof(check),resp, 4, 5)) { Dbprintf("Error: Authentication Fail!"); continue; @@ -1826,7 +1833,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { read[2] = crc >> 8; read[3] = crc & 0xff; - if(sendCmdGetResponseWithRetries(read, sizeof(read),resp, 10, 10)) + if(!sendCmdGetResponseWithRetries(read, sizeof(read),resp, 10, 10)) { Dbprintf("Dump config (block 1) failed"); continue; @@ -1853,7 +1860,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { read[2] = crc >> 8; read[3] = crc & 0xff; - if(!sendCmdGetResponseWithRetries(read, sizeof(read), resp, 10, 10)) + if(sendCmdGetResponseWithRetries(read, sizeof(read), resp, 10, 10)) { Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x", block, resp[0], resp[1], resp[2], @@ -1904,130 +1911,130 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { 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); +void iClass_Authentication(uint8_t *MAC) { + uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t resp[ICLASS_BUFFER_SIZE]; + memcpy(check+5,MAC,4); + bool isOK; + isOK = sendCmdGetResponseWithRetries(check, sizeof(check),resp, 4, 5); + cmd_send(CMD_ACK,isOK,0,0,0,0); + //Dbprintf("isOK %d, Tag response : %02x%02x%02x%02x",isOK,resp[0],resp[1],resp[2],resp[3]); +} +bool iClass_ReadBlock(uint8_t blockNo, uint8_t keyType, uint8_t *readdata) { + uint8_t readcmd[] = {keyType, blockNo}; //0x88, 0x00 + uint8_t resp[8]; + size_t isOK = 1; - // Reset trace buffer - memset(trace, 0x44, RECV_CMD_OFFSET); - traceLen = 0; + readcmd[1] = blockNo; + isOK = sendCmdGetResponseWithRetries(readcmd, sizeof(readcmd),resp, 8, 5); + memcpy(readdata,resp,sizeof(resp)); - // 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); + return isOK; +} - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); +void iClass_ReadBlk(uint8_t blockno, uint8_t keyType) { + uint8_t readblockdata[8]; + bool isOK = false; + isOK = iClass_ReadBlock(blockno, keyType, readblockdata); + //Dbprintf("read block [%02x] [%02x%02x%02x%02x%02x%02x%02x%02x]",blockNo,readblockdata[0],readblockdata[1],readblockdata[2],readblockdata[3],readblockdata[4],readblockdata[5],readblockdata[6],readblockdata[7]); + cmd_send(CMD_ACK,isOK,0,0,readblockdata,8); +} - // 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); +void iClass_Dump(uint8_t blockno, uint8_t numblks, uint8_t keyType) { + uint8_t readblockdata[8]; + bool isOK = false; + uint8_t blkCnt = 0; - LED_A_ON(); + BigBuf_free(); + uint8_t *dataout = BigBuf_malloc(255*8); + memset(dataout,0xFF,255*8); + if (dataout == NULL){ + Dbprintf("out of memory"); + OnError(1); + return; + } - for(int i=0;i<1;i++) { - - if(traceLen > TRACE_SIZE) { - DbpString("Trace full"); - break; + for (;blkCnt < numblks; blkCnt++) { + isOK = iClass_ReadBlock(blockno+blkCnt, keyType, readblockdata); + if (!isOK || (readblockdata[0] == 0xBB || readblockdata[7] == 0x33 || readblockdata[2] == 0xBB)) { //try again + isOK = iClass_ReadBlock(blockno+blkCnt, keyType, readblockdata); + if (!isOK) { + Dbprintf("Block %02X failed to read", blkCnt+blockno); + 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; - } - }// + memcpy(dataout+(blkCnt*8),readblockdata,8); + /*Dbprintf("| %02x | %02x%02x%02x%02x%02x%02x%02x%02x |", + blockno+blkCnt, readblockdata[0], readblockdata[1], readblockdata[2], + readblockdata[3], readblockdata[4], readblockdata[5], + readblockdata[6], readblockdata[7]); + */ + } + //return pointer to dump memory in arg3 + cmd_send(CMD_ACK,isOK,blkCnt,BigBuf_max_traceLen(),0,0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + BigBuf_free(); +} + +bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t keyType, uint8_t *data) { + uint8_t write[] = { 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t readblockdata[8]; + write[1] = blockNo; + memcpy(write+2, data, 12); // data + mac + uint8_t resp[10]; + bool isOK; + isOK = sendCmdGetResponseWithRetries(write,sizeof(write),resp,sizeof(resp),5); + //Dbprintf("reply [%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x]",resp[0],resp[1],resp[2],resp[3],resp[4],resp[5],resp[6],resp[7],resp[8],resp[9]); + if (isOK) { + isOK = iClass_ReadBlock(blockNo, keyType, readblockdata); + //try again + if (!isOK || (readblockdata[0] == 0xBB || readblockdata[7] == 0xBB || readblockdata[2] == 0xBB)) + isOK = iClass_ReadBlock(blockNo, keyType, readblockdata); + } + if (isOK) { + //Dbprintf("read block [%02x] [%02x%02x%02x%02x%02x%02x%02x%02x]",blockNo,readblockdata[0],readblockdata[1],readblockdata[2],readblockdata[3],readblockdata[4],readblockdata[5],readblockdata[6],readblockdata[7]); + if (memcmp(write+2,readblockdata,sizeof(readblockdata)) != 0){ + isOK=false; } - WDT_HIT(); } - - LED_A_OFF(); -}*/ + return isOK; +} + +void iClass_WriteBlock(uint8_t blockNo, uint8_t keyType, uint8_t *data) { + bool isOK = iClass_WriteBlock_ext(blockNo, keyType, data); + if (isOK){ + Dbprintf("Write block [%02x] successful",blockNo); + } else { + Dbprintf("Write block [%02x] failed",blockNo); + } + cmd_send(CMD_ACK,isOK,0,0,0,0); +} + +void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t keyType, uint8_t *data) { + int i; + int written = 0; + int total_block = (endblock - startblock) + 1; + for (i = 0; i < total_block;i++){ + // block number + if (iClass_WriteBlock_ext(i+startblock, keyType, data+(i*12))){ + Dbprintf("Write block [%02x] successful",i + startblock); + written++; + } else { + if (iClass_WriteBlock_ext(i+startblock, keyType, data+(i*12))){ + Dbprintf("Write block [%02x] successful",i + startblock); + written++; + } else { + Dbprintf("Write block [%02x] failed",i + startblock); + } + } + } + if (written == total_block) + Dbprintf("Clone complete"); + else + Dbprintf("Clone incomplete"); + + cmd_send(CMD_ACK,1,0,0,0,0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} diff --git a/client/cmdhf.c b/client/cmdhf.c index f8daff7e..8406fe76 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -557,14 +557,14 @@ int CmdHFSearch(const char *Cmd){ PrintAndLog("\nValid ISO14443A Tag Found - Quiting Search\n"); return ans; } - ans = HF14BInfo(false); + ans = HFiClassReader("", false, false); if (ans) { - PrintAndLog("\nValid ISO14443B Tag Found - Quiting Search\n"); + PrintAndLog("\nValid iClass Tag (or PicoPass Tag) Found - Quiting Search\n"); return ans; } - ans = HFiClassReader("", false, false); + ans = HF14BInfo(false); if (ans) { - PrintAndLog("\nValid iClass Tag (or PicoPass Tag) Found - Quiting Search\n"); + PrintAndLog("\nValid ISO14443B Tag Found - Quiting Search\n"); return ans; } ans = HF15Reader("", false); diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 824aaa36..db3de205 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -31,9 +31,28 @@ #include "loclass/fileutils.h" #include "protocols.h" #include "usb_cmd.h" +#include "cmdhfmfu.h" + +#define llX PRIx64 static int CmdHelp(const char *Cmd); +#define ICLASS_KEYS_MAX 8 +static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][8] = { + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } +}; + +typedef struct iclass_block { + uint8_t d[8]; +} iclass_block_t; + int xorbits_8(uint8_t val) { uint8_t res = val ^ (val >> 1); //1st pass @@ -170,10 +189,11 @@ int HFiClassReader(const char *Cmd, bool loop, bool verbose) bool tagFound = false; UsbCommand c = {CMD_READER_ICLASS, {FLAG_ICLASS_READER_CSN| FLAG_ICLASS_READER_CONF|FLAG_ICLASS_READER_AA}}; - if (!loop) c.arg[0] |= FLAG_ICLASS_READER_ONLY_ONCE | FLAG_ICLASS_READER_ONE_TRY; - SendCommand(&c); + // loop in client not device - else on windows have a communication error + c.arg[0] |= FLAG_ICLASS_READER_ONLY_ONCE | FLAG_ICLASS_READER_ONE_TRY; UsbCommand resp; while(!ukbhit()){ + SendCommand(&c); if (WaitForResponseTimeout(CMD_ACK,&resp, 4500)) { uint8_t readStatus = resp.arg[0] & 0xff; uint8_t *data = resp.d.asBytes; @@ -200,7 +220,6 @@ int HFiClassReader(const char *Cmd, bool loop, bool verbose) if (!loop) break; } return 0; - } int CmdHFiClassReader(const char *Cmd) @@ -231,163 +250,6 @@ int CmdHFiClassReader_Replay(const char *Cmd) 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 [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 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); - 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 - - if(elite) - { - //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; - 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); - //Permute from iclass format to standard format - permutekey_rev(key_sel,key_sel_p); - used_key = key_sel_p; - }else{ - used_key = KEY; - } - - PrintAndLog("Pre-fortified key that would be needed by the OmniKey reader to talk to above CSN:"); - printvar("Used key",used_key,8); - 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):"); - printvar("Div key", div_key, 8); - printvar("CC_NR:",CCNR,12); - doMAC(CCNR,div_key, MAC); - printvar("MAC", MAC, 4); - - uint8_t iclass_data[32000] = {0}; - uint32_t iclass_datalen = 0; - uint32_t iclass_blocksFailed = 0;//Set to 1 if dump was incomplete - - UsbCommand d = {CMD_READER_ICLASS_REPLAY, {readerType}}; - memcpy(d.d.asBytes, MAC, 4); - clearCommandBuffer(); - SendCommand(&d); - PrintAndLog("Waiting for device to dump data. Press button on device and key on keyboard to abort..."); - while (true) { - printf("."); - if (ukbhit()) { - getchar(); - printf("\naborted via keyboard!\n"); - break; - } - if(WaitForResponseTimeout(CMD_ACK,&resp,4500)) - { - uint32_t dataLength = resp.arg[0]; - iclass_blocksFailed |= resp.arg[1]; - if(dataLength > 0) - { - PrintAndLog("Got %d bytes data (total so far %d)" ,dataLength,iclass_datalen); - memcpy(iclass_data+iclass_datalen, resp.d.asBytes,dataLength); - iclass_datalen += dataLength; - }else - {//Last transfer, datalength 0 means the dump is finished - PrintAndLog("Dumped %d bytes of data from tag. ", iclass_datalen); - if(iclass_blocksFailed) - { - PrintAndLog("OBS! Some blocks failed to be dumped correctly!"); - } - if(iclass_datalen > 0) - { - char filename[100] = {0}; - //create a preferred filename - snprintf(filename, 100,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x", - CSN[0],CSN[1],CSN[2],CSN[3], - CSN[4],CSN[5],CSN[6],CSN[7]); - //Place the div_key in block 3 - memcpy(iclass_data+(3*8), div_key, 8); - saveFile(filename,"bin",iclass_data, iclass_datalen ); - } - //Aaaand we're finished - return 0; - } - } - } - - - return 0; -} - int hf_iclass_eload_usage() { PrintAndLog("Loads iclass tag-dump into emulator memory on device"); @@ -395,7 +257,6 @@ int hf_iclass_eload_usage() PrintAndLog(""); PrintAndLog("Example: hf iclass eload f iclass_tagdump-aa162d30f8ff12f1.bin"); return 0; - } int iclassEmlSetMem(uint8_t *data, int blockNum, int blocksCount) { @@ -462,21 +323,6 @@ int CmdHFiClassELoad(const char *Cmd) return 0; } -int usage_hf_iclass_decrypt() -{ - PrintAndLog("Usage: hf iclass decrypt f o "); - PrintAndLog(""); - PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside"); - PrintAndLog("in the working directory. The file should be 16 bytes binary data"); - PrintAndLog(""); - PrintAndLog("example: hf iclass decrypt f tagdump_12312342343.bin"); - PrintAndLog(""); - PrintAndLog("OBS! This is pretty stupid implementation, it tries to decrypt every block after block 6. "); - PrintAndLog("Correct behaviour would be to decrypt only the application areas where the key is valid,"); - PrintAndLog("which is defined by the configuration block."); - return 1; -} - int readKeyfile(const char *filename, size_t len, uint8_t* buffer) { FILE *f = fopen(filename, "rb"); @@ -502,6 +348,21 @@ int readKeyfile(const char *filename, size_t len, uint8_t* buffer) return 0; } +int usage_hf_iclass_decrypt() +{ + PrintAndLog("Usage: hf iclass decrypt f o "); + PrintAndLog(""); + PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside"); + PrintAndLog("in the working directory. The file should be 16 bytes binary data"); + PrintAndLog(""); + PrintAndLog("example: hf iclass decrypt f tagdump_12312342343.bin"); + PrintAndLog(""); + PrintAndLog("OBS! This is pretty stupid implementation, it tries to decrypt every block after block 6. "); + PrintAndLog("Correct behaviour would be to decrypt only the application areas where the key is valid,"); + PrintAndLog("which is defined by the configuration block."); + return 1; +} + int CmdHFiClassDecrypt(const char *Cmd) { uint8_t key[16] = { 0 }; @@ -560,91 +421,987 @@ int CmdHFiClassDecrypt(const char *Cmd) return 0; } -int CmdHFiClass_iso14443A_write(const char *Cmd) +int usage_hf_iclass_encrypt(){ + PrintAndLog("Usage: hf iclass encrypt "); + PrintAndLog(""); + PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside"); + PrintAndLog("in the working directory. The file should be 16 bytes binary data"); + PrintAndLog(""); + PrintAndLog("example: hf iclass encrypt 0102030405060708"); + PrintAndLog(""); + return 0; +} + +int iClassEncryptBlkData(uint8_t *blkData) { - 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 key[16] = { 0 }; + if(readKeyfile("iclass_decryptionkey.bin", 16, key)) + { + usage_hf_iclass_encrypt(); + return 1; + } + PrintAndLog("Decryption file found... "); - uint8_t blockNo=0; - uint8_t bldata[8]={0}; + uint8_t decryptedData[16]; + uint8_t *decrypted = decryptedData; + des3_context ctx = { DES_DECRYPT ,{ 0 } }; + des3_set2key_enc( &ctx, key); + + des3_crypt_ecb(&ctx, blkData,decrypted); + //printvar("decrypted block", decrypted, 8); + memcpy(blkData,decrypted,8); + + return 1; +} + +int CmdHFiClassEncryptBlk(const char *Cmd) +{ + uint8_t blkData[8] = {0}; + char opt = param_getchar(Cmd, 0); + if (strlen(Cmd)<1 || opt == 'h') + return usage_hf_iclass_encrypt(); - if (strlen(Cmd)<3) + //get the bytes to encrypt + if (param_gethex(Cmd, 0, blkData, 16)) { - PrintAndLog("Usage: hf iclass write "); - PrintAndLog(" sample: hf iclass write 0011223344556677 10 AAAAAAAAAAAAAAAA"); + PrintAndLog("BlockData must include 16 HEX symbols"); return 0; } + if (!iClassEncryptBlkData(blkData)) return 0; - if (param_gethex(Cmd, 0, KEY, 16)) - { - PrintAndLog("KEY must include 16 HEX symbols"); - return 1; - } + printvar("encrypted block", blkData, 8); + 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; - } +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); + doMAC_N(WB,sizeof(WB),div_key,MAC); + //printf("Cal wb mac block [%02x][%02x%02x%02x%02x%02x%02x%02x%02x] : MAC [%02x%02x%02x%02x]",WB[0],WB[1],WB[2],WB[3],WB[4],WB[5],WB[6],WB[7],WB[8],MAC[0],MAC[1],MAC[2],MAC[3]); +} - UsbCommand c = {CMD_ICLASS_ISO14443A_WRITE, {0}}; - SendCommand(&c); +static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool verbose){ UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,4500)) { - uint8_t isOK = resp.arg[0] & 0xff; - uint8_t * data = resp.d.asBytes; + UsbCommand c = {CMD_READER_ICLASS, {0}}; + c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE| FLAG_ICLASS_READER_CC; + if (use_credit_key) + c.arg[0] |= FLAG_ICLASS_READER_CEDITKEY; - 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 { + clearCommandBuffer(); + SendCommand(&c); + if (!WaitForResponseTimeout(CMD_ACK,&resp,4500)) + { PrintAndLog("Command execute timeout"); + return false; } - diversifyKey(CSN,KEY, div_key); - - PrintAndLog("Div Key: %s",sprint_hex(div_key,8)); - 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; + 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"); + memcpy(CSN,data,8); + if (CCNR!=NULL)memcpy(CCNR,data+16,8); + //PrintAndLog("isOk:%02x", isOK); + if(isOK > 0) + { + if (verbose) PrintAndLog("CSN: %s",sprint_hex(CSN,8)); } - return 0; + if(isOK <= 1){ + PrintAndLog("Failed to obtain CC! Aborting"); + return false; + } + return true; } -int CmdHFiClass_loclass(const char *Cmd) -{ - char opt = param_getchar(Cmd, 0); - if (strlen(Cmd)<1 || opt == 'h') { - PrintAndLog("Usage: hf iclass loclass [options]"); - PrintAndLog("Options:"); - PrintAndLog("h Show this help"); +static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool use_credit_key, bool elite, bool verbose) { + 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 keytable[128] = {0}; + uint8_t *used_key; + uint8_t key_sel[8] = {0}; + uint8_t key_sel_p[8] = { 0 }; + + if (!select_only(CSN, CCNR, use_credit_key, verbose)) + return false; + + if(elite) { + hash2(KEY, keytable); + //Get the key index (hash1) + uint8_t key_index[8] = {0}; + hash1(CSN, key_index); + //printvar("hash1", key_index,8); + for(uint8_t i = 0; i < 8 ; i++) + 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:"); + //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 { + used_key = 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, used_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); + UsbCommand resp; + UsbCommand d = {CMD_ICLASS_AUTHENTICATION, {0}}; + memcpy(d.d.asBytes, MAC, 4); + clearCommandBuffer(); + SendCommand(&d); + if (!WaitForResponseTimeout(CMD_ACK,&resp,4500)) + { + PrintAndLog("Auth Command execute timeout"); + return false; + } + uint8_t isOK = resp.arg[0] & 0xff; + if (!isOK) { + PrintAndLog("Authentication error"); + return false; + } + return true; +} + +int usage_hf_iclass_dump(){ + PrintAndLog("Usage: hf iclass dump f k c e\n"); + PrintAndLog("Options:"); + PrintAndLog(" f : specify a filename to save dump to"); + PrintAndLog(" k : *Access Key as 16 hex symbols or 1 hex to select key from memory"); + PrintAndLog(" c : Credit Key as 16 hex symbols or 1 hex to select key from memory"); + 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(" NOTE: * = required"); + PrintAndLog("Samples:"); + PrintAndLog(" hf iclass dump k 001122334455667B"); + PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA c 001122334455667B"); + PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA e"); + return 0; +} + +int CmdHFiClassReader_Dump(const char *Cmd){ + + uint8_t MAC[4] = {0x00,0x00,0x00,0x00}; + uint8_t div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t c_div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t blockno = 0; + uint8_t numblks = 0; + uint8_t maxBlk = 32; + uint8_t KEY[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t CreditKEY[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t keyNbr = 0; + uint8_t dataLen = 0; + uint8_t fileNameLen = 0; + char filename[FILE_PATH_SIZE]={0}; + char tempStr[50] = {0}; + bool have_credit_key = false; + bool elite = false; + bool errors = false; + uint8_t cmdp = 0; + + while(param_getchar(Cmd, cmdp) != 0x00) + { + switch(param_getchar(Cmd, cmdp)) + { + case 'h': + case 'H': + return usage_hf_iclass_dump(); + case 'c': + case 'C': + have_credit_key = true; + dataLen = param_getstr(Cmd, cmdp+1, tempStr); + if (dataLen == 16) { + errors = param_gethex(tempStr, 0, CreditKEY, dataLen); + } else if (dataLen == 1) { + keyNbr = param_get8(Cmd, cmdp+1); + if (keyNbr <= ICLASS_KEYS_MAX) { + memcpy(CreditKEY, iClass_Key_Table[keyNbr], 8); + } else { + PrintAndLog("\nERROR: Credit KeyNbr is invalid\n"); + errors = true; + } + } else { + PrintAndLog("\nERROR: Credit Key is incorrect length\n"); + errors = true; + } + cmdp += 2; + break; + case 'e': + case 'E': + elite = true; + cmdp++; + break; + case 'f': + case 'F': + fileNameLen = param_getstr(Cmd, cmdp+1, filename); + if (fileNameLen < 1) { + PrintAndLog("No filename found after f"); + errors = true; + } + cmdp += 2; + break; + case 'k': + case 'K': + dataLen = param_getstr(Cmd, cmdp+1, tempStr); + if (dataLen == 16) { + errors = param_gethex(tempStr, 0, KEY, dataLen); + } else if (dataLen == 1) { + keyNbr = param_get8(Cmd, cmdp+1); + if (keyNbr <= ICLASS_KEYS_MAX) { + memcpy(KEY, iClass_Key_Table[keyNbr], 8); + } else { + PrintAndLog("\nERROR: Credit KeyNbr is invalid\n"); + errors = true; + } + } else { + PrintAndLog("\nERROR: Credit Key is incorrect length\n"); + errors = true; + } + cmdp += 2; + break; + default: + PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + if(errors) return usage_hf_iclass_dump(); + } + + if (cmdp < 2) return usage_hf_iclass_dump(); + + //get config and first 3 blocks + UsbCommand c = {CMD_READER_ICLASS, {FLAG_ICLASS_READER_CSN | + FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_ONLY_ONCE | FLAG_ICLASS_READER_ONE_TRY}}; + UsbCommand resp; + uint8_t tag_data[255*8]; + clearCommandBuffer(); + SendCommand(&c); + if (WaitForResponseTimeout(CMD_ACK, &resp, 4500)) { + uint8_t readStatus = resp.arg[0] & 0xff; + uint8_t *data = resp.d.asBytes; + + if( readStatus == 0){ + //Aborted + PrintAndLog("No tag found..."); + return 0; + } + if( readStatus & (FLAG_ICLASS_READER_CSN|FLAG_ICLASS_READER_CONF|FLAG_ICLASS_READER_CC)){ + memcpy(tag_data, data, 8*3); + /*for (; blockno < 3; blockno++) { + PrintAndLog(" | %02X | %02X%02X%02X%02X%02X%02X%02X%02X |", blockno, + data[(blockno*8)+0],data[(blockno*8)+1],data[(blockno*8)+2],data[(blockno*8)+3], + data[(blockno*8)+4],data[(blockno*8)+5],data[(blockno*8)+6],data[(blockno*8)+7]); + }*/ + blockno+=2; + numblks = data[8]; + + if (data[13] & 0x80) { + // large memory - not able to dump pages currently + maxBlk = 255; + } else { + maxBlk = 32; + } + //PrintAndLog("maxBlk: %02X",maxBlk); + } + } else { + PrintAndLog("Command execute timeout"); + return 0; + } + + if (!select_and_auth(KEY, MAC, div_key, false, elite, false)){ + //try twice - for some reason it sometimes fails the first time... + if (!select_and_auth(KEY, MAC, div_key, false, elite, false)){ + ul_switch_off_field(); + return 0; + } + } + //print debit div_key + //PrintAndLog(" | 03 | %02X%02X%02X%02X%02X%02X%02X%02X |", + // div_key[0],div_key[1],div_key[2],div_key[3], + // div_key[4],div_key[5],div_key[6],div_key[7]); + + if (have_credit_key){ + //turn off hf field + //PrintAndLog("attempt 1 to auth with credit key"); + ul_switch_off_field(); + memset(c_div_key,0,8); + memset(MAC,0,4); + if (!select_and_auth(CreditKEY, MAC, c_div_key, true, false, false)){ + //try twice - for some reason it sometimes fails the first time... + memset(c_div_key,0,8); + memset(MAC,0,4); + if (!select_and_auth(CreditKEY, MAC, c_div_key, true, false, false)){ + ul_switch_off_field(); + return 0; + } + } + //print credit div_key + //PrintAndLog(" | 04 | %02X%02X%02X%02X%02X%02X%02X%02X |", + // div_key[0],div_key[1],div_key[2],div_key[3], + // div_key[4],div_key[5],div_key[6],div_key[7]); + + //turn off hf field + //PrintAndLog("attempt 2 to auth with debit key"); + ul_switch_off_field(); + memset(div_key,0,8); + memset(MAC,0,4); + if (!select_and_auth(KEY, MAC, div_key, false, elite, false)){ + //try twice - for some reason it sometimes fails the first time... + if (!select_and_auth(KEY, MAC, div_key, false, elite, false)){ + ul_switch_off_field(); + return 0; + } + } + } + //PrintAndLog("have %d blocks",blockno); + + UsbCommand w = {CMD_ICLASS_DUMP, {blockno, numblks-blockno+1, 0x88}}; + clearCommandBuffer(); + SendCommand(&w); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) { + PrintAndLog("Command execute time-out 1"); + return 1; + } + uint32_t blocksRead = resp.arg[1]; + uint8_t isOK = resp.arg[0] & 0xff; + if (!isOK && !blocksRead) { + PrintAndLog("Read Block Failed"); + return 0; + } + uint32_t startindex = resp.arg[2]; + if (blocksRead*8 > sizeof(tag_data)-(blockno*8)) { + PrintAndLog("Data exceeded Buffer size!"); + blocksRead = (sizeof(tag_data)/8) - blockno; + } + //PrintAndLog("blocksread: %d, blockno: %d, startindex: %x",blocksRead,blockno,startindex); + GetFromBigBuf(tag_data+(blockno*8), blocksRead*8, startindex); + WaitForResponse(CMD_ACK,NULL); + uint32_t gotBytes = blocksRead*8 + blockno*8; + + //PrintAndLog("have %d blocks",gotBytes/8); + + if (have_credit_key && maxBlk > blockno+numblks+1) { + //turn off hf field + ul_switch_off_field(); + //PrintAndLog("attempt 2 to auth with credit key"); + memset(c_div_key,0,8); + memset(MAC,0,4); + if (!select_and_auth(CreditKEY, MAC, c_div_key, true, false, false)){ + //try twice - for some reason it sometimes fails the first time... + if (!select_and_auth(CreditKEY, MAC, c_div_key, true, false, false)){ + ul_switch_off_field(); + return 0; + } + } + w.arg[0] = blockno + blocksRead; + w.arg[1] = maxBlk - (blockno + blocksRead); + w.arg[2] = 0x18; + clearCommandBuffer(); + SendCommand(&w); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) { + PrintAndLog("Command execute timeout 2"); + return 0; + } + uint8_t isOK = resp.arg[0] & 0xff; + blocksRead = resp.arg[1]; + if (!isOK && !blocksRead) { + PrintAndLog("Read Block Failed 2"); + return 0; + } + + startindex = resp.arg[2]; + if (blocksRead*8 > sizeof(tag_data)-gotBytes) { + PrintAndLog("Data exceeded Buffer size!"); + blocksRead = (sizeof(tag_data) - gotBytes)/8; + } + GetFromBigBuf(tag_data+gotBytes, blocksRead*8, startindex); + WaitForResponse(CMD_ACK,NULL); + + gotBytes += blocksRead*8; + //PrintAndLog("have %d blocks",gotBytes/8); + } + + memcpy(tag_data+(3*8),div_key,8); + memcpy(tag_data+(4*8),c_div_key,8); + + for (blockno = 0; blockno < gotBytes/8; blockno++){ + PrintAndLog(" | %02X | %02X%02X%02X%02X%02X%02X%02X%02X |", blockno, + tag_data[(blockno*8)+0],tag_data[(blockno*8)+1],tag_data[(blockno*8)+2],tag_data[(blockno*8)+3], + tag_data[(blockno*8)+4],tag_data[(blockno*8)+5],tag_data[(blockno*8)+6],tag_data[(blockno*8)+7]); + } + if (filename[0] == 0){ + snprintf(filename, FILE_PATH_SIZE,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x", + tag_data[0],tag_data[1],tag_data[2],tag_data[3], + tag_data[4],tag_data[5],tag_data[6],tag_data[7]); + } + saveFile(filename,"bin",tag_data, gotBytes ); + PrintAndLog("Saving dump file - %d blocks read", gotBytes/8); + return 1; +} + +/* +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 div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t keytable[128] = {0}; + bool elite = false; + bool use_credit_key = false; + uint8_t *used_key; + int i; + if (strlen(Cmd) < 1) + { + return usage_hf_iclass_dump(); + } + + 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 = true; + + //calc h2 + hash2(KEY, keytable); + printarr_human_readable("keytable", keytable, 128); + + if (param_getchar(Cmd, 2) == 'c') + use_credit_key = true; + } else if (param_getchar(Cmd, 1) == 'c'){ + use_credit_key = true; + } + + 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; + if (use_credit_key) + c.arg[0] |= FLAG_ICLASS_READER_CEDITKEY; + clearCommandBuffer(); + 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 + + if(elite) + { + //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; + 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); + //Permute from iclass format to standard format + permutekey_rev(key_sel,key_sel_p); + used_key = key_sel_p; + }else{ + used_key = KEY; + } + + PrintAndLog("Pre-fortified key that would be needed by the OmniKey reader to talk to above CSN:"); + printvar("Used key",used_key,8); + 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):"); + printvar("Div key", div_key, 8); + printvar("CC_NR:",CCNR,12); + doMAC(CCNR,div_key, MAC); + printvar("MAC", MAC, 4); + + uint8_t iclass_data[32000] = {0}; + uint32_t iclass_datalen = 0; + uint32_t iclass_blocksFailed = 0;//Set to 1 if dump was incomplete + + UsbCommand d = {CMD_READER_ICLASS_REPLAY, {readerType}}; + memcpy(d.d.asBytes, MAC, 4); + clearCommandBuffer(); + SendCommand(&d); + PrintAndLog("Waiting for device to dump data. Press button on device and key on keyboard to abort..."); + while (true) { + printf("."); + if (ukbhit()) { + getchar(); + printf("\naborted via keyboard!\n"); + break; + } + if(WaitForResponseTimeout(CMD_ACK,&resp,4500)) + { + uint32_t dataLength = resp.arg[0]; + iclass_blocksFailed |= resp.arg[1]; + if(dataLength > 0) + { + PrintAndLog("Got %d bytes data (total so far %d)" ,dataLength,iclass_datalen); + memcpy(iclass_data+iclass_datalen, resp.d.asBytes,dataLength); + iclass_datalen += dataLength; + }else + {//Last transfer, datalength 0 means the dump is finished + PrintAndLog("Dumped %d bytes of data from tag. ", iclass_datalen); + if(iclass_blocksFailed) + { + PrintAndLog("OBS! Some blocks failed to be dumped correctly!"); + } + if(iclass_datalen > 0) + { + char filename[100] = {0}; + //create a preferred filename + snprintf(filename, 100,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x", + CSN[0],CSN[1],CSN[2],CSN[3], + CSN[4],CSN[5],CSN[6],CSN[7]); + //Place the div_key in block 3 + memcpy(iclass_data+(3*8), div_key, 8); + saveFile(filename,"bin",iclass_data, iclass_datalen ); + } + //Aaaand we're finished + return 0; + } + } + } + return 0; +} +*/ + +int WriteBlock(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_credit_key, bool elite, bool verbose){ + uint8_t MAC[4]={0x00,0x00,0x00,0x00}; + uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t keyType = (use_credit_key) ? 0x18 : 0x88; + if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, verbose)) + return 0; + + UsbCommand resp; + + Calc_wb_mac(blockno,bldata,div_key,MAC); + UsbCommand w = {CMD_ICLASS_WRITEBLOCK, {blockno, keyType}}; + memcpy(w.d.asBytes, bldata, 8); + memcpy(w.d.asBytes + 8,MAC, 4); + + clearCommandBuffer(); + SendCommand(&w); + if (!WaitForResponseTimeout(CMD_ACK,&resp,4500)) + { + PrintAndLog("Write Command execute timeout"); + return 0; + } + uint8_t isOK = resp.arg[0] & 0xff; + if (!isOK) { + PrintAndLog("Write Block Failed"); + return 0; + } + PrintAndLog("Write Block Successful"); + + return 1; +} + +int usage_hf_iclass_writeblock() { + PrintAndLog("Options:"); + PrintAndLog(" b : The block number as 2 hex symbols"); + PrintAndLog(" d : Set the Data to write as 16 hex symbols"); + PrintAndLog(" k : Access Key as 16 hex symbols or 1 hex to select key from memory"); + PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n"); + PrintAndLog(" e : If 'e' is specified, elite computations applied to key"); + PrintAndLog("Samples:"); + PrintAndLog(" hf iclass writeblk b 0A d AAAAAAAAAAAAAAAA k 001122334455667B"); + PrintAndLog(" hf iclass writeblk b 1B d AAAAAAAAAAAAAAAA k 001122334455667B c"); + PrintAndLog(" hf iclass writeblk b 0A d AAAAAAAAAAAAAAAA n 0"); + return 0; +} + +int CmdHFiClass_WriteBlock(const char *Cmd) { + uint8_t blockno=0; + uint8_t bldata[8]={0}; + uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t keyNbr = 0; + uint8_t dataLen = 0; + char tempStr[50] = {0}; + bool use_credit_key = false; + bool elite = false; + bool errors = false; + uint8_t cmdp = 0; + while(param_getchar(Cmd, cmdp) != 0x00) + { + switch(param_getchar(Cmd, cmdp)) + { + case 'h': + case 'H': + return usage_hf_iclass_writeblock(); + case 'b': + case 'B': + if (param_gethex(Cmd, cmdp+1, &blockno, 2)) { + PrintAndLog("Block No must include 2 HEX symbols\n"); + errors = true; + } + cmdp += 2; + break; + case 'c': + case 'C': + use_credit_key = true; + cmdp++; + break; + case 'd': + case 'D': + if (param_gethex(Cmd, cmdp+1, bldata, 16)) + { + PrintAndLog("KEY must include 16 HEX symbols\n"); + errors = true; + } + cmdp += 2; + break; + case 'e': + case 'E': + elite = true; + cmdp++; + break; + case 'k': + case 'K': + dataLen = param_getstr(Cmd, cmdp+1, tempStr); + if (dataLen == 16) { + errors = param_gethex(tempStr, 0, KEY, dataLen); + } else if (dataLen == 1) { + keyNbr = param_get8(Cmd, cmdp+1); + if (keyNbr <= ICLASS_KEYS_MAX) { + memcpy(KEY, iClass_Key_Table[keyNbr], 8); + } else { + PrintAndLog("\nERROR: Credit KeyNbr is invalid\n"); + errors = true; + } + } else { + PrintAndLog("\nERROR: Credit Key is incorrect length\n"); + errors = true; + } + cmdp += 2; + break; + default: + PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + if(errors) return usage_hf_iclass_writeblock(); + } + + if (cmdp < 6) return usage_hf_iclass_writeblock(); + + return WriteBlock(blockno, bldata, KEY, use_credit_key, elite, true); +} + +int usage_hf_iclass_clone() { + PrintAndLog("Usage: hf iclass clone f b l k e c"); + PrintAndLog("Options:"); + PrintAndLog(" f : specify a filename to clone from"); + PrintAndLog(" b : The first block to clone as 2 hex symbols"); + PrintAndLog(" l : Set the Data to write as 16 hex symbols"); + PrintAndLog(" k : Access Key as 16 hex symbols or 1 hex to select key from memory"); + PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n"); + PrintAndLog(" e : If 'e' is specified, elite computations applied to key"); + PrintAndLog("Samples:"); + PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 1A k 1122334455667788 e"); + PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 05 l 19 k 0"); + PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 19 k 0 e"); + return -1; +} + +int CmdHFiClassCloneTag(const char *Cmd) { + char filename[FILE_PATH_SIZE]; + char tempStr[50]={0}; + uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t keyNbr = 0; + uint8_t fileNameLen = 0; + uint8_t startblock = 0; + uint8_t endblock = 0; + uint8_t dataLen = 0; + bool use_credit_key = false; + bool elite = false; + bool errors = false; + uint8_t cmdp = 0; + while(param_getchar(Cmd, cmdp) != 0x00) + { + switch(param_getchar(Cmd, cmdp)) + { + case 'h': + case 'H': + return usage_hf_iclass_clone(); + case 'b': + case 'B': + if (param_gethex(Cmd, cmdp+1, &startblock, 2)) { + PrintAndLog("Start Block No must include 2 HEX symbols\n"); + errors = true; + } + cmdp += 2; + break; + case 'c': + case 'C': + use_credit_key = true; + cmdp++; + break; + case 'e': + case 'E': + elite = true; + cmdp++; + break; + case 'f': + case 'F': + fileNameLen = param_getstr(Cmd, cmdp+1, filename); + if (fileNameLen < 1) { + PrintAndLog("No filename found after f"); + errors = true; + } + cmdp += 2; + break; + case 'k': + case 'K': + dataLen = param_getstr(Cmd, cmdp+1, tempStr); + if (dataLen == 16) { + errors = param_gethex(tempStr, 0, KEY, dataLen); + } else if (dataLen == 1) { + keyNbr = param_get8(Cmd, cmdp+1); + if (keyNbr <= ICLASS_KEYS_MAX) { + memcpy(KEY, iClass_Key_Table[keyNbr], 8); + } else { + PrintAndLog("\nERROR: Credit KeyNbr is invalid\n"); + errors = true; + } + } else { + PrintAndLog("\nERROR: Credit Key is incorrect length\n"); + errors = true; + } + cmdp += 2; + break; + case 'l': + case 'L': + if (param_gethex(Cmd, cmdp+1, &endblock, 2)) { + PrintAndLog("Start Block No must include 2 HEX symbols\n"); + errors = true; + } + cmdp += 2; + break; + default: + PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + if(errors) return usage_hf_iclass_clone(); + } + + if (cmdp < 8) return usage_hf_iclass_clone(); + + FILE *f; + + iclass_block_t tag_data[USB_CMD_DATA_SIZE/12]; + + if ((endblock-startblock+1)*12 > USB_CMD_DATA_SIZE) { + PrintAndLog("Trying to write too many blocks at once. Max: %d", USB_CMD_DATA_SIZE/8); + } + // file handling and reading + f = fopen(filename,"rb"); + if(!f) { + PrintAndLog("Failed to read from file '%s'", filename); + return 1; + } + + if (startblock<5) { + PrintAndLog("You cannot write key blocks this way. yet... make your start block > 4"); + return 0; + } + // 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,startblock*8,SEEK_SET); + fread(tag_data,sizeof(iclass_block_t),endblock - startblock + 1,f); + /* + for (i = 0; i < endblock - startblock+1; i++){ + printf("block [%02x] [%02x%02x%02x%02x%02x%02x%02x%02x]\n",i + startblock,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]); + }*/ + + uint8_t MAC[4]={0x00,0x00,0x00,0x00}; + uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + + if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, true)) + return 0; + + UsbCommand w = {CMD_ICLASS_CLONE,{startblock,endblock,((use_credit_key) ? 0x18 : 0x88)}}; + 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 - startblock].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 - startblock) * 12; + memcpy(ptr, &(tag_data[i - startblock].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 + startblock); + 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]); + } + UsbCommand resp; + SendCommand(&w); + if (!WaitForResponseTimeout(CMD_ACK,&resp,4500)) + { + PrintAndLog("Command execute timeout"); + return 0; + } + return 1; +} + +int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool verbose){ + uint8_t MAC[4]={0x00,0x00,0x00,0x00}; + uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + + if (!select_and_auth(KEY, MAC, div_key, (keyType==0x18), elite, verbose)) + return 0; + + UsbCommand resp; + UsbCommand w = {CMD_ICLASS_READBLOCK, {blockno, keyType}}; + clearCommandBuffer(); + SendCommand(&w); + if (!WaitForResponseTimeout(CMD_ACK,&resp,4500)) + { + PrintAndLog("Command execute timeout"); + return 0; + } + uint8_t isOK = resp.arg[0] & 0xff; + if (!isOK) { + PrintAndLog("Read Block Failed"); + return 0; + } + //data read is stored in: resp.d.asBytes[0-15] + if (verbose) PrintAndLog("Block %02X: %s\n",blockno, sprint_hex(resp.d.asBytes,8)); + return 1; +} + +int usage_hf_iclass_readblock(){ + PrintAndLog("Usage: hf iclass readblk b k c e\n"); + PrintAndLog("Options:"); + PrintAndLog(" b : The block number as 2 hex symbols"); + PrintAndLog(" k : Access Key as 16 hex symbols or 1 hex to select key from memory"); + PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n"); + PrintAndLog(" e : If 'e' is specified, elite computations applied to key"); + PrintAndLog("Samples:"); + PrintAndLog(" hf iclass readblk b 06 k 0011223344556677"); + PrintAndLog(" hf iclass readblk b 1B k 0011223344556677 c"); + PrintAndLog(" hf iclass readblk b 0A k 0"); + return 0; +} + +int CmdHFiClass_ReadBlock(const char *Cmd) +{ + uint8_t blockno=0; + uint8_t keyType = 0x88; //debit key + uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t keyNbr = 0; + uint8_t dataLen = 0; + char tempStr[50] = {0}; + bool elite = false; + bool errors = false; + uint8_t cmdp = 0; + while(param_getchar(Cmd, cmdp) != 0x00) + { + switch(param_getchar(Cmd, cmdp)) + { + case 'h': + case 'H': + return usage_hf_iclass_readblock(); + case 'b': + case 'B': + if (param_gethex(Cmd, cmdp+1, &blockno, 2)) { + PrintAndLog("Block No must include 2 HEX symbols\n"); + errors = true; + } + cmdp += 2; + break; + case 'c': + case 'C': + keyType = 0x18; + cmdp++; + break; + case 'e': + case 'E': + elite = true; + cmdp++; + break; + case 'k': + case 'K': + dataLen = param_getstr(Cmd, cmdp+1, tempStr); + if (dataLen == 16) { + errors = param_gethex(tempStr, 0, KEY, dataLen); + } else if (dataLen == 1) { + keyNbr = param_get8(Cmd, cmdp+1); + if (keyNbr <= ICLASS_KEYS_MAX) { + memcpy(KEY, iClass_Key_Table[keyNbr], 8); + } else { + PrintAndLog("\nERROR: Credit KeyNbr is invalid\n"); + errors = true; + } + } else { + PrintAndLog("\nERROR: Credit Key is incorrect length\n"); + errors = true; + } + cmdp += 2; + break; + default: + PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + if(errors) return usage_hf_iclass_readblock(); + } + + if (cmdp < 4) return usage_hf_iclass_readblock(); + + return ReadBlock(KEY, blockno, keyType, elite, true); +} + +int CmdHFiClass_loclass(const char *Cmd) +{ + char opt = param_getchar(Cmd, 0); + + if (strlen(Cmd)<1 || opt == 'h') { + PrintAndLog("Usage: hf iclass loclass [options]"); + PrintAndLog("Options:"); + PrintAndLog("h Show this help"); PrintAndLog("t Perform self-test"); PrintAndLog("f Bruteforce iclass dumpfile"); PrintAndLog(" An iclass dumpfile is assumed to consist of an arbitrary number of"); @@ -683,19 +1440,350 @@ int CmdHFiClass_loclass(const char *Cmd) return 0; } +int usage_hf_iclass_readtagfile(){ + PrintAndLog("Usage: hf iclass readtagfile "); + 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; +} + +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,"%016"llX,&uint_key) < 1) + return 0; + return uint_key; +} + +int usage_hf_iclass_calc_ekey(){ + PrintAndLog("Usage: hf iclass calc_ekey [c]"); + return 1; +} + +int CmdHFiClassCalcEKey(const char *Cmd){ + uint8_t STDKEY[8]; + uint8_t ELITEKEY[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 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; + bool use_credit_key = false; + //memcpy(STDKEY,GLOBAL_KEY,sizeof(STDKEY)); + int i; + if (strlen(Cmd) < 2) + return usage_hf_iclass_calc_ekey(); + + if (param_gethex(Cmd, 0, STDKEY, 16)) + return usage_hf_iclass_calc_ekey(); + + if (param_gethex(Cmd, 1, ELITEKEY, 16) != 0) + return usage_hf_iclass_calc_ekey(); + + if (param_getchar(Cmd, 2)=='c') + use_credit_key = true; + + hash2(ELITEKEY, keytable); + + uint8_t key_sel[8] = { 0 }; + uint8_t key_sel_p[8] = { 0 }; + + if (!select_only(CSN, CCNR, use_credit_key, true)) + return 0; + + diversifyKey(CSN, STDKEY, 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("New Div Key : %016"llX"\n",new_div_key); + return 0; +} + +int loadKeys(char *filename){ + FILE *f; + f = fopen(filename,"rb"); + if(!f) { + PrintAndLog("Failed to read from file '%s'", filename); + return 0; + } + 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); + if (bytes_read > ICLASS_KEYS_MAX * 8){ + PrintAndLog("File is too long to load - bytes: %u", bytes_read); + free(dump); + return 0; + } + uint8_t i = 0; + for (; i < bytes_read/8; i++){ + memcpy(iClass_Key_Table[i],dump+(i*8),8); + } + free(dump); + PrintAndLog("%u keys loaded", i); + return 1; +} + +int saveKeys(char *filename){ + FILE *f; + f = fopen(filename,"wb"); + if (f == NULL) { + printf("error opening file %s\n",filename); + return 0; + } + for (uint8_t i = 0; i < ICLASS_KEYS_MAX; i++){ + if (fwrite(iClass_Key_Table[i],8,1,f) != 1){ + PrintAndLog("save key failed to write to file: %s", filename); + break; + } + } + fclose(f); + return 0; +} + +int printKeys(){ + PrintAndLog(""); + for (uint8_t i = 0; i < ICLASS_KEYS_MAX; i++){ + PrintAndLog("%u: %s",i,sprint_hex(iClass_Key_Table[i],8)); + } + PrintAndLog(""); + return 0; +} + +int usage_hf_iclass_managekeys(){ + PrintAndLog("HELP : Manage iClass Keys in client memory:\n"); + PrintAndLog("Usage: hf iclass managekeys n [keynbr] k [key] f [filename] s l p\n"); + PrintAndLog(" Options:"); + PrintAndLog(" n : specify the keyNbr to set in memory"); + PrintAndLog(" k : set a key in memory"); + PrintAndLog(" f : specify a filename to use with load or save operations"); + PrintAndLog(" s : save keys in memory to file specified by filename"); + PrintAndLog(" l : load keys to memory from file specified by filename"); + PrintAndLog(" p : print keys loaded into memory\n"); + PrintAndLog("Samples:"); + PrintAndLog(" set key : hf iclass managekeys n 0 k 1122334455667788"); + PrintAndLog(" save key file: hf iclass managekeys f mykeys.bin s"); + PrintAndLog(" load key file: hf iclass managekeys f mykeys.bin l"); + PrintAndLog(" print keys : hf iclass managekeys p\n"); + return 0; +} + +int CmdManageKeys(const char *Cmd){ + uint8_t keyNbr = 0; + uint8_t dataLen = 0; + uint8_t KEY[8] = {0}; + char filename[FILE_PATH_SIZE]; + uint8_t fileNameLen = 0; + bool errors = false; + uint8_t operation = 0; + char tempStr[20]; + uint8_t cmdp = 0; + + while(param_getchar(Cmd, cmdp) != 0x00) + { + switch(param_getchar(Cmd, cmdp)) + { + case 'h': + case 'H': + return usage_hf_iclass_managekeys(); + case 'f': + case 'F': + fileNameLen = param_getstr(Cmd, cmdp+1, filename); + if (fileNameLen < 1) { + PrintAndLog("No filename found after f"); + errors = true; + } + cmdp += 2; + break; + case 'n': + case 'N': + keyNbr = param_get8(Cmd, cmdp+1); + if (keyNbr < 0) { + PrintAndLog("Wrong block number"); + errors = true; + } + cmdp += 2; + break; + case 'k': + case 'K': + operation += 3; //set key + dataLen = param_getstr(Cmd, cmdp+1, tempStr); + if (dataLen == 16) { //ul-c or ev1/ntag key length + errors = param_gethex(tempStr, 0, KEY, dataLen); + } else { + PrintAndLog("\nERROR: Key is incorrect length\n"); + errors = true; + } + cmdp += 2; + break; + case 'p': + case 'P': + operation += 4; //print keys in memory + cmdp++; + break; + case 'l': + case 'L': + operation += 5; //load keys from file + cmdp++; + break; + case 's': + case 'S': + operation += 6; //save keys to file + cmdp++; + break; + default: + PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + if(errors) return usage_hf_iclass_managekeys(); + } + if (operation == 0){ + PrintAndLog("no operation specified (load, save, or print)\n"); + return usage_hf_iclass_managekeys(); + } + if (operation > 6){ + PrintAndLog("Too many operations specified\n"); + return usage_hf_iclass_managekeys(); + } + if (operation > 4 && fileNameLen == 0){ + PrintAndLog("You must enter a filename when loading or saving\n"); + return usage_hf_iclass_managekeys(); + } + + switch (operation){ + case 3: memcpy(iClass_Key_Table[keyNbr], KEY, 8); return 1; + case 4: return printKeys(); + case 5: return loadKeys(filename); + case 6: return saveKeys(filename); + break; + } + return 0; +} + static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"list", CmdHFiClassList, 0, "[Deprecated] 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"}, - {"loclass", CmdHFiClass_loclass, 1, "Use loclass to perform bruteforce of reader attack dump"}, - {"eload", CmdHFiClassELoad, 0, "[experimental] Load data into iclass emulator memory"}, - {"decrypt", CmdHFiClassDecrypt, 1, "Decrypt tagdump" }, + {"help", CmdHelp, 1, "This help"}, + {"calc_ekey", CmdHFiClassCalcEKey, 0, "Get Elite Diversified key (block 3) to write to convert std to elite"}, + {"clone", CmdHFiClassCloneTag, 0, "Authenticate and Clone from iClass bin file"}, + {"decrypt", CmdHFiClassDecrypt, 1, "Decrypt tagdump" }, + {"dump", CmdHFiClassReader_Dump, 0, "Authenticate and Dump iClass tag's AA1"}, + {"eload", CmdHFiClassELoad, 0, "[experimental] Load data into iClass emulator memory"}, + {"encryptblk", CmdHFiClassEncryptBlk, 1, "[blockData] Encrypt given block data"}, + {"list", CmdHFiClassList, 0, "[Deprecated] List iClass history"}, + //{"load", CmdHFiClass_load, 0, "Load from tagfile to iClass card"}, + {"loclass", CmdHFiClass_loclass, 1, "Use loclass to perform bruteforce of reader attack dump"}, + {"managekeys", CmdManageKeys, 1, "Manage the keys to use with iClass"}, + {"readblk", CmdHFiClass_ReadBlock, 0, "Authenticate and Read iClass block"}, + {"reader", CmdHFiClassReader, 0, "Read an iClass tag"}, + {"readtagfile", CmdHFiClassReadTagFile, 1, "Display Content from tagfile"}, + {"replay", CmdHFiClassReader_Replay, 0, "Read an iClass tag via Reply Attack"}, + {"sim", CmdHFiClassSim, 0, "Simulate iClass tag"}, + {"snoop", CmdHFiClassSnoop, 0, "Eavesdrop iClass communication"}, + {"writeblk", CmdHFiClass_WriteBlock, 0, "Authenticate and Write iClass block"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdhficlass.h b/client/cmdhficlass.h index 30c6a8a7..88e61434 100644 --- a/client/cmdhficlass.h +++ b/client/cmdhficlass.h @@ -20,5 +20,11 @@ int CmdHFiClassList(const char *Cmd); int HFiClassReader(const char *Cmd, bool loop, bool verbose); int CmdHFiClassReader(const char *Cmd); int CmdHFiClassReader_Replay(const char *Cmd); +int CmdHFiClassReadKeyFile(const char *filename); +int CmdHFiClassWriteKeyFile(const char *Cmd); +int CmdHFiClass_ReadBlock(const char *Cmd); +int CmdHFiClass_WriteBlock(const char *Cmd); +int CmdHFiClassCalcEKey(const char *Cmd); +int CmdHFiClass_TestMac(const char *Cmd); #endif diff --git a/client/cmdlf.c b/client/cmdlf.c index 1acee39b..21b19b09 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -1136,7 +1136,7 @@ static command_t CommandTable[] = {"read", CmdLFRead, 0, "['s' silent] Read 125/134 kHz LF ID-only tag. Do 'lf read h' for help"}, {"search", CmdLFfind, 1, "[offline] ['u'] Read and Search for valid known tag (in offline mode it you can load first then search) - 'u' to search for unknown tags"}, {"sim", CmdLFSim, 0, "[GAP] -- Simulate LF tag from buffer with optional GAP (in microseconds)"}, - {"simask", CmdLFaskSim, 0, "[clock] [invert <1|0>] [manchester/raw <'m'|'r'>] [msg separator 's'] [d ] -- Simulate LF ASK tag from demodbuffer or input"}, + {"simask", CmdLFaskSim, 0, "[clock] [invert <1|0>] [biphase/manchester/raw <'b'|'m'|'r'>] [msg separator 's'] [d ] -- Simulate LF ASK tag from demodbuffer or input"}, {"simfsk", CmdLFfskSim, 0, "[c ] [i] [H ] [L ] [d ] -- Simulate LF FSK tag from demodbuffer or input"}, {"simpsk", CmdLFpskSim, 0, "[1|2|3] [c ] [i] [r ] [d ] -- Simulate LF PSK tag from demodbuffer or input"}, {"simbidir", CmdLFSimBidir, 0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"}, diff --git a/client/hid-flasher/usb_cmd.h b/client/hid-flasher/usb_cmd.h index b3a7f4ec..cc415352 100644 --- a/client/hid-flasher/usb_cmd.h +++ b/client/hid-flasher/usb_cmd.h @@ -114,9 +114,16 @@ typedef struct { #define CMD_WRITER_LEGIC_RF 0x0389 #define CMD_EPA_PACE_COLLECT_NONCE 0x038A +#define CMD_ICLASS_CLONE 0x0390 +#define CMD_ICLASS_DUMP 0x0391 #define CMD_SNOOP_ICLASS 0x0392 #define CMD_SIMULATE_TAG_ICLASS 0x0393 #define CMD_READER_ICLASS 0x0394 +#define CMD_READER_ICLASS_REPLAY 0x0395 +#define CMD_ICLASS_READBLOCK 0x0396 +#define CMD_ICLASS_WRITEBLOCK 0x0397 +#define CMD_ICLASS_EML_MEMSET 0x0398 +#define CMD_ICLASS_AUTHENTICATION 0x0399 // For measurements of the antenna tuning #define CMD_MEASURE_ANTENNA_TUNING 0x0400 diff --git a/client/loclass/cipher.c b/client/loclass/cipher.c index 7c9cc873..2aae093d 100644 --- a/client/loclass/cipher.c +++ b/client/loclass/cipher.c @@ -241,6 +241,27 @@ void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]) //free(cc_nr); 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 int testMAC() { diff --git a/client/loclass/cipher.h b/client/loclass/cipher.h index bdea9432..24e86851 100644 --- a/client/loclass/cipher.h +++ b/client/loclass/cipher.h @@ -42,6 +42,8 @@ #include 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 int testMAC(); #endif diff --git a/client/lualibs/commands.lua b/client/lualibs/commands.lua index 4c7bc638..97f0b70a 100644 --- a/client/lualibs/commands.lua +++ b/client/lualibs/commands.lua @@ -86,11 +86,16 @@ local _commands = { CMD_EPA_PACE_COLLECT_NONCE = 0x038A, --//CMD_EPA_ = 0x038B, + CMD_ICLASS_CLONE = 0x0390, + CMD_ICLASS_DUMP = 0x0391, CMD_SNOOP_ICLASS = 0x0392, CMD_SIMULATE_TAG_ICLASS = 0x0393, CMD_READER_ICLASS = 0x0394, - CMD_READER_ICLASS_REPLAY = 0x0395, - CMD_ICLASS_ISO14443A_WRITE = 0x0397, + CMD_READER_ICLASS_REPLAY = 0x0395, + CMD_ICLASS_READBLOCK = 0x0396, + CMD_ICLASS_WRITEBLOCK = 0x0397, + CMD_ICLASS_EML_MEMSET = 0x0398, + CMD_ICLASS_AUTHENTICATION = 0x0399, --// For measurements of the antenna tuning CMD_MEASURE_ANTENNA_TUNING = 0x0400, diff --git a/common/protocols.c b/common/protocols.c index aa80491b..56a6924f 100644 --- a/common/protocols.c +++ b/common/protocols.c @@ -74,24 +74,30 @@ void fuse_config(const picopass_hdr *hdr) if( isset( fuses, FUSE_RA)) prnt(" RA: Read access enabled"); else prnt(" RA: Read access not enabled"); } -void mem_config(const picopass_hdr *hdr) +void mem_app_config(const picopass_hdr *hdr) { uint8_t mem = hdr->conf.mem_config; - if( isset (mem, 0x80)) prnt(" Mem: 16KBits (255 * 8 bytes)"); - else prnt(" Mem: 2 KBits ( 32 * 8 bytes)"); - -} -void applimit_config(const picopass_hdr *hdr) -{ uint8_t applimit = hdr->conf.app_limit; - prnt(" AA1: blocks 6-%d", applimit); - prnt(" AA2: blocks %d-", (applimit+1)); + if (applimit < 6) applimit = 26; + uint8_t kb=2; + uint8_t maxBlk = 32; + if( isset(mem, 0x10) && notset(mem, 0x80)){ + // 2kb default + } else if( isset(mem, 0x80) && notset(mem, 0x10)){ + kb = 16; + maxBlk = 255; //16kb + } else { + kb = 32; + maxBlk = 255; + } + prnt(" Mem: %u KBits ( %u * 8 bytes) [%02X]", kb, maxBlk, mem); + prnt(" AA1: blocks 06-%02X", applimit); + prnt(" AA2: blocks %02X-%02X", (applimit+1), (hdr->conf.mem_config)); } void print_picopass_info(const picopass_hdr *hdr) { fuse_config(hdr); - mem_config(hdr); - applimit_config(hdr); + mem_app_config(hdr); } void printIclassDumpInfo(uint8_t* iclass_dump) { diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 524554e9..2618476a 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -128,12 +128,16 @@ typedef struct{ #define CMD_EPA_PACE_COLLECT_NONCE 0x038A #define CMD_EPA_PACE_REPLAY 0x038B +#define CMD_ICLASS_CLONE 0x0390 +#define CMD_ICLASS_DUMP 0x0391 #define CMD_SNOOP_ICLASS 0x0392 #define CMD_SIMULATE_TAG_ICLASS 0x0393 #define CMD_READER_ICLASS 0x0394 #define CMD_READER_ICLASS_REPLAY 0x0395 -#define CMD_ICLASS_ISO14443A_WRITE 0x0397 +#define CMD_ICLASS_READBLOCK 0x0396 +#define CMD_ICLASS_WRITEBLOCK 0x0397 #define CMD_ICLASS_EML_MEMSET 0x0398 +#define CMD_ICLASS_AUTHENTICATION 0x0399 // For measurements of the antenna tuning #define CMD_MEASURE_ANTENNA_TUNING 0x0400 @@ -204,6 +208,7 @@ typedef struct{ #define FLAG_ICLASS_READER_CONF 0x08 #define FLAG_ICLASS_READER_AA 0x10 #define FLAG_ICLASS_READER_ONE_TRY 0x20 +#define FLAG_ICLASS_READER_CEDITKEY 0x40 -- 2.39.2