]> git.zerfleddert.de Git - proxmark3-svn/blob - client/cmdhflegic.c
FIX: forgot a LEN in print message.
[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 (0x%02X)", len, 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 UsbCommand c = {CMD_READER_LEGIC_RF, {offset, len, IV}};
417 clearCommandBuffer();
418 SendCommand(&c);
419 UsbCommand resp;
420 if (WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
421 uint8_t isOK = resp.arg[0] & 0xFF;
422 uint16_t readlen = resp.arg[1];
423 if ( isOK ) {
424
425 uint8_t *data = malloc(readlen);
426 if ( !data ){
427 PrintAndLog("Cannot allocate memory");
428 return 2;
429 }
430
431 if ( readlen != len )
432 PrintAndLog("Fail, only managed to read 0x%02X bytes", readlen);
433
434 // copy data from device
435 GetEMLFromBigBuf(data, readlen, 0);
436 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2500)){
437 PrintAndLog("Command execute timeout");
438 if ( data )
439 free(data);
440 return 1;
441 }
442
443 PrintAndLog("\nData");
444 PrintAndLog("-----------------------------");
445 print_hex_break( data, readlen, 32);
446 } else {
447 PrintAndLog("failed reading tag");
448 }
449 } else {
450 PrintAndLog("command execution time out");
451 return 1;
452 }
453 return 0;
454 }
455
456 int CmdLegicLoad(const char *Cmd) {
457
458 // iceman: potential bug, where all filepaths or filename which starts with H or h will print the helptext :)
459 char cmdp = param_getchar(Cmd, 0);
460 if ( cmdp == 'H' || cmdp == 'h' || cmdp == 0x00) return usage_legic_load();
461
462 char filename[FILE_PATH_SIZE] = {0x00};
463 int len = strlen(Cmd);
464
465 if (len > FILE_PATH_SIZE) {
466 PrintAndLog("Filepath too long (was %s bytes), max allowed is %s ", len, FILE_PATH_SIZE);
467 return 0;
468 }
469 memcpy(filename, Cmd, len);
470
471 FILE *f = fopen(filename, "r");
472 if(!f) {
473 PrintAndLog("couldn't open '%s'", Cmd);
474 return -1;
475 }
476
477 char line[80];
478 int offset = 0;
479 uint8_t data[USB_CMD_DATA_SIZE] = {0x00};
480 int index = 0;
481 int totalbytes = 0;
482 while ( fgets(line, sizeof(line), f) ) {
483 int res = sscanf(line, "%x %x %x %x %x %x %x %x",
484 (unsigned int *)&data[index],
485 (unsigned int *)&data[index + 1],
486 (unsigned int *)&data[index + 2],
487 (unsigned int *)&data[index + 3],
488 (unsigned int *)&data[index + 4],
489 (unsigned int *)&data[index + 5],
490 (unsigned int *)&data[index + 6],
491 (unsigned int *)&data[index + 7]);
492
493 if(res != 8) {
494 PrintAndLog("Error: could not read samples");
495 fclose(f);
496 return -1;
497 }
498 index += res;
499
500 if ( index == USB_CMD_DATA_SIZE ){
501 // PrintAndLog("sent %d | %d | %d", index, offset, totalbytes);
502 UsbCommand c = { CMD_DOWNLOADED_SIM_SAMPLES_125K, {offset, 0, 0}};
503 memcpy(c.d.asBytes, data, sizeof(data));
504 clearCommandBuffer();
505 SendCommand(&c);
506 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 1500)){
507 PrintAndLog("Command execute timeout");
508 fclose(f);
509 return 1;
510 }
511 offset += index;
512 totalbytes += index;
513 index = 0;
514 }
515 }
516 fclose(f);
517
518 // left over bytes?
519 if ( index != 0 ) {
520 UsbCommand c = { CMD_DOWNLOADED_SIM_SAMPLES_125K, {offset, 0, 0}};
521 memcpy(c.d.asBytes, data, 8);
522 clearCommandBuffer();
523 SendCommand(&c);
524 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 1500)){
525 PrintAndLog("Command execute timeout");
526 return 1;
527 }
528 totalbytes += index;
529 }
530
531 PrintAndLog("loaded %u samples", totalbytes);
532 return 0;
533 }
534
535 int CmdLegicSave(const char *Cmd) {
536 int requested = 1024;
537 int offset = 0;
538 int delivered = 0;
539 char filename[FILE_PATH_SIZE] = {0x00};
540 uint8_t got[1024] = {0x00};
541
542 memset(filename, 0, FILE_PATH_SIZE);
543
544 sscanf(Cmd, " %s %i %i", filename, &requested, &offset);
545
546 /* If no length given save entire legic read buffer */
547 /* round up to nearest 8 bytes so the saved data can be used with legicload */
548 if (requested == 0)
549 requested = 1024;
550
551 if (requested % 8 != 0) {
552 int remainder = requested % 8;
553 requested = requested + 8 - remainder;
554 }
555
556 if (offset + requested > sizeof(got)) {
557 PrintAndLog("Tried to read past end of buffer, <bytes> + <offset> > 1024");
558 return 0;
559 }
560
561 GetFromBigBuf(got, requested, offset);
562 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2000)){
563 PrintAndLog("Command execute timeout");
564 return 1;
565 }
566
567 FILE *f = fopen(filename, "w");
568 if(!f) {
569 PrintAndLog("couldn't open '%s'", Cmd+1);
570 return -1;
571 }
572
573 for (int j = 0; j < requested; j += 8) {
574 fprintf(f, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
575 got[j+0], got[j+1], got[j+2], got[j+3],
576 got[j+4], got[j+5], got[j+6], got[j+7]
577 );
578 delivered += 8;
579 if (delivered >= requested) break;
580 }
581
582 fclose(f);
583 PrintAndLog("saved %u samples", delivered);
584 return 0;
585 }
586
587 //TODO: write a help text (iceman)
588 int CmdLegicRfSim(const char *Cmd) {
589 UsbCommand c = {CMD_SIMULATE_TAG_LEGIC_RF, {6,3,0}};
590 sscanf(Cmd, " %"lli" %"lli" %"lli, &c.arg[0], &c.arg[1], &c.arg[2]);
591 clearCommandBuffer();
592 SendCommand(&c);
593 return 0;
594 }
595
596 int CmdLegicRfWrite(const char *Cmd) {
597
598 // params:
599 // offset - in tag memory
600 // length - num of bytes to be written
601 // IV - initialisation vector
602
603 char cmdp = param_getchar(Cmd, 0);
604 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_write();
605
606 uint32_t offset = 0, len = 0, IV = 0;
607
608 int res = sscanf(Cmd, "%x %x %x", &offset, &len, &IV);
609 if(res < 2) {
610 PrintAndLog("Please specify the offset and length as two hex strings and, optionally, the IV also as an hex string");
611 return -1;
612 }
613
614 // OUT-OF-BOUNDS check
615 if ( len + offset > MAX_LENGTH ) {
616 len = MAX_LENGTH - offset;
617 PrintAndLog("Out-of-bound, shorten len to %d (0x%02X)", len, len);
618 }
619 if ( (IV & 0x7F) != IV ){
620 IV &= 0x7F;
621 PrintAndLog("Truncating IV to 7bits");
622 }
623 if ( (IV & 1) == 0 ){
624 IV |= 0x01; // IV must be odd
625 PrintAndLog("LSB of IV must be SET");
626 }
627
628 UsbCommand c = {CMD_WRITER_LEGIC_RF, {offset, len, IV}};
629 clearCommandBuffer();
630 SendCommand(&c);
631 UsbCommand resp;
632 if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
633 uint8_t isOK = resp.arg[0] & 0xFF;
634 if ( isOK ) {
635 } else {
636 PrintAndLog("failed writig tag");
637 }
638 } else {
639 PrintAndLog("command execution time out");
640 return 1;
641 }
642
643 return 0;
644 }
645
646 int CmdLegicRfRawWrite(const char *Cmd) {
647
648 char cmdp = param_getchar(Cmd, 0);
649 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_rawwrite();
650
651 uint32_t offset = 0, data = 0, IV = 0;
652 char answer;
653
654 int res = sscanf(Cmd, "%x %x %x", &offset, &data, &IV);
655 if(res < 2)
656 return usage_legic_rawwrite();
657
658 // OUT-OF-BOUNDS check
659 if ( offset > MAX_LENGTH ) {
660 PrintAndLog("Out-of-bound, offset");
661 return 1;
662 }
663
664 if ( (IV & 0x7F) != IV ){
665 IV &= 0x7F;
666 PrintAndLog("Truncating IV to 7bits");
667 }
668 if ( (IV & 1) == 0 ){
669 IV |= 0x01; // IV must be odd
670 PrintAndLog("LSB of IV must be SET");
671 }
672
673 UsbCommand c = { CMD_RAW_WRITER_LEGIC_RF, {offset, data, IV} };
674
675 if (c.arg[0] == 0x05 || c.arg[0] == 0x06) {
676 PrintAndLog("############# DANGER !! #############");
677 PrintAndLog("# changing the DCF is irreversible #");
678 PrintAndLog("#####################################");
679 PrintAndLog("do youe really want to continue? y(es) n(o)");
680 if (scanf(" %c", &answer) > 0 && (answer == 'y' || answer == 'Y')) {
681 SendCommand(&c);
682 return 0;
683 }
684 return -1;
685 }
686
687 clearCommandBuffer();
688 SendCommand(&c);
689 return 0;
690 }
691
692 //TODO: write a help text (iceman)
693 int CmdLegicRfFill(const char *Cmd) {
694 UsbCommand cmd = {CMD_WRITER_LEGIC_RF, {0,0,0} };
695 int res = sscanf(Cmd, " 0x%"llx" 0x%"llx" 0x%"llx, &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]);
696 if(res != 3) {
697 PrintAndLog("Please specify the offset, length and value as two hex strings");
698 return -1;
699 }
700
701 int i;
702 UsbCommand c = {CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 0, 0}};
703 memset(c.d.asBytes, cmd.arg[2], 48);
704
705 for(i = 0; i < 22; i++) {
706 c.arg[0] = i*48;
707
708 clearCommandBuffer();
709 SendCommand(&c);
710 WaitForResponse(CMD_ACK, NULL);
711 }
712 clearCommandBuffer();
713 SendCommand(&cmd);
714 return 0;
715 }
716
717 void static calc4(uint8_t *cmd, uint8_t len){
718 crc_t crc;
719 //crc_init_ref(&crc, 4, 0x19 >> 1, 0x5, 0, TRUE, TRUE);
720 crc_init(&crc, 4, 0x19 >> 1, 0x5, 0);
721
722 crc_clear(&crc);
723 crc_update(&crc, 1, 1); /* CMD_READ */
724 crc_update(&crc, cmd[0], 8);
725 crc_update(&crc, cmd[1], 8);
726 printf("crc4 %X\n", reflect(crc_finish(&crc), 4) ) ;
727
728 crc_clear(&crc);
729 crc_update(&crc, 1, 1); /* CMD_READ */
730 crc_update(&crc, cmd[0], 8);
731 crc_update(&crc, cmd[1], 8);
732 printf("crc4 %X\n", crc_finish(&crc) ) ;
733
734 printf("---- old ---\n");
735 crc_update2(&crc, 1, 1); /* CMD_READ */
736 crc_update2(&crc, cmd[0], 8);
737 crc_update2(&crc, cmd[1], 8);
738 printf("crc4 %X \n", reflect(crc_finish(&crc), 4) ) ;
739
740
741 crc_clear(&crc);
742 crc_update2(&crc, 1, 1); /* CMD_READ */
743 crc_update2(&crc, cmd[0], 8);
744 crc_update2(&crc, cmd[1], 8);
745 printf("crc4 %X\n", crc_finish(&crc) ) ;
746 }
747
748 int CmdLegicCalcCrc8(const char *Cmd){
749
750 uint8_t *data = NULL;
751 uint8_t cmdp = 0, uidcrc = 0, type=0;
752 bool errors = false;
753 int len = 0;
754 int bg, en;
755
756 while(param_getchar(Cmd, cmdp) != 0x00) {
757 switch(param_getchar(Cmd, cmdp)) {
758 case 'b':
759 case 'B':
760 // peek at length of the input string so we can
761 // figure out how many elements to malloc in "data"
762 bg=en=0;
763 if (param_getptr(Cmd, &bg, &en, cmdp+1)) {
764 errors = true;
765 break;
766 }
767 len = (en - bg + 1);
768
769 // check that user entered even number of characters
770 // for hex data string
771 if (len & 1) {
772 errors = true;
773 break;
774 }
775
776 // it's possible for user to accidentally enter "b" parameter
777 // more than once - we have to clean previous malloc
778 if (data) free(data);
779 data = malloc(len >> 1);
780 if ( data == NULL ) {
781 PrintAndLog("Can't allocate memory. exiting");
782 errors = true;
783 break;
784 }
785
786 if (param_gethex(Cmd, cmdp+1, data, len)) {
787 errors = true;
788 break;
789 }
790
791 len >>= 1;
792 cmdp += 2;
793 break;
794 case 'u':
795 case 'U':
796 uidcrc = param_get8ex(Cmd, cmdp+1, 0, 16);
797 cmdp += 2;
798 break;
799 case 'c':
800 case 'C':
801 type = param_get8ex(Cmd, cmdp+1, 0, 10);
802 cmdp += 2;
803 break;
804 case 'h':
805 case 'H':
806 errors = true;
807 break;
808 default:
809 PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
810 errors = true;
811 break;
812 }
813 if (errors) break;
814 }
815 //Validations
816 if (errors){
817 if (data) free(data);
818 return usage_legic_calccrc8();
819 }
820
821 switch (type){
822 case 16:
823 PrintAndLog("Legic crc16: %X", CRC16Legic(data, len, uidcrc));
824 break;
825 case 4:
826 calc4(data, 0);
827 break;
828 default:
829 PrintAndLog("Legic crc8: %X", CRC8Legic(data, len) );
830 break;
831 }
832
833 if (data) free(data);
834 return 0;
835 }
836
837 int HFLegicInfo(const char *Cmd, bool verbose) {
838
839 char cmdp = param_getchar(Cmd, 0);
840 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_info();
841
842 UsbCommand c = {CMD_LEGIC_INFO, {0,0,0}};
843 clearCommandBuffer();
844 SendCommand(&c);
845 UsbCommand resp;
846 if (!WaitForResponseTimeout(CMD_ACK, &resp, 500)) {
847 if ( verbose ) PrintAndLog("command execution time out");
848 return 1;
849 }
850
851 uint8_t isOK = resp.arg[0] & 0xFF;
852 if ( !isOK ) {
853 if ( verbose ) PrintAndLog("legic card select failed");
854 return 1;
855 }
856
857 legic_card_select_t card;
858 memcpy(&card, (legic_card_select_t *)resp.d.asBytes, sizeof(legic_card_select_t));
859
860 PrintAndLog(" UID : %s", sprint_hex(card.uid, sizeof(card.uid)));
861 switch(card.cardsize) {
862 case 22:
863 case 256:
864 case 1024:
865 PrintAndLog(" TYPE : MIM%d card (%d bytes)", card.cardsize, card.cardsize); break;
866 default: {
867 PrintAndLog("Unknown card format: %d", card.cardsize);
868 return 1;
869 }
870 }
871 return 0;
872 }
873 int CmdLegicInfo(const char *Cmd){
874 return HFLegicInfo(Cmd, TRUE);
875 }
876
877 static command_t CommandTable[] = {
878 {"help", CmdHelp, 1, "This help"},
879 {"decode", CmdLegicDecode, 0, "Display deobfuscated and decoded LEGIC RF tag data (use after hf legic reader)"},
880 {"read", CmdLegicRFRead, 0, "[offset][length] <iv> -- read bytes from a LEGIC card"},
881 {"save", CmdLegicSave, 0, "<filename> [<length>] -- Store samples"},
882 {"load", CmdLegicLoad, 0, "<filename> -- Restore samples"},
883 {"sim", CmdLegicRfSim, 0, "[phase drift [frame drift [req/resp drift]]] Start tag simulator (use after load or read)"},
884 {"write", CmdLegicRfWrite,0, "<offset> <length> <iv> -- Write sample buffer (user after load or read)"},
885 {"writeraw",CmdLegicRfRawWrite, 0, "<address> <value> <iv> -- Write direct to address"},
886 {"fill", CmdLegicRfFill, 0, "<offset> <length> <value> -- Fill/Write tag with constant value"},
887 {"crc8", CmdLegicCalcCrc8, 1, "Calculate Legic CRC8 over given hexbytes"},
888 {"info", CmdLegicInfo, 1, "Information"},
889 {NULL, NULL, 0, NULL}
890 };
891
892 int CmdHFLegic(const char *Cmd) {
893 clearCommandBuffer();
894 CmdsParse(CommandTable, Cmd);
895 return 0;
896 }
897
898 int CmdHelp(const char *Cmd) {
899 CmdsHelp(CommandTable);
900 return 0;
901 }
Impressum, Datenschutz