]> git.zerfleddert.de Git - proxmark3-svn/blob - client/cmdhflegic.c
ae67dd76e28b33d55d28ce8e419cae7a7237a677
[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_read(void){
43 PrintAndLog("Read data from a legic tag.");
44 PrintAndLog("Usage: hf legic read [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 read 0 21 - reads from byte[0] 21 bytes(system header)");
53 PrintAndLog(" hf legic read 0 4 55 - reads from byte[0] 4 bytes with IV 0x55");
54 PrintAndLog(" hf legic read 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_info(void){
92 PrintAndLog("Read info from a legic tag.");
93 PrintAndLog("Usage: hf legic info [h]");
94 PrintAndLog("Options:");
95 PrintAndLog(" h : this help");
96 PrintAndLog("");
97 PrintAndLog("Samples:");
98 PrintAndLog(" hf legic info");
99 return 0;
100 }
101 /*
102 * Output BigBuf and deobfuscate LEGIC RF tag data.
103 * This is based on information given in the talk held
104 * by Henryk Ploetz and Karsten Nohl at 26c3
105 */
106 int CmdLegicDecode(const char *Cmd) {
107
108 int i = 0, k = 0, segmentNum = 0, segment_len = 0, segment_flag = 0;
109 int crc = 0, wrp = 0, wrc = 0;
110 uint8_t stamp_len = 0;
111 uint8_t data[1024]; // receiver buffer
112 char token_type[5] = {0,0,0,0,0};
113 int dcf = 0;
114 int bIsSegmented = 0;
115
116 // copy data from device
117 GetEMLFromBigBuf(data, sizeof(data), 0);
118 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2000)){
119 PrintAndLog("Command execute timeout");
120 return 1;
121 }
122
123 // Output CDF System area (9 bytes) plus remaining header area (12 bytes)
124 crc = data[4];
125 uint32_t calc_crc = CRC8Legic(data, 4);
126
127 PrintAndLog("\nCDF: System Area");
128 PrintAndLog("------------------------------------------------------");
129 PrintAndLog("MCD: %02x, MSN: %02x %02x %02x, MCC: %02x %s",
130 data[0],
131 data[1],
132 data[2],
133 data[3],
134 data[4],
135 (calc_crc == crc) ? "OK":"Fail"
136 );
137
138
139 token_type[0] = 0;
140 dcf = ((int)data[6] << 8) | (int)data[5];
141
142 // New unwritten media?
143 if(dcf == 0xFFFF) {
144
145 PrintAndLog("DCF: %d (%02x %02x), Token Type=NM (New Media)",
146 dcf,
147 data[5],
148 data[6]
149 );
150
151 } else if(dcf > 60000) { // Master token?
152
153 int fl = 0;
154
155 if(data[6] == 0xec) {
156 strncpy(token_type, "XAM", sizeof(token_type));
157 fl = 1;
158 stamp_len = 0x0c - (data[5] >> 4);
159 } else {
160 switch (data[5] & 0x7f) {
161 case 0x00 ... 0x2f:
162 strncpy(token_type, "IAM", sizeof(token_type));
163 fl = (0x2f - (data[5] & 0x7f)) + 1;
164 break;
165 case 0x30 ... 0x6f:
166 strncpy(token_type, "SAM", sizeof(token_type));
167 fl = (0x6f - (data[5] & 0x7f)) + 1;
168 break;
169 case 0x70 ... 0x7f:
170 strncpy(token_type, "GAM", sizeof(token_type));
171 fl = (0x7f - (data[5] & 0x7f)) + 1;
172 break;
173 }
174
175 stamp_len = 0xfc - data[6];
176 }
177
178 PrintAndLog("DCF: %d (%02x %02x), Token Type=%s (OLE=%01u), OL=%02u, FL=%02u",
179 dcf,
180 data[5],
181 data[6],
182 token_type,
183 (data[5] & 0x80 )>> 7,
184 stamp_len,
185 fl
186 );
187
188 } else { // Is IM(-S) type of card...
189
190 if(data[7] == 0x9F && data[8] == 0xFF) {
191 bIsSegmented = 1;
192 strncpy(token_type, "IM-S", sizeof(token_type));
193 } else {
194 strncpy(token_type, "IM", sizeof(token_type));
195 }
196
197 PrintAndLog("DCF: %d (%02x %02x), Token Type=%s (OLE=%01u)",
198 dcf,
199 data[5],
200 data[6],
201 token_type,
202 (data[5]&0x80) >> 7
203 );
204 }
205
206 // Makes no sence to show this on blank media...
207 if(dcf != 0xFFFF) {
208
209 if(bIsSegmented) {
210 PrintAndLog("WRP=%02u, WRC=%01u, RD=%01u, SSC=%02x",
211 data[7] & 0x0f,
212 (data[7] & 0x70) >> 4,
213 (data[7] & 0x80) >> 7,
214 data[8]
215 );
216 }
217
218 // Header area is only available on IM-S cards, on master tokens this data is the master token data itself
219 if(bIsSegmented || dcf > 60000) {
220 if(dcf > 60000) {
221 PrintAndLog("Master token data");
222 PrintAndLog("%s", sprint_hex(data+8, 14));
223 } else {
224 PrintAndLog("Remaining Header Area");
225 PrintAndLog("%s", sprint_hex(data+9, 13));
226 }
227 }
228 }
229
230 uint8_t segCrcBytes[8] = {0,0,0,0,0,0,0,0};
231 uint32_t segCalcCRC = 0;
232 uint32_t segCRC = 0;
233
234 // Data card?
235 if(dcf <= 60000) {
236
237 PrintAndLog("\nADF: User Area");
238 PrintAndLog("------------------------------------------------------");
239
240 if(bIsSegmented) {
241
242 // Data start point on segmented cards
243 i = 22;
244
245 // decode segments
246 for (segmentNum=1; segmentNum < 128; segmentNum++ )
247 {
248 segment_len = ((data[i+1] ^ crc) & 0x0f) * 256 + (data[i] ^ crc);
249 segment_flag = ((data[i+1] ^ crc) & 0xf0) >> 4;
250 wrp = (data[i+2] ^ crc);
251 wrc = ((data[i+3] ^ crc) & 0x70) >> 4;
252
253 bool hasWRC = (wrc > 0);
254 bool hasWRP = (wrp > wrc);
255 int wrp_len = (wrp - wrc);
256 int remain_seg_payload_len = (segment_len - wrp - 5);
257
258 // validate segment-crc
259 segCrcBytes[0]=data[0]; //uid0
260 segCrcBytes[1]=data[1]; //uid1
261 segCrcBytes[2]=data[2]; //uid2
262 segCrcBytes[3]=data[3]; //uid3
263 segCrcBytes[4]=(data[i] ^ crc); //hdr0
264 segCrcBytes[5]=(data[i+1] ^ crc); //hdr1
265 segCrcBytes[6]=(data[i+2] ^ crc); //hdr2
266 segCrcBytes[7]=(data[i+3] ^ crc); //hdr3
267
268 segCalcCRC = CRC8Legic(segCrcBytes, 8);
269 segCRC = data[i+4] ^ crc;
270
271 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)",
272 segmentNum,
273 data[i] ^ crc,
274 data[i+1] ^ crc,
275 data[i+2] ^ crc,
276 data[i+3] ^ crc,
277 segment_len,
278 segment_flag,
279 (segment_flag & 0x4) >> 2,
280 (segment_flag & 0x8) >> 3,
281 wrp,
282 wrc,
283 ((data[i+3]^crc) & 0x80) >> 7,
284 segCRC,
285 ( segCRC == segCalcCRC ) ? "OK" : "fail"
286 );
287
288 i += 5;
289
290 if ( hasWRC ) {
291 PrintAndLog("WRC protected area: (I %d | K %d| WRC %d)", i, k, wrc);
292 PrintAndLog("\nrow | data");
293 PrintAndLog("-----+------------------------------------------------");
294
295 for ( k=i; k < (i + wrc); ++k)
296 data[k] ^= crc;
297
298 print_hex_break( data+i, wrc, 16);
299
300 i += wrc;
301 }
302
303 if ( hasWRP ) {
304 PrintAndLog("Remaining write protected area: (I %d | K %d | WRC %d | WRP %d WRP_LEN %d)",i, k, wrc, wrp, wrp_len);
305 PrintAndLog("\nrow | data");
306 PrintAndLog("-----+------------------------------------------------");
307
308 for (k=i; k < (i+wrp_len); ++k)
309 data[k] ^= crc;
310
311 print_hex_break( data+i, wrp_len, 16);
312
313 i += wrp_len;
314
315 // does this one work? (Answer: Only if KGH/BGH is used with BCD encoded card number! So maybe this will show just garbage...)
316 if( wrp_len == 8 )
317 PrintAndLog("Card ID: %2X%02X%02X", data[i-4]^crc, data[i-3]^crc, data[i-2]^crc);
318 }
319
320 PrintAndLog("Remaining segment payload: (I %d | K %d | Remain LEN %d)", i, k, remain_seg_payload_len);
321 PrintAndLog("\nrow | data");
322 PrintAndLog("-----+------------------------------------------------");
323
324 for ( k=i; k < (i+remain_seg_payload_len); ++k)
325 data[k] ^= crc;
326
327 print_hex_break( data+i, remain_seg_payload_len, 16);
328
329 i += remain_seg_payload_len;
330
331 PrintAndLog("-----+------------------------------------------------\n");
332
333 // end with last segment
334 if (segment_flag & 0x8) return 0;
335
336 } // end for loop
337
338 } else {
339
340 // Data start point on unsegmented cards
341 i = 8;
342
343 wrp = data[7] & 0x0F;
344 wrc = (data[7] & 0x70) >> 4;
345
346 bool hasWRC = (wrc > 0);
347 bool hasWRP = (wrp > wrc);
348 int wrp_len = (wrp - wrc);
349 int remain_seg_payload_len = (1024 - 22 - wrp); // Any chance to get physical card size here!?
350
351 PrintAndLog("Unsegmented card - WRP: %02u, WRC: %02u, RD: %01u",
352 wrp,
353 wrc,
354 (data[7] & 0x80) >> 7
355 );
356
357 if ( hasWRC ) {
358 PrintAndLog("WRC protected area: (I %d | WRC %d)", i, wrc);
359 PrintAndLog("\nrow | data");
360 PrintAndLog("-----+------------------------------------------------");
361 print_hex_break( data+i, wrc, 16);
362 i += wrc;
363 }
364
365 if ( hasWRP ) {
366 PrintAndLog("Remaining write protected area: (I %d | WRC %d | WRP %d | WRP_LEN %d)", i, wrc, wrp, wrp_len);
367 PrintAndLog("\nrow | data");
368 PrintAndLog("-----+------------------------------------------------");
369 print_hex_break( data + i, wrp_len, 16);
370 i += wrp_len;
371
372 // does this one work? (Answer: Only if KGH/BGH is used with BCD encoded card number! So maybe this will show just garbage...)
373 if( wrp_len == 8 )
374 PrintAndLog("Card ID: %2X%02X%02X", data[i-4], data[i-3], data[i-2]);
375 }
376
377 PrintAndLog("Remaining segment payload: (I %d | Remain LEN %d)", i, remain_seg_payload_len);
378 PrintAndLog("\nrow | data");
379 PrintAndLog("-----+------------------------------------------------");
380 print_hex_break( data + i, remain_seg_payload_len, 16);
381 i += remain_seg_payload_len;
382
383 PrintAndLog("-----+------------------------------------------------\n");
384 }
385 }
386 return 0;
387 }
388
389 int CmdLegicRFRead(const char *Cmd) {
390
391 // params:
392 // offset in data memory
393 // number of bytes to read
394 char cmdp = param_getchar(Cmd, 0);
395 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_read();
396
397 uint32_t offset = 0, len = 0, IV = 1;
398 sscanf(Cmd, "%x %x %x", &offset, &len, &IV);
399
400 // OUT-OF-BOUNDS check
401 if ( len + offset > MAX_LENGTH ) {
402 len = MAX_LENGTH - offset;
403 PrintAndLog("Out-of-bound, shorten len to %d", len);
404 }
405
406 if ( (IV & 0x7F) != IV ){
407 IV &= 0x7F;
408 PrintAndLog("Truncating IV to 7bits");
409 }
410
411 if ( (IV & 1) == 0 ){
412 IV |= 0x01;
413 PrintAndLog("LSB of IV must be SET");
414 }
415
416 //PrintAndLog("Using IV: 0x%02x", IV);
417
418 UsbCommand c = {CMD_READER_LEGIC_RF, {offset, len, IV}};
419 clearCommandBuffer();
420 SendCommand(&c);
421 UsbCommand resp;
422 if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
423 uint8_t isOK = resp.arg[0] & 0xFF;
424 uint16_t readlen = resp.arg[1] & 0x3FF;
425 if ( isOK ) {
426
427 uint8_t *data = malloc(readlen);
428 if ( !data ){
429 PrintAndLog("Cannot allocate memory");
430 return 2;
431 }
432
433 if ( readlen != len )
434 PrintAndLog("Fail, only managed to read 0x%02X bytes", readlen);
435
436 // copy data from device
437 GetEMLFromBigBuf(data, readlen, 0);
438 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2000)){
439 PrintAndLog("Command execute timeout");
440 if ( data )
441 free(data);
442 return 1;
443 }
444
445 PrintAndLog("\nData");
446 PrintAndLog("-----------------------------");
447 print_hex_break( data, readlen, 32);
448 } else {
449 PrintAndLog("failed reading tag");
450 }
451 } else {
452 PrintAndLog("command execution time out");
453 return 1;
454 }
455 return 0;
456 }
457
458 int CmdLegicLoad(const char *Cmd) {
459
460 // iceman: potential bug, where all filepaths or filename which starts with H or h will print the helptext :)
461 char cmdp = param_getchar(Cmd, 0);
462 if ( cmdp == 'H' || cmdp == 'h' || cmdp == 0x00) return usage_legic_load();
463
464 char filename[FILE_PATH_SIZE] = {0x00};
465 int len = strlen(Cmd);
466
467 if (len > FILE_PATH_SIZE) {
468 PrintAndLog("Filepath too long (was %s bytes), max allowed is %s ", len, FILE_PATH_SIZE);
469 return 0;
470 }
471 memcpy(filename, Cmd, len);
472
473 FILE *f = fopen(filename, "r");
474 if(!f) {
475 PrintAndLog("couldn't open '%s'", Cmd);
476 return -1;
477 }
478
479 char line[80];
480 int offset = 0;
481 uint8_t data[USB_CMD_DATA_SIZE] = {0x00};
482 int index = 0;
483 int totalbytes = 0;
484 while ( fgets(line, sizeof(line), f) ) {
485 int res = sscanf(line, "%x %x %x %x %x %x %x %x",
486 (unsigned int *)&data[index],
487 (unsigned int *)&data[index + 1],
488 (unsigned int *)&data[index + 2],
489 (unsigned int *)&data[index + 3],
490 (unsigned int *)&data[index + 4],
491 (unsigned int *)&data[index + 5],
492 (unsigned int *)&data[index + 6],
493 (unsigned int *)&data[index + 7]);
494
495 if(res != 8) {
496 PrintAndLog("Error: could not read samples");
497 fclose(f);
498 return -1;
499 }
500 index += res;
501
502 if ( index == USB_CMD_DATA_SIZE ){
503 // PrintAndLog("sent %d | %d | %d", index, offset, totalbytes);
504 UsbCommand c = { CMD_DOWNLOADED_SIM_SAMPLES_125K, {offset, 0, 0}};
505 memcpy(c.d.asBytes, data, sizeof(data));
506 clearCommandBuffer();
507 SendCommand(&c);
508 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 1500)){
509 PrintAndLog("Command execute timeout");
510 fclose(f);
511 return 1;
512 }
513 offset += index;
514 totalbytes += index;
515 index = 0;
516 }
517 }
518 fclose(f);
519
520 // left over bytes?
521 if ( index != 0 ) {
522 UsbCommand c = { CMD_DOWNLOADED_SIM_SAMPLES_125K, {offset, 0, 0}};
523 memcpy(c.d.asBytes, data, 8);
524 clearCommandBuffer();
525 SendCommand(&c);
526 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 1500)){
527 PrintAndLog("Command execute timeout");
528 return 1;
529 }
530 totalbytes += index;
531 }
532
533 PrintAndLog("loaded %u samples", totalbytes);
534 return 0;
535 }
536
537 int CmdLegicSave(const char *Cmd) {
538 int requested = 1024;
539 int offset = 0;
540 int delivered = 0;
541 char filename[FILE_PATH_SIZE] = {0x00};
542 uint8_t got[1024] = {0x00};
543
544 memset(filename, 0, FILE_PATH_SIZE);
545
546 sscanf(Cmd, " %s %i %i", filename, &requested, &offset);
547
548 /* If no length given save entire legic read buffer */
549 /* round up to nearest 8 bytes so the saved data can be used with legicload */
550 if (requested == 0)
551 requested = 1024;
552
553 if (requested % 8 != 0) {
554 int remainder = requested % 8;
555 requested = requested + 8 - remainder;
556 }
557
558 if (offset + requested > sizeof(got)) {
559 PrintAndLog("Tried to read past end of buffer, <bytes> + <offset> > 1024");
560 return 0;
561 }
562
563 GetFromBigBuf(got, requested, offset);
564 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2000)){
565 PrintAndLog("Command execute timeout");
566 return 1;
567 }
568
569 FILE *f = fopen(filename, "w");
570 if(!f) {
571 PrintAndLog("couldn't open '%s'", Cmd+1);
572 return -1;
573 }
574
575 for (int j = 0; j < requested; j += 8) {
576 fprintf(f, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
577 got[j+0], got[j+1], got[j+2], got[j+3],
578 got[j+4], got[j+5], got[j+6], got[j+7]
579 );
580 delivered += 8;
581 if (delivered >= requested) break;
582 }
583
584 fclose(f);
585 PrintAndLog("saved %u samples", delivered);
586 return 0;
587 }
588
589 //TODO: write a help text (iceman)
590 int CmdLegicRfSim(const char *Cmd) {
591 UsbCommand c = {CMD_SIMULATE_TAG_LEGIC_RF, {6,3,0}};
592 sscanf(Cmd, " %"lli" %"lli" %"lli, &c.arg[0], &c.arg[1], &c.arg[2]);
593 clearCommandBuffer();
594 SendCommand(&c);
595 return 0;
596 }
597
598 int CmdLegicRfWrite(const char *Cmd) {
599
600 // params:
601 // offset - in tag memory
602 // length - num of bytes to be written
603 // IV - initialisation vector
604
605 char cmdp = param_getchar(Cmd, 0);
606 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_write();
607
608 uint32_t offset = 0, len = 0, IV = 0;
609
610 int res = sscanf(Cmd, "%x %x %x", &offset, &len, &IV);
611 if(res < 2) {
612 PrintAndLog("Please specify the offset and length as two hex strings and, optionally, the IV also as an hex string");
613 return -1;
614 }
615
616 // OUT-OF-BOUNDS check
617 if ( len + offset > MAX_LENGTH ) {
618 len = MAX_LENGTH - offset;
619 PrintAndLog("Out-of-bound, shorten len to %d", len);
620 }
621 if ( (IV & 0x7F) != IV ){
622 IV &= 0x7F;
623 PrintAndLog("Truncating IV to 7bits");
624 }
625 if ( (IV & 1) == 0 ){
626 IV |= 0x01; // IV must be odd
627 PrintAndLog("LSB of IV must be SET");
628 }
629
630 UsbCommand c = {CMD_WRITER_LEGIC_RF, {offset, len, IV}};
631 clearCommandBuffer();
632 SendCommand(&c);
633 UsbCommand resp;
634 if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
635 uint8_t isOK = resp.arg[0] & 0xFF;
636 if ( isOK ) {
637 } else {
638 PrintAndLog("failed writig tag");
639 }
640 } else {
641 PrintAndLog("command execution time out");
642 return 1;
643 }
644
645 return 0;
646 }
647
648 int CmdLegicRfRawWrite(const char *Cmd) {
649
650 char cmdp = param_getchar(Cmd, 0);
651 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_rawwrite();
652
653 uint32_t offset = 0, data = 0, IV = 0;
654 char answer;
655
656 int res = sscanf(Cmd, "%x %x %x", &offset, &data, &IV);
657 if(res < 2)
658 return usage_legic_rawwrite();
659
660 // OUT-OF-BOUNDS check
661 if ( offset > MAX_LENGTH ) {
662 offset = MAX_LENGTH;
663 PrintAndLog("Out-of-bound, shorten len to %d", offset);
664 }
665
666 if ( (IV & 0x7F) != IV ){
667 IV &= 0x7F;
668 PrintAndLog("Truncating IV to 7bits");
669 }
670 if ( (IV & 1) == 0 ){
671 IV |= 0x01; // IV must be odd
672 PrintAndLog("LSB of IV must be SET");
673 }
674
675 UsbCommand c = { CMD_RAW_WRITER_LEGIC_RF, {offset, data, IV} };
676
677 if (c.arg[0] == 0x05 || c.arg[0] == 0x06) {
678 PrintAndLog("############# DANGER !! #############");
679 PrintAndLog("# changing the DCF is irreversible #");
680 PrintAndLog("#####################################");
681 PrintAndLog("do youe really want to continue? y(es) n(o)");
682 if (scanf(" %c", &answer) > 0 && (answer == 'y' || answer == 'Y')) {
683 SendCommand(&c);
684 return 0;
685 }
686 return -1;
687 }
688
689 clearCommandBuffer();
690 SendCommand(&c);
691 return 0;
692 }
693
694 //TODO: write a help text (iceman)
695 int CmdLegicRfFill(const char *Cmd) {
696 UsbCommand cmd = {CMD_WRITER_LEGIC_RF, {0,0,0} };
697 int res = sscanf(Cmd, " 0x%"llx" 0x%"llx" 0x%"llx, &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]);
698 if(res != 3) {
699 PrintAndLog("Please specify the offset, length and value as two hex strings");
700 return -1;
701 }
702
703 int i;
704 UsbCommand c = {CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 0, 0}};
705 memset(c.d.asBytes, cmd.arg[2], 48);
706
707 for(i = 0; i < 22; i++) {
708 c.arg[0] = i*48;
709
710 clearCommandBuffer();
711 SendCommand(&c);
712 WaitForResponse(CMD_ACK, NULL);
713 }
714 clearCommandBuffer();
715 SendCommand(&cmd);
716 return 0;
717 }
718
719 void static calc4(uint8_t *cmd, uint8_t len){
720 crc_t crc;
721 //crc_init_ref(&crc, 4, 0x19 >> 1, 0x5, 0, TRUE, TRUE);
722 crc_init(&crc, 4, 0x19 >> 1, 0x5, 0);
723
724 crc_clear(&crc);
725 crc_update(&crc, 1, 1); /* CMD_READ */
726 crc_update(&crc, cmd[0], 8);
727 crc_update(&crc, cmd[1], 8);
728 printf("crc4 %X\n", reflect(crc_finish(&crc), 4) ) ;
729
730 crc_clear(&crc);
731 crc_update(&crc, 1, 1); /* CMD_READ */
732 crc_update(&crc, cmd[0], 8);
733 crc_update(&crc, cmd[1], 8);
734 printf("crc4 %X\n", crc_finish(&crc) ) ;
735
736 printf("---- old ---\n");
737 crc_update2(&crc, 1, 1); /* CMD_READ */
738 crc_update2(&crc, cmd[0], 8);
739 crc_update2(&crc, cmd[1], 8);
740 printf("crc4 %X \n", reflect(crc_finish(&crc), 4) ) ;
741
742
743 crc_clear(&crc);
744 crc_update2(&crc, 1, 1); /* CMD_READ */
745 crc_update2(&crc, cmd[0], 8);
746 crc_update2(&crc, cmd[1], 8);
747 printf("crc4 %X\n", crc_finish(&crc) ) ;
748 }
749
750 int CmdLegicCalcCrc8(const char *Cmd){
751
752 uint8_t *data = NULL;
753 uint8_t cmdp = 0, uidcrc = 0, type=0;
754 bool errors = false;
755 int len = 0;
756 int bg, en;
757
758 while(param_getchar(Cmd, cmdp) != 0x00) {
759 switch(param_getchar(Cmd, cmdp)) {
760 case 'b':
761 case 'B':
762 // peek at length of the input string so we can
763 // figure out how many elements to malloc in "data"
764 bg=en=0;
765 if (param_getptr(Cmd, &bg, &en, cmdp+1)) {
766 errors = true;
767 break;
768 }
769 len = (en - bg + 1);
770
771 // check that user entered even number of characters
772 // for hex data string
773 if (len & 1) {
774 errors = true;
775 break;
776 }
777
778 // it's possible for user to accidentally enter "b" parameter
779 // more than once - we have to clean previous malloc
780 if (data) free(data);
781 data = malloc(len >> 1);
782 if ( data == NULL ) {
783 PrintAndLog("Can't allocate memory. exiting");
784 errors = true;
785 break;
786 }
787
788 if (param_gethex(Cmd, cmdp+1, data, len)) {
789 errors = true;
790 break;
791 }
792
793 len >>= 1;
794 cmdp += 2;
795 break;
796 case 'u':
797 case 'U':
798 uidcrc = param_get8ex(Cmd, cmdp+1, 0, 16);
799 cmdp += 2;
800 break;
801 case 'c':
802 case 'C':
803 type = param_get8ex(Cmd, cmdp+1, 0, 10);
804 cmdp += 2;
805 break;
806 case 'h':
807 case 'H':
808 errors = true;
809 break;
810 default:
811 PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
812 errors = true;
813 break;
814 }
815 if (errors) break;
816 }
817 //Validations
818 if (errors){
819 if (data) free(data);
820 return usage_legic_calccrc8();
821 }
822
823 switch (type){
824 case 16:
825 PrintAndLog("Legic crc16: %X", CRC16Legic(data, len, uidcrc));
826 break;
827 case 4:
828 calc4(data, 0);
829 break;
830 default:
831 PrintAndLog("Legic crc8: %X", CRC8Legic(data, len) );
832 break;
833 }
834
835 if (data) free(data);
836 return 0;
837 }
838
839 int HFLegicInfo(const char *Cmd, bool verbose) {
840
841 char cmdp = param_getchar(Cmd, 0);
842 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_info();
843
844 UsbCommand c = {CMD_LEGIC_INFO, {0,0,0}};
845 clearCommandBuffer();
846 SendCommand(&c);
847 UsbCommand resp;
848 if (!WaitForResponseTimeout(CMD_ACK, &resp, 500)) {
849 if ( verbose ) PrintAndLog("command execution time out");
850 return 1;
851 }
852
853 uint8_t isOK = resp.arg[0] & 0xFF;
854 if ( !isOK ) {
855 if ( verbose ) PrintAndLog("legic card select failed");
856 return 1;
857 }
858
859 legic_card_select_t card;
860 memcpy(&card, (legic_card_select_t *)resp.d.asBytes, sizeof(legic_card_select_t));
861
862 PrintAndLog(" UID : %s", sprint_hex(card.uid, sizeof(card.uid)));
863 switch(card.cardsize) {
864 case 22:
865 case 256:
866 case 1024:
867 PrintAndLog(" TYPE : MIM%d card (%d bytes)", card.cardsize, card.cardsize); break;
868 default: {
869 PrintAndLog("Unknown card format: %d", card.cardsize);
870 return 1;
871 }
872 }
873 return 0;
874 }
875 int CmdLegicInfo(const char *Cmd){
876 return HFLegicInfo(Cmd, TRUE);
877 }
878
879 static command_t CommandTable[] = {
880 {"help", CmdHelp, 1, "This help"},
881 {"decode", CmdLegicDecode, 0, "Display deobfuscated and decoded LEGIC RF tag data (use after hf legic reader)"},
882 {"read", CmdLegicRFRead, 0, "[offset][length] <iv> -- read bytes from a LEGIC card"},
883 {"save", CmdLegicSave, 0, "<filename> [<length>] -- Store samples"},
884 {"load", CmdLegicLoad, 0, "<filename> -- Restore samples"},
885 {"sim", CmdLegicRfSim, 0, "[phase drift [frame drift [req/resp drift]]] Start tag simulator (use after load or read)"},
886 {"write", CmdLegicRfWrite,0, "<offset> <length> <iv> -- Write sample buffer (user after load or read)"},
887 {"writeraw",CmdLegicRfRawWrite, 0, "<address> <value> <iv> -- Write direct to address"},
888 {"fill", CmdLegicRfFill, 0, "<offset> <length> <value> -- Fill/Write tag with constant value"},
889 {"crc8", CmdLegicCalcCrc8, 1, "Calculate Legic CRC8 over given hexbytes"},
890 {"info", CmdLegicInfo, 1, "Information"},
891 {NULL, NULL, 0, NULL}
892 };
893
894 int CmdHFLegic(const char *Cmd) {
895 clearCommandBuffer();
896 CmdsParse(CommandTable, Cmd);
897 return 0;
898 }
899
900 int CmdHelp(const char *Cmd) {
901 CmdsHelp(CommandTable);
902 return 0;
903 }
Impressum, Datenschutz