+ #define ICLASS_BUFFER_SIZE 32
+ uint8_t readerToTagCmd[ICLASS_BUFFER_SIZE];
+ // The response (tag -> reader) that we're receiving.
+ uint8_t tagToReaderResponse[ICLASS_BUFFER_SIZE];
+
+ FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
+
+ // free all BigBuf memory
+ BigBuf_free();
+ // The DMA buffer, used to stream samples from the FPGA
+ uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE);
+
+ set_tracing(true);
+ clear_trace();
+ iso14a_set_trigger(false);
+
+ int lastRxCounter;
+ uint8_t *upTo;
+ int smpl;
+ int maxBehindBy = 0;
+
+ // Count of samples received so far, so that we can include timing
+ // information in the trace buffer.
+ int samples = 0;
+ rsamples = 0;
+
+ // Set up the demodulator for tag -> reader responses.
+ Demod.output = tagToReaderResponse;
+ Demod.len = 0;
+ Demod.state = DEMOD_UNSYNCD;
+
+ // Setup for the DMA.
+ FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A);
+ upTo = dmaBuf;
+ lastRxCounter = DMA_BUFFER_SIZE;
+ FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE);
+
+ // And the reader -> tag commands
+ memset(&Uart, 0, sizeof(Uart));
+ Uart.output = readerToTagCmd;
+ Uart.byteCntMax = 32; // was 100 (greg)////////////////////////////////////////////////////////////////////////
+ Uart.state = STATE_UNSYNCD;
+
+ // And put the FPGA in the appropriate mode
+ // Signal field is off with the appropriate LED
+ LED_D_OFF();
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_SNIFFER);
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+
+ uint32_t time_0 = GetCountSspClk();
+ uint32_t time_start = 0;
+ uint32_t time_stop = 0;
+
+ int div = 0;
+ //int div2 = 0;
+ int decbyte = 0;
+ int decbyter = 0;
+
+ // And now we loop, receiving samples.
+ for (;;) {
+ LED_A_ON();
+ WDT_HIT();
+ int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (DMA_BUFFER_SIZE-1);
+ if (behindBy > maxBehindBy) {
+ maxBehindBy = behindBy;
+ if (behindBy > (9 * DMA_BUFFER_SIZE / 10)) {
+ Dbprintf("blew circular buffer! behindBy=0x%x", behindBy);
+ goto done;
+ }
+ }
+ if (behindBy < 1) continue;
+
+ LED_A_OFF();
+ smpl = upTo[0];
+ upTo++;
+ lastRxCounter -= 1;
+ if (upTo - dmaBuf > DMA_BUFFER_SIZE) {
+ upTo -= DMA_BUFFER_SIZE;
+ lastRxCounter += DMA_BUFFER_SIZE;
+ AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo;
+ AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;
+ }
+
+ //samples += 4;
+ samples += 1;
+
+ if (smpl & 0xF) {
+ decbyte ^= (1 << (3 - div));
+ }
+
+ // FOR READER SIDE COMMUMICATION...
+
+ decbyter <<= 2;
+ decbyter ^= (smpl & 0x30);
+
+ div++;
+
+ if ((div + 1) % 2 == 0) {
+ smpl = decbyter;
+ if (OutOfNDecoding((smpl & 0xF0) >> 4)) {
+ rsamples = samples - Uart.samples;
+ time_stop = (GetCountSspClk()-time_0) << 4;
+
+ //if (!LogTrace(Uart.output, Uart.byteCnt, rsamples, Uart.parityBits,true)) break;
+ //if (!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, true)) break;
+ uint8_t parity[MAX_PARITY_SIZE];
+ GetParity(Uart.output, Uart.byteCnt, parity);
+ LogTrace_ISO15693(Uart.output, Uart.byteCnt, time_start*32, time_stop*32, parity, true);
+
+ /* And ready to receive another command. */
+ Uart.state = STATE_UNSYNCD;
+ /* And also reset the demod code, which might have been */
+ /* false-triggered by the commands from the reader. */
+ Demod.state = DEMOD_UNSYNCD;
+ Uart.byteCnt = 0;
+ } else {
+ time_start = (GetCountSspClk()-time_0) << 4;
+ }
+ decbyter = 0;
+ }
+
+ if (div > 3) {
+ smpl = decbyte;
+ if (ManchesterDecoding(smpl & 0x0F)) {
+ time_stop = (GetCountSspClk()-time_0) << 4;
+
+ rsamples = samples - Demod.samples;
+
+ uint8_t parity[MAX_PARITY_SIZE];
+ GetParity(Demod.output, Demod.len, parity);
+ LogTrace_ISO15693(Demod.output, Demod.len, time_start*32, time_stop*32, parity, false);
+
+ // And ready to receive another response.
+ memset(&Demod, 0, sizeof(Demod));
+ Demod.output = tagToReaderResponse;
+ Demod.state = DEMOD_UNSYNCD;
+ } else {
+ time_start = (GetCountSspClk()-time_0) << 4;
+ }
+
+ div = 0;
+ decbyte = 0x00;
+ }
+
+ if (BUTTON_PRESS()) {
+ DbpString("cancelled_a");
+ goto done;
+ }
+ }
+
+ DbpString("COMMAND FINISHED");
+
+ Dbprintf("%x %x %x", maxBehindBy, Uart.state, Uart.byteCnt);
+ Dbprintf("%x %x %x", Uart.byteCntMax, BigBuf_get_traceLen(), (int)Uart.output[0]);
+
+done:
+ AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
+ Dbprintf("%x %x %x", maxBehindBy, Uart.state, Uart.byteCnt);
+ Dbprintf("%x %x %x", Uart.byteCntMax, BigBuf_get_traceLen(), (int)Uart.output[0]);
+ LEDsoff();
+}
+
+void rotateCSN(uint8_t* originalCSN, uint8_t* rotatedCSN) {
+ int i;
+ for (i = 0; i < 8; i++) {
+ rotatedCSN[i] = (originalCSN[i] >> 3) | (originalCSN[(i+1)%8] << 5);
+ }
+}
+
+// Encode SOF only
+static void CodeIClassTagSOF() {
+ ToSendReset();
+ ToSend[++ToSendMax] = 0x1D;
+ ToSendMax++;
+}
+
+static void AppendCrc(uint8_t *data, int len) {
+ ComputeCrc14443(CRC_ICLASS, data, len, data+len, data+len+1);
+}
+
+
+/**
+ * @brief Does the actual simulation
+ */
+int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
+
+ // free eventually allocated BigBuf memory
+ BigBuf_free_keep_EM();
+
+ uint16_t page_size = 32 * 8;
+ uint8_t current_page = 0;
+
+ // maintain cipher states for both credit and debit key for each page
+ State cipher_state_KC[8];
+ State cipher_state_KD[8];
+ State *cipher_state = &cipher_state_KD[0];
+
+ uint8_t *emulator = BigBuf_get_EM_addr();
+ uint8_t *csn = emulator;
+
+ // CSN followed by two CRC bytes
+ uint8_t anticoll_data[10];
+ uint8_t csn_data[10];
+ memcpy(csn_data, csn, sizeof(csn_data));
+ Dbprintf("Simulating CSN %02x%02x%02x%02x%02x%02x%02x%02x", csn[0], csn[1], csn[2], csn[3], csn[4], csn[5], csn[6], csn[7]);
+
+ // Construct anticollision-CSN
+ rotateCSN(csn_data, anticoll_data);
+
+ // Compute CRC on both CSNs
+ AppendCrc(anticoll_data, 8);
+ AppendCrc(csn_data, 8);
+
+ uint8_t diversified_key_d[8] = { 0x00 };
+ uint8_t diversified_key_c[8] = { 0x00 };
+ uint8_t *diversified_key = diversified_key_d;
+
+ // configuration block
+ uint8_t conf_block[10] = {0x12, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0xFF, 0x3C, 0x00, 0x00};
+
+ // e-Purse
+ uint8_t card_challenge_data[8] = { 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ if (simulationMode == ICLASS_SIM_MODE_FULL) {
+ // initialize from page 0
+ memcpy(conf_block, emulator + 8 * 1, 8);
+ memcpy(card_challenge_data, emulator + 8 * 2, 8); // e-purse
+ memcpy(diversified_key_d, emulator + 8 * 3, 8); // Kd
+ memcpy(diversified_key_c, emulator + 8 * 4, 8); // Kc
+ }
+
+ AppendCrc(conf_block, 8);
+
+ // save card challenge for sim2,4 attack
+ if (reader_mac_buf != NULL) {
+ memcpy(reader_mac_buf, card_challenge_data, 8);
+ }
+
+ if (conf_block[5] & 0x80) {
+ page_size = 256 * 8;
+ }
+
+ // From PicoPass DS:
+ // When the page is in personalization mode this bit is equal to 1.
+ // Once the application issuer has personalized and coded its dedicated areas, this bit must be set to 0:
+ // the page is then "in application mode".
+ bool personalization_mode = conf_block[7] & 0x80;
+
+ // chip memory may be divided in 8 pages
+ uint8_t max_page = conf_block[4] & 0x10 ? 0 : 7;
+
+ // Precalculate the cipher states, feeding it the CC
+ cipher_state_KD[0] = opt_doTagMAC_1(card_challenge_data, diversified_key_d);
+ cipher_state_KC[0] = opt_doTagMAC_1(card_challenge_data, diversified_key_c);
+ if (simulationMode == ICLASS_SIM_MODE_FULL) {
+ for (int i = 1; i < max_page; i++) {
+ uint8_t *epurse = emulator + i*page_size + 8*2;
+ uint8_t *Kd = emulator + i*page_size + 8*3;
+ uint8_t *Kc = emulator + i*page_size + 8*4;
+ cipher_state_KD[i] = opt_doTagMAC_1(epurse, Kd);
+ cipher_state_KC[i] = opt_doTagMAC_1(epurse, Kc);
+ }
+ }
+
+ int exitLoop = 0;
+ // Reader 0a
+ // Tag 0f
+ // Reader 0c
+ // Tag anticoll. CSN
+ // Reader 81 anticoll. CSN
+ // Tag CSN
+
+ uint8_t *modulated_response;
+ int modulated_response_size = 0;
+ uint8_t *trace_data = NULL;
+ int trace_data_size = 0;
+
+ // Respond SOF -- takes 1 bytes
+ uint8_t *resp_sof = BigBuf_malloc(1);
+ int resp_sof_Len;
+
+ // Anticollision CSN (rotated CSN)
+ // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte)
+ uint8_t *resp_anticoll = BigBuf_malloc(22);
+ int resp_anticoll_len;
+
+ // CSN (block 0)
+ // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte)
+ uint8_t *resp_csn = BigBuf_malloc(22);
+ int resp_csn_len;
+
+ // configuration (block 1) picopass 2ks
+ uint8_t *resp_conf = BigBuf_malloc(22);
+ int resp_conf_len;
+
+ // e-Purse (block 2)
+ // 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/bit)
+ uint8_t *resp_cc = BigBuf_malloc(18);
+ int resp_cc_len;
+
+ // Kd, Kc (blocks 3 and 4). Cannot be read. Always respond with 0xff bytes only
+ uint8_t *resp_ff = BigBuf_malloc(22);
+ int resp_ff_len;
+ uint8_t ff_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00};
+ AppendCrc(ff_data, 8);
+
+ // Application Issuer Area (block 5)
+ uint8_t *resp_aia = BigBuf_malloc(22);
+ int resp_aia_len;
+ uint8_t aia_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00};
+ AppendCrc(aia_data, 8);
+
+ uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE);
+ int len;
+
+ // Prepare card messages
+
+ // First card answer: SOF only
+ CodeIClassTagSOF();
+ memcpy(resp_sof, ToSend, ToSendMax);
+ resp_sof_Len = ToSendMax;
+
+ // Anticollision CSN
+ CodeIso15693AsTag(anticoll_data, sizeof(anticoll_data));
+ memcpy(resp_anticoll, ToSend, ToSendMax);
+ resp_anticoll_len = ToSendMax;
+
+ // CSN (block 0)
+ CodeIso15693AsTag(csn_data, sizeof(csn_data));
+ memcpy(resp_csn, ToSend, ToSendMax);
+ resp_csn_len = ToSendMax;
+
+ // Configuration (block 1)
+ CodeIso15693AsTag(conf_block, sizeof(conf_block));
+ memcpy(resp_conf, ToSend, ToSendMax);
+ resp_conf_len = ToSendMax;
+
+ // e-Purse (block 2)
+ CodeIso15693AsTag(card_challenge_data, sizeof(card_challenge_data));
+ memcpy(resp_cc, ToSend, ToSendMax);
+ resp_cc_len = ToSendMax;
+
+ // Kd, Kc (blocks 3 and 4)
+ CodeIso15693AsTag(ff_data, sizeof(ff_data));
+ memcpy(resp_ff, ToSend, ToSendMax);
+ resp_ff_len = ToSendMax;
+
+ // Application Issuer Area (block 5)
+ CodeIso15693AsTag(aia_data, sizeof(aia_data));
+ memcpy(resp_aia, ToSend, ToSendMax);
+ resp_aia_len = ToSendMax;
+
+ //This is used for responding to READ-block commands or other data which is dynamically generated
+ uint8_t *data_generic_trace = BigBuf_malloc(32 + 2); // 32 bytes data + 2byte CRC is max tag answer
+ uint8_t *data_response = BigBuf_malloc( (32 + 2) * 2 + 2);
+
+ bool buttonPressed = false;
+ enum { IDLE, ACTIVATED, SELECTED, HALTED } chip_state = IDLE;
+
+ while (!exitLoop) {
+ WDT_HIT();
+
+ uint32_t reader_eof_time = 0;
+ len = GetIso15693CommandFromReader(receivedCmd, MAX_FRAME_SIZE, &reader_eof_time);
+ if (len < 0) {
+ buttonPressed = true;
+ break;
+ }
+
+ // Now look at the reader command and provide appropriate responses
+ // default is no response:
+ modulated_response = NULL;
+ modulated_response_size = 0;
+ trace_data = NULL;
+ trace_data_size = 0;
+
+ if (receivedCmd[0] == ICLASS_CMD_ACTALL && len == 1) {
+ // Reader in anticollision phase
+ if (chip_state != HALTED) {
+ modulated_response = resp_sof;
+ modulated_response_size = resp_sof_Len;
+ chip_state = ACTIVATED;
+ }
+
+ } else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 1) { // identify
+ // Reader asks for anticollision CSN
+ if (chip_state == SELECTED || chip_state == ACTIVATED) {
+ modulated_response = resp_anticoll;
+ modulated_response_size = resp_anticoll_len;
+ trace_data = anticoll_data;
+ trace_data_size = sizeof(anticoll_data);
+ }
+
+ } else if (receivedCmd[0] == ICLASS_CMD_SELECT && len == 9) {
+ // Reader selects anticollision CSN.
+ // Tag sends the corresponding real CSN
+ if (chip_state == ACTIVATED || chip_state == SELECTED) {
+ if (!memcmp(receivedCmd+1, anticoll_data, 8)) {
+ modulated_response = resp_csn;
+ modulated_response_size = resp_csn_len;
+ trace_data = csn_data;
+ trace_data_size = sizeof(csn_data);
+ chip_state = SELECTED;
+ } else {
+ chip_state = IDLE;
+ }
+ } else if (chip_state == HALTED) {
+ // RESELECT with CSN
+ if (!memcmp(receivedCmd+1, csn_data, 8)) {
+ modulated_response = resp_csn;
+ modulated_response_size = resp_csn_len;
+ trace_data = csn_data;
+ trace_data_size = sizeof(csn_data);
+ chip_state = SELECTED;
+ }
+ }
+
+ } else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 4) { // read block
+ uint16_t blockNo = receivedCmd[1];
+ if (chip_state == SELECTED) {
+ if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) {
+ // provide defaults for blocks 0 ... 5
+ switch (blockNo) {
+ case 0: // csn (block 00)
+ modulated_response = resp_csn;
+ modulated_response_size = resp_csn_len;
+ trace_data = csn_data;
+ trace_data_size = sizeof(csn_data);
+ break;
+ case 1: // configuration (block 01)
+ modulated_response = resp_conf;
+ modulated_response_size = resp_conf_len;
+ trace_data = conf_block;
+ trace_data_size = sizeof(conf_block);
+ break;
+ case 2: // e-purse (block 02)
+ modulated_response = resp_cc;
+ modulated_response_size = resp_cc_len;
+ trace_data = card_challenge_data;
+ trace_data_size = sizeof(card_challenge_data);
+ // set epurse of sim2,4 attack
+ if (reader_mac_buf != NULL) {
+ memcpy(reader_mac_buf, card_challenge_data, 8);
+ }
+ break;
+ case 3:
+ case 4: // Kd, Kc, always respond with 0xff bytes
+ modulated_response = resp_ff;
+ modulated_response_size = resp_ff_len;
+ trace_data = ff_data;
+ trace_data_size = sizeof(ff_data);
+ break;
+ case 5: // Application Issuer Area (block 05)
+ modulated_response = resp_aia;
+ modulated_response_size = resp_aia_len;
+ trace_data = aia_data;
+ trace_data_size = sizeof(aia_data);
+ break;
+ // default: don't respond
+ }
+ } else if (simulationMode == ICLASS_SIM_MODE_FULL) {
+ if (blockNo == 3 || blockNo == 4) { // Kd, Kc, always respond with 0xff bytes
+ modulated_response = resp_ff;
+ modulated_response_size = resp_ff_len;
+ trace_data = ff_data;
+ trace_data_size = sizeof(ff_data);
+ } else { // use data from emulator memory
+ memcpy(data_generic_trace, emulator + current_page*page_size + 8*blockNo, 8);
+ AppendCrc(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_READCHECK_KD
+ || receivedCmd[0] == ICLASS_CMD_READCHECK_KC) && receivedCmd[1] == 0x02 && len == 2) {
+ // Read e-purse (88 02 || 18 02)
+ if (chip_state == SELECTED) {
+ if(receivedCmd[0] == ICLASS_CMD_READCHECK_KD){
+ cipher_state = &cipher_state_KD[current_page];
+ diversified_key = diversified_key_d;
+ } else {
+ cipher_state = &cipher_state_KC[current_page];
+ diversified_key = diversified_key_c;
+ }
+ modulated_response = resp_cc;
+ modulated_response_size = resp_cc_len;
+ trace_data = card_challenge_data;
+ trace_data_size = sizeof(card_challenge_data);
+ }
+
+ } else if ((receivedCmd[0] == ICLASS_CMD_CHECK_KC
+ || receivedCmd[0] == ICLASS_CMD_CHECK_KD) && len == 9) {
+ // Reader random and reader MAC!!!
+ if (chip_state == SELECTED) {
+ if (simulationMode == ICLASS_SIM_MODE_FULL) {
+ //NR, from reader, is in receivedCmd+1
+ opt_doTagMAC_2(*cipher_state, receivedCmd+1, data_generic_trace, diversified_key);
+ trace_data = data_generic_trace;
+ trace_data_size = 4;
+ CodeIso15693AsTag(trace_data, trace_data_size);
+ memcpy(data_response, ToSend, ToSendMax);
+ modulated_response = data_response;
+ modulated_response_size = ToSendMax;
+ //exitLoop = true;
+ } else { // Not fullsim, we don't respond
+ // We do not know what to answer, so lets keep quiet
+ if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) {
+ if (reader_mac_buf != NULL) {
+ // save NR and MAC for sim 2,4
+ memcpy(reader_mac_buf + 8, receivedCmd + 1, 8);
+ }
+ exitLoop = true;
+ }
+ }
+ }
+
+ } else if (receivedCmd[0] == ICLASS_CMD_HALT && len == 1) {
+ if (chip_state == SELECTED) {
+ // Reader ends the session
+ modulated_response = resp_sof;
+ modulated_response_size = resp_sof_Len;
+ chip_state = HALTED;
+ }
+
+ } else if (simulationMode == ICLASS_SIM_MODE_FULL && receivedCmd[0] == ICLASS_CMD_READ4 && len == 4) { // 0x06
+ //Read 4 blocks
+ if (chip_state == SELECTED) {
+ uint8_t blockNo = receivedCmd[1];
+ memcpy(data_generic_trace, emulator + current_page*page_size + blockNo*8, 8 * 4);
+ AppendCrc(data_generic_trace, 8 * 4);
+ trace_data = data_generic_trace;
+ trace_data_size = 8 * 4 + 2;
+ 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_UPDATE && (len == 12 || len == 14)) {
+ // 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
+ if (chip_state == SELECTED) {
+ uint8_t blockNo = receivedCmd[1];
+ if (blockNo == 2) { // update e-purse
+ memcpy(card_challenge_data, receivedCmd+2, 8);
+ CodeIso15693AsTag(card_challenge_data, sizeof(card_challenge_data));
+ memcpy(resp_cc, ToSend, ToSendMax);
+ resp_cc_len = ToSendMax;
+ cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_key_d);
+ cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_key_c);
+ if (simulationMode == ICLASS_SIM_MODE_FULL) {
+ memcpy(emulator + current_page*page_size + 8*2, card_challenge_data, 8);
+ }
+ } else if (blockNo == 3) { // update Kd
+ for (int i = 0; i < 8; i++) {
+ if (personalization_mode) {
+ diversified_key_d[i] = receivedCmd[2 + i];
+ } else {
+ diversified_key_d[i] ^= receivedCmd[2 + i];
+ }
+ }
+ cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_key_d);
+ if (simulationMode == ICLASS_SIM_MODE_FULL) {
+ memcpy(emulator + current_page*page_size + 8*3, diversified_key_d, 8);
+ }
+ } else if (blockNo == 4) { // update Kc
+ for (int i = 0; i < 8; i++) {
+ if (personalization_mode) {
+ diversified_key_c[i] = receivedCmd[2 + i];
+ } else {
+ diversified_key_c[i] ^= receivedCmd[2 + i];
+ }
+ }
+ cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_key_c);
+ if (simulationMode == ICLASS_SIM_MODE_FULL) {
+ memcpy(emulator + current_page*page_size + 8*4, diversified_key_c, 8);
+ }
+ } else if (simulationMode == ICLASS_SIM_MODE_FULL) { // update any other data block
+ memcpy(emulator + current_page*page_size + 8*blockNo, receivedCmd+2, 8);
+ }
+ memcpy(data_generic_trace, receivedCmd + 2, 8);
+ AppendCrc(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_PAGESEL && len == 4) {
+ // Pagesel
+ // Chips with a single page will not answer to this command
+ // 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_key_d, emulator + current_page*page_size + 8*3, 8);
+ memcpy(diversified_key_c, emulator + current_page*page_size + 8*4, 8);
+ cipher_state = &cipher_state_KD[current_page];
+ personalization_mode = data_generic_trace[7] & 0x80;
+ AppendCrc(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] == 0x26 && len == 5) {
+ // standard ISO15693 INVENTORY command. Ignore.
+
+ } else {
+ // don't know how to handle this command
+ char debug_message[250]; // should be enough
+ sprintf(debug_message, "Unhandled command (len = %d) received from reader:", len);
+ for (int i = 0; i < len && strlen(debug_message) < sizeof(debug_message) - 3 - 1; i++) {
+ sprintf(debug_message + strlen(debug_message), " %02x", receivedCmd[i]);
+ }
+ Dbprintf("%s", debug_message);
+ // Do not respond
+ }
+
+ /**
+ A legit tag has about 273,4us delay between reader EOT and tag SOF.
+ **/
+ if (modulated_response_size > 0) {
+ uint32_t response_time = reader_eof_time + DELAY_ICLASS_VCD_TO_VICC_SIM;
+ TransmitTo15693Reader(modulated_response, modulated_response_size, &response_time, 0, false);
+ LogTrace_ISO15693(trace_data, trace_data_size, response_time*32, response_time*32 + modulated_response_size/2, NULL, false);
+ }
+
+ }
+
+ if (buttonPressed)
+ {
+ DbpString("Button pressed");
+ }
+ return buttonPressed;
+}
+
+/**
+ * @brief SimulateIClass simulates an iClass card.
+ * @param arg0 type of simulation
+ * - 0 uses the first 8 bytes in usb data as CSN
+ * - 2 "dismantling iclass"-attack. This mode iterates through all CSN's specified
+ * in the usb data. This mode collects MAC from the reader, in order to do an offline
+ * attack on the keys. For more info, see "dismantling iclass" and proxclone.com.
+ * - Other : Uses the default CSN (031fec8af7ff12e0)
+ * @param arg1 - number of CSN's contained in datain (applicable for mode 2 only)
+ * @param arg2
+ * @param datain
+ */
+void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) {
+
+ LED_A_ON();
+
+ uint32_t simType = arg0;
+ uint32_t numberOfCSNS = arg1;
+
+ // setup hardware for simulation:
+ FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION);
+ LED_D_OFF();
+ FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
+ StartCountSspClk();
+
+ // Enable and clear the trace
+ set_tracing(true);
+ clear_trace();
+ //Use the emulator memory for SIM
+ uint8_t *emulator = BigBuf_get_EM_addr();
+
+ if (simType == ICLASS_SIM_MODE_CSN) {
+ // Use the CSN from commandline
+ memcpy(emulator, datain, 8);
+ doIClassSimulation(ICLASS_SIM_MODE_CSN, NULL);
+ } else if (simType == ICLASS_SIM_MODE_CSN_DEFAULT) {
+ //Default CSN
+ uint8_t csn_crc[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 };
+ // Use the CSN from commandline
+ memcpy(emulator, csn_crc, 8);
+ doIClassSimulation(ICLASS_SIM_MODE_CSN, NULL);
+ } else if (simType == ICLASS_SIM_MODE_READER_ATTACK) {
+ uint8_t mac_responses[USB_CMD_DATA_SIZE] = { 0 };
+ Dbprintf("Going into attack mode, %d CSNS sent", numberOfCSNS);
+ // In this mode, a number of csns are within datain. We'll simulate each one, one at a time
+ // in order to collect MAC's from the reader. This can later be used in an offline-attack
+ // in order to obtain the keys, as in the "dismantling iclass"-paper.
+ int i;
+ for (i = 0; i < numberOfCSNS && i*16+16 <= USB_CMD_DATA_SIZE; i++) {
+ // The usb data is 512 bytes, fitting 32 responses (8 byte CC + 4 Byte NR + 4 Byte MAC = 16 Byte response).
+ memcpy(emulator, datain+(i*8), 8);
+ if (doIClassSimulation(ICLASS_SIM_MODE_EXIT_AFTER_MAC, mac_responses+i*16)) {
+ // Button pressed
+ break;
+ }
+ Dbprintf("CSN: %02x %02x %02x %02x %02x %02x %02x %02x",
+ datain[i*8+0], datain[i*8+1], datain[i*8+2], datain[i*8+3],
+ datain[i*8+4], datain[i*8+5], datain[i*8+6], datain[i*8+7]);
+ Dbprintf("NR,MAC: %02x %02x %02x %02x %02x %02x %02x %02x",
+ mac_responses[i*16+ 8], mac_responses[i*16+ 9], mac_responses[i*16+10], mac_responses[i*16+11],
+ mac_responses[i*16+12], mac_responses[i*16+13], mac_responses[i*16+14], mac_responses[i*16+15]);
+ SpinDelay(100); // give the reader some time to prepare for next CSN
+ }
+ cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i*16);
+ } else if (simType == ICLASS_SIM_MODE_FULL) {
+ //This is 'full sim' mode, where we use the emulator storage for data.
+ doIClassSimulation(ICLASS_SIM_MODE_FULL, NULL);
+ } else {
+ // We may want a mode here where we hardcode the csns to use (from proxclone).
+ // That will speed things up a little, but not required just yet.
+ Dbprintf("The mode is not implemented, reserved for future use");
+ }
+
+ Dbprintf("Done...");