]> cvs.zerfleddert.de Git - proxmark3-svn/blame_incremental - client/mifarehost.c
improved command hf mf sniff. Now it cant decode nested authentication and cant write...
[proxmark3-svn] / client / mifarehost.c
... / ...
CommitLineData
1// Merlok, 2011, 2012\r
2// people from mifare@nethemba.com, 2010\r
3//\r
4// This code is licensed to you under the terms of the GNU GPL, version 2 or,\r
5// at your option, any later version. See the LICENSE.txt file for the text of\r
6// the license.\r
7//-----------------------------------------------------------------------------\r
8// mifare commands\r
9//-----------------------------------------------------------------------------\r
10\r
11#include <stdio.h>\r
12#include <stdlib.h> \r
13#include <string.h>\r
14#include "mifarehost.h"\r
15\r
16// MIFARE\r
17\r
18int compar_int(const void * a, const void * b) {\r
19 return (*(uint64_t*)b - *(uint64_t*)a);\r
20}\r
21\r
22// Compare countKeys structure\r
23int compar_special_int(const void * a, const void * b) {\r
24 return (((countKeys *)b)->count - ((countKeys *)a)->count);\r
25}\r
26\r
27countKeys * uniqsort(uint64_t * possibleKeys, uint32_t size) {\r
28 int i, j = 0;\r
29 int count = 0;\r
30 countKeys *our_counts;\r
31 \r
32 qsort(possibleKeys, size, sizeof (uint64_t), compar_int);\r
33 \r
34 our_counts = calloc(size, sizeof(countKeys));\r
35 if (our_counts == NULL) {\r
36 PrintAndLog("Memory allocation error for our_counts");\r
37 return NULL;\r
38 }\r
39 \r
40 for (i = 0; i < size; i++) {\r
41 if (possibleKeys[i+1] == possibleKeys[i]) { \r
42 count++;\r
43 } else {\r
44 our_counts[j].key = possibleKeys[i];\r
45 our_counts[j].count = count;\r
46 j++;\r
47 count=0;\r
48 }\r
49 }\r
50 qsort(our_counts, j, sizeof(countKeys), compar_special_int);\r
51 return (our_counts);\r
52}\r
53\r
54int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * resultKeys) \r
55{\r
56 int i, m, len;\r
57 uint8_t isEOF;\r
58 uint32_t uid;\r
59 fnVector * vector = NULL;\r
60 countKeys *ck;\r
61 int lenVector = 0;\r
62 UsbCommand * resp = NULL;\r
63 \r
64 memset(resultKeys, 0x00, 16 * 6);\r
65\r
66 // flush queue\r
67 while (WaitForResponseTimeout(CMD_ACK, 500) != NULL) ;\r
68 \r
69 UsbCommand c = {CMD_MIFARE_NESTED, {blockNo, keyType, trgBlockNo + trgKeyType * 0x100}};\r
70 memcpy(c.d.asBytes, key, 6);\r
71 SendCommand(&c);\r
72\r
73 PrintAndLog("\n");\r
74\r
75 // wait cycle\r
76 while (true) {\r
77 printf(".");\r
78 if (ukbhit()) {\r
79 getchar();\r
80 printf("\naborted via keyboard!\n");\r
81 break;\r
82 }\r
83\r
84 resp = WaitForResponseTimeout(CMD_ACK, 1500);\r
85\r
86 if (resp != NULL) {\r
87 isEOF = resp->arg[0] & 0xff;\r
88\r
89 if (isEOF) break;\r
90 \r
91 len = resp->arg[1] & 0xff;\r
92 if (len == 0) continue;\r
93 \r
94 memcpy(&uid, resp->d.asBytes, 4); \r
95 PrintAndLog("uid:%08x len=%d trgbl=%d trgkey=%x", uid, len, resp->arg[2] & 0xff, (resp->arg[2] >> 8) & 0xff);\r
96 vector = (fnVector *) realloc((void *)vector, (lenVector + len) * sizeof(fnVector) + 200);\r
97 if (vector == NULL) {\r
98 PrintAndLog("Memory allocation error for fnVector. len: %d bytes: %d", lenVector + len, (lenVector + len) * sizeof(fnVector)); \r
99 break;\r
100 }\r
101 \r
102 for (i = 0; i < len; i++) {\r
103 vector[lenVector + i].blockNo = resp->arg[2] & 0xff;\r
104 vector[lenVector + i].keyType = (resp->arg[2] >> 8) & 0xff;\r
105 vector[lenVector + i].uid = uid;\r
106\r
107 memcpy(&vector[lenVector + i].nt, (void *)(resp->d.asBytes + 8 + i * 8 + 0), 4);\r
108 memcpy(&vector[lenVector + i].ks1, (void *)(resp->d.asBytes + 8 + i * 8 + 4), 4);\r
109 }\r
110\r
111 lenVector += len;\r
112 }\r
113 }\r
114 \r
115 if (!lenVector) {\r
116 PrintAndLog("Got 0 keys from proxmark."); \r
117 return 1;\r
118 }\r
119 printf("------------------------------------------------------------------\n");\r
120 \r
121 // calc keys\r
122 struct Crypto1State* revstate = NULL;\r
123 struct Crypto1State* revstate_start = NULL;\r
124 uint64_t lfsr;\r
125 int kcount = 0;\r
126 pKeys *pk;\r
127 \r
128 if ((pk = (void *) malloc(sizeof(pKeys))) == NULL) return 1;\r
129 memset(pk, 0x00, sizeof(pKeys));\r
130 \r
131 for (m = 0; m < lenVector; m++) {\r
132 // And finally recover the first 32 bits of the key\r
133 revstate = lfsr_recovery32(vector[m].ks1, vector[m].nt ^ vector[m].uid);\r
134 if (revstate_start == NULL) revstate_start = revstate;\r
135 \r
136 while ((revstate->odd != 0x0) || (revstate->even != 0x0)) {\r
137 lfsr_rollback_word(revstate, vector[m].nt ^ vector[m].uid, 0);\r
138 crypto1_get_lfsr(revstate, &lfsr);\r
139\r
140 // Allocate a new space for keys\r
141 if (((kcount % MEM_CHUNK) == 0) || (kcount >= pk->size)) {\r
142 pk->size += MEM_CHUNK;\r
143//fprintf(stdout, "New chunk by %d, sizeof %d\n", kcount, pk->size * sizeof(uint64_t));\r
144 pk->possibleKeys = (uint64_t *) realloc((void *)pk->possibleKeys, pk->size * sizeof(uint64_t));\r
145 if (pk->possibleKeys == NULL) {\r
146 PrintAndLog("Memory allocation error for pk->possibleKeys"); \r
147 return 1;\r
148 }\r
149 }\r
150 pk->possibleKeys[kcount] = lfsr;\r
151 kcount++;\r
152 revstate++;\r
153 }\r
154 free(revstate_start);\r
155 revstate_start = NULL;\r
156\r
157 }\r
158 \r
159 // Truncate\r
160 if (kcount != 0) {\r
161 pk->size = --kcount;\r
162 if ((pk->possibleKeys = (uint64_t *) realloc((void *)pk->possibleKeys, pk->size * sizeof(uint64_t))) == NULL) {\r
163 PrintAndLog("Memory allocation error for pk->possibleKeys"); \r
164 return 1;\r
165 } \r
166 }\r
167\r
168 PrintAndLog("Total keys count:%d", kcount);\r
169 ck = uniqsort(pk->possibleKeys, pk->size);\r
170\r
171 // fill key array\r
172 for (i = 0; i < 16 ; i++) {\r
173 num_to_bytes(ck[i].key, 6, (uint8_t*)(resultKeys + i * 6));\r
174 }\r
175\r
176 // finalize\r
177 free(pk->possibleKeys);\r
178 free(pk);\r
179 free(ck);\r
180 free(vector);\r
181\r
182 return 0;\r
183}\r
184\r
185int mfCheckKeys (uint8_t blockNo, uint8_t keyType, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key){\r
186 *key = 0;\r
187\r
188 UsbCommand c = {CMD_MIFARE_CHKKEYS, {blockNo, keyType, keycnt}};\r
189 memcpy(c.d.asBytes, keyBlock, 6 * keycnt);\r
190\r
191 SendCommand(&c);\r
192\r
193 UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 3000);\r
194\r
195 if (resp == NULL) return 1;\r
196 if ((resp->arg[0] & 0xff) != 0x01) return 2;\r
197 *key = bytes_to_num(resp->d.asBytes, 6);\r
198 return 0;\r
199}\r
200\r
201// EMULATOR\r
202\r
203int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount) {\r
204 UsbCommand c = {CMD_MIFARE_EML_MEMGET, {blockNum, blocksCount, 0}};\r
205 \r
206 SendCommand(&c);\r
207\r
208 UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500);\r
209\r
210 if (resp == NULL) return 1;\r
211 memcpy(data, resp->d.asBytes, blocksCount * 16); \r
212 return 0;\r
213}\r
214\r
215int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount) {\r
216 UsbCommand c = {CMD_MIFARE_EML_MEMSET, {blockNum, blocksCount, 0}};\r
217 memcpy(c.d.asBytes, data, blocksCount * 16); \r
218 SendCommand(&c);\r
219 return 0;\r
220}\r
221\r
222// "MAGIC" CARD\r
223\r
224int mfCSetUID(uint8_t *uid, uint8_t *oldUID, int wantWipe) {\r
225 uint8_t block0[16];\r
226 memset(block0, 0, 16);\r
227 memcpy(block0, uid, 4); \r
228 block0[4] = block0[0]^block0[1]^block0[2]^block0[3]; // Mifare UID BCC\r
229 // mifare classic SAK(byte 5) and ATQA(byte 6 and 7)\r
230 block0[5] = 0x88;\r
231 block0[6] = 0x04;\r
232 block0[7] = 0x00;\r
233 \r
234 return mfCSetBlock(0, block0, oldUID, wantWipe, CSETBLOCK_SINGLE_OPER);\r
235}\r
236\r
237int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, int wantWipe, uint8_t params) {\r
238 uint8_t isOK = 0;\r
239\r
240 UsbCommand c = {CMD_MIFARE_EML_CSETBLOCK, {wantWipe, params & (0xFE | (uid == NULL ? 0:1)), blockNo}};\r
241 memcpy(c.d.asBytes, data, 16); \r
242 SendCommand(&c);\r
243\r
244 UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500);\r
245\r
246 if (resp != NULL) {\r
247 isOK = resp->arg[0] & 0xff;\r
248 if (uid != NULL) memcpy(uid, resp->d.asBytes, 4); \r
249 if (!isOK) return 2;\r
250 } else {\r
251 PrintAndLog("Command execute timeout");\r
252 return 1;\r
253 }\r
254 return 0;\r
255}\r
256\r
257int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params) {\r
258 uint8_t isOK = 0;\r
259\r
260 UsbCommand c = {CMD_MIFARE_EML_CGETBLOCK, {params, 0, blockNo}};\r
261 SendCommand(&c);\r
262\r
263 UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500);\r
264\r
265 if (resp != NULL) {\r
266 isOK = resp->arg[0] & 0xff;\r
267 memcpy(data, resp->d.asBytes, 16); \r
268 if (!isOK) return 2;\r
269 } else {\r
270 PrintAndLog("Command execute timeout");\r
271 return 1;\r
272 }\r
273 return 0;\r
274}\r
275\r
276// SNIFFER\r
277\r
278// variables\r
279char logHexFileName[200] = {0x00};\r
280static uint8_t traceCard[4096];\r
281static int traceState = TRACE_IDLE;\r
282static uint8_t traceCurBlock = 0;\r
283static uint8_t traceCurKey = 0;\r
284\r
285struct Crypto1State *traceCrypto1 = NULL;\r
286\r
287struct Crypto1State *revstate;\r
288uint64_t lfsr;\r
289uint32_t ks2;\r
290uint32_t ks3;\r
291\r
292uint32_t uid; // serial number\r
293uint32_t nt; // tag challenge\r
294uint32_t nr_enc; // encrypted reader challenge\r
295uint32_t ar_enc; // encrypted reader response\r
296uint32_t at_enc; // encrypted tag response\r
297\r
298int mfTraceInit(uint8_t *tuid, uint8_t *atqa, uint8_t sak) {\r
299\r
300 if (traceCrypto1) crypto1_destroy(traceCrypto1);\r
301 traceCrypto1 = NULL;\r
302\r
303 memset(traceCard, 0x00, 4096);\r
304 memcpy(traceCard, tuid + 3, 4);\r
305 traceCard[4] = traceCard[0] ^ traceCard[1] ^ traceCard[2] ^ traceCard[3];\r
306 traceCard[5] = sak;\r
307 memcpy(&traceCard[6], atqa, 2);\r
308 traceCurBlock = 0;\r
309 uid = bytes_to_num(tuid + 3, 4);\r
310 \r
311 traceState = TRACE_IDLE;\r
312\r
313 return 0;\r
314}\r
315\r
316void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted){\r
317 uint8_t bt = 0;\r
318 int i;\r
319 \r
320 if (len != 1) {\r
321 for (i = 0; i < len; i++)\r
322 data[i] = crypto1_byte(pcs, 0x00, isEncrypted) ^ data[i];\r
323 } else {\r
324 bt = 0;\r
325 for (i = 0; i < 4; i++)\r
326 bt |= (crypto1_bit(pcs, 0, isEncrypted) ^ BIT(data[0], i)) << i;\r
327 \r
328 data[0] = bt;\r
329 }\r
330 return;\r
331}\r
332\r
333\r
334int mfTraceDecode(uint8_t *data_src, int len) {\r
335 uint8_t data[64];\r
336\r
337 if (traceState == TRACE_ERROR) return 1;\r
338 if (len > 64) {\r
339 traceState = TRACE_ERROR;\r
340 return 1;\r
341 }\r
342 \r
343 memcpy(data, data_src, len);\r
344 if ((traceCrypto1) && ((traceState == TRACE_IDLE) || (traceState > TRACE_AUTH_OK))) {\r
345 mf_crypto1_decrypt(traceCrypto1, data, len, 0);\r
346 PrintAndLog("dec> %s", sprint_hex(data, len));\r
347 AddLogHex(logHexFileName, "dec> ", data, len); \r
348 }\r
349 \r
350 switch (traceState) {\r
351 case TRACE_IDLE: \r
352 // TODO: check packet crc16!\r
353 \r
354 // AUTHENTICATION\r
355 if ((len ==4) && ((data[0] == 0x60) || (data[0] == 0x61))) {\r
356 traceState = TRACE_AUTH1;\r
357 traceCurBlock = data[1];\r
358 traceCurKey = data[0] == 60 ? 1:0;\r
359 return 0;\r
360 }\r
361\r
362 // READ\r
363 if ((len ==4) && ((data[0] == 0x30))) {\r
364 traceState = TRACE_READ_DATA;\r
365 traceCurBlock = data[1];\r
366 return 0;\r
367 }\r
368\r
369 // WRITE\r
370 if ((len ==4) && ((data[0] == 0xA0))) {\r
371 traceState = TRACE_WRITE_OK;\r
372 traceCurBlock = data[1];\r
373 return 0;\r
374 }\r
375\r
376 // HALT\r
377 if ((len ==4) && ((data[0] == 0x50) && (data[1] == 0x00))) {\r
378 traceState = TRACE_ERROR; // do not decrypt the next commands\r
379 return 0;\r
380 }\r
381 \r
382 return 0;\r
383 break;\r
384 \r
385 case TRACE_READ_DATA: \r
386 if (len == 18) {\r
387 traceState = TRACE_IDLE;\r
388\r
389 memcpy(traceCard + traceCurBlock * 16, data, 16);\r
390 return 0;\r
391 } else {\r
392 traceState = TRACE_ERROR;\r
393 return 1;\r
394 }\r
395 break;\r
396\r
397 case TRACE_WRITE_OK: \r
398 if ((len == 1) && (data[0] = 0x0a)) {\r
399 traceState = TRACE_WRITE_DATA;\r
400\r
401 return 0;\r
402 } else {\r
403 traceState = TRACE_ERROR;\r
404 return 1;\r
405 }\r
406 break;\r
407\r
408 case TRACE_WRITE_DATA: \r
409 if (len == 18) {\r
410 traceState = TRACE_IDLE;\r
411\r
412 memcpy(traceCard + traceCurBlock * 16, data, 16);\r
413 return 0;\r
414 } else {\r
415 traceState = TRACE_ERROR;\r
416 return 1;\r
417 }\r
418 break;\r
419\r
420 case TRACE_AUTH1: \r
421 if (len == 4) {\r
422 traceState = TRACE_AUTH2;\r
423\r
424 nt = bytes_to_num(data, 4);\r
425 return 0;\r
426 } else {\r
427 traceState = TRACE_ERROR;\r
428 return 1;\r
429 }\r
430 break;\r
431\r
432 case TRACE_AUTH2: \r
433 if (len == 8) {\r
434 traceState = TRACE_AUTH_OK;\r
435\r
436 nr_enc = bytes_to_num(data, 4);\r
437 ar_enc = bytes_to_num(data + 4, 4);\r
438 return 0;\r
439 } else {\r
440 traceState = TRACE_ERROR;\r
441 return 1;\r
442 }\r
443 break;\r
444\r
445 case TRACE_AUTH_OK: \r
446 if (len ==4) {\r
447 traceState = TRACE_IDLE;\r
448\r
449 at_enc = bytes_to_num(data, 4);\r
450 \r
451 // decode key here)\r
452 if (!traceCrypto1) {\r
453 ks2 = ar_enc ^ prng_successor(nt, 64);\r
454 ks3 = at_enc ^ prng_successor(nt, 96);\r
455 revstate = lfsr_recovery64(ks2, ks3);\r
456 lfsr_rollback_word(revstate, 0, 0);\r
457 lfsr_rollback_word(revstate, 0, 0);\r
458 lfsr_rollback_word(revstate, nr_enc, 1);\r
459 lfsr_rollback_word(revstate, uid ^ nt, 0);\r
460 }else{\r
461 ks2 = ar_enc ^ prng_successor(nt, 64);\r
462 ks3 = at_enc ^ prng_successor(nt, 96);\r
463 revstate = lfsr_recovery64(ks2, ks3);\r
464 lfsr_rollback_word(revstate, 0, 0);\r
465 lfsr_rollback_word(revstate, 0, 0);\r
466 lfsr_rollback_word(revstate, nr_enc, 1);\r
467 lfsr_rollback_word(revstate, uid ^ nt, 0);\r
468 }\r
469 crypto1_get_lfsr(revstate, &lfsr);\r
470 printf("key> %x%x\n", (unsigned int)((lfsr & 0xFFFFFFFF00000000) >> 32), (unsigned int)(lfsr & 0xFFFFFFFF));\r
471 AddLogUint64(logHexFileName, "key> ", lfsr); \r
472 \r
473 if (traceCurKey) {\r
474 num_to_bytes(lfsr, 6, traceCard + traceCurBlock * 16 + 10);\r
475 } else {\r
476 num_to_bytes(lfsr, 6, traceCard + traceCurBlock * 16);\r
477 }\r
478\r
479 if (traceCrypto1) {\r
480 crypto1_destroy(traceCrypto1);\r
481 }\r
482 \r
483 // set cryptosystem state\r
484 traceCrypto1 = lfsr_recovery64(ks2, ks3);\r
485 \r
486// nt = crypto1_word(traceCrypto1, nt ^ uid, 1) ^ nt;\r
487\r
488 /* traceCrypto1 = crypto1_create(lfsr); // key in lfsr\r
489 crypto1_word(traceCrypto1, nt ^ uid, 0);\r
490 crypto1_word(traceCrypto1, ar, 1);\r
491 crypto1_word(traceCrypto1, 0, 0);\r
492 crypto1_word(traceCrypto1, 0, 0);*/\r
493 \r
494 return 0;\r
495 } else {\r
496 traceState = TRACE_ERROR;\r
497 return 1;\r
498 }\r
499 break;\r
500\r
501 default: \r
502 traceState = TRACE_ERROR;\r
503 return 1;\r
504 }\r
505\r
506 return 0;\r
507}\r
Impressum, Datenschutz