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
, 1000)) {
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("Error: No response from Proxmark.");
382 static void usage_hf_iclass_reader(void) {
383 PrintAndLogEx(NORMAL
, "Act as a Iclass reader. Look for iClass tags until Enter or the pm3 button is pressed\n");
384 PrintAndLogEx(NORMAL
, "Usage: hf iclass reader [h] [1]\n");
385 PrintAndLogEx(NORMAL
, "Options:");
386 PrintAndLogEx(NORMAL
, " h This help text");
387 PrintAndLogEx(NORMAL
, " 1 read only 1 tag");
388 PrintAndLogEx(NORMAL
, "Examples:");
389 PrintAndLogEx(NORMAL
, " hf iclass reader 1");
393 static int CmdHFiClassReader(const char *Cmd
) {
394 char cmdp
= tolower(param_getchar(Cmd
, 0));
396 usage_hf_iclass_reader();
399 bool findone
= (cmdp
== '1') ? false : true;
400 return HFiClassReader(findone
, true);
404 static void usage_hf_iclass_eload(void) {
405 PrintAndLog("Loads iclass tag-dump into emulator memory on device");
406 PrintAndLog("Usage: hf iclass eload f <filename>");
408 PrintAndLog("Example: hf iclass eload f iclass_tagdump-aa162d30f8ff12f1.bin");
412 static int CmdHFiClassELoad(const char *Cmd
) {
414 char opt
= param_getchar(Cmd
, 0);
415 if (strlen(Cmd
)<1 || opt
== 'h') {
416 usage_hf_iclass_eload();
420 //File handling and reading
422 char filename
[FILE_PATH_SIZE
];
423 if (opt
== 'f' && param_getstr(Cmd
, 1, filename
, sizeof(filename
)) > 0) {
424 f
= fopen(filename
, "rb");
426 usage_hf_iclass_eload();
431 PrintAndLog("Failed to read from file '%s'", filename
);
435 fseek(f
, 0, SEEK_END
);
436 long fsize
= ftell(f
);
437 fseek(f
, 0, SEEK_SET
);
440 PrintAndLog("Error, when getting filesize");
445 uint8_t *dump
= malloc(fsize
);
447 size_t bytes_read
= fread(dump
, 1, fsize
, f
);
450 printIclassDumpInfo(dump
);
453 if (bytes_read
< fsize
) {
454 prnlog("Error, could only read %d bytes (should be %d)",bytes_read
, fsize
);
459 uint32_t bytes_sent
= 0;
460 uint32_t bytes_remaining
= bytes_read
;
462 while (bytes_remaining
> 0) {
463 uint32_t bytes_in_packet
= MIN(USB_CMD_DATA_SIZE
, bytes_remaining
);
464 UsbCommand c
= {CMD_ICLASS_EML_MEMSET
, {bytes_sent
,bytes_in_packet
,0}};
465 memcpy(c
.d
.asBytes
, dump
+bytes_sent
, bytes_in_packet
);
467 bytes_remaining
-= bytes_in_packet
;
468 bytes_sent
+= bytes_in_packet
;
471 PrintAndLog("Sent %d bytes of data to device emulator memory", bytes_sent
);
476 static int readKeyfile(const char *filename
, size_t len
, uint8_t* buffer
) {
477 FILE *f
= fopen(filename
, "rb");
479 PrintAndLog("Failed to read from file '%s'", filename
);
482 fseek(f
, 0, SEEK_END
);
483 long fsize
= ftell(f
);
484 fseek(f
, 0, SEEK_SET
);
485 size_t bytes_read
= fread(buffer
, 1, len
, f
);
489 PrintAndLog("Warning, file size is %d, expected %d", fsize
, len
);
492 if(bytes_read
!= len
)
494 PrintAndLog("Warning, could only read %d bytes, expected %d" ,bytes_read
, len
);
501 static void usage_hf_iclass_decrypt(void) {
502 PrintAndLog("Usage: hf iclass decrypt f <tagdump>");
504 PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside");
505 PrintAndLog("in the working directory. The file should be 16 bytes binary data");
507 PrintAndLog("example: hf iclass decrypt f tagdump_12312342343.bin");
509 PrintAndLog("OBS! This is pretty stupid implementation, it tries to decrypt every block after block 6. ");
510 PrintAndLog("Correct behaviour would be to decrypt only the application areas where the key is valid,");
511 PrintAndLog("which is defined by the configuration block.");
515 static int CmdHFiClassDecrypt(const char *Cmd
) {
516 uint8_t key
[16] = { 0 };
517 if(readKeyfile("iclass_decryptionkey.bin", 16, key
))
519 usage_hf_iclass_decrypt();
522 PrintAndLog("Decryption file found... ");
523 char opt
= param_getchar(Cmd
, 0);
524 if (strlen(Cmd
)<1 || opt
== 'h') {
525 usage_hf_iclass_decrypt();
529 //Open the tagdump-file
531 char filename
[FILE_PATH_SIZE
];
532 if(opt
== 'f' && param_getstr(Cmd
, 1, filename
, sizeof(filename
)) > 0) {
533 f
= fopen(filename
, "rb");
535 PrintAndLog("Could not find file %s", filename
);
539 usage_hf_iclass_decrypt();
543 fseek(f
, 0, SEEK_END
);
544 long fsize
= ftell(f
);
545 fseek(f
, 0, SEEK_SET
);
546 uint8_t enc_dump
[8] = {0};
547 uint8_t *decrypted
= malloc(fsize
);
548 mbedtls_des3_context ctx
= { {0} };
549 mbedtls_des3_set2key_dec( &ctx
, key
);
550 size_t bytes_read
= fread(enc_dump
, 1, 8, f
);
552 //Use the first block (CSN) for filename
553 char outfilename
[FILE_PATH_SIZE
] = { 0 };
554 snprintf(outfilename
,FILE_PATH_SIZE
,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x-decrypted",
555 enc_dump
[0],enc_dump
[1],enc_dump
[2],enc_dump
[3],
556 enc_dump
[4],enc_dump
[5],enc_dump
[6],enc_dump
[7]);
559 while(bytes_read
== 8)
563 memcpy(decrypted
+(blocknum
*8), enc_dump
, 8);
565 mbedtls_des3_crypt_ecb(&ctx
, enc_dump
,decrypted
+(blocknum
*8) );
567 printvar("decrypted block", decrypted
+(blocknum
*8), 8);
568 bytes_read
= fread(enc_dump
, 1, 8, f
);
573 saveFile(outfilename
,"bin", decrypted
, blocknum
*8);
579 static void usage_hf_iclass_encrypt(void) {
580 PrintAndLog("Usage: hf iclass encrypt <BlockData>");
582 PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside");
583 PrintAndLog("in the working directory. The file should be 16 bytes binary data");
585 PrintAndLog("example: hf iclass encrypt 0102030405060708");
590 static int iClassEncryptBlkData(uint8_t *blkData
) {
591 uint8_t key
[16] = { 0 };
592 if(readKeyfile("iclass_decryptionkey.bin", 16, key
))
594 usage_hf_iclass_encrypt();
597 PrintAndLog("Decryption file found... ");
599 uint8_t encryptedData
[16];
600 uint8_t *encrypted
= encryptedData
;
601 mbedtls_des3_context ctx
= { {0} };
602 mbedtls_des3_set2key_enc( &ctx
, key
);
604 mbedtls_des3_crypt_ecb(&ctx
, blkData
,encrypted
);
605 //printvar("decrypted block", decrypted, 8);
606 memcpy(blkData
,encrypted
,8);
612 static int CmdHFiClassEncryptBlk(const char *Cmd
) {
613 uint8_t blkData
[8] = {0};
614 char opt
= param_getchar(Cmd
, 0);
615 if (strlen(Cmd
)<1 || opt
== 'h') {
616 usage_hf_iclass_encrypt();
619 //get the bytes to encrypt
620 if (param_gethex(Cmd
, 0, blkData
, 16)) {
621 PrintAndLog("BlockData must include 16 HEX symbols");
624 if (!iClassEncryptBlkData(blkData
)) return 0;
625 printvar("encrypted block", blkData
, 8);
630 static void Calc_wb_mac(uint8_t blockno
, uint8_t *data
, uint8_t *div_key
, uint8_t MAC
[4]) {
633 memcpy(WB
+1, data
, 8);
634 doMAC_N(WB
, sizeof(WB
), div_key
, MAC
);
635 //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]);
639 static bool iClass_select(uint8_t *CSN
, bool verbose
, bool cleartrace
, bool init
) {
641 UsbCommand c
= {CMD_READER_ICLASS
, {FLAG_ICLASS_READER_CSN
}};
642 if (init
) c
.arg
[0] |= FLAG_ICLASS_READER_INIT
;
643 if (cleartrace
) c
.arg
[0] |= FLAG_ICLASS_READER_CLEARTRACE
;
646 clearCommandBuffer();
648 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
649 PrintAndLog("Command execute timeout");
653 uint8_t isOK
= resp
.arg
[0] & 0xff;
654 uint8_t *data
= resp
.d
.asBytes
;
656 if (isOK
& FLAG_ICLASS_READER_CSN
) {
657 memcpy(CSN
, data
, 8);
658 if (verbose
) PrintAndLog("CSN: %s", sprint_hex(CSN
, 8));
660 PrintAndLog("Failed to select card! Aborting");
667 static void HFiClassCalcDivKey(uint8_t *CSN
, uint8_t *KEY
, uint8_t *div_key
, bool elite
){
668 uint8_t keytable
[128] = {0};
669 uint8_t key_index
[8] = {0};
671 uint8_t key_sel
[8] = { 0 };
672 uint8_t key_sel_p
[8] = { 0 };
673 hash2(KEY
, keytable
);
674 hash1(CSN
, key_index
);
675 for(uint8_t i
= 0; i
< 8 ; i
++)
676 key_sel
[i
] = keytable
[key_index
[i
]] & 0xFF;
678 //Permute from iclass format to standard format
679 permutekey_rev(key_sel
, key_sel_p
);
680 diversifyKey(CSN
, key_sel_p
, div_key
);
682 diversifyKey(CSN
, KEY
, div_key
);
687 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
) {
690 if (rawkey
|| replay
)
691 memcpy(div_key
, KEY
, 8);
693 HFiClassCalcDivKey(CSN
, KEY
, div_key
, elite
);
695 char keytypetext
[23] = "legacy diversified key";
697 strcpy(keytypetext
, "raw key");
699 strcpy(keytypetext
, "replayed NR/MAC");
701 strcpy(keytypetext
, "Elite diversified key");
704 if (verbose
) PrintAndLog("Authenticating with %s: %s", keytypetext
, sprint_hex(div_key
, 8));
707 UsbCommand d
= {CMD_ICLASS_READCHECK
, {2, use_credit_key
, 0}};
709 clearCommandBuffer();
712 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
713 if (verbose
) PrintAndLog("Auth Command (READCHECK[2]) execute timeout");
716 bool isOK
= resp
.arg
[0];
718 if (verbose
) PrintAndLog("Couldn't get Card Challenge");
723 memcpy(MAC
, KEY
+4, 4);
726 memcpy(CCNR
, resp
.d
.asBytes
, 8);
727 memset(CCNR
+8, 0x00, 4); // default NR = {0, 0, 0, 0}
728 doMAC(CCNR
, div_key
, MAC
);
731 d
.cmd
= CMD_ICLASS_CHECK
;
733 memcpy(d
.d
.asBytes
, KEY
, 8);
735 memset(d
.d
.asBytes
, 0x00, 4); // default NR = {0, 0, 0, 0}
736 memcpy(d
.d
.asBytes
+4, MAC
, 4);
738 clearCommandBuffer();
740 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
741 if (verbose
) PrintAndLog("Auth Command (CHECK) execute timeout");
746 if (verbose
) PrintAndLog("Authentication error");
753 static void usage_hf_iclass_dump(void) {
754 PrintAndLog("Usage: hf iclass dump f <fileName> k <Key> c <CreditKey> e|r|n\n");
755 PrintAndLog("Options:");
756 PrintAndLog(" f <filename> : specify a filename to save dump to");
757 PrintAndLog(" k <Key> : *Debit Key (AA1) as 16 hex symbols (8 bytes) or 1 hex to select key from memory");
758 PrintAndLog(" c <CreditKey>: Credit Key (AA2) as 16 hex symbols (8 bytes) or 1 hex to select key from memory");
759 PrintAndLog(" e : If 'e' is specified, the keys are interpreted as Elite");
760 PrintAndLog(" Custom Keys (KCus), which can be obtained via reader-attack");
761 PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format");
762 PrintAndLog(" r : If 'r' is specified, keys are interpreted as raw blocks 3/4");
763 PrintAndLog(" n : If 'n' is specified, keys are interpreted as NR/MAC pairs which can be obtained by 'hf iclass snoop'");
764 PrintAndLog(" NOTE: * = required");
765 PrintAndLog("Samples:");
766 PrintAndLog(" hf iclass dump k 001122334455667B");
767 PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA c 001122334455667B");
768 PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA e");
772 static void printIclassDumpContents(uint8_t *iclass_dump
, uint8_t startblock
, uint8_t endblock
, size_t filesize
) {
774 memcpy(&mem_config
, iclass_dump
+ 13,1);
776 uint8_t filemaxblock
= filesize
/ 8;
777 if (mem_config
& 0x80)
781 //PrintAndLog ("endblock: %d, filesize: %d, maxmemcount: %d, filemaxblock: %d", endblock,filesize, maxmemcount, filemaxblock);
785 if ((endblock
> maxmemcount
) || (endblock
== 0))
786 endblock
= maxmemcount
;
788 // remember endblock need to relate to zero-index arrays.
789 if (endblock
> filemaxblock
-1)
790 endblock
= filemaxblock
;
793 printf("------+--+-------------------------+\n");
794 while (i
<= endblock
) {
795 uint8_t *blk
= iclass_dump
+ (i
* 8);
796 printf("Block |%02X| %s|\n", i
, sprint_hex(blk
, 8) );
799 printf("------+--+-------------------------+\n");
803 static int CmdHFiClassReader_Dump(const char *Cmd
) {
805 uint8_t MAC
[4] = {0x00,0x00,0x00,0x00};
806 uint8_t div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
807 uint8_t c_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
809 uint8_t AA1_maxBlk
= 0;
811 uint8_t app_areas
= 1;
813 uint8_t KEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
814 uint8_t CreditKEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
817 uint8_t fileNameLen
= 0;
818 char filename
[FILE_PATH_SIZE
]={0};
819 char tempStr
[50] = {0};
820 bool have_debit_key
= false;
821 bool have_credit_key
= false;
822 bool use_credit_key
= false;
825 bool NRMAC_replay
= false;
827 bool verbose
= false;
830 while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) {
831 switch(param_getchar(Cmd
, cmdp
)) {
834 usage_hf_iclass_dump();
838 have_credit_key
= true;
839 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
841 errors
= param_gethex(tempStr
, 0, CreditKEY
, dataLen
);
842 } else if (dataLen
== 1) {
843 keyNbr
= param_get8(Cmd
, cmdp
+1);
844 if (keyNbr
< ICLASS_KEYS_MAX
) {
845 memcpy(CreditKEY
, iClass_Key_Table
[keyNbr
], 8);
847 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
851 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
863 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
864 if (fileNameLen
< 1) {
865 PrintAndLog("No filename found after f");
872 have_debit_key
= true;
873 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
875 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
876 } else if (dataLen
== 1) {
877 keyNbr
= param_get8(Cmd
, cmdp
+1);
878 if (keyNbr
< ICLASS_KEYS_MAX
) {
879 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
881 PrintAndLog("\nERROR: Debit KeyNbr is invalid\n");
885 PrintAndLog("\nERROR: Debit Key is incorrect length\n");
906 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
912 if (elite
+ rawkey
+ NRMAC_replay
> 1) {
913 PrintAndLog("You cannot combine the 'e', 'r', and 'n' options\n");
917 if (errors
|| cmdp
< 2) {
918 usage_hf_iclass_dump();
922 // if only credit key is given: try for AA1 as well (not for iclass but for some picopass this will work)
923 if (!have_debit_key
&& have_credit_key
) {
924 memcpy(KEY
, CreditKEY
, 8);
927 // clear trace and get first 3 blocks
928 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
}};
930 uint8_t tag_data
[256*8];
932 clearCommandBuffer();
934 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
935 PrintAndLog("Command execute timeout");
940 uint8_t readStatus
= resp
.arg
[0] & 0xff;
941 uint8_t *data
= resp
.d
.asBytes
;
942 uint8_t status_mask
= FLAG_ICLASS_READER_CSN
| FLAG_ICLASS_READER_CONF
| FLAG_ICLASS_READER_CC
;
944 if (readStatus
!= status_mask
) {
945 PrintAndLog("No tag found ...");
948 memcpy(tag_data
, data
, 8*3);
949 if (verbose
) PrintAndLog("CSN: %s", sprint_hex(tag_data
, 8));
950 AA1_maxBlk
= data
[8];
951 getMemConfig(data
[13], data
[12], &maxBlk
, &app_areas
, &kb
);
952 // large memory - not able to dump pages currently
953 if (AA1_maxBlk
> maxBlk
) AA1_maxBlk
= maxBlk
;
956 // authenticate with debit key (or credit key if we have no debit key) and get div_key - later store in dump block 3
957 if (!iClass_authenticate(tag_data
, KEY
, MAC
, div_key
, false, elite
, rawkey
, NRMAC_replay
, verbose
)) {
963 UsbCommand w
= {CMD_ICLASS_DUMP
};
964 uint32_t blocksRead
= 0;
965 for (blockno
= 3; blockno
<= AA1_maxBlk
; blockno
+= blocksRead
) {
967 w
.arg
[1] = AA1_maxBlk
- blockno
+ 1;
968 clearCommandBuffer();
970 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
971 PrintAndLog("Command execute time-out 1");
975 blocksRead
= resp
.arg
[1];
976 bool isOK
= resp
.arg
[0];
978 PrintAndLog("Reading AA1 block failed");
982 memcpy(tag_data
+ blockno
*8, resp
.d
.asBytes
, blocksRead
*8);
985 // do we still need to read more blocks (AA2 enabled)?
986 if (have_credit_key
&& maxBlk
> AA1_maxBlk
) {
987 if (!use_credit_key
) {
988 //turn off hf field before authenticating with different key
990 // AA2 authenticate credit key and git c_div_key - later store in dump block 4
992 if (!iClass_select(CSN
, verbose
, false, true) || !iClass_authenticate(CSN
, CreditKEY
, MAC
, c_div_key
, true, false, false, NRMAC_replay
, verbose
)){
997 for ( ; blockno
<= maxBlk
; blockno
+= blocksRead
) {
999 w
.arg
[1] = maxBlk
- blockno
+ 1;
1000 clearCommandBuffer();
1002 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
1003 PrintAndLog("Command execute time-out 1");
1007 blocksRead
= resp
.arg
[1];
1008 bool isOK
= resp
.arg
[0];
1010 PrintAndLog("Reading AA2 block failed");
1014 memcpy(tag_data
+ blockno
*8, resp
.d
.asBytes
, blocksRead
*8);
1020 // add diversified keys to dump
1021 if (have_debit_key
) {
1022 memcpy(tag_data
+ 3*8, div_key
, 8);
1024 memset(tag_data
+ 3*8, 0xff, 8);
1026 if (have_credit_key
) {
1027 memcpy(tag_data
+ 4*8, c_div_key
, 8);
1029 memset(tag_data
+ 4*8, 0xff, 8);
1033 printf("------+--+-------------------------+\n");
1034 printf("CSN |00| %s|\n",sprint_hex(tag_data
, 8));
1035 printIclassDumpContents(tag_data
, 1, blockno
-1, blockno
*8);
1037 if (filename
[0] == 0) {
1038 snprintf(filename
, FILE_PATH_SIZE
,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x",
1039 tag_data
[0],tag_data
[1],tag_data
[2],tag_data
[3],
1040 tag_data
[4],tag_data
[5],tag_data
[6],tag_data
[7]);
1043 // save the dump to .bin file
1044 PrintAndLog("Saving dump file - %d blocks read", blockno
);
1045 saveFile(filename
, "bin", tag_data
, blockno
*8);
1050 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
) {
1052 uint8_t MAC
[4] = {0x00,0x00,0x00,0x00};
1053 uint8_t div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1056 if (!iClass_select(CSN
, verbose
, true, true) || !iClass_authenticate(CSN
, KEY
, MAC
, div_key
, use_credit_key
, elite
, rawkey
, NRMAC_replay
, verbose
)) {
1063 Calc_wb_mac(blockno
, bldata
, div_key
, MAC
);
1065 UsbCommand w
= {CMD_ICLASS_WRITEBLOCK
, {blockno
}};
1066 memcpy(w
.d
.asBytes
, bldata
, 8);
1067 memcpy(w
.d
.asBytes
+ 8, MAC
, 4);
1069 clearCommandBuffer();
1071 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
1072 PrintAndLog("Write Command execute timeout");
1076 bool isOK
= resp
.arg
[0];
1078 PrintAndLog("Write Block Failed");
1083 PrintAndLog("Write Block Successful");
1088 static void usage_hf_iclass_writeblock(void) {
1089 PrintAndLog("Options:");
1090 PrintAndLog(" b <Block> : The block number as 2 hex symbols");
1091 PrintAndLog(" d <data> : Set the Data to write as 16 hex symbols");
1092 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
1093 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
1094 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
1095 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
1096 PrintAndLog(" o : override protection and allow modification of blocks 0...4");
1097 PrintAndLog("Samples:");
1098 PrintAndLog(" hf iclass writeblk b 0A d AAAAAAAAAAAAAAAA k 001122334455667B");
1099 PrintAndLog(" hf iclass writeblk b 1B d AAAAAAAAAAAAAAAA k 001122334455667B c");
1100 PrintAndLog(" hf iclass writeblk b 03 d AAAAAAAAAAAAAAAA k 001122334455667B c o");
1104 static int CmdHFiClass_WriteBlock(const char *Cmd
) {
1105 uint8_t blockno
= 0;
1106 uint8_t bldata
[8] = {0};
1107 uint8_t KEY
[8] = {0};
1109 uint8_t dataLen
= 0;
1110 char tempStr
[50] = {0};
1111 bool use_credit_key
= false;
1113 bool rawkey
= false;
1114 bool override_protection
= false;
1115 bool errors
= false;
1118 while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) {
1119 switch(param_getchar(Cmd
, cmdp
)) {
1122 usage_hf_iclass_writeblock();
1126 if (param_gethex(Cmd
, cmdp
+1, &blockno
, 2)) {
1127 PrintAndLog("Block No must include 2 HEX symbols\n");
1134 use_credit_key
= true;
1139 if (param_gethex(Cmd
, cmdp
+1, bldata
, 16)) {
1140 PrintAndLog("Data must include 16 HEX symbols\n");
1152 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1153 if (dataLen
== 16) {
1154 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1155 } else if (dataLen
== 1) {
1156 keyNbr
= param_get8(Cmd
, cmdp
+1);
1157 if (keyNbr
< ICLASS_KEYS_MAX
) {
1158 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
1160 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1164 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1176 override_protection
= true;
1180 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1185 usage_hf_iclass_writeblock();
1190 if (elite
&& rawkey
) {
1191 PrintAndLog("You cannot combine the 'e' and 'r' options\n");
1196 usage_hf_iclass_writeblock();
1201 if (override_protection
) {
1202 PrintAndLog("Info: modifying keys, e-purse or configuration block.");
1204 PrintAndLog("You are going to modify keys, e-purse or configuration block.");
1205 PrintAndLog("You must add the 'o' (override) option to confirm that you know what you are doing");
1210 int ans
= WriteBlock(blockno
, bldata
, KEY
, use_credit_key
, elite
, rawkey
, false, true);
1217 static void usage_hf_iclass_clone(void) {
1218 PrintAndLog("Usage: hf iclass clone f <tagfile.bin> b <first block> l <last block> k <KEY> c e|r o");
1219 PrintAndLog("Options:");
1220 PrintAndLog(" f <filename>: specify a filename to clone from");
1221 PrintAndLog(" b <Block> : The first block to clone as 2 hex symbols");
1222 PrintAndLog(" l <Last Blk>: The last block to clone as 2 hex symbols");
1223 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
1224 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
1225 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
1226 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
1227 PrintAndLog(" o : override protection and allow modification of target blocks 0...4");
1228 PrintAndLog("Samples:");
1229 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 1A k 1122334455667788 e");
1230 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 05 l 19 k 0");
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 06 l 19 k 0 e");
1233 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 03 l 19 k 0 e o");
1237 static int CmdHFiClassCloneTag(const char *Cmd
) {
1238 char filename
[FILE_PATH_SIZE
] = {0};
1239 char tempStr
[50]={0};
1240 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1242 uint8_t fileNameLen
= 0;
1243 uint8_t startblock
= 0;
1244 uint8_t endblock
= 0;
1245 uint8_t dataLen
= 0;
1246 bool use_credit_key
= false;
1248 bool rawkey
= false;
1249 bool override_protection
= false;
1250 bool errors
= false;
1253 while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) {
1254 switch (param_getchar(Cmd
, cmdp
)) {
1257 usage_hf_iclass_clone();
1261 if (param_gethex(Cmd
, cmdp
+1, &startblock
, 2)) {
1262 PrintAndLog("Start Block No must include 2 HEX symbols\n");
1269 use_credit_key
= true;
1279 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
1280 if (fileNameLen
< 1) {
1281 PrintAndLog("No filename found after f");
1288 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1289 if (dataLen
== 16) {
1290 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1291 } else if (dataLen
== 1) {
1292 keyNbr
= param_get8(Cmd
, cmdp
+1);
1293 if (keyNbr
< ICLASS_KEYS_MAX
) {
1294 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
1296 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1300 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1307 if (param_gethex(Cmd
, cmdp
+1, &endblock
, 2)) {
1308 PrintAndLog("Last Block No must include 2 HEX symbols\n");
1320 override_protection
= true;
1324 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1329 usage_hf_iclass_clone();
1335 usage_hf_iclass_clone();
1339 if (startblock
< 5) {
1340 if (override_protection
) {
1341 PrintAndLog("Info: modifying keys, e-purse or configuration block.");
1343 PrintAndLog("You are going to modify keys, e-purse or configuration block.");
1344 PrintAndLog("You must add the 'o' (override) option to confirm that you know what you are doing");
1349 if ((endblock
- startblock
+ 1) * 12 > USB_CMD_DATA_SIZE
) {
1350 PrintAndLog("Trying to write too many blocks at once. Max: %d", USB_CMD_DATA_SIZE
/12);
1353 // file handling and reading
1355 f
= fopen(filename
,"rb");
1357 PrintAndLog("Failed to read from file '%s'", filename
);
1361 uint8_t tag_data
[USB_CMD_DATA_SIZE
/12][8];
1362 fseek(f
, startblock
*8, SEEK_SET
);
1363 for (int i
= 0; i
< endblock
- startblock
+ 1; i
++) {
1364 if (fread(&tag_data
[i
], 1, 8, f
) == 0 ) {
1365 PrintAndLog("File reading error.");
1371 uint8_t MAC
[4] = {0x00, 0x00, 0x00, 0x00};
1372 uint8_t div_key
[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1375 if (!iClass_select(CSN
, true, true, true) || !iClass_authenticate(CSN
, KEY
, MAC
, div_key
, use_credit_key
, elite
, rawkey
, false, true)) {
1380 UsbCommand w
= {CMD_ICLASS_CLONE
, {startblock
, endblock
}};
1382 // calculate MAC for every block we will write
1383 for (int i
= 0; i
< endblock
- startblock
+ 1; i
++) {
1384 Calc_wb_mac(startblock
+ i
, tag_data
[i
], div_key
, MAC
);
1385 ptr
= w
.d
.asBytes
+ i
* 12;
1386 memcpy(ptr
, tag_data
[i
], 8);
1387 memcpy(ptr
+ 8, MAC
, 4);
1391 PrintAndLog("Cloning");
1392 for (int i
= 0; i
< endblock
- startblock
+ 1; i
++){
1393 memcpy(p
, w
.d
.asBytes
+ (i
* 12), 12);
1394 PrintAndLog("Block |%02x| %02x%02x%02x%02x%02x%02x%02x%02x | MAC |%02x%02x%02x%02x|",
1395 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]);
1400 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
1401 PrintAndLog("Command execute timeout");
1411 static int ReadBlock(uint8_t *KEY
, uint8_t blockno
, uint8_t keyType
, bool elite
, bool rawkey
, bool NRMAC_replay
, bool verbose
, bool auth
) {
1413 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
1414 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1417 if (!iClass_select(CSN
, verbose
, true, true)) {
1423 if (!iClass_authenticate(CSN
, KEY
, MAC
, div_key
, (keyType
==0x18), elite
, rawkey
, NRMAC_replay
, verbose
)) {
1430 UsbCommand w
= {CMD_ICLASS_READBLOCK
, {blockno
}};
1431 clearCommandBuffer();
1433 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
1434 PrintAndLog("Command execute timeout");
1438 bool isOK
= resp
.arg
[0];
1440 PrintAndLog("Read Block Failed");
1444 //data read is stored in: resp.d.asBytes[0-15]
1446 PrintAndLog("Block %02X: %s\n",blockno
, sprint_hex(resp
.d
.asBytes
,8));
1452 static void usage_hf_iclass_readblock(void) {
1453 PrintAndLog("Usage: hf iclass readblk b <Block> k <Key> [c] [e|r|n]\n");
1454 PrintAndLog("Options:");
1455 PrintAndLog(" b <Block> : The block number as 2 hex symbols");
1456 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
1457 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
1458 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
1459 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
1460 PrintAndLog(" n : If 'n' is specified, <Key> specifies a NR/MAC pair which can be obtained by 'hf iclass snoop'");
1461 PrintAndLog("Samples:");
1462 PrintAndLog(" hf iclass readblk b 06 k 0011223344556677");
1463 PrintAndLog(" hf iclass readblk b 1B k 0011223344556677 c");
1464 PrintAndLog(" hf iclass readblk b 0A k 0");
1468 static int CmdHFiClass_ReadBlock(const char *Cmd
) {
1470 uint8_t keyType
= 0x88; //debit key
1471 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1473 uint8_t dataLen
= 0;
1474 char tempStr
[50] = {0};
1476 bool rawkey
= false;
1477 bool NRMAC_replay
= false;
1478 bool errors
= false;
1482 while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) {
1483 switch (param_getchar(Cmd
, cmdp
)) {
1486 usage_hf_iclass_readblock();
1490 if (param_gethex(Cmd
, cmdp
+1, &blockno
, 2)) {
1491 PrintAndLog("Block No must include 2 HEX symbols\n");
1509 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1510 if (dataLen
== 16) {
1511 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1512 } else if (dataLen
== 1) {
1513 keyNbr
= param_get8(Cmd
, cmdp
+1);
1514 if (keyNbr
< ICLASS_KEYS_MAX
) {
1515 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
1517 PrintAndLog("\nERROR: KeyNbr is invalid\n");
1521 PrintAndLog("\nERROR: Key is incorrect length\n");
1533 NRMAC_replay
= true;
1537 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1543 if (elite
+ rawkey
+ NRMAC_replay
> 1) {
1544 PrintAndLog("You cannot combine the 'e', 'r', and 'n' options\n");
1549 usage_hf_iclass_readblock();
1554 usage_hf_iclass_readblock();
1558 PrintAndLog("warning: no authentication used with read, only a few specific blocks can be read accurately without authentication.");
1560 return ReadBlock(KEY
, blockno
, keyType
, elite
, rawkey
, NRMAC_replay
, true, auth
);
1564 static int CmdHFiClass_loclass(const char *Cmd
) {
1565 char opt
= param_getchar(Cmd
, 0);
1567 if (strlen(Cmd
)<1 || opt
== 'h') {
1568 PrintAndLog("Usage: hf iclass loclass [options]");
1569 PrintAndLog("Options:");
1570 PrintAndLog("h Show this help");
1571 PrintAndLog("t Perform self-test");
1572 PrintAndLog("f <filename> Bruteforce iclass dumpfile");
1573 PrintAndLog(" An iclass dumpfile is assumed to consist of an arbitrary number of");
1574 PrintAndLog(" malicious CSNs, and their protocol responses");
1575 PrintAndLog(" The binary format of the file is expected to be as follows: ");
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(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1579 PrintAndLog(" ... totalling N*24 bytes");
1582 char fileName
[255] = {0};
1584 if(param_getstr(Cmd
, 1, fileName
, sizeof(fileName
)) > 0) {
1585 return bruteforceFileNoKeys(fileName
);
1587 PrintAndLog("You must specify a filename");
1589 } else if(opt
== 't') {
1590 int errors
= testCipherUtils();
1591 errors
+= testMAC();
1592 errors
+= doKeyTests(0);
1593 errors
+= testElite();
1595 prnlog("OBS! There were errors!!!");
1604 static void usage_hf_iclass_readtagfile() {
1605 PrintAndLog("Usage: hf iclass readtagfile <filename> [startblock] [endblock]");
1609 static int CmdHFiClassReadTagFile(const char *Cmd
) {
1614 char filename
[FILE_PATH_SIZE
];
1615 if (param_getstr(Cmd
, 0, filename
, sizeof(filename
)) < 1) {
1616 usage_hf_iclass_readtagfile();
1619 if (param_getstr(Cmd
, 1, tempnum
, sizeof(tempnum
)) < 1)
1622 sscanf(tempnum
,"%d",&startblock
);
1624 if (param_getstr(Cmd
,2, tempnum
, sizeof(tempnum
)) < 1)
1627 sscanf(tempnum
,"%d",&endblock
);
1628 // file handling and reading
1629 f
= fopen(filename
,"rb");
1631 PrintAndLog("Failed to read from file '%s'", filename
);
1634 fseek(f
, 0, SEEK_END
);
1635 long fsize
= ftell(f
);
1636 fseek(f
, 0, SEEK_SET
);
1639 PrintAndLog("Error, when getting filesize");
1644 uint8_t *dump
= malloc(fsize
);
1646 size_t bytes_read
= fread(dump
, 1, fsize
, f
);
1648 uint8_t *csn
= dump
;
1649 printf("------+--+-------------------------+\n");
1650 printf("CSN |00| %s|\n", sprint_hex(csn
, 8) );
1651 // printIclassDumpInfo(dump);
1652 printIclassDumpContents(dump
,startblock
,endblock
,bytes_read
);
1658 uint64_t xorcheck(uint64_t sdiv,uint64_t hdiv) {
1659 uint64_t new_div = 0x00;
1665 uint64_t hexarray_to_uint64(uint8_t *key) {
1668 for (int i = 0;i < 8;i++)
1669 sprintf(&temp[(i *2)],"%02X",key[i]);
1671 if (sscanf(temp,"%016" SCNx64,&uint_key) < 1)
1678 //when told CSN, oldkey, newkey, if new key is elite (elite), and if old key was elite (oldElite)
1679 //calculate and return xor_div_key (ready for a key write command)
1680 //print all div_keys if verbose
1681 static void HFiClassCalcNewKey(uint8_t *CSN
, uint8_t *OLDKEY
, uint8_t *NEWKEY
, uint8_t *xor_div_key
, bool elite
, bool oldElite
, bool verbose
){
1682 uint8_t old_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1683 uint8_t new_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1685 HFiClassCalcDivKey(CSN
, OLDKEY
, old_div_key
, oldElite
);
1687 HFiClassCalcDivKey(CSN
, NEWKEY
, new_div_key
, elite
);
1689 for (uint8_t i
= 0; i
< sizeof(old_div_key
); i
++){
1690 xor_div_key
[i
] = old_div_key
[i
] ^ new_div_key
[i
];
1693 printf("Old Div Key : %s\n",sprint_hex(old_div_key
,8));
1694 printf("New Div Key : %s\n",sprint_hex(new_div_key
,8));
1695 printf("Xor Div Key : %s\n",sprint_hex(xor_div_key
,8));
1700 static void usage_hf_iclass_calc_newkey(void) {
1701 PrintAndLog("HELP : Manage iClass Keys in client memory:\n");
1702 PrintAndLog("Usage: hf iclass calc_newkey o <Old key> n <New key> s [csn] e");
1703 PrintAndLog(" Options:");
1704 PrintAndLog(" o <oldkey> : *specify a key as 16 hex symbols or a key number as 1 symbol");
1705 PrintAndLog(" n <newkey> : *specify a key as 16 hex symbols or a key number as 1 symbol");
1706 PrintAndLog(" s <csn> : specify a card Serial number to diversify the key (if omitted will attempt to read a csn)");
1707 PrintAndLog(" e : specify new key as elite calc");
1708 PrintAndLog(" ee : specify old and new key as elite calc");
1709 PrintAndLog("Samples:");
1710 PrintAndLog(" e key to e key given csn : hf iclass calcnewkey o 1122334455667788 n 2233445566778899 s deadbeafdeadbeaf ee");
1711 PrintAndLog(" std key to e key read csn: hf iclass calcnewkey o 1122334455667788 n 2233445566778899 e");
1712 PrintAndLog(" std to std read csn : hf iclass calcnewkey o 1122334455667788 n 2233445566778899");
1713 PrintAndLog("NOTE: * = required\n");
1717 static int CmdHFiClassCalcNewKey(const char *Cmd
) {
1718 uint8_t OLDKEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1719 uint8_t NEWKEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1720 uint8_t xor_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1721 uint8_t CSN
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1723 uint8_t dataLen
= 0;
1724 char tempStr
[50] = {0};
1725 bool givenCSN
= false;
1726 bool oldElite
= false;
1728 bool errors
= false;
1731 while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) {
1732 switch(param_getchar(Cmd
, cmdp
)) {
1735 usage_hf_iclass_calc_newkey();
1739 dataLen
= param_getstr(Cmd
, cmdp
, tempStr
, sizeof(tempStr
));
1747 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1748 if (dataLen
== 16) {
1749 errors
= param_gethex(tempStr
, 0, NEWKEY
, dataLen
);
1750 } else if (dataLen
== 1) {
1751 keyNbr
= param_get8(Cmd
, cmdp
+1);
1752 if (keyNbr
< ICLASS_KEYS_MAX
) {
1753 memcpy(NEWKEY
, iClass_Key_Table
[keyNbr
], 8);
1755 PrintAndLog("\nERROR: NewKey Nbr is invalid\n");
1759 PrintAndLog("\nERROR: NewKey is incorrect length\n");
1766 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1767 if (dataLen
== 16) {
1768 errors
= param_gethex(tempStr
, 0, OLDKEY
, dataLen
);
1769 } else if (dataLen
== 1) {
1770 keyNbr
= param_get8(Cmd
, cmdp
+1);
1771 if (keyNbr
< ICLASS_KEYS_MAX
) {
1772 memcpy(OLDKEY
, iClass_Key_Table
[keyNbr
], 8);
1774 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1778 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1786 if (param_gethex(Cmd
, cmdp
+1, CSN
, 16)) {
1787 usage_hf_iclass_calc_newkey();
1793 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1798 usage_hf_iclass_calc_newkey();
1804 usage_hf_iclass_calc_newkey();
1809 if (!iClass_select(CSN
, true, true, true)) {
1815 HFiClassCalcNewKey(CSN
, OLDKEY
, NEWKEY
, xor_div_key
, elite
, oldElite
, true);
1820 static int loadKeys(char *filename
) {
1822 f
= fopen(filename
,"rb");
1824 PrintAndLog("Failed to read from file '%s'", filename
);
1827 fseek(f
, 0, SEEK_END
);
1828 long fsize
= ftell(f
);
1829 fseek(f
, 0, SEEK_SET
);
1832 PrintAndLog("Error, when getting filesize");
1837 uint8_t *dump
= malloc(fsize
);
1839 size_t bytes_read
= fread(dump
, 1, fsize
, f
);
1841 if (bytes_read
> ICLASS_KEYS_MAX
* 8){
1842 PrintAndLog("File is too long to load - bytes: %u", bytes_read
);
1847 for (; i
< bytes_read
/8; i
++){
1848 memcpy(iClass_Key_Table
[i
],dump
+(i
*8),8);
1851 PrintAndLog("%u keys loaded", i
);
1856 static int saveKeys(char *filename
) {
1858 f
= fopen(filename
,"wb");
1860 printf("error opening file %s\n",filename
);
1863 for (uint8_t i
= 0; i
< ICLASS_KEYS_MAX
; i
++){
1864 if (fwrite(iClass_Key_Table
[i
],8,1,f
) != 1){
1865 PrintAndLog("save key failed to write to file: %s", filename
);
1874 static int printKeys(void) {
1876 for (uint8_t i
= 0; i
< ICLASS_KEYS_MAX
; i
++){
1877 PrintAndLog("%u: %s",i
,sprint_hex(iClass_Key_Table
[i
],8));
1884 static void usage_hf_iclass_managekeys(void) {
1885 PrintAndLog("HELP : Manage iClass Keys in client memory:\n");
1886 PrintAndLog("Usage: hf iclass managekeys n [keynbr] k [key] f [filename] s l p\n");
1887 PrintAndLog(" Options:");
1888 PrintAndLog(" n <keynbr> : specify the keyNbr to set in memory");
1889 PrintAndLog(" k <key> : set a key in memory");
1890 PrintAndLog(" f <filename>: specify a filename to use with load or save operations");
1891 PrintAndLog(" s : save keys in memory to file specified by filename");
1892 PrintAndLog(" l : load keys to memory from file specified by filename");
1893 PrintAndLog(" p : print keys loaded into memory\n");
1894 PrintAndLog("Samples:");
1895 PrintAndLog(" set key : hf iclass managekeys n 0 k 1122334455667788");
1896 PrintAndLog(" save key file: hf iclass managekeys f mykeys.bin s");
1897 PrintAndLog(" load key file: hf iclass managekeys f mykeys.bin l");
1898 PrintAndLog(" print keys : hf iclass managekeys p\n");
1902 static int CmdHFiClassManageKeys(const char *Cmd
) {
1904 uint8_t dataLen
= 0;
1905 uint8_t KEY
[8] = {0};
1906 char filename
[FILE_PATH_SIZE
];
1907 uint8_t fileNameLen
= 0;
1908 bool errors
= false;
1909 uint8_t operation
= 0;
1913 while(param_getchar(Cmd
, cmdp
) != 0x00) {
1914 switch(param_getchar(Cmd
, cmdp
)) {
1917 usage_hf_iclass_managekeys();
1921 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
1922 if (fileNameLen
< 1) {
1923 PrintAndLog("No filename found after f");
1930 keyNbr
= param_get8(Cmd
, cmdp
+1);
1931 if (keyNbr
>= ICLASS_KEYS_MAX
) {
1932 PrintAndLog("Invalid block number");
1939 operation
+= 3; //set key
1940 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1941 if (dataLen
== 16) { //ul-c or ev1/ntag key length
1942 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1944 PrintAndLog("\nERROR: Key is incorrect length\n");
1951 operation
+= 4; //print keys in memory
1956 operation
+= 5; //load keys from file
1961 operation
+= 6; //save keys to file
1965 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1970 usage_hf_iclass_managekeys();
1975 if (operation
== 0){
1976 PrintAndLog("no operation specified (load, save, or print)\n");
1977 usage_hf_iclass_managekeys();
1982 PrintAndLog("Too many operations specified\n");
1983 usage_hf_iclass_managekeys();
1986 if (operation
> 4 && fileNameLen
== 0){
1987 PrintAndLog("You must enter a filename when loading or saving\n");
1988 usage_hf_iclass_managekeys();
1993 case 3: memcpy(iClass_Key_Table
[keyNbr
], KEY
, 8); return 1;
1994 case 4: return printKeys();
1995 case 5: return loadKeys(filename
);
1996 case 6: return saveKeys(filename
);
2003 static int CmdHFiClassCheckKeys(const char *Cmd
) {
2005 uint8_t mac
[4] = {0x00,0x00,0x00,0x00};
2006 uint8_t key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
2007 uint8_t div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
2009 // elite key, raw key, standard key
2010 bool use_elite
= false;
2011 bool use_raw
= false;
2012 bool found_debit
= false;
2013 bool found_credit
= false;
2014 bool errors
= false;
2015 uint8_t cmdp
= 0x00;
2017 char filename
[FILE_PATH_SIZE
] = {0};
2018 uint8_t fileNameLen
= 0;
2020 uint8_t *keyBlock
= NULL
, *p
;
2023 while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) {
2024 switch (param_getchar(Cmd
, cmdp
)) {
2027 usage_hf_iclass_chk();
2031 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
2032 if (fileNameLen
< 1) {
2033 PrintAndLog("No filename found after f");
2049 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
2056 usage_hf_iclass_chk();
2060 if (!(f
= fopen(filename
, "r"))) {
2061 PrintAndLog("File %s not found or locked.", filename
);
2065 while (fgets(buf
, sizeof(buf
), f
)) {
2066 if (strlen(buf
) < 16 || buf
[15] == '\n')
2069 while (fgetc(f
) != '\n' && !feof(f
)) ; //goto next line
2071 if (buf
[0] == '#') continue; //The line start with # is comment, skip
2073 if (!isxdigit(buf
[0])){
2074 PrintAndLog("File content error. '%s' must include 16 HEX symbols", buf
);
2080 p
= realloc(keyBlock
, 8 * (keycnt
+ 1));
2082 PrintAndLog("Cannot allocate memory for default keys");
2089 memset(keyBlock
+ 8 * keycnt
, 0, 8);
2090 num_to_bytes(strtoull(buf
, NULL
, 16), 8, keyBlock
+ 8 * keycnt
);
2093 memset(buf
, 0, sizeof(buf
));
2096 PrintAndLog("Loaded %2d keys from %s", keycnt
, filename
);
2099 if (!iClass_select(CSN
, false, true, true)) {
2104 for (uint32_t c
= 0; c
< keycnt
; c
++) {
2106 memcpy(key
, keyBlock
+ 8 * c
, 8);
2109 if (iClass_authenticate(CSN
, key
, mac
, div_key
, false, use_elite
, use_raw
, false, false)) {
2110 PrintAndLog("\n Found AA1 debit key\t\t[%s]", sprint_hex(key
, 8));
2115 if (iClass_authenticate(CSN
, key
, mac
, div_key
, true, use_elite
, use_raw
, false, false)) {
2116 PrintAndLog("\n Found AA2 credit key\t\t[%s]", sprint_hex(key
, 8));
2117 found_credit
= true;
2121 if (found_debit
&& found_credit
)
2132 static void usage_hf_iclass_permutekey(void) {
2133 PrintAndLogEx(NORMAL
, "Convert keys from standard NIST to iClass format (and vice versa)");
2134 PrintAndLogEx(NORMAL
, "");
2135 PrintAndLogEx(NORMAL
, "Usage: hf iclass permute [h] [r] <key>");
2136 PrintAndLogEx(NORMAL
, "Options:");
2137 PrintAndLogEx(NORMAL
, " h This help");
2138 PrintAndLogEx(NORMAL
, " r reverse convert key from iClass to NIST format");
2139 PrintAndLogEx(NORMAL
, "");
2140 PrintAndLogEx(NORMAL
, "Examples:");
2141 PrintAndLogEx(NORMAL
, " hf iclass permute r 0123456789abcdef");
2145 static int CmdHFiClassPermuteKey(const char *Cmd
) {
2147 uint8_t key
[8] = {0};
2148 uint8_t data
[16] = {0};
2149 bool isReverse
= false;
2150 int len
= sizeof(data
);
2151 char cmdp
= tolower(param_getchar(Cmd
, 0));
2152 if (strlen(Cmd
) == 0 || cmdp
== 'h') {
2153 usage_hf_iclass_permutekey();
2159 param_gethex_ex(Cmd
, 1, data
, &len
);
2160 } else if (cmdp
== 'f') {
2161 param_gethex_ex(Cmd
, 1, data
, &len
);
2163 param_gethex_ex(Cmd
, 0, data
, &len
);
2168 usage_hf_iclass_permutekey();
2174 memcpy(key
, data
, 8);
2177 // generate_rev(data, len);
2178 uint8_t key_std_format
[8] = {0};
2179 permutekey_rev(key
, key_std_format
);
2180 PrintAndLogEx(SUCCESS
, "key in standard NIST format: %s \n", sprint_hex(key_std_format
, 8));
2181 // if (mbedtls_des_key_check_key_parity(key_std_format
2183 // generate(data, len);
2184 uint8_t key_iclass_format
[8] = {0};
2185 permutekey(key
, key_iclass_format
);
2186 PrintAndLogEx(SUCCESS
, "key in iClass (permuted) format: %s \n", sprint_hex(key_iclass_format
, 8));
2192 static int CmdHelp(const char *Cmd
);
2194 static command_t CommandTable
[] = {
2195 {"help", CmdHelp
, 1, "This help"},
2196 {"calcnewkey", CmdHFiClassCalcNewKey
, 1, "[options..] Calc Diversified keys (blocks 3 & 4) to write new keys"},
2197 {"chk", CmdHFiClassCheckKeys
, 0, " Check keys"},
2198 {"clone", CmdHFiClassCloneTag
, 0, "[options..] Authenticate and Clone from iClass bin file"},
2199 {"decrypt", CmdHFiClassDecrypt
, 1, "[f <fname>] Decrypt tagdump" },
2200 {"dump", CmdHFiClassReader_Dump
, 0, "[options..] Authenticate and Dump iClass tag's AA1 and/or AA2"},
2201 {"eload", CmdHFiClassELoad
, 0, "[f <fname>] (experimental) Load data into iClass emulator memory"},
2202 {"encryptblk", CmdHFiClassEncryptBlk
, 1, "<BlockData> Encrypt given block data"},
2203 {"list", CmdHFiClassList
, 0, " (Deprecated) List iClass history"},
2204 {"loclass", CmdHFiClass_loclass
, 1, "[options..] Use loclass to perform bruteforce of reader attack dump"},
2205 {"managekeys", CmdHFiClassManageKeys
, 1, "[options..] Manage the keys to use with iClass"},
2206 {"permutekey", CmdHFiClassPermuteKey
, 1, " iClass key permutation"},
2207 {"readblk", CmdHFiClass_ReadBlock
, 0, "[options..] Authenticate and Read iClass block"},
2208 {"reader", CmdHFiClassReader
, 0, " Look for iClass tags until a key or the pm3 button is pressed"},
2209 {"readtagfile", CmdHFiClassReadTagFile
, 1, "[options..] Display Content from tagfile"},
2210 {"sim", CmdHFiClassSim
, 0, "[options..] Simulate iClass tag"},
2211 {"snoop", CmdHFiClassSnoop
, 0, " Eavesdrop iClass communication"},
2212 {"writeblk", CmdHFiClass_WriteBlock
, 0, "[options..] Authenticate and Write iClass block"},
2213 {NULL
, NULL
, 0, NULL
}
2217 int CmdHFiClass(const char *Cmd
) {
2218 clearCommandBuffer();
2219 CmdsParse(CommandTable
, Cmd
);
2224 int CmdHelp(const char *Cmd
) {
2225 CmdsHelp(CommandTable
);