+ SendCommand(&c);\r
+\r
+ UsbCommand resp;\r
+ if (!WaitForResponseTimeoutW(CMD_ACK, &resp, MAX(3000, 1000 + 13 * sectorCnt * keycnt * (keyType == 2 ? 2 : 1)), false)) return 1; // timeout: 13 ms / fail auth\r
+ if ((resp.arg[0] & 0xff) != 0x01) return 2;\r
+ \r
+ bool foundAKey = false;\r
+ for(int sec = 0; sec < sectorCnt; sec++){\r
+ for(int keyAB = 0; keyAB < 2; keyAB++){\r
+ keyPtr = *(resp.d.asBytes + keyAB * 40 + sec);\r
+ if (keyPtr){\r
+ e_sector[sec].foundKey[keyAB] = true;\r
+ e_sector[sec].Key[keyAB] = bytes_to_num(keyBlock + (keyPtr - 1) * 6, 6);\r
+ foundAKey = true;\r
+ }\r
+ }\r
+ }\r
+ return foundAKey ? 0 : 3;\r
+}\r
+\r
+// Compare 16 Bits out of cryptostate\r
+int Compare16Bits(const void * a, const void * b) {\r
+ if ((*(uint64_t*)b & 0x00ff000000ff0000) == (*(uint64_t*)a & 0x00ff000000ff0000)) return 0;\r
+ else if ((*(uint64_t*)b & 0x00ff000000ff0000) > (*(uint64_t*)a & 0x00ff000000ff0000)) return 1;\r
+ else return -1;\r
+}\r
+\r
+typedef\r
+ struct {\r
+ union {\r
+ struct Crypto1State *slhead;\r
+ uint64_t *keyhead;\r
+ } head;\r
+ union {\r
+ struct Crypto1State *sltail;\r
+ uint64_t *keytail;\r
+ } tail;\r
+ uint32_t len;\r
+ uint32_t uid;\r
+ uint32_t blockNo;\r
+ uint32_t keyType;\r
+ uint32_t nt;\r
+ uint32_t ks1;\r
+ } StateList_t;\r
+\r
+\r
+// wrapper function for multi-threaded lfsr_recovery32\r
+void\r
+#ifdef __has_attribute\r
+#if __has_attribute(force_align_arg_pointer)\r
+__attribute__((force_align_arg_pointer)) \r
+#endif\r
+#endif\r
+*nested_worker_thread(void *arg)\r
+{\r
+ struct Crypto1State *p1;\r
+ StateList_t *statelist = arg;\r
+\r
+ statelist->head.slhead = lfsr_recovery32(statelist->ks1, statelist->nt ^ statelist->uid);\r
+ for (p1 = statelist->head.slhead; *(uint64_t *)p1 != 0; p1++);\r
+ statelist->len = p1 - statelist->head.slhead;\r
+ statelist->tail.sltail = --p1;\r
+ qsort(statelist->head.slhead, statelist->len, sizeof(uint64_t), Compare16Bits);\r
+\r
+ return statelist->head.slhead;\r
+}\r
+\r
+\r
+int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool calibrate)\r
+{\r
+ uint16_t i;\r
+ uint32_t uid;\r
+ UsbCommand resp;\r
+\r
+ StateList_t statelists[2];\r
+ struct Crypto1State *p1, *p2, *p3, *p4;\r
+\r
+ // flush queue\r
+ (void)WaitForResponseTimeout(CMD_ACK,NULL,100);\r
+\r
+ UsbCommand c = {CMD_MIFARE_NESTED, {blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, calibrate}};\r
+ memcpy(c.d.asBytes, key, 6);\r
+ SendCommand(&c);\r
+\r
+ if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {\r
+ return -1;\r
+ }\r
+\r
+ if (resp.arg[0]) {\r
+ return resp.arg[0]; // error during nested\r
+ }\r
+\r
+ memcpy(&uid, resp.d.asBytes, 4);\r
+ PrintAndLog("uid:%08x trgbl=%d trgkey=%x", uid, (uint16_t)resp.arg[2] & 0xff, (uint16_t)resp.arg[2] >> 8);\r
+\r
+ for (i = 0; i < 2; i++) {\r
+ statelists[i].blockNo = resp.arg[2] & 0xff;\r
+ statelists[i].keyType = (resp.arg[2] >> 8) & 0xff;\r
+ statelists[i].uid = uid;\r
+ memcpy(&statelists[i].nt, (void *)(resp.d.asBytes + 4 + i * 8 + 0), 4);\r
+ memcpy(&statelists[i].ks1, (void *)(resp.d.asBytes + 4 + i * 8 + 4), 4);\r
+ }\r
+\r
+ // calc keys\r
+\r
+ pthread_t thread_id[2];\r
+\r
+ // create and run worker threads\r
+ for (i = 0; i < 2; i++) {\r
+ pthread_create(thread_id + i, NULL, nested_worker_thread, &statelists[i]);\r
+ }\r