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
\r
for (rtr = 0; rtr < 17; rtr++) {\r
\r
- // Test if the action was cancelled\r
- if(BUTTON_PRESS()) {\r
- isOK = -2;\r
- break;\r
- }\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
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
for(i=0; i < 2 && !isOK; i++) { // look for exactly two different nonces\r
\r
target_nt[i] = 0;\r
- while(target_nt[i] == 0) { // continue until we have an unambiguous nonce\r
+ while(target_nt[i] == 0 && !isOK) { // continue until we have an unambiguous nonce\r
\r
// prepare next select. No need to power down the card.\r
if(mifare_classic_halt(pcs, cuid)) {\r
continue;\r
}\r
\r
+ // break out of the loop on button press\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
continue;\r
- };\r
+ }\r
\r
auth1_time = 0;\r
if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) {\r
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error");\r
continue;\r
- };\r
+ }\r
\r
// nested authentication\r
auth2_time = auth1_time + delta_time;\r
if (len != 4) {\r
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error len=%d", len);\r
continue;\r
- };\r
+ }\r
\r
nt2 = bytes_to_num(receivedAnswer, 4);\r
if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: Testing nt1=%08x nt2enc=%08x nt2par=%02x", i+1, nt1, nt2, par[0]);\r
target_ks[i] = ks1;\r
ncount++;\r
if (i == 1 && target_nt[1] == target_nt[0]) { // we need two different nonces\r
- target_nt[i] = 0;\r
+ if( ++target_nt_duplicate_count >= NESTED_MAX_TRIES ) { // unable to get a 2nd nonce after NESTED_MAX_TRIES tries, probably a fixed nonce\r
+ if (MF_DBGLEVEL >= 2) Dbprintf("Nonce#2: cannot get nonce that != nonce#1, continuing anyway with single nonce! ntdist=%d", j);\r
+ break;\r
+ }\r
+\r
+ target_nt[1] = 0;\r
if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#2: dismissed (= nonce#1), ntdist=%d", j);\r
break;\r
}\r
int res = MifareMultisectorChk(datain, keyCount, sectorCnt, keyType, OLD_MF_DBGLEVEL, &keyIndex);\r
\r
if (res >= 0) {\r
- cmd_send(CMD_ACK, 1, 0, 0, keyIndex, 80);\r
+ cmd_send(CMD_ACK, 1, res, 0, keyIndex, 80);\r
} else {\r
- cmd_send(CMD_ACK, 0, 0, 0, NULL, 0);\r
+ cmd_send(CMD_ACK, 0, res, 0, NULL, 0);\r
}\r
} else { \r
int res = MifareChkBlockKeys(datain, keyCount, blockNo, keyType, OLD_MF_DBGLEVEL);\r
\r
if (res > 0) {\r
- cmd_send(CMD_ACK, 1, 0, 0, datain + (res - 1) * 6, 6);\r
+ cmd_send(CMD_ACK, 1, res, 0, datain + (res - 1) * 6, 6);\r
} else {\r
- cmd_send(CMD_ACK, 0, 0, 0, NULL, 0);\r
+ cmd_send(CMD_ACK, 0, res, 0, NULL, 0);\r
}\r
}\r
\r
if (cmdp == 'o') { // ------------------------------------ one sector working\r
PrintAndLog("--target block no:%3d, target key type:%c ", trgBlockNo, trgKeyType?'B':'A');\r
int16_t isOK = mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock, true);\r
- if (isOK) {\r
+ if (isOK < 0) {\r
switch (isOK) {\r
case -1 : PrintAndLog("Error: No response from Proxmark.\n"); break;\r
case -2 : PrintAndLog("Button pressed. Aborted.\n"); break;\r
case -3 : PrintAndLog("Tag isn't vulnerable to Nested Attack (random numbers are not predictable).\n"); break;\r
- default : PrintAndLog("Unknown Error.\n");\r
+ default : PrintAndLog("Unknown Error (%d)\n", isOK);\r
}\r
return 2;\r
}\r
key64 = bytes_to_num(keyBlock, 6);\r
- if (key64) {\r
+ if (!isOK) {\r
PrintAndLog("Found valid key:%012" PRIx64, key64);\r
\r
// transfer key to the emulator\r
if (e_sector[sectorNo].foundKey[trgKeyType]) continue;\r
PrintAndLog("-----------------------------------------------");\r
int16_t isOK = mfnested(blockNo, keyType, key, FirstBlockOfSector(sectorNo), trgKeyType, keyBlock, calibrate);\r
- if(isOK) {\r
+ if(isOK < 0) {\r
switch (isOK) {\r
case -1 : PrintAndLog("Error: No response from Proxmark.\n"); break;\r
case -2 : PrintAndLog("Button pressed. Aborted.\n"); break;\r
case -3 : PrintAndLog("Tag isn't vulnerable to Nested Attack (random numbers are not predictable).\n"); break;\r
- default : PrintAndLog("Unknown Error.\n");\r
+ default : PrintAndLog("Unknown Error (%d)\n", isOK);\r
}\r
free(e_sector);\r
return 2;\r
iterations++;\r
\r
key64 = bytes_to_num(keyBlock, 6);\r
- if (key64) {\r
+ if (!isOK) {\r
PrintAndLog("Found valid key:%012" PRIx64, key64);\r
e_sector[sectorNo].foundKey[trgKeyType] = 1;\r
e_sector[sectorNo].Key[trgKeyType] = key64;\r
#include "parity.h"
#include "util.h"
#include "iso14443crc.h"
+#include "util_posix.h"
#include "mifare.h"
#include "mifare4.h"
SendCommand(&c);
UsbCommand resp;
- if (!WaitForResponseTimeout(CMD_ACK,&resp,3000)) return 1;
- if ((resp.arg[0] & 0xff) != 0x01) return 2;
+ if (!WaitForResponseTimeout(CMD_ACK,&resp,3000))
+ return 1;
+
+ if ((resp.arg[0] & 0xff) != 0x01) {
+ if (((int)resp.arg[1]) < 0)
+ return (int)resp.arg[1];
+
+ return 2;
+ }
+
*key = bytes_to_num(resp.d.asBytes, 6);
return 0;
}
int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool calibrate)
{
- uint16_t i;
+ uint32_t i, j;
uint32_t uid;
UsbCommand resp;
+ int num_unique_nonces;
+
StateList_t statelists[2];
struct Crypto1State *p1, *p2, *p3, *p4;
+ uint8_t *keyBlock = NULL;
+ uint64_t key64;
+
+ int isOK = 1;
+
+ uint64_t next_print_time = 0;
+ uint64_t start_time;
+ float brute_force_time;
+ float brute_force_per_second;
+
// flush queue
(void)WaitForResponseTimeout(CMD_ACK,NULL,100);
memcpy(c.d.asBytes, key, 6);
SendCommand(&c);
- if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
+ if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
+ // some cards can cause it to get stuck in a loop, so break out of it
+ UsbCommand c = {CMD_PING};
+ SendCommand(&c);
+ (void)WaitForResponseTimeout(CMD_ACK,NULL,500);
return -1;
}
memcpy(&statelists[i].ks1, (void *)(resp.d.asBytes + 4 + i * 8 + 4), 4);
}
+ if (statelists[0].nt == statelists[1].nt && statelists[0].ks1 == statelists[1].ks1)
+ num_unique_nonces = 1;
+ else
+ num_unique_nonces = 2;
+
// calc keys
pthread_t thread_id[2];
statelists[0].tail.sltail=--p3;
statelists[1].tail.sltail=--p4;
+ for (i = 0; i < 2; i++) {
+ PrintAndLog("statelist %d: length:%d block:%02d keytype:%d nt:%08X ks1:%08X", i, statelists[i].len, statelists[i].blockNo, statelists[i].keyType, statelists[i].nt, statelists[i].ks1);
+ }
+
// the statelists now contain possible keys. The key we are searching for must be in the
// intersection of both lists. Create the intersection:
qsort(statelists[0].head.keyhead, statelists[0].len, sizeof(uint64_t), compare_uint64);
- qsort(statelists[1].head.keyhead, statelists[1].len, sizeof(uint64_t), compare_uint64);
- statelists[0].len = intersection(statelists[0].head.keyhead, statelists[1].head.keyhead);
+
+ if (num_unique_nonces > 1) {
+ qsort(statelists[1].head.keyhead, statelists[1].len, sizeof(uint64_t), compare_uint64);
+ statelists[0].len = intersection(statelists[0].head.keyhead, statelists[1].head.keyhead);
+ }
+ else {
+ PrintAndLog("Nonce 1 and 2 are the same!");
+ }
+
+ if (statelists[0].len > 100) {
+ PrintAndLog("We have %d keys to check. This will take a very long time!", statelists[0].len);
+ PrintAndLog("Press button to abort.");
+ }
+ else if (statelists[0].len < 1) {
+ PrintAndLog("No candidate keys to check!");
+ }
+ else {
+ PrintAndLog("We have %d key(s) to check.", statelists[0].len);
+ }
+
+ uint32_t max_keys = (statelists[0].len > (USB_CMD_DATA_SIZE / 6)) ? (USB_CMD_DATA_SIZE / 6) : statelists[0].len;
+ keyBlock = calloc(max_keys, 6);
+
+ if (keyBlock == NULL) {
+ free(statelists[0].head.slhead);
+ free(statelists[1].head.slhead);
+ return -4;
+ }
memset(resultKey, 0, 6);
+ start_time = msclock();
+ next_print_time = start_time + 1 * 1000;
// The list may still contain several key candidates. Test each of them with mfCheckKeys
- for (i = 0; i < statelists[0].len; i++) {
- uint8_t keyBlock[6];
- uint64_t key64;
- crypto1_get_lfsr(statelists[0].head.slhead + i, &key64);
- num_to_bytes(key64, 6, keyBlock);
+ for (i = 0; i < statelists[0].len; i+=max_keys) {
+ if (next_print_time <= msclock()) {
+ brute_force_per_second = ((float)i) / (((float)(msclock() - start_time)) / 1000.0);
+ brute_force_time = ((float)(statelists[0].len - i)) / brute_force_per_second;
+ next_print_time = msclock() + 10 * 1000;
+ PrintAndLog(" %8d keys left | %5.1f keys/sec | worst case %6.1f seconds remaining", statelists[0].len - i, brute_force_per_second, brute_force_time);
+ }
+
+ if ((i+max_keys) >= statelists[0].len)
+ max_keys = statelists[0].len - i;
+
+ for (j = 0; j < max_keys; j++) {
+ crypto1_get_lfsr(statelists[0].head.slhead + i + j, &key64);
+ num_to_bytes(key64, 6, keyBlock+(j*6));
+ }
+
key64 = 0;
- if (!mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, false, 1, keyBlock, &key64)) {
+ isOK = mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, true, max_keys, keyBlock, &key64);
+
+ if (isOK == 1) { // timeout
+ isOK = -1;
+ break;
+ }
+ else if (isOK < 0) { // -2 is button pressed
+ break;
+ }
+ else if (!isOK) {
num_to_bytes(key64, 6, resultKey);
break;
}
}
+ if (isOK == 0 && statelists[0].len != 1)
+ PrintAndLog("Key found in %0.2f seconds after checking %d keys\n", ((float)(msclock() - start_time)) / 1000.0, i+max_keys);
+
free(statelists[0].head.slhead);
free(statelists[1].head.slhead);
+ free(keyBlock);
- return 0;
+ return isOK;
}
// MIFARE