diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index c5d098cd3..978b798b6 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -1196,23 +1196,79 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 set_tracing(false); } -void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t *key) { - - LEDsoff(); +static void MifareFastStaticNestedImpl(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t* key, uint32_t* nt1, uint32_t* nt2, uint32_t* cuid, bool firstGet, int16_t* isOK) { uint64_t ui64Key = 0; ui64Key = bytes_to_num(key, 6); uint16_t len; - uint8_t uid[10] = {0x00}; - uint32_t cuid = 0, nt1, nt2; - uint32_t target_nt = 0, target_ks = 0; - uint8_t par[1] = {0x00}; - uint8_t receivedAnswer[10] = {0x00}; + uint8_t uid[10] = { 0x00 }; + uint8_t par[1] = { 0x00 }; + uint8_t receivedAnswer[10] = { 0x00 }; - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; + struct Crypto1State mpcs = { 0, 0 }; + struct Crypto1State* pcs; pcs = &mpcs; + *isOK = 0; + LED_C_ON(); + + for (uint8_t retry = 0; retry < 3 && (*isOK == 0); retry++) { + + WDT_HIT(); + + // prepare next select. No need to power down the card. + if (mifare_classic_halt(pcs, *cuid)) { + if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Halt error"); + retry--; + continue; + } + + if (!iso14443a_select_card(uid, NULL, cuid, true, 0, true)) { + if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Can't select card"); + retry--; + continue; + }; + + // First authentication. Normal auth. + if (mifare_classic_authex(pcs, *cuid, blockNo, keyType, ui64Key, AUTH_FIRST, nt1, NULL)) { + if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Auth1 error"); + retry--; + continue; + }; + + // not first get, we need auth again... + if (!firstGet) { + if (mifare_classic_authex(pcs, *cuid, blockNo, keyType, ui64Key, AUTH_NESTED, NULL, NULL)) { + if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Auth1 again error"); + retry--; + continue; + }; + } + + // second authentication. Nested auth + len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, NULL); + if (len != 4) { + if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Auth2 error len=%d", len); + continue; + }; + + *nt2 = bytes_to_num(receivedAnswer, 4); + *isOK = 1; + } + + LED_C_OFF(); + + crypto1_deinit(pcs); +} + +void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t* key) { + + int16_t isOK; + uint32_t cuid; + uint32_t nt1_1, nt2_1; + uint32_t nt1_2, nt2_2; + + LEDsoff(); LED_A_ON(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); @@ -1222,76 +1278,43 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, clear_trace(); set_tracing(true); - int16_t isOK = 0; - LED_C_ON(); - - for (uint8_t retry = 0; retry < 3 && (isOK == 0); retry++) { - - WDT_HIT(); - - // prepare next select. No need to power down the card. - if (mifare_classic_halt(pcs, cuid)) { - if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Halt error"); - retry--; - continue; - } - - if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Can't select card"); - retry--; - continue; - }; - - // First authentication. Normal auth. - if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) { - if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Auth1 error"); - retry--; - continue; - }; - - // second authentication. Nested auth - len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, NULL); - if (len != 4) { - if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Auth2 error len=%d", len); - continue; - }; - - nt2 = bytes_to_num(receivedAnswer, 4); - target_nt = prng_successor(nt1, 160); - target_ks = nt2 ^ target_nt; - isOK = 1; - - if (g_dbglevel >= DBG_DEBUG) Dbprintf("Testing nt1=%08x nt2enc=%08x nt2par=%02x ks=%08x", nt1, nt2, par[0], target_ks); + MifareFastStaticNestedImpl(blockNo, keyType, targetBlockNo, targetKeyType, key, &nt1_1, &nt2_1, &cuid, true, &isOK); + if (isOK) { + MifareFastStaticNestedImpl(blockNo, keyType, targetBlockNo, targetKeyType, key, &nt1_2, &nt2_2, &cuid, false, &isOK); } - LED_C_OFF(); - - crypto1_deinit(pcs); - struct p { int16_t isOK; uint8_t block; uint8_t keytype; uint8_t cuid[4]; - uint8_t nt[4]; - uint8_t ks[4]; + uint8_t nt1_1[4]; + uint8_t nt2_1[4]; + // new nt + uint8_t nt1_2[4]; + uint8_t nt2_2[4]; } PACKED payload; payload.isOK = isOK; payload.block = targetBlockNo; payload.keytype = targetKeyType; memcpy(payload.cuid, &cuid, 4); - memcpy(payload.nt, &target_nt, 4); - memcpy(payload.ks, &target_ks, 4); + + // copy nonces to response body. + memcpy(payload.nt1_1, &nt1_1, 4); + memcpy(payload.nt2_1, &nt2_1, 4); + memcpy(payload.nt1_2, &nt1_2, 4); + memcpy(payload.nt2_2, &nt2_2, 4); LED_B_ON(); - reply_ng(CMD_HF_MIFARE_STATIC_NESTED, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload)); + reply_ng(CMD_HF_MIFARE_STATIC_NESTED, PM3_SUCCESS, (uint8_t*)&payload, sizeof(payload)); LED_B_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); set_tracing(false); } + //----------------------------------------------------------------------------- // MIFARE check keys. key count up to 85. // diff --git a/client/src/mifare/mifarehost.c b/client/src/mifare/mifarehost.c index e58488a87..94f331a05 100644 --- a/client/src/mifare/mifarehost.c +++ b/client/src/mifare/mifarehost.c @@ -581,11 +581,11 @@ out: } -int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey) { +int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t* key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t* resultKey) { uint32_t uid; - StateList_t statelists[1]; - struct Crypto1State *p1, *p3; + StateList_t statelists[2]; + struct Crypto1State* p1, * p2, * p3, * p4; struct { uint8_t block; @@ -602,7 +602,7 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl PacketResponseNG resp; clearCommandBuffer(); - SendCommandNG(CMD_HF_MIFARE_STATIC_NESTED, (uint8_t *)&payload, sizeof(payload)); + SendCommandNG(CMD_HF_MIFARE_STATIC_NESTED, (uint8_t*)&payload, sizeof(payload)); if (!WaitForResponseTimeout(CMD_HF_MIFARE_STATIC_NESTED, &resp, 2000)) return PM3_ETIMEOUT; @@ -615,51 +615,169 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl uint8_t block; uint8_t keytype; uint8_t cuid[4]; - uint8_t nt[4]; - uint8_t ks[4]; + uint8_t nt1_1[4]; + uint8_t nt2_1[4]; + // new nt + uint8_t nt1_2[4]; + uint8_t nt2_2[4]; } PACKED; - struct p *package = (struct p *)resp.data.asBytes; + struct p* package = (struct p*)resp.data.asBytes; // error during collecting static nested information if (package->isOK == 0) return PM3_EUNDEF; + uint32_t nt1_1, nt2_1; + uint32_t nt1_2, nt2_2; + uint32_t dist = 160; + memcpy(&uid, package->cuid, sizeof(package->cuid)); + memcpy(&nt1_1, package->nt1_1, 4); + memcpy(&nt2_1, package->nt2_1, 4); + memcpy(&nt1_2, package->nt1_2, 4); + memcpy(&nt2_2, package->nt2_2, 4); - statelists[0].blockNo = package->block; - statelists[0].keyType = package->keytype; - statelists[0].uid = uid; - - memcpy(&statelists[0].nt_enc, package->nt, sizeof(package->nt)); - memcpy(&statelists[0].ks1, package->ks, sizeof(package->ks)); - - // calc keys - pthread_t t; - - // create and run worker thread - pthread_create(&t, NULL, nested_worker_thread, &statelists[0]); - - // wait for thread to terminate: - pthread_join(t, (void *)&statelists[0].head.slhead); - - // the first 16 Bits of the cryptostate already contain part of our key. - p1 = p3 = statelists[0].head.slhead; - - // create key candidates. - while (p1 <= statelists[0].tail.sltail) { - struct Crypto1State savestate; - savestate = *p1; - while (Compare16Bits(p1, &savestate) == 0 && p1 <= statelists[0].tail.sltail) { - *p3 = *p1; - lfsr_rollback_word(p3, statelists[0].nt_enc ^ statelists[0].uid, 0); - p3++; - p1++; + // is fast decrypt supported? + uint8_t level = 0; + if (nt2_1 != nt2_2) { + level = 1; + // check level(staticnested) + if (nt1_1 == 0x01200145) { + level = 1; + } + if (nt1_1 == 0x009080A2) { + level = 2; + if (trgKeyType == 1) { + // if level is 2 and recover keyb, we must use 161 dist first. + dist = 161; + } } } + else { + level = 0; + } - p3->odd = -1; - p3->even = -1; - statelists[0].len = p3 - statelists[0].head.slhead; - statelists[0].tail.sltail = --p3; + PrintAndLogEx(SUCCESS, "Auto detect staticnested level %d", level); + + uint32_t ntp_1 = prng_successor(nt1_1, dist); + uint32_t ks1_1 = nt2_1 ^ ntp_1; + + // normal static nested + if (level == 0) { + statelists[0].blockNo = package->block; + statelists[0].keyType = package->keytype; + statelists[0].uid = uid; + + memcpy(&statelists[0].nt_enc, &ntp_1, sizeof(ntp_1)); + memcpy(&statelists[0].ks1, &ks1_1, sizeof(ks1_1)); + + // calc keys + pthread_t t; + + // create and run worker thread + pthread_create(&t, NULL, nested_worker_thread, &statelists[0]); + + // wait for thread to terminate: + pthread_join(t, (void*)&statelists[0].head.slhead); + + // the first 16 Bits of the cryptostate already contain part of our key. + p1 = p3 = statelists[0].head.slhead; + + // create key candidates. + while (p1 <= statelists[0].tail.sltail) { + struct Crypto1State savestate; + savestate = *p1; + while (Compare16Bits(p1, &savestate) == 0 && p1 <= statelists[0].tail.sltail) { + *p3 = *p1; + lfsr_rollback_word(p3, statelists[0].nt_enc ^ statelists[0].uid, 0); + p3++; + p1++; + } + } + + p3->odd = -1; + p3->even = -1; + statelists[0].len = p3 - statelists[0].head.slhead; + statelists[0].tail.sltail = --p3; + } + else { // fast decrypt static nested + + PrintAndLogEx(SUCCESS, "Fast staticnested decrypt running..."); + + for (uint8_t i = 0; i < 2; i++) { + statelists[i].blockNo = package->block; + statelists[i].keyType = package->keytype; + statelists[i].uid = uid; + } + + dist += 160; + + uint32_t ntp_2 = prng_successor(nt1_2, dist); + uint32_t ks1_2 = nt2_2 ^ ntp_2; + + memcpy(&statelists[0].nt_enc, &ntp_1, sizeof(ntp_1)); + memcpy(&statelists[0].ks1, &ks1_1, sizeof(ks1_1)); + + memcpy(&statelists[1].nt_enc, &ntp_2, sizeof(ntp_2)); + memcpy(&statelists[1].ks1, &ks1_2, sizeof(ks1_2)); + + // calc keys + pthread_t thread_id[2]; + + // create and run worker threads + for (uint8_t i = 0; i < 2; i++) + pthread_create(thread_id + i, NULL, nested_worker_thread, &statelists[i]); + + // wait for threads to terminate: + for (uint8_t i = 0; i < 2; i++) + pthread_join(thread_id[i], (void*)&statelists[i].head.slhead); + + // the first 16 Bits of the cryptostate already contain part of our key. + // Create the intersection of the two lists based on these 16 Bits and + // roll back the cryptostate + p1 = p3 = statelists[0].head.slhead; + p2 = p4 = statelists[1].head.slhead; + + while (p1 <= statelists[0].tail.sltail && p2 <= statelists[1].tail.sltail) { + if (Compare16Bits(p1, p2) == 0) { + + struct Crypto1State savestate; + savestate = *p1; + while (Compare16Bits(p1, &savestate) == 0 && p1 <= statelists[0].tail.sltail) { + *p3 = *p1; + lfsr_rollback_word(p3, statelists[0].nt_enc ^ statelists[0].uid, 0); + p3++; + p1++; + } + savestate = *p2; + while (Compare16Bits(p2, &savestate) == 0 && p2 <= statelists[1].tail.sltail) { + *p4 = *p2; + lfsr_rollback_word(p4, statelists[1].nt_enc ^ statelists[1].uid, 0); + p4++; + p2++; + } + } + else { + while (Compare16Bits(p1, p2) == -1) p1++; + while (Compare16Bits(p1, p2) == 1) p2++; + } + } + + p3->odd = -1; + p3->even = -1; + p4->odd = -1; + p4->even = -1; + statelists[0].len = p3 - statelists[0].head.slhead; + statelists[1].len = p4 - statelists[1].head.slhead; + statelists[0].tail.sltail = --p3; + statelists[1].tail.sltail = --p4; + + // the statelists now contain possible keys. The key we are searching for must be in the + // intersection of both lists + 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); + // Create the intersection + statelists[0].len = intersection(statelists[0].head.keyhead, statelists[1].head.keyhead); + } uint32_t keycnt = statelists[0].len; if (keycnt == 0) goto out; @@ -667,43 +785,28 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl PrintAndLogEx(SUCCESS, "Found " _YELLOW_("%u") " key candidates", keycnt); memset(resultKey, 0, 6); + uint64_t key64 = -1; // The list may still contain several key candidates. Test each of them with mfCheckKeys uint32_t maxkeysinblock = IfPm3Flash() ? 1000 : KEYS_IN_BLOCK; uint32_t max_keys_chunk = keycnt > maxkeysinblock ? maxkeysinblock : keycnt; - uint8_t *mem = NULL; - uint8_t *p_keyblock = NULL; - - if (IfPm3Flash()) { - - // used for mfCheckKeys_file, which needs a header - mem = calloc((maxkeysinblock * 6) + 5, sizeof(uint8_t)); - if (mem == NULL) { - free(statelists[0].head.slhead); - return PM3_EMALLOC; - } - - mem[0] = statelists[0].keyType; - mem[1] = statelists[0].blockNo; - mem[2] = 1; - mem[3] = ((max_keys_chunk >> 8) & 0xFF); - mem[4] = (max_keys_chunk & 0xFF); - - p_keyblock = mem + 5; - } else { - - // used for mfCheckKeys, which adds its own header. - mem = calloc((maxkeysinblock * 6), sizeof(uint8_t)); - if (mem == NULL) { - free(statelists[0].head.slhead); - return PM3_EMALLOC; - } - p_keyblock = mem; + uint8_t* mem = calloc((maxkeysinblock * 6) + 5, sizeof(uint8_t)); + if (mem == NULL) { + free(statelists[0].head.slhead); + return PM3_EMALLOC; } + mem[0] = statelists[0].keyType; + mem[1] = statelists[0].blockNo; + mem[2] = 1; + mem[3] = ((max_keys_chunk >> 8) & 0xFF); + mem[4] = (max_keys_chunk & 0xFF); + + uint8_t* p_keyblock = mem + 5; + uint8_t destfn[32]; - strncpy((char *)destfn, "static_nested_000.bin", sizeof(destfn) - 1); + strncpy((char*)destfn, "static_nested_000.bin", sizeof(destfn) - 1); uint64_t start_time = msclock(); for (uint32_t i = 0; i < keycnt; i += max_keys_chunk) { @@ -717,8 +820,7 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl } int res = 0; - uint64_t key64 = 0; - + key64 = 0; uint32_t chunk = keycnt - i > max_keys_chunk ? max_keys_chunk : keycnt - i; // copy x keys to device. @@ -728,21 +830,22 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl } // check a block of generated key candidates. - if (IfPm3Flash()) { + if (IfPm3Flash() && keycnt > 10) { mem[3] = ((chunk >> 8) & 0xFF); mem[4] = (chunk & 0xFF); // upload to flash. - res = flashmem_spiffs_load((char *)destfn, mem, 5 + (chunk * 6)); + res = flashmem_spiffs_load((char*)destfn, mem, 5 + (chunk * 6)); if (res != PM3_SUCCESS) { PrintAndLogEx(WARNING, "\nSPIFFS upload failed"); free(mem); return res; } res = mfCheckKeys_file(destfn, &key64); - } else { - res = mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, true, chunk, mem, &key64); + } + else { + res = mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, false, chunk, p_keyblock, &key64); } if (res == PM3_SUCCESS) { @@ -753,13 +856,14 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl num_to_bytes(key64, 6, resultKey); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "target block: %3u key type: %c -- found valid key [ " _GREEN_("%s") " ]", - package->block, - package->keytype ? 'B' : 'A', - sprint_hex_inrow(resultKey, 6) - ); + PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]", + package->block, + package->keytype ? 'B' : 'A', + sprint_hex(resultKey, 6) + ); return PM3_SUCCESS; - } else if (res == PM3_ETIMEOUT || res == PM3_EOPABORTED) { + } + else if (res == PM3_ETIMEOUT || res == PM3_EOPABORTED) { PrintAndLogEx(NORMAL, ""); free(mem); return res; @@ -773,12 +877,17 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl free(mem); out: - PrintAndLogEx(SUCCESS, "\ntarget block: %3u key type: %c", - package->block, - package->keytype ? 'B' : 'A' - ); + PrintAndLogEx(SUCCESS, "\ntarget block:%3u key type: %c", + package->block, + package->keytype ? 'B' : 'A' + ); free(statelists[0].head.slhead); + + if (level != 0) { + free(statelists[1].head.slhead); + } + return PM3_ESOFT; }