From 3772d1651af81dcb1df73417856002177a0dbabc Mon Sep 17 00:00:00 2001 From: LW Date: Wed, 18 Dec 2019 02:26:40 -0800 Subject: [PATCH] modify mfCheckKeys() to pass button press events upstream, don't abort nested when a static nonce is encountered, and modify nested to try multiple keys in a single operation --- armsrc/mifarecmd.c | 17 ++++----- client/mifare/mifarehost.c | 78 ++++++++++++++++++++++++++++++++------ 2 files changed, 73 insertions(+), 22 deletions(-) diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 50dc2443..af1dff02 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -951,15 +951,12 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat target_ks[i] = ks1; ncount++; if (i == 1 && target_nt[1] == target_nt[0]) { // we need two different nonces - target_nt[1] = 0; - if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#2: dismissed (= nonce#1), ntdist=%d", j); - - if( ++target_nt_duplicate_count == 50 ) { // unable to get a 2nd nonce after 50 tries, probably a fixed nonce - isOK = -4; - target_nt[1] = nt1; + if( ++target_nt_duplicate_count >= 10 ) { // unable to get a 2nd nonce after 10 tries, probably a fixed nonce break; } + target_nt[1] = 0; + if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#2: dismissed (= nonce#1), ntdist=%d", j); break; } if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: valid, ntdist=%d", i+1, j); @@ -1027,17 +1024,17 @@ void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) int res = MifareMultisectorChk(datain, keyCount, sectorCnt, keyType, OLD_MF_DBGLEVEL, &keyIndex); if (res >= 0) { - cmd_send(CMD_ACK, 1, 0, 0, keyIndex, 80); + cmd_send(CMD_ACK, 1, res, 0, keyIndex, 80); } else { - cmd_send(CMD_ACK, 0, 0, 0, NULL, 0); + cmd_send(CMD_ACK, 0, res, 0, NULL, 0); } } else { int res = MifareChkBlockKeys(datain, keyCount, blockNo, keyType, OLD_MF_DBGLEVEL); if (res > 0) { - cmd_send(CMD_ACK, 1, 0, 0, datain + (res - 1) * 6, 6); + cmd_send(CMD_ACK, 1, res, 0, datain + (res - 1) * 6, 6); } else { - cmd_send(CMD_ACK, 0, 0, 0, NULL, 0); + cmd_send(CMD_ACK, 0, res, 0, NULL, 0); } } diff --git a/client/mifare/mifarehost.c b/client/mifare/mifarehost.c index 33df6e04..accbf645 100644 --- a/client/mifare/mifarehost.c +++ b/client/mifare/mifarehost.c @@ -236,8 +236,16 @@ int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t key 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; } @@ -321,13 +329,20 @@ __attribute__((force_align_arg_pointer)) 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 = -6; + // flush queue (void)WaitForResponseTimeout(CMD_ACK,NULL,100); @@ -358,8 +373,15 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, statelists[i].uid = uid; memcpy(&statelists[i].nt, (void *)(resp.d.asBytes + 4 + i * 8 + 0), 4); memcpy(&statelists[i].ks1, (void *)(resp.d.asBytes + 4 + i * 8 + 4), 4); + + PrintAndLog("statelist %d: %02X %x %08X %08X", i, statelists[i].blockNo, statelists[i].keyType, statelists[i].nt, statelists[i].ks1); } + 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]; @@ -413,27 +435,59 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, // 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."); + } + + 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) return -5; memset(resultKey, 0, 6); // 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) { + PrintAndLog("Keys left to check: %d", statelists[0].len - i); + 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) + PrintAndLog("Key found after checking %d keys\n", i+max_keys); + free(statelists[0].head.slhead); free(statelists[1].head.slhead); - return 0; + return isOK; } // MIFARE