Improved error handling, naming, UI
This commit is contained in:
@ -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)
|
||||||
@ -409,14 +415,14 @@ 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
|
||||||
@ -424,7 +430,7 @@ void nested_auth(uint32_t uid, uint64_t known_key, uint8_t ab_key, uint8_t for_b
|
|||||||
|
|
||||||
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;
|
||||||
@ -437,7 +443,7 @@ void nested_auth(uint32_t uid, uint64_t known_key, uint8_t ab_key, uint8_t for_b
|
|||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user