mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-11-10 09:32:41 +08:00
Added few tools to tackle FM11RF08S cards
This commit is contained in:
parent
dc287c232f
commit
7fec0d693c
7 changed files with 968 additions and 0 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -82,6 +82,11 @@ tools/cryptorf/cm
|
|||
tools/cryptorf/sm
|
||||
tools/cryptorf/sma
|
||||
tools/cryptorf/sma_multi
|
||||
tools/mf_fudan_rf08s/rf08s_nested
|
||||
tools/mf_fudan_rf08s/rf08s_nested_known
|
||||
tools/mf_fudan_rf08s/rf08s_nested_known_collision
|
||||
tools/mf_fudan_rf08s/rf08s_nested_known_match
|
||||
tools/mf_fudan_rf08s/keys*
|
||||
tools/mf_nonce_brute/mf_nonce_brute
|
||||
tools/mf_nonce_brute/mf_trace_brute
|
||||
tools/jtag_openocd/openocd_configuration
|
||||
|
|
|
@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
|
|||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Added few tools to tackle FM11RF08S cards (@doegox)
|
||||
- Changed standalone mode HF_MATTYRUN - support more card sizes, user dictionaries, improved emulation (@michaelroland)
|
||||
- Changed `hf iclass dump --ns` - now supports the nosave flag (@iceman1001)
|
||||
- Fixed write check in hitag2crack2 buildtables (@mwalker33)
|
||||
|
|
33
tools/mf_fudan_rf08s/Makefile
Normal file
33
tools/mf_fudan_rf08s/Makefile
Normal file
|
@ -0,0 +1,33 @@
|
|||
MYSRCPATHS = ../../common ../../common/crapto1
|
||||
MYSRCS = crypto1.c crapto1.c bucketsort.c
|
||||
MYINCLUDES = -I../../include -I../../common
|
||||
MYCFLAGS = -O3
|
||||
MYDEFS =
|
||||
|
||||
BINS = rf08s_nested rf08s_nested_known rf08s_nested_known_collision rf08s_nested_known_match
|
||||
|
||||
INSTALLTOOLS = $(BINS)
|
||||
|
||||
include ../../Makefile.host
|
||||
|
||||
# rf08s_nested.c needs pthread support. Older glibc needs it externally
|
||||
ifneq ($(SKIPPTHREAD),1)
|
||||
MYLDLIBS += -lpthread
|
||||
endif
|
||||
|
||||
# checking platform can be done only after Makefile.host
|
||||
ifneq (,$(findstring MINGW,$(platform)))
|
||||
# Mingw uses by default Microsoft printf, we want the GNU printf (e.g. for %z)
|
||||
# and setting _ISOC99_SOURCE sets internally __USE_MINGW_ANSI_STDIO=1
|
||||
CFLAGS += -D_ISOC99_SOURCE
|
||||
endif
|
||||
|
||||
# macOS doesn't like these compiler params
|
||||
ifneq ($(platform),Darwin)
|
||||
MYCFLAGS += --param max-completely-peeled-insns=1000 --param max-completely-peel-times=10000
|
||||
endif
|
||||
|
||||
rf08s_nested : $(OBJDIR)/rf08s_nested.o $(MYOBJS)
|
||||
rf08s_nested_known : $(OBJDIR)/rf08s_nested_known.o $(MYOBJS)
|
||||
rf08s_nested_known_collision : $(OBJDIR)/rf08s_nested_known_collision.o $(MYOBJS)
|
||||
rf08s_nested_known_match : $(OBJDIR)/rf08s_nested_known_match.o $(MYOBJS)
|
406
tools/mf_fudan_rf08s/rf08s_nested.c
Normal file
406
tools/mf_fudan_rf08s/rf08s_nested.c
Normal file
|
@ -0,0 +1,406 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
#include "common.h"
|
||||
#include "crapto1/crapto1.h"
|
||||
#include "parity.h"
|
||||
|
||||
#define NUM_THREADS 20
|
||||
#define BATCH_SIZE (8192 / NUM_THREADS)
|
||||
// oversized just in case...
|
||||
#define KEY_SPACE_SIZE ((1 << 16) * 4)
|
||||
// we expect intersection to be about 250-500 keys. Oversized just in case...
|
||||
#define KEY_SPACE_SIZE_STEP2 2000
|
||||
#define MAX_NR_NONCES 32
|
||||
|
||||
typedef struct {
|
||||
uint32_t ntp;
|
||||
uint32_t ks1;
|
||||
} NtpKs1;
|
||||
|
||||
typedef struct {
|
||||
uint32_t authuid;
|
||||
NtpKs1 *pNK;
|
||||
uint32_t sizeNK;
|
||||
uint32_t nt_enc;
|
||||
uint8_t nt_par_enc;
|
||||
} NtData;
|
||||
|
||||
typedef struct {
|
||||
NtData NtDataList[MAX_NR_NONCES];
|
||||
uint32_t nr_nonces;
|
||||
} NtpKs1List;
|
||||
|
||||
// Struct for thread data
|
||||
typedef struct {
|
||||
NtpKs1List *pNKL;
|
||||
uint32_t startPos;
|
||||
uint32_t endPos;
|
||||
uint32_t *keyCount[MAX_NR_NONCES];
|
||||
uint64_t *result_keys[MAX_NR_NONCES];
|
||||
uint32_t thread_id;
|
||||
pthread_mutex_t *keyCount_mutex[MAX_NR_NONCES];
|
||||
uint32_t num_nonces;
|
||||
} thread_data_t;
|
||||
|
||||
static uint32_t hex_to_uint32(const char *hex_str) {
|
||||
return (uint32_t)strtoul(hex_str, NULL, 16);
|
||||
}
|
||||
|
||||
static int bin_to_uint8_arr(const char *bin_str, uint8_t bit_arr[], uint8_t arr_size) {
|
||||
if (strlen(bin_str) != arr_size) {
|
||||
fprintf(stderr, "Error: Binary string (%s) length does not match array size (%i).\n", bin_str, arr_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < arr_size; i++) {
|
||||
if (bin_str[i] == '0') {
|
||||
bit_arr[i] = 0;
|
||||
} else if (bin_str[i] == '1') {
|
||||
bit_arr[i] = 1;
|
||||
} else {
|
||||
fprintf(stderr, "Error: Invalid character '%c' in binary string.\n", bin_str[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t valid_nonce(uint32_t Nt, uint32_t ks1, uint8_t nt_par_enc) {
|
||||
return (oddparity8((Nt >> 24) & 0xFF) == (((nt_par_enc >> 3) & 1) ^ BIT(ks1, 16))) &&
|
||||
(oddparity8((Nt >> 16) & 0xFF) == (((nt_par_enc >> 2) & 1) ^ BIT(ks1, 8))) &&
|
||||
(oddparity8((Nt >> 8) & 0xFF) == (((nt_par_enc >> 1) & 1) ^ BIT(ks1, 0)));
|
||||
}
|
||||
|
||||
static bool search_match(NtData *pND, NtData *pND0, uint64_t key) {
|
||||
bool ret = 0;
|
||||
struct Crypto1State *s;
|
||||
s = crypto1_create(0);
|
||||
if (s == NULL) {
|
||||
fprintf(stderr, "\nMalloc error in search_match!\n");
|
||||
return 0;
|
||||
}
|
||||
crypto1_init(s, key);
|
||||
uint32_t authuid = pND->authuid;
|
||||
uint32_t nt_enc = pND->nt_enc;
|
||||
uint8_t nt_par_enc = pND->nt_par_enc;
|
||||
uint32_t nt = crypto1_word(s, nt_enc ^ authuid, 1) ^ nt_enc;
|
||||
// filter: we know nt should be valid, no need to spend time on other ones
|
||||
if (validate_prng_nonce(nt)) {
|
||||
// look for same nt
|
||||
for (uint32_t k = 0; k < pND->sizeNK; k++) {
|
||||
if (nt == pND->pNK[k].ntp) {
|
||||
// Possible match
|
||||
// filter: check the full 4 bits of parity (actually only the last one might be wrong)
|
||||
uint32_t ks1, ks2;
|
||||
uint8_t par1, par2, ksp;
|
||||
par1 = (oddparity8((nt >> 24) & 0xFF) << 3) | (oddparity8((nt >> 16) & 0xFF) << 2) | (oddparity8((nt >> 8) & 0xFF) << 1) | (oddparity8(nt & 0xFF));
|
||||
ks1 = nt ^ nt_enc;
|
||||
ks2 = crypto1_word(s, 0, 0);
|
||||
ksp = (((ks1 >> 16) & 1) << 3) | (((ks1 >> 8) & 1) << 2) | (((ks1 >> 0) & 1) << 1) | ((ks2 >> 24) & 1);
|
||||
par2 = nt_par_enc ^ ksp;
|
||||
|
||||
if (par1 != par2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// filter: same check on the full 4 bits of parity of initial nonce
|
||||
// check is slow so we do it only now
|
||||
crypto1_init(s, key);
|
||||
authuid = pND0->authuid;
|
||||
nt_enc = pND0->nt_enc;
|
||||
nt_par_enc = pND0->nt_par_enc;
|
||||
nt = crypto1_word(s, nt_enc ^ authuid, 1) ^ nt_enc;
|
||||
par1 = (oddparity8((nt >> 24) & 0xFF) << 3) | (oddparity8((nt >> 16) & 0xFF) << 2) | (oddparity8((nt >> 8) & 0xFF) << 1) | (oddparity8(nt & 0xFF));
|
||||
ks1 = nt ^ nt_enc;
|
||||
ks2 = crypto1_word(s, 0, 0);
|
||||
ksp = (((ks1 >> 16) & 1) << 3) | (((ks1 >> 8) & 1) << 2) | (((ks1 >> 0) & 1) << 1) | ((ks2 >> 24) & 1);
|
||||
par2 = nt_par_enc ^ ksp;
|
||||
if (par1 != par2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
k = pND->sizeNK;
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
crypto1_destroy(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *generate_and_intersect_keys(void *threadarg) {
|
||||
thread_data_t *data = (thread_data_t *)threadarg;
|
||||
NtpKs1List *pNKL = data->pNKL;
|
||||
uint32_t startPos = data->startPos;
|
||||
uint32_t endPos = data->endPos;
|
||||
uint32_t thread_id = data->thread_id;
|
||||
uint32_t num_nonces = data->num_nonces;
|
||||
|
||||
struct Crypto1State *revstate, *revstate_start = NULL;
|
||||
uint64_t lfsr = 0;
|
||||
|
||||
uint32_t authuid = pNKL->NtDataList[0].authuid;
|
||||
for (uint32_t i = startPos; i < endPos; i++) {
|
||||
uint32_t ntp = pNKL->NtDataList[0].pNK[i].ntp;
|
||||
uint32_t ks1 = pNKL->NtDataList[0].pNK[i].ks1;
|
||||
uint32_t nt_probe = ntp ^ authuid;
|
||||
|
||||
revstate = lfsr_recovery32(ks1, nt_probe);
|
||||
if (revstate == NULL) {
|
||||
fprintf(stderr, "\nMalloc error in generate_and_intersect_keys!\n");
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
if (revstate_start == NULL) {
|
||||
revstate_start = revstate;
|
||||
}
|
||||
uint32_t keyCount0 = 0;
|
||||
while ((revstate->odd != 0x0) || (revstate->even != 0x0)) {
|
||||
lfsr_rollback_word(revstate, nt_probe, 0);
|
||||
crypto1_get_lfsr(revstate, &lfsr);
|
||||
keyCount0++;
|
||||
for (uint32_t nonce_index = 1; nonce_index < num_nonces; nonce_index++) {
|
||||
if (search_match(&pNKL->NtDataList[nonce_index], &pNKL->NtDataList[0], lfsr)) {
|
||||
pthread_mutex_lock(data->keyCount_mutex[nonce_index]);
|
||||
data->result_keys[nonce_index][*data->keyCount[nonce_index]] = lfsr;
|
||||
(*data->keyCount[nonce_index])++;
|
||||
pthread_mutex_unlock(data->keyCount_mutex[nonce_index]);
|
||||
if (*data->keyCount[nonce_index] == KEY_SPACE_SIZE_STEP2) {
|
||||
fprintf(stderr, "No space left on result_keys[%d], abort!\n", nonce_index);
|
||||
i = endPos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
revstate++;
|
||||
}
|
||||
free(revstate_start);
|
||||
revstate_start = NULL;
|
||||
|
||||
pthread_mutex_lock(data->keyCount_mutex[0]);
|
||||
(*data->keyCount[0]) += keyCount0;
|
||||
keyCount0 = 0;
|
||||
pthread_mutex_unlock(data->keyCount_mutex[0]);
|
||||
|
||||
if ((i != startPos) && ((i - startPos) % ((endPos - startPos) / 20) == 0)) { // every 5%
|
||||
printf("\rThread %3i %3i%%", thread_id, (i - startPos) * 100 / (endPos - startPos));
|
||||
printf(" keys[%d]:%9i", 0, *data->keyCount[0]);
|
||||
for (uint32_t nonce_index = 1; nonce_index < num_nonces; nonce_index++) {
|
||||
printf(" keys[%d]:%5i", nonce_index, *data->keyCount[nonce_index]);
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
static uint64_t **unpredictable_nested(NtpKs1List *pNKL, uint32_t keyCounts[]) {
|
||||
pthread_t threads[NUM_THREADS];
|
||||
thread_data_t thread_data[NUM_THREADS];
|
||||
pthread_mutex_t keyCount_mutex[MAX_NR_NONCES];
|
||||
|
||||
uint64_t **result_keys = (uint64_t **)malloc(MAX_NR_NONCES * sizeof(uint64_t *));
|
||||
// no result_keys[0] stored, would be too large
|
||||
for (uint32_t i = 1; i < MAX_NR_NONCES; i++) {
|
||||
result_keys[i] = (uint64_t *)malloc(KEY_SPACE_SIZE_STEP2 * sizeof(uint64_t));
|
||||
keyCounts[i] = 0;
|
||||
pthread_mutex_init(&keyCount_mutex[i], NULL);
|
||||
}
|
||||
|
||||
uint32_t average = pNKL->NtDataList[0].sizeNK / NUM_THREADS;
|
||||
uint32_t modulo = pNKL->NtDataList[0].sizeNK % NUM_THREADS;
|
||||
for (uint32_t t = 0, j = 0; t < NUM_THREADS; t++, j += average) {
|
||||
thread_data[t].pNKL = pNKL;
|
||||
thread_data[t].startPos = j;
|
||||
thread_data[t].endPos = j + average;
|
||||
for (uint32_t i = 0; i < MAX_NR_NONCES; i++) {
|
||||
thread_data[t].result_keys[i] = result_keys[i];
|
||||
thread_data[t].keyCount[i] = &keyCounts[i];
|
||||
thread_data[t].keyCount_mutex[i] = &keyCount_mutex[i];
|
||||
}
|
||||
thread_data[t].thread_id = t;
|
||||
thread_data[t].num_nonces = pNKL->nr_nonces;
|
||||
// last thread can decrypt more pNK
|
||||
if (t == (NUM_THREADS - 1) && modulo > 0) {
|
||||
thread_data[t].endPos += modulo;
|
||||
}
|
||||
pthread_create(&threads[t], NULL, generate_and_intersect_keys, (void *)&thread_data[t]);
|
||||
}
|
||||
printf("All threads spawn...\n");
|
||||
|
||||
for (uint32_t t = 0; t < NUM_THREADS; t++) {
|
||||
pthread_join(threads[t], NULL);
|
||||
}
|
||||
|
||||
// no result_keys[0]
|
||||
for (uint32_t i = 1; i < MAX_NR_NONCES; i++) {
|
||||
if (keyCounts[i] == 0) {
|
||||
free(result_keys[i]);
|
||||
result_keys[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return result_keys;
|
||||
}
|
||||
|
||||
// Function to compare keys and keep track of their occurrences
|
||||
static void analyze_keys(uint64_t **keys, uint32_t keyCounts[MAX_NR_NONCES], uint32_t nr_nonces) {
|
||||
// Assuming the maximum possible keys
|
||||
#define MAX_KEYS (MAX_NR_NONCES * KEY_SPACE_SIZE_STEP2)
|
||||
uint64_t combined_keys[MAX_KEYS] = {0};
|
||||
uint32_t combined_counts[MAX_KEYS] = {0};
|
||||
uint32_t combined_length = 0;
|
||||
|
||||
printf("Analyzing keys...\n");
|
||||
for (uint32_t i = 0; i < nr_nonces; i++) {
|
||||
if (i==0) {
|
||||
printf("nT(%i): %i key candidates\n", i, keyCounts[i]);
|
||||
continue;
|
||||
} else {
|
||||
printf("nT(%i): %i key candidates matching nT(0)\n", i, keyCounts[i]);
|
||||
}
|
||||
for (uint32_t j = 0; j < keyCounts[i]; j++) {
|
||||
uint64_t key = keys[i][j];
|
||||
// Check if key is already in combined_keys
|
||||
bool found = false;
|
||||
for (uint32_t k = 0; k < combined_length; k++) {
|
||||
if (combined_keys[k] == key) {
|
||||
combined_counts[k]++;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If key not found, add it to combined_keys
|
||||
if (!found) {
|
||||
combined_keys[combined_length] = key;
|
||||
combined_counts[combined_length] = 1;
|
||||
combined_length++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < combined_length; i++) {
|
||||
if (combined_counts[i] > 1) {
|
||||
printf("Key %012" PRIx64 " found in %d arrays: 0", combined_keys[i], combined_counts[i]+1);
|
||||
for (uint32_t ii = 1; ii < nr_nonces; ii++) {
|
||||
for (uint32_t j = 0; j < keyCounts[ii]; j++) {
|
||||
if (combined_keys[i] == keys[ii][j]) {
|
||||
printf(", %2i", ii);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *const argv[]) {
|
||||
if (argc < 2) {
|
||||
int cmdlen = strlen(argv[0]);
|
||||
printf("Usage:\n %s <uid1> <nt_enc1> <nt_par_err1> <uid2> <nt_enc2> <nt_par_err2> ...\n", argv[0]);
|
||||
printf(" UID placeholder: if uid(n)==uid(n-1) you can use '.' as uid(n+1) placeholder\n");
|
||||
printf(" parity example: if nt in trace is 7b! fc! 7a! 5b , then nt_enc is 7bfc7a5b and nt_par_err is 1110\n");
|
||||
printf("Example:\n");
|
||||
printf(" %*s a13e4902 2e9e49fc 1111 . 7bfc7a5b 1110 a17e4902 50f2abc2 1101\n", cmdlen, argv[0]);
|
||||
printf(" %*s +uid1 | | +uid2=uid1 | +uid3 | |\n", cmdlen, "");
|
||||
printf(" %*s +nt_enc1 | +nt_enc2 | +nt_enc3 |\n", cmdlen, "");
|
||||
printf(" %*s +nt_par_err1 +nt_par_err2 +nt_par_err3\n", cmdlen, "");
|
||||
return 1;
|
||||
}
|
||||
if (argc < 1 + 2 * 3) {
|
||||
fprintf(stderr, "Too few nonces, abort. Need 2 nonces min.\n");
|
||||
return 1;
|
||||
}
|
||||
if (argc > 1 + MAX_NR_NONCES * 3) {
|
||||
fprintf(stderr, "Too many nonces, abort. Choose max %i nonces.\n", MAX_NR_NONCES);
|
||||
return 1;
|
||||
}
|
||||
|
||||
NtpKs1List NKL = {0};
|
||||
uint64_t **keys = NULL;
|
||||
uint32_t keyCounts[MAX_NR_NONCES] = {0};
|
||||
|
||||
uint32_t authuid = hex_to_uint32(argv[1]);
|
||||
// process all args.
|
||||
printf("Generating nonce candidates...\n");
|
||||
for (uint32_t i = 1; i < argc; i += 3) {
|
||||
// uid + ntEnc + parEnc
|
||||
if (strcmp(argv[i], ".") != 0) {
|
||||
authuid = hex_to_uint32(argv[i]);
|
||||
}
|
||||
uint32_t nt_enc = hex_to_uint32(argv[i + 1]);
|
||||
uint8_t nt_par_err_arr[4];
|
||||
if (bin_to_uint8_arr(argv[i + 2], nt_par_err_arr, 4)) {
|
||||
return 1;
|
||||
}
|
||||
uint8_t nt_par_enc = ((nt_par_err_arr[0] ^ oddparity8((nt_enc >> 24) & 0xFF)) << 3) |
|
||||
((nt_par_err_arr[1] ^ oddparity8((nt_enc >> 16) & 0xFF)) << 2) |
|
||||
((nt_par_err_arr[2] ^ oddparity8((nt_enc >> 8) & 0xFF)) << 1) |
|
||||
((nt_par_err_arr[3] ^ oddparity8((nt_enc >> 0) & 0xFF)) << 0);
|
||||
NtData *pNtData = &NKL.NtDataList[NKL.nr_nonces];
|
||||
// Try to recover the keystream1
|
||||
uint32_t nttest = prng_successor(1, 16); // a first valid nonce
|
||||
pNtData->pNK = (NtpKs1 *)malloc(sizeof(NtpKs1) * 8192); // 2**16 filtered with 3 parity bits => 2**13
|
||||
if (pNtData->pNK == NULL) {
|
||||
return 1;
|
||||
}
|
||||
uint32_t j = 0;
|
||||
for (uint16_t m = 1; m; m++) {
|
||||
uint32_t ks1 = nt_enc ^ nttest;
|
||||
if (valid_nonce(nttest, ks1, nt_par_enc)) {
|
||||
pNtData->pNK[j].ntp = nttest;
|
||||
pNtData->pNK[j].ks1 = ks1;
|
||||
j++;
|
||||
}
|
||||
nttest = prng_successor(nttest, 1);
|
||||
}
|
||||
printf("uid=%08x nt_enc=%08x nt_par_err=%i%i%i%i nt_par_enc=%i%i%i%i %i/%i: %d\n", authuid, nt_enc,
|
||||
nt_par_err_arr[0], nt_par_err_arr[1], nt_par_err_arr[2], nt_par_err_arr[3],
|
||||
(nt_par_enc >> 3)&1, (nt_par_enc >> 2)&1, (nt_par_enc >> 1)&1, nt_par_enc&1,
|
||||
NKL.nr_nonces + 1, (argc - 1) / 3, j);
|
||||
|
||||
pNtData->authuid = authuid;
|
||||
pNtData->sizeNK = j;
|
||||
pNtData->nt_enc = nt_enc;
|
||||
pNtData->nt_par_enc = nt_par_enc;
|
||||
NKL.nr_nonces++;
|
||||
}
|
||||
|
||||
printf("Finding key candidates...\n");
|
||||
keys = unpredictable_nested(&NKL, keyCounts);
|
||||
printf("\n\nFinding phase complete.\n");
|
||||
|
||||
for (uint32_t k = 0; k < NKL.nr_nonces; k++)
|
||||
free(NKL.NtDataList[k].pNK);
|
||||
|
||||
analyze_keys(keys, keyCounts, NKL.nr_nonces);
|
||||
FILE* fptr;
|
||||
// opening the file in read mode
|
||||
fptr = fopen("keys.dic", "w");
|
||||
if (fptr != NULL) {
|
||||
for (uint32_t i = 1; i < NKL.nr_nonces; i++) {
|
||||
if (keyCounts[i] > 0) {
|
||||
for (uint32_t j = 0; j < keyCounts[i]; j++) {
|
||||
fprintf(fptr, "%012" PRIx64 "\n", keys[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fptr);
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Cannot save keys in keys.dic\n");
|
||||
}
|
||||
for (uint32_t i = 1; i < NKL.nr_nonces; i++) {
|
||||
if (keys[i] != NULL) {
|
||||
free(keys[i]);
|
||||
}
|
||||
}
|
||||
if (keys != NULL) {
|
||||
free(keys);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
153
tools/mf_fudan_rf08s/rf08s_nested_known.c
Normal file
153
tools/mf_fudan_rf08s/rf08s_nested_known.c
Normal file
|
@ -0,0 +1,153 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "common.h"
|
||||
#include "crapto1/crapto1.h"
|
||||
#include "parity.h"
|
||||
|
||||
#define KEY_SPACE_SIZE (1 << 18)
|
||||
|
||||
typedef struct {
|
||||
uint32_t authuid;
|
||||
uint32_t nt;
|
||||
uint32_t nt_enc;
|
||||
uint8_t nt_par_enc;
|
||||
} NtData;
|
||||
|
||||
static uint32_t hex_to_uint32(const char *hex_str) {
|
||||
return (uint32_t)strtoul(hex_str, NULL, 16);
|
||||
}
|
||||
|
||||
static int bin_to_uint8_arr(const char *bin_str, uint8_t bit_arr[], uint8_t arr_size) {
|
||||
if (strlen(bin_str) != arr_size) {
|
||||
fprintf(stderr, "Error: Binary string (%s) length does not match array size (%i).\n", bin_str, arr_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < arr_size; i++) {
|
||||
if (bin_str[i] == '0') {
|
||||
bit_arr[i] = 0;
|
||||
} else if (bin_str[i] == '1') {
|
||||
bit_arr[i] = 1;
|
||||
} else {
|
||||
fprintf(stderr, "Error: Invalid character '%c' in binary string.\n", bin_str[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t *generate_keys(uint64_t authuid, uint32_t nt, uint32_t nt_enc, uint32_t nt_par_enc, uint32_t *keyCount) {
|
||||
uint64_t *result_keys = (uint64_t *)malloc(KEY_SPACE_SIZE * sizeof(uint64_t));
|
||||
if (result_keys == NULL) {
|
||||
fprintf(stderr, "\nMalloc error in generate_and_intersect_keys!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct Crypto1State *revstate, *revstate_start = NULL, *s = NULL;
|
||||
uint64_t lfsr = 0;
|
||||
uint32_t ks1 = nt ^ nt_enc;
|
||||
|
||||
revstate = lfsr_recovery32(ks1, nt ^ authuid);
|
||||
if (revstate == NULL) {
|
||||
fprintf(stderr, "\nMalloc error in generate_keys!\n");
|
||||
free(result_keys);
|
||||
return NULL;
|
||||
}
|
||||
if (revstate_start == NULL) {
|
||||
revstate_start = revstate;
|
||||
}
|
||||
s = crypto1_create(0);
|
||||
if (s == NULL) {
|
||||
fprintf(stderr, "\nMalloc error in generate_keys!\n");
|
||||
free(result_keys);
|
||||
crypto1_destroy(revstate_start);
|
||||
return 0;
|
||||
}
|
||||
while ((revstate->odd != 0x0) || (revstate->even != 0x0)) {
|
||||
lfsr_rollback_word(revstate, nt ^ authuid, 0);
|
||||
crypto1_get_lfsr(revstate, &lfsr);
|
||||
|
||||
// only filtering possibility: last parity bit ks in ks2
|
||||
uint32_t ks2;
|
||||
uint8_t lastpar1, lastpar2, kslastp;
|
||||
crypto1_init(s, lfsr);
|
||||
crypto1_word(s, nt ^ authuid, 0);
|
||||
ks2 = crypto1_word(s, 0, 0);
|
||||
lastpar1 = oddparity8(nt & 0xFF);
|
||||
kslastp = (ks2 >> 24) & 1;
|
||||
lastpar2 = (nt_par_enc & 1) ^ kslastp;
|
||||
if (lastpar1 == lastpar2) {
|
||||
result_keys[(*keyCount)++] = lfsr;
|
||||
if (*keyCount == KEY_SPACE_SIZE) {
|
||||
fprintf(stderr, "No space left on result_keys, abort! Increase KEY_SPACE_SIZE\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
revstate++;
|
||||
}
|
||||
crypto1_destroy(s);
|
||||
crypto1_destroy(revstate_start);
|
||||
revstate_start = NULL;
|
||||
return result_keys;
|
||||
}
|
||||
|
||||
int main(int argc, char *const argv[]) {
|
||||
if (argc != 6) {
|
||||
int cmdlen = strlen(argv[0]);
|
||||
printf("Usage:\n %s <uid:hex> <sector:dec> <nt:hex> <nt_enc:hex> <nt_par_err:bin>\n"
|
||||
" parity example: if for block 63 == sector 15, nt in trace is 7b! fc! 7a! 5b\n"
|
||||
" then nt_enc is 7bfc7a5b and nt_par_err is 1110\n"
|
||||
"Example:\n"
|
||||
" %*s a13e4902 15 d14191b3 2e9e49fc 1111\n"
|
||||
" %*s +uid +s +nt +nt_enc +nt_par_err\n",
|
||||
argv[0], cmdlen, argv[0], cmdlen, "");
|
||||
return 1;
|
||||
}
|
||||
uint64_t *keys = NULL;
|
||||
uint32_t keyCount = 0;
|
||||
|
||||
uint32_t authuid = hex_to_uint32(argv[1]);
|
||||
uint32_t sector = hex_to_uint32(argv[2]);
|
||||
uint32_t nt = hex_to_uint32(argv[3]);
|
||||
uint32_t nt_enc = hex_to_uint32(argv[4]);
|
||||
uint8_t nt_par_err_arr[4];
|
||||
if (bin_to_uint8_arr(argv[5], nt_par_err_arr, 4)) {
|
||||
return 1;
|
||||
}
|
||||
uint8_t nt_par_enc = ((nt_par_err_arr[0] ^ oddparity8((nt_enc >> 24) & 0xFF)) << 3) |
|
||||
((nt_par_err_arr[1] ^ oddparity8((nt_enc >> 16) & 0xFF)) << 2) |
|
||||
((nt_par_err_arr[2] ^ oddparity8((nt_enc >> 8) & 0xFF)) << 1) |
|
||||
((nt_par_err_arr[3] ^ oddparity8((nt_enc >> 0) & 0xFF)) << 0);
|
||||
printf("uid=%08x nt=%08x nt_enc=%08x nt_par_err=%i%i%i%i nt_par_enc=%i%i%i%i ks1=%08x\n", authuid, nt, nt_enc,
|
||||
nt_par_err_arr[0], nt_par_err_arr[1], nt_par_err_arr[2], nt_par_err_arr[3],
|
||||
(nt_par_enc >> 3)&1, (nt_par_enc >> 2)&1, (nt_par_enc >> 1)&1, nt_par_enc&1,
|
||||
nt ^ nt_enc);
|
||||
|
||||
|
||||
printf("Finding key candidates...\n");
|
||||
keys = generate_keys(authuid, nt, nt_enc, nt_par_enc, &keyCount);
|
||||
printf("Finding phase complete, found %i keys\n", keyCount);
|
||||
|
||||
FILE* fptr;
|
||||
char filename[30];
|
||||
snprintf(filename, sizeof(filename), "keys_%08x_%02i_%08x.dic", authuid, sector, nt);
|
||||
|
||||
fptr = fopen(filename, "w");
|
||||
if (fptr != NULL) {
|
||||
if (keyCount > 0) {
|
||||
for (uint32_t j = 0; j < keyCount; j++) {
|
||||
fprintf(fptr, "%012" PRIx64 "\n", keys[j]);
|
||||
}
|
||||
}
|
||||
fclose(fptr);
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Cannot save keys in %s\n", filename);
|
||||
}
|
||||
if (keys != NULL) {
|
||||
free(keys);
|
||||
}
|
||||
return 0;
|
||||
}
|
230
tools/mf_fudan_rf08s/rf08s_nested_known_collision.c
Normal file
230
tools/mf_fudan_rf08s/rf08s_nested_known_collision.c
Normal file
|
@ -0,0 +1,230 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
uint16_t i_lfsr16[1 << 16] = {0};
|
||||
uint16_t s_lfsr16[1 << 16] = {0};
|
||||
|
||||
static void init_lfsr16_table(void) {
|
||||
uint16_t x = 1;
|
||||
for (uint16_t i=1; i; ++i) {
|
||||
i_lfsr16[(x & 0xff) << 8 | x >> 8] = i;
|
||||
s_lfsr16[i] = (x & 0xff) << 8 | x >> 8;
|
||||
x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15;
|
||||
}
|
||||
}
|
||||
|
||||
// static uint16_t next_lfsr16(uint16_t nonce) {
|
||||
// return s_lfsr16[(i_lfsr16[nonce]+1) % 65535];
|
||||
// }
|
||||
|
||||
static uint16_t prev_lfsr16(uint16_t nonce) {
|
||||
return s_lfsr16[(i_lfsr16[nonce]-1) % 65535];
|
||||
}
|
||||
|
||||
static uint16_t compute_seednt16_nt32(uint32_t nt32, uint64_t key) {
|
||||
uint8_t a[] = {0, 8, 9, 4, 6, 11, 1, 15, 12, 5, 2, 13, 10, 14, 3, 7};
|
||||
uint8_t b[] = {0, 13, 1, 14, 4, 10, 15, 7, 5, 3, 8, 6, 9, 2, 12, 11};
|
||||
uint16_t nt = nt32 >> 16;
|
||||
uint8_t prev = 14;
|
||||
for (uint8_t i=0; i<prev; i++) {
|
||||
nt = prev_lfsr16(nt);
|
||||
}
|
||||
uint8_t prevoff = 8;
|
||||
bool odd = 1;
|
||||
|
||||
for (uint8_t i=0; i<6*8; i+=8) {
|
||||
if (odd) {
|
||||
nt ^= (a[(key >> i) & 0xF]);
|
||||
nt ^= (b[(key >> i >> 4) & 0xF]) << 4;
|
||||
} else {
|
||||
nt ^= (b[(key >> i) & 0xF]);
|
||||
nt ^= (a[(key >> i >> 4) & 0xF]) << 4;
|
||||
}
|
||||
odd ^= 1;
|
||||
prev += prevoff;
|
||||
for (uint8_t j=0; j<prevoff; j++) {
|
||||
nt = prev_lfsr16(nt);
|
||||
}
|
||||
}
|
||||
return nt;
|
||||
}
|
||||
|
||||
int main(int argc, char *const argv[]) {
|
||||
if (argc != 3) {
|
||||
printf("Usage:\n %s keys_<uid:08x>_<sector:02>_<nt1:08x>.dic keys_<uid:08x>_<sector:02>_<nt2:08x>.dic\n"
|
||||
" where both dict files are produced by rf08s_nested_known *for the same UID and same sector*\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t uid1, sector1, nt1, uid2, sector2, nt2;
|
||||
char *filename1 = argv[1], *filename2= argv[2];
|
||||
|
||||
int result;
|
||||
result = sscanf(filename1, "keys_%8x_%2d_%8x.dic", &uid1, §or1, &nt1);
|
||||
if (result != 3) {
|
||||
fprintf(stderr, "Error: Failed to parse the filename %s.\n", filename1);
|
||||
return 1;
|
||||
}
|
||||
result = sscanf(filename2, "keys_%8x_%2d_%8x.dic", &uid2, §or2, &nt2);
|
||||
if (result != 3) {
|
||||
fprintf(stderr, "Error: Failed to parse the filename %s.\n", filename2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (uid1 != uid2) {
|
||||
fprintf(stderr, "Error: Files must belong to the same UID.\n");
|
||||
return 1;
|
||||
}
|
||||
if (sector1 != sector2) {
|
||||
fprintf(stderr, "Error: Files must belong to the same sector.\n");
|
||||
return 1;
|
||||
}
|
||||
if (nt1 == nt2) {
|
||||
fprintf(stderr, "Error: Files must belong to different nonces.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
init_lfsr16_table();
|
||||
|
||||
uint32_t keycount1 = 0;
|
||||
uint64_t* keys1 = NULL;
|
||||
uint8_t* filter_keys1 = NULL;
|
||||
uint16_t* seednt1 = NULL;
|
||||
uint32_t keycount2 = 0;
|
||||
uint64_t* keys2 = NULL;
|
||||
uint8_t* filter_keys2 = NULL;
|
||||
FILE* fptr;
|
||||
|
||||
fptr = fopen(filename1, "r");
|
||||
if (fptr != NULL) {
|
||||
uint64_t buffer;
|
||||
while (fscanf(fptr, "%012" PRIx64, &buffer) == 1) {
|
||||
keycount1++;
|
||||
}
|
||||
|
||||
keys1 = (uint64_t*)malloc(keycount1 * sizeof(uint64_t));
|
||||
filter_keys1 = (uint8_t*)calloc(keycount1, sizeof(uint8_t));
|
||||
if ((keys1 == NULL)||(filter_keys1 == NULL)) {
|
||||
perror("Failed to allocate memory");
|
||||
fclose(fptr);
|
||||
goto end;
|
||||
}
|
||||
rewind(fptr);
|
||||
|
||||
for (uint32_t i = 0; i < keycount1; i++) {
|
||||
if (fscanf(fptr, "%012" PRIx64, &keys1[i]) != 1) {
|
||||
perror("Failed to read key");
|
||||
fclose(fptr);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
fclose(fptr);
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Cannot open %s\n", filename1);
|
||||
goto end;
|
||||
}
|
||||
|
||||
fptr = fopen(filename2, "r");
|
||||
if (fptr != NULL) {
|
||||
uint64_t buffer;
|
||||
while (fscanf(fptr, "%012" PRIx64, &buffer) == 1) {
|
||||
keycount2++;
|
||||
}
|
||||
|
||||
keys2 = (uint64_t*)malloc(keycount2 * sizeof(uint64_t));
|
||||
filter_keys2 = (uint8_t*)calloc(keycount1, sizeof(uint8_t));
|
||||
if ((keys2 == NULL)||(filter_keys2 == NULL)) {
|
||||
perror("Failed to allocate memory");
|
||||
fclose(fptr);
|
||||
goto end;
|
||||
}
|
||||
rewind(fptr);
|
||||
|
||||
for (uint32_t i = 0; i < keycount2; i++) {
|
||||
if (fscanf(fptr, "%012" PRIx64, &keys2[i]) != 1) {
|
||||
perror("Failed to read key");
|
||||
fclose(fptr);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
fclose(fptr);
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Cannot open %s\n", filename2);
|
||||
goto end;
|
||||
}
|
||||
|
||||
printf("%s: %i keys loaded\n", filename1, keycount1);
|
||||
printf("%s: %i keys loaded\n", filename2, keycount2);
|
||||
|
||||
seednt1 = (uint16_t*)malloc(keycount1 * sizeof(uint16_t));
|
||||
if (seednt1 == NULL) {
|
||||
perror("Failed to allocate memory");
|
||||
goto end;
|
||||
}
|
||||
for (uint32_t i = 0; i < keycount1; i++) {
|
||||
seednt1[i] = compute_seednt16_nt32(nt1, keys1[i]);
|
||||
}
|
||||
for (uint32_t j = 0; j < keycount2; j++) {
|
||||
uint16_t seednt2 = compute_seednt16_nt32(nt2, keys2[j]);
|
||||
for (uint32_t i = 0; i < keycount1; i++) {
|
||||
if (seednt2 == seednt1[i]) {
|
||||
// printf("MATCH: key1=%012" PRIx64 " key2=%012" PRIx64 "\n", keys1[i], keys2[j]);
|
||||
filter_keys1[i] = 1;
|
||||
filter_keys2[j] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char filter_filename1[40];
|
||||
uint32_t filter_keycount1 = 0;
|
||||
snprintf(filter_filename1, sizeof(filter_filename1), "keys_%08x_%02i_%08x_filtered.dic", uid1, sector1, nt1);
|
||||
fptr = fopen(filter_filename1, "w");
|
||||
if (fptr != NULL) {
|
||||
for (uint32_t j = 0; j < keycount1; j++) {
|
||||
if (filter_keys1[j]) {
|
||||
filter_keycount1++;
|
||||
fprintf(fptr, "%012" PRIx64 "\n", keys1[j]);
|
||||
}
|
||||
}
|
||||
fclose(fptr);
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Cannot save keys in %s\n", filter_filename1);
|
||||
}
|
||||
|
||||
char filter_filename2[40];
|
||||
uint32_t filter_keycount2 = 0;
|
||||
snprintf(filter_filename2, sizeof(filter_filename2), "keys_%08x_%02i_%08x_filtered.dic", uid2, sector2, nt2);
|
||||
fptr = fopen(filter_filename2, "w");
|
||||
if (fptr != NULL) {
|
||||
for (uint32_t j = 0; j < keycount2; j++) {
|
||||
if (filter_keys2[j]) {
|
||||
filter_keycount2++;
|
||||
fprintf(fptr, "%012" PRIx64 "\n", keys2[j]);
|
||||
}
|
||||
}
|
||||
fclose(fptr);
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Cannot save keys in %s\n", filter_filename2);
|
||||
}
|
||||
printf("%s: %i keys saved\n", filter_filename1, filter_keycount1);
|
||||
printf("%s: %i keys saved\n", filter_filename2, filter_keycount2);
|
||||
|
||||
end:
|
||||
if (keys1 != NULL)
|
||||
free(keys1);
|
||||
if (keys2 != NULL)
|
||||
free(keys2);
|
||||
if (filter_keys1 != NULL)
|
||||
free(filter_keys1);
|
||||
if (filter_keys2 != NULL)
|
||||
free(filter_keys2);
|
||||
if (seednt1 != NULL)
|
||||
free(seednt1);
|
||||
|
||||
return 0;
|
||||
}
|
140
tools/mf_fudan_rf08s/rf08s_nested_known_match.c
Normal file
140
tools/mf_fudan_rf08s/rf08s_nested_known_match.c
Normal file
|
@ -0,0 +1,140 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
static uint32_t hex_to_uint32(const char *hex_str) {
|
||||
return (uint32_t)strtoul(hex_str, NULL, 16);
|
||||
}
|
||||
|
||||
uint16_t i_lfsr16[1 << 16] = {0};
|
||||
uint16_t s_lfsr16[1 << 16] = {0};
|
||||
|
||||
static void init_lfsr16_table(void) {
|
||||
uint16_t x = 1;
|
||||
for (uint16_t i=1; i; ++i) {
|
||||
i_lfsr16[(x & 0xff) << 8 | x >> 8] = i;
|
||||
s_lfsr16[i] = (x & 0xff) << 8 | x >> 8;
|
||||
x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15;
|
||||
}
|
||||
}
|
||||
|
||||
// static uint16_t next_lfsr16(uint16_t nonce) {
|
||||
// return s_lfsr16[(i_lfsr16[nonce]+1) % 65535];
|
||||
// }
|
||||
|
||||
static uint16_t prev_lfsr16(uint16_t nonce) {
|
||||
return s_lfsr16[(i_lfsr16[nonce]-1) % 65535];
|
||||
}
|
||||
|
||||
static uint16_t compute_seednt16_nt32(uint32_t nt32, uint64_t key) {
|
||||
uint8_t a[] = {0, 8, 9, 4, 6, 11, 1, 15, 12, 5, 2, 13, 10, 14, 3, 7};
|
||||
uint8_t b[] = {0, 13, 1, 14, 4, 10, 15, 7, 5, 3, 8, 6, 9, 2, 12, 11};
|
||||
uint16_t nt = nt32 >> 16;
|
||||
uint8_t prev = 14;
|
||||
for (uint8_t i=0; i<prev; i++) {
|
||||
nt = prev_lfsr16(nt);
|
||||
}
|
||||
uint8_t prevoff = 8;
|
||||
bool odd = 1;
|
||||
|
||||
for (uint8_t i=0; i<6*8; i+=8) {
|
||||
if (odd) {
|
||||
nt ^= (a[(key >> i) & 0xF]);
|
||||
nt ^= (b[(key >> i >> 4) & 0xF]) << 4;
|
||||
} else {
|
||||
nt ^= (b[(key >> i) & 0xF]);
|
||||
nt ^= (a[(key >> i >> 4) & 0xF]) << 4;
|
||||
}
|
||||
odd ^= 1;
|
||||
prev += prevoff;
|
||||
for (uint8_t j=0; j<prevoff; j++) {
|
||||
nt = prev_lfsr16(nt);
|
||||
}
|
||||
}
|
||||
return nt;
|
||||
}
|
||||
|
||||
int main(int argc, char *const argv[]) {
|
||||
if (argc != 4) {
|
||||
printf("Usage:\n %s <nt1:08x> <key1:012x> keys_<uid:08x>_<sector:02>_<nt2:08x>.dic\n"
|
||||
" where dict file is produced by rf08s_nested_known *for the same UID and same sector* as provided nt and key\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
uint32_t nt1 = hex_to_uint32(argv[1]);
|
||||
uint64_t key1 = 0;
|
||||
if (sscanf(argv[2], "%012" PRIx64, &key1) != 1) {
|
||||
fprintf(stderr, "Failed to parse key: %s", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *filename= argv[3];
|
||||
uint32_t uid, sector, nt2;
|
||||
|
||||
int result;
|
||||
result = sscanf(filename, "keys_%8x_%2d_%8x.dic", &uid, §or, &nt2);
|
||||
if (result != 3) {
|
||||
fprintf(stderr, "Error: Failed to parse the filename %s.\n", filename);
|
||||
return 1;
|
||||
}
|
||||
if (nt1 == nt2) {
|
||||
fprintf(stderr, "Error: File must belong to different nonce.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
init_lfsr16_table();
|
||||
|
||||
uint32_t keycount2 = 0;
|
||||
uint64_t* keys2 = NULL;
|
||||
|
||||
FILE* fptr = fopen(filename, "r");
|
||||
if (fptr != NULL) {
|
||||
uint64_t buffer;
|
||||
while (fscanf(fptr, "%012" PRIx64, &buffer) == 1) {
|
||||
keycount2++;
|
||||
}
|
||||
|
||||
keys2 = (uint64_t*)malloc(keycount2 * sizeof(uint64_t));
|
||||
if (keys2 == NULL) {
|
||||
perror("Failed to allocate memory");
|
||||
fclose(fptr);
|
||||
goto end;
|
||||
}
|
||||
rewind(fptr);
|
||||
|
||||
for (uint32_t i = 0; i < keycount2; i++) {
|
||||
if (fscanf(fptr, "%012" PRIx64, &keys2[i]) != 1) {
|
||||
perror("Failed to read key");
|
||||
fclose(fptr);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
fclose(fptr);
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Cannot open %s\n", filename);
|
||||
goto end;
|
||||
}
|
||||
|
||||
printf("%s: %i keys loaded\n", filename, keycount2);
|
||||
|
||||
uint32_t found = 0;
|
||||
uint16_t seednt1 = compute_seednt16_nt32(nt1, key1);
|
||||
for (uint32_t i = 0; i < keycount2; i++) {
|
||||
if (seednt1 == compute_seednt16_nt32(nt2, keys2[i])) {
|
||||
printf("MATCH: key2=%012" PRIx64 "\n", keys2[i]);
|
||||
found++;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
printf("No key found :(\n");
|
||||
}
|
||||
|
||||
end:
|
||||
if (keys2 != NULL)
|
||||
free(keys2);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue