+ if (!have_uid) { // need a full select cycle to get the uid first\r
+ iso14a_card_select_t card_info;\r
+ if(!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {\r
+ if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (ALL)");\r
+ continue;\r
+ }\r
+ switch (card_info.uidlen) {\r
+ case 4 : cascade_levels = 1; break;\r
+ case 7 : cascade_levels = 2; break;\r
+ case 10: cascade_levels = 3; break;\r
+ default: break;\r
+ }\r
+ have_uid = true;\r
+ } else { // no need for anticollision. We can directly select the card\r
+ if(!iso14443a_select_card(uid, NULL, NULL, false, cascade_levels, true)) {\r
+ if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)");\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if (slow) {\r
+ timeout = GetCountSspClk() + HARDNESTED_PRE_AUTHENTICATION_LEADTIME;\r
+ while(GetCountSspClk() < timeout);\r
+ }\r
+\r
+ uint32_t nt1;\r
+ if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL, NULL)) {\r
+ if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth1 error");\r
+ continue;\r
+ }\r
+\r
+ // nested authentication\r
+ uint16_t len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par_enc, NULL);\r
+ if (len != 4) {\r
+ if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth2 error len=%d", len);\r
+ continue;\r
+ }\r
+\r
+ // send an incomplete dummy response in order to trigger the card's authentication failure timeout\r
+ uint8_t dummy_answer[1] = {0};\r
+ ReaderTransmit(dummy_answer, 1, NULL);\r
+\r
+ timeout = GetCountSspClk() + HARDNESTED_AUTHENTICATION_TIMEOUT;\r
+\r
+ num_nonces++;\r
+ if (num_nonces % 2) {\r
+ memcpy(buf+i, receivedAnswer, 4);\r
+ nt_par_enc = par_enc[0] & 0xf0;\r
+ } else {\r
+ nt_par_enc |= par_enc[0] >> 4;\r
+ memcpy(buf+i+4, receivedAnswer, 4);\r
+ memcpy(buf+i+8, &nt_par_enc, 1);\r
+ i += 9;\r
+ }\r
+\r
+ // wait for the card to become ready again\r
+ while(GetCountSspClk() < timeout);\r
+\r
+ }\r
+\r
+ LED_C_OFF();\r
+\r
+ crypto1_destroy(pcs);\r
+\r
+ if (field_off) {\r
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
+ LEDsoff();\r
+ }\r
+\r
+ LED_B_ON();\r
+ cmd_send(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf));\r
+ LED_B_OFF();\r
+\r
+ if (MF_DBGLEVEL >= 3) DbpString("AcquireEncryptedNonces finished");\r
+\r
+}\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// MIFARE nested authentication.\r
+//\r
+//-----------------------------------------------------------------------------\r
+void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *datain) {\r
+\r
+ uint8_t blockNo = arg0 & 0xff;\r
+ uint8_t keyType = (arg0 >> 8) & 0xff;\r
+ uint8_t targetBlockNo = arg1 & 0xff;\r
+ uint8_t targetKeyType = (arg1 >> 8) & 0xff;\r
+ uint64_t ui64Key = 0;\r
+\r
+ ui64Key = bytes_to_num(datain, 6);\r
+\r
+ uint16_t rtr, i, j, len;\r
+ uint16_t davg;\r
+ static uint16_t dmin, dmax;\r
+ uint8_t uid[10];\r
+ uint32_t cuid, nt1, nt2, nttmp, nttest, ks1;\r
+ uint8_t par[1];\r
+ uint32_t target_nt[2], target_ks[2];\r
+ uint8_t target_nt_duplicate_count = 0;\r
+\r
+ uint8_t par_array[4];\r
+ uint16_t ncount = 0;\r
+ struct Crypto1State mpcs = {0, 0};\r
+ struct Crypto1State *pcs;\r
+ pcs = &mpcs;\r
+ uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];\r
+\r
+ uint32_t auth1_time, auth2_time, authentication_timeout = 0;\r
+ static uint16_t delta_time;\r
+\r
+ LED_A_ON();\r
+ iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);\r
+\r
+ // free eventually allocated BigBuf memory\r
+ BigBuf_free();\r
+\r
+ if (calibrate) clear_trace();\r
+ set_tracing(true);\r
+\r
+ // statistics on nonce distance\r
+ int16_t isOK = 0;\r
+ #define NESTED_MAX_TRIES 12\r
+ uint16_t unsuccessfull_tries = 0;\r
+ if (calibrate) { // for first call only. Otherwise reuse previous calibration\r
+ LED_B_ON();\r
+ WDT_HIT();\r
+\r
+ davg = dmax = 0;\r
+ dmin = 2000;\r
+ delta_time = 0;\r
+\r
+ for (rtr = 0; rtr < 17; rtr++) {\r
+\r
+ // prepare next select. No need to power down the card.\r
+ if (mifare_classic_halt(pcs, cuid)) {\r
+ if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error");\r
+ rtr--;\r
+ continue;\r
+ }\r
+\r
+ // Test if the action was cancelled\r
+ if (BUTTON_PRESS()) {\r
+ isOK = -2;\r
+ break;\r
+ }\r
+\r
+ if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {\r
+ if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card");\r
+ rtr--;\r