Improved error handling, naming, UI

This commit is contained in:
Aram
2016-05-03 04:39:34 +02:00
parent bd7aad29cd
commit 2cd2973cfa

View File

@ -1,4 +1,3 @@
// Almost entirely based on code from Mifare Offline Cracker (MFOC) by Nethemba, cheers guys! :)
// Copyright (C) 2016 Aram Verstegen // Copyright (C) 2016 Aram Verstegen
/* /*
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
@ -332,7 +331,14 @@ static nfc_context *context;
uint64_t *nonces = NULL; uint64_t *nonces = NULL;
size_t nonces_collected; size_t nonces_collected;
void nested_auth(uint32_t uid, uint64_t known_key, uint8_t ab_key, uint8_t for_block, uint8_t target_block, uint8_t target_key, FILE* fp) enum {
OK,
ERROR,
KEY_WRONG,
};
// Almost entirely based on code from Mifare Offline Cracker (MFOC) by Nethemba, cheers guys! :)
int nested_auth(uint32_t uid, uint64_t known_key, uint8_t ab_key, uint8_t for_block, uint8_t target_block, uint8_t target_key, FILE* fp)
{ {
uint64_t *pcs; uint64_t *pcs;
@ -358,24 +364,24 @@ void nested_auth(uint32_t uid, uint64_t known_key, uint8_t ab_key, uint8_t for_b
// We need full control over the CRC // We need full control over the CRC
if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) { if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) {
nfc_perror(pnd, "nfc_device_set_property_bool crc"); nfc_perror(pnd, "nfc_device_set_property_bool crc");
return; return ERROR;
} }
// Request plain tag-nonce // Request plain tag-nonce
// TODO: Set NP_EASY_FRAMING option only once if possible // TODO: Set NP_EASY_FRAMING option only once if possible
if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false) < 0) { if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false) < 0) {
nfc_perror(pnd, "nfc_device_set_property_bool framing"); nfc_perror(pnd, "nfc_device_set_property_bool framing");
return; return ERROR;
} }
if (nfc_initiator_transceive_bytes(pnd, Cmd, 4, Rx, sizeof(Rx), 0) < 0) { if (nfc_initiator_transceive_bytes(pnd, Cmd, 4, Rx, sizeof(Rx), 0) < 0) {
fprintf(stdout, "Error while requesting plain tag-nonce\n"); fprintf(stdout, "Error while requesting plain tag-nonce ");
return; return ERROR;
} }
if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, true) < 0) { if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, true) < 0) {
nfc_perror(pnd, "nfc_device_set_property_bool"); nfc_perror(pnd, "nfc_device_set_property_bool");
return; return ERROR;
} }
// Save the tag nonce (Nt) // Save the tag nonce (Nt)
@ -408,23 +414,23 @@ void nested_auth(uint32_t uid, uint64_t known_key, uint8_t ab_key, uint8_t for_b
// Finally we want to send arbitrary parity bits // Finally we want to send arbitrary parity bits
if (nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, false) < 0) { if (nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, false) < 0) {
nfc_perror(pnd, "nfc_device_set_property_bool parity"); nfc_perror(pnd, "nfc_device_set_property_bool parity ");
return; return 1;
} }
// Transmit reader-answer // Transmit reader-answer
int res; int res;
if (((res = nfc_initiator_transceive_bits(pnd, ArEnc, 64, ArEncPar, Rx, sizeof(Rx), RxPar)) < 0) || (res != 32)) { if (((res = nfc_initiator_transceive_bits(pnd, ArEnc, 64, ArEncPar, Rx, sizeof(Rx), RxPar)) < 0) || (res != 32)) {
fprintf(stderr, "Reader-answer transfer error, exiting.."); fprintf(stderr, "Reader-answer transfer error, exiting.. ");
return; return KEY_WRONG;
} }
// Decrypt the tag answer and verify that suc3(Nt) is At // Decrypt the tag answer and verify that suc3(Nt) is At
Nt = prng_successor(Nt, 32); Nt = prng_successor(Nt, 32);
if (!((crypto1_word(pcs, 0x00, 0) ^ bytes_to_num(Rx, 4)) == (Nt & 0xFFFFFFFF))) { if (!((crypto1_word(pcs, 0x00, 0) ^ bytes_to_num(Rx, 4)) == (Nt & 0xFFFFFFFF))) {
fprintf(stderr, "[At] is not Suc3(Nt), something is wrong, exiting.."); fprintf(stderr, "[At] is not Suc3(Nt), something is wrong, exiting.. ");
return; return ERROR;
} }
Cmd[0] = target_key; Cmd[0] = target_key;
@ -436,8 +442,8 @@ void nested_auth(uint32_t uid, uint64_t known_key, uint8_t ab_key, uint8_t for_b
ArEncPar[i] = filter(*pcs) ^ oddparity(Cmd[i]); ArEncPar[i] = filter(*pcs) ^ oddparity(Cmd[i]);
} }
if (((res = nfc_initiator_transceive_bits(pnd, ArEnc, 32, ArEncPar, Rx, sizeof(Rx), RxPar)) < 0) || (res != 32)) { if (((res = nfc_initiator_transceive_bits(pnd, ArEnc, 32, ArEncPar, Rx, sizeof(Rx), RxPar)) < 0) || (res != 32)) {
fprintf(stderr, "Reader-answer transfer error, exiting.."); fprintf(stderr, "Reader-answer transfer error, exiting.. ");
return; return ERROR;
} }
if(fp){ if(fp){
@ -462,10 +468,12 @@ void nested_auth(uint32_t uid, uint64_t known_key, uint8_t ab_key, uint8_t for_b
} }
crypto1_destroy(pcs); crypto1_destroy(pcs);
return OK;
} }
uint32_t uid; uint32_t uid;
uint32_t **space; uint32_t **space;
uint64_t found_key;
size_t thread_count; size_t thread_count;
size_t total_states; size_t total_states;
void* crack_states_thread(void* x){ void* crack_states_thread(void* x){
@ -474,13 +482,11 @@ void* crack_states_thread(void* x){
for(j = thread_id; space[j * 5]; j += thread_count) { for(j = thread_id; space[j * 5]; j += thread_count) {
const uint64_t key = crack_states_bitsliced(space + j * 5); const uint64_t key = crack_states_bitsliced(space + j * 5);
if(key != -1){ if(key != -1){
printf("Found key: %012"PRIx64"\n", key); found_key = key;
__sync_fetch_and_add(&keys_found, 1); __sync_fetch_and_add(&keys_found, 1);
break; break;
} else if(keys_found){ } else if(keys_found){
break; break;
} else {
printf("Cracking... %6.02f%%\n", (100.0*total_states_tested/(total_states)));
} }
} }
return NULL; return NULL;
@ -488,7 +494,7 @@ void* crack_states_thread(void* x){
bool stop_collection = false; bool stop_collection = false;
void * update_total_states_thread(void* p){ void * update_predictions_thread(void* p){
while(!stop_collection){ while(!stop_collection){
if(nonces && uid){ if(nonces && uid){
space = craptev1_get_space(nonces, 95, uid); space = craptev1_get_space(nonces, 95, uid);
@ -501,6 +507,33 @@ void * update_total_states_thread(void* p){
return NULL; return NULL;
} }
void notify_status_offline(int sig){
printf("\rCracking... %6.02f%%", (100.0*total_states_tested/(total_states)));
alarm(1);
fflush(stdout);
signal(SIGALRM, notify_status_offline);
}
void notify_status_online(int sig){
if(!space){
printf("\rCollected %zu nonces... ", nonces_collected);
} else {
printf("\rCollected %zu nonces... leftover complexity %zu (press enter to start brute-force phase)", nonces_collected, total_states);
}
if(total_states){
char c;
if(scanf("%c", &c) == 1 || total_states < 0x1000000000){
printf(" - initializing brute-force phase...\n");
alarm(0);
stop_collection = true;
return;
}
}
alarm(1);
fflush(stdout);
signal(SIGALRM, notify_status_online);
}
uint64_t known_key; uint64_t known_key;
uint8_t for_block; uint8_t for_block;
uint8_t ab_key; uint8_t ab_key;
@ -514,7 +547,7 @@ const nfc_modulation nmMifare = {
}; };
void * update_nonces_thread(void* v){ void * update_nonces_thread(void* v){
while(true){ while(!stop_collection){
// Configure the CRC and Parity settings // Configure the CRC and Parity settings
nfc_device_set_property_bool(pnd,NP_HANDLE_CRC,true); nfc_device_set_property_bool(pnd,NP_HANDLE_CRC,true);
nfc_device_set_property_bool(pnd,NP_HANDLE_PARITY,true); nfc_device_set_property_bool(pnd,NP_HANDLE_PARITY,true);
@ -525,29 +558,10 @@ void * update_nonces_thread(void* v){
printf("\rDon't move the tag!"); printf("\rDon't move the tag!");
fflush(stdout); fflush(stdout);
} }
if(total_states){
char c;
if(read(0, &c, 1) == 1 || total_states < 0x1000000000){
alarm(0);
stop_collection = true;
break;
}
}
} }
return NULL; return NULL;
} }
void have_enough_states(int sig){
if(!space){
printf("\rCollected %zu nonces... ", nonces_collected);
} else {
printf("\rCollected %zu nonces... leftover complexity %zu (press any key to start brute-force phase)", nonces_collected, total_states);
}
alarm(1);
fflush(stdout);
signal(SIGALRM, have_enough_states);
}
int main (int argc, const char * argv[]) { int main (int argc, const char * argv[]) {
nfc_init(&context); nfc_init(&context);
pnd = nfc_open(context, NULL); pnd = nfc_open(context, NULL);
@ -597,6 +611,10 @@ int main (int argc, const char * argv[]) {
if(argv[5][0] == 'b' || argv[5][0] == 'B'){ if(argv[5][0] == 'b' || argv[5][0] == 'B'){
target_key = MC_AUTH_B; target_key = MC_AUTH_B;
} }
if(nested_auth(uid, known_key, ab_key, for_block, target_block, target_key, NULL) == KEY_WRONG){
printf("This doesn't look like the right key.\n");
return 1;
}
char filename[21]; char filename[21];
sprintf(filename, "0x%04x_%03u%s.txt", uid, target_block, ab_key == MC_AUTH_A ? "A" : "B"); sprintf(filename, "0x%04x_%03u%s.txt", uid, target_block, ab_key == MC_AUTH_A ? "A" : "B");
@ -606,16 +624,16 @@ int main (int argc, const char * argv[]) {
nonces_collected = 0; nonces_collected = 0;
nonces = malloc(sizeof (uint64_t) << 24); nonces = malloc(sizeof (uint64_t) << 24);
memset(nonces, 0xff, sizeof (uint64_t) << 24); memset(nonces, 0xff, sizeof (uint64_t) << 24);
signal(SIGALRM, have_enough_states);
alarm(1);
fcntl(0, F_SETFL, O_NONBLOCK); fcntl(0, F_SETFL, O_NONBLOCK);
signal(SIGALRM, notify_status_online);
pthread_t state_counting_thread, nonce_gathering_thread; alarm(1);
pthread_t prediction_thread, nonce_gathering_thread;
pthread_create(&nonce_gathering_thread, NULL, update_nonces_thread, NULL); pthread_create(&nonce_gathering_thread, NULL, update_nonces_thread, NULL);
pthread_create(&state_counting_thread, NULL, update_total_states_thread, NULL); pthread_create(&prediction_thread, NULL, update_predictions_thread, NULL);
pthread_join(nonce_gathering_thread, 0); pthread_join(nonce_gathering_thread, 0);
pthread_join(state_counting_thread, 0); pthread_join(prediction_thread, 0);
alarm(0);
fclose(fp); fclose(fp);
nfc_close(pnd); nfc_close(pnd);
@ -625,7 +643,7 @@ int main (int argc, const char * argv[]) {
total_states = craptev1_sizeof_space(space); total_states = craptev1_sizeof_space(space);
} }
if(!total_states){ if(!total_states){
fprintf(stderr, "No solution found!\n"); fprintf(stderr, "No solution found :(\n");
return 1; return 1;
} }
@ -634,7 +652,6 @@ int main (int argc, const char * argv[]) {
size_t i; size_t i;
printf(" - initializing BS crypto-1...\n");
crypto1_bs_init(); crypto1_bs_init();
printf("Using %u-bit bitslices\n", MAX_BITSLICES); printf("Using %u-bit bitslices\n", MAX_BITSLICES);
@ -656,6 +673,8 @@ int main (int argc, const char * argv[]) {
total_states_tested = 0; total_states_tested = 0;
keys_found = 0; keys_found = 0;
signal(SIGALRM, notify_status_offline);
alarm(1);
printf("Starting %zu threads to test %zu states\n", thread_count, total_states); printf("Starting %zu threads to test %zu states\n", thread_count, total_states);
for(i = 0; i < thread_count; i++){ for(i = 0; i < thread_count; i++){
@ -665,7 +684,14 @@ int main (int argc, const char * argv[]) {
pthread_join(threads[i], 0); pthread_join(threads[i], 0);
} }
printf("Tested %zu states\n", total_states_tested); printf("Tested %zu states\n", total_states_tested);
if(!keys_found){
fprintf(stderr, "No solution found :(\n");
return 1;
} else {
printf("Found key: %012"PRIx64"\n", found_key);
}
craptev1_destroy_space(space); craptev1_destroy_space(space);
alarm(0);
return 0; return 0;
} }