]> git.zerfleddert.de Git - proxmark3-svn/blob - client/cmdhficlass.c
hf mf dump bugfix: wrongly tried key A instead of key B for a specific Access Condition
[proxmark3-svn] / client / cmdhficlass.c
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch
3 // Copyright (C) 2011 Gerhard de Koning Gans
4 //
5 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
6 // at your option, any later version. See the LICENSE.txt file for the text of
7 // the license.
8 //-----------------------------------------------------------------------------
9 // High frequency iClass commands
10 //-----------------------------------------------------------------------------
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/stat.h>
16 #include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type
17 #include "data.h"
18 //#include "proxusb.h"
19 #include "proxmark3.h"
20 #include "ui.h"
21 #include "cmdparser.h"
22 #include "cmdhficlass.h"
23 #include "common.h"
24 #include "util.h"
25 #include "cmdmain.h"
26
27 static int CmdHelp(const char *Cmd);
28
29 int xorbits_8(uint8_t val)
30 {
31 uint8_t res = val ^ (val >> 1); //1st pass
32 res = res ^ (res >> 1); // 2nd pass
33 res = res ^ (res >> 2); // 3rd pass
34 res = res ^ (res >> 4); // 4th pass
35 return res & 1;
36 }
37
38 int CmdHFiClassList(const char *Cmd)
39 {
40
41 bool ShowWaitCycles = false;
42 char param = param_getchar(Cmd, 0);
43
44 if (param != 0) {
45 PrintAndLog("List data in trace buffer.");
46 PrintAndLog("Usage: hf iclass list");
47 PrintAndLog("h - help");
48 PrintAndLog("sample: hf iclass list");
49 return 0;
50 }
51
52 uint8_t got[1920];
53 GetFromBigBuf(got,sizeof(got),0);
54 WaitForResponse(CMD_ACK,NULL);
55
56 PrintAndLog("Recorded Activity");
57 PrintAndLog("");
58 PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer");
59 PrintAndLog("All times are in carrier periods (1/13.56Mhz)");
60 PrintAndLog("");
61 PrintAndLog(" Start | End | Src | Data");
62 PrintAndLog("-----------|-----------|-----|--------");
63
64 int i;
65 uint32_t first_timestamp = 0;
66 uint32_t timestamp;
67 bool tagToReader;
68 uint32_t parityBits;
69 uint8_t len;
70 uint8_t *frame;
71 uint32_t EndOfTransmissionTimestamp = 0;
72
73
74 for( i=0; i < 1900;)
75 {
76 //First 32 bits contain
77 // isResponse (1 bit)
78 // timestamp (remaining)
79 //Then paritybits
80 //Then length
81 timestamp = *((uint32_t *)(got+i));
82 parityBits = *((uint32_t *)(got+i+4));
83 len = got[i+8];
84 frame = (got+i+9);
85 uint32_t next_timestamp = (*((uint32_t *)(got+i+9))) & 0x7fffffff;
86
87 tagToReader = timestamp & 0x80000000;
88 timestamp &= 0x7fffffff;
89
90 if(i==0) {
91 first_timestamp = timestamp;
92 }
93
94 // Break and stick with current result if buffer was not completely full
95 if (frame[0] == 0x44 && frame[1] == 0x44 && frame[2] == 0x44 && frame[3] == 0x44) break;
96
97 char line[1000] = "";
98
99 if(len)//We have some data to display
100 {
101 int j,oddparity;
102
103 for(j = 0; j < len ; j++)
104 {
105 oddparity = 0x01 ^ xorbits_8(frame[j] & 0xFF);
106
107 if (tagToReader && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) {
108 sprintf(line+(j*4), "%02x! ", frame[j]);
109 } else {
110 sprintf(line+(j*4), "%02x ", frame[j]);
111 }
112 }
113 }else
114 {
115 if (ShowWaitCycles) {
116 sprintf(line, "fdt (Frame Delay Time): %d", (next_timestamp - timestamp));
117 }
118 }
119
120 char *crc = "";
121
122 if(len > 2)
123 {
124 uint8_t b1, b2;
125 if(!tagToReader && len == 4) {
126 // Rough guess that this is a command from the reader
127 // For iClass the command byte is not part of the CRC
128 ComputeCrc14443(CRC_ICLASS, &frame[1], len-3, &b1, &b2);
129 }
130 else {
131 // For other data.. CRC might not be applicable (UPDATE commands etc.)
132 ComputeCrc14443(CRC_ICLASS, frame, len-2, &b1, &b2);
133 }
134
135 if (b1 != frame[len-2] || b2 != frame[len-1]) {
136 crc = (tagToReader & (len < 8)) ? "" : " !crc";
137 }
138 }
139
140 i += (len + 9);
141 EndOfTransmissionTimestamp = (*((uint32_t *)(got+i))) & 0x7fffffff;
142
143 // Not implemented for iclass on the ARM-side
144 //if (!ShowWaitCycles) i += 9;
145
146 PrintAndLog(" %9d | %9d | %s | %s %s",
147 (timestamp - first_timestamp),
148 (EndOfTransmissionTimestamp - first_timestamp),
149 (len?(tagToReader ? "Tag" : "Rdr"):" "),
150 line, crc);
151 }
152 return 0;
153 }
154
155 int CmdHFiClassListOld(const char *Cmd)
156 {
157 uint8_t got[1920];
158 GetFromBigBuf(got,sizeof(got),0);
159
160 PrintAndLog("recorded activity:");
161 PrintAndLog(" ETU :rssi: who bytes");
162 PrintAndLog("---------+----+----+-----------");
163
164 int i = 0;
165 int prev = -1;
166
167 for (;;) {
168 if(i >= 1900) {
169 break;
170 }
171
172 bool isResponse;
173 int timestamp = *((uint32_t *)(got+i));
174 if (timestamp & 0x80000000) {
175 timestamp &= 0x7fffffff;
176 isResponse = 1;
177 } else {
178 isResponse = 0;
179 }
180
181
182 int metric = 0;
183
184 int parityBits = *((uint32_t *)(got+i+4));
185 // 4 bytes of additional information...
186 // maximum of 32 additional parity bit information
187 //
188 // TODO:
189 // at each quarter bit period we can send power level (16 levels)
190 // or each half bit period in 256 levels.
191
192
193 int len = got[i+8];
194
195 if (len > 100) {
196 break;
197 }
198 if (i + len >= 1900) {
199 break;
200 }
201
202 uint8_t *frame = (got+i+9);
203
204 // Break and stick with current result if buffer was not completely full
205 if (frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; }
206
207 char line[1000] = "";
208 int j;
209 for (j = 0; j < len; j++) {
210 int oddparity = 0x01;
211 int k;
212
213 for (k=0;k<8;k++) {
214 oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01);
215 }
216
217 //if((parityBits >> (len - j - 1)) & 0x01) {
218 if (isResponse && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) {
219 sprintf(line+(j*4), "%02x! ", frame[j]);
220 }
221 else {
222 sprintf(line+(j*4), "%02x ", frame[j]);
223 }
224 }
225
226 char *crc;
227 crc = "";
228 if (len > 2) {
229 uint8_t b1, b2;
230 for (j = 0; j < (len - 1); j++) {
231 // gives problems... search for the reason..
232 /*if(frame[j] == 0xAA) {
233 switch(frame[j+1]) {
234 case 0x01:
235 crc = "[1] Two drops close after each other";
236 break;
237 case 0x02:
238 crc = "[2] Potential SOC with a drop in second half of bitperiod";
239 break;
240 case 0x03:
241 crc = "[3] Segment Z after segment X is not possible";
242 break;
243 case 0x04:
244 crc = "[4] Parity bit of a fully received byte was wrong";
245 break;
246 default:
247 crc = "[?] Unknown error";
248 break;
249 }
250 break;
251 }*/
252 }
253
254 if (strlen(crc)==0) {
255 if(!isResponse && len == 4) {
256 // Rough guess that this is a command from the reader
257 // For iClass the command byte is not part of the CRC
258 ComputeCrc14443(CRC_ICLASS, &frame[1], len-3, &b1, &b2);
259 }
260 else {
261 // For other data.. CRC might not be applicable (UPDATE commands etc.)
262 ComputeCrc14443(CRC_ICLASS, frame, len-2, &b1, &b2);
263 }
264 //printf("%1x %1x",(unsigned)b1,(unsigned)b2);
265 if (b1 != frame[len-2] || b2 != frame[len-1]) {
266 crc = (isResponse & (len < 8)) ? "" : " !crc";
267 } else {
268 crc = "";
269 }
270 }
271 } else {
272 crc = ""; // SHORT
273 }
274
275 char metricString[100];
276 if (isResponse) {
277 sprintf(metricString, "%3d", metric);
278 } else {
279 strcpy(metricString, " ");
280 }
281
282 PrintAndLog(" +%7d: %s: %s %s %s",
283 (prev < 0 ? 0 : (timestamp - prev)),
284 metricString,
285 (isResponse ? "TAG" : " "), line, crc);
286
287 prev = timestamp;
288 i += (len + 9);
289 }
290 return 0;
291 }
292
293 /*void iso14a_set_timeout(uint32_t timeout) {
294 UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_SET_TIMEOUT, 0, timeout}};
295 SendCommand(&c);
296 }*/
297
298 int CmdHFiClassSnoop(const char *Cmd)
299 {
300 UsbCommand c = {CMD_SNOOP_ICLASS};
301 SendCommand(&c);
302 return 0;
303 }
304
305 int CmdHFiClassSim(const char *Cmd)
306 {
307 uint8_t simType = 0;
308 uint8_t CSN[8] = {0, 0, 0, 0, 0, 0, 0, 0};
309
310 if (strlen(Cmd)<1) {
311 PrintAndLog("Usage: hf iclass sim [0 <CSN>] | x");
312 PrintAndLog(" options");
313 PrintAndLog(" 0 <CSN> simulate the given CSN");
314 PrintAndLog(" 1 simulate default CSN");
315 PrintAndLog(" 2 iterate CSNs, gather MACs");
316 PrintAndLog(" sample: hf iclass sim 0 031FEC8AF7FF12E0");
317 PrintAndLog(" sample: hf iclass sim 2");
318 return 0;
319 }
320
321 simType = param_get8(Cmd, 0);
322
323 if(simType == 0)
324 {
325 if (param_gethex(Cmd, 1, CSN, 16)) {
326 PrintAndLog("A CSN should consist of 16 HEX symbols");
327 return 1;
328 }
329 PrintAndLog("--simtype:%02x csn:%s", simType, sprint_hex(CSN, 8));
330
331 }
332 if(simType > 2)
333 {
334 PrintAndLog("Undefined simptype %d", simType);
335 return 1;
336 }
337 uint8_t numberOfCSNs=0;
338
339 if(simType == 2)
340 {
341 UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType,63}};
342 UsbCommand resp = {0};
343
344 uint8_t csns[64] = {
345 0x00,0x0B,0x0F,0xFF,0xF7,0xFF,0x12,0xE0 ,
346 0x00,0x13,0x94,0x7e,0x76,0xff,0x12,0xe0 ,
347 0x2a,0x99,0xac,0x79,0xec,0xff,0x12,0xe0 ,
348 0x17,0x12,0x01,0xfd,0xf7,0xff,0x12,0xe0 ,
349 0xcd,0x56,0x01,0x7c,0x6f,0xff,0x12,0xe0 ,
350 0x4b,0x5e,0x0b,0x72,0xef,0xff,0x12,0xe0 ,
351 0x00,0x73,0xd8,0x75,0x58,0xff,0x12,0xe0 ,
352 0x0c,0x90,0x32,0xf3,0x5d,0xff,0x12,0xe0 };
353
354 memcpy(c.d.asBytes, csns, 64);
355
356 SendCommand(&c);
357 if (!WaitForResponseTimeout(CMD_ACK, &resp, -1)) {
358 PrintAndLog("Command timed out");
359 return 0;
360 }
361
362 uint8_t num_mac_responses = resp.arg[1];
363 PrintAndLog("Mac responses: %d MACs obtained (should be 8)", num_mac_responses);
364
365 size_t datalen = 8*24;
366 /*
367 * Now, time to dump to file. We'll use this format:
368 * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
369 * So, it should wind up as
370 * 8 * 24 bytes.
371 *
372 * The returndata from the pm3 is on the following format
373 * <4 byte NR><4 byte MAC>
374 * CC are all zeroes, CSN is the same as was sent in
375 **/
376 void* dump = malloc(datalen);
377 memset(dump,0,datalen);//<-- Need zeroes for the CC-field
378 uint8_t i = 0;
379 for(i = 0 ; i < 8 ; i++)
380 {
381 memcpy(dump+i*24, csns+i*8,8); //CSN
382 //8 zero bytes here...
383 //Then comes NR_MAC (eight bytes from the response)
384 memcpy(dump+i*24+16,resp.d.asBytes+i*8,8);
385
386 }
387 /** Now, save to dumpfile **/
388 saveFile("iclass_mac_attack", "bin", dump,datalen);
389 free(dump);
390 }else
391 {
392 UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType,numberOfCSNs}};
393 memcpy(c.d.asBytes, CSN, 8);
394 SendCommand(&c);
395 }
396 return 0;
397 }
398
399 int CmdHFiClassReader(const char *Cmd)
400 {
401 uint8_t readerType = 0;
402
403 if (strlen(Cmd)<1) {
404 PrintAndLog("Usage: hf iclass reader <reader type>");
405 PrintAndLog(" sample: hf iclass reader 0");
406 return 0;
407 }
408
409 readerType = param_get8(Cmd, 0);
410 PrintAndLog("--readertype:%02x", readerType);
411
412 UsbCommand c = {CMD_READER_ICLASS, {readerType}};
413 //memcpy(c.d.asBytes, CSN, 8);
414 SendCommand(&c);
415
416 /*UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500);
417 if (resp != NULL) {
418 uint8_t isOK = resp->arg[0] & 0xff;
419 PrintAndLog("isOk:%02x", isOK);
420 } else {
421 PrintAndLog("Command execute timeout");
422 }*/
423
424 return 0;
425 }
426
427 static command_t CommandTable[] =
428 {
429 {"help", CmdHelp, 1, "This help"},
430 {"list", CmdHFiClassList, 0, "List iClass history"},
431 {"snoop", CmdHFiClassSnoop, 0, "Eavesdrop iClass communication"},
432 {"sim", CmdHFiClassSim, 0, "Simulate iClass tag"},
433 {"reader", CmdHFiClassReader, 0, "Read an iClass tag"},
434 {NULL, NULL, 0, NULL}
435 };
436
437 int CmdHFiClass(const char *Cmd)
438 {
439 CmdsParse(CommandTable, Cmd);
440 return 0;
441 }
442
443 int CmdHelp(const char *Cmd)
444 {
445 CmdsHelp(CommandTable);
446 return 0;
447 }
448
449 /**
450 * @brief checks if a file exists
451 * @param filename
452 * @return
453 */
454 int fileExists(const char *filename) {
455 struct stat st;
456 int result = stat(filename, &st);
457 return result == 0;
458 }
459 /**
460 * @brief Utility function to save data to a file. This method takes a preferred name, but if that
461 * file already exists, it tries with another name until it finds something suitable.
462 * E.g. dumpdata-15.txt
463 * @param preferredName
464 * @param suffix the file suffix. Leave out the ".".
465 * @param data The binary data to write to the file
466 * @param datalen the length of the data
467 * @return 0 for ok, 1 for failz
468 */
469 int saveFile(const char *preferredName, const char *suffix, const void* data, size_t datalen)
470 {
471 FILE *f = fopen(preferredName, "wb");
472 int size = sizeof(char) * (strlen(preferredName)+strlen(suffix)+5);
473 char * fileName = malloc(size);
474
475 memset(fileName,0,size);
476 int num = 1;
477 sprintf(fileName,"%s.%s", preferredName, suffix);
478 while(fileExists(fileName))
479 {
480 sprintf(fileName,"%s-%d.%s", preferredName, num, suffix);
481 num++;
482 }
483 /* We should have a valid filename now, e.g. dumpdata-3.bin */
484
485 /*Opening file for writing in binary mode*/
486 FILE *fileHandle=fopen(fileName,"wb");
487 if(!f) {
488 PrintAndLog("Failed to write to file '%s'", fileName);
489 return 0;
490 }
491 fwrite(data, 1, datalen, fileHandle);
492 fclose(fileHandle);
493 PrintAndLog("Saved data to '%s'", fileName);
494
495 free(fileName);
496 return 0;
497 }
Impressum, Datenschutz