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 // Copyright (C) 2019 piwi
7 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
8 // at your option, any later version. See the LICENSE.txt file for the text of
10 //-----------------------------------------------------------------------------
11 // High frequency iClass commands
12 //-----------------------------------------------------------------------------
19 #include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type
22 #include "cliparser/cliparser.h"
23 #include "cmdparser.h"
24 #include "cmdhficlass.h"
28 #include "mbedtls/des.h"
29 #include "loclass/cipherutils.h"
30 #include "loclass/cipher.h"
31 #include "loclass/ikeys.h"
32 #include "loclass/elite_crack.h"
33 #include "loclass/fileutils.h"
34 #include "protocols.h"
37 #include "util_posix.h"
38 #include "cmdhf14a.h" // DropField()
41 #define ICLASS_KEYS_MAX 8
42 static uint8_t iClass_Key_Table
[ICLASS_KEYS_MAX
][8] = {
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 },
50 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
54 // iclass / picopass chip config structures and shared routines
56 uint8_t app_limit
; //[8]
57 uint8_t otp
[2]; //[9-10]
58 uint8_t block_writelock
;//[11]
59 uint8_t chip_config
; //[12]
60 uint8_t mem_config
; //[13]
63 } picopass_conf_block
;
67 picopass_conf_block conf
;
71 uint8_t app_issuer_area
[8];
75 static void fuse_config(const picopass_hdr
*hdr
) {
76 uint8_t fuses
= hdr
->conf
.fuses
;
78 if (fuses
& FUSE_FPERS
)
79 PrintAndLog(" Mode: Personalization [Programmable]");
81 PrintAndLog(" Mode: Application [Locked]");
83 if (fuses
& FUSE_CODING1
)
84 PrintAndLog("Coding: RFU");
86 if (fuses
& FUSE_CODING0
)
87 PrintAndLog("Coding: ISO 14443-2 B/ISO 15693");
89 PrintAndLog("Coding: ISO 14443B only");
91 if ((fuses
& FUSE_CRYPT1
) && (fuses
& FUSE_CRYPT0
)) PrintAndLog(" Crypt: Secured page, keys not locked");
92 if ((fuses
& FUSE_CRYPT1
) && !(fuses
& FUSE_CRYPT0
)) PrintAndLog(" Crypt: Secured page, keys locked");
93 if (!(fuses
& FUSE_CRYPT1
) && (fuses
& FUSE_CRYPT0
)) PrintAndLog(" Crypt: Non secured page");
94 if (!(fuses
& FUSE_CRYPT1
) && !(fuses
& FUSE_CRYPT0
)) PrintAndLog(" Crypt: No auth possible. Read only if RA is enabled");
97 PrintAndLog(" RA: Read access enabled");
99 PrintAndLog(" RA: Read access not enabled");
103 static void getMemConfig(uint8_t mem_cfg
, uint8_t chip_cfg
, uint8_t *max_blk
, uint8_t *app_areas
, uint8_t *kb
) {
104 // mem-bit 5, mem-bit 7, chip-bit 4: defines chip type
105 if((chip_cfg
& 0x10) && !(mem_cfg
& 0x80) && !(mem_cfg
& 0x20)) {
109 } else if((chip_cfg
& 0x10) && (mem_cfg
& 0x80) && !(mem_cfg
& 0x20)) {
112 *max_blk
= 255; //16kb
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
133 static void mem_app_config(const picopass_hdr
*hdr
) {
134 uint8_t mem
= hdr
->conf
.mem_config
;
135 uint8_t chip
= hdr
->conf
.chip_config
;
136 uint8_t applimit
= hdr
->conf
.app_limit
;
137 if (applimit
< 6) applimit
= 26;
139 uint8_t app_areas
= 2;
140 uint8_t max_blk
= 31;
141 getMemConfig(mem
, chip
, &max_blk
, &app_areas
, &kb
);
142 PrintAndLog(" Mem: %u KBits/%u App Areas (%u * 8 bytes) [%02X]", kb
, app_areas
, max_blk
+1, mem
);
143 PrintAndLog(" AA1: blocks 06-%02X", applimit
);
144 PrintAndLog(" AA2: blocks %02X-%02X", applimit
+1, max_blk
);
148 static void printIclassDumpInfo(uint8_t* iclass_dump
) {
149 fuse_config((picopass_hdr
*)iclass_dump
);
150 mem_app_config((picopass_hdr
*)iclass_dump
);
154 static void usage_hf_iclass_chk(void) {
155 PrintAndLog("Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag");
156 PrintAndLog("Usage: hf iclass chk [h|e|r] <f (*.dic)>");
157 PrintAndLog("Options:");
158 PrintAndLog("h Show this help");
159 PrintAndLog("f <filename> Dictionary file with default iclass keys");
160 PrintAndLog(" e target Elite / High security key scheme");
161 PrintAndLog(" r interpret dictionary file as raw (diversified keys)");
162 PrintAndLog("Samples:");
163 PrintAndLog(" hf iclass chk f default_iclass_keys.dic");
164 PrintAndLog(" hf iclass chk f default_iclass_keys.dic e");
168 static int CmdHFiClassList(const char *Cmd
) {
169 PrintAndLog("Deprecated command, use 'hf list iclass' instead");
174 static int CmdHFiClassSnoop(const char *Cmd
) {
176 CLIParserInit("hf iclass snoop", "\nSnoop a communication between an iClass Reader and an iClass Tag.", NULL
);
179 arg_lit0("j", "jam", "Jam (prevent) e-purse Updates"),
182 if (CLIParserParseString(Cmd
, argtable
, arg_getsize(argtable
), true)){
187 bool jam_epurse_update
= arg_get_lit(1);
189 const uint8_t update_epurse_sequence
[2] = {0x87, 0x02};
191 UsbCommand c
= {CMD_SNOOP_ICLASS
, {0}};
192 if (jam_epurse_update
) {
193 c
.arg
[0] = sizeof(update_epurse_sequence
);
194 memcpy(c
.d
.asBytes
, update_epurse_sequence
, sizeof(update_epurse_sequence
));
202 static void usage_hf_iclass_sim(void) {
203 PrintAndLog("Usage: hf iclass sim <option> [CSN]");
204 PrintAndLog(" options");
205 PrintAndLog(" 0 <CSN> simulate the given CSN");
206 PrintAndLog(" 1 simulate default CSN");
207 PrintAndLog(" 2 Reader-attack, gather reader responses to extract elite key");
208 PrintAndLog(" 3 Full simulation using emulator memory (see 'hf iclass eload')");
209 PrintAndLog(" example: hf iclass sim 0 031FEC8AF7FF12E0");
210 PrintAndLog(" example: hf iclass sim 2");
211 PrintAndLog(" example: hf iclass eload 'tagdump.bin'");
212 PrintAndLog(" hf iclass sim 3");
216 // the original malicious IDs from Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult,
217 // and Milosch Meriac. Dismantling iClass and iClass Elite.
219 static uint8_t csns
[8 * NUM_CSNS
] = {
220 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
221 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0,
222 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0,
223 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0,
224 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0,
225 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0,
226 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0,
227 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0,
228 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0,
229 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0,
230 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0,
231 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0,
232 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0,
233 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0,
234 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 };
237 // pre-defined 9 CSNs by iceman.
238 // only one csn depend on several others.
239 // six depends only on the first csn, (0,1, 0x45)
241 // #define NUM_CSNS 9
242 // static uint8_t csns[8 * NUM_CSNS] = {
243 // 0x01, 0x0A, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
244 // 0x0C, 0x06, 0x0C, 0xFE, 0xF7, 0xFF, 0x12, 0xE0,
245 // 0x10, 0x97, 0x83, 0x7B, 0xF7, 0xFF, 0x12, 0xE0,
246 // 0x13, 0x97, 0x82, 0x7A, 0xF7, 0xFF, 0x12, 0xE0,
247 // 0x07, 0x0E, 0x0D, 0xF9, 0xF7, 0xFF, 0x12, 0xE0,
248 // 0x14, 0x96, 0x84, 0x76, 0xF7, 0xFF, 0x12, 0xE0,
249 // 0x17, 0x96, 0x85, 0x71, 0xF7, 0xFF, 0x12, 0xE0,
250 // 0xCE, 0xC5, 0x0F, 0x77, 0xF7, 0xFF, 0x12, 0xE0,
251 // 0xD2, 0x5A, 0x82, 0xF8, 0xF7, 0xFF, 0x12, 0xE0
252 // //0x04, 0x08, 0x9F, 0x78, 0x6E, 0xFF, 0x12, 0xE0
256 static int CmdHFiClassSim(const char *Cmd
) {
258 uint8_t CSN
[8] = {0, 0, 0, 0, 0, 0, 0, 0};
260 if (strlen(Cmd
) < 1) {
261 usage_hf_iclass_sim();
264 simType
= param_get8ex(Cmd
, 0, 0, 10);
266 if (simType
== ICLASS_SIM_MODE_CSN
) {
267 if (param_gethex(Cmd
, 1, CSN
, 16)) {
268 PrintAndLog("A CSN should consist of 16 HEX symbols");
269 usage_hf_iclass_sim();
272 PrintAndLog("--simtype:%02x csn:%s", simType
, sprint_hex(CSN
, 8));
275 if (simType
== ICLASS_SIM_MODE_READER_ATTACK
) {
276 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
, NUM_CSNS
}};
277 UsbCommand resp
= {0};
279 memcpy(c
.d
.asBytes
, csns
, 8 * NUM_CSNS
);
282 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, -1)) {
283 PrintAndLog("Command timed out");
287 uint8_t num_mac_responses
= resp
.arg
[1];
288 PrintAndLog("Mac responses: %d MACs obtained (should be %d)", num_mac_responses
, NUM_CSNS
);
290 size_t datalen
= NUM_CSNS
* 24;
292 * Now, time to dump to file. We'll use this format:
293 * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
294 * So, it should wind up as
297 * The returndata from the pm3 is on the following format
298 * <8 byte CC><4 byte NR><4 byte MAC>
299 * CSN is the same as was sent in
301 void* dump
= malloc(datalen
);
302 for(int i
= 0; i
< NUM_CSNS
; i
++) {
303 memcpy(dump
+ i
*24, csns
+i
*8, 8); //CSN
304 //copy CC from response
305 memcpy(dump
+ i
*24 + 8, resp
.d
.asBytes
+ i
*16, 8);
306 //Then comes NR_MAC (eight bytes from the response)
307 memcpy(dump
+ i
*24 + 16, resp
.d
.asBytes
+ i
*16 + 8, 8);
309 /** Now, save to dumpfile **/
310 saveFile("iclass_mac_attack", "bin", dump
,datalen
);
313 } else if (simType
== ICLASS_SIM_MODE_CSN
|| simType
== ICLASS_SIM_MODE_CSN_DEFAULT
|| simType
== ICLASS_SIM_MODE_FULL
) {
314 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
, 0}};
315 memcpy(c
.d
.asBytes
, CSN
, 8);
319 PrintAndLog("Undefined simtype %d", simType
);
320 usage_hf_iclass_sim();
328 int HFiClassReader(bool loop
, bool verbose
) {
330 bool tagFound
= false;
331 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
} };
336 if (WaitForResponseTimeout(CMD_ACK
,&resp
, 4500)) {
337 uint8_t readStatus
= resp
.arg
[0] & 0xff;
338 uint8_t *data
= resp
.d
.asBytes
;
341 if (readStatus
== 0 && !loop
) {
343 if (verbose
) PrintAndLog("Quitting...");
348 if (readStatus
& FLAG_ICLASS_READER_CSN
) {
349 PrintAndLog(" CSN: %s",sprint_hex(data
,8));
352 if (readStatus
& FLAG_ICLASS_READER_CC
) {
353 PrintAndLog(" CC: %s",sprint_hex(data
+16,8));
355 if (readStatus
& FLAG_ICLASS_READER_CONF
) {
356 printIclassDumpInfo(data
);
358 if (readStatus
& FLAG_ICLASS_READER_AA
) {
360 PrintAndLog(" AppIA: %s",sprint_hex(data
+8*5,8));
361 for (int i
= 0; i
<8; i
++) {
362 if (data
[8*5+i
] != 0xFF) {
366 PrintAndLog(" : Possible iClass %s",(legacy
) ? "(legacy tag)" : "(NOT legacy tag)");
369 if (tagFound
&& !loop
) return 1;
371 if (verbose
) PrintAndLog("Command execute timeout");
381 static void usage_hf_iclass_reader(void) {
382 PrintAndLogEx(NORMAL
, "Act as a Iclass reader. Look for iClass tags until Enter or the pm3 button is pressed\n");
383 PrintAndLogEx(NORMAL
, "Usage: hf iclass reader [h] [1]\n");
384 PrintAndLogEx(NORMAL
, "Options:");
385 PrintAndLogEx(NORMAL
, " h This help text");
386 PrintAndLogEx(NORMAL
, " 1 read only 1 tag");
387 PrintAndLogEx(NORMAL
, "Examples:");
388 PrintAndLogEx(NORMAL
, " hf iclass reader 1");
392 static int CmdHFiClassReader(const char *Cmd
) {
393 char cmdp
= tolower(param_getchar(Cmd
, 0));
395 usage_hf_iclass_reader();
398 bool findone
= (cmdp
== '1') ? false : true;
399 return HFiClassReader(findone
, true);
403 static void usage_hf_iclass_eload(void) {
404 PrintAndLog("Loads iclass tag-dump into emulator memory on device");
405 PrintAndLog("Usage: hf iclass eload f <filename>");
407 PrintAndLog("Example: hf iclass eload f iclass_tagdump-aa162d30f8ff12f1.bin");
411 static int CmdHFiClassELoad(const char *Cmd
) {
413 char opt
= param_getchar(Cmd
, 0);
414 if (strlen(Cmd
)<1 || opt
== 'h') {
415 usage_hf_iclass_eload();
419 //File handling and reading
421 char filename
[FILE_PATH_SIZE
];
422 if (opt
== 'f' && param_getstr(Cmd
, 1, filename
, sizeof(filename
)) > 0) {
423 f
= fopen(filename
, "rb");
425 usage_hf_iclass_eload();
430 PrintAndLog("Failed to read from file '%s'", filename
);
434 fseek(f
, 0, SEEK_END
);
435 long fsize
= ftell(f
);
436 fseek(f
, 0, SEEK_SET
);
439 PrintAndLog("Error, when getting filesize");
444 uint8_t *dump
= malloc(fsize
);
446 size_t bytes_read
= fread(dump
, 1, fsize
, f
);
449 printIclassDumpInfo(dump
);
452 if (bytes_read
< fsize
) {
453 prnlog("Error, could only read %d bytes (should be %d)",bytes_read
, fsize
);
458 uint32_t bytes_sent
= 0;
459 uint32_t bytes_remaining
= bytes_read
;
461 while (bytes_remaining
> 0) {
462 uint32_t bytes_in_packet
= MIN(USB_CMD_DATA_SIZE
, bytes_remaining
);
463 UsbCommand c
= {CMD_ICLASS_EML_MEMSET
, {bytes_sent
,bytes_in_packet
,0}};
464 memcpy(c
.d
.asBytes
, dump
+bytes_sent
, bytes_in_packet
);
466 bytes_remaining
-= bytes_in_packet
;
467 bytes_sent
+= bytes_in_packet
;
470 PrintAndLog("Sent %d bytes of data to device emulator memory", bytes_sent
);
475 static int readKeyfile(const char *filename
, size_t len
, uint8_t* buffer
) {
476 FILE *f
= fopen(filename
, "rb");
478 PrintAndLog("Failed to read from file '%s'", filename
);
481 fseek(f
, 0, SEEK_END
);
482 long fsize
= ftell(f
);
483 fseek(f
, 0, SEEK_SET
);
484 size_t bytes_read
= fread(buffer
, 1, len
, f
);
488 PrintAndLog("Warning, file size is %d, expected %d", fsize
, len
);
491 if(bytes_read
!= len
)
493 PrintAndLog("Warning, could only read %d bytes, expected %d" ,bytes_read
, len
);
500 static void usage_hf_iclass_decrypt(void) {
501 PrintAndLog("Usage: hf iclass decrypt f <tagdump>");
503 PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside");
504 PrintAndLog("in the working directory. The file should be 16 bytes binary data");
506 PrintAndLog("example: hf iclass decrypt f tagdump_12312342343.bin");
508 PrintAndLog("OBS! This is pretty stupid implementation, it tries to decrypt every block after block 6. ");
509 PrintAndLog("Correct behaviour would be to decrypt only the application areas where the key is valid,");
510 PrintAndLog("which is defined by the configuration block.");
514 static int CmdHFiClassDecrypt(const char *Cmd
) {
515 uint8_t key
[16] = { 0 };
516 if(readKeyfile("iclass_decryptionkey.bin", 16, key
))
518 usage_hf_iclass_decrypt();
521 PrintAndLog("Decryption file found... ");
522 char opt
= param_getchar(Cmd
, 0);
523 if (strlen(Cmd
)<1 || opt
== 'h') {
524 usage_hf_iclass_decrypt();
528 //Open the tagdump-file
530 char filename
[FILE_PATH_SIZE
];
531 if(opt
== 'f' && param_getstr(Cmd
, 1, filename
, sizeof(filename
)) > 0) {
532 f
= fopen(filename
, "rb");
534 PrintAndLog("Could not find file %s", filename
);
538 usage_hf_iclass_decrypt();
542 fseek(f
, 0, SEEK_END
);
543 long fsize
= ftell(f
);
544 fseek(f
, 0, SEEK_SET
);
545 uint8_t enc_dump
[8] = {0};
546 uint8_t *decrypted
= malloc(fsize
);
547 mbedtls_des3_context ctx
= { {0} };
548 mbedtls_des3_set2key_dec( &ctx
, key
);
549 size_t bytes_read
= fread(enc_dump
, 1, 8, f
);
551 //Use the first block (CSN) for filename
552 char outfilename
[FILE_PATH_SIZE
] = { 0 };
553 snprintf(outfilename
,FILE_PATH_SIZE
,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x-decrypted",
554 enc_dump
[0],enc_dump
[1],enc_dump
[2],enc_dump
[3],
555 enc_dump
[4],enc_dump
[5],enc_dump
[6],enc_dump
[7]);
558 while(bytes_read
== 8)
562 memcpy(decrypted
+(blocknum
*8), enc_dump
, 8);
564 mbedtls_des3_crypt_ecb(&ctx
, enc_dump
,decrypted
+(blocknum
*8) );
566 printvar("decrypted block", decrypted
+(blocknum
*8), 8);
567 bytes_read
= fread(enc_dump
, 1, 8, f
);
572 saveFile(outfilename
,"bin", decrypted
, blocknum
*8);
578 static void usage_hf_iclass_encrypt(void) {
579 PrintAndLog("Usage: hf iclass encrypt <BlockData>");
581 PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside");
582 PrintAndLog("in the working directory. The file should be 16 bytes binary data");
584 PrintAndLog("example: hf iclass encrypt 0102030405060708");
589 static int iClassEncryptBlkData(uint8_t *blkData
) {
590 uint8_t key
[16] = { 0 };
591 if(readKeyfile("iclass_decryptionkey.bin", 16, key
))
593 usage_hf_iclass_encrypt();
596 PrintAndLog("Decryption file found... ");
598 uint8_t encryptedData
[16];
599 uint8_t *encrypted
= encryptedData
;
600 mbedtls_des3_context ctx
= { {0} };
601 mbedtls_des3_set2key_enc( &ctx
, key
);
603 mbedtls_des3_crypt_ecb(&ctx
, blkData
,encrypted
);
604 //printvar("decrypted block", decrypted, 8);
605 memcpy(blkData
,encrypted
,8);
611 static int CmdHFiClassEncryptBlk(const char *Cmd
) {
612 uint8_t blkData
[8] = {0};
613 char opt
= param_getchar(Cmd
, 0);
614 if (strlen(Cmd
)<1 || opt
== 'h') {
615 usage_hf_iclass_encrypt();
618 //get the bytes to encrypt
619 if (param_gethex(Cmd
, 0, blkData
, 16)) {
620 PrintAndLog("BlockData must include 16 HEX symbols");
623 if (!iClassEncryptBlkData(blkData
)) return 0;
624 printvar("encrypted block", blkData
, 8);
629 static void Calc_wb_mac(uint8_t blockno
, uint8_t *data
, uint8_t *div_key
, uint8_t MAC
[4]) {
632 memcpy(WB
+1, data
, 8);
633 doMAC_N(WB
, sizeof(WB
), div_key
, MAC
);
634 //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]);
638 static bool iClass_select(uint8_t *CSN
, bool verbose
, bool cleartrace
, bool init
) {
640 UsbCommand c
= {CMD_READER_ICLASS
, {FLAG_ICLASS_READER_CSN
}};
641 if (init
) c
.arg
[0] |= FLAG_ICLASS_READER_INIT
;
642 if (cleartrace
) c
.arg
[0] |= FLAG_ICLASS_READER_CLEARTRACE
;
645 clearCommandBuffer();
647 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
648 PrintAndLog("Command execute timeout");
652 uint8_t isOK
= resp
.arg
[0] & 0xff;
653 uint8_t *data
= resp
.d
.asBytes
;
655 if (isOK
& FLAG_ICLASS_READER_CSN
) {
656 memcpy(CSN
, data
, 8);
657 if (verbose
) PrintAndLog("CSN: %s", sprint_hex(CSN
, 8));
659 PrintAndLog("Failed to select card! Aborting");
666 static void HFiClassCalcDivKey(uint8_t *CSN
, uint8_t *KEY
, uint8_t *div_key
, bool elite
){
667 uint8_t keytable
[128] = {0};
668 uint8_t key_index
[8] = {0};
670 uint8_t key_sel
[8] = { 0 };
671 uint8_t key_sel_p
[8] = { 0 };
672 hash2(KEY
, keytable
);
673 hash1(CSN
, key_index
);
674 for(uint8_t i
= 0; i
< 8 ; i
++)
675 key_sel
[i
] = keytable
[key_index
[i
]] & 0xFF;
677 //Permute from iclass format to standard format
678 permutekey_rev(key_sel
, key_sel_p
);
679 diversifyKey(CSN
, key_sel_p
, div_key
);
681 diversifyKey(CSN
, KEY
, div_key
);
686 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 replay
, bool verbose
) {
689 if (rawkey
|| replay
)
690 memcpy(div_key
, KEY
, 8);
692 HFiClassCalcDivKey(CSN
, KEY
, div_key
, elite
);
694 char keytypetext
[23] = "legacy diversified key";
696 strcpy(keytypetext
, "raw key");
698 strcpy(keytypetext
, "replayed NR/MAC");
700 strcpy(keytypetext
, "Elite diversified key");
703 if (verbose
) PrintAndLog("Authenticating with %s: %s", keytypetext
, sprint_hex(div_key
, 8));
706 UsbCommand d
= {CMD_ICLASS_READCHECK
, {2, use_credit_key
, 0}};
708 clearCommandBuffer();
711 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
712 if (verbose
) PrintAndLog("Auth Command (READCHECK[2]) execute timeout");
715 bool isOK
= resp
.arg
[0];
717 if (verbose
) PrintAndLog("Couldn't get Card Challenge");
722 memcpy(MAC
, KEY
+4, 4);
725 memcpy(CCNR
, resp
.d
.asBytes
, 8);
726 memset(CCNR
+8, 0x00, 4); // default NR = {0, 0, 0, 0}
727 doMAC(CCNR
, div_key
, MAC
);
730 d
.cmd
= CMD_ICLASS_CHECK
;
732 memcpy(d
.d
.asBytes
, KEY
, 8);
734 memset(d
.d
.asBytes
, 0x00, 4); // default NR = {0, 0, 0, 0}
735 memcpy(d
.d
.asBytes
+4, MAC
, 4);
737 clearCommandBuffer();
739 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
740 if (verbose
) PrintAndLog("Auth Command (CHECK) execute timeout");
745 if (verbose
) PrintAndLog("Authentication error");
752 static void usage_hf_iclass_dump(void) {
753 PrintAndLog("Usage: hf iclass dump f <fileName> k <Key> c <CreditKey> e|r|n\n");
754 PrintAndLog("Options:");
755 PrintAndLog(" f <filename> : specify a filename to save dump to");
756 PrintAndLog(" k <Key> : *Debit Key (AA1) as 16 hex symbols (8 bytes) or 1 hex to select key from memory");
757 PrintAndLog(" c <CreditKey>: Credit Key (AA2) as 16 hex symbols (8 bytes) or 1 hex to select key from memory");
758 PrintAndLog(" e : If 'e' is specified, the keys are interpreted as Elite");
759 PrintAndLog(" Custom Keys (KCus), which can be obtained via reader-attack");
760 PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format");
761 PrintAndLog(" r : If 'r' is specified, keys are interpreted as raw blocks 3/4");
762 PrintAndLog(" n : If 'n' is specified, keys are interpreted as NR/MAC pairs which can be obtained by 'hf iclass snoop'");
763 PrintAndLog(" NOTE: * = required");
764 PrintAndLog("Samples:");
765 PrintAndLog(" hf iclass dump k 001122334455667B");
766 PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA c 001122334455667B");
767 PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA e");
771 static void printIclassDumpContents(uint8_t *iclass_dump
, uint8_t startblock
, uint8_t endblock
, size_t filesize
) {
773 memcpy(&mem_config
, iclass_dump
+ 13,1);
775 uint8_t filemaxblock
= filesize
/ 8;
776 if (mem_config
& 0x80)
780 //PrintAndLog ("endblock: %d, filesize: %d, maxmemcount: %d, filemaxblock: %d", endblock,filesize, maxmemcount, filemaxblock);
784 if ((endblock
> maxmemcount
) || (endblock
== 0))
785 endblock
= maxmemcount
;
787 // remember endblock need to relate to zero-index arrays.
788 if (endblock
> filemaxblock
-1)
789 endblock
= filemaxblock
;
792 printf("------+--+-------------------------+\n");
793 while (i
<= endblock
) {
794 uint8_t *blk
= iclass_dump
+ (i
* 8);
795 printf("Block |%02X| %s|\n", i
, sprint_hex(blk
, 8) );
798 printf("------+--+-------------------------+\n");
802 static int CmdHFiClassReader_Dump(const char *Cmd
) {
804 uint8_t MAC
[4] = {0x00,0x00,0x00,0x00};
805 uint8_t div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
806 uint8_t c_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
808 uint8_t AA1_maxBlk
= 0;
810 uint8_t app_areas
= 1;
812 uint8_t KEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
813 uint8_t CreditKEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
816 uint8_t fileNameLen
= 0;
817 char filename
[FILE_PATH_SIZE
]={0};
818 char tempStr
[50] = {0};
819 bool have_debit_key
= false;
820 bool have_credit_key
= false;
821 bool use_credit_key
= false;
824 bool NRMAC_replay
= false;
826 bool verbose
= false;
829 while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) {
830 switch(param_getchar(Cmd
, cmdp
)) {
833 usage_hf_iclass_dump();
837 have_credit_key
= true;
838 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
840 errors
= param_gethex(tempStr
, 0, CreditKEY
, dataLen
);
841 } else if (dataLen
== 1) {
842 keyNbr
= param_get8(Cmd
, cmdp
+1);
843 if (keyNbr
< ICLASS_KEYS_MAX
) {
844 memcpy(CreditKEY
, iClass_Key_Table
[keyNbr
], 8);
846 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
850 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
862 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
863 if (fileNameLen
< 1) {
864 PrintAndLog("No filename found after f");
871 have_debit_key
= true;
872 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
874 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
875 } else if (dataLen
== 1) {
876 keyNbr
= param_get8(Cmd
, cmdp
+1);
877 if (keyNbr
< ICLASS_KEYS_MAX
) {
878 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
880 PrintAndLog("\nERROR: Debit KeyNbr is invalid\n");
884 PrintAndLog("\nERROR: Debit Key is incorrect length\n");
905 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
911 if (elite
+ rawkey
+ NRMAC_replay
> 1) {
912 PrintAndLog("You cannot combine the 'e', 'r', and 'n' options\n");
916 if (errors
|| cmdp
< 2) {
917 usage_hf_iclass_dump();
921 // if only credit key is given: try for AA1 as well (not for iclass but for some picopass this will work)
922 if (!have_debit_key
&& have_credit_key
) {
923 memcpy(KEY
, CreditKEY
, 8);
926 // clear trace and get first 3 blocks
927 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
}};
929 uint8_t tag_data
[256*8];
931 clearCommandBuffer();
933 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
934 PrintAndLog("Command execute timeout");
939 uint8_t readStatus
= resp
.arg
[0] & 0xff;
940 uint8_t *data
= resp
.d
.asBytes
;
941 uint8_t status_mask
= FLAG_ICLASS_READER_CSN
| FLAG_ICLASS_READER_CONF
| FLAG_ICLASS_READER_CC
;
943 if (readStatus
!= status_mask
) {
944 PrintAndLog("No tag found ...");
947 memcpy(tag_data
, data
, 8*3);
948 if (verbose
) PrintAndLog("CSN: %s", sprint_hex(tag_data
, 8));
949 AA1_maxBlk
= data
[8];
950 getMemConfig(data
[13], data
[12], &maxBlk
, &app_areas
, &kb
);
951 // large memory - not able to dump pages currently
952 if (AA1_maxBlk
> maxBlk
) AA1_maxBlk
= maxBlk
;
955 // authenticate with debit key (or credit key if we have no debit key) and get div_key - later store in dump block 3
956 if (!iClass_authenticate(tag_data
, KEY
, MAC
, div_key
, false, elite
, rawkey
, NRMAC_replay
, verbose
)) {
962 UsbCommand w
= {CMD_ICLASS_DUMP
};
963 uint32_t blocksRead
= 0;
964 for (blockno
= 3; blockno
<= AA1_maxBlk
; blockno
+= blocksRead
) {
966 w
.arg
[1] = AA1_maxBlk
- blockno
+ 1;
967 clearCommandBuffer();
969 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
970 PrintAndLog("Command execute time-out 1");
974 blocksRead
= resp
.arg
[1];
975 bool isOK
= resp
.arg
[0];
977 PrintAndLog("Reading AA1 block failed");
981 memcpy(tag_data
+ blockno
*8, resp
.d
.asBytes
, blocksRead
*8);
984 // do we still need to read more blocks (AA2 enabled)?
985 if (have_credit_key
&& maxBlk
> AA1_maxBlk
) {
986 if (!use_credit_key
) {
987 //turn off hf field before authenticating with different key
989 // AA2 authenticate credit key and git c_div_key - later store in dump block 4
991 if (!iClass_select(CSN
, verbose
, false, true) || !iClass_authenticate(CSN
, CreditKEY
, MAC
, c_div_key
, true, false, false, NRMAC_replay
, verbose
)){
996 for ( ; blockno
<= maxBlk
; blockno
+= blocksRead
) {
998 w
.arg
[1] = maxBlk
- blockno
+ 1;
999 clearCommandBuffer();
1001 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
1002 PrintAndLog("Command execute time-out 1");
1006 blocksRead
= resp
.arg
[1];
1007 bool isOK
= resp
.arg
[0];
1009 PrintAndLog("Reading AA2 block failed");
1013 memcpy(tag_data
+ blockno
*8, resp
.d
.asBytes
, blocksRead
*8);
1019 // add diversified keys to dump
1020 if (have_debit_key
) {
1021 memcpy(tag_data
+ 3*8, div_key
, 8);
1023 memset(tag_data
+ 3*8, 0xff, 8);
1025 if (have_credit_key
) {
1026 memcpy(tag_data
+ 4*8, c_div_key
, 8);
1028 memset(tag_data
+ 4*8, 0xff, 8);
1032 printf("------+--+-------------------------+\n");
1033 printf("CSN |00| %s|\n",sprint_hex(tag_data
, 8));
1034 printIclassDumpContents(tag_data
, 1, blockno
-1, blockno
*8);
1036 if (filename
[0] == 0) {
1037 snprintf(filename
, FILE_PATH_SIZE
,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x",
1038 tag_data
[0],tag_data
[1],tag_data
[2],tag_data
[3],
1039 tag_data
[4],tag_data
[5],tag_data
[6],tag_data
[7]);
1042 // save the dump to .bin file
1043 PrintAndLog("Saving dump file - %d blocks read", blockno
);
1044 saveFile(filename
, "bin", tag_data
, blockno
*8);
1049 static int WriteBlock(uint8_t blockno
, uint8_t *bldata
, uint8_t *KEY
, bool use_credit_key
, bool elite
, bool rawkey
, bool NRMAC_replay
, bool verbose
) {
1051 uint8_t MAC
[4] = {0x00,0x00,0x00,0x00};
1052 uint8_t div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1055 if (!iClass_select(CSN
, verbose
, true, true) || !iClass_authenticate(CSN
, KEY
, MAC
, div_key
, use_credit_key
, elite
, rawkey
, NRMAC_replay
, verbose
)) {
1062 Calc_wb_mac(blockno
, bldata
, div_key
, MAC
);
1064 UsbCommand w
= {CMD_ICLASS_WRITEBLOCK
, {blockno
}};
1065 memcpy(w
.d
.asBytes
, bldata
, 8);
1066 memcpy(w
.d
.asBytes
+ 8, MAC
, 4);
1068 clearCommandBuffer();
1070 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
1071 PrintAndLog("Write Command execute timeout");
1075 bool isOK
= resp
.arg
[0];
1077 PrintAndLog("Write Block Failed");
1082 PrintAndLog("Write Block Successful");
1087 static void usage_hf_iclass_writeblock(void) {
1088 PrintAndLog("Options:");
1089 PrintAndLog(" b <Block> : The block number as 2 hex symbols");
1090 PrintAndLog(" d <data> : Set the Data to write as 16 hex symbols");
1091 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
1092 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
1093 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
1094 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
1095 PrintAndLog(" o : override protection and allow modification of blocks 0...4");
1096 PrintAndLog("Samples:");
1097 PrintAndLog(" hf iclass writeblk b 0A d AAAAAAAAAAAAAAAA k 001122334455667B");
1098 PrintAndLog(" hf iclass writeblk b 1B d AAAAAAAAAAAAAAAA k 001122334455667B c");
1099 PrintAndLog(" hf iclass writeblk b 03 d AAAAAAAAAAAAAAAA k 001122334455667B c o");
1103 static int CmdHFiClass_WriteBlock(const char *Cmd
) {
1104 uint8_t blockno
= 0;
1105 uint8_t bldata
[8] = {0};
1106 uint8_t KEY
[8] = {0};
1108 uint8_t dataLen
= 0;
1109 char tempStr
[50] = {0};
1110 bool use_credit_key
= false;
1112 bool rawkey
= false;
1113 bool override_protection
= false;
1114 bool errors
= false;
1117 while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) {
1118 switch(param_getchar(Cmd
, cmdp
)) {
1121 usage_hf_iclass_writeblock();
1125 if (param_gethex(Cmd
, cmdp
+1, &blockno
, 2)) {
1126 PrintAndLog("Block No must include 2 HEX symbols\n");
1133 use_credit_key
= true;
1138 if (param_gethex(Cmd
, cmdp
+1, bldata
, 16)) {
1139 PrintAndLog("Data must include 16 HEX symbols\n");
1151 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1152 if (dataLen
== 16) {
1153 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1154 } else if (dataLen
== 1) {
1155 keyNbr
= param_get8(Cmd
, cmdp
+1);
1156 if (keyNbr
< ICLASS_KEYS_MAX
) {
1157 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
1159 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1163 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1175 override_protection
= true;
1179 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1184 usage_hf_iclass_writeblock();
1189 if (elite
&& rawkey
) {
1190 PrintAndLog("You cannot combine the 'e' and 'r' options\n");
1195 usage_hf_iclass_writeblock();
1200 if (override_protection
) {
1201 PrintAndLog("Info: modifying keys, e-purse or configuration block.");
1203 PrintAndLog("You are going to modify keys, e-purse or configuration block.");
1204 PrintAndLog("You must add the 'o' (override) option to confirm that you know what you are doing");
1209 int ans
= WriteBlock(blockno
, bldata
, KEY
, use_credit_key
, elite
, rawkey
, false, true);
1216 static void usage_hf_iclass_clone(void) {
1217 PrintAndLog("Usage: hf iclass clone f <tagfile.bin> b <first block> l <last block> k <KEY> c e|r o");
1218 PrintAndLog("Options:");
1219 PrintAndLog(" f <filename>: specify a filename to clone from");
1220 PrintAndLog(" b <Block> : The first block to clone as 2 hex symbols");
1221 PrintAndLog(" l <Last Blk>: The last block to clone as 2 hex symbols");
1222 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
1223 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
1224 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
1225 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
1226 PrintAndLog(" o : override protection and allow modification of target blocks 0...4");
1227 PrintAndLog("Samples:");
1228 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 1A k 1122334455667788 e");
1229 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 05 l 19 k 0");
1230 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 19 k 0 e");
1231 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 19 k 0 e");
1232 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 03 l 19 k 0 e o");
1236 static int CmdHFiClassCloneTag(const char *Cmd
) {
1237 char filename
[FILE_PATH_SIZE
] = {0};
1238 char tempStr
[50]={0};
1239 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1241 uint8_t fileNameLen
= 0;
1242 uint8_t startblock
= 0;
1243 uint8_t endblock
= 0;
1244 uint8_t dataLen
= 0;
1245 bool use_credit_key
= false;
1247 bool rawkey
= false;
1248 bool override_protection
= false;
1249 bool errors
= false;
1252 while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) {
1253 switch (param_getchar(Cmd
, cmdp
)) {
1256 usage_hf_iclass_clone();
1260 if (param_gethex(Cmd
, cmdp
+1, &startblock
, 2)) {
1261 PrintAndLog("Start Block No must include 2 HEX symbols\n");
1268 use_credit_key
= true;
1278 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
1279 if (fileNameLen
< 1) {
1280 PrintAndLog("No filename found after f");
1287 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1288 if (dataLen
== 16) {
1289 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1290 } else if (dataLen
== 1) {
1291 keyNbr
= param_get8(Cmd
, cmdp
+1);
1292 if (keyNbr
< ICLASS_KEYS_MAX
) {
1293 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
1295 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1299 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1306 if (param_gethex(Cmd
, cmdp
+1, &endblock
, 2)) {
1307 PrintAndLog("Last Block No must include 2 HEX symbols\n");
1319 override_protection
= true;
1323 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1328 usage_hf_iclass_clone();
1334 usage_hf_iclass_clone();
1338 if (startblock
< 5) {
1339 if (override_protection
) {
1340 PrintAndLog("Info: modifying keys, e-purse or configuration block.");
1342 PrintAndLog("You are going to modify keys, e-purse or configuration block.");
1343 PrintAndLog("You must add the 'o' (override) option to confirm that you know what you are doing");
1348 if ((endblock
- startblock
+ 1) * 12 > USB_CMD_DATA_SIZE
) {
1349 PrintAndLog("Trying to write too many blocks at once. Max: %d", USB_CMD_DATA_SIZE
/12);
1352 // file handling and reading
1354 f
= fopen(filename
,"rb");
1356 PrintAndLog("Failed to read from file '%s'", filename
);
1360 uint8_t tag_data
[USB_CMD_DATA_SIZE
/12][8];
1361 fseek(f
, startblock
*8, SEEK_SET
);
1362 for (int i
= 0; i
< endblock
- startblock
+ 1; i
++) {
1363 if (fread(&tag_data
[i
], 1, 8, f
) == 0 ) {
1364 PrintAndLog("File reading error.");
1370 uint8_t MAC
[4] = {0x00, 0x00, 0x00, 0x00};
1371 uint8_t div_key
[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1374 if (!iClass_select(CSN
, true, true, true) || !iClass_authenticate(CSN
, KEY
, MAC
, div_key
, use_credit_key
, elite
, rawkey
, false, true)) {
1379 UsbCommand w
= {CMD_ICLASS_CLONE
, {startblock
, endblock
}};
1381 // calculate MAC for every block we will write
1382 for (int i
= 0; i
< endblock
- startblock
+ 1; i
++) {
1383 Calc_wb_mac(startblock
+ i
, tag_data
[i
], div_key
, MAC
);
1384 ptr
= w
.d
.asBytes
+ i
* 12;
1385 memcpy(ptr
, tag_data
[i
], 8);
1386 memcpy(ptr
+ 8, MAC
, 4);
1390 PrintAndLog("Cloning");
1391 for (int i
= 0; i
< endblock
- startblock
+ 1; i
++){
1392 memcpy(p
, w
.d
.asBytes
+ (i
* 12), 12);
1393 PrintAndLog("Block |%02x| %02x%02x%02x%02x%02x%02x%02x%02x | MAC |%02x%02x%02x%02x|",
1394 i
+ startblock
, p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6], p
[7], p
[8], p
[9], p
[10], p
[11]);
1399 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
1400 PrintAndLog("Command execute timeout");
1410 static int ReadBlock(uint8_t *KEY
, uint8_t blockno
, uint8_t keyType
, bool elite
, bool rawkey
, bool NRMAC_replay
, bool verbose
, bool auth
) {
1412 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
1413 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1416 if (!iClass_select(CSN
, verbose
, true, true)) {
1422 if (!iClass_authenticate(CSN
, KEY
, MAC
, div_key
, (keyType
==0x18), elite
, rawkey
, NRMAC_replay
, verbose
)) {
1429 UsbCommand w
= {CMD_ICLASS_READBLOCK
, {blockno
}};
1430 clearCommandBuffer();
1432 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
1433 PrintAndLog("Command execute timeout");
1437 bool isOK
= resp
.arg
[0];
1439 PrintAndLog("Read Block Failed");
1443 //data read is stored in: resp.d.asBytes[0-15]
1445 PrintAndLog("Block %02X: %s\n",blockno
, sprint_hex(resp
.d
.asBytes
,8));
1451 static void usage_hf_iclass_readblock(void) {
1452 PrintAndLog("Usage: hf iclass readblk b <Block> k <Key> [c] [e|r|n]\n");
1453 PrintAndLog("Options:");
1454 PrintAndLog(" b <Block> : The block number as 2 hex symbols");
1455 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
1456 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
1457 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
1458 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
1459 PrintAndLog(" n : If 'n' is specified, <Key> specifies a NR/MAC pair which can be obtained by 'hf iclass snoop'");
1460 PrintAndLog("Samples:");
1461 PrintAndLog(" hf iclass readblk b 06 k 0011223344556677");
1462 PrintAndLog(" hf iclass readblk b 1B k 0011223344556677 c");
1463 PrintAndLog(" hf iclass readblk b 0A k 0");
1467 static int CmdHFiClass_ReadBlock(const char *Cmd
) {
1469 uint8_t keyType
= 0x88; //debit key
1470 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1472 uint8_t dataLen
= 0;
1473 char tempStr
[50] = {0};
1475 bool rawkey
= false;
1476 bool NRMAC_replay
= false;
1477 bool errors
= false;
1481 while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) {
1482 switch (param_getchar(Cmd
, cmdp
)) {
1485 usage_hf_iclass_readblock();
1489 if (param_gethex(Cmd
, cmdp
+1, &blockno
, 2)) {
1490 PrintAndLog("Block No must include 2 HEX symbols\n");
1508 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1509 if (dataLen
== 16) {
1510 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1511 } else if (dataLen
== 1) {
1512 keyNbr
= param_get8(Cmd
, cmdp
+1);
1513 if (keyNbr
< ICLASS_KEYS_MAX
) {
1514 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
1516 PrintAndLog("\nERROR: KeyNbr is invalid\n");
1520 PrintAndLog("\nERROR: Key is incorrect length\n");
1532 NRMAC_replay
= true;
1536 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1542 if (elite
+ rawkey
+ NRMAC_replay
> 1) {
1543 PrintAndLog("You cannot combine the 'e', 'r', and 'n' options\n");
1548 usage_hf_iclass_readblock();
1553 usage_hf_iclass_readblock();
1557 PrintAndLog("warning: no authentication used with read, only a few specific blocks can be read accurately without authentication.");
1559 return ReadBlock(KEY
, blockno
, keyType
, elite
, rawkey
, NRMAC_replay
, true, auth
);
1563 static int CmdHFiClass_loclass(const char *Cmd
) {
1564 char opt
= param_getchar(Cmd
, 0);
1566 if (strlen(Cmd
)<1 || opt
== 'h') {
1567 PrintAndLog("Usage: hf iclass loclass [options]");
1568 PrintAndLog("Options:");
1569 PrintAndLog("h Show this help");
1570 PrintAndLog("t Perform self-test");
1571 PrintAndLog("f <filename> Bruteforce iclass dumpfile");
1572 PrintAndLog(" An iclass dumpfile is assumed to consist of an arbitrary number of");
1573 PrintAndLog(" malicious CSNs, and their protocol responses");
1574 PrintAndLog(" The binary format of the file is expected to be as follows: ");
1575 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1576 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1577 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1578 PrintAndLog(" ... totalling N*24 bytes");
1581 char fileName
[255] = {0};
1583 if(param_getstr(Cmd
, 1, fileName
, sizeof(fileName
)) > 0) {
1584 return bruteforceFileNoKeys(fileName
);
1586 PrintAndLog("You must specify a filename");
1588 } else if(opt
== 't') {
1589 int errors
= testCipherUtils();
1590 errors
+= testMAC();
1591 errors
+= doKeyTests(0);
1592 errors
+= testElite();
1594 prnlog("OBS! There were errors!!!");
1603 static void usage_hf_iclass_readtagfile() {
1604 PrintAndLog("Usage: hf iclass readtagfile <filename> [startblock] [endblock]");
1608 static int CmdHFiClassReadTagFile(const char *Cmd
) {
1613 char filename
[FILE_PATH_SIZE
];
1614 if (param_getstr(Cmd
, 0, filename
, sizeof(filename
)) < 1) {
1615 usage_hf_iclass_readtagfile();
1618 if (param_getstr(Cmd
, 1, tempnum
, sizeof(tempnum
)) < 1)
1621 sscanf(tempnum
,"%d",&startblock
);
1623 if (param_getstr(Cmd
,2, tempnum
, sizeof(tempnum
)) < 1)
1626 sscanf(tempnum
,"%d",&endblock
);
1627 // file handling and reading
1628 f
= fopen(filename
,"rb");
1630 PrintAndLog("Failed to read from file '%s'", filename
);
1633 fseek(f
, 0, SEEK_END
);
1634 long fsize
= ftell(f
);
1635 fseek(f
, 0, SEEK_SET
);
1638 PrintAndLog("Error, when getting filesize");
1643 uint8_t *dump
= malloc(fsize
);
1645 size_t bytes_read
= fread(dump
, 1, fsize
, f
);
1647 uint8_t *csn
= dump
;
1648 printf("------+--+-------------------------+\n");
1649 printf("CSN |00| %s|\n", sprint_hex(csn
, 8) );
1650 // printIclassDumpInfo(dump);
1651 printIclassDumpContents(dump
,startblock
,endblock
,bytes_read
);
1657 uint64_t xorcheck(uint64_t sdiv,uint64_t hdiv) {
1658 uint64_t new_div = 0x00;
1664 uint64_t hexarray_to_uint64(uint8_t *key) {
1667 for (int i = 0;i < 8;i++)
1668 sprintf(&temp[(i *2)],"%02X",key[i]);
1670 if (sscanf(temp,"%016" SCNx64,&uint_key) < 1)
1677 //when told CSN, oldkey, newkey, if new key is elite (elite), and if old key was elite (oldElite)
1678 //calculate and return xor_div_key (ready for a key write command)
1679 //print all div_keys if verbose
1680 static void HFiClassCalcNewKey(uint8_t *CSN
, uint8_t *OLDKEY
, uint8_t *NEWKEY
, uint8_t *xor_div_key
, bool elite
, bool oldElite
, bool verbose
){
1681 uint8_t old_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1682 uint8_t new_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1684 HFiClassCalcDivKey(CSN
, OLDKEY
, old_div_key
, oldElite
);
1686 HFiClassCalcDivKey(CSN
, NEWKEY
, new_div_key
, elite
);
1688 for (uint8_t i
= 0; i
< sizeof(old_div_key
); i
++){
1689 xor_div_key
[i
] = old_div_key
[i
] ^ new_div_key
[i
];
1692 printf("Old Div Key : %s\n",sprint_hex(old_div_key
,8));
1693 printf("New Div Key : %s\n",sprint_hex(new_div_key
,8));
1694 printf("Xor Div Key : %s\n",sprint_hex(xor_div_key
,8));
1699 static void usage_hf_iclass_calc_newkey(void) {
1700 PrintAndLog("HELP : Manage iClass Keys in client memory:\n");
1701 PrintAndLog("Usage: hf iclass calc_newkey o <Old key> n <New key> s [csn] e");
1702 PrintAndLog(" Options:");
1703 PrintAndLog(" o <oldkey> : *specify a key as 16 hex symbols or a key number as 1 symbol");
1704 PrintAndLog(" n <newkey> : *specify a key as 16 hex symbols or a key number as 1 symbol");
1705 PrintAndLog(" s <csn> : specify a card Serial number to diversify the key (if omitted will attempt to read a csn)");
1706 PrintAndLog(" e : specify new key as elite calc");
1707 PrintAndLog(" ee : specify old and new key as elite calc");
1708 PrintAndLog("Samples:");
1709 PrintAndLog(" e key to e key given csn : hf iclass calcnewkey o 1122334455667788 n 2233445566778899 s deadbeafdeadbeaf ee");
1710 PrintAndLog(" std key to e key read csn: hf iclass calcnewkey o 1122334455667788 n 2233445566778899 e");
1711 PrintAndLog(" std to std read csn : hf iclass calcnewkey o 1122334455667788 n 2233445566778899");
1712 PrintAndLog("NOTE: * = required\n");
1716 static int CmdHFiClassCalcNewKey(const char *Cmd
) {
1717 uint8_t OLDKEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1718 uint8_t NEWKEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1719 uint8_t xor_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1720 uint8_t CSN
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1722 uint8_t dataLen
= 0;
1723 char tempStr
[50] = {0};
1724 bool givenCSN
= false;
1725 bool oldElite
= false;
1727 bool errors
= false;
1730 while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) {
1731 switch(param_getchar(Cmd
, cmdp
)) {
1734 usage_hf_iclass_calc_newkey();
1738 dataLen
= param_getstr(Cmd
, cmdp
, tempStr
, sizeof(tempStr
));
1746 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1747 if (dataLen
== 16) {
1748 errors
= param_gethex(tempStr
, 0, NEWKEY
, dataLen
);
1749 } else if (dataLen
== 1) {
1750 keyNbr
= param_get8(Cmd
, cmdp
+1);
1751 if (keyNbr
< ICLASS_KEYS_MAX
) {
1752 memcpy(NEWKEY
, iClass_Key_Table
[keyNbr
], 8);
1754 PrintAndLog("\nERROR: NewKey Nbr is invalid\n");
1758 PrintAndLog("\nERROR: NewKey is incorrect length\n");
1765 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1766 if (dataLen
== 16) {
1767 errors
= param_gethex(tempStr
, 0, OLDKEY
, dataLen
);
1768 } else if (dataLen
== 1) {
1769 keyNbr
= param_get8(Cmd
, cmdp
+1);
1770 if (keyNbr
< ICLASS_KEYS_MAX
) {
1771 memcpy(OLDKEY
, iClass_Key_Table
[keyNbr
], 8);
1773 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1777 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1785 if (param_gethex(Cmd
, cmdp
+1, CSN
, 16)) {
1786 usage_hf_iclass_calc_newkey();
1792 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1797 usage_hf_iclass_calc_newkey();
1803 usage_hf_iclass_calc_newkey();
1808 if (!iClass_select(CSN
, true, true, true)) {
1814 HFiClassCalcNewKey(CSN
, OLDKEY
, NEWKEY
, xor_div_key
, elite
, oldElite
, true);
1819 static int loadKeys(char *filename
) {
1821 f
= fopen(filename
,"rb");
1823 PrintAndLog("Failed to read from file '%s'", filename
);
1826 fseek(f
, 0, SEEK_END
);
1827 long fsize
= ftell(f
);
1828 fseek(f
, 0, SEEK_SET
);
1831 PrintAndLog("Error, when getting filesize");
1836 uint8_t *dump
= malloc(fsize
);
1838 size_t bytes_read
= fread(dump
, 1, fsize
, f
);
1840 if (bytes_read
> ICLASS_KEYS_MAX
* 8){
1841 PrintAndLog("File is too long to load - bytes: %u", bytes_read
);
1846 for (; i
< bytes_read
/8; i
++){
1847 memcpy(iClass_Key_Table
[i
],dump
+(i
*8),8);
1850 PrintAndLog("%u keys loaded", i
);
1855 static int saveKeys(char *filename
) {
1857 f
= fopen(filename
,"wb");
1859 printf("error opening file %s\n",filename
);
1862 for (uint8_t i
= 0; i
< ICLASS_KEYS_MAX
; i
++){
1863 if (fwrite(iClass_Key_Table
[i
],8,1,f
) != 1){
1864 PrintAndLog("save key failed to write to file: %s", filename
);
1873 static int printKeys(void) {
1875 for (uint8_t i
= 0; i
< ICLASS_KEYS_MAX
; i
++){
1876 PrintAndLog("%u: %s",i
,sprint_hex(iClass_Key_Table
[i
],8));
1883 static void usage_hf_iclass_managekeys(void) {
1884 PrintAndLog("HELP : Manage iClass Keys in client memory:\n");
1885 PrintAndLog("Usage: hf iclass managekeys n [keynbr] k [key] f [filename] s l p\n");
1886 PrintAndLog(" Options:");
1887 PrintAndLog(" n <keynbr> : specify the keyNbr to set in memory");
1888 PrintAndLog(" k <key> : set a key in memory");
1889 PrintAndLog(" f <filename>: specify a filename to use with load or save operations");
1890 PrintAndLog(" s : save keys in memory to file specified by filename");
1891 PrintAndLog(" l : load keys to memory from file specified by filename");
1892 PrintAndLog(" p : print keys loaded into memory\n");
1893 PrintAndLog("Samples:");
1894 PrintAndLog(" set key : hf iclass managekeys n 0 k 1122334455667788");
1895 PrintAndLog(" save key file: hf iclass managekeys f mykeys.bin s");
1896 PrintAndLog(" load key file: hf iclass managekeys f mykeys.bin l");
1897 PrintAndLog(" print keys : hf iclass managekeys p\n");
1901 static int CmdHFiClassManageKeys(const char *Cmd
) {
1903 uint8_t dataLen
= 0;
1904 uint8_t KEY
[8] = {0};
1905 char filename
[FILE_PATH_SIZE
];
1906 uint8_t fileNameLen
= 0;
1907 bool errors
= false;
1908 uint8_t operation
= 0;
1912 while(param_getchar(Cmd
, cmdp
) != 0x00) {
1913 switch(param_getchar(Cmd
, cmdp
)) {
1916 usage_hf_iclass_managekeys();
1920 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
1921 if (fileNameLen
< 1) {
1922 PrintAndLog("No filename found after f");
1929 keyNbr
= param_get8(Cmd
, cmdp
+1);
1930 if (keyNbr
>= ICLASS_KEYS_MAX
) {
1931 PrintAndLog("Invalid block number");
1938 operation
+= 3; //set key
1939 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1940 if (dataLen
== 16) { //ul-c or ev1/ntag key length
1941 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1943 PrintAndLog("\nERROR: Key is incorrect length\n");
1950 operation
+= 4; //print keys in memory
1955 operation
+= 5; //load keys from file
1960 operation
+= 6; //save keys to file
1964 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1969 usage_hf_iclass_managekeys();
1974 if (operation
== 0){
1975 PrintAndLog("no operation specified (load, save, or print)\n");
1976 usage_hf_iclass_managekeys();
1981 PrintAndLog("Too many operations specified\n");
1982 usage_hf_iclass_managekeys();
1985 if (operation
> 4 && fileNameLen
== 0){
1986 PrintAndLog("You must enter a filename when loading or saving\n");
1987 usage_hf_iclass_managekeys();
1992 case 3: memcpy(iClass_Key_Table
[keyNbr
], KEY
, 8); return 1;
1993 case 4: return printKeys();
1994 case 5: return loadKeys(filename
);
1995 case 6: return saveKeys(filename
);
2002 static int CmdHFiClassCheckKeys(const char *Cmd
) {
2004 uint8_t mac
[4] = {0x00,0x00,0x00,0x00};
2005 uint8_t key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
2006 uint8_t div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
2008 // elite key, raw key, standard key
2009 bool use_elite
= false;
2010 bool use_raw
= false;
2011 bool found_debit
= false;
2012 bool found_credit
= false;
2013 bool errors
= false;
2014 uint8_t cmdp
= 0x00;
2016 char filename
[FILE_PATH_SIZE
] = {0};
2017 uint8_t fileNameLen
= 0;
2019 uint8_t *keyBlock
= NULL
, *p
;
2022 while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) {
2023 switch (param_getchar(Cmd
, cmdp
)) {
2026 usage_hf_iclass_chk();
2030 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
2031 if (fileNameLen
< 1) {
2032 PrintAndLog("No filename found after f");
2048 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
2055 usage_hf_iclass_chk();
2059 if (!(f
= fopen(filename
, "r"))) {
2060 PrintAndLog("File %s not found or locked.", filename
);
2064 while (fgets(buf
, sizeof(buf
), f
)) {
2065 if (strlen(buf
) < 16 || buf
[15] == '\n')
2068 while (fgetc(f
) != '\n' && !feof(f
)) ; //goto next line
2070 if (buf
[0] == '#') continue; //The line start with # is comment, skip
2072 if (!isxdigit(buf
[0])){
2073 PrintAndLog("File content error. '%s' must include 16 HEX symbols", buf
);
2079 p
= realloc(keyBlock
, 8 * (keycnt
+ 1));
2081 PrintAndLog("Cannot allocate memory for default keys");
2088 memset(keyBlock
+ 8 * keycnt
, 0, 8);
2089 num_to_bytes(strtoull(buf
, NULL
, 16), 8, keyBlock
+ 8 * keycnt
);
2092 memset(buf
, 0, sizeof(buf
));
2095 PrintAndLog("Loaded %2d keys from %s", keycnt
, filename
);
2098 if (!iClass_select(CSN
, false, true, true)) {
2103 for (uint32_t c
= 0; c
< keycnt
; c
++) {
2105 memcpy(key
, keyBlock
+ 8 * c
, 8);
2108 if (iClass_authenticate(CSN
, key
, mac
, div_key
, false, use_elite
, use_raw
, false, false)) {
2109 PrintAndLog("\n Found AA1 debit key\t\t[%s]", sprint_hex(key
, 8));
2114 if (iClass_authenticate(CSN
, key
, mac
, div_key
, true, use_elite
, use_raw
, false, false)) {
2115 PrintAndLog("\n Found AA2 credit key\t\t[%s]", sprint_hex(key
, 8));
2116 found_credit
= true;
2120 if (found_debit
&& found_credit
)
2131 static void usage_hf_iclass_permutekey(void) {
2132 PrintAndLogEx(NORMAL
, "Convert keys from standard NIST to iClass format (and vice versa)");
2133 PrintAndLogEx(NORMAL
, "");
2134 PrintAndLogEx(NORMAL
, "Usage: hf iclass permute [h] [r] <key>");
2135 PrintAndLogEx(NORMAL
, "Options:");
2136 PrintAndLogEx(NORMAL
, " h This help");
2137 PrintAndLogEx(NORMAL
, " r reverse convert key from iClass to NIST format");
2138 PrintAndLogEx(NORMAL
, "");
2139 PrintAndLogEx(NORMAL
, "Examples:");
2140 PrintAndLogEx(NORMAL
, " hf iclass permute r 0123456789abcdef");
2144 static int CmdHFiClassPermuteKey(const char *Cmd
) {
2146 uint8_t key
[8] = {0};
2147 uint8_t data
[16] = {0};
2148 bool isReverse
= false;
2149 int len
= sizeof(data
);
2150 char cmdp
= tolower(param_getchar(Cmd
, 0));
2151 if (strlen(Cmd
) == 0 || cmdp
== 'h') {
2152 usage_hf_iclass_permutekey();
2158 param_gethex_ex(Cmd
, 1, data
, &len
);
2159 } else if (cmdp
== 'f') {
2160 param_gethex_ex(Cmd
, 1, data
, &len
);
2162 param_gethex_ex(Cmd
, 0, data
, &len
);
2167 usage_hf_iclass_permutekey();
2173 memcpy(key
, data
, 8);
2176 // generate_rev(data, len);
2177 uint8_t key_std_format
[8] = {0};
2178 permutekey_rev(key
, key_std_format
);
2179 PrintAndLogEx(SUCCESS
, "key in standard NIST format: %s \n", sprint_hex(key_std_format
, 8));
2180 // if (mbedtls_des_key_check_key_parity(key_std_format
2182 // generate(data, len);
2183 uint8_t key_iclass_format
[8] = {0};
2184 permutekey(key
, key_iclass_format
);
2185 PrintAndLogEx(SUCCESS
, "key in iClass (permuted) format: %s \n", sprint_hex(key_iclass_format
, 8));
2191 static int CmdHelp(const char *Cmd
);
2193 static command_t CommandTable
[] = {
2194 {"help", CmdHelp
, 1, "This help"},
2195 {"calcnewkey", CmdHFiClassCalcNewKey
, 1, "[options..] Calc Diversified keys (blocks 3 & 4) to write new keys"},
2196 {"chk", CmdHFiClassCheckKeys
, 0, " Check keys"},
2197 {"clone", CmdHFiClassCloneTag
, 0, "[options..] Authenticate and Clone from iClass bin file"},
2198 {"decrypt", CmdHFiClassDecrypt
, 1, "[f <fname>] Decrypt tagdump" },
2199 {"dump", CmdHFiClassReader_Dump
, 0, "[options..] Authenticate and Dump iClass tag's AA1 and/or AA2"},
2200 {"eload", CmdHFiClassELoad
, 0, "[f <fname>] (experimental) Load data into iClass emulator memory"},
2201 {"encryptblk", CmdHFiClassEncryptBlk
, 1, "<BlockData> Encrypt given block data"},
2202 {"list", CmdHFiClassList
, 0, " (Deprecated) List iClass history"},
2203 {"loclass", CmdHFiClass_loclass
, 1, "[options..] Use loclass to perform bruteforce of reader attack dump"},
2204 {"managekeys", CmdHFiClassManageKeys
, 1, "[options..] Manage the keys to use with iClass"},
2205 {"permutekey", CmdHFiClassPermuteKey
, 1, " iClass key permutation"},
2206 {"readblk", CmdHFiClass_ReadBlock
, 0, "[options..] Authenticate and Read iClass block"},
2207 {"reader", CmdHFiClassReader
, 0, " Look for iClass tags until a key or the pm3 button is pressed"},
2208 {"readtagfile", CmdHFiClassReadTagFile
, 1, "[options..] Display Content from tagfile"},
2209 {"sim", CmdHFiClassSim
, 0, "[options..] Simulate iClass tag"},
2210 {"snoop", CmdHFiClassSnoop
, 0, " Eavesdrop iClass communication"},
2211 {"writeblk", CmdHFiClass_WriteBlock
, 0, "[options..] Authenticate and Write iClass block"},
2212 {NULL
, NULL
, 0, NULL
}
2216 int CmdHFiClass(const char *Cmd
) {
2217 clearCommandBuffer();
2218 CmdsParse(CommandTable
, Cmd
);
2223 int CmdHelp(const char *Cmd
) {
2224 CmdsHelp(CommandTable
);