ADD: 'hf iclass check' - increased speed in check keys with new algo.

ADD: 'hf iclass' - trying to add the timeout-limits for commands in order to get a more stable iclass communication
This commit is contained in:
iceman1001 2017-12-21 10:13:40 +01:00
commit 5eafdbf872
6 changed files with 329 additions and 167 deletions

View file

@ -946,6 +946,9 @@ void UsbPacketReceived(uint8_t *packet, int len) {
case CMD_ICLASS_AUTHENTICATION: //check
iClass_Authentication(c->d.asBytes);
break;
case CMD_ICLASS_CHECK_KEYS:
iClass_Authentication_fast(c->arg[0], c->arg[1], c->d.asBytes);
break;
case CMD_ICLASS_DUMP:
iClass_Dump(c->arg[0], c->arg[1]);
break;

View file

@ -208,12 +208,13 @@ 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_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain);
void iClass_WriteBlock(uint8_t blockNo, uint8_t *data);
void iClass_ReadBlk(uint8_t blockNo);
bool iClass_ReadBlock(uint8_t blockNo, uint8_t *readdata);
void iClass_Dump(uint8_t blockno, uint8_t numblks);
void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data);
void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType);
void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType);
// hitag2.h
void SnoopHitag(uint32_t type);

View file

@ -48,7 +48,7 @@
#include "usb_cdc.h" // for usb_poll_validate_length
static int timeout = 4096;
static int SendIClassAnswer(uint8_t *resp, int respLen, int delay);
static int SendIClassAnswer(uint8_t *resp, int respLen, uint16_t delay);
#define MODE_SIM_CSN 0
#define MODE_EXIT_AFTER_MAC 1
@ -863,6 +863,7 @@ void rotateCSN(uint8_t* originalCSN, uint8_t* rotatedCSN) {
}
//-----------------------------------------------------------------------------
// SIMULATION
// Wait for commands from reader
// Stop when button is pressed
// Or return TRUE when command is captured
@ -1276,33 +1277,28 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) {
StartCountSspClk();
// To control where we are in the protocol
int cmdsRecvd = 0;
uint32_t time_0 = GetCountSspClk();
uint32_t t2r_time = 0, r2t_time = 0;
uint32_t t2r_stime = 0, t2r_etime = 0;
uint32_t r2t_stime = 0, r2t_etime = 0;
LED_A_ON();
bool buttonPressed = false;
uint8_t response_delay = 1;
uint16_t response_delay = 1;
while (!exitLoop) {
WDT_HIT();
response_delay = 200;
// receivedCmd[0] = 0; receivedCmd[1] = 0; receivedCmd[2] = 0; receivedCmd[3] = 0;
// receivedCmd[4] = 0; receivedCmd[5] = 0; receivedCmd[6] = 0; receivedCmd[7] = 0;
// receivedCmd[8] = 0; receivedCmd[9] = 0; receivedCmd[10] = 0; receivedCmd[11] = 0;
// receivedCmd[12] = 0;receivedCmd[13] = 0;receivedCmd[14] = 0; receivedCmd[15] = 0;
//Signal tracer, can be used to get a trigger for an oscilloscope..
LED_B_OFF(); LED_C_OFF();
r2t_stime = (GetCountSspClk() - time_0) << 4;
if (!GetIClassCommandFromReader(receivedCmd, &len, 0)) {
buttonPressed = true;
exitLoop = true;
continue;
}
r2t_etime = ((GetCountSspClk() - time_0) << 4 ) - r2t_stime;
r2t_time = GetCountSspClk();
response_delay = 330;
LED_C_ON(); //Signal tracer
@ -1311,6 +1307,7 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) {
modulated_response = resp_sof; modulated_response_size = resp_sof_Len; //order = 1;
trace_data = sof_data;
trace_data_size = sizeof(sof_data);
response_delay = 330+160;
} else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 1) { // 0x0C
// Reader asks for anticollission CSN
modulated_response = resp_anticoll; modulated_response_size = resp_anticoll_len; //order = 2;
@ -1332,7 +1329,7 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) {
// Reader random and reader MAC!!!
if (simulationMode == MODE_FULLSIM) {
//NR, from reader, is in receivedCmd +1
opt_doTagMAC_2(cipher_state,receivedCmd+1,data_generic_trace,diversified_key);
opt_doTagMAC_2(cipher_state, receivedCmd+1, data_generic_trace, diversified_key);
trace_data = data_generic_trace;
trace_data_size = 4;
@ -1418,15 +1415,18 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) {
//receivedcmd is now UPDATE 1b | ADDRESS 1b| DATA 8b| Signature 4b or CRC 2b|
//Take the data...
memcpy(data_generic_trace, receivedCmd+2,8);
memcpy(data_generic_trace, receivedCmd+2, 8);
//Add crc
AppendCrc(data_generic_trace, 8);
trace_data = data_generic_trace;
trace_data_size = 10;
CodeIClassTagAnswer(trace_data , trace_data_size);
CodeIClassTagAnswer(trace_data, trace_data_size);
memcpy(data_response, ToSend, ToSendMax);
modulated_response = data_response;
modulated_response_size = ToSendMax;
response_delay = 4000; // tPROG 4-15ms
// } else if(receivedCmd[0] == ICLASS_CMD_PAGESEL) { // 0x84
//Pagesel
//Pagesel enables to select a page in the selected chip memory and return its configuration block
@ -1452,22 +1452,19 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) {
trace_data_size = 0;
}
cmdsRecvd++;
/**
A legit tag has about 380us delay between reader EOT and tag SOF.
A legit tag has about 330us delay between reader EOT and tag SOF.
**/
if (modulated_response_size > 0) {
t2r_stime = (GetCountSspClk() - time_0) << 4;
SendIClassAnswer(modulated_response, modulated_response_size, response_delay);
t2r_time = (GetCountSspClk() - time_0) << 4;
t2r_etime = ((GetCountSspClk() - time_0) << 4 ) - t2r_stime;
}
LogTrace(receivedCmd, len, (r2t_time - time_0)<< 4, (r2t_time - time_0) << 4, NULL, true);
LogTrace(receivedCmd, len, r2t_stime, r2t_etime, NULL, true);
if (trace_data != NULL) {
LogTrace(trace_data, trace_data_size, t2r_time, t2r_time, NULL, false);
if ( MF_DBGLEVEL == MF_DBG_EXTENDED) DbpString("trace written");
}
if (trace_data != NULL)
LogTrace(trace_data, trace_data_size, t2r_stime, t2r_etime, NULL, false);
}
LEDsoff();
@ -1484,13 +1481,14 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) {
* @param respLen
* @param delay
*/
static int SendIClassAnswer(uint8_t *resp, int respLen, int delay) {
int i = 0, d = 0;
static int SendIClassAnswer(uint8_t *resp, int respLen, uint16_t delay) {
int i = 0; // d = 0;
uint8_t b = 0;
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K_8BIT);
AT91C_BASE_SSC->SSC_THR = 0x00;
//FpgaSetupSsc();
SpinDelayUs(delay); // So, first make sure we timeout previous comms.
while (!BUTTON_PRESS()) {
if ( (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)){
@ -1498,16 +1496,12 @@ static int SendIClassAnswer(uint8_t *resp, int respLen, int delay) {
}
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)){
b = 0x00;
if (d < delay) {
d++;
} else {
if ( i < respLen){
b = resp[i];
//Hack
//b = 0xAC;
}
i++;
if ( i < respLen){
b = resp[i];
//Hack
//b = 0xAC;
}
i++;
AT91C_BASE_SSC->SSC_THR = b;
}
// if (i > respLen + 4) break;
@ -1523,33 +1517,17 @@ static int SendIClassAnswer(uint8_t *resp, int respLen, int delay) {
//-----------------------------------------------------------------------------
static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int *wait) {
int c;
int c = 0;
volatile uint32_t r;
bool firstpart = true;
uint8_t sendbyte;
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
AT91C_BASE_SSC->SSC_THR = 0x00;
//SpinDelay(100);
if (wait) {
if (*wait < 10) *wait = 10;
for (c = 0; c < *wait;) {
WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing!
c++;
}
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
r = AT91C_BASE_SSC->SSC_RHR; (void)r;
}
}
}
c = 0;
// make sure we timeout previous comms.
if ( *wait )
SpinDelayUs(*wait);
for (;;) {
@ -1627,9 +1605,9 @@ void CodeIClassCommand(const uint8_t* cmd, int len) {
ToSendMax++;
}
void ReaderTransmitIClass(uint8_t* frame, int len) {
void ReaderTransmitIClass_ext(uint8_t* frame, int len, int wait) {
int wait = 0, samples = 0;
int samples = 0;
// This is tied to other size changes
CodeIClassCommand(frame, len);
@ -1639,12 +1617,13 @@ void ReaderTransmitIClass(uint8_t* frame, int len) {
if (trigger)
LED_A_ON();
// Store reader command in buffer
//uint8_t par[len/8];
//GetParity(frame, len, par);
//LogTrace(frame, len, rsamples, rsamples, par, true);
rsamples += samples;
LogTrace(frame, len, rsamples, rsamples, NULL, true);
}
void ReaderTransmitIClass(uint8_t* frame, int len) {
ReaderTransmitIClass_ext(frame, len, 330);
}
//-----------------------------------------------------------------------------
// Wait a certain time for tag response
@ -1666,6 +1645,7 @@ static int GetIClassAnswer(uint8_t* receivedResponse, int maxLen, int *samples,
// Set FPGA mode to "reader listen mode", no modulation (listen
// only, since we are receiving, not transmitting).
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_LISTEN);
SpinDelayUs(330); //310 Tout= 330us (iso15603-2) (330/21.3) take consideration for clock increments.
// clear RXRDY:
uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
@ -1692,7 +1672,7 @@ static int GetIClassAnswer(uint8_t* receivedResponse, int maxLen, int *samples,
if (ManchesterDecoding(b & 0x0f)) {
if (samples)
*samples = c << 3;
return true;
return true;
}
}
}
@ -1711,6 +1691,7 @@ int ReaderReceiveIClass(uint8_t* receivedAnswer) {
if (samples == 0)
return false;
return Demod.len;
}
@ -1735,7 +1716,7 @@ void setupIclassReader() {
// 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);
SpinDelay(300);
// Start the timer
StartCountSspClk();
@ -1776,7 +1757,7 @@ uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) {
uint8_t read_status = 0;
// Send act_all
ReaderTransmitIClass(act_all, 1);
ReaderTransmitIClass_ext(act_all, 1, 330+160);
// Card present?
if (!ReaderReceiveIClass(resp)) return read_status;//Fail
@ -1790,8 +1771,10 @@ uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) {
//Copy the Anti-collision CSN to our select-packet
memcpy(&select[1], resp, 8);
//Select the card
ReaderTransmitIClass(select, sizeof(select));
//We expect a 10-byte response here, 8 byte CSN and 2 byte CRC
len = ReaderReceiveIClass(resp);
if (len != 10) return read_status;//Fail
@ -1803,7 +1786,7 @@ uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) {
//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)
// Card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC)
ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
if (ReaderReceiveIClass(resp) == 8) {
//Save CC (e-purse) in response data
@ -1846,7 +1829,7 @@ void ReaderIClass(uint8_t arg0) {
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;
//uint8_t flagReadCC = arg0 & FLAG_ICLASS_READER_CC;
uint8_t flagReadAA = arg0 & FLAG_ICLASS_READER_AA;
setupIclassReader();
@ -1861,6 +1844,7 @@ void ReaderIClass(uint8_t arg0) {
if (try_once && tryCnt > 2) break;
tryCnt++;
result_status = 0;
read_status = handshakeIclassTag_ext(card_data, use_credit_key);
@ -1879,7 +1863,7 @@ void ReaderIClass(uint8_t arg0) {
result_status |= FLAG_ICLASS_READER_CONF;
memcpy(card_data+8, resp, 8);
} else {
DbpString("Failed to dump config block");
if (MF_DBGLEVEL > 1) DbpString("Failed to dump config block");
}
}
@ -1889,7 +1873,7 @@ void ReaderIClass(uint8_t arg0) {
result_status |= FLAG_ICLASS_READER_AA;
memcpy(card_data+(8*5), resp, 8);
} else {
//DbpString("Failed to dump AA block");
if (MF_DBGLEVEL > 1) DbpString("Failed to dump AA block");
}
}
@ -1899,7 +1883,7 @@ void ReaderIClass(uint8_t arg0) {
// (3,4 write-only, kc and kd)
// 5 Application issuer area
//
//Then we can 'ship' back the 8 * 5 bytes of data,
//Then we can 'ship' back the 6 * 8 bytes of data,
// with 0xFF:s in block 3 and 4.
LED_B_ON();
@ -1907,11 +1891,12 @@ void ReaderIClass(uint8_t arg0) {
// 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) {
if ( (result_status ^ FLAG_ICLASS_READER_CSN ^ FLAG_ICLASS_READER_CONF ^ FLAG_ICLASS_READER_CC ^ FLAG_ICLASS_READER_AA) == 0) {
cmd_send(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data) );
if (abort_after_read)
goto out;
if (abort_after_read) {
LED_B_OFF();
return;
}
//Save that we already sent this....
memcpy(last_csn, card_data, 8);
}
@ -1919,14 +1904,13 @@ void ReaderIClass(uint8_t arg0) {
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);
out:
if ( abort_after_read )
if (userCancelled) {
cmd_send(CMD_ACK, 0xFF, 0, 0, card_data, 0);
switch_off();
} else {
cmd_send(CMD_ACK, 0, 0, 0, card_data, 0);
}
}
// turn off afterwards
@ -2061,8 +2045,9 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) {
switch_off();
}
// not used. ?!? ( CMD_ICLASS_READCHECK)
// turn off afterwards
void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType) {
void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType) {
uint8_t readcheck[] = { keyType, blockNo };
uint8_t resp[] = {0,0,0,0,0,0,0,0};
size_t isOK = 0;
@ -2073,16 +2058,109 @@ void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType) {
// used with function select_and_auth (cmdhficlass.c)
// which needs to authenticate before doing more things like read/write
void iClass_Authentication(uint8_t *MAC) {
void iClass_Authentication(uint8_t *mac) {
uint8_t check[] = { ICLASS_CMD_CHECK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t resp[ICLASS_BUFFER_SIZE];
memcpy(check+5, MAC, 4);
memcpy(check+5, mac, 4);
// 6 retries
bool isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, 4, 6);
cmd_send(CMD_ACK,isOK,0,0,0,0);
}
typedef struct iclass_precalc {
//uint8_t key[8];
uint8_t mac[4];
} iclass_precalc_t;
/* this function works on the following assumptions.
* - one select first, to get CSN / CC (e-purse)
* - calculate before diversified keys and precalc mac based on CSN/KEY.
* - data in contains of diversified keys, mac
* - key loop only test one type of authtication key. Ie two calls needed
* to cover debit and credit key. (AA1/AA2)
*/
void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) {
uint8_t i = 0, isOK = 0;
uint8_t lastChunk = ((arg0 >> 8) & 0xFF);
bool use_credit_key =((arg0 >> 16) & 0xFF);
uint8_t keyCount = arg1 & 0xFF;
uint8_t check[] = { ICLASS_CMD_CHECK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t resp[ICLASS_BUFFER_SIZE];
uint8_t readcheck_cc[] = { ICLASS_CMD_READCHECK_KD, 0x02 };
if (use_credit_key)
readcheck_cc[0] = ICLASS_CMD_READCHECK_KC;
// select card / e-purse
uint8_t card_data[6 * 8] = {0};
iclass_precalc_t *keys = (iclass_precalc_t *)datain;
LED_A_ON();
setupIclassReader();
int read_status = 0;
uint8_t startup_limit = 10;
while ( read_status != 2) {
if (BUTTON_PRESS() && !usb_poll_validate_length()) goto out;
read_status = handshakeIclassTag_ext(card_data, use_credit_key);
if ( startup_limit-- == 0 ) {
Dbprintf("Handshake status | %d (fail 10)", read_status);
isOK = 99;
goto out;
}
};
// Keychunk loop
for (i = 0; i < keyCount; i++) {
LED_C_INV();
// Allow button press / usb cmd to interrupt device
if (BUTTON_PRESS() && !usb_poll_validate_length()) break;
WDT_HIT();
LED_B_ON();
// Auth Sequence MUST begin with reading e-purse. (block2)
// Card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC)
ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
if (ReaderReceiveIClass(resp) == 8) {
}
LED_B_OFF();
// copy MAC to check command (readersignature)
check[5] = keys[i].mac[0];
check[6] = keys[i].mac[1];
check[7] = keys[i].mac[2];
check[8] = keys[i].mac[3];
// expect 4bytes, 3 retries times..
isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, 4, 2);
if ( isOK )
goto out;
SpinDelayUs(350); //iClass (iso15693-2) should timeout after 330us.
}
out:
// send keyindex.
cmd_send(CMD_ACK, isOK, i, 0, 0, 0);
if ( isOK >= 1 || lastChunk ) {
switch_off();
LED_A_OFF();
}
LED_B_OFF();
LED_C_OFF();
}
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;
@ -2151,13 +2229,12 @@ bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) {
bool isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 10);
if (isOK) { //if reader responded correctly
//Dbprintf("WriteResp: %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 response is not equal to write values
if (memcmp(write + 2, resp, 8)) {
//if not programming key areas (note key blocks don't get programmed with actual key data it is xor data)
//if not programming key areas (note key blocks don't get programmed with actual key data it is xor data)
if (blockNo != 3 && blockNo != 4) {
//error try again
isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 10);
}
}

View file

@ -32,6 +32,11 @@ typedef struct iclass_block {
uint8_t d[8];
} iclass_block_t;
typedef struct iclass_precalc {
// uint8_t key[8];
uint8_t mac[4];
} iclass_precalc_t;
int usage_hf_iclass_sim(void) {
PrintAndLog("Usage: hf iclass sim <option> [CSN]");
PrintAndLog(" options");
@ -769,7 +774,7 @@ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool v
clearCommandBuffer();
SendCommand(&c);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
PrintAndLog("Command execute timeout");
return false;
}
@ -782,9 +787,9 @@ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool v
if (CCNR != NULL)
memcpy(CCNR, data+16, 8);
if (isOK > 0) {
if (verbose) PrintAndLog("CSN: %s",sprint_hex(CSN,8));
}
// if (isOK > 0) {
// if (verbose) PrintAndLog("CSN: %s",sprint_hex(CSN,8));
// }
if (isOK <= 1){
PrintAndLog("Failed to obtain CC! Aborting...");
@ -810,15 +815,15 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u
doMAC(CCNR, div_key, MAC);
UsbCommand resp;
UsbCommand d = {CMD_ICLASS_AUTHENTICATION, {0}};
UsbCommand d = {CMD_ICLASS_AUTHENTICATION, {0,0,0}};
memcpy(d.d.asBytes, MAC, 4);
clearCommandBuffer();
SendCommand(&d);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
if (verbose) PrintAndLog("Auth Command execute timeout");
return false;
}
uint8_t isOK = resp.arg[0] & 0xff;
uint8_t isOK = resp.arg[0] & 0xFF;
if (!isOK) {
if (verbose) PrintAndLog("Authentication error");
return false;
@ -1097,7 +1102,7 @@ int CmdHFiClass_WriteBlock(const char *Cmd) {
char tempStr[50] = {0};
bool use_credit_key = false;
bool elite = false;
bool rawkey= false;
bool rawkey = false;
bool errors = false;
uint8_t cmdp = 0;
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
@ -1120,9 +1125,8 @@ int CmdHFiClass_WriteBlock(const char *Cmd) {
break;
case 'd':
case 'D':
if (param_gethex(Cmd, cmdp+1, bldata, 16))
{
PrintAndLog("KEY must include 16 HEX symbols\n");
if (param_gethex(Cmd, cmdp+1, bldata, 16)) {
PrintAndLog("Data must include 16 HEX symbols\n");
errors = true;
}
cmdp += 2;
@ -1330,20 +1334,20 @@ static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite,
// block 0,1 should always be able to read, and block 5 on some cards.
if (auth || blockno >= 2) {
if (!select_and_auth(KEY, MAC, div_key, (keyType==0x18), elite, rawkey, verbose))
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] = {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))
return 0;
}
UsbCommand resp;
UsbCommand w = {CMD_ICLASS_READBLOCK, {blockno}};
UsbCommand c = {CMD_ICLASS_READBLOCK, {blockno}};
clearCommandBuffer();
SendCommand(&w);
if (!WaitForResponseTimeout(CMD_ACK,&resp,4500)) {
SendCommand(&c);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
PrintAndLog("Command execute timeout");
return 0;
}
@ -1354,12 +1358,12 @@ static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite,
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));
PrintAndLog("Block %02X: %s\n", blockno, sprint_hex(resp.d.asBytes, 8));
return 1;
}
int CmdHFiClass_ReadBlock(const char *Cmd) {
uint8_t blockno=0;
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;
@ -1370,8 +1374,8 @@ int CmdHFiClass_ReadBlock(const char *Cmd) {
bool errors = false;
bool auth = false;
uint8_t cmdp = 0;
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch(param_getchar(Cmd, cmdp)) {
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (param_getchar(Cmd, cmdp)) {
case 'h':
case 'H':
return usage_hf_iclass_readblock();
@ -1426,10 +1430,9 @@ int CmdHFiClass_ReadBlock(const char *Cmd) {
}
if (errors || cmdp < 4) return usage_hf_iclass_readblock();
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);
return ReadBlock(KEY, blockno, keyType, elite, rawkey, false, auth);
}
int CmdHFiClass_loclass(const char *Cmd) {
@ -1539,7 +1542,7 @@ int CmdHFiClassReadTagFile(const char *Cmd) {
return 0;
}
void HFiClassCalcDivKey(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key, bool elite){
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) {
@ -1821,16 +1824,18 @@ int CmdHFiClassManageKeys(const char *Cmd) {
int CmdHFiClassCheckKeys(const char *Cmd) {
uint8_t mac[4] = {0x00,0x00,0x00,0x00};
//uint8_t mac[4] = {0x00,0x00,0x00,0x00};
uint8_t key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t 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};
// elite key, raw key, standard key
bool use_elite = false;
bool use_raw = false;
bool found_debit = false;
bool found_credit = false;
bool got_csn = false;
bool errors = false;
uint8_t cmdp = 0x00;
FILE * f;
@ -1838,8 +1843,12 @@ int CmdHFiClassCheckKeys(const char *Cmd) {
uint8_t fileNameLen = 0;
char buf[17];
uint8_t *keyBlock = NULL, *p;
iclass_precalc_t *pre = NULL;
int keyitems = 0, keycnt = 0;
// time
uint64_t t1 = msclock();
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (param_getchar(Cmd, cmdp)) {
case 'h':
@ -1903,59 +1912,133 @@ int CmdHFiClassCheckKeys(const char *Cmd) {
memset(keyBlock + 8 * keycnt, 0, 8);
num_to_bytes(strtoull(buf, NULL, 16), 8, keyBlock + 8 * keycnt);
PrintAndLog("check key[%2d] %016" PRIx64, keycnt, bytes_to_num(keyBlock + 8*keycnt, 8));
keycnt++;
memset(buf, 0, sizeof(buf));
}
fclose(f);
PrintAndLog("Loaded %2d keys from %s", keycnt, filename);
PrintAndLog("[+] Loaded %2d keys from %s", keycnt, filename);
// time
uint64_t t1 = msclock();
// // Get CSN / UID and CCNR
for (uint8_t i=0; i<10 && !got_csn; i++) {
if (select_only(CSN, CCNR, false, false)) {
got_csn = true;
}
}
DropField();
for (uint32_t c = 0; c < keycnt; c += 1) {
printf("."); fflush(stdout);
if (ukbhit()) {
int gc = getchar(); (void)gc;
printf("\naborted via keyboard!\n");
break;
}
memcpy(key, keyBlock + 8 * c , 8);
// debit key. try twice
for (int foo = 0; foo < 2 && !found_debit; foo++) {
if (!select_and_auth(key, mac, div_key, false, use_elite, use_raw, false))
continue;
// key found.
PrintAndLog("\n--------------------------------------------------------");
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;
if ( !got_csn ) {
PrintAndLog("Can't select card, aborting...");
free(keyBlock);
return 1;
}
pre = calloc(keycnt, sizeof(iclass_precalc_t));
if ( !pre ) {
free(keyBlock);
return 1;
}
// precalc diversified keys
PrintAndLog("#key | key | mac");
PrintAndLog("-----+------------------+---------");
for ( int m=0; m < keycnt; m++) {
memcpy(key, keyBlock + 8 * m , 8);
if (use_raw)
memcpy(div_key, key, 8);
else
HFiClassCalcDivKey(CSN, key, div_key, use_elite);
doMAC(CCNR, div_key, pre[m].mac);
if (m < 10 ) {
PrintAndLog("[%2d] | %016" PRIx64 " | %08" PRIx32,
m,
bytes_to_num(key, 8),
bytes_to_num( pre[m].mac, 4) );
} else if ( m == 10 ) {
PrintAndLog("... skip printing the rest");
}
}
// max 42 keys inside USB_COMMAND. 512/4 = 103 mac
uint32_t chunksize = keycnt > (USB_CMD_DATA_SIZE/4) ? (USB_CMD_DATA_SIZE/4) : keycnt;
bool lastChunk = false;
// main keychunk loop
for (uint32_t i = 0; i < keycnt; i += chunksize) {
uint64_t t2 = msclock();
uint32_t timeout = 0;
if (ukbhit()) {
int gc = getchar(); (void)gc;
printf("\naborted via keyboard!\n");
goto out;
}
uint32_t keys = ((keycnt - i) > chunksize) ? chunksize : keycnt - i;
// last chunk?
if ( keys == keycnt - i)
lastChunk = true;
UsbCommand c = {CMD_ICLASS_CHECK_KEYS, { (lastChunk << 8), keys, 0}};
memcpy(c.d.asBytes, pre, 4 * keys);
clearCommandBuffer();
SendCommand(&c);
UsbCommand resp;
while ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) {
timeout++;
printf(".");
fflush(stdout);
if (timeout > 120) {
PrintAndLog("\nNo response from Proxmark. Aborting...");
goto out;
}
}
uint8_t found = resp.arg[1] & 0xFF;
uint8_t isOK = resp.arg[0] & 0xFF;
t2 = msclock() - t2;
switch ( isOK ) {
case 1: {
found_debit = true;
PrintAndLog("\n[-] Chunk: %.1fs [debit] found key %s (index %u)"
, (float)(t2/1000.0)
, sprint_hex(keyBlock + (i+found)*8, 8)
, found
);
break;
}
case 0: {
PrintAndLog("\n[-] Chunk: %.1fs [debit]", (float)(t2/1000.0));
break;
}
case 99: {
}
default: break;
}
// both keys found.
if ( found_debit && found_credit ) {
PrintAndLog("[+] All keys found, exiting");
break;
}
} // end chunks of keys
out:
t1 = msclock() - t1;
PrintAndLog("\nTime in iclass checkkeys: %.0f seconds\n", (float)t1/1000.0);
DropField();
free(pre);
free(keyBlock);
PrintAndLog("");
return 0;

View file

@ -29,7 +29,6 @@
* @file cmd.c
* @brief
*/
#include "cmd.h"
// (iceman 2017) this method is not used anymore. uart_win32 /uart_posix is used instead
@ -79,5 +78,3 @@ bool cmd_send(uint32_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* d
return true;
}

View file

@ -166,6 +166,7 @@ typedef struct{
#define CMD_ICLASS_WRITEBLOCK 0x0397
#define CMD_ICLASS_EML_MEMSET 0x0398
#define CMD_ICLASS_AUTHENTICATION 0x0399
#define CMD_ICLASS_CHECK_KEYS 0x039A
// For ISO1092 / FeliCa
#define CMD_FELICA_SIMULATE_TAG 0x03A0