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.
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.
10 #define __STDC_FORMAT_MACROS
20 #include "crapto1/crapto1.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
{
45 uint8_t enc
[ENC_LEN
]; // next encrypted command + a full read/write
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},
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
) {
65 int len
= strlen(line
);
71 while (line
[*bg
] == ' ' || line
[*bg
] == '\t')(*bg
)++;
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;
84 while (line
[*en
] != ' ' && line
[*en
] != '\t' && line
[*en
] != '\0')(*en
)++;
91 static int param_gethex_to_eol(const char *line
, int paramnum
, uint8_t *data
, int maxdatalen
, int *datalen
) {
96 if (param_getptr(line
, &bg
, &en
, paramnum
)) return 1;
102 if (line
[indx
] == '\t' || line
[indx
] == ' ') {
107 if (isxdigit(line
[indx
])) {
108 buf
[strlen(buf
) + 1] = 0x00;
109 buf
[strlen(buf
)] = line
[indx
];
111 // if we have symbols other than spaces and hex
115 if (*datalen
>= maxdatalen
) {
116 // if we dont have space in buffer and have symbols to translate
120 if (strlen(buf
) >= 2) {
121 sscanf(buf
, "%x", &temp
);
122 data
[*datalen
] = (uint8_t)(temp
& 0xff);
131 //error when not completed hex bytes
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
= (char *)buf
;
144 memset(tmp
, 0x00, hex_max_len
);
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 sprintf(tmp
, (uppercase
) ? "%02X" : "%02x", (unsigned int) hex_data
[i
]);
151 for (size_t j
= 0; j
< spaces_between
; j
++)
152 sprintf(tmp
+ 2 + j
, " ");
155 i
*= (2 + spaces_between
);
157 size_t mlen
= min_str_len
> i
? min_str_len
: 0;
158 if (mlen
> hex_max_len
)
161 for (; i
< mlen
; i
++, tmp
+= 1)
169 static char *sprint_hex_inrow_ex(const uint8_t *data
, const size_t len
, const size_t min_str_len
) {
170 static char buf
[100] = {0};
171 hex_to_buffer((uint8_t *)buf
, data
, len
, sizeof(buf
) - 1, min_str_len
, 0, true);
175 static bool checkValidCmdByte(uint8_t *cmd
, uint16_t n
) {
178 for (int i
= 0; i
< 8; ++i
) {
179 if (cmd
[0] == cmds
[i
][0]) {
182 ok
= CheckCrc14443(CRC_14443_A
, cmd
, 4);
184 if (cmds
[i
][1] > 0 && n
>= cmds
[i
][1])
185 ok
= CheckCrc14443(CRC_14443_A
, cmd
+ 4, cmds
[i
][1]);
195 static void *brute_thread(void *arguments
) {
197 struct thread_args
*args
= (struct thread_args
*) arguments
;
198 uint64_t key
= args
->part_key
;
199 uint8_t local_enc
[args
->enc_len
];
200 memcpy(local_enc
, args
->enc
, args
->enc_len
);
202 for (uint64_t count
= args
->idx
; count
< 0xFFFF; count
+= thread_count
) {
204 if (__atomic_load_n(&global_found
, __ATOMIC_ACQUIRE
) == 1) {
210 // Init cipher with key
211 struct Crypto1State
*pcs
= crypto1_create(key
);
213 // NESTED decrypt nt with help of new key
214 crypto1_word(pcs
, args
->nt_enc
^ args
->uid
, 1);
215 crypto1_word(pcs
, args
->nr_enc
, 1);
216 crypto1_word(pcs
, 0, 0);
217 crypto1_word(pcs
, 0, 0);
220 uint8_t dec
[args
->enc_len
];
221 for (int i
= 0; i
< args
->enc_len
; i
++)
222 dec
[i
] = crypto1_byte(pcs
, 0x00, 0) ^ local_enc
[i
];
224 crypto1_destroy(pcs
);
226 if (checkValidCmdByte(dec
, args
->enc_len
) == false) {
229 __sync_fetch_and_add(&global_found
, 1);
231 // lock this section to avoid interlacing prints from different threats
232 pthread_mutex_lock(&print_lock
);
233 printf("\nenc: %s\n", sprint_hex_inrow_ex(local_enc
, args
->enc_len
, 0));
234 printf("dec: %s\n", sprint_hex_inrow_ex(dec
, args
->enc_len
, 0));
235 printf("\nValid Key found [ " _GREEN_("%012" PRIx64
) " ]\n\n", key
);
236 pthread_mutex_unlock(&print_lock
);
244 static int usage(void) {
245 printf(" syntax: mf_trace_brute <uid> <partial key> <nt enc> <nr enc> [<next_command + 18 bytes>]\n\n");
249 int main(int argc
, char *argv
[]) {
250 printf("Mifare classic nested auth key recovery Phase 2\n");
251 if (argc
< 3) return usage();
253 uint32_t uid
= 0; // serial number
254 uint32_t part_key
= 0; // last 4 keys of key
255 uint32_t nt_enc
= 0; // noncce tag
256 uint32_t nr_enc
= 0; // nonce reader encrypted
258 sscanf(argv
[1], "%x", &uid
);
259 sscanf(argv
[2], "%x", &part_key
);
260 sscanf(argv
[3], "%x", &nt_enc
);
261 sscanf(argv
[4], "%x", &nr_enc
);
264 uint8_t enc
[ENC_LEN
] = {0}; // next encrypted command + a full read/write
265 param_gethex_to_eol(argv
[5], 0, enc
, sizeof(enc
), &enc_len
);
267 printf("-------------------------------------------------\n");
268 printf("uid.................. %08x\n", uid
);
269 printf("partial key.......... %08x\n", part_key
);
270 printf("nt enc............... %08x\n", nt_enc
);
271 printf("nr enc............... %08x\n", nr_enc
);
272 printf("next encrypted cmd... %s\n", sprint_hex_inrow_ex(enc
, enc_len
, 0));
274 uint64_t t1
= msclock();
276 #if !defined(_WIN32) || !defined(__WIN32__)
277 thread_count
= sysconf(_SC_NPROCESSORS_CONF
);
278 if (thread_count
< 2)
282 printf("\nBruteforce using %d threads to find upper 16bits of key\n", thread_count
);
284 pthread_t threads
[thread_count
];
286 // create a mutex to avoid interlacing print commands from our different threads
287 pthread_mutex_init(&print_lock
, NULL
);
290 for (int i
= 0; i
< thread_count
; ++i
) {
291 struct thread_args
*a
= calloc(1, sizeof(struct thread_args
));
295 a
->part_key
= part_key
;
298 a
->enc_len
= enc_len
;
299 memcpy(a
->enc
, enc
, enc_len
);
300 pthread_create(&threads
[i
], NULL
, brute_thread
, (void *)a
);
303 // wait for threads to terminate:
304 for (int i
= 0; i
< thread_count
; ++i
)
305 pthread_join(threads
[i
], NULL
);
307 if (global_found
== false) {
308 printf("\nFailed to find a key\n\n");
313 printf("execution time " _YELLOW_("%.2f") " sec\n", (float)t1
/ 1000.0);
316 pthread_mutex_destroy(&print_lock
);