]> git.zerfleddert.de Git - proxmark3-svn/blame - client/cmdhflegic.c
FIX: one too many semicolons for #defines
[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}
00271f77 42int usage_legic_rdmem(void){
cbdcc89a 43 PrintAndLog("Read data from a legic tag.");
00271f77 44 PrintAndLog("Usage: hf legic rdmem [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:");
00271f77 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");
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}
633d0686 91int 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}
3e750be3 101int usage_legic_info(void){
633d0686 102 PrintAndLog("Reads information from a legic prime tag.");
103 PrintAndLog("Shows systemarea, user areas etc");
3e750be3 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}
633d0686 112int 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
669c1b80 127/*
128 * Output BigBuf and deobfuscate LEGIC RF tag data.
cbdcc89a 129 * This is based on information given in the talk held
669c1b80 130 * by Henryk Ploetz and Karsten Nohl at 26c3
669c1b80 131 */
633d0686 132int CmdLegicInfo(const char *Cmd) {
133
134 char cmdp = param_getchar(Cmd, 0);
135 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_info();
e8fecd72 136
137 int i = 0, k = 0, segmentNum = 0, segment_len = 0, segment_flag = 0;
138 int crc = 0, wrp = 0, wrc = 0;
60bb5ef7 139 uint8_t stamp_len = 0;
77a689db 140 uint8_t data[1024]; // receiver buffer
e8fecd72 141 char token_type[5] = {0,0,0,0,0};
142 int dcf = 0;
3e134b4c 143 int bIsSegmented = 0;
52cf34c1 144
00271f77 145 CmdLegicRdmem("0 21 55");
633d0686 146
77a689db 147 // copy data from device
148 GetEMLFromBigBuf(data, sizeof(data), 0);
f7f844d0 149 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2000)){
150 PrintAndLog("Command execute timeout");
151 return 1;
152 }
153
52cf34c1 154 // Output CDF System area (9 bytes) plus remaining header area (12 bytes)
77a689db 155 crc = data[4];
156 uint32_t calc_crc = CRC8Legic(data, 4);
3b920280 157
52cf34c1 158 PrintAndLog("\nCDF: System Area");
aacb96d7 159 PrintAndLog("------------------------------------------------------");
3b920280 160 PrintAndLog("MCD: %02x, MSN: %02x %02x %02x, MCC: %02x %s",
77a689db 161 data[0],
162 data[1],
163 data[2],
164 data[3],
165 data[4],
166 (calc_crc == crc) ? "OK":"Fail"
52cf34c1 167 );
669c1b80 168
3e134b4c 169
170 token_type[0] = 0;
77a689db 171 dcf = ((int)data[6] << 8) | (int)data[5];
3e134b4c 172
173 // New unwritten media?
174 if(dcf == 0xFFFF) {
175
176 PrintAndLog("DCF: %d (%02x %02x), Token Type=NM (New Media)",
177 dcf,
77a689db 178 data[5],
179 data[6]
3e134b4c 180 );
181
182 } else if(dcf > 60000) { // Master token?
183
184 int fl = 0;
185
77a689db 186 if(data[6] == 0xec) {
3e134b4c 187 strncpy(token_type, "XAM", sizeof(token_type));
188 fl = 1;
77a689db 189 stamp_len = 0x0c - (data[5] >> 4);
3e134b4c 190 } else {
77a689db 191 switch (data[5] & 0x7f) {
e8fecd72 192 case 0x00 ... 0x2f:
193 strncpy(token_type, "IAM", sizeof(token_type));
77a689db 194 fl = (0x2f - (data[5] & 0x7f)) + 1;
e8fecd72 195 break;
196 case 0x30 ... 0x6f:
197 strncpy(token_type, "SAM", sizeof(token_type));
77a689db 198 fl = (0x6f - (data[5] & 0x7f)) + 1;
e8fecd72 199 break;
200 case 0x70 ... 0x7f:
201 strncpy(token_type, "GAM", sizeof(token_type));
77a689db 202 fl = (0x7f - (data[5] & 0x7f)) + 1;
e8fecd72 203 break;
204 }
52cf34c1 205
77a689db 206 stamp_len = 0xfc - data[6];
3e134b4c 207 }
52cf34c1 208
3e134b4c 209 PrintAndLog("DCF: %d (%02x %02x), Token Type=%s (OLE=%01u), OL=%02u, FL=%02u",
210 dcf,
77a689db 211 data[5],
212 data[6],
e8fecd72 213 token_type,
77a689db 214 (data[5] & 0x80 )>> 7,
3e134b4c 215 stamp_len,
216 fl
e8fecd72 217 );
52cf34c1 218
e8fecd72 219 } else { // Is IM(-S) type of card...
3e134b4c 220
77a689db 221 if(data[7] == 0x9F && data[8] == 0xFF) {
3e134b4c 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,
77a689db 230 data[5],
231 data[6],
3e134b4c 232 token_type,
77a689db 233 (data[5]&0x80) >> 7
3e134b4c 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",
77a689db 242 data[7] & 0x0f,
243 (data[7] & 0x70) >> 4,
244 (data[7] & 0x80) >> 7,
245 data[8]
e8fecd72 246 );
3e134b4c 247 }
52cf34c1 248
3e134b4c 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");
77a689db 253 PrintAndLog("%s", sprint_hex(data+8, 14));
3e134b4c 254 } else {
e8fecd72 255 PrintAndLog("Remaining Header Area");
77a689db 256 PrintAndLog("%s", sprint_hex(data+9, 13));
3e134b4c 257 }
258 }
259 }
d7fd9084 260
e8fecd72 261 uint8_t segCrcBytes[8] = {0,0,0,0,0,0,0,0};
e579e768 262 uint32_t segCalcCRC = 0;
263 uint32_t segCRC = 0;
d7fd9084 264
3e134b4c 265 // Data card?
266 if(dcf <= 60000) {
cbdcc89a 267
e8fecd72 268 PrintAndLog("\nADF: User Area");
269 PrintAndLog("------------------------------------------------------");
3e134b4c 270
271 if(bIsSegmented) {
272
273 // Data start point on segmented cards
e8fecd72 274 i = 22;
3e134b4c 275
276 // decode segments
277 for (segmentNum=1; segmentNum < 128; segmentNum++ )
278 {
77a689db 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;
e8fecd72 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);
e579e768 288
e8fecd72 289 // validate segment-crc
77a689db 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
e8fecd72 298
299 segCalcCRC = CRC8Legic(segCrcBytes, 8);
77a689db 300 segCRC = data[i+4] ^ crc;
e8fecd72 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,
77a689db 304 data[i] ^ crc,
305 data[i+1] ^ crc,
306 data[i+2] ^ crc,
307 data[i+3] ^ crc,
e8fecd72 308 segment_len,
309 segment_flag,
310 (segment_flag & 0x4) >> 2,
311 (segment_flag & 0x8) >> 3,
312 wrp,
313 wrc,
77a689db 314 ((data[i+3]^crc) & 0x80) >> 7,
e8fecd72 315 segCRC,
316 ( segCRC == segCalcCRC ) ? "OK" : "fail"
317 );
318
319 i += 5;
669c1b80 320
e8fecd72 321 if ( hasWRC ) {
322 PrintAndLog("WRC protected area: (I %d | K %d| WRC %d)", i, k, wrc);
323 PrintAndLog("\nrow | data");
324 PrintAndLog("-----+------------------------------------------------");
3e134b4c 325
26778ea7 326 for ( k=i; k < (i + wrc); ++k)
77a689db 327 data[k] ^= crc;
3e134b4c 328
77a689db 329 print_hex_break( data+i, wrc, 16);
3b920280 330
e8fecd72 331 i += wrc;
332 }
669c1b80 333
e8fecd72 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("-----+------------------------------------------------");
d7fd9084 338
3e134b4c 339 for (k=i; k < (i+wrp_len); ++k)
77a689db 340 data[k] ^= crc;
3b920280 341
77a689db 342 print_hex_break( data+i, wrp_len, 16);
3b920280 343
e8fecd72 344 i += wrp_len;
d7fd9084 345
3e134b4c 346 // does this one work? (Answer: Only if KGH/BGH is used with BCD encoded card number! So maybe this will show just garbage...)
e8fecd72 347 if( wrp_len == 8 )
77a689db 348 PrintAndLog("Card ID: %2X%02X%02X", data[i-4]^crc, data[i-3]^crc, data[i-2]^crc);
e8fecd72 349 }
669c1b80 350
e8fecd72 351 PrintAndLog("Remaining segment payload: (I %d | K %d | Remain LEN %d)", i, k, remain_seg_payload_len);
352 PrintAndLog("\nrow | data");
353 PrintAndLog("-----+------------------------------------------------");
3e134b4c 354
355 for ( k=i; k < (i+remain_seg_payload_len); ++k)
77a689db 356 data[k] ^= crc;
3b920280 357
77a689db 358 print_hex_break( data+i, remain_seg_payload_len, 16);
669c1b80 359
e8fecd72 360 i += remain_seg_payload_len;
d7fd9084 361
e8fecd72 362 PrintAndLog("-----+------------------------------------------------\n");
a182a680 363
e8fecd72 364 // end with last segment
365 if (segment_flag & 0x8) return 0;
52cf34c1 366
e8fecd72 367 } // end for loop
3e134b4c 368
369 } else {
370
371 // Data start point on unsegmented cards
372 i = 8;
373
77a689db 374 wrp = data[7] & 0x0F;
375 wrc = (data[7] & 0x70) >> 4;
3e134b4c 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,
77a689db 385 (data[7] & 0x80) >> 7
3e134b4c 386 );
387
388 if ( hasWRC ) {
389 PrintAndLog("WRC protected area: (I %d | WRC %d)", i, wrc);
390 PrintAndLog("\nrow | data");
391 PrintAndLog("-----+------------------------------------------------");
77a689db 392 print_hex_break( data+i, wrc, 16);
3e134b4c 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("-----+------------------------------------------------");
77a689db 400 print_hex_break( data + i, wrp_len, 16);
3e134b4c 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 )
77a689db 405 PrintAndLog("Card ID: %2X%02X%02X", data[i-4], data[i-3], data[i-2]);
3e134b4c 406 }
407
408 PrintAndLog("Remaining segment payload: (I %d | Remain LEN %d)", i, remain_seg_payload_len);
409 PrintAndLog("\nrow | data");
410 PrintAndLog("-----+------------------------------------------------");
77a689db 411 print_hex_break( data + i, remain_seg_payload_len, 16);
3e134b4c 412 i += remain_seg_payload_len;
413
414 PrintAndLog("-----+------------------------------------------------\n");
415 }
416 }
52cf34c1 417 return 0;
669c1b80 418}
41dab153 419
00271f77 420int CmdLegicRdmem(const char *Cmd) {
ffa306de 421
cbdcc89a 422 // params:
fabef615 423 // offset in data memory
424 // number of bytes to read
cbdcc89a 425 char cmdp = param_getchar(Cmd, 0);
00271f77 426 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_rdmem();
cbdcc89a 427
b98827ff 428 uint32_t offset = 0, len = 0, IV = 1;
ffa306de 429 sscanf(Cmd, "%x %x %x", &offset, &len, &IV);
52cf34c1 430
ffa306de 431 // OUT-OF-BOUNDS check
a3994421 432 if ( len + offset > MAX_LENGTH ) {
433 len = MAX_LENGTH - offset;
e1a0ed65 434 PrintAndLog("Out-of-bound, shorten len to %d (0x%02X)", len, len);
a3994421 435 }
ffa306de 436
b98827ff 437 if ( (IV & 0x7F) != IV ){
438 IV &= 0x7F;
439 PrintAndLog("Truncating IV to 7bits");
440 }
a3994421 441
b98827ff 442 if ( (IV & 1) == 0 ){
a3994421 443 IV |= 0x01;
b98827ff 444 PrintAndLog("LSB of IV must be SET");
445 }
ffa306de 446
ad5bc8cc 447 UsbCommand c = {CMD_READER_LEGIC_RF, {offset, len, IV}};
52cf34c1 448 clearCommandBuffer();
449 SendCommand(&c);
ad5bc8cc 450 UsbCommand resp;
1daa1226 451 if (WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
ad5bc8cc 452 uint8_t isOK = resp.arg[0] & 0xFF;
7a8db2f6 453 uint16_t readlen = resp.arg[1];
87342aad 454 if ( isOK ) {
c649c433 455
86087eba 456 uint8_t *data = malloc(readlen);
0b0b182f 457 if ( !data ){
458 PrintAndLog("Cannot allocate memory");
459 return 2;
460 }
86087eba 461
462 if ( readlen != len )
463 PrintAndLog("Fail, only managed to read 0x%02X bytes", readlen);
464
0b0b182f 465 // copy data from device
86087eba 466 GetEMLFromBigBuf(data, readlen, 0);
7a8db2f6 467 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2500)){
0b0b182f 468 PrintAndLog("Command execute timeout");
469 if ( data )
470 free(data);
471 return 1;
472 }
473
c15e07f1 474 PrintAndLog("\n ## | Data");
475 PrintAndLog("-----+-----");
86087eba 476 print_hex_break( data, readlen, 32);
c649c433 477 } else {
478 PrintAndLog("failed reading tag");
479 }
ad5bc8cc 480 } else {
481 PrintAndLog("command execution time out");
482 return 1;
483 }
52cf34c1 484 return 0;
41dab153 485}
3612a8a8 486
52cf34c1 487int CmdLegicLoad(const char *Cmd) {
e8fecd72 488
489// iceman: potential bug, where all filepaths or filename which starts with H or h will print the helptext :)
52cf34c1 490 char cmdp = param_getchar(Cmd, 0);
e579e768 491 if ( cmdp == 'H' || cmdp == 'h' || cmdp == 0x00) return usage_legic_load();
b915fda3 492
e579e768 493 char filename[FILE_PATH_SIZE] = {0x00};
494 int len = strlen(Cmd);
495
b915fda3 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");
3612a8a8 503 if(!f) {
504 PrintAndLog("couldn't open '%s'", Cmd);
505 return -1;
506 }
52cf34c1 507
508 char line[80];
810f5379 509 int offset = 0;
c6e0a2eb 510 uint8_t data[USB_CMD_DATA_SIZE] = {0x00};
511 int index = 0;
512 int totalbytes = 0;
52cf34c1 513 while ( fgets(line, sizeof(line), f) ) {
3612a8a8 514 int res = sscanf(line, "%x %x %x %x %x %x %x %x",
c6e0a2eb 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]);
e7d099dc 523
3612a8a8 524 if(res != 8) {
525 PrintAndLog("Error: could not read samples");
526 fclose(f);
527 return -1;
528 }
c6e0a2eb 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);
d7fd9084 537 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 1500)){
538 PrintAndLog("Command execute timeout");
539 fclose(f);
540 return 1;
541 }
c6e0a2eb 542 offset += index;
543 totalbytes += index;
544 index = 0;
545 }
3612a8a8 546 }
547 fclose(f);
c6e0a2eb 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);
d7fd9084 555 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 1500)){
556 PrintAndLog("Command execute timeout");
557 return 1;
558 }
c6e0a2eb 559 totalbytes += index;
560 }
561
562 PrintAndLog("loaded %u samples", totalbytes);
3612a8a8 563 return 0;
564}
565
52cf34c1 566int CmdLegicSave(const char *Cmd) {
567 int requested = 1024;
568 int offset = 0;
569 int delivered = 0;
e8fecd72 570 char filename[FILE_PATH_SIZE] = {0x00};
52cf34c1 571 uint8_t got[1024] = {0x00};
572
e8fecd72 573 memset(filename, 0, FILE_PATH_SIZE);
574
52cf34c1 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 */
e7d099dc 579 if (requested == 0)
52cf34c1 580 requested = 1024;
52cf34c1 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
d7fd9084 592 GetFromBigBuf(got, requested, offset);
f7f844d0 593 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2000)){
aacb96d7 594 PrintAndLog("Command execute timeout");
f7f844d0 595 return 1;
596 }
52cf34c1 597
aacb96d7 598 FILE *f = fopen(filename, "w");
599 if(!f) {
600 PrintAndLog("couldn't open '%s'", Cmd+1);
601 return -1;
602 }
603
52cf34c1 604 for (int j = 0; j < requested; j += 8) {
605 fprintf(f, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
c6e0a2eb 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]
52cf34c1 608 );
609 delivered += 8;
610 if (delivered >= requested) break;
611 }
612
613 fclose(f);
614 PrintAndLog("saved %u samples", delivered);
615 return 0;
3612a8a8 616}
617
f7f844d0 618//TODO: write a help text (iceman)
52cf34c1 619int CmdLegicRfSim(const char *Cmd) {
3b920280 620 UsbCommand c = {CMD_SIMULATE_TAG_LEGIC_RF, {6,3,0}};
52cf34c1 621 sscanf(Cmd, " %"lli" %"lli" %"lli, &c.arg[0], &c.arg[1], &c.arg[2]);
622 clearCommandBuffer();
623 SendCommand(&c);
624 return 0;
3612a8a8 625}
626
52cf34c1 627int CmdLegicRfWrite(const char *Cmd) {
ffa306de 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
b98827ff 637 uint32_t offset = 0, len = 0, IV = 0;
ffa306de 638
ffa306de 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");
3612a8a8 642 return -1;
643 }
ffa306de 644
645 // OUT-OF-BOUNDS check
7bc3c99e 646 if ( len + offset > MAX_LENGTH ) {
647 len = MAX_LENGTH - offset;
e1a0ed65 648 PrintAndLog("Out-of-bound, shorten len to %d (0x%02X)", len, len);
7bc3c99e 649 }
b98827ff 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 }
ffa306de 658
7bc3c99e 659 UsbCommand c = {CMD_WRITER_LEGIC_RF, {offset, len, IV}};
52cf34c1 660 clearCommandBuffer();
3612a8a8 661 SendCommand(&c);
7bc3c99e 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
3612a8a8 674 return 0;
675}
676
3e134b4c 677int CmdLegicRfRawWrite(const char *Cmd) {
ffa306de 678
679 char cmdp = param_getchar(Cmd, 0);
680 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_rawwrite();
681
86087eba 682 uint32_t offset = 0, data = 0, IV = 0;
3e134b4c 683 char answer;
ffa306de 684
86087eba 685 int res = sscanf(Cmd, "%x %x %x", &offset, &data, &IV);
ffa306de 686 if(res < 2)
687 return usage_legic_rawwrite();
86087eba 688
ffa306de 689 // OUT-OF-BOUNDS check
86087eba 690 if ( offset > MAX_LENGTH ) {
7a8db2f6 691 PrintAndLog("Out-of-bound, offset");
692 return 1;
86087eba 693 }
ffa306de 694
b98827ff 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 }
ffa306de 703
86087eba 704 UsbCommand c = { CMD_RAW_WRITER_LEGIC_RF, {offset, data, IV} };
3e134b4c 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)");
6e321dd8 711 if (scanf(" %c", &answer) > 0 && (answer == 'y' || answer == 'Y')) {
3e134b4c 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)
52cf34c1 724int CmdLegicRfFill(const char *Cmd) {
3e134b4c 725 UsbCommand cmd = {CMD_WRITER_LEGIC_RF, {0,0,0} };
1a07fd51 726 int res = sscanf(Cmd, " 0x%"llx" 0x%"llx" 0x%"llx, &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]);
3612a8a8 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;
52cf34c1 733 UsbCommand c = {CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 0, 0}};
ba4ad25b 734 memset(c.d.asBytes, cmd.arg[2], 48);
3e134b4c 735
52cf34c1 736 for(i = 0; i < 22; i++) {
737 c.arg[0] = i*48;
3e134b4c 738
739 clearCommandBuffer();
52cf34c1 740 SendCommand(&c);
3e134b4c 741 WaitForResponse(CMD_ACK, NULL);
52cf34c1 742 }
743 clearCommandBuffer();
3612a8a8 744 SendCommand(&cmd);
745 return 0;
746 }
747
87342aad 748void 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);
f1f7430a 763 printf("crc4 %X\n", crc_finish(&crc) ) ;
87342aad 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);
f1f7430a 776 printf("crc4 %X\n", crc_finish(&crc) ) ;
87342aad 777}
778
3b920280 779int CmdLegicCalcCrc8(const char *Cmd){
780
cc4c8fd6 781 uint8_t *data = NULL;
3e134b4c 782 uint8_t cmdp = 0, uidcrc = 0, type=0;
783 bool errors = false;
784 int len = 0;
e31a0f73 785 int bg, en;
3b920280 786
3e134b4c 787 while(param_getchar(Cmd, cmdp) != 0x00) {
788 switch(param_getchar(Cmd, cmdp)) {
789 case 'b':
790 case 'B':
e31a0f73
AG
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;
987c5984
AG
794 if (param_getptr(Cmd, &bg, &en, cmdp+1)) {
795 errors = true;
796 break;
797 }
e31a0f73
AG
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
08927081
AG
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);
e31a0f73 810 data = malloc(len >> 1);
3e134b4c 811 if ( data == NULL ) {
812 PrintAndLog("Can't allocate memory. exiting");
813 errors = true;
814 break;
e31a0f73
AG
815 }
816
987c5984
AG
817 if (param_gethex(Cmd, cmdp+1, data, len)) {
818 errors = true;
819 break;
820 }
3e134b4c 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){
aeb128e2 848 if (data) free(data);
3e134b4c 849 return usage_legic_calccrc8();
850 }
851
852 switch (type){
853 case 16:
87342aad 854 PrintAndLog("Legic crc16: %X", CRC16Legic(data, len, uidcrc));
855 break;
856 case 4:
857 calc4(data, 0);
3e134b4c 858 break;
859 default:
87342aad 860 PrintAndLog("Legic crc8: %X", CRC8Legic(data, len) );
3e134b4c 861 break;
eb5206bd 862 }
3b920280 863
aeb128e2 864 if (data) free(data);
3b920280 865 return 0;
866}
867
633d0686 868int HFLegicReader(const char *Cmd, bool verbose) {
3e750be3 869
870 char cmdp = param_getchar(Cmd, 0);
871 if ( cmdp == 'H' || cmdp == 'h' ) return usage_legic_info();
872
873 UsbCommand c = {CMD_LEGIC_INFO, {0,0,0}};
874 clearCommandBuffer();
875 SendCommand(&c);
876 UsbCommand resp;
a3994421 877 if (!WaitForResponseTimeout(CMD_ACK, &resp, 500)) {
323e05cc 878 if ( verbose ) PrintAndLog("command execution time out");
3e750be3 879 return 1;
880 }
a3994421 881
882 uint8_t isOK = resp.arg[0] & 0xFF;
883 if ( !isOK ) {
884 if ( verbose ) PrintAndLog("legic card select failed");
885 return 1;
886 }
887
888 legic_card_select_t card;
889 memcpy(&card, (legic_card_select_t *)resp.d.asBytes, sizeof(legic_card_select_t));
890
891 PrintAndLog(" UID : %s", sprint_hex(card.uid, sizeof(card.uid)));
892 switch(card.cardsize) {
893 case 22:
894 case 256:
895 case 1024:
896 PrintAndLog(" TYPE : MIM%d card (%d bytes)", card.cardsize, card.cardsize); break;
897 default: {
898 PrintAndLog("Unknown card format: %d", card.cardsize);
899 return 1;
900 }
901 }
3e750be3 902 return 0;
903}
633d0686 904int CmdLegicReader(const char *Cmd){
905 return HFLegicReader(Cmd, TRUE);
3e750be3 906}
633d0686 907
908int CmdLegicDump(const char *Cmd){
00271f77 909
910 FILE *fout;
911 char filename[FILE_PATH_SIZE] = {0x00};
912 char *fnameptr = filename;
913 size_t fileNlen = 0;
914 bool errors = false;
915 uint16_t dumplen = 0x100;
916
633d0686 917 char cmdp = param_getchar(Cmd, 0);
00271f77 918
919 while(param_getchar(Cmd, cmdp) != 0x00)
920 {
921 switch(param_getchar(Cmd, cmdp))
922 {
923 case 'h':
924 case 'H':
925 return usage_legic_dump();
926 case 'o':
927 case 'O':
928 fileNlen = param_getstr(Cmd, cmdp+1, filename);
929 if (!fileNlen) errors = true;
930 if (fileNlen > FILE_PATH_SIZE-5) fileNlen = FILE_PATH_SIZE-5;
931 cmdp += 2;
932 break;
933 default:
934 PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
935 errors = true;
936 break;
937 }
938 if(errors) break;
939 }
940
941 //Validations
942 if(errors) return usage_legic_dump();
943
944 // tagtype
945 //uint32_t tagtype = GetHF14AMfU_Type();
946 //if (tagtype == -1) return -1;
947
948 UsbCommand c = {CMD_READER_LEGIC_RF, {0x00, dumplen, 0x55}};
949 clearCommandBuffer();
950 SendCommand(&c);
951 UsbCommand resp;
952 if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
953 PrintAndLog("Command execute time-out");
954 return 1;
955 }
956
957 uint8_t isOK = resp.arg[0] & 0xFF;
958 if ( !isOK ) {
959 PrintAndLog("Failed dumping tag data");
960 return 2;
961 }
962
963 uint16_t readlen = resp.arg[1];
964 uint8_t *data = malloc(readlen);
965 if ( !data ){
966 PrintAndLog("Fail, cannot allocate memory");
967 return 3;
968 }
969
970 if ( readlen != dumplen )
971 PrintAndLog("Fail, only managed to read 0x%02X bytes of 0x%02X", readlen, dumplen);
972
973 // copy data from device
974 GetEMLFromBigBuf(data, readlen, 0);
975 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2500)) {
976 PrintAndLog("Fail, transfer from device time-out");
977 if ( data ) free(data);
978 return 4;
979 }
980
981 // user supplied filename?
982 if (fileNlen < 1)
983 sprintf(fnameptr,"%02X%02X%02X%02X.bin", data[0], data[1], data[2], data[3]);
984 else
985 sprintf(fnameptr + fileNlen,".bin");
986
987 if ((fout = fopen(filename,"wb")) == NULL) {
988 PrintAndLog("Could not create file name %s", filename);
989 if ( data ) free(data);
990 return 5;
991 }
992 fwrite( data, 1, readlen, fout );
993 fclose(fout);
994 if ( data ) free(data);
995
996 PrintAndLog("Wrote %d bytes to %s", readlen, filename);
633d0686 997 return 0;
998}
3e750be3 999
52cf34c1 1000static command_t CommandTable[] = {
633d0686 1001 {"help", CmdHelp, 1, "This help"},
1002 {"reader", CmdLegicReader, 1, "LEGIC Prime Reader UID and Type tag info"},
1003 {"info", CmdLegicInfo, 0, "Display deobfuscated and decoded LEGIC Prime tag data"},
1004 {"dump", CmdLegicDump, 0, "Dump LEGIC Prime card to binary file"},
00271f77 1005 {"rdmem", CmdLegicRdmem, 0, "[offset][length] <iv> -- read bytes from a LEGIC card"},
633d0686 1006 {"save", CmdLegicSave, 0, "<filename> [<length>] -- Store samples"},
1007 {"load", CmdLegicLoad, 0, "<filename> -- Restore samples"},
1008 {"sim", CmdLegicRfSim, 0, "[phase drift [frame drift [req/resp drift]]] Start tag simulator (use after load or read)"},
1009 {"write", CmdLegicRfWrite, 0, "<offset> <length> <iv> -- Write sample buffer (user after load or read)"},
ffa306de 1010 {"writeraw",CmdLegicRfRawWrite, 0, "<address> <value> <iv> -- Write direct to address"},
633d0686 1011 {"fill", CmdLegicRfFill, 0, "<offset> <length> <value> -- Fill/Write tag with constant value"},
1012 {"crc8", CmdLegicCalcCrc8, 1, "Calculate Legic CRC8 over given hexbytes"},
52cf34c1 1013 {NULL, NULL, 0, NULL}
1014};
1015
1016int CmdHFLegic(const char *Cmd) {
1017 clearCommandBuffer();
1018 CmdsParse(CommandTable, Cmd);
1019 return 0;
1020}
1021
1022int CmdHelp(const char *Cmd) {
1023 CmdsHelp(CommandTable);
1024 return 0;
1025}
Impressum, Datenschutz