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
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
9 //-----------------------------------------------------------------------------
10 // High frequency iClass commands
11 //-----------------------------------------------------------------------------
18 #include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type
21 #include "cliparser/cliparser.h"
22 #include "cmdparser.h"
23 #include "cmdhficlass.h"
27 #include "mbedtls/des.h"
28 #include "loclass/cipherutils.h"
29 #include "loclass/cipher.h"
30 #include "loclass/ikeys.h"
31 #include "loclass/elite_crack.h"
32 #include "loclass/fileutils.h"
33 #include "protocols.h"
36 #include "util_posix.h"
37 #include "cmdhf14a.h" // DropField()
40 #define ICLASS_KEYS_MAX 8
41 static uint8_t iClass_Key_Table
[ICLASS_KEYS_MAX
][8] = {
42 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
43 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
44 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
45 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
46 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
47 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
48 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
49 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
53 typedef struct iclass_block
{
58 // iclass / picopass chip config structures and shared routines
60 uint8_t app_limit
; //[8]
61 uint8_t otp
[2]; //[9-10]
62 uint8_t block_writelock
;//[11]
63 uint8_t chip_config
; //[12]
64 uint8_t mem_config
; //[13]
67 } picopass_conf_block
;
71 picopass_conf_block conf
;
75 uint8_t app_issuer_area
[8];
79 static void fuse_config(const picopass_hdr
*hdr
) {
80 uint8_t fuses
= hdr
->conf
.fuses
;
82 if (fuses
& FUSE_FPERS
)
83 PrintAndLog(" Mode: Personalization [Programmable]");
85 PrintAndLog(" Mode: Application [Locked]");
87 if (fuses
& FUSE_CODING1
)
88 PrintAndLog("Coding: RFU");
90 if (fuses
& FUSE_CODING0
)
91 PrintAndLog("Coding: ISO 14443-2 B/ISO 15693");
93 PrintAndLog("Coding: ISO 14443B only");
95 if ((fuses
& FUSE_CRYPT1
) && (fuses
& FUSE_CRYPT0
)) PrintAndLog(" Crypt: Secured page, keys not locked");
96 if ((fuses
& FUSE_CRYPT1
) && !(fuses
& FUSE_CRYPT0
)) PrintAndLog(" Crypt: Secured page, keys locked");
97 if (!(fuses
& FUSE_CRYPT1
) && (fuses
& FUSE_CRYPT0
)) PrintAndLog(" Crypt: Non secured page");
98 if (!(fuses
& FUSE_CRYPT1
) && !(fuses
& FUSE_CRYPT0
)) PrintAndLog(" Crypt: No auth possible. Read only if RA is enabled");
101 PrintAndLog(" RA: Read access enabled");
103 PrintAndLog(" RA: Read access not enabled");
107 static void getMemConfig(uint8_t mem_cfg
, uint8_t chip_cfg
, uint8_t *max_blk
, uint8_t *app_areas
, uint8_t *kb
) {
108 // mem-bit 5, mem-bit 7, chip-bit 4: defines chip type
109 if((chip_cfg
& 0x10) && !(mem_cfg
& 0x80) && !(mem_cfg
& 0x20)) {
113 } else if((chip_cfg
& 0x10) && (mem_cfg
& 0x80) && !(mem_cfg
& 0x20)) {
116 *max_blk
= 255; //16kb
117 } else if(!(chip_cfg
& 0x10) && !(mem_cfg
& 0x80) && !(mem_cfg
& 0x20)) {
120 *max_blk
= 255; //16kb
121 } else if((chip_cfg
& 0x10) && (mem_cfg
& 0x80) && (mem_cfg
& 0x20)) {
124 *max_blk
= 255; //16kb
125 } else if(!(chip_cfg
& 0x10) && !(mem_cfg
& 0x80) && (mem_cfg
& 0x20)) {
128 *max_blk
= 255; //16kb
137 static void mem_app_config(const picopass_hdr
*hdr
) {
138 uint8_t mem
= hdr
->conf
.mem_config
;
139 uint8_t chip
= hdr
->conf
.chip_config
;
140 uint8_t applimit
= hdr
->conf
.app_limit
;
141 if (applimit
< 6) applimit
= 26;
143 uint8_t app_areas
= 2;
144 uint8_t max_blk
= 31;
145 getMemConfig(mem
, chip
, &max_blk
, &app_areas
, &kb
);
146 PrintAndLog(" Mem: %u KBits/%u App Areas (%u * 8 bytes) [%02X]", kb
, app_areas
, max_blk
+1, mem
);
147 PrintAndLog(" AA1: blocks 06-%02X", applimit
);
148 PrintAndLog(" AA2: blocks %02X-%02X", applimit
+1, max_blk
);
152 static void printIclassDumpInfo(uint8_t* iclass_dump
) {
153 fuse_config((picopass_hdr
*)iclass_dump
);
154 mem_app_config((picopass_hdr
*)iclass_dump
);
158 static void usage_hf_iclass_chk(void) {
159 PrintAndLog("Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag");
160 PrintAndLog("Usage: hf iclass chk [h|e|r] <f (*.dic)>");
161 PrintAndLog("Options:");
162 PrintAndLog("h Show this help");
163 PrintAndLog("f <filename> Dictionary file with default iclass keys");
164 PrintAndLog(" e target Elite / High security key scheme");
165 PrintAndLog(" r interpret dictionary file as raw (diversified keys)");
166 PrintAndLog("Samples:");
167 PrintAndLog(" hf iclass chk f default_iclass_keys.dic");
168 PrintAndLog(" hf iclass chk f default_iclass_keys.dic e");
172 static int CmdHFiClassList(const char *Cmd
) {
173 PrintAndLog("Deprecated command, use 'hf list iclass' instead");
178 static int CmdHFiClassSnoop(const char *Cmd
) {
180 CLIParserInit("hf iclass snoop", "\nSnoop a communication between an iClass Reader and an iClass Tag.", NULL
);
183 arg_lit0("j", "--jam", "Jam (prevent) e-purse Updates"),
186 if (CLIParserParseString(Cmd
, argtable
, arg_getsize(argtable
), true)){
191 bool jam_epurse_update
= arg_get_lit(1);
193 const uint8_t update_epurse_sequence
[2] = {0x87, 0x02};
195 UsbCommand c
= {CMD_SNOOP_ICLASS
, {0}};
196 if (jam_epurse_update
) {
197 c
.arg
[0] = sizeof(update_epurse_sequence
);
198 memcpy(c
.d
.asBytes
, update_epurse_sequence
, sizeof(update_epurse_sequence
));
206 static void usage_hf_iclass_sim(void) {
207 PrintAndLog("Usage: hf iclass sim <option> [CSN]");
208 PrintAndLog(" options");
209 PrintAndLog(" 0 <CSN> simulate the given CSN");
210 PrintAndLog(" 1 simulate default CSN");
211 PrintAndLog(" 2 Reader-attack, gather reader responses to extract elite key");
212 PrintAndLog(" 3 Full simulation using emulator memory (see 'hf iclass eload')");
213 PrintAndLog(" example: hf iclass sim 0 031FEC8AF7FF12E0");
214 PrintAndLog(" example: hf iclass sim 2");
215 PrintAndLog(" example: hf iclass eload 'tagdump.bin'");
216 PrintAndLog(" hf iclass sim 3");
220 // the original malicious IDs from Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult,
221 // and Milosch Meriac. Dismantling iClass and iClass Elite.
223 static uint8_t csns
[8 * NUM_CSNS
] = {
224 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
225 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0,
226 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0,
227 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0,
228 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0,
229 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0,
230 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0,
231 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0,
232 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0,
233 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0,
234 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0,
235 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0,
236 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0,
237 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0,
238 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 };
241 // pre-defined 9 CSNs by iceman.
242 // only one csn depend on several others.
243 // six depends only on the first csn, (0,1, 0x45)
245 // #define NUM_CSNS 9
246 // static uint8_t csns[8 * NUM_CSNS] = {
247 // 0x01, 0x0A, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
248 // 0x0C, 0x06, 0x0C, 0xFE, 0xF7, 0xFF, 0x12, 0xE0,
249 // 0x10, 0x97, 0x83, 0x7B, 0xF7, 0xFF, 0x12, 0xE0,
250 // 0x13, 0x97, 0x82, 0x7A, 0xF7, 0xFF, 0x12, 0xE0,
251 // 0x07, 0x0E, 0x0D, 0xF9, 0xF7, 0xFF, 0x12, 0xE0,
252 // 0x14, 0x96, 0x84, 0x76, 0xF7, 0xFF, 0x12, 0xE0,
253 // 0x17, 0x96, 0x85, 0x71, 0xF7, 0xFF, 0x12, 0xE0,
254 // 0xCE, 0xC5, 0x0F, 0x77, 0xF7, 0xFF, 0x12, 0xE0,
255 // 0xD2, 0x5A, 0x82, 0xF8, 0xF7, 0xFF, 0x12, 0xE0
256 // //0x04, 0x08, 0x9F, 0x78, 0x6E, 0xFF, 0x12, 0xE0
260 static int CmdHFiClassSim(const char *Cmd
) {
262 uint8_t CSN
[8] = {0, 0, 0, 0, 0, 0, 0, 0};
264 if (strlen(Cmd
) < 1) {
265 usage_hf_iclass_sim();
268 simType
= param_get8ex(Cmd
, 0, 0, 10);
270 if (simType
== ICLASS_SIM_MODE_CSN
) {
271 if (param_gethex(Cmd
, 1, CSN
, 16)) {
272 PrintAndLog("A CSN should consist of 16 HEX symbols");
273 usage_hf_iclass_sim();
276 PrintAndLog("--simtype:%02x csn:%s", simType
, sprint_hex(CSN
, 8));
279 if (simType
== ICLASS_SIM_MODE_READER_ATTACK
) {
280 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
, NUM_CSNS
}};
281 UsbCommand resp
= {0};
283 memcpy(c
.d
.asBytes
, csns
, 8 * NUM_CSNS
);
286 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, -1)) {
287 PrintAndLog("Command timed out");
291 uint8_t num_mac_responses
= resp
.arg
[1];
292 PrintAndLog("Mac responses: %d MACs obtained (should be %d)", num_mac_responses
, NUM_CSNS
);
294 size_t datalen
= NUM_CSNS
* 24;
296 * Now, time to dump to file. We'll use this format:
297 * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
298 * So, it should wind up as
301 * The returndata from the pm3 is on the following format
302 * <8 byte CC><4 byte NR><4 byte MAC>
303 * CSN is the same as was sent in
305 void* dump
= malloc(datalen
);
306 for(int i
= 0; i
< NUM_CSNS
; i
++) {
307 memcpy(dump
+ i
*24, csns
+i
*8, 8); //CSN
308 //copy CC from response
309 memcpy(dump
+ i
*24 + 8, resp
.d
.asBytes
+ i
*16, 8);
310 //Then comes NR_MAC (eight bytes from the response)
311 memcpy(dump
+ i
*24 + 16, resp
.d
.asBytes
+ i
*16 + 8, 8);
313 /** Now, save to dumpfile **/
314 saveFile("iclass_mac_attack", "bin", dump
,datalen
);
317 } else if (simType
== ICLASS_SIM_MODE_CSN
|| simType
== ICLASS_SIM_MODE_CSN_DEFAULT
|| simType
== ICLASS_SIM_MODE_FULL
) {
318 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
, 0}};
319 memcpy(c
.d
.asBytes
, CSN
, 8);
323 PrintAndLog("Undefined simtype %d", simType
);
324 usage_hf_iclass_sim();
332 int HFiClassReader(bool loop
, bool verbose
) {
334 bool tagFound
= false;
335 UsbCommand c
= {CMD_READER_ICLASS
, {FLAG_ICLASS_READER_INIT
| FLAG_ICLASS_READER_CLEARTRACE
| FLAG_ICLASS_READER_CSN
| FLAG_ICLASS_READER_CONF
| FLAG_ICLASS_READER_CC
| FLAG_ICLASS_READER_AA
} };
340 if (WaitForResponseTimeout(CMD_ACK
,&resp
, 4500)) {
341 uint8_t readStatus
= resp
.arg
[0] & 0xff;
342 uint8_t *data
= resp
.d
.asBytes
;
345 if (readStatus
== 0 && !loop
) {
347 if (verbose
) PrintAndLog("Quitting...");
352 if (readStatus
& FLAG_ICLASS_READER_CSN
) {
353 PrintAndLog(" CSN: %s",sprint_hex(data
,8));
356 if (readStatus
& FLAG_ICLASS_READER_CC
) {
357 PrintAndLog(" CC: %s",sprint_hex(data
+16,8));
359 if (readStatus
& FLAG_ICLASS_READER_CONF
) {
360 printIclassDumpInfo(data
);
362 if (readStatus
& FLAG_ICLASS_READER_AA
) {
364 PrintAndLog(" AppIA: %s",sprint_hex(data
+8*5,8));
365 for (int i
= 0; i
<8; i
++) {
366 if (data
[8*5+i
] != 0xFF) {
370 PrintAndLog(" : Possible iClass %s",(legacy
) ? "(legacy tag)" : "(NOT legacy tag)");
373 if (tagFound
&& !loop
) return 1;
375 if (verbose
) PrintAndLog("Command execute timeout");
385 static void usage_hf_iclass_reader(void) {
386 PrintAndLogEx(NORMAL
, "Act as a Iclass reader. Look for iClass tags until Enter or the pm3 button is pressed\n");
387 PrintAndLogEx(NORMAL
, "Usage: hf iclass reader [h] [1]\n");
388 PrintAndLogEx(NORMAL
, "Options:");
389 PrintAndLogEx(NORMAL
, " h This help text");
390 PrintAndLogEx(NORMAL
, " 1 read only 1 tag");
391 PrintAndLogEx(NORMAL
, "Examples:");
392 PrintAndLogEx(NORMAL
, " hf iclass reader 1");
396 static int CmdHFiClassReader(const char *Cmd
) {
397 char cmdp
= tolower(param_getchar(Cmd
, 0));
399 usage_hf_iclass_reader();
402 bool findone
= (cmdp
== '1') ? false : true;
403 return HFiClassReader(findone
, true);
407 static int CmdHFiClassReader_Replay(const char *Cmd
) {
408 uint8_t readerType
= 0;
409 uint8_t MAC
[4]={0x00, 0x00, 0x00, 0x00};
412 PrintAndLog("Usage: hf iclass replay <MAC>");
413 PrintAndLog(" sample: hf iclass replay 00112233");
417 if (param_gethex(Cmd
, 0, MAC
, 8)) {
418 PrintAndLog("MAC must include 8 HEX symbols");
422 UsbCommand c
= {CMD_READER_ICLASS_REPLAY
, {readerType
}};
423 memcpy(c
.d
.asBytes
, MAC
, 4);
430 static void usage_hf_iclass_eload(void) {
431 PrintAndLog("Loads iclass tag-dump into emulator memory on device");
432 PrintAndLog("Usage: hf iclass eload f <filename>");
434 PrintAndLog("Example: hf iclass eload f iclass_tagdump-aa162d30f8ff12f1.bin");
438 static int CmdHFiClassELoad(const char *Cmd
) {
440 char opt
= param_getchar(Cmd
, 0);
441 if (strlen(Cmd
)<1 || opt
== 'h') {
442 usage_hf_iclass_eload();
446 //File handling and reading
448 char filename
[FILE_PATH_SIZE
];
449 if (opt
== 'f' && param_getstr(Cmd
, 1, filename
, sizeof(filename
)) > 0) {
450 f
= fopen(filename
, "rb");
452 usage_hf_iclass_eload();
457 PrintAndLog("Failed to read from file '%s'", filename
);
461 fseek(f
, 0, SEEK_END
);
462 long fsize
= ftell(f
);
463 fseek(f
, 0, SEEK_SET
);
466 PrintAndLog("Error, when getting filesize");
471 uint8_t *dump
= malloc(fsize
);
473 size_t bytes_read
= fread(dump
, 1, fsize
, f
);
476 printIclassDumpInfo(dump
);
479 if (bytes_read
< fsize
) {
480 prnlog("Error, could only read %d bytes (should be %d)",bytes_read
, fsize
);
485 uint32_t bytes_sent
= 0;
486 uint32_t bytes_remaining
= bytes_read
;
488 while (bytes_remaining
> 0) {
489 uint32_t bytes_in_packet
= MIN(USB_CMD_DATA_SIZE
, bytes_remaining
);
490 UsbCommand c
= {CMD_ICLASS_EML_MEMSET
, {bytes_sent
,bytes_in_packet
,0}};
491 memcpy(c
.d
.asBytes
, dump
+bytes_sent
, bytes_in_packet
);
493 bytes_remaining
-= bytes_in_packet
;
494 bytes_sent
+= bytes_in_packet
;
497 PrintAndLog("Sent %d bytes of data to device emulator memory", bytes_sent
);
502 static int readKeyfile(const char *filename
, size_t len
, uint8_t* buffer
) {
503 FILE *f
= fopen(filename
, "rb");
505 PrintAndLog("Failed to read from file '%s'", filename
);
508 fseek(f
, 0, SEEK_END
);
509 long fsize
= ftell(f
);
510 fseek(f
, 0, SEEK_SET
);
511 size_t bytes_read
= fread(buffer
, 1, len
, f
);
515 PrintAndLog("Warning, file size is %d, expected %d", fsize
, len
);
518 if(bytes_read
!= len
)
520 PrintAndLog("Warning, could only read %d bytes, expected %d" ,bytes_read
, len
);
527 static void usage_hf_iclass_decrypt(void) {
528 PrintAndLog("Usage: hf iclass decrypt f <tagdump>");
530 PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside");
531 PrintAndLog("in the working directory. The file should be 16 bytes binary data");
533 PrintAndLog("example: hf iclass decrypt f tagdump_12312342343.bin");
535 PrintAndLog("OBS! This is pretty stupid implementation, it tries to decrypt every block after block 6. ");
536 PrintAndLog("Correct behaviour would be to decrypt only the application areas where the key is valid,");
537 PrintAndLog("which is defined by the configuration block.");
541 static int CmdHFiClassDecrypt(const char *Cmd
) {
542 uint8_t key
[16] = { 0 };
543 if(readKeyfile("iclass_decryptionkey.bin", 16, key
))
545 usage_hf_iclass_decrypt();
548 PrintAndLog("Decryption file found... ");
549 char opt
= param_getchar(Cmd
, 0);
550 if (strlen(Cmd
)<1 || opt
== 'h') {
551 usage_hf_iclass_decrypt();
555 //Open the tagdump-file
557 char filename
[FILE_PATH_SIZE
];
558 if(opt
== 'f' && param_getstr(Cmd
, 1, filename
, sizeof(filename
)) > 0) {
559 f
= fopen(filename
, "rb");
561 PrintAndLog("Could not find file %s", filename
);
565 usage_hf_iclass_decrypt();
569 fseek(f
, 0, SEEK_END
);
570 long fsize
= ftell(f
);
571 fseek(f
, 0, SEEK_SET
);
572 uint8_t enc_dump
[8] = {0};
573 uint8_t *decrypted
= malloc(fsize
);
574 mbedtls_des3_context ctx
= { {0} };
575 mbedtls_des3_set2key_dec( &ctx
, key
);
576 size_t bytes_read
= fread(enc_dump
, 1, 8, f
);
578 //Use the first block (CSN) for filename
579 char outfilename
[FILE_PATH_SIZE
] = { 0 };
580 snprintf(outfilename
,FILE_PATH_SIZE
,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x-decrypted",
581 enc_dump
[0],enc_dump
[1],enc_dump
[2],enc_dump
[3],
582 enc_dump
[4],enc_dump
[5],enc_dump
[6],enc_dump
[7]);
585 while(bytes_read
== 8)
589 memcpy(decrypted
+(blocknum
*8), enc_dump
, 8);
591 mbedtls_des3_crypt_ecb(&ctx
, enc_dump
,decrypted
+(blocknum
*8) );
593 printvar("decrypted block", decrypted
+(blocknum
*8), 8);
594 bytes_read
= fread(enc_dump
, 1, 8, f
);
599 saveFile(outfilename
,"bin", decrypted
, blocknum
*8);
605 static void usage_hf_iclass_encrypt(void) {
606 PrintAndLog("Usage: hf iclass encrypt <BlockData>");
608 PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside");
609 PrintAndLog("in the working directory. The file should be 16 bytes binary data");
611 PrintAndLog("example: hf iclass encrypt 0102030405060708");
616 static int iClassEncryptBlkData(uint8_t *blkData
) {
617 uint8_t key
[16] = { 0 };
618 if(readKeyfile("iclass_decryptionkey.bin", 16, key
))
620 usage_hf_iclass_encrypt();
623 PrintAndLog("Decryption file found... ");
625 uint8_t encryptedData
[16];
626 uint8_t *encrypted
= encryptedData
;
627 mbedtls_des3_context ctx
= { {0} };
628 mbedtls_des3_set2key_enc( &ctx
, key
);
630 mbedtls_des3_crypt_ecb(&ctx
, blkData
,encrypted
);
631 //printvar("decrypted block", decrypted, 8);
632 memcpy(blkData
,encrypted
,8);
638 static int CmdHFiClassEncryptBlk(const char *Cmd
) {
639 uint8_t blkData
[8] = {0};
640 char opt
= param_getchar(Cmd
, 0);
641 if (strlen(Cmd
)<1 || opt
== 'h') {
642 usage_hf_iclass_encrypt();
645 //get the bytes to encrypt
646 if (param_gethex(Cmd
, 0, blkData
, 16)) {
647 PrintAndLog("BlockData must include 16 HEX symbols");
650 if (!iClassEncryptBlkData(blkData
)) return 0;
651 printvar("encrypted block", blkData
, 8);
656 static void Calc_wb_mac(uint8_t blockno
, uint8_t *data
, uint8_t *div_key
, uint8_t MAC
[4]) {
659 memcpy(WB
+1, data
, 8);
660 doMAC_N(WB
, sizeof(WB
), div_key
, MAC
);
661 //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]);
665 static bool iClass_select(uint8_t *CSN
, bool verbose
, bool cleartrace
, bool init
) {
667 UsbCommand c
= {CMD_READER_ICLASS
, {FLAG_ICLASS_READER_CSN
}};
668 if (init
) c
.arg
[0] |= FLAG_ICLASS_READER_INIT
;
669 if (cleartrace
) c
.arg
[0] |= FLAG_ICLASS_READER_CLEARTRACE
;
672 clearCommandBuffer();
674 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
675 PrintAndLog("Command execute timeout");
679 uint8_t isOK
= resp
.arg
[0] & 0xff;
680 uint8_t *data
= resp
.d
.asBytes
;
682 if (isOK
& FLAG_ICLASS_READER_CSN
) {
683 memcpy(CSN
, data
, 8);
684 if (verbose
) PrintAndLog("CSN: %s", sprint_hex(CSN
, 8));
686 PrintAndLog("Failed to select card! Aborting");
693 static void HFiClassCalcDivKey(uint8_t *CSN
, uint8_t *KEY
, uint8_t *div_key
, bool elite
){
694 uint8_t keytable
[128] = {0};
695 uint8_t key_index
[8] = {0};
697 uint8_t key_sel
[8] = { 0 };
698 uint8_t key_sel_p
[8] = { 0 };
699 hash2(KEY
, keytable
);
700 hash1(CSN
, key_index
);
701 for(uint8_t i
= 0; i
< 8 ; i
++)
702 key_sel
[i
] = keytable
[key_index
[i
]] & 0xFF;
704 //Permute from iclass format to standard format
705 permutekey_rev(key_sel
, key_sel_p
);
706 diversifyKey(CSN
, key_sel_p
, div_key
);
708 diversifyKey(CSN
, KEY
, div_key
);
713 static bool iClass_authenticate(uint8_t *CSN
, uint8_t *KEY
, uint8_t *MAC
, uint8_t *div_key
, bool use_credit_key
, bool elite
, bool rawkey
, bool verbose
) {
717 memcpy(div_key
, KEY
, 8);
719 HFiClassCalcDivKey(CSN
, KEY
, div_key
, elite
);
721 if (verbose
) PrintAndLog("Authenticating with %s: %s", rawkey
? "raw key" : "diversified key", sprint_hex(div_key
, 8));
724 UsbCommand d
= {CMD_ICLASS_READCHECK
, {2, use_credit_key
, 0}};
726 clearCommandBuffer();
729 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
730 if (verbose
) PrintAndLog("Auth Command (READCHECK[2]) execute timeout");
733 bool isOK
= resp
.arg
[0];
735 if (verbose
) PrintAndLog("Couldn't get Card Challenge");
740 memcpy(CCNR
, resp
.d
.asBytes
, 8);
741 memset(CCNR
+8, 0x00, 4); // NR = {0, 0, 0, 0}
743 doMAC(CCNR
, div_key
, MAC
);
745 d
.cmd
= CMD_ICLASS_CHECK
;
746 memcpy(d
.d
.asBytes
, MAC
, 4);
747 clearCommandBuffer();
749 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
750 if (verbose
) PrintAndLog("Auth Command (CHECK) execute timeout");
755 if (verbose
) PrintAndLog("Authentication error");
762 static void usage_hf_iclass_dump(void) {
763 PrintAndLog("Usage: hf iclass dump f <fileName> k <Key> c <CreditKey> e|r\n");
764 PrintAndLog("Options:");
765 PrintAndLog(" f <filename> : specify a filename to save dump to");
766 PrintAndLog(" k <Key> : *Access Key as 16 hex symbols or 1 hex to select key from memory");
767 PrintAndLog(" c <CreditKey>: Credit Key as 16 hex symbols or 1 hex to select key from memory");
768 PrintAndLog(" e : If 'e' is specified, the key is interpreted as the 16 byte");
769 PrintAndLog(" Custom Key (KCus), which can be obtained via reader-attack");
770 PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format");
771 PrintAndLog(" r : If 'r' is specified, the key is interpreted as raw block 3/4");
772 PrintAndLog(" NOTE: * = required");
773 PrintAndLog("Samples:");
774 PrintAndLog(" hf iclass dump k 001122334455667B");
775 PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA c 001122334455667B");
776 PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA e");
780 static void printIclassDumpContents(uint8_t *iclass_dump
, uint8_t startblock
, uint8_t endblock
, size_t filesize
) {
782 memcpy(&mem_config
, iclass_dump
+ 13,1);
784 uint8_t filemaxblock
= filesize
/ 8;
785 if (mem_config
& 0x80)
789 //PrintAndLog ("endblock: %d, filesize: %d, maxmemcount: %d, filemaxblock: %d", endblock,filesize, maxmemcount, filemaxblock);
793 if ((endblock
> maxmemcount
) || (endblock
== 0))
794 endblock
= maxmemcount
;
796 // remember endblock need to relate to zero-index arrays.
797 if (endblock
> filemaxblock
-1)
798 endblock
= filemaxblock
;
801 printf("------+--+-------------------------+\n");
802 while (i
<= endblock
) {
803 uint8_t *blk
= iclass_dump
+ (i
* 8);
804 printf("Block |%02X| %s|\n", i
, sprint_hex(blk
, 8) );
807 printf("------+--+-------------------------+\n");
811 static int CmdHFiClassReader_Dump(const char *Cmd
) {
813 uint8_t MAC
[4] = {0x00,0x00,0x00,0x00};
814 uint8_t div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
815 uint8_t c_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
817 uint8_t AA1_maxBlk
= 0;
819 uint8_t app_areas
= 1;
821 uint8_t KEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
822 uint8_t CreditKEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
825 uint8_t fileNameLen
= 0;
826 char filename
[FILE_PATH_SIZE
]={0};
827 char tempStr
[50] = {0};
828 bool have_debit_key
= false;
829 bool have_credit_key
= false;
830 bool use_credit_key
= false;
834 bool verbose
= false;
837 while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) {
838 switch(param_getchar(Cmd
, cmdp
)) {
841 usage_hf_iclass_dump();
845 have_credit_key
= true;
846 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
848 errors
= param_gethex(tempStr
, 0, CreditKEY
, dataLen
);
849 } else if (dataLen
== 1) {
850 keyNbr
= param_get8(Cmd
, cmdp
+1);
851 if (keyNbr
< ICLASS_KEYS_MAX
) {
852 memcpy(CreditKEY
, iClass_Key_Table
[keyNbr
], 8);
854 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
858 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
870 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
871 if (fileNameLen
< 1) {
872 PrintAndLog("No filename found after f");
879 have_debit_key
= true;
880 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
882 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
883 } else if (dataLen
== 1) {
884 keyNbr
= param_get8(Cmd
, cmdp
+1);
885 if (keyNbr
< ICLASS_KEYS_MAX
) {
886 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
888 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
892 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
908 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
914 if (errors
|| cmdp
< 2) {
915 usage_hf_iclass_dump();
919 // if only credit key is given: try for AA1 as well (not for iclass but for some picopass this will work)
920 if (!have_debit_key
&& have_credit_key
) {
921 use_credit_key
= true;
922 memcpy(KEY
, CreditKEY
, 8);
925 // clear trace and get first 3 blocks
926 UsbCommand c
= {CMD_READER_ICLASS
, {FLAG_ICLASS_READER_INIT
| FLAG_ICLASS_READER_CLEARTRACE
| FLAG_ICLASS_READER_CSN
| FLAG_ICLASS_READER_CONF
| FLAG_ICLASS_READER_CC
}};
928 uint8_t tag_data
[256*8];
930 clearCommandBuffer();
932 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
933 PrintAndLog("Command execute timeout");
938 uint8_t readStatus
= resp
.arg
[0] & 0xff;
939 uint8_t *data
= resp
.d
.asBytes
;
940 uint8_t status_mask
= FLAG_ICLASS_READER_CSN
| FLAG_ICLASS_READER_CONF
| FLAG_ICLASS_READER_CC
;
942 if (readStatus
!= status_mask
) {
943 PrintAndLog("No tag found ...");
946 memcpy(tag_data
, data
, 8*3);
947 if (verbose
) PrintAndLog("CSN: %s", sprint_hex(tag_data
, 8));
948 AA1_maxBlk
= data
[8];
949 getMemConfig(data
[13], data
[12], &maxBlk
, &app_areas
, &kb
);
950 // large memory - not able to dump pages currently
951 if (AA1_maxBlk
> maxBlk
) AA1_maxBlk
= maxBlk
;
954 // authenticate debit key (or credit key if we have no debit key) and get div_key - later store in dump block 3
955 if (!iClass_authenticate(tag_data
, KEY
, MAC
, div_key
, use_credit_key
, elite
, rawkey
, verbose
)){
961 UsbCommand w
= {CMD_ICLASS_DUMP
};
962 uint32_t blocksRead
= 0;
963 for (blockno
= 3; blockno
<= AA1_maxBlk
; blockno
+= blocksRead
) {
965 w
.arg
[1] = AA1_maxBlk
- blockno
+ 1;
966 clearCommandBuffer();
968 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
969 PrintAndLog("Command execute time-out 1");
973 blocksRead
= resp
.arg
[1];
974 bool isOK
= resp
.arg
[0];
976 PrintAndLog("Reading AA1 block failed");
980 memcpy(tag_data
+ blockno
*8, resp
.d
.asBytes
, blocksRead
*8);
983 // do we still need to read more blocks (AA2 enabled)?
984 if (have_credit_key
&& maxBlk
> AA1_maxBlk
) {
985 if (!use_credit_key
) {
986 //turn off hf field before authenticating with different key
988 // AA2 authenticate credit key and git c_div_key - later store in dump block 4
990 if (!iClass_select(CSN
, verbose
, false, true) || !iClass_authenticate(CSN
, CreditKEY
, MAC
, c_div_key
, true, false, false, verbose
)){
995 for ( ; blockno
<= maxBlk
; blockno
+= blocksRead
) {
997 w
.arg
[1] = maxBlk
- blockno
+ 1;
998 clearCommandBuffer();
1000 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
1001 PrintAndLog("Command execute time-out 1");
1005 blocksRead
= resp
.arg
[1];
1006 bool isOK
= resp
.arg
[0];
1008 PrintAndLog("Reading AA2 block failed");
1012 memcpy(tag_data
+ blockno
*8, resp
.d
.asBytes
, blocksRead
*8);
1018 // add diversified keys to dump
1019 if (have_debit_key
) {
1020 memcpy(tag_data
+ 3*8, div_key
, 8);
1022 memset(tag_data
+ 3*8, 0xff, 8);
1024 if (have_credit_key
) {
1025 memcpy(tag_data
+ 4*8, c_div_key
, 8);
1027 memset(tag_data
+ 4*8, 0xff, 8);
1031 printf("------+--+-------------------------+\n");
1032 printf("CSN |00| %s|\n",sprint_hex(tag_data
, 8));
1033 printIclassDumpContents(tag_data
, 1, blockno
-1, blockno
*8);
1035 if (filename
[0] == 0) {
1036 snprintf(filename
, FILE_PATH_SIZE
,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x",
1037 tag_data
[0],tag_data
[1],tag_data
[2],tag_data
[3],
1038 tag_data
[4],tag_data
[5],tag_data
[6],tag_data
[7]);
1041 // save the dump to .bin file
1042 PrintAndLog("Saving dump file - %d blocks read", blockno
);
1043 saveFile(filename
, "bin", tag_data
, blockno
*8);
1048 static int WriteBlock(uint8_t blockno
, uint8_t *bldata
, uint8_t *KEY
, bool use_credit_key
, bool elite
, bool rawkey
, bool verbose
) {
1050 uint8_t MAC
[4] = {0x00,0x00,0x00,0x00};
1051 uint8_t div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1054 if (!iClass_select(CSN
, verbose
, true, true) || !iClass_authenticate(CSN
, KEY
, MAC
, div_key
, use_credit_key
, elite
, rawkey
, verbose
)) {
1061 Calc_wb_mac(blockno
, bldata
, div_key
, MAC
);
1063 UsbCommand w
= {CMD_ICLASS_WRITEBLOCK
, {blockno
}};
1064 memcpy(w
.d
.asBytes
, bldata
, 8);
1065 memcpy(w
.d
.asBytes
+ 8, MAC
, 4);
1067 clearCommandBuffer();
1069 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
1070 PrintAndLog("Write Command execute timeout");
1074 bool isOK
= resp
.arg
[0];
1076 PrintAndLog("Write Block Failed");
1081 PrintAndLog("Write Block Successful");
1086 static void usage_hf_iclass_writeblock(void) {
1087 PrintAndLog("Options:");
1088 PrintAndLog(" b <Block> : The block number as 2 hex symbols");
1089 PrintAndLog(" d <data> : Set the Data to write as 16 hex symbols");
1090 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
1091 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
1092 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
1093 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
1094 PrintAndLog("Samples:");
1095 PrintAndLog(" hf iclass writeblk b 0A d AAAAAAAAAAAAAAAA k 001122334455667B");
1096 PrintAndLog(" hf iclass writeblk b 1B d AAAAAAAAAAAAAAAA k 001122334455667B c");
1097 PrintAndLog(" hf iclass writeblk b 0A d AAAAAAAAAAAAAAAA n 0");
1101 static int CmdHFiClass_WriteBlock(const char *Cmd
) {
1103 uint8_t bldata
[8]={0,0,0,0,0,0,0,0};
1104 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1106 uint8_t dataLen
= 0;
1107 char tempStr
[50] = {0};
1108 bool use_credit_key
= false;
1111 bool errors
= false;
1113 while(param_getchar(Cmd
, cmdp
) != 0x00)
1115 switch(param_getchar(Cmd
, cmdp
))
1119 usage_hf_iclass_writeblock();
1123 if (param_gethex(Cmd
, cmdp
+1, &blockno
, 2)) {
1124 PrintAndLog("Block No must include 2 HEX symbols\n");
1131 use_credit_key
= true;
1136 if (param_gethex(Cmd
, cmdp
+1, bldata
, 16)) {
1137 PrintAndLog("Data must include 16 HEX symbols\n");
1149 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1150 if (dataLen
== 16) {
1151 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1152 } else if (dataLen
== 1) {
1153 keyNbr
= param_get8(Cmd
, cmdp
+1);
1154 if (keyNbr
< ICLASS_KEYS_MAX
) {
1155 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
1157 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1161 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1172 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1177 usage_hf_iclass_writeblock();
1183 usage_hf_iclass_writeblock();
1186 int ans
= WriteBlock(blockno
, bldata
, KEY
, use_credit_key
, elite
, rawkey
, true);
1192 static void usage_hf_iclass_clone(void) {
1193 PrintAndLog("Usage: hf iclass clone f <tagfile.bin> b <first block> l <last block> k <KEY> c e|r");
1194 PrintAndLog("Options:");
1195 PrintAndLog(" f <filename>: specify a filename to clone from");
1196 PrintAndLog(" b <Block> : The first block to clone as 2 hex symbols");
1197 PrintAndLog(" l <Last Blk>: Set the Data to write as 16 hex symbols");
1198 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
1199 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
1200 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
1201 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
1202 PrintAndLog("Samples:");
1203 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 1A k 1122334455667788 e");
1204 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 05 l 19 k 0");
1205 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 19 k 0 e");
1209 static int CmdHFiClassCloneTag(const char *Cmd
) {
1210 char filename
[FILE_PATH_SIZE
] = {0};
1211 char tempStr
[50]={0};
1212 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1214 uint8_t fileNameLen
= 0;
1215 uint8_t startblock
= 0;
1216 uint8_t endblock
= 0;
1217 uint8_t dataLen
= 0;
1218 bool use_credit_key
= false;
1220 bool rawkey
= false;
1221 bool errors
= false;
1223 while(param_getchar(Cmd
, cmdp
) != 0x00)
1225 switch(param_getchar(Cmd
, cmdp
))
1229 usage_hf_iclass_clone();
1233 if (param_gethex(Cmd
, cmdp
+1, &startblock
, 2)) {
1234 PrintAndLog("Start Block No must include 2 HEX symbols\n");
1241 use_credit_key
= true;
1251 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
1252 if (fileNameLen
< 1) {
1253 PrintAndLog("No filename found after f");
1260 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1261 if (dataLen
== 16) {
1262 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1263 } else if (dataLen
== 1) {
1264 keyNbr
= param_get8(Cmd
, cmdp
+1);
1265 if (keyNbr
< ICLASS_KEYS_MAX
) {
1266 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
1268 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1272 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1279 if (param_gethex(Cmd
, cmdp
+1, &endblock
, 2)) {
1280 PrintAndLog("Start Block No must include 2 HEX symbols\n");
1291 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1296 usage_hf_iclass_clone();
1302 usage_hf_iclass_clone();
1308 iclass_block_t tag_data
[USB_CMD_DATA_SIZE
/12];
1310 if ((endblock
-startblock
+1)*12 > USB_CMD_DATA_SIZE
) {
1311 PrintAndLog("Trying to write too many blocks at once. Max: %d", USB_CMD_DATA_SIZE
/8);
1313 // file handling and reading
1314 f
= fopen(filename
,"rb");
1316 PrintAndLog("Failed to read from file '%s'", filename
);
1321 PrintAndLog("You cannot write key blocks this way. yet... make your start block > 4");
1325 // now read data from the file from block 6 --- 19
1326 // ok we will use this struct [data 8 bytes][MAC 4 bytes] for each block calculate all mac number for each data
1327 // 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,
1328 // else we have to create a share memory
1330 fseek(f
, startblock
*8, SEEK_SET
);
1331 if (fread(tag_data
, sizeof(iclass_block_t
), endblock
- startblock
+ 1, f
) == 0 ) {
1332 PrintAndLog("File reading error.");
1337 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
1338 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1341 if (!iClass_select(CSN
, true, false, false) || !iClass_authenticate(CSN
, KEY
, MAC
, div_key
, use_credit_key
, elite
, rawkey
, true)) {
1346 UsbCommand w
= {CMD_ICLASS_CLONE
, {startblock
, endblock
}};
1348 // calculate all mac for every the block we will write
1349 for (i
= startblock
; i
<= endblock
; i
++){
1350 Calc_wb_mac(i
, tag_data
[i
- startblock
].d
, div_key
, MAC
);
1351 // usb command d start pointer = d + (i - 6) * 12
1352 // memcpy(pointer,tag_data[i - 6],8) 8 bytes
1353 // memcpy(pointer + 8,mac,sizoof(mac) 4 bytes;
1355 ptr
= w
.d
.asBytes
+ (i
- startblock
) * 12;
1356 memcpy(ptr
, &(tag_data
[i
- startblock
].d
[0]), 8);
1357 memcpy(ptr
+ 8,MAC
, 4);
1360 for (i
= 0; i
<= endblock
- startblock
;i
++){
1361 memcpy(p
,w
.d
.asBytes
+ (i
* 12),12);
1362 printf("Block |%02x|",i
+ startblock
);
1363 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]);
1364 printf(" MAC |%02x%02x%02x%02x|\n",p
[8],p
[9],p
[10],p
[11]);
1369 if (!WaitForResponseTimeout(CMD_ACK
,&resp
,4500))
1371 PrintAndLog("Command execute timeout");
1379 static int ReadBlock(uint8_t *KEY
, uint8_t blockno
, uint8_t keyType
, bool elite
, bool rawkey
, bool verbose
, bool auth
) {
1381 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
1382 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1385 if (!iClass_select(CSN
, verbose
, true, true)) {
1391 if (!iClass_authenticate(CSN
, KEY
, MAC
, div_key
, (keyType
==0x18), elite
, rawkey
, verbose
)) {
1398 UsbCommand w
= {CMD_ICLASS_READBLOCK
, {blockno
}};
1399 clearCommandBuffer();
1401 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
1402 PrintAndLog("Command execute timeout");
1406 bool isOK
= resp
.arg
[0];
1408 PrintAndLog("Read Block Failed");
1412 //data read is stored in: resp.d.asBytes[0-15]
1414 PrintAndLog("Block %02X: %s\n",blockno
, sprint_hex(resp
.d
.asBytes
,8));
1420 static void usage_hf_iclass_readblock(void) {
1421 PrintAndLog("Usage: hf iclass readblk b <Block> k <Key> [c] [e|r]\n");
1422 PrintAndLog("Options:");
1423 PrintAndLog(" b <Block> : The block number as 2 hex symbols");
1424 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
1425 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
1426 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
1427 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
1428 PrintAndLog("Samples:");
1429 PrintAndLog(" hf iclass readblk b 06 k 0011223344556677");
1430 PrintAndLog(" hf iclass readblk b 1B k 0011223344556677 c");
1431 PrintAndLog(" hf iclass readblk b 0A k 0");
1435 static int CmdHFiClass_ReadBlock(const char *Cmd
) {
1437 uint8_t keyType
= 0x88; //debit key
1438 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1440 uint8_t dataLen
= 0;
1441 char tempStr
[50] = {0};
1443 bool rawkey
= false;
1444 bool errors
= false;
1447 while (param_getchar(Cmd
, cmdp
) != 0x00) {
1448 switch (param_getchar(Cmd
, cmdp
)) {
1451 usage_hf_iclass_readblock();
1455 if (param_gethex(Cmd
, cmdp
+1, &blockno
, 2)) {
1456 PrintAndLog("Block No must include 2 HEX symbols\n");
1474 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1475 if (dataLen
== 16) {
1476 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1477 } else if (dataLen
== 1) {
1478 keyNbr
= param_get8(Cmd
, cmdp
+1);
1479 if (keyNbr
< ICLASS_KEYS_MAX
) {
1480 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
1482 PrintAndLog("\nERROR: KeyNbr is invalid\n");
1486 PrintAndLog("\nERROR: Key is incorrect length\n");
1497 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1502 usage_hf_iclass_readblock();
1508 usage_hf_iclass_readblock();
1512 PrintAndLog("warning: no authentication used with read, only a few specific blocks can be read accurately without authentication.");
1514 return ReadBlock(KEY
, blockno
, keyType
, elite
, rawkey
, true, auth
);
1518 static int CmdHFiClass_loclass(const char *Cmd
) {
1519 char opt
= param_getchar(Cmd
, 0);
1521 if (strlen(Cmd
)<1 || opt
== 'h') {
1522 PrintAndLog("Usage: hf iclass loclass [options]");
1523 PrintAndLog("Options:");
1524 PrintAndLog("h Show this help");
1525 PrintAndLog("t Perform self-test");
1526 PrintAndLog("f <filename> Bruteforce iclass dumpfile");
1527 PrintAndLog(" An iclass dumpfile is assumed to consist of an arbitrary number of");
1528 PrintAndLog(" malicious CSNs, and their protocol responses");
1529 PrintAndLog(" The binary format of the file is expected to be as follows: ");
1530 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1531 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1532 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1533 PrintAndLog(" ... totalling N*24 bytes");
1536 char fileName
[255] = {0};
1538 if(param_getstr(Cmd
, 1, fileName
, sizeof(fileName
)) > 0) {
1539 return bruteforceFileNoKeys(fileName
);
1541 PrintAndLog("You must specify a filename");
1543 } else if(opt
== 't') {
1544 int errors
= testCipherUtils();
1545 errors
+= testMAC();
1546 errors
+= doKeyTests(0);
1547 errors
+= testElite();
1549 prnlog("OBS! There were errors!!!");
1558 static void usage_hf_iclass_readtagfile() {
1559 PrintAndLog("Usage: hf iclass readtagfile <filename> [startblock] [endblock]");
1563 static int CmdHFiClassReadTagFile(const char *Cmd
) {
1568 char filename
[FILE_PATH_SIZE
];
1569 if (param_getstr(Cmd
, 0, filename
, sizeof(filename
)) < 1) {
1570 usage_hf_iclass_readtagfile();
1573 if (param_getstr(Cmd
, 1, tempnum
, sizeof(tempnum
)) < 1)
1576 sscanf(tempnum
,"%d",&startblock
);
1578 if (param_getstr(Cmd
,2, tempnum
, sizeof(tempnum
)) < 1)
1581 sscanf(tempnum
,"%d",&endblock
);
1582 // file handling and reading
1583 f
= fopen(filename
,"rb");
1585 PrintAndLog("Failed to read from file '%s'", filename
);
1588 fseek(f
, 0, SEEK_END
);
1589 long fsize
= ftell(f
);
1590 fseek(f
, 0, SEEK_SET
);
1593 PrintAndLog("Error, when getting filesize");
1598 uint8_t *dump
= malloc(fsize
);
1600 size_t bytes_read
= fread(dump
, 1, fsize
, f
);
1602 uint8_t *csn
= dump
;
1603 printf("------+--+-------------------------+\n");
1604 printf("CSN |00| %s|\n", sprint_hex(csn
, 8) );
1605 // printIclassDumpInfo(dump);
1606 printIclassDumpContents(dump
,startblock
,endblock
,bytes_read
);
1612 uint64_t xorcheck(uint64_t sdiv,uint64_t hdiv) {
1613 uint64_t new_div = 0x00;
1619 uint64_t hexarray_to_uint64(uint8_t *key) {
1622 for (int i = 0;i < 8;i++)
1623 sprintf(&temp[(i *2)],"%02X",key[i]);
1625 if (sscanf(temp,"%016" SCNx64,&uint_key) < 1)
1632 //when told CSN, oldkey, newkey, if new key is elite (elite), and if old key was elite (oldElite)
1633 //calculate and return xor_div_key (ready for a key write command)
1634 //print all div_keys if verbose
1635 static void HFiClassCalcNewKey(uint8_t *CSN
, uint8_t *OLDKEY
, uint8_t *NEWKEY
, uint8_t *xor_div_key
, bool elite
, bool oldElite
, bool verbose
){
1636 uint8_t old_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1637 uint8_t new_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1639 HFiClassCalcDivKey(CSN
, OLDKEY
, old_div_key
, oldElite
);
1641 HFiClassCalcDivKey(CSN
, NEWKEY
, new_div_key
, elite
);
1643 for (uint8_t i
= 0; i
< sizeof(old_div_key
); i
++){
1644 xor_div_key
[i
] = old_div_key
[i
] ^ new_div_key
[i
];
1647 printf("Old Div Key : %s\n",sprint_hex(old_div_key
,8));
1648 printf("New Div Key : %s\n",sprint_hex(new_div_key
,8));
1649 printf("Xor Div Key : %s\n",sprint_hex(xor_div_key
,8));
1654 static void usage_hf_iclass_calc_newkey(void) {
1655 PrintAndLog("HELP : Manage iClass Keys in client memory:\n");
1656 PrintAndLog("Usage: hf iclass calc_newkey o <Old key> n <New key> s [csn] e");
1657 PrintAndLog(" Options:");
1658 PrintAndLog(" o <oldkey> : *specify a key as 16 hex symbols or a key number as 1 symbol");
1659 PrintAndLog(" n <newkey> : *specify a key as 16 hex symbols or a key number as 1 symbol");
1660 PrintAndLog(" s <csn> : specify a card Serial number to diversify the key (if omitted will attempt to read a csn)");
1661 PrintAndLog(" e : specify new key as elite calc");
1662 PrintAndLog(" ee : specify old and new key as elite calc");
1663 PrintAndLog("Samples:");
1664 PrintAndLog(" e key to e key given csn : hf iclass calcnewkey o 1122334455667788 n 2233445566778899 s deadbeafdeadbeaf ee");
1665 PrintAndLog(" std key to e key read csn: hf iclass calcnewkey o 1122334455667788 n 2233445566778899 e");
1666 PrintAndLog(" std to std read csn : hf iclass calcnewkey o 1122334455667788 n 2233445566778899");
1667 PrintAndLog("NOTE: * = required\n");
1671 static int CmdHFiClassCalcNewKey(const char *Cmd
) {
1672 uint8_t OLDKEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1673 uint8_t NEWKEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1674 uint8_t xor_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1675 uint8_t CSN
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1677 uint8_t dataLen
= 0;
1678 char tempStr
[50] = {0};
1679 bool givenCSN
= false;
1680 bool oldElite
= false;
1682 bool errors
= false;
1684 while(param_getchar(Cmd
, cmdp
) != 0x00)
1686 switch(param_getchar(Cmd
, cmdp
))
1690 usage_hf_iclass_calc_newkey();
1694 dataLen
= param_getstr(Cmd
, cmdp
, tempStr
, sizeof(tempStr
));
1702 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1703 if (dataLen
== 16) {
1704 errors
= param_gethex(tempStr
, 0, NEWKEY
, dataLen
);
1705 } else if (dataLen
== 1) {
1706 keyNbr
= param_get8(Cmd
, cmdp
+1);
1707 if (keyNbr
< ICLASS_KEYS_MAX
) {
1708 memcpy(NEWKEY
, iClass_Key_Table
[keyNbr
], 8);
1710 PrintAndLog("\nERROR: NewKey Nbr is invalid\n");
1714 PrintAndLog("\nERROR: NewKey is incorrect length\n");
1721 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1722 if (dataLen
== 16) {
1723 errors
= param_gethex(tempStr
, 0, OLDKEY
, dataLen
);
1724 } else if (dataLen
== 1) {
1725 keyNbr
= param_get8(Cmd
, cmdp
+1);
1726 if (keyNbr
< ICLASS_KEYS_MAX
) {
1727 memcpy(OLDKEY
, iClass_Key_Table
[keyNbr
], 8);
1729 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1733 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1741 if (param_gethex(Cmd
, cmdp
+1, CSN
, 16)) {
1742 usage_hf_iclass_calc_newkey();
1748 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1753 usage_hf_iclass_calc_newkey();
1759 usage_hf_iclass_calc_newkey();
1764 if (!iClass_select(CSN
, true, true, true)) {
1770 HFiClassCalcNewKey(CSN
, OLDKEY
, NEWKEY
, xor_div_key
, elite
, oldElite
, true);
1775 static int loadKeys(char *filename
) {
1777 f
= fopen(filename
,"rb");
1779 PrintAndLog("Failed to read from file '%s'", filename
);
1782 fseek(f
, 0, SEEK_END
);
1783 long fsize
= ftell(f
);
1784 fseek(f
, 0, SEEK_SET
);
1787 PrintAndLog("Error, when getting filesize");
1792 uint8_t *dump
= malloc(fsize
);
1794 size_t bytes_read
= fread(dump
, 1, fsize
, f
);
1796 if (bytes_read
> ICLASS_KEYS_MAX
* 8){
1797 PrintAndLog("File is too long to load - bytes: %u", bytes_read
);
1802 for (; i
< bytes_read
/8; i
++){
1803 memcpy(iClass_Key_Table
[i
],dump
+(i
*8),8);
1806 PrintAndLog("%u keys loaded", i
);
1811 static int saveKeys(char *filename
) {
1813 f
= fopen(filename
,"wb");
1815 printf("error opening file %s\n",filename
);
1818 for (uint8_t i
= 0; i
< ICLASS_KEYS_MAX
; i
++){
1819 if (fwrite(iClass_Key_Table
[i
],8,1,f
) != 1){
1820 PrintAndLog("save key failed to write to file: %s", filename
);
1829 static int printKeys(void) {
1831 for (uint8_t i
= 0; i
< ICLASS_KEYS_MAX
; i
++){
1832 PrintAndLog("%u: %s",i
,sprint_hex(iClass_Key_Table
[i
],8));
1839 static void usage_hf_iclass_managekeys(void) {
1840 PrintAndLog("HELP : Manage iClass Keys in client memory:\n");
1841 PrintAndLog("Usage: hf iclass managekeys n [keynbr] k [key] f [filename] s l p\n");
1842 PrintAndLog(" Options:");
1843 PrintAndLog(" n <keynbr> : specify the keyNbr to set in memory");
1844 PrintAndLog(" k <key> : set a key in memory");
1845 PrintAndLog(" f <filename>: specify a filename to use with load or save operations");
1846 PrintAndLog(" s : save keys in memory to file specified by filename");
1847 PrintAndLog(" l : load keys to memory from file specified by filename");
1848 PrintAndLog(" p : print keys loaded into memory\n");
1849 PrintAndLog("Samples:");
1850 PrintAndLog(" set key : hf iclass managekeys n 0 k 1122334455667788");
1851 PrintAndLog(" save key file: hf iclass managekeys f mykeys.bin s");
1852 PrintAndLog(" load key file: hf iclass managekeys f mykeys.bin l");
1853 PrintAndLog(" print keys : hf iclass managekeys p\n");
1857 static int CmdHFiClassManageKeys(const char *Cmd
) {
1859 uint8_t dataLen
= 0;
1860 uint8_t KEY
[8] = {0};
1861 char filename
[FILE_PATH_SIZE
];
1862 uint8_t fileNameLen
= 0;
1863 bool errors
= false;
1864 uint8_t operation
= 0;
1868 while(param_getchar(Cmd
, cmdp
) != 0x00)
1870 switch(param_getchar(Cmd
, cmdp
))
1874 usage_hf_iclass_managekeys();
1878 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
1879 if (fileNameLen
< 1) {
1880 PrintAndLog("No filename found after f");
1887 keyNbr
= param_get8(Cmd
, cmdp
+1);
1888 if (keyNbr
>= ICLASS_KEYS_MAX
) {
1889 PrintAndLog("Invalid block number");
1896 operation
+= 3; //set key
1897 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1898 if (dataLen
== 16) { //ul-c or ev1/ntag key length
1899 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1901 PrintAndLog("\nERROR: Key is incorrect length\n");
1908 operation
+= 4; //print keys in memory
1913 operation
+= 5; //load keys from file
1918 operation
+= 6; //save keys to file
1922 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1927 usage_hf_iclass_managekeys();
1931 if (operation
== 0){
1932 PrintAndLog("no operation specified (load, save, or print)\n");
1933 usage_hf_iclass_managekeys();
1937 PrintAndLog("Too many operations specified\n");
1938 usage_hf_iclass_managekeys();
1941 if (operation
> 4 && fileNameLen
== 0){
1942 PrintAndLog("You must enter a filename when loading or saving\n");
1943 usage_hf_iclass_managekeys();
1948 case 3: memcpy(iClass_Key_Table
[keyNbr
], KEY
, 8); return 1;
1949 case 4: return printKeys();
1950 case 5: return loadKeys(filename
);
1951 case 6: return saveKeys(filename
);
1958 static int CmdHFiClassCheckKeys(const char *Cmd
) {
1960 uint8_t mac
[4] = {0x00,0x00,0x00,0x00};
1961 uint8_t key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1962 uint8_t div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1964 // elite key, raw key, standard key
1965 bool use_elite
= false;
1966 bool use_raw
= false;
1967 bool found_debit
= false;
1968 bool found_credit
= false;
1969 bool errors
= false;
1970 uint8_t cmdp
= 0x00;
1972 char filename
[FILE_PATH_SIZE
] = {0};
1973 uint8_t fileNameLen
= 0;
1975 uint8_t *keyBlock
= NULL
, *p
;
1976 int keyitems
= 0, keycnt
= 0;
1978 while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) {
1979 switch (param_getchar(Cmd
, cmdp
)) {
1982 usage_hf_iclass_chk();
1986 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
1987 if (fileNameLen
< 1) {
1988 PrintAndLog("No filename found after f");
2004 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
2010 usage_hf_iclass_chk();
2014 if ( !(f
= fopen( filename
, "r")) ) {
2015 PrintAndLog("File: %s: not found or locked.", filename
);
2019 while( fgets(buf
, sizeof(buf
), f
) ){
2020 if (strlen(buf
) < 16 || buf
[15] == '\n')
2023 while (fgetc(f
) != '\n' && !feof(f
)) ; //goto next line
2025 if( buf
[0]=='#' ) continue; //The line start with # is comment, skip
2027 if (!isxdigit(buf
[0])){
2028 PrintAndLog("File content error. '%s' must include 16 HEX symbols",buf
);
2034 p
= realloc(keyBlock
, 8 * (keyitems
+= 64));
2036 PrintAndLog("Cannot allocate memory for default keys");
2043 memset(keyBlock
+ 8 * keycnt
, 0, 8);
2044 num_to_bytes(strtoull(buf
, NULL
, 16), 8, keyBlock
+ 8 * keycnt
);
2046 //PrintAndLog("check key[%2d] %016" PRIx64, keycnt, bytes_to_num(keyBlock + 8*keycnt, 8));
2048 memset(buf
, 0, sizeof(buf
));
2051 PrintAndLog("Loaded %2d keys from %s", keycnt
, filename
);
2054 uint64_t t1
= msclock();
2057 if (!iClass_select(CSN
, false, true, true)) {
2058 PrintAndLog("Couldn't select card");
2063 for (uint32_t c
= 0; c
< keycnt
; c
++) {
2064 printf("."); fflush(stdout
);
2066 int gc
= getchar(); (void)gc
;
2067 printf("\naborted via keyboard!\n");
2071 memcpy(key
, keyBlock
+ 8 * c
, 8);
2074 if (!iClass_authenticate(CSN
, key
, mac
, div_key
, false, use_elite
, use_raw
, false))
2078 PrintAndLog("\n--------------------------------------------------------");
2079 PrintAndLog(" Found AA1 debit key\t\t[%s]", sprint_hex(key
, 8));
2083 if (!iClass_authenticate(CSN
, key
, mac
, div_key
, true, use_elite
, use_raw
, false))
2087 PrintAndLog("\n--------------------------------------------------------");
2088 PrintAndLog(" Found AA2 credit key\t\t[%s]", sprint_hex(key
, 8));
2089 found_credit
= true;
2092 if (found_debit
&& found_credit
)
2096 t1
= msclock() - t1
;
2098 PrintAndLog("\nTime in iclass checkkeys: %.0f seconds\n", (float)t1
/1000.0);
2107 static void usage_hf_iclass_permutekey(void) {
2108 PrintAndLogEx(NORMAL
, "Convert keys from standard NIST to iClass format (and vice versa)");
2109 PrintAndLogEx(NORMAL
, "");
2110 PrintAndLogEx(NORMAL
, "Usage: hf iclass permute [h] [r] <key>");
2111 PrintAndLogEx(NORMAL
, "Options:");
2112 PrintAndLogEx(NORMAL
, " h This help");
2113 PrintAndLogEx(NORMAL
, " r reverse convert key from iClass to NIST format");
2114 PrintAndLogEx(NORMAL
, "");
2115 PrintAndLogEx(NORMAL
, "Examples:");
2116 PrintAndLogEx(NORMAL
, " hf iclass permute r 0123456789abcdef");
2120 static int CmdHFiClassPermuteKey(const char *Cmd
) {
2122 uint8_t key
[8] = {0};
2123 uint8_t data
[16] = {0};
2124 bool isReverse
= false;
2125 int len
= sizeof(data
);
2126 char cmdp
= tolower(param_getchar(Cmd
, 0));
2127 if (strlen(Cmd
) == 0 || cmdp
== 'h') {
2128 usage_hf_iclass_permutekey();
2134 param_gethex_ex(Cmd
, 1, data
, &len
);
2135 } else if (cmdp
== 'f') {
2136 param_gethex_ex(Cmd
, 1, data
, &len
);
2138 param_gethex_ex(Cmd
, 0, data
, &len
);
2143 usage_hf_iclass_permutekey();
2149 memcpy(key
, data
, 8);
2152 // generate_rev(data, len);
2153 uint8_t key_std_format
[8] = {0};
2154 permutekey_rev(key
, key_std_format
);
2155 PrintAndLogEx(SUCCESS
, "key in standard NIST format: %s \n", sprint_hex(key_std_format
, 8));
2156 // if (mbedtls_des_key_check_key_parity(key_std_format
2158 // generate(data, len);
2159 uint8_t key_iclass_format
[8] = {0};
2160 permutekey(key
, key_iclass_format
);
2161 PrintAndLogEx(SUCCESS
, "key in iClass (permuted) format: %s \n", sprint_hex(key_iclass_format
, 8));
2167 static int CmdHelp(const char *Cmd
);
2169 static command_t CommandTable
[] = {
2170 {"help", CmdHelp
, 1, "This help"},
2171 {"calcnewkey", CmdHFiClassCalcNewKey
, 1, "[options..] Calc Diversified keys (blocks 3 & 4) to write new keys"},
2172 {"chk", CmdHFiClassCheckKeys
, 0, " Check keys"},
2173 {"clone", CmdHFiClassCloneTag
, 0, "[options..] Authenticate and Clone from iClass bin file"},
2174 {"decrypt", CmdHFiClassDecrypt
, 1, "[f <fname>] Decrypt tagdump" },
2175 {"dump", CmdHFiClassReader_Dump
, 0, "[options..] Authenticate and Dump iClass tag's AA1"},
2176 {"eload", CmdHFiClassELoad
, 0, "[f <fname>] (experimental) Load data into iClass emulator memory"},
2177 {"encryptblk", CmdHFiClassEncryptBlk
, 1, "<BlockData> Encrypt given block data"},
2178 {"list", CmdHFiClassList
, 0, " (Deprecated) List iClass history"},
2179 {"loclass", CmdHFiClass_loclass
, 1, "[options..] Use loclass to perform bruteforce of reader attack dump"},
2180 {"managekeys", CmdHFiClassManageKeys
, 1, "[options..] Manage the keys to use with iClass"},
2181 {"permutekey", CmdHFiClassPermuteKey
, 1, " iClass key permutation"},
2182 {"readblk", CmdHFiClass_ReadBlock
, 0, "[options..] Authenticate and Read iClass block"},
2183 {"reader", CmdHFiClassReader
, 0, " Look for iClass tags until a key or the pm3 button is pressed"},
2184 {"readtagfile", CmdHFiClassReadTagFile
, 1, "[options..] Display Content from tagfile"},
2185 {"replay", CmdHFiClassReader_Replay
, 0, "<mac> Read an iClass tag via Reply Attack"},
2186 {"sim", CmdHFiClassSim
, 0, "[options..] Simulate iClass tag"},
2187 {"snoop", CmdHFiClassSnoop
, 0, " Eavesdrop iClass communication"},
2188 {"writeblk", CmdHFiClass_WriteBlock
, 0, "[options..] Authenticate and Write iClass block"},
2189 {NULL
, NULL
, 0, NULL
}
2193 int CmdHFiClass(const char *Cmd
) {
2194 clearCommandBuffer();
2195 CmdsParse(CommandTable
, Cmd
);
2200 int CmdHelp(const char *Cmd
) {
2201 CmdsHelp(CommandTable
);