mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 21:33:47 -07:00
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:
parent
c2725bfa99
commit
5eafdbf872
6 changed files with 329 additions and 167 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
249
armsrc/iclass.c
249
armsrc/iclass.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue