Merge pull request #2737 from jareckib/master
[RRG-proxmark3.git] / tools / mfc / card_reader / mf_trace_brute.c
blob1a8ce84c8f23ad6af9144bdd225a55ce7c7f2e31
1 //
2 // bruteforce the upper 16bits of a partial key recovered from mf_nonce_brute.
3 // J-run's original idea was a two part recovery vector with first a offline trace and then online for 2 bytes.
4 //
5 // This idea is two use only offline, to recover a nested authentication key.
6 // Assumption, we get a read/write command after a nested auth, we need 22 bytes of data.
7 // Iceman, 2021,
8 //
10 #define __STDC_FORMAT_MACROS
12 #include <inttypes.h>
13 #include <stdio.h>
14 #include <stdbool.h>
15 #include <string.h>
16 #include <pthread.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include "ctype.h"
20 #include "crapto1/crapto1.h"
21 #include "protocol.h"
22 #include "iso14443crc.h"
23 #include <util_posix.h>
25 #define AEND "\x1b[0m"
26 #define _RED_(s) "\x1b[31m" s AEND
27 #define _GREEN_(s) "\x1b[32m" s AEND
28 #define _YELLOW_(s) "\x1b[33m" s AEND
29 #define _CYAN_(s) "\x1b[36m" s AEND
31 // a global mutex to prevent interlaced printing from different threads
32 pthread_mutex_t print_lock;
34 #define ENC_LEN (4 + 16 + 2)
35 //--------------------- define options here
37 typedef struct thread_args {
38 int thread;
39 int idx;
40 uint32_t uid;
41 uint32_t part_key;
42 uint32_t nt_enc;
43 uint32_t nr_enc;
44 uint16_t enc_len;
45 uint8_t enc[ENC_LEN]; // next encrypted command + a full read/write
46 } targs;
48 //------------------------------------------------------------------
49 uint8_t cmds[8][2] = {
50 {ISO14443A_CMD_READBLOCK, 18},
51 {ISO14443A_CMD_WRITEBLOCK, 18},
52 {MIFARE_AUTH_KEYA, 0},
53 {MIFARE_AUTH_KEYB, 0},
54 {MIFARE_CMD_INC, 6},
55 {MIFARE_CMD_DEC, 6},
56 {MIFARE_CMD_RESTORE, 6},
57 {MIFARE_CMD_TRANSFER, 0}
60 static int global_found = 0;
61 static int thread_count = 2;
63 static int param_getptr(const char *line, int *bg, int *en, int paramnum) {
64 int i;
65 int len = strlen(line);
67 *bg = 0;
68 *en = 0;
70 // skip spaces
71 while (line[*bg] == ' ' || line[*bg] == '\t')(*bg)++;
72 if (*bg >= len) {
73 return 1;
76 for (i = 0; i < paramnum; i++) {
77 while (line[*bg] != ' ' && line[*bg] != '\t' && line[*bg] != '\0')(*bg)++;
78 while (line[*bg] == ' ' || line[*bg] == '\t')(*bg)++;
80 if (line[*bg] == '\0') return 1;
83 *en = *bg;
84 while (line[*en] != ' ' && line[*en] != '\t' && line[*en] != '\0')(*en)++;
86 (*en)--;
88 return 0;
91 static int param_gethex_to_eol(const char *line, int paramnum, uint8_t *data, int maxdatalen, int *datalen) {
92 int bg, en;
93 uint32_t temp;
94 char buf[5] = {0};
96 if (param_getptr(line, &bg, &en, paramnum)) return 1;
98 *datalen = 0;
100 int indx = bg;
101 while (line[indx]) {
102 if (line[indx] == '\t' || line[indx] == ' ') {
103 indx++;
104 continue;
107 if (isxdigit(line[indx])) {
108 buf[strlen(buf) + 1] = 0x00;
109 buf[strlen(buf)] = line[indx];
110 } else {
111 // if we have symbols other than spaces and hex
112 return 1;
115 if (*datalen >= maxdatalen) {
116 // if we don't have space in buffer and have symbols to translate
117 return 2;
120 if (strlen(buf) >= 2) {
121 sscanf(buf, "%x", &temp);
122 data[*datalen] = (uint8_t)(temp & 0xff);
123 *buf = 0;
124 (*datalen)++;
127 indx++;
130 if (strlen(buf) > 0)
131 //error when not completed hex bytes
132 return 3;
134 return 0;
137 static void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, const size_t hex_max_len,
138 const size_t min_str_len, const size_t spaces_between, bool uppercase) {
140 if (buf == NULL) return;
142 char *tmp_base = (char *)buf;
143 char *tmp = tmp_base;
144 size_t i;
146 size_t max_len = (hex_len > hex_max_len) ? hex_max_len : hex_len;
148 for (i = 0; i < max_len; ++i, tmp += 2 + spaces_between) {
149 snprintf(tmp, hex_max_len - (tmp - tmp_base), (uppercase) ? "%02X" : "%02x", (unsigned int) hex_data[i]);
151 for (size_t j = 0; j < spaces_between; j++)
152 snprintf(tmp + 2 + j, hex_max_len - (2 + j + (tmp - tmp_base)), " ");
155 i *= (2 + spaces_between);
157 size_t mlen = min_str_len > i ? min_str_len : 0;
158 if (mlen > hex_max_len)
159 mlen = hex_max_len;
161 for (; i < mlen; i++, tmp += 1)
162 snprintf(tmp, hex_max_len - (tmp - tmp_base), " ");
164 // remove last space
165 *tmp = '\0';
168 static char *sprint_hex_inrow_ex(const uint8_t *data, const size_t len, const size_t min_str_len) {
169 static char buf[100] = {0};
170 hex_to_buffer((uint8_t *)buf, data, len, sizeof(buf) - 1, min_str_len, 0, true);
171 return buf;
174 static bool checkValidCmdByte(uint8_t *cmd, uint16_t n) {
176 bool ok = false;
177 if (cmd == NULL)
178 return false;
179 for (int i = 0; i < 8; ++i) {
180 if (cmd[0] == cmds[i][0]) {
182 if (n >= 4)
183 ok = CheckCrc14443(CRC_14443_A, cmd, 4);
185 if (cmds[i][1] > 0 && n >= cmds[i][1])
186 ok = CheckCrc14443(CRC_14443_A, cmd + 4, cmds[i][1]);
188 if (ok) {
189 return true;
193 return false;
196 static void *brute_thread(void *arguments) {
198 struct thread_args *args = (struct thread_args *) arguments;
199 uint64_t key = args->part_key;
200 uint8_t local_enc[args->enc_len];
201 memcpy(local_enc, args->enc, args->enc_len);
203 for (uint64_t count = args->idx; count < 0xFFFF; count += thread_count) {
205 if (__atomic_load_n(&global_found, __ATOMIC_ACQUIRE) == 1) {
206 break;
209 key |= count << 32;
211 // Init cipher with key
212 struct Crypto1State *pcs = crypto1_create(key);
214 // NESTED decrypt nt with help of new key
215 crypto1_word(pcs, args->nt_enc ^ args->uid, 1);
216 crypto1_word(pcs, args->nr_enc, 1);
217 crypto1_word(pcs, 0, 0);
218 crypto1_word(pcs, 0, 0);
220 // decrypt 22 bytes
221 uint8_t dec[args->enc_len];
222 for (int i = 0; i < args->enc_len; i++)
223 dec[i] = crypto1_byte(pcs, 0x00, 0) ^ local_enc[i];
225 crypto1_destroy(pcs);
227 if (checkValidCmdByte(dec, args->enc_len) == false) {
228 continue;
230 __sync_fetch_and_add(&global_found, 1);
232 // lock this section to avoid interlacing prints from different threats
233 pthread_mutex_lock(&print_lock);
234 printf("\nenc: %s\n", sprint_hex_inrow_ex(local_enc, args->enc_len, 0));
235 printf("dec: %s\n", sprint_hex_inrow_ex(dec, args->enc_len, 0));
236 printf("\nValid Key found [ " _GREEN_("%012" PRIx64) " ]\n\n", key);
237 pthread_mutex_unlock(&print_lock);
238 break;
241 free(args);
242 return NULL;
245 static int usage(void) {
246 printf(" syntax: mf_trace_brute <uid> <partial key> <{nt}> <{nr}> [<{next_command + 18 bytes}>]\n\n");
247 return 1;
250 int main(int argc, const char *argv[]) {
251 printf("Mifare classic nested auth key recovery Phase 2\n");
252 if (argc < 3) return usage();
254 uint32_t uid = 0; // serial number
255 uint32_t part_key = 0; // last 4 keys of key
256 uint32_t nt_enc = 0; // noncce tag
257 uint32_t nr_enc = 0; // nonce reader encrypted
259 sscanf(argv[1], "%x", &uid);
260 sscanf(argv[2], "%x", &part_key);
261 sscanf(argv[3], "%x", &nt_enc);
262 sscanf(argv[4], "%x", &nr_enc);
264 int enc_len = 0;
265 uint8_t enc[ENC_LEN] = {0}; // next encrypted command + a full read/write
266 param_gethex_to_eol(argv[5], 0, enc, sizeof(enc), &enc_len);
268 printf("-------------------------------------------------\n");
269 printf("uid.................. %08x\n", uid);
270 printf("partial key.......... %08x\n", part_key);
271 printf("nt enc............... %08x\n", nt_enc);
272 printf("nr enc............... %08x\n", nr_enc);
273 printf("next encrypted cmd... %s\n", sprint_hex_inrow_ex(enc, enc_len, 0));
275 uint64_t t1 = msclock();
277 #if !defined(_WIN32) || !defined(__WIN32__)
278 thread_count = sysconf(_SC_NPROCESSORS_CONF);
279 if (thread_count < 2)
280 thread_count = 2;
281 #endif /* _WIN32 */
283 printf("\nBruteforce using %d threads to find upper 16bits of key\n", thread_count);
285 pthread_t threads[thread_count];
287 // create a mutex to avoid interlacing print commands from our different threads
288 pthread_mutex_init(&print_lock, NULL);
290 // threads
291 for (int i = 0; i < thread_count; ++i) {
292 struct thread_args *a = calloc(1, sizeof(struct thread_args));
293 a->thread = i;
294 a->idx = i;
295 a->uid = uid;
296 a->part_key = part_key;
297 a->nt_enc = nt_enc;
298 a->nr_enc = nr_enc;
299 a->enc_len = enc_len;
300 memcpy(a->enc, enc, enc_len);
301 pthread_create(&threads[i], NULL, brute_thread, (void *)a);
304 // wait for threads to terminate:
305 for (int i = 0; i < thread_count; ++i)
306 pthread_join(threads[i], NULL);
308 if (global_found == false) {
309 printf("\nFailed to find a key\n\n");
312 t1 = msclock() - t1;
313 if (t1 > 0)
314 printf("execution time " _YELLOW_("%.2f") " sec\n", (float)t1 / 1000.0);
316 // clean up mutex
317 pthread_mutex_destroy(&print_lock);
318 return 0;