From: pwpiwi <pwpiwi@users.noreply.github.com> Date: Sun, 27 Oct 2019 15:51:27 +0000 (+0100) Subject: fix 'hf iclass reader' and 'hf iclass readblk' X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/ece38ef311b28eefb1d716937139aad9ee00985c?ds=sidebyside;hp=--cc fix 'hf iclass reader' and 'hf iclass readblk' * don't do READCHECK when not trying to authenticate * standard LED handling * remove unused FLAG_ICLASS_READER_ONLY_ONCE and FLAG_ICLASS_READER_ONE_TRY * sanity check for negative times in TransmitTo15693Tag() * increase reader timeout for 'hf 15' functions to be enough for slot 7 answers to ACTALL * add 'hf iclass permute' inspired by RRG repository * whitespace fixes --- ece38ef311b28eefb1d716937139aad9ee00985c diff --git a/armsrc/appmain.c b/armsrc/appmain.c index e3bd1fe0..56da5434 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1327,8 +1327,11 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_ICLASS_READBLOCK: iClass_ReadBlk(c->arg[0]); break; - case CMD_ICLASS_AUTHENTICATION: //check - iClass_Authentication(c->d.asBytes); + case CMD_ICLASS_CHECK: + iClass_Check(c->d.asBytes); + break; + case CMD_ICLASS_READCHECK: + iClass_Readcheck(c->arg[0], c->arg[1]); break; case CMD_ICLASS_DUMP: iClass_Dump(c->arg[0], c->arg[1]); diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 392271bd..1a729f3f 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -63,9 +63,9 @@ // 56,64us = 24 ssp_clk_cycles #define DELAY_ICLASS_VCD_TO_VICC_SIM (140 - 24) // times in ssp_clk_cycles @ 3,3625MHz when acting as reader -#define DELAY_ICLASS_VICC_TO_VCD_READER DELAY_ISO15693_VICC_TO_VCD_READER +#define DELAY_ICLASS_VICC_TO_VCD_READER DELAY_ISO15693_VICC_TO_VCD_READER // times in samples @ 212kHz when acting as reader -#define ICLASS_READER_TIMEOUT_ACTALL 330 // 1558us, nominal 330us + 7slots*160us = 1450us +#define ICLASS_READER_TIMEOUT_ACTALL 330 // 1558us, nominal 330us + 7slots*160us = 1450us #define ICLASS_READER_TIMEOUT_OTHERS 80 // 380us, nominal 330us @@ -695,7 +695,6 @@ void RAMFUNC SnoopIClass(void) { if (OutOfNDecoding((smpl & 0xF0) >> 4)) { rsamples = samples - Uart.samples; time_stop = (GetCountSspClk()-time_0) << 4; - LED_C_ON(); //if (!LogTrace(Uart.output, Uart.byteCnt, rsamples, Uart.parityBits,true)) break; //if (!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, true)) break; @@ -708,7 +707,6 @@ void RAMFUNC SnoopIClass(void) { /* And also reset the demod code, which might have been */ /* false-triggered by the commands from the reader. */ Demod.state = DEMOD_UNSYNCD; - LED_B_OFF(); Uart.byteCnt = 0; } else { time_start = (GetCountSspClk()-time_0) << 4; @@ -722,7 +720,6 @@ void RAMFUNC SnoopIClass(void) { time_stop = (GetCountSspClk()-time_0) << 4; rsamples = samples - Demod.samples; - LED_B_ON(); uint8_t parity[MAX_PARITY_SIZE]; GetParity(Demod.output, Demod.len, parity); @@ -732,7 +729,6 @@ void RAMFUNC SnoopIClass(void) { memset(&Demod, 0, sizeof(Demod)); Demod.output = tagToReaderResponse; Demod.state = DEMOD_UNSYNCD; - LED_C_OFF(); } else { time_start = (GetCountSspClk()-time_0) << 4; } @@ -1341,7 +1337,7 @@ static void ReaderTransmitIClass(uint8_t *frame, int len, uint32_t *start_time) } -static bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, size_t max_resp_size, +static bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, size_t max_resp_size, uint8_t expected_size, uint8_t retries, uint32_t start_time, uint32_t *eof_time) { while (retries-- > 0) { ReaderTransmitIClass(command, cmdsize, &start_time); @@ -1353,39 +1349,31 @@ static bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint } /** - * @brief Talks to an iclass tag, sends the commands to get CSN and CC. - * @param card_data where the CSN and CC are stored for return - * @return 0 = fail - * 1 = Got CSN - * 2 = Got CSN and CC + * @brief Selects an iclass tag + * @param card_data where the CSN is stored for return + * @return false = fail + * true = success */ -static uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time) { +static bool selectIclassTag(uint8_t *card_data, uint32_t *eof_time) { 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 }; - if (use_credit_key) - readcheck_cc[0] = 0x18; - else - readcheck_cc[0] = 0x88; uint8_t resp[ICLASS_BUFFER_SIZE]; - uint8_t read_status = 0; uint32_t start_time = GetCountSspClk(); // Send act_all ReaderTransmitIClass(act_all, 1, &start_time); // Card present? - if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time) < 0) return read_status;//Fail - + if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time) < 0) return false;//Fail + //Send Identify start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; ReaderTransmitIClass(identify, 1, &start_time); - // FpgaDisableTracing(); // DEBUGGING //We expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC uint8_t len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); - if (len != 10) return read_status;//Fail + if (len != 10) return false;//Fail //Copy the Anti-collision CSN to our select-packet memcpy(&select[1], resp, 8); @@ -1394,54 +1382,33 @@ static uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key, u ReaderTransmitIClass(select, sizeof(select), &start_time); //We expect a 10-byte response here, 8 byte CSN and 2 byte CRC len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); - if (len != 10) return read_status;//Fail + if (len != 10) return false;//Fail - //Success - level 1, we got CSN + //Success - we got CSN //Save CSN in response data memcpy(card_data, resp, 8); - //Flag that we got to at least stage 1, read CSN - read_status = 1; - - // Card selected, now read e-purse (cc) (only 8 bytes no CRC) - start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc), &start_time); - if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time) == 8) { - //Save CC (e-purse) in response data - memcpy(card_data+8, resp, 8); - read_status++; - } - - return read_status; -} - -static uint8_t handshakeIclassTag(uint8_t *card_data, uint32_t *eof_time) { - return handshakeIclassTag_ext(card_data, false, eof_time); + return true; } -// Reader iClass Anticollission +// Select an iClass tag and read all blocks which are always readable without authentication void ReaderIClass(uint8_t arg0) { + LED_A_ON(); + uint8_t card_data[6 * 8] = {0}; memset(card_data, 0xFF, sizeof(card_data)); - uint8_t last_csn[8] = {0,0,0,0,0,0,0,0}; uint8_t resp[ICLASS_BUFFER_SIZE]; - memset(resp, 0xFF, sizeof(resp)); //Read conf block CRC(0x01) => 0xfa 0x22 - uint8_t readConf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22}; + uint8_t readConf[] = {ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22}; + //Read e-purse block CRC(0x02) => 0x61 0x10 + uint8_t readEpurse[] = {ICLASS_CMD_READ_OR_IDENTIFY, 0x02, 0x61, 0x10}; //Read App Issuer Area block CRC(0x05) => 0xde 0x64 - uint8_t readAA[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; + uint8_t readAA[] = {ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; - int read_status= 0; uint8_t result_status = 0; - // flag to read until one tag is found successfully - bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE; - // flag to only try 5 times to find one tag then return - bool try_once = arg0 & FLAG_ICLASS_READER_ONE_TRY; - // if neither abort_after_read nor try_once then continue reading until button pressed. - bool use_credit_key = arg0 & FLAG_ICLASS_READER_CEDITKEY; // test flags for what blocks to be sure to read uint8_t flagReadConfig = arg0 & FLAG_ICLASS_READER_CONF; uint8_t flagReadCC = arg0 & FLAG_ICLASS_READER_CC; @@ -1454,93 +1421,57 @@ void ReaderIClass(uint8_t arg0) { StartCountSspClk(); uint32_t start_time = 0; uint32_t eof_time = 0; + + if (selectIclassTag(resp, &eof_time)) { + result_status = FLAG_ICLASS_READER_CSN; + memcpy(card_data, resp, 8); + } - uint16_t tryCnt = 0; - bool userCancelled = BUTTON_PRESS() || usb_poll_validate_length(); - while (!userCancelled) { - // if only looking for one card try 2 times if we missed it the first time - if (try_once && tryCnt > 2) { - break; - } - tryCnt++; - if (!get_tracing()) { - DbpString("Trace full"); - break; + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + + //Read block 1, config + if (flagReadConfig) { + if (sendCmdGetResponseWithRetries(readConf, sizeof(readConf), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { + result_status |= FLAG_ICLASS_READER_CONF; + memcpy(card_data+8, resp, 8); + } else { + Dbprintf("Failed to read config block"); } - WDT_HIT(); - - read_status = handshakeIclassTag_ext(card_data, use_credit_key, &eof_time); - - if (read_status == 0) continue; - if (read_status == 1) result_status = FLAG_ICLASS_READER_CSN; - if (read_status == 2) result_status = FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CC; - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - // handshakeIclass returns CSN|CC, but the actual block - // layout is CSN|CONFIG|CC, so here we reorder the data, - // moving CC forward 8 bytes - memcpy(card_data+16, card_data+8, 8); - //Read block 1, config - if (flagReadConfig) { - if (sendCmdGetResponseWithRetries(readConf, sizeof(readConf), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { - result_status |= FLAG_ICLASS_READER_CONF; - memcpy(card_data+8, resp, 8); - } else { - Dbprintf("Failed to dump config block"); - } - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - } + } - //Read block 5, AA - if (flagReadAA) { - if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { - result_status |= FLAG_ICLASS_READER_AA; - memcpy(card_data + (8*5), resp, 8); - } else { - //Dbprintf("Failed to dump AA block"); - } + //Read block 2, e-purse + if (flagReadCC) { + if (sendCmdGetResponseWithRetries(readEpurse, sizeof(readEpurse), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { + result_status |= FLAG_ICLASS_READER_CC; + memcpy(card_data + (8*2), resp, 8); + } else { + Dbprintf("Failed to read e-purse"); } + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + } - // 0 : CSN - // 1 : Configuration - // 2 : e-purse - // 3 : kd / debit / aa2 (write-only) - // 4 : kc / credit / aa1 (write-only) - // 5 : AIA, Application issuer area - //Then we can 'ship' back the 6 * 8 bytes of data, - // with 0xFF:s in block 3 and 4. - - LED_B_ON(); - //Send back to client, but don't bother if we already sent this - - // only useful if looping in arm (not try_once && not abort_after_read) - if (memcmp(last_csn, card_data, 8) != 0) { - // If caller requires that we get Conf, CC, AA, continue until we got it - if ( (result_status ^ FLAG_ICLASS_READER_CSN ^ flagReadConfig ^ flagReadCC ^ flagReadAA) == 0) { - cmd_send(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); - if (abort_after_read) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_A_OFF(); - LED_B_OFF(); - return; - } - //Save that we already sent this.... - memcpy(last_csn, card_data, 8); - } - + //Read block 5, AA + if (flagReadAA) { + if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { + result_status |= FLAG_ICLASS_READER_AA; + memcpy(card_data + (8*5), resp, 8); + } else { + Dbprintf("Failed to read AA block"); } - LED_B_OFF(); - userCancelled = BUTTON_PRESS() || usb_poll_validate_length(); - } - if (userCancelled) { - cmd_send(CMD_ACK, 0xFF, 0, 0, card_data, 0); - } else { - cmd_send(CMD_ACK, 0, 0, 0, card_data, 0); } + + cmd_send(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); + LED_A_OFF(); } + void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { + LED_A_ON(); + + bool use_credit_key = false; uint8_t card_data[USB_CMD_DATA_SIZE]={0}; uint16_t block_crc_LUT[255] = {0}; @@ -1551,6 +1482,9 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { } //Dbprintf("Lookup table: %02x %02x %02x" ,block_crc_LUT[0],block_crc_LUT[1],block_crc_LUT[2]); + uint8_t readcheck_cc[] = { ICLASS_CMD_READCHECK_KD, 0x02 }; + if (use_credit_key) + readcheck_cc[0] = ICLASS_CMD_READCHECK_KC; uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 }; @@ -1575,7 +1509,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { StartCountSspClk(); uint32_t start_time = 0; uint32_t eof_time = 0; - + while (!BUTTON_PRESS()) { WDT_HIT(); @@ -1585,34 +1519,33 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { break; } - uint8_t read_status = handshakeIclassTag(card_data, &eof_time); - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + if (!selectIclassTag(card_data, &eof_time)) continue; - if (read_status < 2) continue; + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + if (!sendCmdGetResponseWithRetries(readcheck_cc, sizeof(readcheck_cc), resp, sizeof(resp), 8, 3, start_time, &eof_time)) continue; - //for now replay captured auth (as cc not updated) + // replay captured auth (cc must not have been updated) memcpy(check+5, MAC, 4); + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; if (!sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 5, start_time, &eof_time)) { - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; Dbprintf("Error: Authentication Fail!"); continue; } - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; //first get configuration block (block 1) crc = block_crc_LUT[1]; read[1] = 1; read[2] = crc >> 8; read[3] = crc & 0xff; + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; if (!sendCmdGetResponseWithRetries(read, sizeof(read), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; Dbprintf("Dump config (block 1) failed"); continue; } - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; mem = resp[5]; memory.k16 = (mem & 0x80); memory.book = (mem & 0x20); @@ -1633,8 +1566,8 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { read[2] = crc >> 8; read[3] = crc & 0xff; + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; if (sendCmdGetResponseWithRetries(read, sizeof(read), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x", block, resp[0], resp[1], resp[2], resp[3], resp[4], resp[5], @@ -1683,19 +1616,33 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { 0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); LED_A_OFF(); } -void iClass_Authentication(uint8_t *MAC) { - uint8_t check[] = { ICLASS_CMD_CHECK_KD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t resp[ICLASS_BUFFER_SIZE]; + +void iClass_Check(uint8_t *MAC) { + uint8_t check[9] = {ICLASS_CMD_CHECK_KD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t resp[4]; memcpy(check+5, MAC, 4); - bool isOK; uint32_t eof_time; - isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 6, 0, &eof_time); - cmd_send(CMD_ACK,isOK, 0, 0, 0, 0); + bool isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 6, 0, &eof_time); + cmd_send(CMD_ACK, isOK, 0, 0, resp, sizeof(resp)); +} + + +void iClass_Readcheck(uint8_t block, bool use_credit_key) { + uint8_t readcheck[2] = {ICLASS_CMD_READCHECK_KD, block}; + if (use_credit_key) { + readcheck[0] = ICLASS_CMD_READCHECK_KC; + } + uint8_t resp[8]; + uint32_t eof_time; + bool isOK = sendCmdGetResponseWithRetries(readcheck, sizeof(readcheck), resp, sizeof(resp), 8, 6, 0, &eof_time); + cmd_send(CMD_ACK, isOK, 0, 0, resp, sizeof(resp)); } + static bool iClass_ReadBlock(uint8_t blockNo, uint8_t *readdata) { uint8_t readcmd[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockNo, 0x00, 0x00}; //0x88, 0x00 // can i use 0C? char bl = blockNo; @@ -1705,23 +1652,32 @@ static bool iClass_ReadBlock(uint8_t blockNo, uint8_t *readdata) { uint8_t resp[10]; bool isOK = false; uint32_t eof_time; - - //readcmd[1] = blockNo; + isOK = sendCmdGetResponseWithRetries(readcmd, sizeof(readcmd), resp, sizeof(resp), 10, 10, 0, &eof_time); memcpy(readdata, resp, sizeof(resp)); return isOK; } + void iClass_ReadBlk(uint8_t blockno) { + + LED_A_ON(); + uint8_t readblockdata[] = {0,0,0,0,0,0,0,0,0,0}; bool isOK = false; isOK = iClass_ReadBlock(blockno, readblockdata); cmd_send(CMD_ACK, isOK, 0, 0, readblockdata, 8); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + + LED_A_OFF(); } void iClass_Dump(uint8_t blockno, uint8_t numblks) { + + LED_A_ON(); + uint8_t readblockdata[] = {0,0,0,0,0,0,0,0,0,0}; bool isOK = false; uint8_t blkCnt = 0; @@ -1751,12 +1707,19 @@ void iClass_Dump(uint8_t blockno, uint8_t numblks) { } //return pointer to dump memory in arg3 cmd_send(CMD_ACK, isOK, blkCnt, BigBuf_max_traceLen(), 0, 0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); BigBuf_free(); + + LED_A_OFF(); } + static bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) { + + LED_A_ON(); + uint8_t write[] = { ICLASS_CMD_UPDATE, blockNo, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; //uint8_t readblockdata[10]; //write[1] = blockNo; @@ -1768,7 +1731,7 @@ static bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) { uint8_t resp[10]; bool isOK = false; uint32_t eof_time = 0; - + isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 10, 10, 0, &eof_time); uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; if (isOK) { //if reader responded correctly @@ -1780,10 +1743,17 @@ static bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) { } } } + + LED_A_OFF(); + return isOK; } + void iClass_WriteBlock(uint8_t blockNo, uint8_t *data) { + + LED_A_ON(); + bool isOK = iClass_WriteBlock_ext(blockNo, data); if (isOK){ Dbprintf("Write block [%02x] successful", blockNo); @@ -1791,7 +1761,11 @@ void iClass_WriteBlock(uint8_t blockNo, uint8_t *data) { Dbprintf("Write block [%02x] failed", blockNo); } cmd_send(CMD_ACK, isOK, 0, 0, 0, 0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + + LED_A_OFF(); } void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) { @@ -1819,5 +1793,6 @@ void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) { cmd_send(CMD_ACK, 1, 0, 0, 0, 0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); + LED_A_OFF(); } diff --git a/armsrc/iclass.h b/armsrc/iclass.h index 3cbe79fb..9666e888 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -15,6 +15,7 @@ #define ICLASS_H__ #include <stdint.h> +#include <stdbool.h> #include "common.h" // for RAMFUNC extern void RAMFUNC SnoopIClass(void); @@ -22,7 +23,8 @@ extern void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t extern void ReaderIClass(uint8_t arg0); extern void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC); extern void IClass_iso14443A_GetPublic(uint8_t arg0); -extern void iClass_Authentication(uint8_t *MAC); +extern void iClass_Readcheck(uint8_t block, bool use_credit_key); +extern void iClass_Check(uint8_t *MAC); extern void iClass_WriteBlock(uint8_t blockNo, uint8_t *data); extern void iClass_ReadBlk(uint8_t blockNo); extern void iClass_Dump(uint8_t blockno, uint8_t numblks); diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index fff8b370..3b39d576 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -132,7 +132,7 @@ void CodeIso15693AsReader(uint8_t *cmd, int n) { // EOF ToSend[++ToSendMax] = 0x20; //0010 + 0000 padding - + ToSendMax++; } @@ -249,14 +249,18 @@ void CodeIso15693AsTag(uint8_t *cmd, size_t len) { void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) { FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD); - + + if (*start_time < DELAY_ARM_TO_TAG) { + *start_time = DELAY_ARM_TO_TAG; + } + *start_time = (*start_time - DELAY_ARM_TO_TAG) & 0xfffffff0; while (GetCountSspClk() > *start_time) { // we may miss the intended time *start_time += 16; // next possible time } - + while (GetCountSspClk() < *start_time) /* wait */ ; @@ -275,7 +279,7 @@ void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) { WDT_HIT(); } LED_B_OFF(); - + *start_time = *start_time + DELAY_ARM_TO_TAG; } @@ -289,7 +293,7 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K); uint32_t modulation_start_time = *start_time - DELAY_ARM_TO_READER + 3 * 8; // no need to transfer the unmodulated start of SOF - + while (GetCountSspClk() > (modulation_start_time & 0xfffffff8) + 3) { // we will miss the intended time if (slot_time) { modulation_start_time += slot_time; // use next available slot @@ -298,7 +302,7 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, } } - while (GetCountSspClk() < (modulation_start_time & 0xfffffff8)) + while (GetCountSspClk() < (modulation_start_time & 0xfffffff8)) /* wait */ ; uint8_t shift_delay = modulation_start_time & 0x00000007; @@ -414,7 +418,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 // DecodeTag->posCount = 2; DecodeTag->state = STATE_TAG_SOF_HIGH; break; - + case STATE_TAG_SOF_HIGH: // waiting for 10 times high. Take average over the last 8 if (amplitude > DecodeTag->threshold_sof) { @@ -428,7 +432,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 } } else { // high phase was too short DecodeTag->posCount = 1; - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->previous_amplitude = amplitude; DecodeTag->state = STATE_TAG_SOF_LOW; } break; @@ -444,18 +448,18 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 DecodeTag->sum2 = 0; DecodeTag->posCount = 2; DecodeTag->state = STATE_TAG_RECEIVING_DATA; - // FpgaDisableTracing(); // DEBUGGING - // Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d", - // amplitude, - // DecodeTag->threshold_sof, - // DecodeTag->threshold_half/4, - // DecodeTag->previous_amplitude); // DEBUGGING + FpgaDisableTracing(); // DEBUGGING + Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d", + amplitude, + DecodeTag->threshold_sof, + DecodeTag->threshold_half/4, + DecodeTag->previous_amplitude); // DEBUGGING LED_C_ON(); } else { DecodeTag->posCount++; if (DecodeTag->posCount > 13) { // high phase too long DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->previous_amplitude = amplitude; DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } @@ -478,7 +482,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 DecodeTag->state = STATE_TAG_EOF; } else { DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->previous_amplitude = amplitude; DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } @@ -508,7 +512,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 // logic 0 if (DecodeTag->lastBit == SOF_PART1) { // incomplete SOF DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->previous_amplitude = amplitude; DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } else { @@ -522,7 +526,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 if (DecodeTag->len > DecodeTag->max_len) { // buffer overflow, give up DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->previous_amplitude = amplitude; DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } @@ -561,7 +565,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 DecodeTag->state = STATE_TAG_EOF_TAIL; } else { DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->previous_amplitude = amplitude; DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } @@ -585,7 +589,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 return true; } else { DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->previous_amplitude = amplitude; DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } @@ -598,8 +602,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 } -static void DecodeTagInit(DecodeTag_t *DecodeTag, uint8_t *data, uint16_t max_len) -{ +static void DecodeTagInit(DecodeTag_t *DecodeTag, uint8_t *data, uint16_t max_len) { DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; DecodeTag->posCount = 0; DecodeTag->state = STATE_TAG_SOF_LOW; @@ -608,8 +611,7 @@ static void DecodeTagInit(DecodeTag_t *DecodeTag, uint8_t *data, uint16_t max_le } -static void DecodeTagReset(DecodeTag_t *DecodeTag) -{ +static void DecodeTagReset(DecodeTag_t *DecodeTag) { DecodeTag->posCount = 0; DecodeTag->state = STATE_TAG_SOF_LOW; DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; @@ -649,10 +651,10 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo samples++; if (samples == 1) { - // DMA has transferred the very first data + // DMA has transferred the very first data dma_start_time = GetCountSspClk() & 0xfffffff0; } - + uint16_t tagdata = *upTo++; if(upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. @@ -680,7 +682,7 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo } if (samples > timeout && DecodeTag.state < STATE_TAG_RECEIVING_DATA) { - ret = -1; // timeout + ret = -1; // timeout break; } @@ -699,9 +701,9 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo - DecodeTag.len * 8 * 8 * 16 // time for byte transfers - 32 * 16 // time for SOF transfer - (DecodeTag.lastBit != SOF_PART2?32*16:0); // time for EOF transfer - + if (DEBUG) Dbprintf("timing: sof_time = %d, eof_time = %d", sof_time, *eof_time); - + LogTrace_ISO15693(DecodeTag.output, DecodeTag.len, sof_time*4, *eof_time*4, NULL, false); return DecodeTag.len; @@ -1089,20 +1091,19 @@ static void BuildIdentifyRequest(void) //----------------------------------------------------------------------------- void AcquireRawAdcSamplesIso15693(void) { - LEDsoff(); LED_A_ON(); uint8_t *dest = BigBuf_get_addr(); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); + LED_D_ON(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); BuildIdentifyRequest(); // Give the tags time to energize - LED_D_ON(); SpinDelay(100); // Now send the command @@ -1129,6 +1130,7 @@ void AcquireRawAdcSamplesIso15693(void) void SnoopIso15693(void) { LED_A_ON(); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); BigBuf_free(); @@ -1348,17 +1350,13 @@ static void BuildInventoryResponse(uint8_t *uid) // return: length of received data, or -1 for timeout int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, uint32_t *eof_time) { - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - if (init) { Iso15693InitReader(); StartCountSspClk(); } - + int answerLen = 0; - + if (!speed) { // low speed (1 out of 256) CodeIso15693AsReader256(send, sendlen); @@ -1367,18 +1365,13 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t *recv, CodeIso15693AsReader(send, sendlen); } - if (start_time == 0) { - start_time = GetCountSspClk(); - } TransmitTo15693Tag(ToSend, ToSendMax, &start_time); // Now wait for a response if (recv != NULL) { - answerLen = GetIso15693AnswerFromTag(recv, max_recv_len, DELAY_ISO15693_VCD_TO_VICC_READER * 2, eof_time); + answerLen = GetIso15693AnswerFromTag(recv, max_recv_len, ISO15693_READER_TIMEOUT, eof_time); } - LED_A_OFF(); - return answerLen; } @@ -1462,9 +1455,8 @@ void SetDebugIso15693(uint32_t debug) { // Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector. // all demodulation performed in arm rather than host. - greg //--------------------------------------------------------------------------------------- -void ReaderIso15693(uint32_t parameter) -{ - LEDsoff(); +void ReaderIso15693(uint32_t parameter) { + LED_A_ON(); set_tracing(true); @@ -1564,9 +1556,8 @@ void ReaderIso15693(uint32_t parameter) // Simulate an ISO15693 TAG. // For Inventory command: print command and send Inventory Response with given UID // TODO: interpret other reader commands and send appropriate response -void SimTagIso15693(uint32_t parameter, uint8_t *uid) -{ - LEDsoff(); +void SimTagIso15693(uint32_t parameter, uint8_t *uid) { + LED_A_ON(); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); @@ -1597,7 +1588,8 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) } FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); + LED_A_OFF(); } @@ -1605,7 +1597,6 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) // (some manufactures offer a way to read the AFI, though) void BruteforceIso15693Afi(uint32_t speed) { - LEDsoff(); LED_A_ON(); uint8_t data[6]; @@ -1648,17 +1639,19 @@ void BruteforceIso15693Afi(uint32_t speed) Dbprintf("AFI Bruteforcing done."); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); + LED_A_OFF(); + } // Allows to directly send commands to the tag via the client void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t data[]) { + LED_A_ON(); + int recvlen = 0; uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; uint32_t eof_time; - - LED_A_ON(); if (DEBUG) { Dbprintf("SEND:"); @@ -1695,17 +1688,16 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint //----------------------------------------------------------------------------- // Set the UID to the tag (based on Iceman work). -void SetTag15693Uid(uint8_t *uid) -{ - uint8_t cmd[4][9] = {0x00}; +void SetTag15693Uid(uint8_t *uid) { + LED_A_ON(); + + uint8_t cmd[4][9] = {0x00}; uint16_t crc; int recvlen = 0; uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; uint32_t eof_time; - - LED_A_ON(); // Command 1 : 02213E00000000 cmd[0][0] = 0x02; @@ -1767,8 +1759,6 @@ void SetTag15693Uid(uint8_t *uid) cmd_send(CMD_ACK, recvlen>ISO15693_MAX_RESPONSE_LENGTH?ISO15693_MAX_RESPONSE_LENGTH:recvlen, 0, 0, recvbuf, ISO15693_MAX_RESPONSE_LENGTH); } - LED_D_OFF(); - LED_A_OFF(); } diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h index 96a2b39b..5cbe5ecc 100644 --- a/armsrc/iso15693.h +++ b/armsrc/iso15693.h @@ -21,6 +21,8 @@ //SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader. All values should be multiples of 16 #define DELAY_ISO15693_VCD_TO_VICC_READER 1056 // 1056/3,39MHz = 311.5us from end of command EOF to start of tag response #define DELAY_ISO15693_VICC_TO_VCD_READER 1024 // 1024/3.39MHz = 302.1us between end of tag response and next reader command +// times in samples @ 212kHz when acting as reader +#define ISO15693_READER_TIMEOUT 330 // 330/212kHz = 1558us, should be even enough for iClass tags responding to ACTALL void Iso15693InitReader(); void CodeIso15693AsReader(uint8_t *cmd, int n); diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 81738686..195a282d 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -35,7 +35,6 @@ #include "util_posix.h" #include "cmdhf14a.h" // DropField() -static int CmdHelp(const char *Cmd); #define ICLASS_KEYS_MAX 8 static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][8] = { @@ -49,12 +48,14 @@ static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][8] = { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }; + typedef struct iclass_block { - uint8_t d[8]; + uint8_t d[8]; } iclass_block_t; -int usage_hf_iclass_chk(void) { - PrintAndLog("Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag"); + +static void usage_hf_iclass_chk(void) { + PrintAndLog("Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag"); PrintAndLog("Usage: hf iclass chk [h|e|r] <f (*.dic)>"); PrintAndLog("Options:"); PrintAndLog("h Show this help"); @@ -62,31 +63,25 @@ int usage_hf_iclass_chk(void) { PrintAndLog(" e target Elite / High security key scheme"); PrintAndLog(" r interpret dictionary file as raw (diversified keys)"); PrintAndLog("Samples:"); - PrintAndLog(" hf iclass chk f default_iclass_keys.dic"); - PrintAndLog(" hf iclass chk f default_iclass_keys.dic e"); - return 0; + PrintAndLog(" hf iclass chk f default_iclass_keys.dic"); + PrintAndLog(" hf iclass chk f default_iclass_keys.dic e"); } -int xorbits_8(uint8_t val) { - uint8_t res = val ^ (val >> 1); //1st pass - res = res ^ (res >> 1); // 2nd pass - res = res ^ (res >> 2); // 3rd pass - res = res ^ (res >> 4); // 4th pass - return res & 1; -} -int CmdHFiClassList(const char *Cmd) { +static int CmdHFiClassList(const char *Cmd) { PrintAndLog("Deprecated command, use 'hf list iclass' instead"); return 0; } -int CmdHFiClassSnoop(const char *Cmd) { + +static int CmdHFiClassSnoop(const char *Cmd) { UsbCommand c = {CMD_SNOOP_ICLASS}; SendCommand(&c); return 0; } -int usage_hf_iclass_sim(void) { + +static void usage_hf_iclass_sim(void) { PrintAndLog("Usage: hf iclass sim <option> [CSN]"); PrintAndLog(" options"); PrintAndLog(" 0 <CSN> simulate the given CSN"); @@ -97,9 +92,9 @@ int usage_hf_iclass_sim(void) { PrintAndLog(" example: hf iclass sim 2"); PrintAndLog(" example: hf iclass eload 'tagdump.bin'"); PrintAndLog(" hf iclass sim 3"); - return 0; } + // the original malicious IDs from Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult, // and Milosch Meriac. Dismantling iClass and iClass Elite. #define NUM_CSNS 15 @@ -127,32 +122,34 @@ static uint8_t csns[8 * NUM_CSNS] = { // #define NUM_CSNS 9 // static uint8_t csns[8 * NUM_CSNS] = { - // 0x01, 0x0A, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, - // 0x0C, 0x06, 0x0C, 0xFE, 0xF7, 0xFF, 0x12, 0xE0, - // 0x10, 0x97, 0x83, 0x7B, 0xF7, 0xFF, 0x12, 0xE0, - // 0x13, 0x97, 0x82, 0x7A, 0xF7, 0xFF, 0x12, 0xE0, - // 0x07, 0x0E, 0x0D, 0xF9, 0xF7, 0xFF, 0x12, 0xE0, - // 0x14, 0x96, 0x84, 0x76, 0xF7, 0xFF, 0x12, 0xE0, - // 0x17, 0x96, 0x85, 0x71, 0xF7, 0xFF, 0x12, 0xE0, - // 0xCE, 0xC5, 0x0F, 0x77, 0xF7, 0xFF, 0x12, 0xE0, - // 0xD2, 0x5A, 0x82, 0xF8, 0xF7, 0xFF, 0x12, 0xE0 - // //0x04, 0x08, 0x9F, 0x78, 0x6E, 0xFF, 0x12, 0xE0 + // 0x01, 0x0A, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, + // 0x0C, 0x06, 0x0C, 0xFE, 0xF7, 0xFF, 0x12, 0xE0, + // 0x10, 0x97, 0x83, 0x7B, 0xF7, 0xFF, 0x12, 0xE0, + // 0x13, 0x97, 0x82, 0x7A, 0xF7, 0xFF, 0x12, 0xE0, + // 0x07, 0x0E, 0x0D, 0xF9, 0xF7, 0xFF, 0x12, 0xE0, + // 0x14, 0x96, 0x84, 0x76, 0xF7, 0xFF, 0x12, 0xE0, + // 0x17, 0x96, 0x85, 0x71, 0xF7, 0xFF, 0x12, 0xE0, + // 0xCE, 0xC5, 0x0F, 0x77, 0xF7, 0xFF, 0x12, 0xE0, + // 0xD2, 0x5A, 0x82, 0xF8, 0xF7, 0xFF, 0x12, 0xE0 + // //0x04, 0x08, 0x9F, 0x78, 0x6E, 0xFF, 0x12, 0xE0 // }; -int CmdHFiClassSim(const char *Cmd) { +static int CmdHFiClassSim(const char *Cmd) { uint8_t simType = 0; uint8_t CSN[8] = {0, 0, 0, 0, 0, 0, 0, 0}; if (strlen(Cmd) < 1) { - return usage_hf_iclass_sim(); + usage_hf_iclass_sim(); + return 0; } simType = param_get8ex(Cmd, 0, 0, 10); if (simType == ICLASS_SIM_MODE_CSN) { if (param_gethex(Cmd, 1, CSN, 16)) { PrintAndLog("A CSN should consist of 16 HEX symbols"); - return usage_hf_iclass_sim(); + usage_hf_iclass_sim(); + return 0; } PrintAndLog("--simtype:%02x csn:%s", simType, sprint_hex(CSN, 8)); } @@ -186,8 +183,8 @@ int CmdHFiClassSim(const char *Cmd) { void* dump = malloc(datalen); for(int i = 0; i < NUM_CSNS; i++) { memcpy(dump + i*24, csns+i*8, 8); //CSN - //copy CC from response - memcpy(dump + i*24 + 8, resp.d.asBytes + i*16, 8); + //copy CC from response + memcpy(dump + i*24 + 8, resp.d.asBytes + i*16, 8); //Then comes NR_MAC (eight bytes from the response) memcpy(dump + i*24 + 16, resp.d.asBytes + i*16 + 8, 8); } @@ -202,17 +199,18 @@ int CmdHFiClassSim(const char *Cmd) { } else { PrintAndLog("Undefined simtype %d", simType); - return usage_hf_iclass_sim(); + usage_hf_iclass_sim(); + return 0; } return 0; } + int HFiClassReader(const char *Cmd, bool loop, bool verbose) { bool tagFound = false; UsbCommand c = {CMD_READER_ICLASS, {FLAG_ICLASS_READER_CSN | - FLAG_ICLASS_READER_CC | FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_AA | - FLAG_ICLASS_READER_ONLY_ONCE | FLAG_ICLASS_READER_ONE_TRY } }; + FLAG_ICLASS_READER_CC | FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_AA} }; // loop in client not device - else on windows have a communication error UsbCommand resp; while(!ukbhit()){ @@ -232,7 +230,7 @@ int HFiClassReader(const char *Cmd, bool loop, bool verbose) { PrintAndLog(" CSN: %s",sprint_hex(data,8)); tagFound = true; } - if( readStatus & FLAG_ICLASS_READER_CC) { + if( readStatus & FLAG_ICLASS_READER_CC) { PrintAndLog(" CC: %s",sprint_hex(data+16,8)); } if( readStatus & FLAG_ICLASS_READER_CONF) { @@ -244,7 +242,7 @@ int HFiClassReader(const char *Cmd, bool loop, bool verbose) { for (int i = 0; i<8; i++) { if (data[8*5+i] != 0xFF) { legacy = false; - } + } } PrintAndLog(" : Possible iClass %s",(legacy) ? "(legacy tag)" : "(NOT legacy tag)"); } @@ -258,11 +256,13 @@ int HFiClassReader(const char *Cmd, bool loop, bool verbose) { return 0; } -int CmdHFiClassReader(const char *Cmd) { + +static int CmdHFiClassReader(const char *Cmd) { return HFiClassReader(Cmd, true, true); } -int CmdHFiClassReader_Replay(const char *Cmd) { + +static int CmdHFiClassReader_Replay(const char *Cmd) { uint8_t readerType = 0; uint8_t MAC[4]={0x00, 0x00, 0x00, 0x00}; @@ -284,26 +284,22 @@ int CmdHFiClassReader_Replay(const char *Cmd) { return 0; } -int iclassEmlSetMem(uint8_t *data, int blockNum, int blocksCount) { - UsbCommand c = {CMD_MIFARE_EML_MEMSET, {blockNum, blocksCount, 0}}; - memcpy(c.d.asBytes, data, blocksCount * 16); - SendCommand(&c); - return 0; -} -int hf_iclass_eload_usage(void) { +static void usage_hf_iclass_eload(void) { PrintAndLog("Loads iclass tag-dump into emulator memory on device"); PrintAndLog("Usage: hf iclass eload f <filename>"); PrintAndLog(""); PrintAndLog("Example: hf iclass eload f iclass_tagdump-aa162d30f8ff12f1.bin"); - return 0; } -int CmdHFiClassELoad(const char *Cmd) { + +static int CmdHFiClassELoad(const char *Cmd) { char opt = param_getchar(Cmd, 0); - if (strlen(Cmd)<1 || opt == 'h') - return hf_iclass_eload_usage(); + if (strlen(Cmd)<1 || opt == 'h') { + usage_hf_iclass_eload(); + return 0; + } //File handling and reading FILE *f; @@ -311,7 +307,8 @@ int CmdHFiClassELoad(const char *Cmd) { if (opt == 'f' && param_getstr(Cmd, 1, filename, sizeof(filename)) > 0) { f = fopen(filename, "rb"); } else { - return hf_iclass_eload_usage(); + usage_hf_iclass_eload(); + return 0; } if (!f) { @@ -337,7 +334,7 @@ int CmdHFiClassELoad(const char *Cmd) { printIclassDumpInfo(dump); //Validate - if (bytes_read < fsize) { + if (bytes_read < fsize) { prnlog("Error, could only read %d bytes (should be %d)",bytes_read, fsize ); free(dump); return 1; @@ -359,6 +356,7 @@ int CmdHFiClassELoad(const char *Cmd) { return 0; } + static int readKeyfile(const char *filename, size_t len, uint8_t* buffer) { FILE *f = fopen(filename, "rb"); if(!f) { @@ -383,7 +381,8 @@ static int readKeyfile(const char *filename, size_t len, uint8_t* buffer) { return 0; } -int usage_hf_iclass_decrypt(void) { + +static void usage_hf_iclass_decrypt(void) { PrintAndLog("Usage: hf iclass decrypt f <tagdump>"); PrintAndLog(""); PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside"); @@ -394,10 +393,10 @@ int usage_hf_iclass_decrypt(void) { 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) { + +static int CmdHFiClassDecrypt(const char *Cmd) { uint8_t key[16] = { 0 }; if(readKeyfile("iclass_decryptionkey.bin", 16, key)) { @@ -406,8 +405,10 @@ int CmdHFiClassDecrypt(const char *Cmd) { } PrintAndLog("Decryption file found... "); char opt = param_getchar(Cmd, 0); - if (strlen(Cmd)<1 || opt == 'h') - return usage_hf_iclass_decrypt(); + if (strlen(Cmd)<1 || opt == 'h') { + usage_hf_iclass_decrypt(); + return 0; + } //Open the tagdump-file FILE *f; @@ -419,7 +420,8 @@ int CmdHFiClassDecrypt(const char *Cmd) { return 1; } } else { - return usage_hf_iclass_decrypt(); + usage_hf_iclass_decrypt(); + return 0; } fseek(f, 0, SEEK_END); @@ -457,7 +459,8 @@ int CmdHFiClassDecrypt(const char *Cmd) { return 0; } -int usage_hf_iclass_encrypt(void) { + +static void usage_hf_iclass_encrypt(void) { PrintAndLog("Usage: hf iclass encrypt <BlockData>"); PrintAndLog(""); PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside"); @@ -465,9 +468,9 @@ int usage_hf_iclass_encrypt(void) { PrintAndLog(""); PrintAndLog("example: hf iclass encrypt 0102030405060708"); PrintAndLog(""); - return 0; } + static int iClassEncryptBlkData(uint8_t *blkData) { uint8_t key[16] = { 0 }; if(readKeyfile("iclass_decryptionkey.bin", 16, key)) @@ -481,7 +484,7 @@ static int iClassEncryptBlkData(uint8_t *blkData) { uint8_t *encrypted = encryptedData; mbedtls_des3_context ctx = { {0} }; mbedtls_des3_set2key_enc( &ctx, key); - + mbedtls_des3_crypt_ecb(&ctx, blkData,encrypted); //printvar("decrypted block", decrypted, 8); memcpy(blkData,encrypted,8); @@ -489,25 +492,26 @@ static int iClassEncryptBlkData(uint8_t *blkData) { return 1; } -int CmdHFiClassEncryptBlk(const char *Cmd) { + +static 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)<1 || opt == 'h') { + usage_hf_iclass_encrypt(); + return 0; + } //get the bytes to encrypt - if (param_gethex(Cmd, 0, blkData, 16)) - { + if (param_gethex(Cmd, 0, blkData, 16)) { PrintAndLog("BlockData must include 16 HEX symbols"); return 0; } if (!iClassEncryptBlkData(blkData)) return 0; - printvar("encrypted block", blkData, 8); return 1; } -void Calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_t MAC[4]) { + +static 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); @@ -515,18 +519,15 @@ void Calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_t MAC[4 //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]); } -static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool verbose) { + +static bool select_only(uint8_t *CSN, bool verbose) { UsbCommand resp; UsbCommand c = {CMD_READER_ICLASS, {0}}; - c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE | FLAG_ICLASS_READER_CC | FLAG_ICLASS_READER_ONE_TRY; - if (use_credit_key) - c.arg[0] |= FLAG_ICLASS_READER_CEDITKEY; clearCommandBuffer(); SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK,&resp,4500)) - { + if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) { PrintAndLog("Command execute timeout"); return false; } @@ -534,45 +535,81 @@ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool v uint8_t isOK = resp.arg[0] & 0xff; uint8_t *data = resp.d.asBytes; - memcpy(CSN,data,8); - if (CCNR!=NULL)memcpy(CCNR,data+16,8); - if(isOK > 0) - { - if (verbose) PrintAndLog("CSN: %s",sprint_hex(CSN,8)); - } - if(isOK <= 1){ - PrintAndLog("Failed to obtain CC! Aborting"); + memcpy(CSN, data, 8); + + if (isOK > 0) { + if (verbose) PrintAndLog("CSN: %s", sprint_hex(CSN, 8)); + } else { + PrintAndLog("Failed to select card! Aborting"); return false; } - return true; + return true; } + +static void HFiClassCalcDivKey(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key, bool elite){ + uint8_t keytable[128] = {0}; + uint8_t key_index[8] = {0}; + if (elite) { + uint8_t key_sel[8] = { 0 }; + uint8_t key_sel_p[8] = { 0 }; + hash2(KEY, keytable); + hash1(CSN, key_index); + for(uint8_t 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, div_key); + } else { + diversifyKey(CSN, KEY, div_key); + } +} + + static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool use_credit_key, bool elite, bool rawkey, 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 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}; - if (!select_only(CSN, CCNR, use_credit_key, verbose)) + if (!select_only(CSN, verbose)) return false; //get div_key - if(rawkey) + if (rawkey) memcpy(div_key, KEY, 8); else HFiClassCalcDivKey(CSN, KEY, div_key, elite); - if (verbose) PrintAndLog("Authing with %s: %02x%02x%02x%02x%02x%02x%02x%02x", rawkey ? "raw key" : "diversified key", div_key[0],div_key[1],div_key[2],div_key[3],div_key[4],div_key[5],div_key[6],div_key[7]); - doMAC(CCNR, div_key, MAC); + if (verbose) PrintAndLog("Authenticating with %s: %s", rawkey ? "raw key" : "diversified key", sprint_hex(div_key, 8)); + UsbCommand resp; - UsbCommand d = {CMD_ICLASS_AUTHENTICATION, {0}}; + UsbCommand d = {CMD_ICLASS_READCHECK, {2, use_credit_key, 0}}; + + clearCommandBuffer(); + SendCommand(&d); + + if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) { + if (verbose) PrintAndLog("Auth Command (READCHECK[2]) execute timeout"); + return false; + } + bool isOK = resp.arg[0]; + if (!isOK) { + if (verbose) PrintAndLog("Couldn't get Card Challenge"); + return false; + } + memcpy(CCNR, resp.d.asBytes, 8); + + doMAC(CCNR, div_key, MAC); + + d.cmd = CMD_ICLASS_CHECK; memcpy(d.d.asBytes, MAC, 4); clearCommandBuffer(); SendCommand(&d); - if (!WaitForResponseTimeout(CMD_ACK,&resp,4500)) - { - if (verbose) PrintAndLog("Auth Command execute timeout"); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) { + if (verbose) PrintAndLog("Auth Command (CHECK) execute timeout"); return false; } - uint8_t isOK = resp.arg[0] & 0xff; + isOK = resp.arg[0]; if (!isOK) { if (verbose) PrintAndLog("Authentication error"); return false; @@ -580,7 +617,8 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u return true; } -int usage_hf_iclass_dump(void) { + +static void usage_hf_iclass_dump(void) { PrintAndLog("Usage: hf iclass dump f <fileName> k <Key> c <CreditKey> e|r\n"); PrintAndLog("Options:"); PrintAndLog(" f <filename> : specify a filename to save dump to"); @@ -591,14 +629,45 @@ int usage_hf_iclass_dump(void) { PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format"); PrintAndLog(" r : If 'r' is specified, the key is interpreted as raw block 3/4"); PrintAndLog(" NOTE: * = required"); - PrintAndLog("Samples:"); + 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) { + +static void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize) { + 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 = 31; + //PrintAndLog ("endblock: %d, filesize: %d, maxmemcount: %d, filemaxblock: %d", endblock,filesize, maxmemcount, filemaxblock); + + if (startblock == 0) + startblock = 6; + if ((endblock > maxmemcount) || (endblock == 0)) + endblock = maxmemcount; + + // remember endblock need to relate to zero-index arrays. + if (endblock > filemaxblock-1) + endblock = filemaxblock; + + int i = startblock; + printf("------+--+-------------------------+\n"); + while (i <= endblock) { + uint8_t *blk = iclass_dump + (i * 8); + printf("Block |%02X| %s|\n", i, sprint_hex(blk, 8) ); + i++; + } + printf("------+--+-------------------------+\n"); +} + + +static 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}; @@ -629,7 +698,8 @@ int CmdHFiClassReader_Dump(const char *Cmd) { { case 'h': case 'H': - return usage_hf_iclass_dump(); + usage_hf_iclass_dump(); + return 0; case 'c': case 'C': have_credit_key = true; @@ -657,7 +727,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) { break; case 'f': case 'F': - fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); + fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); if (fileNameLen < 1) { PrintAndLog("No filename found after f"); errors = true; @@ -668,7 +738,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) { case 'K': have_debit_key = true; dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr)); - if (dataLen == 16) { + if (dataLen == 16) { errors = param_gethex(tempStr, 0, KEY, dataLen); } else if (dataLen == 1) { keyNbr = param_get8(Cmd, cmdp+1); @@ -694,16 +764,21 @@ int CmdHFiClassReader_Dump(const char *Cmd) { errors = true; break; } - if(errors) return usage_hf_iclass_dump(); + if (errors) { + usage_hf_iclass_dump(); + return 0; + } } - if (cmdp < 2) return usage_hf_iclass_dump(); + if (cmdp < 2) { + usage_hf_iclass_dump(); + return 0; + } // if no debit key given try credit key on AA1 (not for iclass but for some picopass this will work) if (!have_debit_key && have_credit_key) use_credit_key = true; //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 c = {CMD_READER_ICLASS, {FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CONF}}; UsbCommand resp; uint8_t tag_data[255*8]; @@ -739,7 +814,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) { return 0; } } - + // begin dump UsbCommand w = {CMD_ICLASS_DUMP, {blockno, numblks-blockno+1}}; clearCommandBuffer(); @@ -796,7 +871,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) { PrintAndLog("Read Block Failed 2"); DropField(); return 0; - } + } startindex = resp.arg[2]; if (blocksRead*8 > sizeof(tag_data)-gotBytes) { @@ -806,7 +881,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) { // get dumped data from bigbuf GetFromBigBuf(tag_data+gotBytes, blocksRead*8, startindex, NULL, -1, false); - gotBytes += blocksRead*8; + gotBytes += blocksRead*8; } else { //field is still on - turn it off... DropField(); } @@ -819,11 +894,11 @@ int CmdHFiClassReader_Dump(const char *Cmd) { printf("------+--+-------------------------+\n"); printf("CSN |00| %s|\n",sprint_hex(tag_data, 8)); printIclassDumpContents(tag_data, 1, (gotBytes/8), gotBytes); - + 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]); + tag_data[0],tag_data[1],tag_data[2],tag_data[3], + tag_data[4],tag_data[5],tag_data[6],tag_data[7]); } // save the dump to .bin file @@ -832,6 +907,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) { return 1; } + static int WriteBlock(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool verbose) { uint8_t MAC[4]={0x00,0x00,0x00,0x00}; uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; @@ -844,7 +920,7 @@ static int WriteBlock(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_c UsbCommand w = {CMD_ICLASS_WRITEBLOCK, {blockno}}; memcpy(w.d.asBytes, bldata, 8); memcpy(w.d.asBytes + 8, MAC, 4); - + clearCommandBuffer(); SendCommand(&w); if (!WaitForResponseTimeout(CMD_ACK,&resp,4500)) @@ -861,22 +937,23 @@ static int WriteBlock(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_c return 1; } -int usage_hf_iclass_writeblock(void) { + +static void usage_hf_iclass_writeblock(void) { PrintAndLog("Options:"); - PrintAndLog(" b <Block> : The block number as 2 hex symbols"); - PrintAndLog(" d <data> : Set the Data to write as 16 hex symbols"); + PrintAndLog(" b <Block> : The block number as 2 hex symbols"); + PrintAndLog(" d <data> : Set the Data to write as 16 hex symbols"); PrintAndLog(" k <Key> : 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(" r : If 'r' is specified, no computations applied to key"); - PrintAndLog("Samples:"); + 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(" r : If 'r' is specified, no 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) { + +static int CmdHFiClass_WriteBlock(const char *Cmd) { uint8_t blockno=0; uint8_t bldata[8]={0,0,0,0,0,0,0,0}; uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; @@ -894,7 +971,8 @@ int CmdHFiClass_WriteBlock(const char *Cmd) { { case 'h': case 'H': - return usage_hf_iclass_writeblock(); + usage_hf_iclass_writeblock(); + return 0; case 'b': case 'B': if (param_gethex(Cmd, cmdp+1, &blockno, 2)) { @@ -925,7 +1003,7 @@ int CmdHFiClass_WriteBlock(const char *Cmd) { case 'k': case 'K': dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr)); - if (dataLen == 16) { + if (dataLen == 16) { errors = param_gethex(tempStr, 0, KEY, dataLen); } else if (dataLen == 1) { keyNbr = param_get8(Cmd, cmdp+1); @@ -951,16 +1029,23 @@ int CmdHFiClass_WriteBlock(const char *Cmd) { errors = true; break; } - if(errors) return usage_hf_iclass_writeblock(); + if(errors) { + usage_hf_iclass_writeblock(); + return 0; + } } - if (cmdp < 6) return usage_hf_iclass_writeblock(); + if (cmdp < 6) { + usage_hf_iclass_writeblock(); + return 0; + } int ans = WriteBlock(blockno, bldata, KEY, use_credit_key, elite, rawkey, true); DropField(); return ans; } -int usage_hf_iclass_clone(void) { + +static void usage_hf_iclass_clone(void) { PrintAndLog("Usage: hf iclass clone f <tagfile.bin> b <first block> l <last block> k <KEY> c e|r"); PrintAndLog("Options:"); PrintAndLog(" f <filename>: specify a filename to clone from"); @@ -974,10 +1059,10 @@ int usage_hf_iclass_clone(void) { 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) { + +static int CmdHFiClassCloneTag(const char *Cmd) { char filename[FILE_PATH_SIZE] = {0}; char tempStr[50]={0}; uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; @@ -997,7 +1082,8 @@ int CmdHFiClassCloneTag(const char *Cmd) { { case 'h': case 'H': - return usage_hf_iclass_clone(); + usage_hf_iclass_clone(); + return 0; case 'b': case 'B': if (param_gethex(Cmd, cmdp+1, &startblock, 2)) { @@ -1018,7 +1104,7 @@ int CmdHFiClassCloneTag(const char *Cmd) { break; case 'f': case 'F': - fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); + fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); if (fileNameLen < 1) { PrintAndLog("No filename found after f"); errors = true; @@ -1028,7 +1114,7 @@ int CmdHFiClassCloneTag(const char *Cmd) { case 'k': case 'K': dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr)); - if (dataLen == 16) { + if (dataLen == 16) { errors = param_gethex(tempStr, 0, KEY, dataLen); } else if (dataLen == 1) { keyNbr = param_get8(Cmd, cmdp+1); @@ -1062,10 +1148,16 @@ int CmdHFiClassCloneTag(const char *Cmd) { errors = true; break; } - if(errors) return usage_hf_iclass_clone(); + if (errors) { + usage_hf_iclass_clone(); + return 0; + } } - if (cmdp < 8) return usage_hf_iclass_clone(); + if (cmdp < 8) { + usage_hf_iclass_clone(); + return 0; + } FILE *f; @@ -1108,21 +1200,21 @@ int CmdHFiClassCloneTag(const char *Cmd) { 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); + 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]); + 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); @@ -1134,7 +1226,9 @@ int CmdHFiClassCloneTag(const char *Cmd) { return 1; } + static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool verbose, bool auth) { + uint8_t MAC[4]={0x00,0x00,0x00,0x00}; uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; @@ -1142,9 +1236,8 @@ static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, if (!select_and_auth(KEY, MAC, div_key, (keyType==0x18), elite, rawkey, verbose)) return 0; } else { - 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}; - if (!select_only(CSN, CCNR, (keyType==0x18), verbose)) + uint8_t CSN[8]; + if (!select_only(CSN, verbose)) return 0; } @@ -1152,8 +1245,7 @@ static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, UsbCommand w = {CMD_ICLASS_READBLOCK, {blockno}}; clearCommandBuffer(); SendCommand(&w); - if (!WaitForResponseTimeout(CMD_ACK,&resp,4500)) - { + if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) { PrintAndLog("Command execute timeout"); return 0; } @@ -1167,22 +1259,23 @@ static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, return 1; } -int usage_hf_iclass_readblock(void) { - PrintAndLog("Usage: hf iclass readblk b <Block> k <Key> c e|r\n"); + +static void usage_hf_iclass_readblock(void) { + PrintAndLog("Usage: hf iclass readblk b <Block> k <Key> [c] [e|r]\n"); PrintAndLog("Options:"); - PrintAndLog(" b <Block> : The block number as 2 hex symbols"); + PrintAndLog(" b <Block> : The block number as 2 hex symbols"); PrintAndLog(" k <Key> : 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(" r : If 'r' is specified, no computations applied to key"); - PrintAndLog("Samples:"); + 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(" r : If 'r' is specified, no 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) { + +static 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}; @@ -1194,71 +1287,78 @@ int CmdHFiClass_ReadBlock(const char *Cmd) { bool errors = false; bool auth = 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': - auth = true; - dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(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); + while (param_getchar(Cmd, cmdp) != 0x00) { + switch (param_getchar(Cmd, cmdp)) { + case 'h': + case 'H': + usage_hf_iclass_readblock(); + return 0; + 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': + auth = true; + dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(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: KeyNbr is invalid\n"); + errors = true; + } } else { - PrintAndLog("\nERROR: Credit KeyNbr is invalid\n"); + PrintAndLog("\nERROR: Key is incorrect length\n"); errors = true; } - } else { - PrintAndLog("\nERROR: Credit Key is incorrect length\n"); + cmdp += 2; + break; + case 'r': + case 'R': + rawkey = true; + cmdp++; + break; + default: + PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); errors = true; - } - cmdp += 2; - break; - case 'r': - case 'R': - rawkey = true; - cmdp++; - break; - default: - PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); - errors = true; - break; + break; + } + if (errors) { + usage_hf_iclass_readblock(); + return 0; } - if(errors) return usage_hf_iclass_readblock(); } - if (cmdp < 2) return usage_hf_iclass_readblock(); + if (cmdp < 2) { + usage_hf_iclass_readblock(); + return 0; + } if (!auth) PrintAndLog("warning: no authentication used with read, only a few specific blocks can be read accurately without authentication."); + return ReadBlock(KEY, blockno, keyType, elite, rawkey, true, auth); } -int CmdHFiClass_loclass(const char *Cmd) { + +static int CmdHFiClass_loclass(const char *Cmd) { char opt = param_getchar(Cmd, 0); if (strlen(Cmd)<1 || opt == 'h') { @@ -1297,49 +1397,22 @@ int CmdHFiClass_loclass(const char *Cmd) { return 0; } -void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize) { - 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 = 31; - //PrintAndLog ("endblock: %d, filesize: %d, maxmemcount: %d, filemaxblock: %d", endblock,filesize, maxmemcount, filemaxblock); - if (startblock == 0) - startblock = 6; - if ((endblock > maxmemcount) || (endblock == 0)) - endblock = maxmemcount; - - // remember endblock need to relate to zero-index arrays. - if (endblock > filemaxblock-1) - endblock = filemaxblock; - - int i = startblock; - printf("------+--+-------------------------+\n"); - while (i <= endblock) { - uint8_t *blk = iclass_dump + (i * 8); - printf("Block |%02X| %s|\n", i, sprint_hex(blk, 8) ); - i++; - } - printf("------+--+-------------------------+\n"); -} - -int usage_hf_iclass_readtagfile() { +static void usage_hf_iclass_readtagfile() { PrintAndLog("Usage: hf iclass readtagfile <filename> [startblock] [endblock]"); - return 1; } -int CmdHFiClassReadTagFile(const char *Cmd) { + +static 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, sizeof(filename)) < 1) - return usage_hf_iclass_readtagfile(); + if (param_getstr(Cmd, 0, filename, sizeof(filename)) < 1) { + usage_hf_iclass_readtagfile(); + return 0; + } if (param_getstr(Cmd, 1, tempnum, sizeof(tempnum)) < 1) startblock = 0; else @@ -1397,24 +1470,7 @@ uint64_t hexarray_to_uint64(uint8_t *key) { return uint_key; } */ -void HFiClassCalcDivKey(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key, bool elite){ - uint8_t keytable[128] = {0}; - uint8_t key_index[8] = {0}; - if (elite) { - uint8_t key_sel[8] = { 0 }; - uint8_t key_sel_p[8] = { 0 }; - hash2(KEY, keytable); - hash1(CSN, key_index); - for(uint8_t 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, div_key); - } else { - diversifyKey(CSN, KEY, div_key); - } -} //when told CSN, oldkey, newkey, if new key is elite (elite), and if old key was elite (oldElite) //calculate and return xor_div_key (ready for a key write command) @@ -1426,18 +1482,19 @@ static void HFiClassCalcNewKey(uint8_t *CSN, uint8_t *OLDKEY, uint8_t *NEWKEY, u HFiClassCalcDivKey(CSN, OLDKEY, old_div_key, oldElite); //get new div key HFiClassCalcDivKey(CSN, NEWKEY, new_div_key, elite); - + for (uint8_t i = 0; i < sizeof(old_div_key); i++){ xor_div_key[i] = old_div_key[i] ^ new_div_key[i]; } if (verbose) { printf("Old Div Key : %s\n",sprint_hex(old_div_key,8)); printf("New Div Key : %s\n",sprint_hex(new_div_key,8)); - printf("Xor Div Key : %s\n",sprint_hex(xor_div_key,8)); + printf("Xor Div Key : %s\n",sprint_hex(xor_div_key,8)); } } -int usage_hf_iclass_calc_newkey(void) { + +static void usage_hf_iclass_calc_newkey(void) { PrintAndLog("HELP : Manage iClass Keys in client memory:\n"); PrintAndLog("Usage: hf iclass calc_newkey o <Old key> n <New key> s [csn] e"); PrintAndLog(" Options:"); @@ -1451,16 +1508,14 @@ int usage_hf_iclass_calc_newkey(void) { PrintAndLog(" std key to e key read csn: hf iclass calcnewkey o 1122334455667788 n 2233445566778899 e"); PrintAndLog(" std to std read csn : hf iclass calcnewkey o 1122334455667788 n 2233445566778899"); PrintAndLog("NOTE: * = required\n"); - - return 1; } -int CmdHFiClassCalcNewKey(const char *Cmd) { + +static int CmdHFiClassCalcNewKey(const char *Cmd) { uint8_t OLDKEY[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; uint8_t NEWKEY[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; uint8_t xor_div_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 keyNbr = 0; uint8_t dataLen = 0; char tempStr[50] = {0}; @@ -1475,7 +1530,8 @@ int CmdHFiClassCalcNewKey(const char *Cmd) { { case 'h': case 'H': - return usage_hf_iclass_calc_newkey(); + usage_hf_iclass_calc_newkey(); + return 0; case 'e': case 'E': dataLen = param_getstr(Cmd, cmdp, tempStr, sizeof(tempStr)); @@ -1487,7 +1543,7 @@ int CmdHFiClassCalcNewKey(const char *Cmd) { case 'n': case 'N': dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr)); - if (dataLen == 16) { + if (dataLen == 16) { errors = param_gethex(tempStr, 0, NEWKEY, dataLen); } else if (dataLen == 1) { keyNbr = param_get8(Cmd, cmdp+1); @@ -1506,7 +1562,7 @@ int CmdHFiClassCalcNewKey(const char *Cmd) { case 'o': case 'O': dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr)); - if (dataLen == 16) { + if (dataLen == 16) { errors = param_gethex(tempStr, 0, OLDKEY, dataLen); } else if (dataLen == 1) { keyNbr = param_get8(Cmd, cmdp+1); @@ -1525,8 +1581,10 @@ int CmdHFiClassCalcNewKey(const char *Cmd) { case 's': case 'S': givenCSN = true; - if (param_gethex(Cmd, cmdp+1, CSN, 16)) - return usage_hf_iclass_calc_newkey(); + if (param_gethex(Cmd, cmdp+1, CSN, 16)) { + usage_hf_iclass_calc_newkey(); + return 0; + } cmdp += 2; break; default: @@ -1534,19 +1592,26 @@ int CmdHFiClassCalcNewKey(const char *Cmd) { errors = true; break; } - if(errors) return usage_hf_iclass_calc_newkey(); + if (errors) { + usage_hf_iclass_calc_newkey(); + return 0; + } } - if (cmdp < 4) return usage_hf_iclass_calc_newkey(); + if (cmdp < 4) { + usage_hf_iclass_calc_newkey(); + return 0; + } if (!givenCSN) - if (!select_only(CSN, CCNR, false, true)) + if (!select_only(CSN, true)) return 0; - + HFiClassCalcNewKey(CSN, OLDKEY, NEWKEY, xor_div_key, elite, oldElite, true); return 0; } + static int loadKeys(char *filename) { FILE *f; f = fopen(filename,"rb"); @@ -1582,6 +1647,7 @@ static int loadKeys(char *filename) { return 1; } + static int saveKeys(char *filename) { FILE *f; f = fopen(filename,"wb"); @@ -1599,16 +1665,18 @@ static int saveKeys(char *filename) { return 0; } + static int printKeys(void) { PrintAndLog(""); for (uint8_t i = 0; i < ICLASS_KEYS_MAX; i++){ PrintAndLog("%u: %s",i,sprint_hex(iClass_Key_Table[i],8)); } - PrintAndLog(""); + PrintAndLog(""); return 0; } -int usage_hf_iclass_managekeys(void) { + +static void usage_hf_iclass_managekeys(void) { 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:"); @@ -1623,10 +1691,10 @@ int usage_hf_iclass_managekeys(void) { 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 CmdHFiClassManageKeys(const char *Cmd) { + +static int CmdHFiClassManageKeys(const char *Cmd) { uint8_t keyNbr = 0; uint8_t dataLen = 0; uint8_t KEY[8] = {0}; @@ -1643,10 +1711,11 @@ int CmdHFiClassManageKeys(const char *Cmd) { { case 'h': case 'H': - return usage_hf_iclass_managekeys(); + usage_hf_iclass_managekeys(); + return 0; case 'f': case 'F': - fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); + fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); if (fileNameLen < 1) { PrintAndLog("No filename found after f"); errors = true; @@ -1664,7 +1733,7 @@ int CmdHFiClassManageKeys(const char *Cmd) { break; case 'k': case 'K': - operation += 3; //set key + operation += 3; //set key dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr)); if (dataLen == 16) { //ul-c or ev1/ntag key length errors = param_gethex(tempStr, 0, KEY, dataLen); @@ -1694,19 +1763,25 @@ int CmdHFiClassManageKeys(const char *Cmd) { errors = true; break; } - if(errors) return usage_hf_iclass_managekeys(); + if (errors) { + usage_hf_iclass_managekeys(); + return 0; + } } if (operation == 0){ PrintAndLog("no operation specified (load, save, or print)\n"); - return usage_hf_iclass_managekeys(); + usage_hf_iclass_managekeys(); + return 0; } if (operation > 6){ PrintAndLog("Too many operations specified\n"); - return usage_hf_iclass_managekeys(); + usage_hf_iclass_managekeys(); + return 0; } if (operation > 4 && fileNameLen == 0){ PrintAndLog("You must enter a filename when loading or saving\n"); - return usage_hf_iclass_managekeys(); + usage_hf_iclass_managekeys(); + return 0; } switch (operation){ @@ -1719,7 +1794,8 @@ int CmdHFiClassManageKeys(const char *Cmd) { return 0; } -int CmdHFiClassCheckKeys(const char *Cmd) { + +static int CmdHFiClassCheckKeys(const char *Cmd) { uint8_t mac[4] = {0x00,0x00,0x00,0x00}; uint8_t key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; @@ -1727,9 +1803,9 @@ int CmdHFiClassCheckKeys(const char *Cmd) { // elite key, raw key, standard key bool use_elite = false; - bool use_raw = false; + bool use_raw = false; bool found_debit = false; - bool found_credit = false; + bool found_credit = false; bool errors = false; uint8_t cmdp = 0x00; FILE * f; @@ -1743,10 +1819,11 @@ int CmdHFiClassCheckKeys(const char *Cmd) { switch (param_getchar(Cmd, cmdp)) { case 'h': case 'H': - return usage_hf_iclass_chk(); + usage_hf_iclass_chk(); + return 0; case 'f': case 'F': - fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); + fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); if (fileNameLen < 1) { PrintAndLog("No filename found after f"); errors = true; @@ -1769,8 +1846,11 @@ int CmdHFiClassCheckKeys(const char *Cmd) { break; } } - if (errors) return usage_hf_iclass_chk(); - + if (errors) { + usage_hf_iclass_chk(); + return 0; + } + if ( !(f = fopen( filename , "r")) ) { PrintAndLog("File: %s: not found or locked.", filename); return 1; @@ -1779,16 +1859,16 @@ int CmdHFiClassCheckKeys(const char *Cmd) { while( fgets(buf, sizeof(buf), f) ){ if (strlen(buf) < 16 || buf[15] == '\n') continue; - + while (fgetc(f) != '\n' && !feof(f)) ; //goto next line - - if( buf[0]=='#' ) continue; //The line start with # is comment, skip + + if( buf[0]=='#' ) continue; //The line start with # is comment, skip if (!isxdigit(buf[0])){ PrintAndLog("File content error. '%s' must include 16 HEX symbols",buf); continue; } - + buf[16] = 0; p = realloc(keyBlock, 8 * (keyitems += 64)); @@ -1809,19 +1889,19 @@ int CmdHFiClassCheckKeys(const char *Cmd) { } fclose(f); PrintAndLog("Loaded %2d keys from %s", keycnt, filename); - + // time uint64_t t1 = msclock(); - + for (uint32_t c = 0; c < keycnt; c += 1) { - printf("."); fflush(stdout); + printf("."); fflush(stdout); if (ukbhit()) { int gc = getchar(); (void)gc; printf("\naborted via keyboard!\n"); break; } - - memcpy(key, keyBlock + 8 * c , 8); + + memcpy(key, keyBlock + 8 * c , 8); // debit key. try twice for (int foo = 0; foo < 2 && !found_debit; foo++) { @@ -1833,18 +1913,18 @@ int CmdHFiClassCheckKeys(const char *Cmd) { PrintAndLog(" Found AA1 debit key\t\t[%s]", sprint_hex(key, 8)); found_debit = true; } - + // credit key. try twice for (int foo = 0; foo < 2 && !found_credit; foo++) { if (!select_and_auth(key, mac, div_key, true, use_elite, use_raw, false)) continue; - + // key found PrintAndLog("\n--------------------------------------------------------"); PrintAndLog(" Found AA2 credit key\t\t[%s]", sprint_hex(key, 8)); found_credit = true; } - + // both keys found. if ( found_debit && found_credit ) break; @@ -1853,45 +1933,108 @@ int CmdHFiClassCheckKeys(const char *Cmd) { t1 = msclock() - t1; PrintAndLog("\nTime in iclass checkkeys: %.0f seconds\n", (float)t1/1000.0); - + DropField(); free(keyBlock); PrintAndLog(""); return 0; } -static command_t CommandTable[] = -{ - {"help", CmdHelp, 1, "This help"}, - {"calcnewkey", CmdHFiClassCalcNewKey, 1, "[options..] Calc Diversified keys (blocks 3 & 4) to write new keys"}, - {"chk", CmdHFiClassCheckKeys, 0, " Check keys"}, - {"clone", CmdHFiClassCloneTag, 0, "[options..] Authenticate and Clone from iClass bin file"}, - {"decrypt", CmdHFiClassDecrypt, 1, "[f <fname>] Decrypt tagdump" }, - {"dump", CmdHFiClassReader_Dump, 0, "[options..] Authenticate and Dump iClass tag's AA1"}, - {"eload", CmdHFiClassELoad, 0, "[f <fname>] (experimental) Load data into iClass emulator memory"}, - {"encryptblk", CmdHFiClassEncryptBlk, 1, "<BlockData> Encrypt given block data"}, - {"list", CmdHFiClassList, 0, " (Deprecated) List iClass history"}, - {"loclass", CmdHFiClass_loclass, 1, "[options..] Use loclass to perform bruteforce of reader attack dump"}, - {"managekeys", CmdHFiClassManageKeys, 1, "[options..] Manage the keys to use with iClass"}, - {"readblk", CmdHFiClass_ReadBlock, 0, "[options..] Authenticate and Read iClass block"}, - {"reader", CmdHFiClassReader, 0, " Look for iClass tags until a key or the pm3 button is pressed"}, - {"readtagfile", CmdHFiClassReadTagFile, 1, "[options..] Display Content from tagfile"}, - {"replay", CmdHFiClassReader_Replay, 0, "<mac> Read an iClass tag via Reply Attack"}, - {"sim", CmdHFiClassSim, 0, "[options..] Simulate iClass tag"}, - {"snoop", CmdHFiClassSnoop, 0, " Eavesdrop iClass communication"}, - {"writeblk", CmdHFiClass_WriteBlock, 0, "[options..] Authenticate and Write iClass block"}, + +static void usage_hf_iclass_permutekey(void) { + PrintAndLogEx(NORMAL, "Convert keys from standard NIST to iClass format (and vice versa)"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: hf iclass permute [h] [r] <key>"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h This help"); + PrintAndLogEx(NORMAL, " r reverse convert key from iClass to NIST format"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " hf iclass permute r 0123456789abcdef"); +} + + +static int CmdHFiClassPermuteKey(const char *Cmd) { + + uint8_t key[8] = {0}; + uint8_t data[16] = {0}; + bool isReverse = false; + int len = sizeof(data); + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) == 0 || cmdp == 'h') { + usage_hf_iclass_permutekey(); + return 0; + } + + if (cmdp == 'r') { + isReverse = true; + param_gethex_ex(Cmd, 1, data, &len); + } else if (cmdp == 'f') { + param_gethex_ex(Cmd, 1, data, &len); + } else { + param_gethex_ex(Cmd, 0, data, &len); + } + + + if (len % 2) { + usage_hf_iclass_permutekey(); + return 0; + } + + len >>= 1; + + memcpy(key, data, 8); + + if (isReverse) { + // generate_rev(data, len); + uint8_t key_std_format[8] = {0}; + permutekey_rev(key, key_std_format); + PrintAndLogEx(SUCCESS, "key in standard NIST format: %s \n", sprint_hex(key_std_format, 8)); + // if (mbedtls_des_key_check_key_parity(key_std_format + } else { + // generate(data, len); + uint8_t key_iclass_format[8] = {0}; + permutekey(key, key_iclass_format); + PrintAndLogEx(SUCCESS, "key in iClass (permuted) format: %s \n", sprint_hex(key_iclass_format, 8)); + } + return 0; +} + + +static int CmdHelp(const char *Cmd); + +static command_t CommandTable[] = { + {"help", CmdHelp, 1, "This help"}, + {"calcnewkey", CmdHFiClassCalcNewKey, 1, "[options..] Calc Diversified keys (blocks 3 & 4) to write new keys"}, + {"chk", CmdHFiClassCheckKeys, 0, " Check keys"}, + {"clone", CmdHFiClassCloneTag, 0, "[options..] Authenticate and Clone from iClass bin file"}, + {"decrypt", CmdHFiClassDecrypt, 1, "[f <fname>] Decrypt tagdump" }, + {"dump", CmdHFiClassReader_Dump, 0, "[options..] Authenticate and Dump iClass tag's AA1"}, + {"eload", CmdHFiClassELoad, 0, "[f <fname>] (experimental) Load data into iClass emulator memory"}, + {"encryptblk", CmdHFiClassEncryptBlk, 1, "<BlockData> Encrypt given block data"}, + {"list", CmdHFiClassList, 0, " (Deprecated) List iClass history"}, + {"loclass", CmdHFiClass_loclass, 1, "[options..] Use loclass to perform bruteforce of reader attack dump"}, + {"managekeys", CmdHFiClassManageKeys, 1, "[options..] Manage the keys to use with iClass"}, + {"permutekey", CmdHFiClassPermuteKey, 1, " iClass key permutation"}, + {"readblk", CmdHFiClass_ReadBlock, 0, "[options..] Authenticate and Read iClass block"}, + {"reader", CmdHFiClassReader, 0, " Look for iClass tags until a key or the pm3 button is pressed"}, + {"readtagfile", CmdHFiClassReadTagFile, 1, "[options..] Display Content from tagfile"}, + {"replay", CmdHFiClassReader_Replay, 0, "<mac> Read an iClass tag via Reply Attack"}, + {"sim", CmdHFiClassSim, 0, "[options..] Simulate iClass tag"}, + {"snoop", CmdHFiClassSnoop, 0, " Eavesdrop iClass communication"}, + {"writeblk", CmdHFiClass_WriteBlock, 0, "[options..] Authenticate and Write iClass block"}, {NULL, NULL, 0, NULL} }; -int CmdHFiClass(const char *Cmd) -{ - clearCommandBuffer(); + +int CmdHFiClass(const char *Cmd) { + clearCommandBuffer(); CmdsParse(CommandTable, Cmd); return 0; } -int CmdHelp(const char *Cmd) -{ + +int CmdHelp(const char *Cmd) { CmdsHelp(CommandTable); return 0; } diff --git a/client/cmdhficlass.h b/client/cmdhficlass.h index 456bb1c3..09103b33 100644 --- a/client/cmdhficlass.h +++ b/client/cmdhficlass.h @@ -13,28 +13,6 @@ #define CMDHFICLASS_H__ int CmdHFiClass(const char *Cmd); - -int CmdHFiClassCalcNewKey(const char *Cmd); -int CmdHFiClassCloneTag(const char *Cmd); -int CmdHFiClassDecrypt(const char *Cmd); -int CmdHFiClassEncryptBlk(const char *Cmd); -int CmdHFiClassELoad(const char *Cmd); -int CmdHFiClassList(const char *Cmd); int HFiClassReader(const char *Cmd, bool loop, bool verbose); -int CmdHFiClassReader(const char *Cmd); -int CmdHFiClassReader_Dump(const char *Cmd); -int CmdHFiClassReader_Replay(const char *Cmd); -int CmdHFiClassReadKeyFile(const char *filename); -int CmdHFiClassReadTagFile(const char *Cmd); -int CmdHFiClass_ReadBlock(const char *Cmd); -int CmdHFiClass_TestMac(const char *Cmd); -int CmdHFiClassManageKeys(const char *Cmd); -int CmdHFiClass_loclass(const char *Cmd); -int CmdHFiClassSnoop(const char *Cmd); -int CmdHFiClassSim(const char *Cmd); -int CmdHFiClassWriteKeyFile(const char *Cmd); -int CmdHFiClass_WriteBlock(const char *Cmd); -int CmdHFiClassCheckKeys(const char *Cmd); -void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize); -void HFiClassCalcDivKey(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key, bool elite); + #endif diff --git a/client/loclass/elite_crack.h b/client/loclass/elite_crack.h index 46791fb5..c44f5105 100644 --- a/client/loclass/elite_crack.h +++ b/client/loclass/elite_crack.h @@ -85,7 +85,7 @@ typedef struct { uint8_t cc_nr[12]; uint8_t mac[4]; -}dumpdata; +} dumpdata; /** * @brief Performs brute force attack against a dump-data item, containing csn, cc_nr and mac. diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 0802d2f1..75b7c210 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -165,7 +165,8 @@ typedef struct{ #define CMD_ICLASS_READBLOCK 0x0396 #define CMD_ICLASS_WRITEBLOCK 0x0397 #define CMD_ICLASS_EML_MEMSET 0x0398 -#define CMD_ICLASS_AUTHENTICATION 0x0399 +#define CMD_ICLASS_CHECK 0x0399 +#define CMD_ICLASS_READCHECK 0x039A // For measurements of the antenna tuning #define CMD_MEASURE_ANTENNA_TUNING 0x0400 @@ -236,13 +237,11 @@ typedef struct{ // iCLASS reader flags -#define FLAG_ICLASS_READER_ONLY_ONCE 0x01 #define FLAG_ICLASS_READER_CC 0x02 #define FLAG_ICLASS_READER_CSN 0x04 #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 +#define FLAG_ICLASS_READER_CREDITKEY 0x40 // iCLASS simulation modes #define ICLASS_SIM_MODE_CSN 0