]> git.zerfleddert.de Git - proxmark3-svn/blob - client/cmdhflegic.c
CHG: "hf legic dump" now automatically detects tagtype and dumps accordingly.
[proxmark3-svn] / client / cmdhflegic.c
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
3 //
4 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
5 // at your option, any later version. See the LICENSE.txt file for the text of
6 // the license.
7 //-----------------------------------------------------------------------------
8 // High frequency Legic commands
9 //-----------------------------------------------------------------------------
10 #include "cmdhflegic.h"
11
12 static int CmdHelp(const char *Cmd);
13
14 #define MAX_LENGTH 1024
15
16 int usage_legic_calccrc8(void){
17 PrintAndLog("Calculates the legic crc8/crc16 on the input hexbytes.");
18 PrintAndLog("There must be an even number of hexsymbols as input.");
19 PrintAndLog("Usage: hf legic crc8 [h] b <hexbytes> u <uidcrc> c <crc type>");
20 PrintAndLog("Options:");
21 PrintAndLog(" h : this help");
22 PrintAndLog(" b <hexbytes> : hex bytes");
23 PrintAndLog(" u <uidcrc> : MCC hexbyte");
24 PrintAndLog(" c <crc type> : 8|16 bit crc size");
25 PrintAndLog("");
26 PrintAndLog("Samples:");
27 PrintAndLog(" hf legic crc8 b deadbeef1122");
28 PrintAndLog(" hf legic crc8 b deadbeef1122 u 9A c 16");
29 return 0;
30 }
31 int usage_legic_load(void){
32 PrintAndLog("It loads datasamples from the file `filename` to device memory");
33 PrintAndLog("Usage: hf legic load [h] <file name>");
34 PrintAndLog("Options:");
35 PrintAndLog(" h : this help");
36 PrintAndLog(" <filename> : Name of file to load");
37 PrintAndLog("");
38 PrintAndLog("Samples:");
39 PrintAndLog(" hf legic load filename");
40 return 0;
41 }
42 int usage_legic_rdmem(void){
43 PrintAndLog("Read data from a legic tag.");
44 PrintAndLog("Usage: hf legic rdmem [h] <offset> <length> <IV>");
45 PrintAndLog("Options:");
46 PrintAndLog(" h : this help");
47 PrintAndLog(" <offset> : offset in data array to start download from (hex)");
48 PrintAndLog(" <length> : number of bytes to read (hex)");
49 PrintAndLog(" <IV> : (optional) Initialization vector to use (hex, odd and 7bits)");
50 PrintAndLog("");
51 PrintAndLog("Samples:");
52 PrintAndLog(" hf legic rdmem 0 21 - reads from byte[0] 21 bytes(system header)");
53 PrintAndLog(" hf legic rdmem 0 4 55 - reads from byte[0] 4 bytes with IV 0x55");
54 PrintAndLog(" hf legic rdmem 0 100 55 - reads 256bytes with IV 0x55");
55 return 0;
56 }
57 int usage_legic_sim(void){
58 PrintAndLog("Missing help text.");
59 return 0;
60 }
61 int usage_legic_write(void){
62 PrintAndLog(" Write sample buffer to a legic tag. (use after load or read)");
63 PrintAndLog("Usage: hf legic write [h] <offset> <length> <IV>");
64 PrintAndLog("Options:");
65 PrintAndLog(" h : this help");
66 PrintAndLog(" <offset> : offset in data array to start writing from (hex)");
67 PrintAndLog(" <length> : number of bytes to write (hex)");
68 PrintAndLog(" <IV> : (optional) Initialization vector to use (ODD and 7bits)");
69 PrintAndLog("");
70 PrintAndLog("Samples:");
71 PrintAndLog(" hf legic write 10 4 - writes 0x4 to byte[0x10]");
72 return 0;
73 }
74 int usage_legic_rawwrite(void){
75 PrintAndLog("Write raw data direct to a specific offset on legic tag.");
76 PrintAndLog("Usage: hf legic writeraw [h] <offset> <value> <IV>");
77 PrintAndLog("Options:");
78 PrintAndLog(" h : this help");
79 PrintAndLog(" <offset> : offset to write to (hex)");
80 PrintAndLog(" <value> : value (hex)");
81 PrintAndLog(" <IV> : (optional) Initialization vector to use (hex, odd and 7bits)");
82 PrintAndLog("");
83 PrintAndLog("Samples:");
84 PrintAndLog(" hf legic writeraw 10 4 - writes 0x4 to byte[0x10]");
85 return 0;
86 }
87 int usage_legic_fill(void){
88 PrintAndLog("Missing help text.");
89 return 0;
90 }
91 int usage_legic_reader(void){
92 PrintAndLog("Read UID and type information from a legic tag.");
93 PrintAndLog("Usage: hf legic reader [h]");
94 PrintAndLog("Options:");
95 PrintAndLog(" h : this help");
96 PrintAndLog("");
97 PrintAndLog("Samples:");
98 PrintAndLog(" hf legic reader");
99 return 0;
100 }
101 int usage_legic_info(void){
102 PrintAndLog("Reads information from a legic prime tag.");
103 PrintAndLog("Shows systemarea, user areas etc");
104 PrintAndLog("Usage: hf legic info [h]");
105 PrintAndLog("Options:");
106 PrintAndLog(" h : this help");
107 PrintAndLog("");
108 PrintAndLog("Samples:");
109 PrintAndLog(" hf legic info");
110 return 0;
111 }
112 int usage_legic_dump(void){
113 PrintAndLog("Reads all pages from LEGIC MIM22, MIM256, MIM1024");
114 PrintAndLog("and saves binary dump into the file `filename.bin` or `cardUID.bin`");
115 PrintAndLog("It autodetects card type.\n");
116 PrintAndLog("Usage: hf legic dump [h] o <filename w/o .bin>");
117 PrintAndLog("Options:");
118 PrintAndLog(" h : this help");
119 PrintAndLog(" n <FN> : filename w/o .bin to save the dump as");
120 PrintAndLog("");
121 PrintAndLog("Samples:");
122 PrintAndLog(" hf legic dump");
123 PrintAndLog(" hf legic dump o myfile");
124 return 0;
125 }
126
127 /*
128 * Output BigBuf and deobfuscate LEGIC RF tag data.
129 * This is based on information given in the talk held
130 * by Henryk Ploetz and Karsten Nohl at 26c3
131 */
132 int CmdLegicInfo(const char *Cmd) {
133
134 char cmdp = param_getchar(Cmd, 0);
135 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_info();
136
137 int i = 0, k = 0, segmentNum = 0, segment_len = 0, segment_flag = 0;
138 int crc = 0, wrp = 0, wrc = 0;
139 uint8_t stamp_len = 0;
140 uint8_t data[1024]; // receiver buffer
141 char token_type[5] = {0,0,0,0,0};
142 int dcf = 0;
143 int bIsSegmented = 0;
144
145 CmdLegicRdmem("0 22 55");
146
147 // copy data from device
148 GetEMLFromBigBuf(data, sizeof(data), 0);
149 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2000)){
150 PrintAndLog("Command execute timeout");
151 return 1;
152 }
153
154 // Output CDF System area (9 bytes) plus remaining header area (12 bytes)
155 crc = data[4];
156 uint32_t calc_crc = CRC8Legic(data, 4);
157
158 PrintAndLog("\nCDF: System Area");
159 PrintAndLog("------------------------------------------------------");
160 PrintAndLog("MCD: %02x, MSN: %02x %02x %02x, MCC: %02x %s",
161 data[0],
162 data[1],
163 data[2],
164 data[3],
165 data[4],
166 (calc_crc == crc) ? "OK":"Fail"
167 );
168
169
170 token_type[0] = 0;
171 dcf = ((int)data[6] << 8) | (int)data[5];
172
173 // New unwritten media?
174 if(dcf == 0xFFFF) {
175
176 PrintAndLog("DCF: %d (%02x %02x), Token Type=NM (New Media)",
177 dcf,
178 data[5],
179 data[6]
180 );
181
182 } else if(dcf > 60000) { // Master token?
183
184 int fl = 0;
185
186 if(data[6] == 0xec) {
187 strncpy(token_type, "XAM", sizeof(token_type));
188 fl = 1;
189 stamp_len = 0x0c - (data[5] >> 4);
190 } else {
191 switch (data[5] & 0x7f) {
192 case 0x00 ... 0x2f:
193 strncpy(token_type, "IAM", sizeof(token_type));
194 fl = (0x2f - (data[5] & 0x7f)) + 1;
195 break;
196 case 0x30 ... 0x6f:
197 strncpy(token_type, "SAM", sizeof(token_type));
198 fl = (0x6f - (data[5] & 0x7f)) + 1;
199 break;
200 case 0x70 ... 0x7f:
201 strncpy(token_type, "GAM", sizeof(token_type));
202 fl = (0x7f - (data[5] & 0x7f)) + 1;
203 break;
204 }
205
206 stamp_len = 0xfc - data[6];
207 }
208
209 PrintAndLog("DCF: %d (%02x %02x), Token Type=%s (OLE=%01u), OL=%02u, FL=%02u",
210 dcf,
211 data[5],
212 data[6],
213 token_type,
214 (data[5] & 0x80 )>> 7,
215 stamp_len,
216 fl
217 );
218
219 } else { // Is IM(-S) type of card...
220
221 if(data[7] == 0x9F && data[8] == 0xFF) {
222 bIsSegmented = 1;
223 strncpy(token_type, "IM-S", sizeof(token_type));
224 } else {
225 strncpy(token_type, "IM", sizeof(token_type));
226 }
227
228 PrintAndLog("DCF: %d (%02x %02x), Token Type=%s (OLE=%01u)",
229 dcf,
230 data[5],
231 data[6],
232 token_type,
233 (data[5]&0x80) >> 7
234 );
235 }
236
237 // Makes no sence to show this on blank media...
238 if(dcf != 0xFFFF) {
239
240 if(bIsSegmented) {
241 PrintAndLog("WRP=%02u, WRC=%01u, RD=%01u, SSC=%02x",
242 data[7] & 0x0f,
243 (data[7] & 0x70) >> 4,
244 (data[7] & 0x80) >> 7,
245 data[8]
246 );
247 }
248
249 // Header area is only available on IM-S cards, on master tokens this data is the master token data itself
250 if(bIsSegmented || dcf > 60000) {
251 if(dcf > 60000) {
252 PrintAndLog("Master token data");
253 PrintAndLog("%s", sprint_hex(data+8, 14));
254 } else {
255 PrintAndLog("Remaining Header Area");
256 PrintAndLog("%s", sprint_hex(data+9, 13));
257 }
258 }
259 }
260
261 uint8_t segCrcBytes[8] = {0,0,0,0,0,0,0,0};
262 uint32_t segCalcCRC = 0;
263 uint32_t segCRC = 0;
264
265 // Data card?
266 if(dcf <= 60000) {
267
268 PrintAndLog("\nADF: User Area");
269 PrintAndLog("------------------------------------------------------");
270
271 if(bIsSegmented) {
272
273 // Data start point on segmented cards
274 i = 22;
275
276 // decode segments
277 for (segmentNum=1; segmentNum < 128; segmentNum++ )
278 {
279 segment_len = ((data[i+1] ^ crc) & 0x0f) * 256 + (data[i] ^ crc);
280 segment_flag = ((data[i+1] ^ crc) & 0xf0) >> 4;
281 wrp = (data[i+2] ^ crc);
282 wrc = ((data[i+3] ^ crc) & 0x70) >> 4;
283
284 bool hasWRC = (wrc > 0);
285 bool hasWRP = (wrp > wrc);
286 int wrp_len = (wrp - wrc);
287 int remain_seg_payload_len = (segment_len - wrp - 5);
288
289 // validate segment-crc
290 segCrcBytes[0]=data[0]; //uid0
291 segCrcBytes[1]=data[1]; //uid1
292 segCrcBytes[2]=data[2]; //uid2
293 segCrcBytes[3]=data[3]; //uid3
294 segCrcBytes[4]=(data[i] ^ crc); //hdr0
295 segCrcBytes[5]=(data[i+1] ^ crc); //hdr1
296 segCrcBytes[6]=(data[i+2] ^ crc); //hdr2
297 segCrcBytes[7]=(data[i+3] ^ crc); //hdr3
298
299 segCalcCRC = CRC8Legic(segCrcBytes, 8);
300 segCRC = data[i+4] ^ crc;
301
302 PrintAndLog("Segment %02u \nraw header | 0x%02X 0x%02X 0x%02X 0x%02X \nSegment len: %u, Flag: 0x%X (valid:%01u, last:%01u), WRP: %02u, WRC: %02u, RD: %01u, CRC: 0x%02X (%s)",
303 segmentNum,
304 data[i] ^ crc,
305 data[i+1] ^ crc,
306 data[i+2] ^ crc,
307 data[i+3] ^ crc,
308 segment_len,
309 segment_flag,
310 (segment_flag & 0x4) >> 2,
311 (segment_flag & 0x8) >> 3,
312 wrp,
313 wrc,
314 ((data[i+3]^crc) & 0x80) >> 7,
315 segCRC,
316 ( segCRC == segCalcCRC ) ? "OK" : "fail"
317 );
318
319 i += 5;
320
321 if ( hasWRC ) {
322 PrintAndLog("WRC protected area: (I %d | K %d| WRC %d)", i, k, wrc);
323 PrintAndLog("\nrow | data");
324 PrintAndLog("-----+------------------------------------------------");
325
326 for ( k=i; k < (i + wrc); ++k)
327 data[k] ^= crc;
328
329 print_hex_break( data+i, wrc, 16);
330
331 i += wrc;
332 }
333
334 if ( hasWRP ) {
335 PrintAndLog("Remaining write protected area: (I %d | K %d | WRC %d | WRP %d WRP_LEN %d)",i, k, wrc, wrp, wrp_len);
336 PrintAndLog("\nrow | data");
337 PrintAndLog("-----+------------------------------------------------");
338
339 for (k=i; k < (i+wrp_len); ++k)
340 data[k] ^= crc;
341
342 print_hex_break( data+i, wrp_len, 16);
343
344 i += wrp_len;
345
346 // does this one work? (Answer: Only if KGH/BGH is used with BCD encoded card number! So maybe this will show just garbage...)
347 if( wrp_len == 8 )
348 PrintAndLog("Card ID: %2X%02X%02X", data[i-4]^crc, data[i-3]^crc, data[i-2]^crc);
349 }
350
351 PrintAndLog("Remaining segment payload: (I %d | K %d | Remain LEN %d)", i, k, remain_seg_payload_len);
352 PrintAndLog("\nrow | data");
353 PrintAndLog("-----+------------------------------------------------");
354
355 for ( k=i; k < (i+remain_seg_payload_len); ++k)
356 data[k] ^= crc;
357
358 print_hex_break( data+i, remain_seg_payload_len, 16);
359
360 i += remain_seg_payload_len;
361
362 PrintAndLog("-----+------------------------------------------------\n");
363
364 // end with last segment
365 if (segment_flag & 0x8) return 0;
366
367 } // end for loop
368
369 } else {
370
371 // Data start point on unsegmented cards
372 i = 8;
373
374 wrp = data[7] & 0x0F;
375 wrc = (data[7] & 0x70) >> 4;
376
377 bool hasWRC = (wrc > 0);
378 bool hasWRP = (wrp > wrc);
379 int wrp_len = (wrp - wrc);
380 int remain_seg_payload_len = (1024 - 22 - wrp); // Any chance to get physical card size here!?
381
382 PrintAndLog("Unsegmented card - WRP: %02u, WRC: %02u, RD: %01u",
383 wrp,
384 wrc,
385 (data[7] & 0x80) >> 7
386 );
387
388 if ( hasWRC ) {
389 PrintAndLog("WRC protected area: (I %d | WRC %d)", i, wrc);
390 PrintAndLog("\nrow | data");
391 PrintAndLog("-----+------------------------------------------------");
392 print_hex_break( data+i, wrc, 16);
393 i += wrc;
394 }
395
396 if ( hasWRP ) {
397 PrintAndLog("Remaining write protected area: (I %d | WRC %d | WRP %d | WRP_LEN %d)", i, wrc, wrp, wrp_len);
398 PrintAndLog("\nrow | data");
399 PrintAndLog("-----+------------------------------------------------");
400 print_hex_break( data + i, wrp_len, 16);
401 i += wrp_len;
402
403 // does this one work? (Answer: Only if KGH/BGH is used with BCD encoded card number! So maybe this will show just garbage...)
404 if( wrp_len == 8 )
405 PrintAndLog("Card ID: %2X%02X%02X", data[i-4], data[i-3], data[i-2]);
406 }
407
408 PrintAndLog("Remaining segment payload: (I %d | Remain LEN %d)", i, remain_seg_payload_len);
409 PrintAndLog("\nrow | data");
410 PrintAndLog("-----+------------------------------------------------");
411 print_hex_break( data + i, remain_seg_payload_len, 16);
412 i += remain_seg_payload_len;
413
414 PrintAndLog("-----+------------------------------------------------\n");
415 }
416 }
417 return 0;
418 }
419
420 int CmdLegicRdmem(const char *Cmd) {
421
422 // params:
423 // offset in data memory
424 // number of bytes to read
425 char cmdp = param_getchar(Cmd, 0);
426 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_rdmem();
427
428 uint32_t offset = 0, len = 0, IV = 1;
429 sscanf(Cmd, "%x %x %x", &offset, &len, &IV);
430
431 // OUT-OF-BOUNDS check
432 if ( len + offset > MAX_LENGTH ) {
433 len = MAX_LENGTH - offset;
434 PrintAndLog("Out-of-bound, shorten len to %d (0x%02X)", len, len);
435 }
436
437 if ( (IV & 0x7F) != IV ){
438 IV &= 0x7F;
439 PrintAndLog("Truncating IV to 7bits");
440 }
441
442 if ( (IV & 1) == 0 ){
443 IV |= 0x01;
444 PrintAndLog("LSB of IV must be SET");
445 }
446
447 UsbCommand c = {CMD_READER_LEGIC_RF, {offset, len, IV}};
448 clearCommandBuffer();
449 SendCommand(&c);
450 UsbCommand resp;
451 if (WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
452 uint8_t isOK = resp.arg[0] & 0xFF;
453 uint16_t readlen = resp.arg[1];
454 if ( isOK ) {
455
456 uint8_t *data = malloc(readlen);
457 if ( !data ){
458 PrintAndLog("Cannot allocate memory");
459 return 2;
460 }
461
462 if ( readlen != len )
463 PrintAndLog("Fail, only managed to read 0x%02X bytes", readlen);
464
465 // copy data from device
466 GetEMLFromBigBuf(data, readlen, 0);
467 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2500)){
468 PrintAndLog("Command execute timeout");
469 if ( data )
470 free(data);
471 return 1;
472 }
473
474 PrintAndLog("\n ## | Data");
475 PrintAndLog("-----+-----");
476 print_hex_break( data, readlen, 32);
477 } else {
478 PrintAndLog("failed reading tag");
479 }
480 } else {
481 PrintAndLog("command execution time out");
482 return 1;
483 }
484 return 0;
485 }
486
487 int CmdLegicLoad(const char *Cmd) {
488
489 // iceman: potential bug, where all filepaths or filename which starts with H or h will print the helptext :)
490 char cmdp = param_getchar(Cmd, 0);
491 if ( cmdp == 'H' || cmdp == 'h' || cmdp == 0x00) return usage_legic_load();
492
493 char filename[FILE_PATH_SIZE] = {0x00};
494 int len = strlen(Cmd);
495
496 if (len > FILE_PATH_SIZE) {
497 PrintAndLog("Filepath too long (was %s bytes), max allowed is %s ", len, FILE_PATH_SIZE);
498 return 0;
499 }
500 memcpy(filename, Cmd, len);
501
502 FILE *f = fopen(filename, "r");
503 if(!f) {
504 PrintAndLog("couldn't open '%s'", Cmd);
505 return -1;
506 }
507
508 char line[80];
509 int offset = 0;
510 uint8_t data[USB_CMD_DATA_SIZE] = {0x00};
511 int index = 0;
512 int totalbytes = 0;
513 while ( fgets(line, sizeof(line), f) ) {
514 int res = sscanf(line, "%x %x %x %x %x %x %x %x",
515 (unsigned int *)&data[index],
516 (unsigned int *)&data[index + 1],
517 (unsigned int *)&data[index + 2],
518 (unsigned int *)&data[index + 3],
519 (unsigned int *)&data[index + 4],
520 (unsigned int *)&data[index + 5],
521 (unsigned int *)&data[index + 6],
522 (unsigned int *)&data[index + 7]);
523
524 if(res != 8) {
525 PrintAndLog("Error: could not read samples");
526 fclose(f);
527 return -1;
528 }
529 index += res;
530
531 if ( index == USB_CMD_DATA_SIZE ){
532 // PrintAndLog("sent %d | %d | %d", index, offset, totalbytes);
533 UsbCommand c = { CMD_DOWNLOADED_SIM_SAMPLES_125K, {offset, 0, 0}};
534 memcpy(c.d.asBytes, data, sizeof(data));
535 clearCommandBuffer();
536 SendCommand(&c);
537 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 1500)){
538 PrintAndLog("Command execute timeout");
539 fclose(f);
540 return 1;
541 }
542 offset += index;
543 totalbytes += index;
544 index = 0;
545 }
546 }
547 fclose(f);
548
549 // left over bytes?
550 if ( index != 0 ) {
551 UsbCommand c = { CMD_DOWNLOADED_SIM_SAMPLES_125K, {offset, 0, 0}};
552 memcpy(c.d.asBytes, data, 8);
553 clearCommandBuffer();
554 SendCommand(&c);
555 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 1500)){
556 PrintAndLog("Command execute timeout");
557 return 1;
558 }
559 totalbytes += index;
560 }
561
562 PrintAndLog("loaded %u samples", totalbytes);
563 return 0;
564 }
565
566 int CmdLegicSave(const char *Cmd) {
567 int requested = 1024;
568 int offset = 0;
569 int delivered = 0;
570 char filename[FILE_PATH_SIZE] = {0x00};
571 uint8_t got[1024] = {0x00};
572
573 memset(filename, 0, FILE_PATH_SIZE);
574
575 sscanf(Cmd, " %s %i %i", filename, &requested, &offset);
576
577 /* If no length given save entire legic read buffer */
578 /* round up to nearest 8 bytes so the saved data can be used with legicload */
579 if (requested == 0)
580 requested = 1024;
581
582 if (requested % 8 != 0) {
583 int remainder = requested % 8;
584 requested = requested + 8 - remainder;
585 }
586
587 if (offset + requested > sizeof(got)) {
588 PrintAndLog("Tried to read past end of buffer, <bytes> + <offset> > 1024");
589 return 0;
590 }
591
592 GetFromBigBuf(got, requested, offset);
593 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2000)){
594 PrintAndLog("Command execute timeout");
595 return 1;
596 }
597
598 FILE *f = fopen(filename, "w");
599 if(!f) {
600 PrintAndLog("couldn't open '%s'", Cmd+1);
601 return -1;
602 }
603
604 for (int j = 0; j < requested; j += 8) {
605 fprintf(f, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
606 got[j+0], got[j+1], got[j+2], got[j+3],
607 got[j+4], got[j+5], got[j+6], got[j+7]
608 );
609 delivered += 8;
610 if (delivered >= requested) break;
611 }
612
613 fclose(f);
614 PrintAndLog("saved %u samples", delivered);
615 return 0;
616 }
617
618 //TODO: write a help text (iceman)
619 int CmdLegicRfSim(const char *Cmd) {
620 UsbCommand c = {CMD_SIMULATE_TAG_LEGIC_RF, {6,3,0}};
621 sscanf(Cmd, " %"lli" %"lli" %"lli, &c.arg[0], &c.arg[1], &c.arg[2]);
622 clearCommandBuffer();
623 SendCommand(&c);
624 return 0;
625 }
626
627 int CmdLegicRfWrite(const char *Cmd) {
628
629 // params:
630 // offset - in tag memory
631 // length - num of bytes to be written
632 // IV - initialisation vector
633
634 char cmdp = param_getchar(Cmd, 0);
635 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_write();
636
637 uint32_t offset = 0, len = 0, IV = 0;
638
639 int res = sscanf(Cmd, "%x %x %x", &offset, &len, &IV);
640 if(res < 2) {
641 PrintAndLog("Please specify the offset and length as two hex strings and, optionally, the IV also as an hex string");
642 return -1;
643 }
644
645 // OUT-OF-BOUNDS check
646 if ( len + offset > MAX_LENGTH ) {
647 len = MAX_LENGTH - offset;
648 PrintAndLog("Out-of-bound, shorten len to %d (0x%02X)", len, len);
649 }
650 if ( (IV & 0x7F) != IV ){
651 IV &= 0x7F;
652 PrintAndLog("Truncating IV to 7bits");
653 }
654 if ( (IV & 1) == 0 ){
655 IV |= 0x01; // IV must be odd
656 PrintAndLog("LSB of IV must be SET");
657 }
658
659 UsbCommand c = {CMD_WRITER_LEGIC_RF, {offset, len, IV}};
660 clearCommandBuffer();
661 SendCommand(&c);
662 UsbCommand resp;
663 if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
664 uint8_t isOK = resp.arg[0] & 0xFF;
665 if ( isOK ) {
666 } else {
667 PrintAndLog("failed writig tag");
668 }
669 } else {
670 PrintAndLog("command execution time out");
671 return 1;
672 }
673
674 return 0;
675 }
676
677 int CmdLegicRfRawWrite(const char *Cmd) {
678
679 char cmdp = param_getchar(Cmd, 0);
680 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_rawwrite();
681
682 uint32_t offset = 0, data = 0, IV = 0;
683 char answer;
684
685 int res = sscanf(Cmd, "%x %x %x", &offset, &data, &IV);
686 if(res < 2)
687 return usage_legic_rawwrite();
688
689 // OUT-OF-BOUNDS check
690 if ( offset > MAX_LENGTH ) {
691 PrintAndLog("Out-of-bound, offset");
692 return 1;
693 }
694
695 if ( (IV & 0x7F) != IV ){
696 IV &= 0x7F;
697 PrintAndLog("Truncating IV to 7bits");
698 }
699 if ( (IV & 1) == 0 ){
700 IV |= 0x01; // IV must be odd
701 PrintAndLog("LSB of IV must be SET");
702 }
703
704 UsbCommand c = { CMD_RAW_WRITER_LEGIC_RF, {offset, data, IV} };
705
706 if (c.arg[0] == 0x05 || c.arg[0] == 0x06) {
707 PrintAndLog("############# DANGER !! #############");
708 PrintAndLog("# changing the DCF is irreversible #");
709 PrintAndLog("#####################################");
710 PrintAndLog("do youe really want to continue? y(es) n(o)");
711 if (scanf(" %c", &answer) > 0 && (answer == 'y' || answer == 'Y')) {
712 SendCommand(&c);
713 return 0;
714 }
715 return -1;
716 }
717
718 clearCommandBuffer();
719 SendCommand(&c);
720 return 0;
721 }
722
723 //TODO: write a help text (iceman)
724 int CmdLegicRfFill(const char *Cmd) {
725 UsbCommand cmd = {CMD_WRITER_LEGIC_RF, {0,0,0} };
726 int res = sscanf(Cmd, " 0x%"llx" 0x%"llx" 0x%"llx, &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]);
727 if(res != 3) {
728 PrintAndLog("Please specify the offset, length and value as two hex strings");
729 return -1;
730 }
731
732 int i;
733 UsbCommand c = {CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 0, 0}};
734 memset(c.d.asBytes, cmd.arg[2], 48);
735
736 for(i = 0; i < 22; i++) {
737 c.arg[0] = i*48;
738
739 clearCommandBuffer();
740 SendCommand(&c);
741 WaitForResponse(CMD_ACK, NULL);
742 }
743 clearCommandBuffer();
744 SendCommand(&cmd);
745 return 0;
746 }
747
748 void static calc4(uint8_t *cmd, uint8_t len){
749 crc_t crc;
750 //crc_init_ref(&crc, 4, 0x19 >> 1, 0x5, 0, TRUE, TRUE);
751 crc_init(&crc, 4, 0x19 >> 1, 0x5, 0);
752
753 crc_clear(&crc);
754 crc_update(&crc, 1, 1); /* CMD_READ */
755 crc_update(&crc, cmd[0], 8);
756 crc_update(&crc, cmd[1], 8);
757 printf("crc4 %X\n", reflect(crc_finish(&crc), 4) ) ;
758
759 crc_clear(&crc);
760 crc_update(&crc, 1, 1); /* CMD_READ */
761 crc_update(&crc, cmd[0], 8);
762 crc_update(&crc, cmd[1], 8);
763 printf("crc4 %X\n", crc_finish(&crc) ) ;
764
765 printf("---- old ---\n");
766 crc_update2(&crc, 1, 1); /* CMD_READ */
767 crc_update2(&crc, cmd[0], 8);
768 crc_update2(&crc, cmd[1], 8);
769 printf("crc4 %X \n", reflect(crc_finish(&crc), 4) ) ;
770
771
772 crc_clear(&crc);
773 crc_update2(&crc, 1, 1); /* CMD_READ */
774 crc_update2(&crc, cmd[0], 8);
775 crc_update2(&crc, cmd[1], 8);
776 printf("crc4 %X\n", crc_finish(&crc) ) ;
777 }
778
779 int CmdLegicCalcCrc8(const char *Cmd){
780
781 uint8_t *data = NULL;
782 uint8_t cmdp = 0, uidcrc = 0, type=0;
783 bool errors = false;
784 int len = 0;
785 int bg, en;
786
787 while(param_getchar(Cmd, cmdp) != 0x00) {
788 switch(param_getchar(Cmd, cmdp)) {
789 case 'b':
790 case 'B':
791 // peek at length of the input string so we can
792 // figure out how many elements to malloc in "data"
793 bg=en=0;
794 if (param_getptr(Cmd, &bg, &en, cmdp+1)) {
795 errors = true;
796 break;
797 }
798 len = (en - bg + 1);
799
800 // check that user entered even number of characters
801 // for hex data string
802 if (len & 1) {
803 errors = true;
804 break;
805 }
806
807 // it's possible for user to accidentally enter "b" parameter
808 // more than once - we have to clean previous malloc
809 if (data) free(data);
810 data = malloc(len >> 1);
811 if ( data == NULL ) {
812 PrintAndLog("Can't allocate memory. exiting");
813 errors = true;
814 break;
815 }
816
817 if (param_gethex(Cmd, cmdp+1, data, len)) {
818 errors = true;
819 break;
820 }
821
822 len >>= 1;
823 cmdp += 2;
824 break;
825 case 'u':
826 case 'U':
827 uidcrc = param_get8ex(Cmd, cmdp+1, 0, 16);
828 cmdp += 2;
829 break;
830 case 'c':
831 case 'C':
832 type = param_get8ex(Cmd, cmdp+1, 0, 10);
833 cmdp += 2;
834 break;
835 case 'h':
836 case 'H':
837 errors = true;
838 break;
839 default:
840 PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
841 errors = true;
842 break;
843 }
844 if (errors) break;
845 }
846 //Validations
847 if (errors){
848 if (data) free(data);
849 return usage_legic_calccrc8();
850 }
851
852 switch (type){
853 case 16:
854 PrintAndLog("Legic crc16: %X", CRC16Legic(data, len, uidcrc));
855 break;
856 case 4:
857 calc4(data, 0);
858 break;
859 default:
860 PrintAndLog("Legic crc8: %X", CRC8Legic(data, len) );
861 break;
862 }
863
864 if (data) free(data);
865 return 0;
866 }
867
868 int legic_print_type(uint32_t tagtype, uint8_t spaces){
869 char spc[11] = " ";
870 spc[10]=0x00;
871 char *spacer = spc + (10-spaces);
872
873 if ( tagtype == 22 )
874 PrintAndLog("%sTYPE : MIM%d card (outdated)", spacer, tagtype);
875 else if ( tagtype == 256 )
876 PrintAndLog("%sTYPE : MIM%d card (234 bytes)", spacer, tagtype);
877 else if ( tagtype == 1024 )
878 PrintAndLog("%sTYPE : MIM%d card (1002 bytes)", spacer, tagtype);
879 else
880 PrintAndLog("%sTYPE : Unknown %06x", spacer, tagtype);
881 return 0;
882 }
883 int legic_get_type(legic_card_select_t *card){
884
885 if ( card == NULL ) return 1;
886
887 UsbCommand c = {CMD_LEGIC_INFO, {0,0,0}};
888 clearCommandBuffer();
889 SendCommand(&c);
890 UsbCommand resp;
891 if (!WaitForResponseTimeout(CMD_ACK, &resp, 500))
892 return 2;
893
894 uint8_t isOK = resp.arg[0] & 0xFF;
895 if ( !isOK )
896 return 3;
897
898 memcpy(card, (legic_card_select_t *)resp.d.asBytes, sizeof(legic_card_select_t));
899 return 0;
900 }
901
902 int HFLegicReader(const char *Cmd, bool verbose) {
903
904 char cmdp = param_getchar(Cmd, 0);
905 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_reader();
906
907 legic_card_select_t card;
908 switch(legic_get_type(&card)){
909 case 1:
910 if ( verbose ) PrintAndLog("command execution time out");
911 return 1;
912 case 2:
913 case 3:
914 if ( verbose ) PrintAndLog("legic card select failed");
915 return 2;
916 default: break;
917 }
918 PrintAndLog(" UID : %s", sprint_hex(card.uid, sizeof(card.uid)));
919 legic_print_type(card.cardsize, 0);
920 return 0;
921 }
922 int CmdLegicReader(const char *Cmd){
923 return HFLegicReader(Cmd, TRUE);
924 }
925
926 int CmdLegicDump(const char *Cmd){
927
928 FILE *fout;
929 char filename[FILE_PATH_SIZE] = {0x00};
930 char *fnameptr = filename;
931 size_t fileNlen = 0;
932 bool errors = false;
933 uint16_t dumplen;
934 uint8_t cmdp = 0;
935
936 while(param_getchar(Cmd, cmdp) != 0x00)
937 {
938 switch(param_getchar(Cmd, cmdp))
939 {
940 case 'h':
941 case 'H':
942 return usage_legic_dump();
943 case 'o':
944 case 'O':
945 fileNlen = param_getstr(Cmd, cmdp+1, filename);
946 if (!fileNlen) errors = true;
947 if (fileNlen > FILE_PATH_SIZE-5) fileNlen = FILE_PATH_SIZE-5;
948 cmdp += 2;
949 break;
950 default:
951 PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
952 errors = true;
953 break;
954 }
955 if(errors) break;
956 }
957
958 //Validations
959 if(errors) return usage_legic_dump();
960
961 // tagtype
962 legic_card_select_t card;
963 if (legic_get_type(&card)) {
964 PrintAndLog("Failed to identify tagtype");
965 return -1;
966 }
967 dumplen = card.cardsize;
968
969 legic_print_type(dumplen, 0);
970 PrintAndLog("Reading tag memory...");
971
972 UsbCommand c = {CMD_READER_LEGIC_RF, {0x00, dumplen, 0x55}};
973 clearCommandBuffer();
974 SendCommand(&c);
975 UsbCommand resp;
976 if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
977 PrintAndLog("Command execute time-out");
978 return 1;
979 }
980
981 uint8_t isOK = resp.arg[0] & 0xFF;
982 if ( !isOK ) {
983 PrintAndLog("Failed dumping tag data");
984 return 2;
985 }
986
987 uint16_t readlen = resp.arg[1];
988 uint8_t *data = malloc(readlen);
989 if ( !data ){
990 PrintAndLog("Fail, cannot allocate memory");
991 return 3;
992 }
993
994 if ( readlen != dumplen )
995 PrintAndLog("Fail, only managed to read 0x%02X bytes of 0x%02X", readlen, dumplen);
996
997 // copy data from device
998 GetEMLFromBigBuf(data, readlen, 0);
999 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2500)) {
1000 PrintAndLog("Fail, transfer from device time-out");
1001 if ( data ) free(data);
1002 return 4;
1003 }
1004
1005 // user supplied filename?
1006 if (fileNlen < 1)
1007 sprintf(fnameptr,"%02X%02X%02X%02X.bin", data[0], data[1], data[2], data[3]);
1008 else
1009 sprintf(fnameptr + fileNlen,".bin");
1010
1011 if ((fout = fopen(filename,"wb")) == NULL) {
1012 PrintAndLog("Could not create file name %s", filename);
1013 if ( data ) free(data);
1014 return 5;
1015 }
1016 fwrite( data, 1, readlen, fout );
1017 fclose(fout);
1018 if ( data ) free(data);
1019
1020 PrintAndLog("Wrote %d bytes to %s", readlen, filename);
1021 return 0;
1022 }
1023
1024 static command_t CommandTable[] = {
1025 {"help", CmdHelp, 1, "This help"},
1026 {"reader", CmdLegicReader, 1, "LEGIC Prime Reader UID and Type tag info"},
1027 {"info", CmdLegicInfo, 0, "Display deobfuscated and decoded LEGIC Prime tag data"},
1028 {"dump", CmdLegicDump, 0, "Dump LEGIC Prime card to binary file"},
1029 {"rdmem", CmdLegicRdmem, 0, "[offset][length] <iv> -- read bytes from a LEGIC card"},
1030 {"save", CmdLegicSave, 0, "<filename> [<length>] -- Store samples"},
1031 {"load", CmdLegicLoad, 0, "<filename> -- Restore samples"},
1032 {"sim", CmdLegicRfSim, 0, "[phase drift [frame drift [req/resp drift]]] Start tag simulator (use after load or read)"},
1033 {"write", CmdLegicRfWrite, 0, "<offset> <length> <iv> -- Write sample buffer (user after load or read)"},
1034 {"writeraw",CmdLegicRfRawWrite, 0, "<address> <value> <iv> -- Write direct to address"},
1035 {"fill", CmdLegicRfFill, 0, "<offset> <length> <value> -- Fill/Write tag with constant value"},
1036 {"crc8", CmdLegicCalcCrc8, 1, "Calculate Legic CRC8 over given hexbytes"},
1037 {NULL, NULL, 0, NULL}
1038 };
1039
1040 int CmdHFLegic(const char *Cmd) {
1041 clearCommandBuffer();
1042 CmdsParse(CommandTable, Cmd);
1043 return 0;
1044 }
1045
1046 int CmdHelp(const char *Cmd) {
1047 CmdsHelp(CommandTable);
1048 return 0;
1049 }
Impressum, Datenschutz