]> cvs.zerfleddert.de Git - proxmark3-svn/blame_incremental - client/cmdhficlass.c
CHG: the mifare Auth command can make use of a random nonce aswell.
[proxmark3-svn] / client / cmdhficlass.c
... / ...
CommitLineData
1//-----------------------------------------------------------------------------
2// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch
3// Copyright (C) 2011 Gerhard de Koning Gans
4// Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende
5//
6// This code is licensed to you under the terms of the GNU GPL, version 2 or,
7// at your option, any later version. See the LICENSE.txt file for the text of
8// the license.
9//-----------------------------------------------------------------------------
10// High frequency iClass commands
11//-----------------------------------------------------------------------------
12
13#include "cmdhficlass.h"
14
15static int CmdHelp(const char *Cmd);
16
17#define NUM_CSNS 15
18#define ICLASS_KEYS_MAX 8
19static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][8] = {
20 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
21 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
22 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
23 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
24 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
25 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
26 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
27 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
28};
29
30typedef struct iclass_block {
31 uint8_t d[8];
32} iclass_block_t;
33
34int usage_hf_iclass_sim(void) {
35 PrintAndLog("Usage: hf iclass sim <option> [CSN]");
36 PrintAndLog(" options");
37 PrintAndLog(" 0 <CSN> simulate the given CSN");
38 PrintAndLog(" 1 simulate default CSN");
39 PrintAndLog(" 2 Reader-attack, gather reader responses to extract elite key");
40 PrintAndLog(" 3 Full simulation using emulator memory (see 'hf iclass eload')");
41 PrintAndLog(" example: hf iclass sim 0 031FEC8AF7FF12E0");
42 PrintAndLog(" example: hf iclass sim 2");
43 PrintAndLog(" example: hf iclass eload 'tagdump.bin'");
44 PrintAndLog(" hf iclass sim 3");
45 return 0;
46}
47int usage_hf_iclass_eload(void) {
48 PrintAndLog("Loads iclass tag-dump into emulator memory on device");
49 PrintAndLog("Usage: hf iclass eload f <filename>");
50 PrintAndLog("");
51 PrintAndLog("Example: hf iclass eload f iclass_tagdump-aa162d30f8ff12f1.bin");
52 return 0;
53}
54int usage_hf_iclass_decrypt(void) {
55 PrintAndLog("Usage: hf iclass decrypt f <tagdump>");
56 PrintAndLog("");
57 PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside");
58 PrintAndLog("in the working directory. The file should be 16 bytes binary data");
59 PrintAndLog("");
60 PrintAndLog("example: hf iclass decrypt f tagdump_12312342343.bin");
61 PrintAndLog("");
62 PrintAndLog("OBS! This is pretty stupid implementation, it tries to decrypt every block after block 6. ");
63 PrintAndLog("Correct behaviour would be to decrypt only the application areas where the key is valid,");
64 PrintAndLog("which is defined by the configuration block.");
65 return 1;
66}
67int usage_hf_iclass_encrypt(void) {
68 PrintAndLog("Usage: hf iclass encrypt <BlockData>");
69 PrintAndLog("");
70 PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside");
71 PrintAndLog("in the working directory. The file should be 16 bytes binary data");
72 PrintAndLog("");
73 PrintAndLog("example: hf iclass encrypt 0102030405060708");
74 PrintAndLog("");
75 return 0;
76}
77int usage_hf_iclass_dump(void) {
78 PrintAndLog("Usage: hf iclass dump f <fileName> k <Key> c <CreditKey> e|r\n");
79 PrintAndLog("Options:");
80 PrintAndLog(" f <filename> : specify a filename to save dump to");
81 PrintAndLog(" k <Key> : *Access Key as 16 hex symbols or 1 hex to select key from memory");
82 PrintAndLog(" c <CreditKey>: Credit Key as 16 hex symbols or 1 hex to select key from memory");
83 PrintAndLog(" e : If 'e' is specified, the key is interpreted as the 16 byte");
84 PrintAndLog(" Custom Key (KCus), which can be obtained via reader-attack");
85 PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format");
86 PrintAndLog(" r : If 'r' is specified, the key is interpreted as raw block 3/4");
87 PrintAndLog(" NOTE: * = required");
88 PrintAndLog("Samples:");
89 PrintAndLog(" hf iclass dump k 001122334455667B");
90 PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA c 001122334455667B");
91 PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA e");
92 return 0;
93}
94int usage_hf_iclass_clone(void) {
95 PrintAndLog("Usage: hf iclass clone f <tagfile.bin> b <first block> l <last block> k <KEY> c e|r");
96 PrintAndLog("Options:");
97 PrintAndLog(" f <filename>: specify a filename to clone from");
98 PrintAndLog(" b <Block> : The first block to clone as 2 hex symbols");
99 PrintAndLog(" l <Last Blk>: Set the Data to write as 16 hex symbols");
100 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
101 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
102 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
103 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
104 PrintAndLog("Samples:");
105 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 1A k 1122334455667788 e");
106 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 05 l 19 k 0");
107 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 19 k 0 e");
108 return -1;
109}
110int usage_hf_iclass_writeblock(void) {
111 PrintAndLog("Options:");
112 PrintAndLog(" b <Block> : The block number as 2 hex symbols");
113 PrintAndLog(" d <data> : Set the Data to write as 16 hex symbols");
114 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
115 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
116 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
117 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
118 PrintAndLog("Samples:");
119 PrintAndLog(" hf iclass writeblk b 0A d AAAAAAAAAAAAAAAA k 001122334455667B");
120 PrintAndLog(" hf iclass writeblk b 1B d AAAAAAAAAAAAAAAA k 001122334455667B c");
121 PrintAndLog(" hf iclass writeblk b 0A d AAAAAAAAAAAAAAAA n 0");
122 return 0;
123}
124int usage_hf_iclass_readblock(void) {
125 PrintAndLog("Usage: hf iclass readblk b <Block> k <Key> c e|r\n");
126 PrintAndLog("Options:");
127 PrintAndLog(" b <Block> : The block number as 2 hex symbols");
128 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
129 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
130 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
131 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
132 PrintAndLog("Samples:");
133 PrintAndLog(" hf iclass readblk b 06 k 0011223344556677");
134 PrintAndLog(" hf iclass readblk b 1B k 0011223344556677 c");
135 PrintAndLog(" hf iclass readblk b 0A k 0");
136 return 0;
137}
138int usage_hf_iclass_readtagfile() {
139 PrintAndLog("Usage: hf iclass readtagfile <filename> [startblock] [endblock]");
140 return 1;
141}
142int usage_hf_iclass_calc_newkey(void) {
143 PrintAndLog("HELP : Manage iClass Keys in client memory:\n");
144 PrintAndLog("Usage: hf iclass calc_newkey o <Old key> n <New key> s [csn] e");
145 PrintAndLog(" Options:");
146 PrintAndLog(" o <oldkey> : *specify a key as 16 hex symbols or a key number as 1 symbol");
147 PrintAndLog(" n <newkey> : *specify a key as 16 hex symbols or a key number as 1 symbol");
148 PrintAndLog(" s <csn> : specify a card Serial number to diversify the key (if omitted will attempt to read a csn)");
149 PrintAndLog(" e : specify new key as elite calc");
150 PrintAndLog(" ee : specify old and new key as elite calc");
151 PrintAndLog("Samples:");
152 PrintAndLog(" e key to e key given csn : hf iclass calcnewkey o 1122334455667788 n 2233445566778899 s deadbeafdeadbeaf ee");
153 PrintAndLog(" std key to e key read csn: hf iclass calcnewkey o 1122334455667788 n 2233445566778899 e");
154 PrintAndLog(" std to std read csn : hf iclass calcnewkey o 1122334455667788 n 2233445566778899");
155 PrintAndLog("NOTE: * = required\n");
156 return 1;
157}
158int usage_hf_iclass_managekeys(void) {
159 PrintAndLog("HELP : Manage iClass Keys in client memory:\n");
160 PrintAndLog("Usage: hf iclass managekeys n [keynbr] k [key] f [filename] s l p\n");
161 PrintAndLog(" Options:");
162 PrintAndLog(" n <keynbr> : specify the keyNbr to set in memory");
163 PrintAndLog(" k <key> : set a key in memory");
164 PrintAndLog(" f <filename>: specify a filename to use with load or save operations");
165 PrintAndLog(" s : save keys in memory to file specified by filename");
166 PrintAndLog(" l : load keys to memory from file specified by filename");
167 PrintAndLog(" p : print keys loaded into memory\n");
168 PrintAndLog("Samples:");
169 PrintAndLog(" set key : hf iclass managekeys n 0 k 1122334455667788");
170 PrintAndLog(" save key file: hf iclass managekeys f mykeys.bin s");
171 PrintAndLog(" load key file: hf iclass managekeys f mykeys.bin l");
172 PrintAndLog(" print keys : hf iclass managekeys p\n");
173 return 0;
174}
175int usage_hf_iclass_reader(void) {
176 PrintAndLog("HELP : Act as a Iclass reader:\n");
177 PrintAndLog("Usage: hf iclass reader [h] [1]\n");
178 PrintAndLog("Options:");
179 PrintAndLog(" h This help text");
180 PrintAndLog(" 1 read only 1 tag");
181 PrintAndLog("Samples:");
182 PrintAndLog(" hf iclass reader 1");
183 return 0;
184}
185int usage_hf_iclass_replay(void){
186 PrintAndLog("HELP: Replay a collected mac message");
187 PrintAndLog("Usage: hf iclass replay [h] <mac>");
188 PrintAndLog("Options:");
189 PrintAndLog(" h This help text");
190 PrintAndLog(" <mac> Mac bytes to replay (8 hexsymbols)");
191 PrintAndLog("Samples:");
192 PrintAndLog(" hf iclass replay 00112233");
193 return 0;
194}
195int usage_hf_iclass_snoop(void){
196 PrintAndLog("HELP: Snoops the communication between reader and tag");
197 PrintAndLog("Usage: hf iclass snoop [h]");
198 PrintAndLog("Samples:");
199 PrintAndLog(" hf iclass snoop");
200 return 0;
201}
202int xorbits_8(uint8_t val) {
203 uint8_t res = val ^ (val >> 1); //1st pass
204 res = res ^ (res >> 1); // 2nd pass
205 res = res ^ (res >> 2); // 3rd pass
206 res = res ^ (res >> 4); // 4th pass
207 return res & 1;
208}
209
210int CmdHFiClassList(const char *Cmd) {
211 //PrintAndLog("Deprecated command, use 'hf list iclass' instead");
212 CmdHFList("iclass");
213 return 0;
214}
215
216int CmdHFiClassSnoop(const char *Cmd) {
217 char cmdp = param_getchar(Cmd, 0);
218 if (cmdp == 'h' || cmdp == 'H') return usage_hf_iclass_snoop();
219
220 UsbCommand c = {CMD_SNOOP_ICLASS};
221 SendCommand(&c);
222 return 0;
223}
224
225int CmdHFiClassSim(const char *Cmd) {
226 uint8_t simType = 0;
227 uint8_t CSN[8] = {0, 0, 0, 0, 0, 0, 0, 0};
228
229 if (strlen(Cmd)<1) return usage_hf_iclass_sim();
230
231 simType = param_get8ex(Cmd, 0, 0, 10);
232
233 if(simType == 0)
234 {
235 if (param_gethex(Cmd, 1, CSN, 16)) {
236 PrintAndLog("A CSN should consist of 16 HEX symbols");
237 return usage_hf_iclass_sim();
238 }
239
240 PrintAndLog("--simtype:%02x csn:%s", simType, sprint_hex(CSN, 8));
241 }
242
243 if(simType > 3)
244 {
245 PrintAndLog("Undefined simptype %d", simType);
246 return usage_hf_iclass_sim();
247 }
248
249 uint8_t numberOfCSNs=0;
250 if(simType == 2)
251 {
252 UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType,NUM_CSNS}};
253 UsbCommand resp = {0};
254
255 uint8_t csns[8*NUM_CSNS] = {
256 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
257 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0,
258 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0,
259 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0,
260 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0,
261 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0,
262 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0,
263 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0,
264 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0,
265 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0,
266 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0,
267 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0,
268 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0,
269 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0,
270 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 };
271
272 memcpy(c.d.asBytes, csns, 8*NUM_CSNS);
273 clearCommandBuffer();
274 SendCommand(&c);
275 if (!WaitForResponseTimeout(CMD_ACK, &resp, -1)) {
276 PrintAndLog("Command timed out");
277 return 0;
278 }
279
280 uint8_t num_mac_responses = resp.arg[1];
281 PrintAndLog("Mac responses: %d MACs obtained (should be %d)", num_mac_responses,NUM_CSNS);
282
283 size_t datalen = NUM_CSNS*24;
284 /*
285 * Now, time to dump to file. We'll use this format:
286 * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
287 * So, it should wind up as
288 * 8 * 24 bytes.
289 *
290 * The returndata from the pm3 is on the following format
291 * <4 byte NR><4 byte MAC>
292 * CC are all zeroes, CSN is the same as was sent in
293 **/
294 void* dump = malloc(datalen);
295 memset(dump,0,datalen);//<-- Need zeroes for the CC-field
296 uint8_t i = 0;
297 for(i = 0 ; i < NUM_CSNS ; i++) {
298 memcpy(dump+i*24, csns+i*8, 8); //CSN
299 //8 zero bytes here...
300 //Then comes NR_MAC (eight bytes from the response)
301 memcpy(dump+i*24+16, resp.d.asBytes+i*8, 8);
302 }
303 /** Now, save to dumpfile **/
304 saveFile("iclass_mac_attack", "bin", dump, datalen);
305 free(dump);
306 } else {
307 UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType,numberOfCSNs}};
308 memcpy(c.d.asBytes, CSN, 8);
309 clearCommandBuffer();
310 SendCommand(&c);
311 }
312 return 0;
313}
314
315int HFiClassReader(const char *Cmd, bool loop, bool verbose) {
316 bool tagFound = false;
317 UsbCommand c = {CMD_READER_ICLASS, {FLAG_ICLASS_READER_CSN |
318 FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_AA}};
319 // loop in client not device - else on windows have a communication error
320 c.arg[0] |= FLAG_ICLASS_READER_ONLY_ONCE | FLAG_ICLASS_READER_ONE_TRY;
321 UsbCommand resp;
322 while(!ukbhit()){
323 clearCommandBuffer();
324 SendCommand(&c);
325 if (WaitForResponseTimeout(CMD_ACK,&resp, 4500)) {
326 uint8_t readStatus = resp.arg[0] & 0xff;
327 uint8_t *data = resp.d.asBytes;
328
329 if (verbose) PrintAndLog("Readstatus:%02x", readStatus);
330 if( readStatus == 0){
331 //Aborted
332 if (verbose) PrintAndLog("Quitting...");
333 return 0;
334 }
335 if( readStatus & FLAG_ICLASS_READER_CSN){
336 PrintAndLog("CSN: %s",sprint_hex(data,8));
337 tagFound = true;
338 }
339 if( readStatus & FLAG_ICLASS_READER_CC) PrintAndLog("CC: %s", sprint_hex(data+16, 8));
340 if( readStatus & FLAG_ICLASS_READER_CONF) printIclassDumpInfo(data);
341 if (tagFound && !loop) return 1;
342 } else {
343 if (verbose) PrintAndLog("Command execute timeout");
344 }
345 if (!loop) break;
346 }
347 return 0;
348}
349
350int CmdHFiClassReader(const char *Cmd) {
351 char cmdp = param_getchar(Cmd, 0);
352 if (cmdp == 'h' || cmdp == 'H') return usage_hf_iclass_reader();
353 bool findone = (cmdp == '1') ? FALSE : TRUE;
354 return HFiClassReader(Cmd, findone, true);
355}
356
357int CmdHFiClassReader_Replay(const char *Cmd) {
358 uint8_t readerType = 0;
359 uint8_t MAC[4]={0x00, 0x00, 0x00, 0x00};
360
361 if (strlen(Cmd)<1) return usage_hf_iclass_replay();
362
363 if (param_gethex(Cmd, 0, MAC, 8)) {
364 PrintAndLog("MAC must include 8 HEX symbols");
365 return 1;
366 }
367
368 UsbCommand c = {CMD_READER_ICLASS_REPLAY, {readerType}};
369 memcpy(c.d.asBytes, MAC, 4);
370 clearCommandBuffer();
371 SendCommand(&c);
372 return 0;
373}
374
375int iclassEmlSetMem(uint8_t *data, int blockNum, int blocksCount) {
376 UsbCommand c = {CMD_MIFARE_EML_MEMSET, {blockNum, blocksCount, 0}};
377 memcpy(c.d.asBytes, data, blocksCount * 16);
378 clearCommandBuffer();
379 SendCommand(&c);
380 return 0;
381}
382
383int CmdHFiClassELoad(const char *Cmd) {
384
385 char opt = param_getchar(Cmd, 0);
386 if (strlen(Cmd)<1 || opt == 'h' || opt == 'H') return usage_hf_iclass_eload();
387
388 //File handling and reading
389 FILE *f;
390 char filename[FILE_PATH_SIZE];
391 if(opt == 'f' && param_getstr(Cmd, 1, filename) > 0) {
392 f = fopen(filename, "rb");
393 } else {
394 return usage_hf_iclass_eload();
395 }
396
397 if(!f) {
398 PrintAndLog("Failed to read from file '%s'", filename);
399 return 1;
400 }
401
402 fseek(f, 0, SEEK_END);
403 long fsize = ftell(f);
404 fseek(f, 0, SEEK_SET);
405
406 if (fsize < 0) {
407 prnlog("Error, when getting filesize");
408 fclose(f);
409 return 1;
410 }
411
412 uint8_t *dump = malloc(fsize);
413
414 size_t bytes_read = fread(dump, 1, fsize, f);
415 fclose(f);
416
417 printIclassDumpInfo(dump);
418 //Validate
419
420 if (bytes_read < fsize) {
421 prnlog("Error, could only read %d bytes (should be %d)",bytes_read, fsize );
422 free(dump);
423 return 1;
424 }
425 //Send to device
426 uint32_t bytes_sent = 0;
427 uint32_t bytes_remaining = bytes_read;
428
429 while(bytes_remaining > 0){
430 uint32_t bytes_in_packet = MIN(USB_CMD_DATA_SIZE, bytes_remaining);
431 UsbCommand c = {CMD_ICLASS_EML_MEMSET, {bytes_sent,bytes_in_packet,0}};
432 memcpy(c.d.asBytes, dump, bytes_in_packet);
433 clearCommandBuffer();
434 SendCommand(&c);
435 bytes_remaining -= bytes_in_packet;
436 bytes_sent += bytes_in_packet;
437 }
438 free(dump);
439 PrintAndLog("Sent %d bytes of data to device emulator memory", bytes_sent);
440 return 0;
441}
442
443static int readKeyfile(const char *filename, size_t len, uint8_t* buffer) {
444 FILE *f = fopen(filename, "rb");
445 if(!f) {
446 PrintAndLog("Failed to read from file '%s'", filename);
447 return 1;
448 }
449 fseek(f, 0, SEEK_END);
450 long fsize = ftell(f);
451 fseek(f, 0, SEEK_SET);
452 size_t bytes_read = fread(buffer, 1, len, f);
453 fclose(f);
454
455 if(fsize != len) {
456 PrintAndLog("Warning, file size is %d, expected %d", fsize, len);
457 return 1;
458 }
459
460 if(bytes_read != len) {
461 PrintAndLog("Warning, could only read %d bytes, expected %d" ,bytes_read, len);
462 return 1;
463 }
464 return 0;
465}
466
467int CmdHFiClassDecrypt(const char *Cmd) {
468
469 char opt = param_getchar(Cmd, 0);
470 if (strlen(Cmd)<1 || opt == 'h' || opt == 'H') return usage_hf_iclass_decrypt();
471
472 uint8_t key[16] = { 0 };
473 if(readKeyfile("iclass_decryptionkey.bin", 16, key)) return usage_hf_iclass_decrypt();
474
475 PrintAndLog("Decryption key loaded from file [ok]");
476
477 //Open the tagdump-file
478 FILE *f;
479 char filename[FILE_PATH_SIZE];
480 if(opt == 'f' && param_getstr(Cmd, 1, filename) > 0) {
481 f = fopen(filename, "rb");
482 if (!f) {
483 PrintAndLog("Could not find file %s", filename);
484 return 1;
485 }
486 } else {
487 return usage_hf_iclass_decrypt();
488 }
489
490 fseek(f, 0, SEEK_END);
491 long fsize = ftell(f);
492 fseek(f, 0, SEEK_SET);
493
494 if ( fsize < 0 ) {
495 PrintAndLog("Error, when getting filesize");
496 fclose(f);
497 return 2;
498 }
499
500 uint8_t *decrypted = malloc(fsize);
501
502 size_t bytes_read = fread(decrypted, 1, fsize, f);
503 fclose(f);
504 if ( bytes_read == 0) {
505 PrintAndLog("File reading error");
506 free(decrypted);
507 return 3;
508 }
509
510 picopass_hdr *hdr = (picopass_hdr *)decrypted;
511
512 uint8_t mem = hdr->conf.mem_config;
513 uint8_t chip = hdr->conf.chip_config;
514 uint8_t applimit = hdr->conf.app_limit;
515 uint8_t kb = 2;
516 uint8_t app_areas = 2;
517 uint8_t max_blk = 31;
518 getMemConfig(mem, chip, &max_blk, &app_areas, &kb);
519
520 //Use the first block (CSN) for filename
521 char outfilename[FILE_PATH_SIZE] = {0};
522 snprintf(outfilename, FILE_PATH_SIZE, "iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x-decrypted",
523 hdr->csn[0],hdr->csn[1],hdr->csn[2],hdr->csn[3],
524 hdr->csn[4],hdr->csn[5],hdr->csn[6],hdr->csn[7]);
525
526 // tripledes
527 des3_context ctx = { DES_DECRYPT ,{ 0 } };
528 des3_set2key_dec( &ctx, key);
529
530 uint8_t enc_dump[8] = {0};
531 uint8_t empty[8] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
532 for(uint16_t blocknum=0; blocknum < applimit; ++blocknum) {
533
534 uint8_t idx = blocknum*8;
535 memcpy(enc_dump, decrypted + idx, 8);
536
537 // block 7 or higher, and not empty 0xFF
538 if(blocknum > 6 && memcmp(enc_dump, empty, 8) != 0 ) {
539 des3_crypt_ecb(&ctx, enc_dump, decrypted + idx );
540 }
541 //printvar("decrypted block", decrypted + idx, 8);
542 }
543
544 saveFile(outfilename, "bin", decrypted, fsize);
545 free(decrypted);
546
547 printIclassDumpContents(decrypted, 1, (fsize/8), fsize);
548 return 0;
549}
550
551static int iClassEncryptBlkData(uint8_t *blkData) {
552 uint8_t key[16] = { 0 };
553 if(readKeyfile("iclass_decryptionkey.bin", 16, key)) {
554 usage_hf_iclass_encrypt();
555 return 1;
556 }
557 PrintAndLog("Decryption file found... ");
558 uint8_t encryptedData[16];
559 uint8_t *encrypted = encryptedData;
560 des3_context ctx = { DES_DECRYPT ,{ 0 } };
561 des3_set2key_enc( &ctx, key);
562
563 des3_crypt_ecb(&ctx, blkData,encrypted);
564 //printvar("decrypted block", decrypted, 8);
565 memcpy(blkData,encrypted,8);
566
567 return 1;
568}
569
570int CmdHFiClassEncryptBlk(const char *Cmd) {
571 uint8_t blkData[8] = {0};
572 char opt = param_getchar(Cmd, 0);
573 if (strlen(Cmd)<1 || opt == 'h' || opt == 'H') return usage_hf_iclass_encrypt();
574
575 //get the bytes to encrypt
576 if (param_gethex(Cmd, 0, blkData, 16)) {
577 PrintAndLog("BlockData must include 16 HEX symbols");
578 return 0;
579 }
580 if (!iClassEncryptBlkData(blkData)) return 0;
581
582 printvar("encrypted block", blkData, 8);
583 return 1;
584}
585
586void Calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_t MAC[4]) {
587 uint8_t WB[9];
588 WB[0] = blockno;
589 memcpy(WB + 1,data,8);
590 doMAC_N(WB,sizeof(WB),div_key,MAC);
591 //printf("Cal wb mac block [%02x][%02x%02x%02x%02x%02x%02x%02x%02x] : MAC [%02x%02x%02x%02x]",WB[0],WB[1],WB[2],WB[3],WB[4],WB[5],WB[6],WB[7],WB[8],MAC[0],MAC[1],MAC[2],MAC[3]);
592}
593
594static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool verbose) {
595 UsbCommand resp;
596
597 UsbCommand c = {CMD_READER_ICLASS, {0}};
598 c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE | FLAG_ICLASS_READER_CC | FLAG_ICLASS_READER_ONE_TRY;
599 if (use_credit_key)
600 c.arg[0] |= FLAG_ICLASS_READER_CEDITKEY;
601
602 clearCommandBuffer();
603 SendCommand(&c);
604 if (!WaitForResponseTimeout(CMD_ACK,&resp,4500)) {
605 PrintAndLog("Command execute timeout");
606 return false;
607 }
608
609 uint8_t isOK = resp.arg[0] & 0xff;
610 uint8_t *data = resp.d.asBytes;
611
612 memcpy(CSN,data,8);
613
614 if (CCNR!=NULL)
615 memcpy(CCNR,data+16,8);
616
617 if(isOK > 0) {
618 if (verbose) PrintAndLog("CSN: %s",sprint_hex(CSN,8));
619 }
620
621 if(isOK <= 1){
622 PrintAndLog("Failed to obtain CC! Aborting");
623 return false;
624 }
625 return true;
626}
627
628static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool use_credit_key, bool elite, bool rawkey, bool verbose) {
629 uint8_t CSN[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
630 uint8_t CCNR[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
631
632 if (!select_only(CSN, CCNR, use_credit_key, verbose))
633 return false;
634
635 //get div_key
636 if(rawkey)
637 memcpy(div_key, KEY, 8);
638 else
639 HFiClassCalcDivKey(CSN, KEY, div_key, elite);
640
641 PrintAndLog("Authing with %s: %02x%02x%02x%02x%02x%02x%02x%02x", rawkey ? "raw key" : "diversified key", div_key[0],div_key[1],div_key[2],div_key[3],div_key[4],div_key[5],div_key[6],div_key[7]);
642
643 doMAC(CCNR, div_key, MAC);
644 UsbCommand resp;
645 UsbCommand d = {CMD_ICLASS_AUTHENTICATION, {0}};
646 memcpy(d.d.asBytes, MAC, 4);
647 clearCommandBuffer();
648 SendCommand(&d);
649 if (!WaitForResponseTimeout(CMD_ACK,&resp,4500)) {
650 PrintAndLog("Auth Command execute timeout");
651 return false;
652 }
653 uint8_t isOK = resp.arg[0] & 0xff;
654 if (!isOK) {
655 PrintAndLog("Authentication error");
656 return false;
657 }
658 return true;
659}
660
661int CmdHFiClassReader_Dump(const char *Cmd) {
662
663 uint8_t MAC[4] = {0x00,0x00,0x00,0x00};
664 uint8_t div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
665 uint8_t c_div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
666 uint8_t blockno = 0;
667 uint8_t numblks = 0;
668 uint8_t maxBlk = 31;
669 uint8_t app_areas = 1;
670 uint8_t kb = 2;
671 uint8_t KEY[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
672 uint8_t CreditKEY[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
673 uint8_t keyNbr = 0;
674 uint8_t dataLen = 0;
675 uint8_t fileNameLen = 0;
676 char filename[FILE_PATH_SIZE]={0};
677 char tempStr[50] = {0};
678 bool have_debit_key = false;
679 bool have_credit_key = false;
680 bool use_credit_key = false;
681 bool elite = false;
682 bool rawkey = false;
683 bool errors = false;
684 uint8_t cmdp = 0;
685
686 while(param_getchar(Cmd, cmdp) != 0x00)
687 {
688 switch(param_getchar(Cmd, cmdp))
689 {
690 case 'h':
691 case 'H':
692 return usage_hf_iclass_dump();
693 case 'c':
694 case 'C':
695 have_credit_key = true;
696 dataLen = param_getstr(Cmd, cmdp+1, tempStr);
697 if (dataLen == 16) {
698 errors = param_gethex(tempStr, 0, CreditKEY, dataLen);
699 } else if (dataLen == 1) {
700 keyNbr = param_get8(Cmd, cmdp+1);
701 if (keyNbr < ICLASS_KEYS_MAX) {
702 memcpy(CreditKEY, iClass_Key_Table[keyNbr], 8);
703 } else {
704 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
705 errors = true;
706 }
707 } else {
708 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
709 errors = true;
710 }
711 cmdp += 2;
712 break;
713 case 'e':
714 case 'E':
715 elite = true;
716 cmdp++;
717 break;
718 case 'f':
719 case 'F':
720 fileNameLen = param_getstr(Cmd, cmdp+1, filename);
721 if (fileNameLen < 1) {
722 PrintAndLog("No filename found after f");
723 errors = true;
724 }
725 cmdp += 2;
726 break;
727 case 'k':
728 case 'K':
729 have_debit_key = true;
730 dataLen = param_getstr(Cmd, cmdp+1, tempStr);
731 if (dataLen == 16) {
732 errors = param_gethex(tempStr, 0, KEY, dataLen);
733 } else if (dataLen == 1) {
734 keyNbr = param_get8(Cmd, cmdp+1);
735 if (keyNbr < ICLASS_KEYS_MAX) {
736 memcpy(KEY, iClass_Key_Table[keyNbr], 8);
737 } else {
738 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
739 errors = true;
740 }
741 } else {
742 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
743 errors = true;
744 }
745 cmdp += 2;
746 break;
747 case 'r':
748 case 'R':
749 rawkey = true;
750 cmdp++;
751 break;
752 default:
753 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
754 errors = true;
755 break;
756 }
757 if(errors) return usage_hf_iclass_dump();
758 }
759
760 if (cmdp < 2) return usage_hf_iclass_dump();
761 // if no debit key given try credit key on AA1 (not for iclass but for some picopass this will work)
762 if (!have_debit_key && have_credit_key) use_credit_key = true;
763
764 //get config and first 3 blocks
765 UsbCommand c = {CMD_READER_ICLASS, {FLAG_ICLASS_READER_CSN |
766 FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_ONLY_ONCE | FLAG_ICLASS_READER_ONE_TRY}};
767 UsbCommand resp;
768 uint8_t tag_data[255*8];
769
770 clearCommandBuffer();
771 SendCommand(&c);
772 if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
773 PrintAndLog("Command execute timeout");
774 ul_switch_off_field();
775 return 0;
776 }
777 uint8_t readStatus = resp.arg[0] & 0xff;
778 uint8_t * data = resp.d.asBytes;
779
780 if(readStatus == 0){
781 PrintAndLog("No tag found...");
782 ul_switch_off_field();
783 return 0;
784 }
785
786 if( readStatus & (FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_CC)){
787 memcpy(tag_data, data, 8*3);
788 blockno += 2; // 2 to force re-read of block 2 later. (seems to respond differently..)
789 numblks = data[8];
790 getMemConfig(data[13], data[12], &maxBlk, &app_areas, &kb);
791 // large memory - not able to dump pages currently
792 if (numblks > maxBlk) numblks = maxBlk;
793 }
794
795 ul_switch_off_field();
796 // authenticate debit key and get div_key - later store in dump block 3
797 if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, false)){
798 //try twice - for some reason it sometimes fails the first time...
799 if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, false)){
800 ul_switch_off_field();
801 return 0;
802 }
803 }
804
805 // begin dump
806 UsbCommand w = {CMD_ICLASS_DUMP, {blockno, numblks-blockno+1}};
807 clearCommandBuffer();
808 SendCommand(&w);
809 if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
810 PrintAndLog("Command execute time-out 1");
811 ul_switch_off_field();
812 return 1;
813 }
814 uint32_t blocksRead = resp.arg[1];
815 uint8_t isOK = resp.arg[0] & 0xff;
816 if (!isOK && !blocksRead) {
817 PrintAndLog("Read Block Failed");
818 ul_switch_off_field();
819 return 0;
820 }
821 uint32_t startindex = resp.arg[2];
822 if (blocksRead*8 > sizeof(tag_data)-(blockno*8)) {
823 PrintAndLog("Data exceeded Buffer size!");
824 blocksRead = (sizeof(tag_data)/8) - blockno;
825 }
826 // response ok - now get bigbuf content of the dump
827 GetFromBigBuf(tag_data+(blockno*8), blocksRead*8, startindex);
828 WaitForResponse(CMD_ACK,NULL);
829 size_t gotBytes = blocksRead*8 + blockno*8;
830
831 // try AA2
832 if (have_credit_key) {
833 //turn off hf field before authenticating with different key
834 ul_switch_off_field();
835 memset(MAC,0,4);
836 // AA2 authenticate credit key and git c_div_key - later store in dump block 4
837 if (!select_and_auth(CreditKEY, MAC, c_div_key, true, false, false, false)){
838 //try twice - for some reason it sometimes fails the first time...
839 if (!select_and_auth(CreditKEY, MAC, c_div_key, true, false, false, false)){
840 ul_switch_off_field();
841 return 0;
842 }
843 }
844 // do we still need to read more block? (aa2 enabled?)
845 if (maxBlk > blockno+numblks+1) {
846 // setup dump and start
847 w.arg[0] = blockno + blocksRead;
848 w.arg[1] = maxBlk - (blockno + blocksRead);
849 clearCommandBuffer();
850 SendCommand(&w);
851 if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
852 PrintAndLog("Command execute timeout 2");
853 ul_switch_off_field();
854 return 0;
855 }
856 uint8_t isOK = resp.arg[0] & 0xff;
857 blocksRead = resp.arg[1];
858 if (!isOK && !blocksRead) {
859 PrintAndLog("Read Block Failed 2");
860 ul_switch_off_field();
861 return 0;
862 }
863
864 startindex = resp.arg[2];
865 if (blocksRead*8 > sizeof(tag_data)-gotBytes) {
866 PrintAndLog("Data exceeded Buffer size!");
867 blocksRead = (sizeof(tag_data) - gotBytes)/8;
868 }
869 // get dumped data from bigbuf
870 GetFromBigBuf(tag_data+gotBytes, blocksRead*8, startindex);
871 WaitForResponse(CMD_ACK,NULL);
872
873 gotBytes += blocksRead*8;
874 } else { //field is still on - turn it off...
875 ul_switch_off_field();
876 }
877 }
878
879 // add diversified keys to dump
880 if (have_debit_key) memcpy(tag_data+(3*8),div_key,8);
881 if (have_credit_key) memcpy(tag_data+(4*8),c_div_key,8);
882
883 printf("Num of bytes: %zu\n", gotBytes);
884
885 // print the dump
886 printf("------+--+-------------------------+\n");
887 printf("CSN |00| %s|\n", sprint_hex(tag_data, 8));
888 //printIclassDumpContents(tag_data, 1, (gotBytes/8)-1, gotBytes-8);
889 printIclassDumpContents(tag_data, 1, (gotBytes/8), gotBytes);
890
891 if (filename[0] == 0){
892 snprintf(filename, FILE_PATH_SIZE,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x",
893 tag_data[0],tag_data[1],tag_data[2],tag_data[3],
894 tag_data[4],tag_data[5],tag_data[6],tag_data[7]);
895 }
896
897 // save the dump to .bin file
898 PrintAndLog("Saving dump file - %d blocks read", gotBytes/8);
899 saveFile(filename, "bin", tag_data, gotBytes);
900 return 1;
901}
902
903static int WriteBlock(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool verbose) {
904 uint8_t MAC[4]={0x00,0x00,0x00,0x00};
905 uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
906 if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose))
907 return 0;
908
909 UsbCommand resp;
910
911 Calc_wb_mac(blockno,bldata,div_key,MAC);
912 UsbCommand w = {CMD_ICLASS_WRITEBLOCK, {blockno}};
913 memcpy(w.d.asBytes, bldata, 8);
914 memcpy(w.d.asBytes + 8, MAC, 4);
915
916 clearCommandBuffer();
917 SendCommand(&w);
918 if (!WaitForResponseTimeout(CMD_ACK,&resp,4500)) {
919 PrintAndLog("Write Command execute timeout");
920 return 0;
921 }
922 uint8_t isOK = resp.arg[0] & 0xff;
923 if (!isOK) {
924 PrintAndLog("Write Block Failed");
925 return 0;
926 }
927 PrintAndLog("Write Block Successful");
928 return 1;
929}
930
931int CmdHFiClass_WriteBlock(const char *Cmd) {
932 uint8_t blockno=0;
933 uint8_t bldata[8]={0,0,0,0,0,0,0,0};
934 uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
935 uint8_t keyNbr = 0;
936 uint8_t dataLen = 0;
937 char tempStr[50] = {0};
938 bool use_credit_key = false;
939 bool elite = false;
940 bool rawkey= false;
941 bool errors = false;
942 uint8_t cmdp = 0;
943 while(param_getchar(Cmd, cmdp) != 0x00)
944 {
945 switch(param_getchar(Cmd, cmdp))
946 {
947 case 'h':
948 case 'H':
949 return usage_hf_iclass_writeblock();
950 case 'b':
951 case 'B':
952 if (param_gethex(Cmd, cmdp+1, &blockno, 2)) {
953 PrintAndLog("Block No must include 2 HEX symbols\n");
954 errors = true;
955 }
956 cmdp += 2;
957 break;
958 case 'c':
959 case 'C':
960 use_credit_key = true;
961 cmdp++;
962 break;
963 case 'd':
964 case 'D':
965 if (param_gethex(Cmd, cmdp+1, bldata, 16))
966 {
967 PrintAndLog("KEY must include 16 HEX symbols\n");
968 errors = true;
969 }
970 cmdp += 2;
971 break;
972 case 'e':
973 case 'E':
974 elite = true;
975 cmdp++;
976 break;
977 case 'k':
978 case 'K':
979 dataLen = param_getstr(Cmd, cmdp+1, tempStr);
980 if (dataLen == 16) {
981 errors = param_gethex(tempStr, 0, KEY, dataLen);
982 } else if (dataLen == 1) {
983 keyNbr = param_get8(Cmd, cmdp+1);
984 if (keyNbr < ICLASS_KEYS_MAX) {
985 memcpy(KEY, iClass_Key_Table[keyNbr], 8);
986 } else {
987 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
988 errors = true;
989 }
990 } else {
991 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
992 errors = true;
993 }
994 cmdp += 2;
995 break;
996 case 'r':
997 case 'R':
998 rawkey = true;
999 cmdp++;
1000 break;
1001 default:
1002 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
1003 errors = true;
1004 break;
1005 }
1006 if(errors) return usage_hf_iclass_writeblock();
1007 }
1008
1009 if (cmdp < 6) return usage_hf_iclass_writeblock();
1010 int ans = WriteBlock(blockno, bldata, KEY, use_credit_key, elite, rawkey, true);
1011 ul_switch_off_field();
1012 return ans;
1013}
1014
1015int CmdHFiClassCloneTag(const char *Cmd) {
1016 char filename[FILE_PATH_SIZE] = { 0x00 };
1017 char tempStr[50]={0};
1018 uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1019 uint8_t keyNbr = 0;
1020 uint8_t fileNameLen = 0;
1021 uint8_t startblock = 0;
1022 uint8_t endblock = 0;
1023 uint8_t dataLen = 0;
1024 bool use_credit_key = false;
1025 bool elite = false;
1026 bool rawkey = false;
1027 bool errors = false;
1028 uint8_t cmdp = 0;
1029 while(param_getchar(Cmd, cmdp) != 0x00)
1030 {
1031 switch(param_getchar(Cmd, cmdp))
1032 {
1033 case 'h':
1034 case 'H':
1035 return usage_hf_iclass_clone();
1036 case 'b':
1037 case 'B':
1038 if (param_gethex(Cmd, cmdp+1, &startblock, 2)) {
1039 PrintAndLog("Start Block No must include 2 HEX symbols\n");
1040 errors = true;
1041 }
1042 cmdp += 2;
1043 break;
1044 case 'c':
1045 case 'C':
1046 use_credit_key = true;
1047 cmdp++;
1048 break;
1049 case 'e':
1050 case 'E':
1051 elite = true;
1052 cmdp++;
1053 break;
1054 case 'f':
1055 case 'F':
1056 fileNameLen = param_getstr(Cmd, cmdp+1, filename);
1057 if (fileNameLen < 1) {
1058 PrintAndLog("No filename found after f");
1059 errors = true;
1060 }
1061 cmdp += 2;
1062 break;
1063 case 'k':
1064 case 'K':
1065 dataLen = param_getstr(Cmd, cmdp+1, tempStr);
1066 if (dataLen == 16) {
1067 errors = param_gethex(tempStr, 0, KEY, dataLen);
1068 } else if (dataLen == 1) {
1069 keyNbr = param_get8(Cmd, cmdp+1);
1070 if (keyNbr < ICLASS_KEYS_MAX) {
1071 memcpy(KEY, iClass_Key_Table[keyNbr], 8);
1072 } else {
1073 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1074 errors = true;
1075 }
1076 } else {
1077 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1078 errors = true;
1079 }
1080 cmdp += 2;
1081 break;
1082 case 'l':
1083 case 'L':
1084 if (param_gethex(Cmd, cmdp+1, &endblock, 2)) {
1085 PrintAndLog("Start Block No must include 2 HEX symbols\n");
1086 errors = true;
1087 }
1088 cmdp += 2;
1089 break;
1090 case 'r':
1091 case 'R':
1092 rawkey = true;
1093 cmdp++;
1094 break;
1095 default:
1096 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
1097 errors = true;
1098 break;
1099 }
1100 if(errors) return usage_hf_iclass_clone();
1101 }
1102
1103 if (cmdp < 8) return usage_hf_iclass_clone();
1104
1105 FILE *f;
1106
1107 iclass_block_t tag_data[USB_CMD_DATA_SIZE/12];
1108
1109 if ((endblock-startblock+1)*12 > USB_CMD_DATA_SIZE) {
1110 PrintAndLog("Trying to write too many blocks at once. Max: %d", USB_CMD_DATA_SIZE/8);
1111 }
1112 // file handling and reading
1113 f = fopen(filename,"rb");
1114 if(!f) {
1115 PrintAndLog("Failed to read from file '%s'", filename);
1116 return 1;
1117 }
1118
1119 if (startblock<5) {
1120 PrintAndLog("You cannot write key blocks this way. yet... make your start block > 4");
1121 fclose(f);
1122 return 0;
1123 }
1124 // now read data from the file from block 6 --- 19
1125 // ok we will use this struct [data 8 bytes][MAC 4 bytes] for each block calculate all mac number for each data
1126 // then copy to usbcommand->asbytes; the max is 32 - 6 = 24 block 12 bytes each block 288 bytes then we can only accept to clone 21 blocks at the time,
1127 // else we have to create a share memory
1128 int i;
1129 fseek(f,startblock*8,SEEK_SET);
1130 size_t bytes_read = fread(tag_data,sizeof(iclass_block_t),endblock - startblock + 1,f);
1131 if ( bytes_read == 0){
1132 PrintAndLog("File reading error.");
1133 fclose(f);
1134 return 2;
1135 }
1136
1137 uint8_t MAC[4]={0x00,0x00,0x00,0x00};
1138 uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1139
1140 if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, true))
1141 return 0;
1142
1143 UsbCommand w = {CMD_ICLASS_CLONE,{startblock,endblock}};
1144 uint8_t *ptr;
1145 // calculate all mac for every the block we will write
1146 for (i = startblock; i <= endblock; i++){
1147 Calc_wb_mac(i,tag_data[i - startblock].d,div_key,MAC);
1148 // usb command d start pointer = d + (i - 6) * 12
1149 // memcpy(pointer,tag_data[i - 6],8) 8 bytes
1150 // memcpy(pointer + 8,mac,sizoof(mac) 4 bytes;
1151 // next one
1152 ptr = w.d.asBytes + (i - startblock) * 12;
1153 memcpy(ptr, &(tag_data[i - startblock].d[0]), 8);
1154 memcpy(ptr + 8,MAC, 4);
1155 }
1156 uint8_t p[12];
1157 for (i = 0; i <= endblock - startblock;i++){
1158 memcpy(p,w.d.asBytes + (i * 12),12);
1159 printf("Block |%02x|",i + startblock);
1160 printf(" %02x%02x%02x%02x%02x%02x%02x%02x |",p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7]);
1161 printf(" MAC |%02x%02x%02x%02x|\n",p[8],p[9],p[10],p[11]);
1162 }
1163 UsbCommand resp;
1164 clearCommandBuffer();
1165 SendCommand(&w);
1166 if (!WaitForResponseTimeout(CMD_ACK,&resp,4500)) {
1167 PrintAndLog("Command execute timeout");
1168 return 0;
1169 }
1170 return 1;
1171}
1172
1173static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool verbose) {
1174 uint8_t MAC[4]={0x00,0x00,0x00,0x00};
1175 uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1176
1177 if (!select_and_auth(KEY, MAC, div_key, (keyType==0x18), elite, rawkey, verbose))
1178 return 0;
1179
1180 UsbCommand resp;
1181 UsbCommand w = {CMD_ICLASS_READBLOCK, {blockno}};
1182 clearCommandBuffer();
1183 SendCommand(&w);
1184 if (!WaitForResponseTimeout(CMD_ACK,&resp,4500)) {
1185 PrintAndLog("Command execute timeout");
1186 return 0;
1187 }
1188
1189 uint8_t isOK = resp.arg[0] & 0xff;
1190 if (!isOK) {
1191 PrintAndLog("Read Block Failed");
1192 return 0;
1193 }
1194 //data read is stored in: resp.d.asBytes[0-15]
1195 if (verbose) PrintAndLog("Block %02X: %s\n",blockno, sprint_hex(resp.d.asBytes,8));
1196 return 1;
1197}
1198
1199int CmdHFiClass_ReadBlock(const char *Cmd) {
1200 uint8_t blockno=0;
1201 uint8_t keyType = 0x88; //debit key
1202 uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1203 uint8_t keyNbr = 0;
1204 uint8_t dataLen = 0;
1205 char tempStr[50] = {0};
1206 bool elite = false;
1207 bool rawkey = false;
1208 bool errors = false;
1209 uint8_t cmdp = 0;
1210 while(param_getchar(Cmd, cmdp) != 0x00)
1211 {
1212 switch(param_getchar(Cmd, cmdp))
1213 {
1214 case 'h':
1215 case 'H':
1216 return usage_hf_iclass_readblock();
1217 case 'b':
1218 case 'B':
1219 if (param_gethex(Cmd, cmdp+1, &blockno, 2)) {
1220 PrintAndLog("Block No must include 2 HEX symbols\n");
1221 errors = true;
1222 }
1223 cmdp += 2;
1224 break;
1225 case 'c':
1226 case 'C':
1227 keyType = 0x18;
1228 cmdp++;
1229 break;
1230 case 'e':
1231 case 'E':
1232 elite = true;
1233 cmdp++;
1234 break;
1235 case 'k':
1236 case 'K':
1237 dataLen = param_getstr(Cmd, cmdp+1, tempStr);
1238 if (dataLen == 16) {
1239 errors = param_gethex(tempStr, 0, KEY, dataLen);
1240 } else if (dataLen == 1) {
1241 keyNbr = param_get8(Cmd, cmdp+1);
1242 if (keyNbr < ICLASS_KEYS_MAX) {
1243 memcpy(KEY, iClass_Key_Table[keyNbr], 8);
1244 } else {
1245 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1246 errors = true;
1247 }
1248 } else {
1249 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1250 errors = true;
1251 }
1252 cmdp += 2;
1253 break;
1254 case 'r':
1255 case 'R':
1256 rawkey = true;
1257 cmdp++;
1258 break;
1259 default:
1260 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
1261 errors = true;
1262 break;
1263 }
1264 if(errors) return usage_hf_iclass_readblock();
1265 }
1266
1267 if (cmdp < 4) return usage_hf_iclass_readblock();
1268
1269 return ReadBlock(KEY, blockno, keyType, elite, rawkey, true);
1270}
1271
1272int CmdHFiClass_loclass(const char *Cmd) {
1273 char opt = param_getchar(Cmd, 0);
1274
1275 if (strlen(Cmd)<1 || opt == 'h') {
1276 PrintAndLog("Usage: hf iclass loclass [options]");
1277 PrintAndLog("Options:");
1278 PrintAndLog("h Show this help");
1279 PrintAndLog("t Perform self-test");
1280 PrintAndLog("f <filename> Bruteforce iclass dumpfile");
1281 PrintAndLog(" An iclass dumpfile is assumed to consist of an arbitrary number of");
1282 PrintAndLog(" malicious CSNs, and their protocol responses");
1283 PrintAndLog(" The binary format of the file is expected to be as follows: ");
1284 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1285 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1286 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1287 PrintAndLog(" ... totalling N*24 bytes");
1288 return 0;
1289 }
1290 char fileName[255] = {0};
1291 if(opt == 'f') {
1292 if(param_getstr(Cmd, 1, fileName) > 0) {
1293 return bruteforceFileNoKeys(fileName);
1294 } else {
1295 PrintAndLog("You must specify a filename");
1296 // no return?
1297 }
1298 }
1299 else if(opt == 't') {
1300 int errors = testCipherUtils();
1301 errors += testMAC();
1302 errors += doKeyTests(0);
1303 errors += testElite();
1304 if(errors) prnlog("OBS! There were errors!!!");
1305 return errors;
1306 }
1307 return 0;
1308}
1309
1310void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize) {
1311 uint8_t mem_config;
1312 memcpy(&mem_config, iclass_dump + 13,1);
1313 uint8_t maxmemcount;
1314
1315 uint8_t filemaxblock = filesize / 8;
1316
1317 if (mem_config & 0x80)
1318 maxmemcount = 255;
1319 else
1320 maxmemcount = 31;
1321
1322 if (startblock == 0)
1323 startblock = 6;
1324
1325 if ((endblock > maxmemcount) || (endblock == 0))
1326 endblock = maxmemcount;
1327
1328 // remember endblock needs to relate to zero-index arrays.
1329 if (endblock > filemaxblock-1)
1330 endblock = filemaxblock-1;
1331
1332 //PrintAndLog ("startblock: %d, endblock: %d, filesize: %d, maxmemcount: %d, filemaxblock: %d",startblock, endblock,filesize, maxmemcount, filemaxblock);
1333
1334 int i = startblock;
1335 printf("------+--+-------------------------+\n");
1336 while (i <= endblock){
1337 uint8_t *blk = iclass_dump + (i * 8);
1338 printf("Block |%02X| %s\n", i, sprint_hex_ascii(blk, 8) );
1339 i++;
1340 }
1341 printf("------+--+-------------------------+\n");
1342}
1343
1344int CmdHFiClassReadTagFile(const char *Cmd) {
1345 int startblock = 0;
1346 int endblock = 0;
1347 char tempnum[5];
1348 FILE *f;
1349 char filename[FILE_PATH_SIZE];
1350 if (param_getstr(Cmd, 0, filename) < 1)
1351 return usage_hf_iclass_readtagfile();
1352
1353 if (param_getstr(Cmd,1,(char *)&tempnum) < 1)
1354 startblock = 0;
1355 else
1356 sscanf(tempnum,"%d",&startblock);
1357
1358 if (param_getstr(Cmd,2,(char *)&tempnum) < 1)
1359 endblock = 0;
1360 else
1361 sscanf(tempnum,"%d",&endblock);
1362
1363 // file handling and reading
1364 f = fopen(filename,"rb");
1365 if(!f) {
1366 PrintAndLog("Failed to read from file '%s'", filename);
1367 return 1;
1368 }
1369 fseek(f, 0, SEEK_END);
1370 long fsize = ftell(f);
1371 fseek(f, 0, SEEK_SET);
1372
1373 if ( fsize < 0 ) {
1374 PrintAndLog("Error, when getting filesize");
1375 fclose(f);
1376 return 1;
1377 }
1378
1379 uint8_t *dump = malloc(fsize);
1380 size_t bytes_read = fread(dump, 1, fsize, f);
1381 fclose(f);
1382
1383 uint8_t *csn = dump;
1384 printf("------+--+-------------------------+\n");
1385 printf("CSN |00| %s|\n", sprint_hex(csn, 8) );
1386 printIclassDumpContents(dump, startblock, endblock, bytes_read);
1387 free(dump);
1388 return 0;
1389}
1390
1391/*
1392uint64_t xorcheck(uint64_t sdiv,uint64_t hdiv) {
1393 uint64_t new_div = 0x00;
1394 new_div ^= sdiv;
1395 new_div ^= hdiv;
1396 return new_div;
1397}
1398
1399uint64_t hexarray_to_uint64(uint8_t *key) {
1400 char temp[17];
1401 uint64_t uint_key;
1402 for (int i = 0;i < 8;i++)
1403 sprintf(&temp[(i *2)],"%02X",key[i]);
1404 temp[16] = '\0';
1405 if (sscanf(temp,"%016"llX,&uint_key) < 1)
1406 return 0;
1407 return uint_key;
1408}
1409*/
1410void HFiClassCalcDivKey(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key, bool elite){
1411 uint8_t keytable[128] = {0};
1412 uint8_t key_index[8] = {0};
1413 if (elite) {
1414 uint8_t key_sel[8] = { 0 };
1415 uint8_t key_sel_p[8] = { 0 };
1416 hash2(KEY, keytable);
1417 hash1(CSN, key_index);
1418 for(uint8_t i = 0; i < 8 ; i++)
1419 key_sel[i] = keytable[key_index[i]] & 0xFF;
1420
1421 //Permute from iclass format to standard format
1422 permutekey_rev(key_sel, key_sel_p);
1423 diversifyKey(CSN, key_sel_p, div_key);
1424 } else {
1425 diversifyKey(CSN, KEY, div_key);
1426 }
1427}
1428
1429//when told CSN, oldkey, newkey, if new key is elite (elite), and if old key was elite (oldElite)
1430//calculate and return xor_div_key (ready for a key write command)
1431//print all div_keys if verbose
1432static void HFiClassCalcNewKey(uint8_t *CSN, uint8_t *OLDKEY, uint8_t *NEWKEY, uint8_t *xor_div_key, bool elite, bool oldElite, bool verbose){
1433 uint8_t old_div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1434 uint8_t new_div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1435 //get old div key
1436 HFiClassCalcDivKey(CSN, OLDKEY, old_div_key, oldElite);
1437 //get new div key
1438 HFiClassCalcDivKey(CSN, NEWKEY, new_div_key, elite);
1439
1440 for (uint8_t i = 0; i < sizeof(old_div_key); i++){
1441 xor_div_key[i] = old_div_key[i] ^ new_div_key[i];
1442 }
1443 if (verbose) {
1444 printf("Old div key : %s\n",sprint_hex(old_div_key,8));
1445 printf("New div key : %s\n",sprint_hex(new_div_key,8));
1446 printf("Xor div key : %s\n",sprint_hex(xor_div_key,8));
1447 }
1448}
1449
1450int CmdHFiClassCalcNewKey(const char *Cmd) {
1451 uint8_t OLDKEY[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1452 uint8_t NEWKEY[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1453 uint8_t xor_div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1454 uint8_t CSN[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1455 uint8_t CCNR[12] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1456 uint8_t keyNbr = 0;
1457 uint8_t dataLen = 0;
1458 char tempStr[50] = {0};
1459 bool givenCSN = false;
1460 bool oldElite = false;
1461 bool elite = false;
1462 bool errors = false;
1463 uint8_t cmdp = 0;
1464 while(param_getchar(Cmd, cmdp) != 0x00)
1465 {
1466 switch(param_getchar(Cmd, cmdp))
1467 {
1468 case 'h':
1469 case 'H':
1470 return usage_hf_iclass_calc_newkey();
1471 case 'e':
1472 case 'E':
1473 dataLen = param_getstr(Cmd, cmdp, tempStr);
1474 if (dataLen==2)
1475 oldElite = true;
1476 elite = true;
1477 cmdp++;
1478 break;
1479 case 'n':
1480 case 'N':
1481 dataLen = param_getstr(Cmd, cmdp+1, tempStr);
1482 if (dataLen == 16) {
1483 errors = param_gethex(tempStr, 0, NEWKEY, dataLen);
1484 } else if (dataLen == 1) {
1485 keyNbr = param_get8(Cmd, cmdp+1);
1486 if (keyNbr < ICLASS_KEYS_MAX) {
1487 memcpy(NEWKEY, iClass_Key_Table[keyNbr], 8);
1488 } else {
1489 PrintAndLog("\nERROR: NewKey Nbr is invalid\n");
1490 errors = true;
1491 }
1492 } else {
1493 PrintAndLog("\nERROR: NewKey is incorrect length\n");
1494 errors = true;
1495 }
1496 cmdp += 2;
1497 break;
1498 case 'o':
1499 case 'O':
1500 dataLen = param_getstr(Cmd, cmdp+1, tempStr);
1501 if (dataLen == 16) {
1502 errors = param_gethex(tempStr, 0, OLDKEY, dataLen);
1503 } else if (dataLen == 1) {
1504 keyNbr = param_get8(Cmd, cmdp+1);
1505 if (keyNbr < ICLASS_KEYS_MAX) {
1506 memcpy(OLDKEY, iClass_Key_Table[keyNbr], 8);
1507 } else {
1508 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1509 errors = true;
1510 }
1511 } else {
1512 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1513 errors = true;
1514 }
1515 cmdp += 2;
1516 break;
1517 case 's':
1518 case 'S':
1519 givenCSN = true;
1520 if (param_gethex(Cmd, cmdp+1, CSN, 16))
1521 return usage_hf_iclass_calc_newkey();
1522 cmdp += 2;
1523 break;
1524 default:
1525 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
1526 errors = true;
1527 break;
1528 }
1529 if(errors) return usage_hf_iclass_calc_newkey();
1530 }
1531
1532 if (cmdp < 4) return usage_hf_iclass_calc_newkey();
1533
1534 if (!givenCSN)
1535 if (!select_only(CSN, CCNR, false, true))
1536 return 0;
1537
1538 HFiClassCalcNewKey(CSN, OLDKEY, NEWKEY, xor_div_key, elite, oldElite, true);
1539 return 0;
1540}
1541
1542static int loadKeys(char *filename) {
1543 FILE *f;
1544 f = fopen(filename,"rb");
1545 if(!f) {
1546 PrintAndLog("Failed to read from file '%s'", filename);
1547 return 0;
1548 }
1549 fseek(f, 0, SEEK_END);
1550 long fsize = ftell(f);
1551 fseek(f, 0, SEEK_SET);
1552
1553 if ( fsize < 0 ) {
1554 PrintAndLog("Error, when getting filesize");
1555 fclose(f);
1556 return 1;
1557 }
1558
1559 uint8_t *dump = malloc(fsize);
1560
1561 size_t bytes_read = fread(dump, 1, fsize, f);
1562 fclose(f);
1563 if (bytes_read > ICLASS_KEYS_MAX * 8){
1564 PrintAndLog("File is too long to load - bytes: %u", bytes_read);
1565 free(dump);
1566 return 0;
1567 }
1568 uint8_t i = 0;
1569 for (; i < bytes_read/8; i++)
1570 memcpy(iClass_Key_Table[i],dump+(i*8),8);
1571
1572 free(dump);
1573 PrintAndLog("%u keys loaded", i);
1574 return 1;
1575}
1576
1577static int saveKeys(char *filename) {
1578 FILE *f;
1579 f = fopen(filename,"wb");
1580 if (!f) {
1581 printf("error opening file %s\n",filename);
1582 return 0;
1583 }
1584 for (uint8_t i = 0; i < ICLASS_KEYS_MAX; i++){
1585 if (fwrite(iClass_Key_Table[i],8,1,f) != 1){
1586 PrintAndLog("save key failed to write to file: %s", filename);
1587 break;
1588 }
1589 }
1590 fclose(f);
1591 return 0;
1592}
1593
1594static int printKeys(void) {
1595 PrintAndLog("");
1596 for (uint8_t i = 0; i < ICLASS_KEYS_MAX; i++)
1597 PrintAndLog("%u: %s", i, sprint_hex(iClass_Key_Table[i],8));
1598 PrintAndLog("");
1599 return 0;
1600}
1601
1602int CmdHFiClassManageKeys(const char *Cmd) {
1603 uint8_t keyNbr = 0;
1604 uint8_t dataLen = 0;
1605 uint8_t KEY[8] = {0};
1606 char filename[FILE_PATH_SIZE];
1607 uint8_t fileNameLen = 0;
1608 bool errors = false;
1609 uint8_t operation = 0;
1610 char tempStr[20];
1611 uint8_t cmdp = 0;
1612
1613 while(param_getchar(Cmd, cmdp) != 0x00)
1614 {
1615 switch(param_getchar(Cmd, cmdp))
1616 {
1617 case 'h':
1618 case 'H':
1619 return usage_hf_iclass_managekeys();
1620 case 'f':
1621 case 'F':
1622 fileNameLen = param_getstr(Cmd, cmdp+1, filename);
1623 if (fileNameLen < 1) {
1624 PrintAndLog("No filename found after f");
1625 errors = true;
1626 }
1627 cmdp += 2;
1628 break;
1629 case 'n':
1630 case 'N':
1631 keyNbr = param_get8(Cmd, cmdp+1);
1632 if (keyNbr == 0) {
1633 PrintAndLog("Wrong block number");
1634 errors = true;
1635 }
1636 cmdp += 2;
1637 break;
1638 case 'k':
1639 case 'K':
1640 operation += 3; //set key
1641 dataLen = param_getstr(Cmd, cmdp+1, tempStr);
1642 if (dataLen == 16) { //ul-c or ev1/ntag key length
1643 errors = param_gethex(tempStr, 0, KEY, dataLen);
1644 } else {
1645 PrintAndLog("\nERROR: Key is incorrect length\n");
1646 errors = true;
1647 }
1648 cmdp += 2;
1649 break;
1650 case 'p':
1651 case 'P':
1652 operation += 4; //print keys in memory
1653 cmdp++;
1654 break;
1655 case 'l':
1656 case 'L':
1657 operation += 5; //load keys from file
1658 cmdp++;
1659 break;
1660 case 's':
1661 case 'S':
1662 operation += 6; //save keys to file
1663 cmdp++;
1664 break;
1665 default:
1666 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
1667 errors = true;
1668 break;
1669 }
1670 if(errors) return usage_hf_iclass_managekeys();
1671 }
1672 if (operation == 0){
1673 PrintAndLog("no operation specified (load, save, or print)\n");
1674 return usage_hf_iclass_managekeys();
1675 }
1676 if (operation > 6){
1677 PrintAndLog("Too many operations specified\n");
1678 return usage_hf_iclass_managekeys();
1679 }
1680 if (operation > 4 && fileNameLen == 0){
1681 PrintAndLog("You must enter a filename when loading or saving\n");
1682 return usage_hf_iclass_managekeys();
1683 }
1684
1685 switch (operation){
1686 case 3: memcpy(iClass_Key_Table[keyNbr], KEY, 8); return 1;
1687 case 4: return printKeys();
1688 case 5: return loadKeys(filename);
1689 case 6: return saveKeys(filename);
1690 break;
1691 }
1692 return 0;
1693}
1694
1695static command_t CommandTable[] = {
1696 {"help", CmdHelp, 1, "This help"},
1697 {"calcnewkey", CmdHFiClassCalcNewKey, 1, "[options..] Calc Diversified keys (blocks 3 & 4) to write new keys"},
1698 {"clone", CmdHFiClassCloneTag, 0, "[options..] Authenticate and Clone from iClass bin file"},
1699 {"decrypt", CmdHFiClassDecrypt, 1, "[f <fname>] Decrypt tagdump" },
1700 {"dump", CmdHFiClassReader_Dump, 0, "[options..] Authenticate and Dump iClass tag's AA1"},
1701 {"eload", CmdHFiClassELoad, 0, "[f <fname>] (experimental) Load data into iClass emulator memory"},
1702 {"encryptblk", CmdHFiClassEncryptBlk, 1, "<BlockData> Encrypt given block data"},
1703 {"list", CmdHFiClassList, 0, " (Deprecated) List iClass history"},
1704 {"loclass", CmdHFiClass_loclass, 1, "[options..] Use loclass to perform bruteforce of reader attack dump"},
1705 {"managekeys", CmdHFiClassManageKeys, 1, "[options..] Manage the keys to use with iClass"},
1706 {"readblk", CmdHFiClass_ReadBlock, 0, "[options..] Authenticate and Read iClass block"},
1707 {"reader", CmdHFiClassReader, 0, "Read an iClass tag"},
1708 {"readtagfile", CmdHFiClassReadTagFile, 1, "[options..] Display Content from tagfile"},
1709 {"replay", CmdHFiClassReader_Replay, 0, "<mac> Read an iClass tag via Reply Attack"},
1710 {"sim", CmdHFiClassSim, 0, "[options..] Simulate iClass tag"},
1711 {"snoop", CmdHFiClassSnoop, 0, " Eavesdrop iClass communication"},
1712 {"writeblk", CmdHFiClass_WriteBlock, 0, "[options..] Authenticate and Write iClass block"},
1713 {NULL, NULL, 0, NULL}
1714};
1715
1716int CmdHFiClass(const char *Cmd) {
1717 clearCommandBuffer();
1718 CmdsParse(CommandTable, Cmd);
1719 return 0;
1720}
1721
1722int CmdHelp(const char *Cmd) {
1723 CmdsHelp(CommandTable);
1724 return 0;
1725}
Impressum, Datenschutz