diff --git a/src/cmdhfmfhard.c b/src/cmdhfmfhard.c index c5f792c..e58e258 100644 --- a/src/cmdhfmfhard.c +++ b/src/cmdhfmfhard.c @@ -169,89 +169,28 @@ uint8_t block_to_sector(uint8_t block) { return 32 + (block >> 4); } - -#ifdef X86_SIMD -static void get_SIMD_instruction_set(char *instruction_set) { - switch (GetSIMDInstr()) { - case SIMD_AVX512: - strcpy(instruction_set, "AVX512F"); - break; - case SIMD_AVX2: - strcpy(instruction_set, "AVX2"); - break; - case SIMD_AVX: - strcpy(instruction_set, "AVX"); - break; - case SIMD_SSE2: - strcpy(instruction_set, "SSE2"); - break; - default: - printf("\nThis program requires at least an SSE2 capable CPU. Exiting...\n"); - exit(4); - } -} - - -static void print_progress_header(void) { - char progress_text[80]; - char instr_set[12] = {0}; - get_SIMD_instruction_set(instr_set); - sprintf(progress_text, "Start using %d threads and %s SIMD core", num_CPUs(), instr_set); -#else -static void print_progress_header(void) { - char progress_text[80]; - sprintf(progress_text, "Start using %d threads", num_CPUs()); -#endif - - static uint8_t keyType; - if (targetKEY == MC_AUTH_A) { - keyType = 'A'; - } else if (targetKEY == MC_AUTH_B) { - keyType = 'B'; +static pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER; +void hardnested_print_progress(char *activity) { + // pthread_mutex_init(&print_lock, NULL); + // lock this section to avoid interlacing prints from different threads + // pthread_mutex_lock(&print_lock); + fprintf(stdout, "\33[2K\rSector: %d, type %c, %s", block_to_sector(targetBLOCK), (targetKEY == MC_AUTH_A ? 'A' : 'B'), activity); + fflush(stdout); + // pthread_mutex_unlock(&print_lock); +} + +void format_time(char *out, size_t n, uint32_t time) { + if (time < 90) { + snprintf(out, n, "%ds", time); + } else if (time < 60 * 90) { + snprintf(out, n, "%2.0fmin", (float)time / 60); + } else if (time < 60 * 60 * 36) { + snprintf(out, n, "%2.0fh", (float)time / (60 * 60)); } else { - keyType = '?'; - } - - - PrintAndLog(true, "\n\n"); - PrintAndLog(true, " time | trg | #nonces | Activity | expected to brute force"); - PrintAndLog(true, " | | | | #states | time "); - PrintAndLog(true, "-------------------------------------------------------------------------------------------------------------"); - PrintAndLog(true, " 0 | %2d%c | 0 | %-55s | |", block_to_sector(targetBLOCK), keyType, progress_text); -} - - -void hardnested_print_progress(uint32_t nonces, char *activity, float brute_force, uint64_t min_diff_print_time, uint8_t trgKeyBlock, uint8_t trgKeyType, bool newline) { - static uint64_t last_print_time = 0; - static uint8_t keyType; - if (msclock() - last_print_time > min_diff_print_time) { - last_print_time = msclock(); - uint64_t total_time = msclock() - start_time; - float brute_force_time = brute_force / brute_force_per_second; - char brute_force_time_string[20]; - if (brute_force_time < 90) { - sprintf(brute_force_time_string, "%2.0fs", brute_force_time); - } else if (brute_force_time < 60 * 90) { - sprintf(brute_force_time_string, "%2.0fmin", brute_force_time / 60); - } else if (brute_force_time < 60 * 60 * 36) { - sprintf(brute_force_time_string, "%2.0fh", brute_force_time / (60 * 60)); - } else { - sprintf(brute_force_time_string, "%2.0fd", brute_force_time / (60 * 60 * 24)); - } - - if (trgKeyType == MC_AUTH_A) { - keyType = 'A'; - } else if (trgKeyType == MC_AUTH_B) { - keyType = 'B'; - } else { - keyType = '?'; - } - - PrintAndLog(newline, " %7.0f | %2d%c | %7d | %-55s | %15.0f | %5s", (float) total_time / 1000.0, block_to_sector(trgKeyBlock), keyType, nonces, activity, brute_force, brute_force_time_string); + snprintf(out, n, "%2.0fd", (float)time / (60 * 60 * 24)); } } - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // bitarray functions @@ -367,9 +306,6 @@ static void init_bitflip_bitarrays(void) { } qsort(all_effective_bitflip, num_1st_byte_effective_bitflips, sizeof(uint16_t), compare_count_bitflip_bitarrays); qsort(all_effective_bitflip + num_1st_byte_effective_bitflips, num_all_effective_bitflips - num_1st_byte_effective_bitflips, sizeof(uint16_t), compare_count_bitflip_bitarrays); - char progress_text[80]; - sprintf(progress_text, "Using %d precalculated bitflip state tables", num_all_effective_bitflips); - hardnested_print_progress(0, progress_text, (float) (1LL << 47), 0, targetBLOCK, targetKEY, true); } @@ -880,46 +816,6 @@ static float sort_best_first_bytes(void) { return nonces[best_first_bytes[0]].expected_num_brute_force; } - -static float update_reduction_rate(float last, bool init) { - static float queue[QUEUE_LEN]; - - for (uint16_t i = 0; i < QUEUE_LEN - 1; i++) { - if (init) { - queue[i] = (float)(1LL << 48); - } else { - queue[i] = queue[i + 1]; - } - } - if (init) { - queue[QUEUE_LEN - 1] = (float)(1LL << 48); - } else { - queue[QUEUE_LEN - 1] = last; - } - - // linear regression - float avg_y = 0.0; - float avg_x = 0.0; - for (uint16_t i = 0; i < QUEUE_LEN; i++) { - avg_x += i; - avg_y += queue[i]; - } - avg_x /= QUEUE_LEN; - avg_y /= QUEUE_LEN; - - float dev_xy = 0.0; - float dev_x2 = 0.0; - for (uint16_t i = 0; i < QUEUE_LEN; i++) { - dev_xy += (i - avg_x) * (queue[i] - avg_y); - dev_x2 += (i - avg_x) * (i - avg_x); - } - - float reduction_rate = -1.0 * dev_xy / dev_x2; // the negative slope of the linear regression - - return reduction_rate; -} - - static bool shrink_key_space(float *brute_forces) { float brute_forces1 = check_smallest_bitflip_bitarrays(); float brute_forces2 = (float)(1LL << 47); @@ -927,11 +823,16 @@ static bool shrink_key_space(float *brute_forces) { brute_forces2 = sort_best_first_bytes(); } *brute_forces = MIN(brute_forces1, brute_forces2); - float reduction_rate = update_reduction_rate(*brute_forces, false); + if (brute_forces2 != brute_forces2) { // is nan + *brute_forces = brute_forces1; + } - return ((hardnested_stage & CHECK_2ND_BYTES) && - reduction_rate >= 0.0 && - (reduction_rate < brute_force_per_second * (float)sample_period / 1000.0 || *brute_forces < 0xF00000)); + // Start brute force when remaining time < acquisition time + return (hardnested_stage & CHECK_2ND_BYTES) && ( + *brute_forces / brute_force_per_second < sample_period * num_acquired_nonces / 1000 + || *brute_forces < 0xF00000 + || num_acquired_nonces > 9000 + ); } @@ -1123,6 +1024,7 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_ bool acquisition_completed = false; float brute_force; bool reported_suma8 = false; + char remaining[10]; num_acquired_nonces = 0; @@ -1130,7 +1032,8 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_ int a_sector = block_to_sector(trgBlockNo); pKeys pk = {NULL, 0}; bool dumpKeysA = (trgKeyType == MC_AUTH_A ? true : false); - // + char progress_string[80]; + uint32_t enc_bytes = 0; uint8_t parbits = 0; do { @@ -1155,19 +1058,16 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_ } update_nonce_data(true); acquisition_completed = shrink_key_space(&brute_force); - if (!reported_suma8) { - char progress_string[80]; - sprintf(progress_string, "Apply Sum property. Sum(a0) = %d", sums[first_byte_Sum]); - hardnested_print_progress(num_acquired_nonces, progress_string, brute_force, 0, trgBlockNo, trgKeyType, true); - reported_suma8 = true; - } else { - hardnested_print_progress(num_acquired_nonces, "Apply bit flip properties", brute_force, 0, trgBlockNo, trgKeyType, false); - } + } + if (hardnested_stage & CHECK_2ND_BYTES) { + format_time(remaining, sizeof(remaining), brute_force / brute_force_per_second); + snprintf(progress_string, sizeof(progress_string), "acquiring more nonces, %d, remaining bruteforce time %s", num_acquired_nonces, remaining); } else { - update_nonce_data(true); - acquisition_completed = shrink_key_space(&brute_force); - hardnested_print_progress(num_acquired_nonces, "Apply bit flip properties", brute_force, 0, trgBlockNo, trgKeyType, false); + // Make progress meter more monotonic + float progress = (1 - log2(256 - first_byte_num + 1) / 8) * 100; + snprintf(progress_string, sizeof(progress_string), "acquiring nonces, %d (%d%%)", num_acquired_nonces, (int)progress); } + hardnested_print_progress(progress_string); if (msclock() - last_sample_clock < sample_period) { sample_period = msclock() - last_sample_clock; @@ -1272,7 +1172,7 @@ static inline bool bitflips_match(uint8_t byte, uint32_t state, odd_even_t odd_e if (!possible) { if (!quiet && known_target_key != -1 && state == test_state[odd_even]) { printf("Initial state lists: %s test state eliminated by bitflip property.\n", odd_even == EVEN_STATE ? "even" : "odd"); - sprintf(failstr, "Initial %s Byte Bitflip property", odd_even == EVEN_STATE ? "even" : "odd"); + snprintf(failstr, sizeof(failstr), "Initial %s Byte Bitflip property", odd_even == EVEN_STATE ? "even" : "odd"); } return false; } @@ -1312,7 +1212,7 @@ static bool all_bitflips_match(uint8_t byte, uint32_t state, odd_even_t odd_even test_state[odd_even], byte, byte2, num_common); if (failstr[0] == '\0') { - sprintf(failstr, "Other 1st Byte %s, all_bitflips_match(), no match", odd_even ? "odd" : "even"); + snprintf(failstr, sizeof(failstr), "Other 1st Byte %s, all_bitflips_match(), no match", odd_even ? "odd" : "even"); } } return false; @@ -1457,14 +1357,14 @@ static bool TestIfKeyExists(uint64_t key) { } if (found_odd && found_even) { num_keys_tested += count; - hardnested_print_progress(num_acquired_nonces, "(Test: Key found)", 0.0, 0, targetBLOCK, targetKEY, true); + hardnested_print_progress("(Test: Key found)"); crypto1_destroy(pcs); return true; } } num_keys_tested += count; - hardnested_print_progress(num_acquired_nonces, "(Test: Key NOT found)", 0.0, 0, targetBLOCK, targetKEY, true); + hardnested_print_progress("(Test: Key NOT found)"); crypto1_destroy(pcs); return false; @@ -1653,7 +1553,6 @@ static void generate_candidates(uint8_t sum_a0_idx, uint8_t sum_a8_idx) { free(sums); update_expected_brute_force(best_first_bytes[0]); - hardnested_print_progress(num_acquired_nonces, "Apply Sum(a8) and all bytes bitflip properties", nonces[best_first_bytes[0]].expected_num_brute_force, 0, targetBLOCK, targetKEY, true); } @@ -1768,28 +1667,18 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc hard_LOW_MEM = hard_low_memory; char progress_text[80]; + char remaining[10]; cuid = t.authuid; -#ifdef X86_SIMD - char instr_set[12] = {0}; - get_SIMD_instruction_set(instr_set); - PrintAndLog(true, "Using %s SIMD core.", instr_set); -#endif - srand((unsigned) time(NULL)); brute_force_per_second = brute_force_benchmark(); write_stats = false; start_time = msclock(); - print_progress_header(); - sprintf(progress_text, "Brute force benchmark: %1.0f million (2^%1.1f) keys/s", brute_force_per_second / 1000000, log(brute_force_per_second) / log(2.0)); - hardnested_print_progress(0, progress_text, (float) (1LL << 47), 0, targetBLOCK, targetKEY, true); init_bitflip_bitarrays(); -// exit(0); init_part_sum_bitarrays(); init_sum_bitarrays(); init_allbitflips_array(); init_nonce_memory(); - update_reduction_rate(0.0, true); uint16_t is_OK = acquire_nonces(blockNo, keyType, key, trgBlockNo, trgKeyType); if (is_OK != 0) { @@ -1813,8 +1702,9 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc uint32_t num_even = nonces[best_first_byte_smallest_bitarray].num_states_bitarray[EVEN_STATE]; float expected_brute_force1 = (float) num_odd * num_even / 2.0; float expected_brute_force2 = nonces[best_first_bytes[0]].expected_num_brute_force; - if (expected_brute_force1 < expected_brute_force2) { - hardnested_print_progress(num_acquired_nonces, "(Ignoring Sum(a8) properties)", expected_brute_force1, 0, trgBlockNo, trgKeyType, true); + if (expected_brute_force1 < expected_brute_force2 + || expected_brute_force2 != expected_brute_force2 // is nan + ) { set_test_state(best_first_byte_smallest_bitarray); add_bitflip_candidates(best_first_byte_smallest_bitarray); Tests2(); @@ -1825,7 +1715,9 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc best_first_bytes[0] = best_first_byte_smallest_bitarray; pre_XOR_nonces(); prepare_bf_test_nonces(nonces, best_first_bytes[0]); - hardnested_print_progress(num_acquired_nonces, "Starting brute force...", expected_brute_force1, 0, trgBlockNo, trgKeyType, true); + format_time(remaining, sizeof(remaining), expected_brute_force1 / brute_force_per_second); + snprintf(progress_text, sizeof(progress_text), "starting brute force, remaining %s", remaining); + hardnested_print_progress(progress_text); brute_force(trgBlockNo, trgKeyType); free(candidates->states[ODD_STATE]); free(candidates->states[EVEN_STATE]); @@ -1836,10 +1728,10 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc prepare_bf_test_nonces(nonces, best_first_bytes[0]); for (uint8_t j = 0; j < NUM_SUMS && !key_found; j++) { float expected_brute_force = nonces[best_first_bytes[0]].expected_num_brute_force; - sprintf(progress_text, "(%d. guess: Sum(a8) = %" PRIu16 ")", j + 1, sums[nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx]); - hardnested_print_progress(num_acquired_nonces, progress_text, expected_brute_force, 0, trgBlockNo, trgKeyType, true); + format_time(remaining, sizeof(remaining), expected_brute_force / brute_force_per_second); + snprintf(progress_text, sizeof(progress_text), "starting brute force (%d. guess: Sum(a8) = %d), remaining %s", j + 1, sums[nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx], remaining); + hardnested_print_progress(progress_text); generate_candidates(first_byte_Sum, nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx); - hardnested_print_progress(num_acquired_nonces, "Starting brute force...", expected_brute_force, 0, trgBlockNo, trgKeyType, true); key_found = brute_force(trgBlockNo, trgKeyType); free_statelist_cache(); free_candidates_memory(candidates); @@ -1854,6 +1746,9 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc } } + fprintf(stdout, "\n"); + fflush(stdout); + free_nonces_memory(); free_bitarray(all_bitflips_bitarray[ODD_STATE]); free_bitarray(all_bitflips_bitarray[EVEN_STATE]); diff --git a/src/cmdhfmfhard.h b/src/cmdhfmfhard.h index 9ac2e49..1b26d43 100644 --- a/src/cmdhfmfhard.h +++ b/src/cmdhfmfhard.h @@ -54,7 +54,7 @@ typedef struct noncelist { } noncelist_t; int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, bool hard_low_memory); -void hardnested_print_progress(uint32_t nonces, char *activity, float brute_force, uint64_t min_diff_print_time, uint8_t trgKeyBlock, uint8_t trgKeyType, bool newline); +void hardnested_print_progress(char *activity); uint8_t block_to_sector(uint8_t block); #endif diff --git a/src/hardnested/hardnested_bruteforce.c b/src/hardnested/hardnested_bruteforce.c index 864576d..d024d45 100644 --- a/src/hardnested/hardnested_bruteforce.c +++ b/src/hardnested/hardnested_bruteforce.c @@ -151,7 +151,7 @@ crack_states_thread(void* x) { if (key != -1) { __sync_fetch_and_add(&keys_found, 1); char progress_text[80]; - sprintf(progress_text, "Brute force phase completed. Key found: %012" PRIx64, key); + sprintf(progress_text, "brute force phase completed"); if (thread_arg->trgKey == MC_AUTH_A){ t.sectors[block_to_sector(thread_arg->trgBlock)].foundKeyA = true; num_to_bytes(key, 6, t.sectors[block_to_sector(thread_arg->trgBlock)].KeyA); @@ -159,16 +159,16 @@ crack_states_thread(void* x) { t.sectors[block_to_sector(thread_arg->trgBlock)].foundKeyB = true; num_to_bytes(key, 6, t.sectors[block_to_sector(thread_arg->trgBlock)].KeyB); } - hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, 0.0, 0, thread_arg->trgBlock, thread_arg->trgKey, true); + hardnested_print_progress(progress_text); break; } else if (keys_found) { break; } else { if (!thread_arg->silent) { char progress_text[80]; - sprintf(progress_text, "Brute force phase: %6.02f%%", 100.0 * (float) num_keys_tested / (float) (thread_arg->maximum_states)); + sprintf(progress_text, "brute force phase: %6.02f%%", 100.0 * (float) num_keys_tested / (float) (thread_arg->maximum_states)); float remaining_bruteforce = thread_arg->nonces[thread_arg->best_first_bytes[0]].expected_num_brute_force - (float) num_keys_tested / 2; - hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, remaining_bruteforce, 5000, thread_arg->trgBlock, thread_arg->trgKey, true); + hardnested_print_progress(progress_text); } } } @@ -348,7 +348,6 @@ float brute_force_benchmark() { test_candidates[num_core - 1].next = NULL; if (!read_bench_data(test_candidates)) { - PrintAndLog(true, "Couldn't read benchmark data. Assuming brute force rate of %1.0f states per second", DEFAULT_BRUTE_FORCE_RATE); return DEFAULT_BRUTE_FORCE_RATE; } diff --git a/src/mfoc.c b/src/mfoc.c index b6d8f96..08e91a9 100644 --- a/src/mfoc.c +++ b/src/mfoc.c @@ -162,7 +162,7 @@ int main(int argc, char *const argv[]) struct slre_cap caps[2]; // Parse command line arguments - while ((ch = getopt(argc, argv, "hCZFP:T:O:k:f:")) != -1) { + while ((ch = getopt(argc, argv, "hCZBFP:T:O:k:f:")) != -1) { switch (ch) { case 'C': use_default_key=false; @@ -241,8 +241,11 @@ int main(int argc, char *const argv[]) } // fprintf(stdout, "Output file: %s\n", optarg); break; + case 'B': + dumpKeysA = false; + break; case 'h': - usage(stdout, 0); + usage(stderr, 0); break; default: usage(stderr, 1); @@ -278,11 +281,13 @@ int main(int argc, char *const argv[]) t.authuid = (uint32_t) bytes_to_num(t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, 4); // Get Mifare Classic type from SAK - // see http://www.nxp.com/documents/application_note/AN10833.pdf Section 3.2 + // see https://www.nxp.com/docs/en/application-note/AN10833.pdf Section 3.2 + // and https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/nfc/tech/MifareClassic.java switch (t.nt.nti.nai.btSak) { case 0x01: case 0x08: + case 0x10: case 0x88: case 0x28: if (get_rats_is_2k(t, r)) { @@ -300,7 +305,11 @@ int main(int argc, char *const argv[]) t.num_sectors = NR_TRAILERS_MINI; t.num_blocks = NR_BLOCKS_MINI; break; + case 0x11: case 0x18: + case 0x38: + case 0x98: + case 0xB8: printf("Found Mifare Classic 4k tag\n"); t.num_sectors = NR_TRAILERS_4k; t.num_blocks = NR_BLOCKS_4k; @@ -342,45 +351,6 @@ int main(int argc, char *const argv[]) fprintf(stdout, "\nTry to authenticate to all sectors with default keys...\n"); fprintf(stdout, "Symbols: '.' no key found, '/' A key found, '\\' B key found, 'x' both keys found\n"); - // Set the authentication information (uid) - bool did_hardnested=false; - check_keys: - if (did_hardnested) { - use_default_key=false; - printf("\nChecking for key reuse...\n"); - defKeys_len=0; - defKeys = NULL; - for (int i=0;ipossibleKeys = NULL; + pk->size = 0; + // We have 'sets' * 32b keystream of potential keys + for (n = 0; n < sets; n++) { + // AUTH + Recovery key mode (for a_sector), repeat 5 times + mf_enhanced_auth(e_sector, t.sectors[j].trailer, t, r, &d, pk, 'r', dumpKeysA, 0, 0); mf_configure(r.pdi); mf_anticollision(t, r); - - pk->possibleKeys = NULL; - pk->size = 0; - // We have 'sets' * 32b keystream of potential keys - for (n = 0; n < sets; n++) { - // AUTH + Recovery key mode (for a_sector), repeat 5 times - mf_enhanced_auth(e_sector, t.sectors[j].trailer, t, r, &d, pk, 'r', dumpKeysA, 0, 0); - mf_configure(r.pdi); - mf_anticollision(t, r); - fprintf(stdout, "."); - fflush(stdout); - } - fprintf(stdout, "\n"); - // Get first 15 grouped keys - ck = uniqsort(pk->possibleKeys, pk->size); - for (i = 0; i < TRY_KEYS ; i++) { - // We don't known this key, try to break it - // This key can be found here two or more times - if (ck[i].count > 0) { - // fprintf(stdout,"%d %llx\n",ck[i].count, ck[i].key); - // Set required authetication method - num_to_bytes(ck[i].key, 6, mp.mpa.abtKey); - mc = dumpKeysA ? MC_AUTH_A : MC_AUTH_B; - int res; - if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, t.sectors[j].trailer, &mp)) < 0) { - if (res != NFC_EMFCAUTHFAIL) { - nfc_perror(r.pdi, "nfc_initiator_mifare_cmd"); - goto error; - } - mf_anticollision(t, r); + fprintf(stdout, "."); + fflush(stdout); + } + fprintf(stdout, "\n"); + // Get first 15 grouped keys + ck = uniqsort(pk->possibleKeys, pk->size); + for (i = 0; i < TRY_KEYS ; i++) { + // We don't known this key, try to break it + // This key can be found here two or more times + if (ck[i].count > 0) { + // fprintf(stdout,"%d %llx\n",ck[i].count, ck[i].key); + // Set required authetication method + num_to_bytes(ck[i].key, 6, mp.mpa.abtKey); + mc = dumpKeysA ? MC_AUTH_A : MC_AUTH_B; + int res; + if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, t.sectors[j].trailer, &mp)) < 0) { + if (res != NFC_EMFCAUTHFAIL) { + nfc_perror(r.pdi, "nfc_initiator_mifare_cmd"); + goto error; + } + mf_anticollision(t, r); + } else { + if (dumpKeysA) { + memcpy(t.sectors[j].KeyA, mp.mpa.abtKey, 6); + t.sectors[j].foundKeyA = true; } else { - // Save all information about successfull authentization - bk->size++; - bk->brokenKeys = (uint64_t *) realloc((void *)bk->brokenKeys, bk->size * sizeof(uint64_t)); - bk->brokenKeys[bk->size - 1] = bytes_to_num(mp.mpa.abtKey, sizeof(mp.mpa.abtKey)); - if (dumpKeysA) { - memcpy(t.sectors[j].KeyA, mp.mpa.abtKey, sizeof(mp.mpa.abtKey)); - t.sectors[j].foundKeyA = true; - - } else { - memcpy(t.sectors[j].KeyB, mp.mpa.abtKey, sizeof(mp.mpa.abtKey)); - t.sectors[j].foundKeyB = true; - } - fprintf(stdout, " Found Key: %c [%012llx]\n", (dumpKeysA ? 'A' : 'B'), - bytes_to_num(mp.mpa.abtKey, 6)); - // if we need KeyB for this sector, it should be revealed by a data read with KeyA - if (!t.sectors[j].foundKeyB) { - if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_READ, t.sectors[j].trailer, &mtmp)) >= 0) { - fprintf(stdout, " Data read with Key A revealed Key B: [%012llx] - checking Auth: ", bytes_to_num(mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey))); - memcpy(mtmp.mpa.abtKey, mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey)); - memcpy(mtmp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mtmp.mpa.abtAuthUid)); - if ((nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, t.sectors[j].trailer, &mtmp)) < 0) { - fprintf(stdout, "Failed!\n"); - mf_configure(r.pdi); - mf_anticollision(t, r); - } else { - fprintf(stdout, "OK\n"); - memcpy(t.sectors[j].KeyB, mtmp.mpd.abtData + 10, sizeof(t.sectors[j].KeyB)); - t.sectors[j].foundKeyB = true; - bk->size++; - bk->brokenKeys = (uint64_t *) realloc((void *)bk->brokenKeys, bk->size * sizeof(uint64_t)); - bk->brokenKeys[bk->size - 1] = bytes_to_num(mtmp.mpa.abtKey, sizeof(mtmp.mpa.abtKey)); - } - } else { - if (res != NFC_ERFTRANS) { - nfc_perror(r.pdi, "nfc_initiator_mifare_cmd"); - goto error; - } - mf_anticollision(t, r); - } - } - mf_configure(r.pdi); - mf_anticollision(t, r); - break; + memcpy(t.sectors[j].KeyB, mp.mpa.abtKey, 6); + t.sectors[j].foundKeyB = true; } + keyFound = true; + break; } } - free(pk->possibleKeys); - free(ck); - // Success, try the next sector - if ((dumpKeysA && t.sectors[j].foundKeyA) || (!dumpKeysA && t.sectors[j].foundKeyB)) break; } + free(pk->possibleKeys); + free(ck); + // Success, try the next sector + if (keyFound) break; + } + if (!keyFound) { + ERR("No success, maybe you should increase the probes"); + goto error; + } } - // We haven't found any key, exiting - if ((dumpKeysA && !t.sectors[j].foundKeyA) || (!dumpKeysA && !t.sectors[j].foundKeyB)) { - ERR("No success, maybe you should increase the probes"); - goto error; + + if (keyFound) { + // Save all information about successfull authentization + uint64_t key = bytes_to_num(dumpKeysA ? t.sectors[j].KeyA : t.sectors[j].KeyB, 6); + bk->size++; + bk->brokenKeys = (uint64_t *) realloc((void *)bk->brokenKeys, bk->size * sizeof(uint64_t)); + bk->brokenKeys[bk->size - 1] = key; + fprintf(stdout, " Found Key: %c [%012llx]\n", (dumpKeysA ? 'A' : 'B'), key); + // if we need KeyB for this sector, it should be revealed by a data read with KeyA + if (!t.sectors[j].foundKeyB) { + int res; + if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_READ, t.sectors[j].trailer, &mtmp)) >= 0) { + fprintf(stdout, " Data read with Key A revealed Key B: [%012llx] - checking Auth: ", bytes_to_num(mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey))); + memcpy(mtmp.mpa.abtKey, mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey)); + memcpy(mtmp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mtmp.mpa.abtAuthUid)); + if ((nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, t.sectors[j].trailer, &mtmp)) < 0) { + fprintf(stdout, "Failed!\n"); + mf_configure(r.pdi); + mf_anticollision(t, r); + } else { + fprintf(stdout, "OK\n"); + memcpy(t.sectors[j].KeyB, mtmp.mpd.abtData + 10, sizeof(t.sectors[j].KeyB)); + t.sectors[j].foundKeyB = true; + bk->size++; + bk->brokenKeys = (uint64_t *) realloc((void *)bk->brokenKeys, bk->size * sizeof(uint64_t)); + bk->brokenKeys[bk->size - 1] = bytes_to_num(mtmp.mpa.abtKey, sizeof(mtmp.mpa.abtKey)); + } + } else { + if (res != NFC_ERFTRANS) { + nfc_perror(r.pdi, "nfc_initiator_mifare_cmd"); + goto error; + } + mf_anticollision(t, r); + } + } } } } - dumpKeysA = false; + dumpKeysA = !dumpKeysA; } @@ -820,6 +791,7 @@ void usage(FILE *stream, uint8_t errnr) fprintf(stream, " P number of probes per sector, instead of default of 20\n"); fprintf(stream, " T nonce tolerance half-range, instead of default of 20\n (i.e., 40 for the total range, in both directions)\n"); fprintf(stream, " O file in which the card contents will be written\n"); + fprintf(stream, " B extract B keys first\n"); fprintf(stream, "\n"); fprintf(stream, "Example: mfoc-hardnested -O mycard.mfd\n"); fprintf(stream, "Example: mfoc-hardnested -k ffffeeeedddd -O mycard.mfd\n"); @@ -1137,8 +1109,8 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d // Make sure the card is using the known PRNG if (! validate_prng_nonce(NtLast)) { - printf("Card is not vulnerable to nested attack\n"); - return -99999; + // printf("Card is not vulnerable to nested attack\n"); + return -99999; } // Save the determined nonces distance d->distances[m] = nonce_distance(Nt, NtLast);