]> git.zerfleddert.de Git - proxmark3-svn/blame - client/cmdhflegic.c
CHG: fixed the coverity build script
[proxmark3-svn] / client / cmdhflegic.c
CommitLineData
a553f267 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//-----------------------------------------------------------------------------
7fe9b0b7 10#include "cmdhflegic.h"
3e134b4c 11
7fe9b0b7 12static int CmdHelp(const char *Cmd);
13
ffa306de 14#define MAX_LENGTH 1024
15
3b920280 16int usage_legic_calccrc8(void){
3e134b4c 17 PrintAndLog("Calculates the legic crc8/crc16 on the input hexbytes.");
3b920280 18 PrintAndLog("There must be an even number of hexsymbols as input.");
514ddaa2 19 PrintAndLog("Usage: hf legic crc8 [h] b <hexbytes> u <uidcrc> c <crc type>");
20 PrintAndLog("Options:");
ffa306de 21 PrintAndLog(" h : this help");
3e134b4c 22 PrintAndLog(" b <hexbytes> : hex bytes");
23 PrintAndLog(" u <uidcrc> : MCC hexbyte");
514ddaa2 24 PrintAndLog(" c <crc type> : 8|16 bit crc size");
3b920280 25 PrintAndLog("");
514ddaa2 26 PrintAndLog("Samples:");
3e134b4c 27 PrintAndLog(" hf legic crc8 b deadbeef1122");
514ddaa2 28 PrintAndLog(" hf legic crc8 b deadbeef1122 u 9A c 16");
3b920280 29 return 0;
30}
e579e768 31int usage_legic_load(void){
32 PrintAndLog("It loads datasamples from the file `filename` to device memory");
ffa306de 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");
514ddaa2 37 PrintAndLog("");
38 PrintAndLog("Samples:");
39 PrintAndLog(" hf legic load filename");
e579e768 40 return 0;
41}
cbdcc89a 42int usage_legic_read(void){
43 PrintAndLog("Read data from a legic tag.");
ffa306de 44 PrintAndLog("Usage: hf legic read [h] <offset> <length> <IV>");
514ddaa2 45 PrintAndLog("Options:");
ffa306de 46 PrintAndLog(" h : this help");
86087eba 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)");
cbdcc89a 50 PrintAndLog("");
514ddaa2 51 PrintAndLog("Samples:");
86087eba 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");
cbdcc89a 55 return 0;
56}
e8fecd72 57int usage_legic_sim(void){
ffa306de 58 PrintAndLog("Missing help text.");
59 return 0;
60}
61int 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");
86087eba 66 PrintAndLog(" <offset> : offset in data array to start writing from (hex)");
67 PrintAndLog(" <length> : number of bytes to write (hex)");
b98827ff 68 PrintAndLog(" <IV> : (optional) Initialization vector to use (ODD and 7bits)");
ffa306de 69 PrintAndLog("");
70 PrintAndLog("Samples:");
86087eba 71 PrintAndLog(" hf legic write 10 4 - writes 0x4 to byte[0x10]");
e8fecd72 72 return 0;
73}
74int usage_legic_rawwrite(void){
86087eba 75 PrintAndLog("Write raw data direct to a specific offset on legic tag.");
76 PrintAndLog("Usage: hf legic writeraw [h] <offset> <value> <IV>");
ffa306de 77 PrintAndLog("Options:");
78 PrintAndLog(" h : this help");
86087eba 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)");
ffa306de 82 PrintAndLog("");
83 PrintAndLog("Samples:");
86087eba 84 PrintAndLog(" hf legic writeraw 10 4 - writes 0x4 to byte[0x10]");
e8fecd72 85 return 0;
86}
87int usage_legic_fill(void){
ffa306de 88 PrintAndLog("Missing help text.");
e8fecd72 89 return 0;
90}
3e750be3 91int 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}
669c1b80 101/*
102 * Output BigBuf and deobfuscate LEGIC RF tag data.
cbdcc89a 103 * This is based on information given in the talk held
669c1b80 104 * by Henryk Ploetz and Karsten Nohl at 26c3
669c1b80 105 */
3b920280 106int CmdLegicDecode(const char *Cmd) {
e8fecd72 107
108 int i = 0, k = 0, segmentNum = 0, segment_len = 0, segment_flag = 0;
109 int crc = 0, wrp = 0, wrc = 0;
60bb5ef7 110 uint8_t stamp_len = 0;
77a689db 111 uint8_t data[1024]; // receiver buffer
e8fecd72 112 char token_type[5] = {0,0,0,0,0};
113 int dcf = 0;
3e134b4c 114 int bIsSegmented = 0;
52cf34c1 115
77a689db 116 // copy data from device
117 GetEMLFromBigBuf(data, sizeof(data), 0);
f7f844d0 118 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2000)){
119 PrintAndLog("Command execute timeout");
120 return 1;
121 }
122
52cf34c1 123 // Output CDF System area (9 bytes) plus remaining header area (12 bytes)
77a689db 124 crc = data[4];
125 uint32_t calc_crc = CRC8Legic(data, 4);
3b920280 126
52cf34c1 127 PrintAndLog("\nCDF: System Area");
aacb96d7 128 PrintAndLog("------------------------------------------------------");
3b920280 129 PrintAndLog("MCD: %02x, MSN: %02x %02x %02x, MCC: %02x %s",
77a689db 130 data[0],
131 data[1],
132 data[2],
133 data[3],
134 data[4],
135 (calc_crc == crc) ? "OK":"Fail"
52cf34c1 136 );
669c1b80 137
3e134b4c 138
139 token_type[0] = 0;
77a689db 140 dcf = ((int)data[6] << 8) | (int)data[5];
3e134b4c 141
142 // New unwritten media?
143 if(dcf == 0xFFFF) {
144
145 PrintAndLog("DCF: %d (%02x %02x), Token Type=NM (New Media)",
146 dcf,
77a689db 147 data[5],
148 data[6]
3e134b4c 149 );
150
151 } else if(dcf > 60000) { // Master token?
152
153 int fl = 0;
154
77a689db 155 if(data[6] == 0xec) {
3e134b4c 156 strncpy(token_type, "XAM", sizeof(token_type));
157 fl = 1;
77a689db 158 stamp_len = 0x0c - (data[5] >> 4);
3e134b4c 159 } else {
77a689db 160 switch (data[5] & 0x7f) {
e8fecd72 161 case 0x00 ... 0x2f:
162 strncpy(token_type, "IAM", sizeof(token_type));
77a689db 163 fl = (0x2f - (data[5] & 0x7f)) + 1;
e8fecd72 164 break;
165 case 0x30 ... 0x6f:
166 strncpy(token_type, "SAM", sizeof(token_type));
77a689db 167 fl = (0x6f - (data[5] & 0x7f)) + 1;
e8fecd72 168 break;
169 case 0x70 ... 0x7f:
170 strncpy(token_type, "GAM", sizeof(token_type));
77a689db 171 fl = (0x7f - (data[5] & 0x7f)) + 1;
e8fecd72 172 break;
173 }
52cf34c1 174
77a689db 175 stamp_len = 0xfc - data[6];
3e134b4c 176 }
52cf34c1 177
3e134b4c 178 PrintAndLog("DCF: %d (%02x %02x), Token Type=%s (OLE=%01u), OL=%02u, FL=%02u",
179 dcf,
77a689db 180 data[5],
181 data[6],
e8fecd72 182 token_type,
77a689db 183 (data[5] & 0x80 )>> 7,
3e134b4c 184 stamp_len,
185 fl
e8fecd72 186 );
52cf34c1 187
e8fecd72 188 } else { // Is IM(-S) type of card...
3e134b4c 189
77a689db 190 if(data[7] == 0x9F && data[8] == 0xFF) {
3e134b4c 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,
77a689db 199 data[5],
200 data[6],
3e134b4c 201 token_type,
77a689db 202 (data[5]&0x80) >> 7
3e134b4c 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",
77a689db 211 data[7] & 0x0f,
212 (data[7] & 0x70) >> 4,
213 (data[7] & 0x80) >> 7,
214 data[8]
e8fecd72 215 );
3e134b4c 216 }
52cf34c1 217
3e134b4c 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");
77a689db 222 PrintAndLog("%s", sprint_hex(data+8, 14));
3e134b4c 223 } else {
e8fecd72 224 PrintAndLog("Remaining Header Area");
77a689db 225 PrintAndLog("%s", sprint_hex(data+9, 13));
3e134b4c 226 }
227 }
228 }
d7fd9084 229
e8fecd72 230 uint8_t segCrcBytes[8] = {0,0,0,0,0,0,0,0};
e579e768 231 uint32_t segCalcCRC = 0;
232 uint32_t segCRC = 0;
d7fd9084 233
3e134b4c 234 // Data card?
235 if(dcf <= 60000) {
cbdcc89a 236
e8fecd72 237 PrintAndLog("\nADF: User Area");
238 PrintAndLog("------------------------------------------------------");
3e134b4c 239
240 if(bIsSegmented) {
241
242 // Data start point on segmented cards
e8fecd72 243 i = 22;
3e134b4c 244
245 // decode segments
246 for (segmentNum=1; segmentNum < 128; segmentNum++ )
247 {
77a689db 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;
e8fecd72 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);
e579e768 257
e8fecd72 258 // validate segment-crc
77a689db 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
e8fecd72 267
268 segCalcCRC = CRC8Legic(segCrcBytes, 8);
77a689db 269 segCRC = data[i+4] ^ crc;
e8fecd72 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,
77a689db 273 data[i] ^ crc,
274 data[i+1] ^ crc,
275 data[i+2] ^ crc,
276 data[i+3] ^ crc,
e8fecd72 277 segment_len,
278 segment_flag,
279 (segment_flag & 0x4) >> 2,
280 (segment_flag & 0x8) >> 3,
281 wrp,
282 wrc,
77a689db 283 ((data[i+3]^crc) & 0x80) >> 7,
e8fecd72 284 segCRC,
285 ( segCRC == segCalcCRC ) ? "OK" : "fail"
286 );
287
288 i += 5;
669c1b80 289
e8fecd72 290 if ( hasWRC ) {
291 PrintAndLog("WRC protected area: (I %d | K %d| WRC %d)", i, k, wrc);
292 PrintAndLog("\nrow | data");
293 PrintAndLog("-----+------------------------------------------------");
3e134b4c 294
26778ea7 295 for ( k=i; k < (i + wrc); ++k)
77a689db 296 data[k] ^= crc;
3e134b4c 297
77a689db 298 print_hex_break( data+i, wrc, 16);
3b920280 299
e8fecd72 300 i += wrc;
301 }
669c1b80 302
e8fecd72 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("-----+------------------------------------------------");
d7fd9084 307
3e134b4c 308 for (k=i; k < (i+wrp_len); ++k)
77a689db 309 data[k] ^= crc;
3b920280 310
77a689db 311 print_hex_break( data+i, wrp_len, 16);
3b920280 312
e8fecd72 313 i += wrp_len;
d7fd9084 314
3e134b4c 315 // does this one work? (Answer: Only if KGH/BGH is used with BCD encoded card number! So maybe this will show just garbage...)
e8fecd72 316 if( wrp_len == 8 )
77a689db 317 PrintAndLog("Card ID: %2X%02X%02X", data[i-4]^crc, data[i-3]^crc, data[i-2]^crc);
e8fecd72 318 }
669c1b80 319
e8fecd72 320 PrintAndLog("Remaining segment payload: (I %d | K %d | Remain LEN %d)", i, k, remain_seg_payload_len);
321 PrintAndLog("\nrow | data");
322 PrintAndLog("-----+------------------------------------------------");
3e134b4c 323
324 for ( k=i; k < (i+remain_seg_payload_len); ++k)
77a689db 325 data[k] ^= crc;
3b920280 326
77a689db 327 print_hex_break( data+i, remain_seg_payload_len, 16);
669c1b80 328
e8fecd72 329 i += remain_seg_payload_len;
d7fd9084 330
e8fecd72 331 PrintAndLog("-----+------------------------------------------------\n");
a182a680 332
e8fecd72 333 // end with last segment
334 if (segment_flag & 0x8) return 0;
52cf34c1 335
e8fecd72 336 } // end for loop
3e134b4c 337
338 } else {
339
340 // Data start point on unsegmented cards
341 i = 8;
342
77a689db 343 wrp = data[7] & 0x0F;
344 wrc = (data[7] & 0x70) >> 4;
3e134b4c 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,
77a689db 354 (data[7] & 0x80) >> 7
3e134b4c 355 );
356
357 if ( hasWRC ) {
358 PrintAndLog("WRC protected area: (I %d | WRC %d)", i, wrc);
359 PrintAndLog("\nrow | data");
360 PrintAndLog("-----+------------------------------------------------");
77a689db 361 print_hex_break( data+i, wrc, 16);
3e134b4c 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("-----+------------------------------------------------");
77a689db 369 print_hex_break( data + i, wrp_len, 16);
3e134b4c 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 )
77a689db 374 PrintAndLog("Card ID: %2X%02X%02X", data[i-4], data[i-3], data[i-2]);
3e134b4c 375 }
376
377 PrintAndLog("Remaining segment payload: (I %d | Remain LEN %d)", i, remain_seg_payload_len);
378 PrintAndLog("\nrow | data");
379 PrintAndLog("-----+------------------------------------------------");
77a689db 380 print_hex_break( data + i, remain_seg_payload_len, 16);
3e134b4c 381 i += remain_seg_payload_len;
382
383 PrintAndLog("-----+------------------------------------------------\n");
384 }
385 }
52cf34c1 386 return 0;
669c1b80 387}
41dab153 388
52cf34c1 389int CmdLegicRFRead(const char *Cmd) {
ffa306de 390
cbdcc89a 391 // params:
fabef615 392 // offset in data memory
393 // number of bytes to read
cbdcc89a 394 char cmdp = param_getchar(Cmd, 0);
395 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_read();
396
b98827ff 397 uint32_t offset = 0, len = 0, IV = 1;
ffa306de 398 sscanf(Cmd, "%x %x %x", &offset, &len, &IV);
52cf34c1 399
ffa306de 400 // OUT-OF-BOUNDS check
a3994421 401 if ( len + offset > MAX_LENGTH ) {
402 len = MAX_LENGTH - offset;
e1a0ed65 403 PrintAndLog("Out-of-bound, shorten len to %d (0x%02X)", len, len);
a3994421 404 }
ffa306de 405
b98827ff 406 if ( (IV & 0x7F) != IV ){
407 IV &= 0x7F;
408 PrintAndLog("Truncating IV to 7bits");
409 }
a3994421 410
b98827ff 411 if ( (IV & 1) == 0 ){
a3994421 412 IV |= 0x01;
b98827ff 413 PrintAndLog("LSB of IV must be SET");
414 }
ffa306de 415
ad5bc8cc 416 UsbCommand c = {CMD_READER_LEGIC_RF, {offset, len, IV}};
52cf34c1 417 clearCommandBuffer();
418 SendCommand(&c);
ad5bc8cc 419 UsbCommand resp;
1daa1226 420 if (WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
ad5bc8cc 421 uint8_t isOK = resp.arg[0] & 0xFF;
7a8db2f6 422 uint16_t readlen = resp.arg[1];
87342aad 423 if ( isOK ) {
c649c433 424
86087eba 425 uint8_t *data = malloc(readlen);
0b0b182f 426 if ( !data ){
427 PrintAndLog("Cannot allocate memory");
428 return 2;
429 }
86087eba 430
431 if ( readlen != len )
432 PrintAndLog("Fail, only managed to read 0x%02X bytes", readlen);
433
0b0b182f 434 // copy data from device
86087eba 435 GetEMLFromBigBuf(data, readlen, 0);
7a8db2f6 436 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2500)){
0b0b182f 437 PrintAndLog("Command execute timeout");
438 if ( data )
439 free(data);
440 return 1;
441 }
442
c15e07f1 443 PrintAndLog("\n ## | Data");
444 PrintAndLog("-----+-----");
86087eba 445 print_hex_break( data, readlen, 32);
c649c433 446 } else {
447 PrintAndLog("failed reading tag");
448 }
ad5bc8cc 449 } else {
450 PrintAndLog("command execution time out");
451 return 1;
452 }
52cf34c1 453 return 0;
41dab153 454}
3612a8a8 455
52cf34c1 456int CmdLegicLoad(const char *Cmd) {
e8fecd72 457
458// iceman: potential bug, where all filepaths or filename which starts with H or h will print the helptext :)
52cf34c1 459 char cmdp = param_getchar(Cmd, 0);
e579e768 460 if ( cmdp == 'H' || cmdp == 'h' || cmdp == 0x00) return usage_legic_load();
b915fda3 461
e579e768 462 char filename[FILE_PATH_SIZE] = {0x00};
463 int len = strlen(Cmd);
464
b915fda3 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");
3612a8a8 472 if(!f) {
473 PrintAndLog("couldn't open '%s'", Cmd);
474 return -1;
475 }
52cf34c1 476
477 char line[80];
810f5379 478 int offset = 0;
c6e0a2eb 479 uint8_t data[USB_CMD_DATA_SIZE] = {0x00};
480 int index = 0;
481 int totalbytes = 0;
52cf34c1 482 while ( fgets(line, sizeof(line), f) ) {
3612a8a8 483 int res = sscanf(line, "%x %x %x %x %x %x %x %x",
c6e0a2eb 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]);
e7d099dc 492
3612a8a8 493 if(res != 8) {
494 PrintAndLog("Error: could not read samples");
495 fclose(f);
496 return -1;
497 }
c6e0a2eb 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);
d7fd9084 506 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 1500)){
507 PrintAndLog("Command execute timeout");
508 fclose(f);
509 return 1;
510 }
c6e0a2eb 511 offset += index;
512 totalbytes += index;
513 index = 0;
514 }
3612a8a8 515 }
516 fclose(f);
c6e0a2eb 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);
d7fd9084 524 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 1500)){
525 PrintAndLog("Command execute timeout");
526 return 1;
527 }
c6e0a2eb 528 totalbytes += index;
529 }
530
531 PrintAndLog("loaded %u samples", totalbytes);
3612a8a8 532 return 0;
533}
534
52cf34c1 535int CmdLegicSave(const char *Cmd) {
536 int requested = 1024;
537 int offset = 0;
538 int delivered = 0;
e8fecd72 539 char filename[FILE_PATH_SIZE] = {0x00};
52cf34c1 540 uint8_t got[1024] = {0x00};
541
e8fecd72 542 memset(filename, 0, FILE_PATH_SIZE);
543
52cf34c1 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 */
e7d099dc 548 if (requested == 0)
52cf34c1 549 requested = 1024;
52cf34c1 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
d7fd9084 561 GetFromBigBuf(got, requested, offset);
f7f844d0 562 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2000)){
aacb96d7 563 PrintAndLog("Command execute timeout");
f7f844d0 564 return 1;
565 }
52cf34c1 566
aacb96d7 567 FILE *f = fopen(filename, "w");
568 if(!f) {
569 PrintAndLog("couldn't open '%s'", Cmd+1);
570 return -1;
571 }
572
52cf34c1 573 for (int j = 0; j < requested; j += 8) {
574 fprintf(f, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
c6e0a2eb 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]
52cf34c1 577 );
578 delivered += 8;
579 if (delivered >= requested) break;
580 }
581
582 fclose(f);
583 PrintAndLog("saved %u samples", delivered);
584 return 0;
3612a8a8 585}
586
f7f844d0 587//TODO: write a help text (iceman)
52cf34c1 588int CmdLegicRfSim(const char *Cmd) {
3b920280 589 UsbCommand c = {CMD_SIMULATE_TAG_LEGIC_RF, {6,3,0}};
52cf34c1 590 sscanf(Cmd, " %"lli" %"lli" %"lli, &c.arg[0], &c.arg[1], &c.arg[2]);
591 clearCommandBuffer();
592 SendCommand(&c);
593 return 0;
3612a8a8 594}
595
52cf34c1 596int CmdLegicRfWrite(const char *Cmd) {
ffa306de 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
b98827ff 606 uint32_t offset = 0, len = 0, IV = 0;
ffa306de 607
ffa306de 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");
3612a8a8 611 return -1;
612 }
ffa306de 613
614 // OUT-OF-BOUNDS check
7bc3c99e 615 if ( len + offset > MAX_LENGTH ) {
616 len = MAX_LENGTH - offset;
e1a0ed65 617 PrintAndLog("Out-of-bound, shorten len to %d (0x%02X)", len, len);
7bc3c99e 618 }
b98827ff 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 }
ffa306de 627
7bc3c99e 628 UsbCommand c = {CMD_WRITER_LEGIC_RF, {offset, len, IV}};
52cf34c1 629 clearCommandBuffer();
3612a8a8 630 SendCommand(&c);
7bc3c99e 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
3612a8a8 643 return 0;
644}
645
3e134b4c 646int CmdLegicRfRawWrite(const char *Cmd) {
ffa306de 647
648 char cmdp = param_getchar(Cmd, 0);
649 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_rawwrite();
650
86087eba 651 uint32_t offset = 0, data = 0, IV = 0;
3e134b4c 652 char answer;
ffa306de 653
86087eba 654 int res = sscanf(Cmd, "%x %x %x", &offset, &data, &IV);
ffa306de 655 if(res < 2)
656 return usage_legic_rawwrite();
86087eba 657
ffa306de 658 // OUT-OF-BOUNDS check
86087eba 659 if ( offset > MAX_LENGTH ) {
7a8db2f6 660 PrintAndLog("Out-of-bound, offset");
661 return 1;
86087eba 662 }
ffa306de 663
b98827ff 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 }
ffa306de 672
86087eba 673 UsbCommand c = { CMD_RAW_WRITER_LEGIC_RF, {offset, data, IV} };
3e134b4c 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)");
6e321dd8 680 if (scanf(" %c", &answer) > 0 && (answer == 'y' || answer == 'Y')) {
3e134b4c 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)
52cf34c1 693int CmdLegicRfFill(const char *Cmd) {
3e134b4c 694 UsbCommand cmd = {CMD_WRITER_LEGIC_RF, {0,0,0} };
1a07fd51 695 int res = sscanf(Cmd, " 0x%"llx" 0x%"llx" 0x%"llx, &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]);
3612a8a8 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;
52cf34c1 702 UsbCommand c = {CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 0, 0}};
ba4ad25b 703 memset(c.d.asBytes, cmd.arg[2], 48);
3e134b4c 704
52cf34c1 705 for(i = 0; i < 22; i++) {
706 c.arg[0] = i*48;
3e134b4c 707
708 clearCommandBuffer();
52cf34c1 709 SendCommand(&c);
3e134b4c 710 WaitForResponse(CMD_ACK, NULL);
52cf34c1 711 }
712 clearCommandBuffer();
3612a8a8 713 SendCommand(&cmd);
714 return 0;
715 }
716
87342aad 717void 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);
f1f7430a 732 printf("crc4 %X\n", crc_finish(&crc) ) ;
87342aad 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);
f1f7430a 745 printf("crc4 %X\n", crc_finish(&crc) ) ;
87342aad 746}
747
3b920280 748int CmdLegicCalcCrc8(const char *Cmd){
749
cc4c8fd6 750 uint8_t *data = NULL;
3e134b4c 751 uint8_t cmdp = 0, uidcrc = 0, type=0;
752 bool errors = false;
753 int len = 0;
e31a0f73 754 int bg, en;
3b920280 755
3e134b4c 756 while(param_getchar(Cmd, cmdp) != 0x00) {
757 switch(param_getchar(Cmd, cmdp)) {
758 case 'b':
759 case 'B':
e31a0f73
AG
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;
987c5984
AG
763 if (param_getptr(Cmd, &bg, &en, cmdp+1)) {
764 errors = true;
765 break;
766 }
e31a0f73
AG
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
08927081
AG
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);
e31a0f73 779 data = malloc(len >> 1);
3e134b4c 780 if ( data == NULL ) {
781 PrintAndLog("Can't allocate memory. exiting");
782 errors = true;
783 break;
e31a0f73
AG
784 }
785
987c5984
AG
786 if (param_gethex(Cmd, cmdp+1, data, len)) {
787 errors = true;
788 break;
789 }
3e134b4c 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){
aeb128e2 817 if (data) free(data);
3e134b4c 818 return usage_legic_calccrc8();
819 }
820
821 switch (type){
822 case 16:
87342aad 823 PrintAndLog("Legic crc16: %X", CRC16Legic(data, len, uidcrc));
824 break;
825 case 4:
826 calc4(data, 0);
3e134b4c 827 break;
828 default:
87342aad 829 PrintAndLog("Legic crc8: %X", CRC8Legic(data, len) );
3e134b4c 830 break;
eb5206bd 831 }
3b920280 832
aeb128e2 833 if (data) free(data);
3b920280 834 return 0;
835}
836
3e750be3 837int 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;
a3994421 846 if (!WaitForResponseTimeout(CMD_ACK, &resp, 500)) {
323e05cc 847 if ( verbose ) PrintAndLog("command execution time out");
3e750be3 848 return 1;
849 }
a3994421 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 }
3e750be3 871 return 0;
872}
873int CmdLegicInfo(const char *Cmd){
874 return HFLegicInfo(Cmd, TRUE);
875}
876
52cf34c1 877static command_t CommandTable[] = {
3b920280 878 {"help", CmdHelp, 1, "This help"},
879 {"decode", CmdLegicDecode, 0, "Display deobfuscated and decoded LEGIC RF tag data (use after hf legic reader)"},
ffa306de 880 {"read", CmdLegicRFRead, 0, "[offset][length] <iv> -- read bytes from a LEGIC card"},
3b920280 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)"},
ffa306de 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"},
3b920280 886 {"fill", CmdLegicRfFill, 0, "<offset> <length> <value> -- Fill/Write tag with constant value"},
887 {"crc8", CmdLegicCalcCrc8, 1, "Calculate Legic CRC8 over given hexbytes"},
3e750be3 888 {"info", CmdLegicInfo, 1, "Information"},
52cf34c1 889 {NULL, NULL, 0, NULL}
890};
891
892int CmdHFLegic(const char *Cmd) {
893 clearCommandBuffer();
894 CmdsParse(CommandTable, Cmd);
895 return 0;
896}
897
898int CmdHelp(const char *Cmd) {
899 CmdsHelp(CommandTable);
900 return 0;
901}
Impressum, Datenschutz