fpga merge changes

This commit is contained in:
iceman1001 2020-07-06 15:16:00 +02:00
commit d83a45f0cb
6 changed files with 180 additions and 154 deletions

View file

@ -336,7 +336,7 @@ static void BuildFliteRdblk(uint8_t *idm, int blocknum, uint16_t *blocks) {
} }
static void TransmitFor18092_AsReader(uint8_t *frame, int len, uint32_t *timing, uint8_t power, uint8_t highspeed) { static void TransmitFor18092_AsReader(uint8_t *frame, int len, uint32_t *timing, uint8_t power, uint8_t highspeed) {
uint8_t flags = FPGA_MAJOR_MODE_HF_ISO18092; uint16_t flags = FPGA_MAJOR_MODE_HF_ISO18092;
if (power) if (power)
flags |= FPGA_HF_ISO18092_FLAG_READER; flags |= FPGA_HF_ISO18092_FLAG_READER;
if (highspeed) if (highspeed)

View file

@ -41,12 +41,12 @@ int HfSniff(uint32_t samplesToSkip, uint32_t triggersToSkip, uint16_t *len) {
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Set up the synchronous serial port // Set up the synchronous serial port
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SNIFF);
// Setting Frame Mode For better performance on high speed data transfer. // Setting Frame Mode For better performance on high speed data transfer.
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16); AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNOOP); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNIFF);
SpinDelay(100); SpinDelay(100);
*len = (BigBuf_max_traceLen() & 0xFFFE); *len = (BigBuf_max_traceLen() & 0xFFFE);

View file

@ -3,6 +3,7 @@
// Hagen Fritsch - June 2010 // Hagen Fritsch - June 2010
// Gerhard de Koning Gans - May 2011 // Gerhard de Koning Gans - May 2011
// Gerhard de Koning Gans - June 2012 - Added iClass card and reader emulation // Gerhard de Koning Gans - June 2012 - Added iClass card and reader emulation
// piwi - 2019
// //
// This code is licensed to you under the terms of the GNU GPL, version 2 or, // This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of // at your option, any later version. See the LICENSE.txt file for the text of
@ -10,7 +11,6 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Routines to support iClass. // Routines to support iClass.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Based on ISO14443a implementation. Still in experimental phase.
// Contribution made during a security research at Radboud University Nijmegen // Contribution made during a security research at Radboud University Nijmegen
// //
// Please feel free to contribute and extend iClass support!! // Please feel free to contribute and extend iClass support!!
@ -56,11 +56,6 @@
#include "ticks.h" #include "ticks.h"
#include "iso15693.h" #include "iso15693.h"
static int g_wait = 290;
static int timeout = 5000;
static uint32_t time_rdr = 0;
static uint32_t time_response = 0;
static int SendIClassAnswer(uint8_t *resp, int respLen, uint16_t delay); static int SendIClassAnswer(uint8_t *resp, int respLen, uint16_t delay);
int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf); int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf);
@ -117,8 +112,9 @@ void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string) {
} }
static void rotateCSN(uint8_t *original_csn, uint8_t *rotated_csn) { static void rotateCSN(uint8_t *original_csn, uint8_t *rotated_csn) {
for (uint8_t i = 0; i < 8; i++) for (uint8_t i = 0; i < 8; i++) {
rotated_csn[i] = (original_csn[i] >> 3) | (original_csn[(i + 1) % 8] << 5); rotated_csn[i] = (original_csn[i] >> 3) | (original_csn[(i + 1) % 8] << 5);
}
} }
// Encode SOF only // Encode SOF only
@ -376,8 +372,6 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
} }
} }
int exitLoop = 0;
// Anti-collision process: // Anti-collision process:
// Reader 0a // Reader 0a
// Tag 0f // Tag 0f
@ -409,7 +403,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
uint8_t *resp_conf = BigBuf_malloc(28); uint8_t *resp_conf = BigBuf_malloc(28);
int resp_conf_len; int resp_conf_len;
// e-Purse // e-Purse (blk 2)
// 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/bit) // 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/bit)
uint8_t *resp_cc = BigBuf_malloc(28); uint8_t *resp_cc = BigBuf_malloc(28);
int resp_cc_len; int resp_cc_len;
@ -420,7 +414,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
uint8_t ff_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; uint8_t ff_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00};
AddCrc(ff_data, 8); AddCrc(ff_data, 8);
// Application Issuer Area // Application Issuer Area (blk 5)
uint8_t *resp_aia = BigBuf_malloc(28); uint8_t *resp_aia = BigBuf_malloc(28);
int resp_aia_len; int resp_aia_len;
@ -467,7 +461,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
//This is used for responding to READ-block commands or other data which is dynamically generated //This is used for responding to READ-block commands or other data which is dynamically generated
//First the 'trace'-data, not encoded for FPGA //First the 'trace'-data, not encoded for FPGA
uint8_t *data_generic_trace = BigBuf_malloc(32 + 2);//8 bytes data + 2byte CRC is max tag answer uint8_t *data_generic_trace = BigBuf_malloc(32 + 2); // 32 bytes data + 2byte CRC is max tag answer
//Then storage for the modulated data //Then storage for the modulated data
//Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes) //Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes)
@ -479,14 +473,15 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
uint8_t cmd, options, block; uint8_t cmd, options, block;
int len = 0; int len = 0;
while (exitLoop == false) { bool exit_loop = 0;
while (exit_loop == false) {
WDT_HIT(); WDT_HIT();
uint32_t reader_eof_time = 0; uint32_t reader_eof_time = 0;
len = GetIso15693CommandFromReader(receivedCmd, MAX_FRAME_SIZE, &reader_eof_time); len = GetIso15693CommandFromReader(receivedCmd, MAX_FRAME_SIZE, &reader_eof_time);
if (len < 0) { if (len < 0) {
button_pressed = true; button_pressed = true;
exitLoop = true; exit_loop = true;
continue; continue;
} }
@ -506,7 +501,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
// Reader in anticollission phase // Reader in anticollission phase
if (chip_state != HALTED) { if (chip_state != HALTED) {
modulated_response = resp_sof; modulated_response = resp_sof;
modulated_response_size = resp_sof_len; //order = 1; modulated_response_size = resp_sof_len;
chip_state = ACTIVATED; chip_state = ACTIVATED;
goto send; goto send;
} }
@ -527,19 +522,21 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
if (chip_state == SELECTED) { if (chip_state == SELECTED) {
// block0,1,2,5 is always readable. // block0,1,2,5 is always readable.
switch (block) { switch (block) {
case 0: // csn (0c 00) case 0: { // csn (0c 00)
modulated_response = resp_csn; modulated_response = resp_csn;
modulated_response_size = resp_csn_len; modulated_response_size = resp_csn_len;
trace_data = csn_data; trace_data = csn_data;
trace_data_size = sizeof(csn_data); trace_data_size = sizeof(csn_data);
goto send; goto send;
case 1: // configuration (0c 01) }
case 1: { // configuration (0c 01)
modulated_response = resp_conf; modulated_response = resp_conf;
modulated_response_size = resp_conf_len; modulated_response_size = resp_conf_len;
trace_data = conf_data; trace_data = conf_block;
trace_data_size = sizeof(conf_data); trace_data_size = sizeof(conf_block);
goto send; goto send;
case 2: // e-purse (0c 02) }
case 2: {// e-purse (0c 02)
modulated_response = resp_cc; modulated_response = resp_cc;
modulated_response_size = resp_cc_len; modulated_response_size = resp_cc_len;
trace_data = card_challenge_data; trace_data = card_challenge_data;
@ -549,19 +546,22 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
memcpy(reader_mac_buf, card_challenge_data, 8); memcpy(reader_mac_buf, card_challenge_data, 8);
} }
goto send; goto send;
}
case 3: case 3:
case 4: // Kd, Kc, always respond with 0xff bytes case 4: { // Kd, Kc, always respond with 0xff bytes
modulated_response = resp_ff; modulated_response = resp_ff;
modulated_response_size = resp_ff_len; modulated_response_size = resp_ff_len;
trace_data = ff_data; trace_data = ff_data;
trace_data_size = sizeof(ff_data); trace_data_size = sizeof(ff_data);
goto send; goto send;
case 5:// Application Issuer Area (0c 05) }
case 5: { // Application Issuer Area (0c 05)
modulated_response = resp_aia; modulated_response = resp_aia;
modulated_response_size = resp_aia_len; modulated_response_size = resp_aia_len;
trace_data = aia_data; trace_data = aia_data;
trace_data_size = sizeof(aia_data); trace_data_size = sizeof(aia_data);
goto send; goto send;
}
default : { default : {
if (simulationMode == ICLASS_SIM_MODE_FULL) { // 0x0C if (simulationMode == ICLASS_SIM_MODE_FULL) { // 0x0C
//Read block //Read block
@ -570,7 +570,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
AddCrc(data_generic_trace, 8); AddCrc(data_generic_trace, 8);
trace_data = data_generic_trace; trace_data = data_generic_trace;
trace_data_size = 10; trace_data_size = 10;
CodeIClassTagAnswer(trace_data, trace_data_size); CodeIso15693AsTag(trace_data, trace_data_size);
memcpy(modulated_response, ToSend, ToSendMax); memcpy(modulated_response, ToSend, ToSendMax);
modulated_response_size = ToSendMax; modulated_response_size = ToSendMax;
goto send; goto send;
@ -588,23 +588,33 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
trace_data = csn_data; trace_data = csn_data;
trace_data_size = sizeof(csn_data); trace_data_size = sizeof(csn_data);
goto send; goto send;
} else if (cmd == ICLASS_CMD_READCHECK) { // 0x88 } else if (cmd == ICLASS_CMD_READCHECK) { // 0x88
// Read e-purse KD (88 02) KC (18 02) // Read e-purse KD (88 02) KC (18 02)
modulated_response = resp_cc; if (chip_state == SELECTED) {
modulated_response_size = resp_cc_len; //order = 4; if ( ICLASS_DEBIT(cmd) ){
trace_data = card_challenge_data; cipher_state = &cipher_state_KD[current_page];
trace_data_size = sizeof(card_challenge_data); diversified_key = diversified_kd;
LED_B_ON(); } else {
goto send; cipher_state = &cipher_state_KC[current_page];
diversified_key = diversified_kc;
}
modulated_response = resp_cc;
modulated_response_size = resp_cc_len;
trace_data = card_challenge_data;
trace_data_size = sizeof(card_challenge_data);
goto send;
}
} else if (cmd == ICLASS_CMD_CHECK) { // 0x05 } else if (cmd == ICLASS_CMD_CHECK) { // 0x05
// Reader random and reader MAC!!! // Reader random and reader MAC!!!
if (simulationMode == ICLASS_SIM_MODE_FULL) { if (simulationMode == ICLASS_SIM_MODE_FULL) {
// NR, from reader, is in receivedCmd +1 // 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 = data_generic_trace;
trace_data_size = 4; trace_data_size = 4;
CodeIClassTagAnswer(trace_data, trace_data_size); CodeIso15693AsTag(trace_data, trace_data_size);
memcpy(data_response, ToSend, ToSendMax); memcpy(data_response, ToSend, ToSendMax);
modulated_response = data_response; modulated_response = data_response;
modulated_response_size = ToSendMax; modulated_response_size = ToSendMax;
@ -628,21 +638,24 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
Dbprintf("[+] CSN: %02x .... %02x OK", csn[0], csn[7]); Dbprintf("[+] CSN: %02x .... %02x OK", csn[0], csn[7]);
} }
if (reader_mac_buf != NULL) { if (reader_mac_buf != NULL) {
// save NR and MAC for sim 2,4
memcpy(reader_mac_buf + 8, receivedCmd + 1, 8); memcpy(reader_mac_buf + 8, receivedCmd + 1, 8);
} }
exitLoop = true; exit_loop = true;
} }
} }
goto send; goto send;
} else if (cmd == ICLASS_CMD_HALT && options == 0 && len == 1) { } else if (cmd == ICLASS_CMD_HALT && options == 0 && len == 1) {
if (chip_state == SELECTED) { if (chip_state == SELECTED) {
// Reader ends the session // Reader ends the session
modulated_response = resp_sof; modulated_response = resp_sof;
modulated_response_size = resp_sof_Len; modulated_response_size = resp_sof_len;
chip_state = HALTED; chip_state = HALTED;
goto send; goto send;
} }
} else if (simulationMode == ICLASS_SIM_MODE_FULL && cmd == ICLASS_CMD_READ4 && len == 4) { // 0x06 } else if (simulationMode == ICLASS_SIM_MODE_FULL && cmd == ICLASS_CMD_READ4 && len == 4) { // 0x06
if (chip_state == SELECTED) { if (chip_state == SELECTED) {
@ -656,31 +669,86 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
modulated_response_size = ToSendMax; modulated_response_size = ToSendMax;
goto send; goto send;
} }
} else if (simulationMode == ICLASS_SIM_MODE_FULL && cmd == ICLASS_CMD_UPDATE) {
//Probably the reader wants to update the nonce. Let's just ignore that for now. } else if (simulationMode == ICLASS_SIM_MODE_FULL && cmd == ICLASS_CMD_UPDATE && (len == 12 || len == 14)) {
// OBS! If this is implemented, don't forget to regenerate the cipher_state
//We're expected to respond with the data+crc, exactly what's already in the receivedcmd
//receivedcmd is now UPDATE 1b | ADDRESS 1b| DATA 8b| Signature 4b or CRC 2b|
//Take the data... // We're expected to respond with the data+crc, exactly what's already in the receivedCmd
memcpy(data_generic_trace, receivedCmd + 2, 8); // receivedCmd is now UPDATE 1b | ADDRESS 1b | DATA 8b | Signature 4b or CRC 2b
AddCrc(data_generic_trace, 8); if (chip_state == SELECTED) {
trace_data = data_generic_trace;
trace_data_size = 10;
CodeIClassTagAnswer(trace_data, trace_data_size);
memcpy(data_response, ToSend, ToSendMax); if (block == 2) { // update e-purse
modulated_response = data_response; memcpy(card_challenge_data, receivedCmd + 2, 8);
modulated_response_size = ToSendMax; CodeIso15693AsTag(card_challenge_data, sizeof(card_challenge_data));
// response_delay = 4600 * 1.5; // tPROG 4-15ms memcpy(resp_cc, ToSend, ToSendMax);
resp_cc_len = ToSendMax;
cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kd);
cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kc);
} else if (block == 3) { // update Kd
for (int i = 0; i < 8; i++) {
if (personalization_mode) {
diversified_kd[i] = receivedCmd[2 + i];
} else {
diversified_kd[i] ^= receivedCmd[2 + i];
}
}
cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kd);
} else if (block == 4) { // update Kc
for (int i = 0; i < 8; i++) {
if (personalization_mode) {
diversified_kc[i] = receivedCmd[2 + i];
} else {
diversified_kc[i] ^= receivedCmd[2 + i];
}
}
cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kc);
}
// update emulator
memcpy(emulator + (current_page * page_size) + (8 * block), receivedCmd + 2, 8);
memcpy(data_generic_trace, receivedCmd + 2, 8);
AddCrc(data_generic_trace, 8);
trace_data = data_generic_trace;
trace_data_size = 10;
CodeIso15693AsTag(trace_data, trace_data_size);
memcpy(data_response, ToSend, ToSendMax);
modulated_response = data_response;
modulated_response_size = ToSendMax;
}
goto send; goto send;
// } else if(receivedCmd[0] == ICLASS_CMD_PAGESEL) { // 0x84
//Pagesel } else if (receivedCmd[0] == ICLASS_CMD_PAGESEL && len == 4) { // 0x84
//Pagesel enables to select a page in the selected chip memory and return its configuration block // Pagesel,
//Chips with a single page will not answer to this command // - enables to select a page in the selected chip memory and return its configuration block
// It appears we're fine ignoring this. // Chips with a single page will not answer to this command
//Otherwise, we should answer 8bytes (block) + 2bytes CRC // Otherwise, we should answer 8bytes (conf block 1) + 2bytes CRC
if (chip_state == SELECTED) {
if (simulationMode == ICLASS_SIM_MODE_FULL && max_page > 0) {
current_page = receivedCmd[1];
memcpy(data_generic_trace, emulator + (current_page * page_size) + (8 * 1), 8);
memcpy(diversified_kd, emulator + (current_page * page_size) + (8 * 3), 8);
memcpy(diversified_kc, emulator + (current_page * page_size) + (8 * 4), 8);
cipher_state = &cipher_state_KD[current_page];
personalization_mode = data_generic_trace[7] & 0x80;
AddCrc(data_generic_trace, 8);
trace_data = data_generic_trace;
trace_data_size = 10;
CodeIso15693AsTag(trace_data, trace_data_size);
memcpy(data_response, ToSend, ToSendMax);
modulated_response = data_response;
modulated_response_size = ToSendMax;
}
}
// } else if(receivedCmd[0] == ICLASS_CMD_DETECT) { // 0x0F // } else if(receivedCmd[0] == ICLASS_CMD_DETECT) { // 0x0F
} else if (receivedCmd[0] == 0x26 && len == 5) { } else if (receivedCmd[0] == 0x26 && len == 5) {
// standard ISO15693 INVENTORY command. Ignore. // standard ISO15693 INVENTORY command. Ignore.
@ -697,7 +765,7 @@ send:
if (modulated_response_size > 0) { if (modulated_response_size > 0) {
uint32_t response_time = reader_eof_time + DELAY_ICLASS_VCD_TO_VICC_SIM; uint32_t response_time = reader_eof_time + DELAY_ICLASS_VCD_TO_VICC_SIM;
TransmitTo15693Reader(modulated_response, modulated_response_size, &response_time, 0, false); TransmitTo15693Reader(modulated_response, modulated_response_size, &response_time, 0, false);
LogTrace(trace_data, trace_data_size, response_time*32, response_time*32 + modulated_response_size*32*64, NULL, false); LogTrace(trace_data, trace_data_size, response_time * 32, (response_time * 32) + (modulated_response_size * 32 * 64), NULL, false);
} }
} }
@ -711,54 +779,6 @@ send:
/// THE READER CODE /// THE READER CODE
//-----------------------------------------------------------------------------
// Transmit the command (to the tag) that was placed in ToSend[].
//-----------------------------------------------------------------------------
static void TransmitIClassCommand(const uint8_t *cmd, int len, int *wait) {
int c = 0;
bool firstpart = true;
uint8_t sendbyte;
time_rdr = 0;
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
AT91C_BASE_SSC->SSC_THR = 0x00;
// make sure we timeout previous comms.
if (*wait)
SpinDelayUs(*wait);
for (;;) {
WDT_HIT();
// Put byte into tx holding register as soon as it is ready
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
// DOUBLE THE SAMPLES!
if (firstpart) {
sendbyte = (cmd[c] & 0xf0) | (cmd[c] >> 4);
} else {
sendbyte = (cmd[c] & 0x0f) | (cmd[c] << 4);
c++;
}
if (sendbyte == 0xff)
sendbyte = 0xfe;
AT91C_BASE_SSC->SSC_THR = sendbyte;
firstpart = !firstpart;
if (c >= len) break;
}
}
time_rdr = GetCountSspClk();
}
static void ReaderTransmitIClass(uint8_t *frame, int len, uint32_t *start_time) { static void ReaderTransmitIClass(uint8_t *frame, int len, uint32_t *start_time) {
CodeIso15693AsReader(frame, len); CodeIso15693AsReader(frame, len);
@ -800,7 +820,7 @@ static bool selectIclassTag(uint8_t *card_data, bool use_credit_key, uint32_t *e
// bit 7: parity. // bit 7: parity.
if (use_credit_key) if (use_credit_key)
readcheck_cc[0] = 0x10 | ICLASS_CMD_READCHECK; read_check_cc[0] = 0x10 | ICLASS_CMD_READCHECK;
uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; uint8_t resp[ICLASS_BUFFER_SIZE] = {0};
@ -850,7 +870,7 @@ static bool selectIclassTag(uint8_t *card_data, bool use_credit_key, uint32_t *e
// card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) // card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC)
start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc), &start_time); ReaderTransmitIClass(read_check_cc, sizeof(read_check_cc), &start_time);
// expect a 8-byte response here // expect a 8-byte response here
len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time);
@ -864,25 +884,24 @@ static bool selectIclassTag(uint8_t *card_data, bool use_credit_key, uint32_t *e
// Reader iClass Anticollission // Reader iClass Anticollission
// turn off afterwards // turn off afterwards
void ReaderIClass(uint8_t arg0) { void ReaderIClass(uint8_t flags) {
uint8_t card_data[6 * 8] = {0}; uint8_t card_data[6 * 8] = {0xFF};
uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint8_t resp[ICLASS_BUFFER_SIZE]; uint8_t resp[ICLASS_BUFFER_SIZE];
memset(card_data, 0xFF, sizeof(card_data)); // memset(card_data, 0xFF, sizeof(card_data));
memset(resp, 0xFF, sizeof(resp)); memset(resp, 0xFF, sizeof(resp));
bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE; // flag to read until one tag is found successfully bool flag_readonce = flags & FLAG_ICLASS_READER_ONLY_ONCE; // flag to read until one tag is found successfully
bool try_once = arg0 & FLAG_ICLASS_READER_ONE_TRY; // flag to not to loop continuously, looking for tag bool use_credit_key = flags & FLAG_ICLASS_READER_CEDITKEY; // flag to use credit key
bool use_credit_key = arg0 & FLAG_ICLASS_READER_CEDITKEY; // flag to use credit key bool flag_read_aia = flags & FLAG_ICLASS_READER_AIA; // flag to read block5, application issuer area
bool flagReadAIA = arg0 & FLAG_ICLASS_READER_AIA; // flag to read block5, application issuer area
if (flags & FLAG_ICLASS_READER_INIT) { if ((flags & FLAG_ICLASS_READER_INIT) == FLAG_ICLASS_READER_INIT) {
Iso15693InitReader(); Iso15693InitReader();
} }
if (flags & FLAG_ICLASS_READER_CLEARTRACE) { if ((flags & FLAG_ICLASS_READER_CLEARTRACE) == FLAG_ICLASS_READER_CLEARTRACE) {
set_tracing(true); set_tracing(true);
clear_trace(); clear_trace();
StartCountSspClk(); StartCountSspClk();
@ -890,7 +909,6 @@ void ReaderIClass(uint8_t arg0) {
uint32_t start_time = 0; uint32_t start_time = 0;
uint32_t eof_time = 0; uint32_t eof_time = 0;
int read_status = selectIclassTag(card_data, use_credit_key, &eof_time); int read_status = selectIclassTag(card_data, use_credit_key, &eof_time);
if (read_status == 0) { if (read_status == 0) {
reply_mix(CMD_ACK, 0xFF, 0, 0, card_data, 0); reply_mix(CMD_ACK, 0xFF, 0, 0, card_data, 0);
@ -898,18 +916,18 @@ void ReaderIClass(uint8_t arg0) {
return; return;
} }
uint8_t result_status = FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_CC; uint8_t result_status = FLAG_ICLASS_CSN | FLAG_ICLASS_CONF | FLAG_ICLASS_CC;
//Read block 5, AIA //Read block 5, AIA
if (flagReadAIA) { if (flag_read_aia) {
//Read App Issuer Area block CRC(0x05) => 0xde 0x64 //Read App Issuer Area block CRC(0x05) => 0xde 0x64
uint8_t readAA[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; uint8_t read_aa[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64};
if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { if (sendCmdGetResponseWithRetries(read_aa, sizeof(read_aa), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) {
result_status |= FLAG_ICLASS_READER_AIA; result_status |= FLAG_ICLASS_AIA;
memcpy(card_data + (8 * 5), resp, 8); memcpy(card_data + (8 * 5), resp, 8);
} else { } else {
if (DBGLEVEL >= DBG_EXTENDED) DbpString("Failed to dump AA block"); if (DBGLEVEL >= DBG_EXTENDED) DbpString("Failed to dump AIA block");
} }
} }
@ -929,12 +947,10 @@ void ReaderIClass(uint8_t arg0) {
// only useful if looping in arm (not try_once && not abort_after_read) // only useful if looping in arm (not try_once && not abort_after_read)
if (memcmp(last_csn, card_data, 8) != 0) { if (memcmp(last_csn, card_data, 8) != 0) {
if (send) { reply_mix(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data));
reply_mix(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); if (flag_readonce) {
if (abort_after_read) { LED_B_OFF();
LED_B_OFF(); return;
return;
}
} }
LED_B_OFF(); LED_B_OFF();
} }
@ -1269,12 +1285,12 @@ static bool iClass_WriteBlock_ext(uint8_t blockno, uint8_t *data) {
} }
uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
if (blockNo == 2) { if (blockno == 2) {
// check response. e-purse update swaps first and second half // check response. e-purse update swaps first and second half
if (memcmp(data+4, resp, 4) || memcmp(data, resp+4, 4)) { if (memcmp(data+4, resp, 4) || memcmp(data, resp+4, 4)) {
return false; return false;
} }
} else if (blockNo == 3 || blockNo == 4) { } else if (blockno == 3 || blockno == 4) {
// check response. Key updates always return 0xffffffffffffffff // check response. Key updates always return 0xffffffffffffffff
if (memcmp(all_ff, resp, 8)) { if (memcmp(all_ff, resp, 8)) {
return false; return false;

View file

@ -1101,7 +1101,7 @@ static void Calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_
static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool verbose) { static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool verbose) {
PacketResponseNG resp; PacketResponseNG resp;
uint8_t flags = FLAG_ICLASS_READER_ONLY_ONCE | FLAG_ICLASS_READER_CC | FLAG_ICLASS_READER_ONE_TRY; uint8_t flags = FLAG_ICLASS_READER_ONLY_ONCE;
if (use_credit_key) if (use_credit_key)
flags |= FLAG_ICLASS_READER_CEDITKEY; flags |= FLAG_ICLASS_READER_CEDITKEY;
@ -1279,9 +1279,12 @@ static int CmdHFiClassReader_Dump(const char *Cmd) {
// if no debit key given try credit key on AA1 (not for iclass but for some picopass this will work) // 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; if (!have_debit_key && have_credit_key) use_credit_key = true;
uint32_t flags = FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CC | uint32_t flags = (
FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_ONLY_ONCE | FLAG_ICLASS_READER_INIT |
FLAG_ICLASS_READER_ONE_TRY; FLAG_ICLASS_READER_CLEARTRACE |
FLAG_ICLASS_READER_ONLY_ONCE
);
//get config and first 3 blocks //get config and first 3 blocks
PacketResponseNG resp; PacketResponseNG resp;
@ -1305,7 +1308,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) {
return PM3_ESOFT; return PM3_ESOFT;
} }
if (readStatus & (FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_CC)) { if (readStatus & (FLAG_ICLASS_CSN | FLAG_ICLASS_CONF | FLAG_ICLASS_CC)) {
memcpy(tag_data, data, 8 * 3); memcpy(tag_data, data, 8 * 3);
blockno += 2; // 2 to force re-read of block 2 later. (seems to respond differently..) blockno += 2; // 2 to force re-read of block 2 later. (seems to respond differently..)
numblks = data[8]; numblks = data[8];
@ -2927,9 +2930,12 @@ int CmdHFiClass(const char *Cmd) {
int readIclass(bool loop, bool verbose) { int readIclass(bool loop, bool verbose) {
bool tagFound = false; bool tagFound = false;
uint32_t flags = FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CC | FLAG_ICLASS_READER_AIA | uint32_t flags = (
FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_ONLY_ONCE | FLAG_ICLASS_READER_INIT |
FLAG_ICLASS_READER_ONE_TRY; FLAG_ICLASS_READER_CLEARTRACE |
FLAG_ICLASS_READER_ONLY_ONCE |
FLAG_ICLASS_READER_AIA
);
uint32_t res = PM3_ETIMEOUT; uint32_t res = PM3_ETIMEOUT;
// loop in client not device - else on windows have a communication error // loop in client not device - else on windows have a communication error
@ -2960,35 +2966,35 @@ int readIclass(bool loop, bool verbose) {
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " --------------------------"); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " --------------------------");
PrintAndLogEx(INFO, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------");
if (readStatus & FLAG_ICLASS_READER_CSN) { if (readStatus & FLAG_ICLASS_CSN) {
PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " (uid)", sprint_hex(hdr->csn, sizeof(hdr->csn))); PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " (uid)", sprint_hex(hdr->csn, sizeof(hdr->csn)));
tagFound = true; tagFound = true;
} }
if (readStatus & FLAG_ICLASS_READER_CONF) { if (readStatus & FLAG_ICLASS_CONF) {
PrintAndLogEx(SUCCESS, " Config: %s (Card configuration)", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf))); PrintAndLogEx(SUCCESS, " Config: %s (Card configuration)", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf)));
} }
if (readStatus & FLAG_ICLASS_READER_CC) { if (readStatus & FLAG_ICLASS_CC) {
PrintAndLogEx(SUCCESS, "E-purse: %s (Card challenge, CC)", sprint_hex(hdr->epurse, sizeof(hdr->epurse))); PrintAndLogEx(SUCCESS, "E-purse: %s (Card challenge, CC)", sprint_hex(hdr->epurse, sizeof(hdr->epurse)));
} }
PrintAndLogEx(SUCCESS, " Kd: %s (Debit key, hidden)", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); PrintAndLogEx(SUCCESS, " Kd: %s (Debit key, hidden)", sprint_hex(hdr->key_d, sizeof(hdr->key_d)));
PrintAndLogEx(SUCCESS, " Kc: %s (Credit key, hidden)", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); PrintAndLogEx(SUCCESS, " Kc: %s (Credit key, hidden)", sprint_hex(hdr->key_c, sizeof(hdr->key_c)));
if (readStatus & FLAG_ICLASS_READER_AIA) { if (readStatus & FLAG_ICLASS_AIA) {
// PrintAndLogEx(INFO, "--------- " _CYAN_("AIA") " ---------"); // PrintAndLogEx(INFO, "--------- " _CYAN_("AIA") " ---------");
PrintAndLogEx(SUCCESS, " AIA: %s (Application Issuer area)", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area))); PrintAndLogEx(SUCCESS, " AIA: %s (Application Issuer area)", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area)));
} }
if (readStatus & FLAG_ICLASS_READER_CONF) { if (readStatus & FLAG_ICLASS_CONF) {
printIclassDumpInfo(data); printIclassDumpInfo(data);
} }
// if CSN ends with FF12E0, it's inside HID CSN range. // if CSN ends with FF12E0, it's inside HID CSN range.
bool isHidRange = (memcmp((uint8_t *)(data + 5), "\xFF\x12\xE0", 3) == 0); bool isHidRange = (memcmp((uint8_t *)(data + 5), "\xFF\x12\xE0", 3) == 0);
if (readStatus & FLAG_ICLASS_READER_AIA) { if (readStatus & FLAG_ICLASS_AIA) {
bool legacy = (memcmp((uint8_t *)(data + 8 * 5), "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0); bool legacy = (memcmp((uint8_t *)(data + 8 * 5), "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0);
bool se_enabled = (memcmp((uint8_t *)(data + 8 * 5), "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0); bool se_enabled = (memcmp((uint8_t *)(data + 8 * 5), "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);

View file

@ -579,14 +579,18 @@ typedef struct {
#define FLAG_FORCED_ATQA 0x800 #define FLAG_FORCED_ATQA 0x800
#define FLAG_FORCED_SAK 0x1000 #define FLAG_FORCED_SAK 0x1000
//Iclass reader flags // iCLASS reader flags
#define FLAG_ICLASS_READER_ONLY_ONCE 0x01 #define FLAG_ICLASS_READER_INIT 0x01
#define FLAG_ICLASS_READER_CC 0x02 #define FLAG_ICLASS_READER_CLEARTRACE 0x02
#define FLAG_ICLASS_READER_CSN 0x04 #define FLAG_ICLASS_READER_ONLY_ONCE 0x04
#define FLAG_ICLASS_READER_CONF 0x08 #define FLAG_ICLASS_READER_CEDITKEY 0x08
#define FLAG_ICLASS_READER_AIA 0x10 #define FLAG_ICLASS_READER_AIA 0x10
#define FLAG_ICLASS_READER_ONE_TRY 0x20
#define FLAG_ICLASS_READER_CEDITKEY 0x40 // iCLASS reader status flags
#define FLAG_ICLASS_CSN 0x01
#define FLAG_ICLASS_CC 0x02
#define FLAG_ICLASS_CONF 0x04
#define FLAG_ICLASS_AIA 0x08
// iCLASS simulation modes // iCLASS simulation modes
#define ICLASS_SIM_MODE_CSN 0 #define ICLASS_SIM_MODE_CSN 0

View file

@ -135,7 +135,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define ICLASS_CMD_ACT 0xE #define ICLASS_CMD_ACT 0xE
#define ICLASS_CREDIT(x) (((x) & 0x10) == 0x10) #define ICLASS_CREDIT(x) (((x) & 0x10) == 0x10)
#define ICLASS_DEBIT(x) !(ICLASS_CREDIT(x)) #define ICLASS_DEBIT(x) (((x) & 0x80) == 0x80)
#define ISO14443A_CMD_REQA 0x26 #define ISO14443A_CMD_REQA 0x26