1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch
3 // Copyright (C) 2011 Gerhard de Koning Gans
4 // Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende
6 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
7 // at your option, any later version. See the LICENSE.txt file for the text of
9 //-----------------------------------------------------------------------------
10 // High frequency iClass commands
11 //-----------------------------------------------------------------------------
18 #include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type
21 #include "cmdparser.h"
22 #include "cmdhficlass.h"
26 #include "mbedtls/des.h"
27 #include "loclass/cipherutils.h"
28 #include "loclass/cipher.h"
29 #include "loclass/ikeys.h"
30 #include "loclass/elite_crack.h"
31 #include "loclass/fileutils.h"
32 #include "protocols.h"
35 #include "util_posix.h"
36 #include "cmdhf14a.h" // DropField()
39 #define ICLASS_KEYS_MAX 8
40 static uint8_t iClass_Key_Table
[ICLASS_KEYS_MAX
][8] = {
41 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
42 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
43 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
44 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
45 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
46 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
47 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
48 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
52 typedef struct iclass_block
{
57 // iclass / picopass chip config structures and shared routines
59 uint8_t app_limit
; //[8]
60 uint8_t otp
[2]; //[9-10]
61 uint8_t block_writelock
;//[11]
62 uint8_t chip_config
; //[12]
63 uint8_t mem_config
; //[13]
66 } picopass_conf_block
;
70 picopass_conf_block conf
;
74 uint8_t app_issuer_area
[8];
78 static void fuse_config(const picopass_hdr
*hdr
) {
79 uint8_t fuses
= hdr
->conf
.fuses
;
81 if (fuses
& FUSE_FPERS
)
82 PrintAndLog(" Mode: Personalization [Programmable]");
84 PrintAndLog(" Mode: Application [Locked]");
86 if (fuses
& FUSE_CODING1
)
87 PrintAndLog("Coding: RFU");
89 if (fuses
& FUSE_CODING0
)
90 PrintAndLog("Coding: ISO 14443-2 B/ISO 15693");
92 PrintAndLog("Coding: ISO 14443B only");
94 if ((fuses
& FUSE_CRYPT1
) && (fuses
& FUSE_CRYPT0
)) PrintAndLog(" Crypt: Secured page, keys not locked");
95 if ((fuses
& FUSE_CRYPT1
) && !(fuses
& FUSE_CRYPT0
)) PrintAndLog(" Crypt: Secured page, keys locked");
96 if (!(fuses
& FUSE_CRYPT1
) && (fuses
& FUSE_CRYPT0
)) PrintAndLog(" Crypt: Non secured page");
97 if (!(fuses
& FUSE_CRYPT1
) && !(fuses
& FUSE_CRYPT0
)) PrintAndLog(" Crypt: No auth possible. Read only if RA is enabled");
100 PrintAndLog(" RA: Read access enabled");
102 PrintAndLog(" RA: Read access not enabled");
106 static void getMemConfig(uint8_t mem_cfg
, uint8_t chip_cfg
, uint8_t *max_blk
, uint8_t *app_areas
, uint8_t *kb
) {
107 // mem-bit 5, mem-bit 7, chip-bit 4: defines chip type
108 if((chip_cfg
& 0x10) && !(mem_cfg
& 0x80) && !(mem_cfg
& 0x20)) {
112 } else if((chip_cfg
& 0x10) && (mem_cfg
& 0x80) && !(mem_cfg
& 0x20)) {
115 *max_blk
= 255; //16kb
116 } else if(!(chip_cfg
& 0x10) && !(mem_cfg
& 0x80) && !(mem_cfg
& 0x20)) {
119 *max_blk
= 255; //16kb
120 } else if((chip_cfg
& 0x10) && (mem_cfg
& 0x80) && (mem_cfg
& 0x20)) {
123 *max_blk
= 255; //16kb
124 } else if(!(chip_cfg
& 0x10) && !(mem_cfg
& 0x80) && (mem_cfg
& 0x20)) {
127 *max_blk
= 255; //16kb
136 static void mem_app_config(const picopass_hdr
*hdr
) {
137 uint8_t mem
= hdr
->conf
.mem_config
;
138 uint8_t chip
= hdr
->conf
.chip_config
;
139 uint8_t applimit
= hdr
->conf
.app_limit
;
140 if (applimit
< 6) applimit
= 26;
142 uint8_t app_areas
= 2;
143 uint8_t max_blk
= 31;
144 getMemConfig(mem
, chip
, &max_blk
, &app_areas
, &kb
);
145 PrintAndLog(" Mem: %u KBits/%u App Areas (%u * 8 bytes) [%02X]", kb
, app_areas
, max_blk
+1, mem
);
146 PrintAndLog(" AA1: blocks 06-%02X", applimit
);
147 PrintAndLog(" AA2: blocks %02X-%02X", applimit
+1, max_blk
);
151 static void printIclassDumpInfo(uint8_t* iclass_dump
) {
152 fuse_config((picopass_hdr
*)iclass_dump
);
153 mem_app_config((picopass_hdr
*)iclass_dump
);
157 static void usage_hf_iclass_chk(void) {
158 PrintAndLog("Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag");
159 PrintAndLog("Usage: hf iclass chk [h|e|r] <f (*.dic)>");
160 PrintAndLog("Options:");
161 PrintAndLog("h Show this help");
162 PrintAndLog("f <filename> Dictionary file with default iclass keys");
163 PrintAndLog(" e target Elite / High security key scheme");
164 PrintAndLog(" r interpret dictionary file as raw (diversified keys)");
165 PrintAndLog("Samples:");
166 PrintAndLog(" hf iclass chk f default_iclass_keys.dic");
167 PrintAndLog(" hf iclass chk f default_iclass_keys.dic e");
171 static int CmdHFiClassList(const char *Cmd
) {
172 PrintAndLog("Deprecated command, use 'hf list iclass' instead");
177 static int CmdHFiClassSnoop(const char *Cmd
) {
178 UsbCommand c
= {CMD_SNOOP_ICLASS
};
184 static void usage_hf_iclass_sim(void) {
185 PrintAndLog("Usage: hf iclass sim <option> [CSN]");
186 PrintAndLog(" options");
187 PrintAndLog(" 0 <CSN> simulate the given CSN");
188 PrintAndLog(" 1 simulate default CSN");
189 PrintAndLog(" 2 Reader-attack, gather reader responses to extract elite key");
190 PrintAndLog(" 3 Full simulation using emulator memory (see 'hf iclass eload')");
191 PrintAndLog(" example: hf iclass sim 0 031FEC8AF7FF12E0");
192 PrintAndLog(" example: hf iclass sim 2");
193 PrintAndLog(" example: hf iclass eload 'tagdump.bin'");
194 PrintAndLog(" hf iclass sim 3");
198 // the original malicious IDs from Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult,
199 // and Milosch Meriac. Dismantling iClass and iClass Elite.
201 static uint8_t csns
[8 * NUM_CSNS
] = {
202 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
203 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0,
204 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0,
205 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0,
206 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0,
207 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0,
208 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0,
209 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0,
210 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0,
211 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0,
212 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0,
213 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0,
214 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0,
215 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0,
216 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 };
219 // pre-defined 9 CSNs by iceman.
220 // only one csn depend on several others.
221 // six depends only on the first csn, (0,1, 0x45)
223 // #define NUM_CSNS 9
224 // static uint8_t csns[8 * NUM_CSNS] = {
225 // 0x01, 0x0A, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
226 // 0x0C, 0x06, 0x0C, 0xFE, 0xF7, 0xFF, 0x12, 0xE0,
227 // 0x10, 0x97, 0x83, 0x7B, 0xF7, 0xFF, 0x12, 0xE0,
228 // 0x13, 0x97, 0x82, 0x7A, 0xF7, 0xFF, 0x12, 0xE0,
229 // 0x07, 0x0E, 0x0D, 0xF9, 0xF7, 0xFF, 0x12, 0xE0,
230 // 0x14, 0x96, 0x84, 0x76, 0xF7, 0xFF, 0x12, 0xE0,
231 // 0x17, 0x96, 0x85, 0x71, 0xF7, 0xFF, 0x12, 0xE0,
232 // 0xCE, 0xC5, 0x0F, 0x77, 0xF7, 0xFF, 0x12, 0xE0,
233 // 0xD2, 0x5A, 0x82, 0xF8, 0xF7, 0xFF, 0x12, 0xE0
234 // //0x04, 0x08, 0x9F, 0x78, 0x6E, 0xFF, 0x12, 0xE0
238 static int CmdHFiClassSim(const char *Cmd
) {
240 uint8_t CSN
[8] = {0, 0, 0, 0, 0, 0, 0, 0};
242 if (strlen(Cmd
) < 1) {
243 usage_hf_iclass_sim();
246 simType
= param_get8ex(Cmd
, 0, 0, 10);
248 if (simType
== ICLASS_SIM_MODE_CSN
) {
249 if (param_gethex(Cmd
, 1, CSN
, 16)) {
250 PrintAndLog("A CSN should consist of 16 HEX symbols");
251 usage_hf_iclass_sim();
254 PrintAndLog("--simtype:%02x csn:%s", simType
, sprint_hex(CSN
, 8));
257 if (simType
== ICLASS_SIM_MODE_READER_ATTACK
) {
258 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
, NUM_CSNS
}};
259 UsbCommand resp
= {0};
261 memcpy(c
.d
.asBytes
, csns
, 8 * NUM_CSNS
);
264 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, -1)) {
265 PrintAndLog("Command timed out");
269 uint8_t num_mac_responses
= resp
.arg
[1];
270 PrintAndLog("Mac responses: %d MACs obtained (should be %d)", num_mac_responses
, NUM_CSNS
);
272 size_t datalen
= NUM_CSNS
* 24;
274 * Now, time to dump to file. We'll use this format:
275 * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
276 * So, it should wind up as
279 * The returndata from the pm3 is on the following format
280 * <8 byte CC><4 byte NR><4 byte MAC>
281 * CSN is the same as was sent in
283 void* dump
= malloc(datalen
);
284 for(int i
= 0; i
< NUM_CSNS
; i
++) {
285 memcpy(dump
+ i
*24, csns
+i
*8, 8); //CSN
286 //copy CC from response
287 memcpy(dump
+ i
*24 + 8, resp
.d
.asBytes
+ i
*16, 8);
288 //Then comes NR_MAC (eight bytes from the response)
289 memcpy(dump
+ i
*24 + 16, resp
.d
.asBytes
+ i
*16 + 8, 8);
291 /** Now, save to dumpfile **/
292 saveFile("iclass_mac_attack", "bin", dump
,datalen
);
295 } else if (simType
== ICLASS_SIM_MODE_CSN
|| simType
== ICLASS_SIM_MODE_CSN_DEFAULT
|| simType
== ICLASS_SIM_MODE_FULL
) {
296 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
, 0}};
297 memcpy(c
.d
.asBytes
, CSN
, 8);
301 PrintAndLog("Undefined simtype %d", simType
);
302 usage_hf_iclass_sim();
310 int HFiClassReader(bool loop
, bool verbose
) {
312 bool tagFound
= false;
313 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
} };
318 if (WaitForResponseTimeout(CMD_ACK
,&resp
, 4500)) {
319 uint8_t readStatus
= resp
.arg
[0] & 0xff;
320 uint8_t *data
= resp
.d
.asBytes
;
323 if (readStatus
== 0 && !loop
) {
325 if (verbose
) PrintAndLog("Quitting...");
330 if (readStatus
& FLAG_ICLASS_READER_CSN
) {
331 PrintAndLog(" CSN: %s",sprint_hex(data
,8));
334 if (readStatus
& FLAG_ICLASS_READER_CC
) {
335 PrintAndLog(" CC: %s",sprint_hex(data
+16,8));
337 if (readStatus
& FLAG_ICLASS_READER_CONF
) {
338 printIclassDumpInfo(data
);
340 if (readStatus
& FLAG_ICLASS_READER_AA
) {
342 PrintAndLog(" AppIA: %s",sprint_hex(data
+8*5,8));
343 for (int i
= 0; i
<8; i
++) {
344 if (data
[8*5+i
] != 0xFF) {
348 PrintAndLog(" : Possible iClass %s",(legacy
) ? "(legacy tag)" : "(NOT legacy tag)");
351 if (tagFound
&& !loop
) return 1;
353 if (verbose
) PrintAndLog("Command execute timeout");
363 static void usage_hf_iclass_reader(void) {
364 PrintAndLogEx(NORMAL
, "Act as a Iclass reader. Look for iClass tags until Enter or the pm3 button is pressed\n");
365 PrintAndLogEx(NORMAL
, "Usage: hf iclass reader [h] [1]\n");
366 PrintAndLogEx(NORMAL
, "Options:");
367 PrintAndLogEx(NORMAL
, " h This help text");
368 PrintAndLogEx(NORMAL
, " 1 read only 1 tag");
369 PrintAndLogEx(NORMAL
, "Examples:");
370 PrintAndLogEx(NORMAL
, " hf iclass reader 1");
374 static int CmdHFiClassReader(const char *Cmd
) {
375 char cmdp
= tolower(param_getchar(Cmd
, 0));
377 usage_hf_iclass_reader();
380 bool findone
= (cmdp
== '1') ? false : true;
381 return HFiClassReader(findone
, true);
385 static int CmdHFiClassReader_Replay(const char *Cmd
) {
386 uint8_t readerType
= 0;
387 uint8_t MAC
[4]={0x00, 0x00, 0x00, 0x00};
390 PrintAndLog("Usage: hf iclass replay <MAC>");
391 PrintAndLog(" sample: hf iclass replay 00112233");
395 if (param_gethex(Cmd
, 0, MAC
, 8)) {
396 PrintAndLog("MAC must include 8 HEX symbols");
400 UsbCommand c
= {CMD_READER_ICLASS_REPLAY
, {readerType
}};
401 memcpy(c
.d
.asBytes
, MAC
, 4);
408 static void usage_hf_iclass_eload(void) {
409 PrintAndLog("Loads iclass tag-dump into emulator memory on device");
410 PrintAndLog("Usage: hf iclass eload f <filename>");
412 PrintAndLog("Example: hf iclass eload f iclass_tagdump-aa162d30f8ff12f1.bin");
416 static int CmdHFiClassELoad(const char *Cmd
) {
418 char opt
= param_getchar(Cmd
, 0);
419 if (strlen(Cmd
)<1 || opt
== 'h') {
420 usage_hf_iclass_eload();
424 //File handling and reading
426 char filename
[FILE_PATH_SIZE
];
427 if (opt
== 'f' && param_getstr(Cmd
, 1, filename
, sizeof(filename
)) > 0) {
428 f
= fopen(filename
, "rb");
430 usage_hf_iclass_eload();
435 PrintAndLog("Failed to read from file '%s'", filename
);
439 fseek(f
, 0, SEEK_END
);
440 long fsize
= ftell(f
);
441 fseek(f
, 0, SEEK_SET
);
444 PrintAndLog("Error, when getting filesize");
449 uint8_t *dump
= malloc(fsize
);
451 size_t bytes_read
= fread(dump
, 1, fsize
, f
);
454 printIclassDumpInfo(dump
);
457 if (bytes_read
< fsize
) {
458 prnlog("Error, could only read %d bytes (should be %d)",bytes_read
, fsize
);
463 uint32_t bytes_sent
= 0;
464 uint32_t bytes_remaining
= bytes_read
;
466 while (bytes_remaining
> 0) {
467 uint32_t bytes_in_packet
= MIN(USB_CMD_DATA_SIZE
, bytes_remaining
);
468 UsbCommand c
= {CMD_ICLASS_EML_MEMSET
, {bytes_sent
,bytes_in_packet
,0}};
469 memcpy(c
.d
.asBytes
, dump
+bytes_sent
, bytes_in_packet
);
471 bytes_remaining
-= bytes_in_packet
;
472 bytes_sent
+= bytes_in_packet
;
475 PrintAndLog("Sent %d bytes of data to device emulator memory", bytes_sent
);
480 static int readKeyfile(const char *filename
, size_t len
, uint8_t* buffer
) {
481 FILE *f
= fopen(filename
, "rb");
483 PrintAndLog("Failed to read from file '%s'", filename
);
486 fseek(f
, 0, SEEK_END
);
487 long fsize
= ftell(f
);
488 fseek(f
, 0, SEEK_SET
);
489 size_t bytes_read
= fread(buffer
, 1, len
, f
);
493 PrintAndLog("Warning, file size is %d, expected %d", fsize
, len
);
496 if(bytes_read
!= len
)
498 PrintAndLog("Warning, could only read %d bytes, expected %d" ,bytes_read
, len
);
505 static void usage_hf_iclass_decrypt(void) {
506 PrintAndLog("Usage: hf iclass decrypt f <tagdump>");
508 PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside");
509 PrintAndLog("in the working directory. The file should be 16 bytes binary data");
511 PrintAndLog("example: hf iclass decrypt f tagdump_12312342343.bin");
513 PrintAndLog("OBS! This is pretty stupid implementation, it tries to decrypt every block after block 6. ");
514 PrintAndLog("Correct behaviour would be to decrypt only the application areas where the key is valid,");
515 PrintAndLog("which is defined by the configuration block.");
519 static int CmdHFiClassDecrypt(const char *Cmd
) {
520 uint8_t key
[16] = { 0 };
521 if(readKeyfile("iclass_decryptionkey.bin", 16, key
))
523 usage_hf_iclass_decrypt();
526 PrintAndLog("Decryption file found... ");
527 char opt
= param_getchar(Cmd
, 0);
528 if (strlen(Cmd
)<1 || opt
== 'h') {
529 usage_hf_iclass_decrypt();
533 //Open the tagdump-file
535 char filename
[FILE_PATH_SIZE
];
536 if(opt
== 'f' && param_getstr(Cmd
, 1, filename
, sizeof(filename
)) > 0) {
537 f
= fopen(filename
, "rb");
539 PrintAndLog("Could not find file %s", filename
);
543 usage_hf_iclass_decrypt();
547 fseek(f
, 0, SEEK_END
);
548 long fsize
= ftell(f
);
549 fseek(f
, 0, SEEK_SET
);
550 uint8_t enc_dump
[8] = {0};
551 uint8_t *decrypted
= malloc(fsize
);
552 mbedtls_des3_context ctx
= { {0} };
553 mbedtls_des3_set2key_dec( &ctx
, key
);
554 size_t bytes_read
= fread(enc_dump
, 1, 8, f
);
556 //Use the first block (CSN) for filename
557 char outfilename
[FILE_PATH_SIZE
] = { 0 };
558 snprintf(outfilename
,FILE_PATH_SIZE
,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x-decrypted",
559 enc_dump
[0],enc_dump
[1],enc_dump
[2],enc_dump
[3],
560 enc_dump
[4],enc_dump
[5],enc_dump
[6],enc_dump
[7]);
563 while(bytes_read
== 8)
567 memcpy(decrypted
+(blocknum
*8), enc_dump
, 8);
569 mbedtls_des3_crypt_ecb(&ctx
, enc_dump
,decrypted
+(blocknum
*8) );
571 printvar("decrypted block", decrypted
+(blocknum
*8), 8);
572 bytes_read
= fread(enc_dump
, 1, 8, f
);
577 saveFile(outfilename
,"bin", decrypted
, blocknum
*8);
583 static void usage_hf_iclass_encrypt(void) {
584 PrintAndLog("Usage: hf iclass encrypt <BlockData>");
586 PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside");
587 PrintAndLog("in the working directory. The file should be 16 bytes binary data");
589 PrintAndLog("example: hf iclass encrypt 0102030405060708");
594 static int iClassEncryptBlkData(uint8_t *blkData
) {
595 uint8_t key
[16] = { 0 };
596 if(readKeyfile("iclass_decryptionkey.bin", 16, key
))
598 usage_hf_iclass_encrypt();
601 PrintAndLog("Decryption file found... ");
603 uint8_t encryptedData
[16];
604 uint8_t *encrypted
= encryptedData
;
605 mbedtls_des3_context ctx
= { {0} };
606 mbedtls_des3_set2key_enc( &ctx
, key
);
608 mbedtls_des3_crypt_ecb(&ctx
, blkData
,encrypted
);
609 //printvar("decrypted block", decrypted, 8);
610 memcpy(blkData
,encrypted
,8);
616 static int CmdHFiClassEncryptBlk(const char *Cmd
) {
617 uint8_t blkData
[8] = {0};
618 char opt
= param_getchar(Cmd
, 0);
619 if (strlen(Cmd
)<1 || opt
== 'h') {
620 usage_hf_iclass_encrypt();
623 //get the bytes to encrypt
624 if (param_gethex(Cmd
, 0, blkData
, 16)) {
625 PrintAndLog("BlockData must include 16 HEX symbols");
628 if (!iClassEncryptBlkData(blkData
)) return 0;
629 printvar("encrypted block", blkData
, 8);
634 static void Calc_wb_mac(uint8_t blockno
, uint8_t *data
, uint8_t *div_key
, uint8_t MAC
[4]) {
637 memcpy(WB
+1, data
, 8);
638 doMAC_N(WB
, sizeof(WB
), div_key
, MAC
);
639 //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]);
643 static bool iClass_select(uint8_t *CSN
, bool verbose
, bool cleartrace
, bool init
) {
645 UsbCommand c
= {CMD_READER_ICLASS
, {FLAG_ICLASS_READER_CSN
}};
646 if (init
) c
.arg
[0] |= FLAG_ICLASS_READER_INIT
;
647 if (cleartrace
) c
.arg
[0] |= FLAG_ICLASS_READER_CLEARTRACE
;
650 clearCommandBuffer();
652 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
653 PrintAndLog("Command execute timeout");
657 uint8_t isOK
= resp
.arg
[0] & 0xff;
658 uint8_t *data
= resp
.d
.asBytes
;
660 if (isOK
& FLAG_ICLASS_READER_CSN
) {
661 memcpy(CSN
, data
, 8);
662 if (verbose
) PrintAndLog("CSN: %s", sprint_hex(CSN
, 8));
664 PrintAndLog("Failed to select card! Aborting");
671 static void HFiClassCalcDivKey(uint8_t *CSN
, uint8_t *KEY
, uint8_t *div_key
, bool elite
){
672 uint8_t keytable
[128] = {0};
673 uint8_t key_index
[8] = {0};
675 uint8_t key_sel
[8] = { 0 };
676 uint8_t key_sel_p
[8] = { 0 };
677 hash2(KEY
, keytable
);
678 hash1(CSN
, key_index
);
679 for(uint8_t i
= 0; i
< 8 ; i
++)
680 key_sel
[i
] = keytable
[key_index
[i
]] & 0xFF;
682 //Permute from iclass format to standard format
683 permutekey_rev(key_sel
, key_sel_p
);
684 diversifyKey(CSN
, key_sel_p
, div_key
);
686 diversifyKey(CSN
, KEY
, div_key
);
691 static bool iClass_authenticate(uint8_t *CSN
, uint8_t *KEY
, uint8_t *MAC
, uint8_t *div_key
, bool use_credit_key
, bool elite
, bool rawkey
, bool verbose
) {
695 memcpy(div_key
, KEY
, 8);
697 HFiClassCalcDivKey(CSN
, KEY
, div_key
, elite
);
699 if (verbose
) PrintAndLog("Authenticating with %s: %s", rawkey
? "raw key" : "diversified key", sprint_hex(div_key
, 8));
702 UsbCommand d
= {CMD_ICLASS_READCHECK
, {2, use_credit_key
, 0}};
704 clearCommandBuffer();
707 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
708 if (verbose
) PrintAndLog("Auth Command (READCHECK[2]) execute timeout");
711 bool isOK
= resp
.arg
[0];
713 if (verbose
) PrintAndLog("Couldn't get Card Challenge");
718 memcpy(CCNR
, resp
.d
.asBytes
, 8);
719 memset(CCNR
+8, 0x00, 4); // NR = {0, 0, 0, 0}
721 doMAC(CCNR
, div_key
, MAC
);
723 d
.cmd
= CMD_ICLASS_CHECK
;
724 memcpy(d
.d
.asBytes
, MAC
, 4);
725 clearCommandBuffer();
727 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
728 if (verbose
) PrintAndLog("Auth Command (CHECK) execute timeout");
733 if (verbose
) PrintAndLog("Authentication error");
740 static void usage_hf_iclass_dump(void) {
741 PrintAndLog("Usage: hf iclass dump f <fileName> k <Key> c <CreditKey> e|r\n");
742 PrintAndLog("Options:");
743 PrintAndLog(" f <filename> : specify a filename to save dump to");
744 PrintAndLog(" k <Key> : *Access Key as 16 hex symbols or 1 hex to select key from memory");
745 PrintAndLog(" c <CreditKey>: Credit Key as 16 hex symbols or 1 hex to select key from memory");
746 PrintAndLog(" e : If 'e' is specified, the key is interpreted as the 16 byte");
747 PrintAndLog(" Custom Key (KCus), which can be obtained via reader-attack");
748 PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format");
749 PrintAndLog(" r : If 'r' is specified, the key is interpreted as raw block 3/4");
750 PrintAndLog(" NOTE: * = required");
751 PrintAndLog("Samples:");
752 PrintAndLog(" hf iclass dump k 001122334455667B");
753 PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA c 001122334455667B");
754 PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA e");
758 static void printIclassDumpContents(uint8_t *iclass_dump
, uint8_t startblock
, uint8_t endblock
, size_t filesize
) {
760 memcpy(&mem_config
, iclass_dump
+ 13,1);
762 uint8_t filemaxblock
= filesize
/ 8;
763 if (mem_config
& 0x80)
767 //PrintAndLog ("endblock: %d, filesize: %d, maxmemcount: %d, filemaxblock: %d", endblock,filesize, maxmemcount, filemaxblock);
771 if ((endblock
> maxmemcount
) || (endblock
== 0))
772 endblock
= maxmemcount
;
774 // remember endblock need to relate to zero-index arrays.
775 if (endblock
> filemaxblock
-1)
776 endblock
= filemaxblock
;
779 printf("------+--+-------------------------+\n");
780 while (i
<= endblock
) {
781 uint8_t *blk
= iclass_dump
+ (i
* 8);
782 printf("Block |%02X| %s|\n", i
, sprint_hex(blk
, 8) );
785 printf("------+--+-------------------------+\n");
789 static int CmdHFiClassReader_Dump(const char *Cmd
) {
791 uint8_t MAC
[4] = {0x00,0x00,0x00,0x00};
792 uint8_t div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
793 uint8_t c_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
795 uint8_t AA1_maxBlk
= 0;
797 uint8_t app_areas
= 1;
799 uint8_t KEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
800 uint8_t CreditKEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
803 uint8_t fileNameLen
= 0;
804 char filename
[FILE_PATH_SIZE
]={0};
805 char tempStr
[50] = {0};
806 bool have_debit_key
= false;
807 bool have_credit_key
= false;
808 bool use_credit_key
= false;
812 bool verbose
= false;
815 while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) {
816 switch(param_getchar(Cmd
, cmdp
)) {
819 usage_hf_iclass_dump();
823 have_credit_key
= true;
824 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
826 errors
= param_gethex(tempStr
, 0, CreditKEY
, dataLen
);
827 } else if (dataLen
== 1) {
828 keyNbr
= param_get8(Cmd
, cmdp
+1);
829 if (keyNbr
< ICLASS_KEYS_MAX
) {
830 memcpy(CreditKEY
, iClass_Key_Table
[keyNbr
], 8);
832 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
836 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
848 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
849 if (fileNameLen
< 1) {
850 PrintAndLog("No filename found after f");
857 have_debit_key
= true;
858 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
860 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
861 } else if (dataLen
== 1) {
862 keyNbr
= param_get8(Cmd
, cmdp
+1);
863 if (keyNbr
< ICLASS_KEYS_MAX
) {
864 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
866 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
870 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
886 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
892 if (errors
|| cmdp
< 2) {
893 usage_hf_iclass_dump();
897 // if only credit key is given: try for AA1 as well (not for iclass but for some picopass this will work)
898 if (!have_debit_key
&& have_credit_key
) {
899 use_credit_key
= true;
900 memcpy(KEY
, CreditKEY
, 8);
903 // clear trace and get first 3 blocks
904 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
}};
906 uint8_t tag_data
[256*8];
908 clearCommandBuffer();
910 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
911 PrintAndLog("Command execute timeout");
916 uint8_t readStatus
= resp
.arg
[0] & 0xff;
917 uint8_t *data
= resp
.d
.asBytes
;
918 uint8_t status_mask
= FLAG_ICLASS_READER_CSN
| FLAG_ICLASS_READER_CONF
| FLAG_ICLASS_READER_CC
;
920 if (readStatus
!= status_mask
) {
921 PrintAndLog("No tag found ...");
924 memcpy(tag_data
, data
, 8*3);
925 if (verbose
) PrintAndLog("CSN: %s", sprint_hex(tag_data
, 8));
926 AA1_maxBlk
= data
[8];
927 getMemConfig(data
[13], data
[12], &maxBlk
, &app_areas
, &kb
);
928 // large memory - not able to dump pages currently
929 if (AA1_maxBlk
> maxBlk
) AA1_maxBlk
= maxBlk
;
932 // authenticate debit key (or credit key if we have no debit key) and get div_key - later store in dump block 3
933 if (!iClass_authenticate(tag_data
, KEY
, MAC
, div_key
, use_credit_key
, elite
, rawkey
, verbose
)){
939 UsbCommand w
= {CMD_ICLASS_DUMP
};
940 uint32_t blocksRead
= 0;
941 for (blockno
= 3; blockno
<= AA1_maxBlk
; blockno
+= blocksRead
) {
943 w
.arg
[1] = AA1_maxBlk
- blockno
+ 1;
944 clearCommandBuffer();
946 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
947 PrintAndLog("Command execute time-out 1");
951 blocksRead
= resp
.arg
[1];
952 bool isOK
= resp
.arg
[0];
954 PrintAndLog("Reading AA1 block failed");
958 memcpy(tag_data
+ blockno
*8, resp
.d
.asBytes
, blocksRead
*8);
961 // do we still need to read more blocks (AA2 enabled)?
962 if (have_credit_key
&& maxBlk
> AA1_maxBlk
) {
963 if (!use_credit_key
) {
964 //turn off hf field before authenticating with different key
966 // AA2 authenticate credit key and git c_div_key - later store in dump block 4
968 if (!iClass_select(CSN
, verbose
, false, true) || !iClass_authenticate(CSN
, CreditKEY
, MAC
, c_div_key
, true, false, false, verbose
)){
973 for ( ; blockno
<= maxBlk
; blockno
+= blocksRead
) {
975 w
.arg
[1] = maxBlk
- blockno
+ 1;
976 clearCommandBuffer();
978 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
979 PrintAndLog("Command execute time-out 1");
983 blocksRead
= resp
.arg
[1];
984 bool isOK
= resp
.arg
[0];
986 PrintAndLog("Reading AA2 block failed");
990 memcpy(tag_data
+ blockno
*8, resp
.d
.asBytes
, blocksRead
*8);
996 // add diversified keys to dump
997 if (have_debit_key
) {
998 memcpy(tag_data
+ 3*8, div_key
, 8);
1000 memset(tag_data
+ 3*8, 0xff, 8);
1002 if (have_credit_key
) {
1003 memcpy(tag_data
+ 4*8, c_div_key
, 8);
1005 memset(tag_data
+ 4*8, 0xff, 8);
1009 printf("------+--+-------------------------+\n");
1010 printf("CSN |00| %s|\n",sprint_hex(tag_data
, 8));
1011 printIclassDumpContents(tag_data
, 1, blockno
-1, blockno
*8);
1013 if (filename
[0] == 0) {
1014 snprintf(filename
, FILE_PATH_SIZE
,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x",
1015 tag_data
[0],tag_data
[1],tag_data
[2],tag_data
[3],
1016 tag_data
[4],tag_data
[5],tag_data
[6],tag_data
[7]);
1019 // save the dump to .bin file
1020 PrintAndLog("Saving dump file - %d blocks read", blockno
);
1021 saveFile(filename
, "bin", tag_data
, blockno
*8);
1026 static int WriteBlock(uint8_t blockno
, uint8_t *bldata
, uint8_t *KEY
, bool use_credit_key
, bool elite
, bool rawkey
, bool verbose
) {
1028 uint8_t MAC
[4] = {0x00,0x00,0x00,0x00};
1029 uint8_t div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1032 if (!iClass_select(CSN
, verbose
, true, true) || !iClass_authenticate(CSN
, KEY
, MAC
, div_key
, use_credit_key
, elite
, rawkey
, verbose
)) {
1039 Calc_wb_mac(blockno
, bldata
, div_key
, MAC
);
1041 UsbCommand w
= {CMD_ICLASS_WRITEBLOCK
, {blockno
}};
1042 memcpy(w
.d
.asBytes
, bldata
, 8);
1043 memcpy(w
.d
.asBytes
+ 8, MAC
, 4);
1045 clearCommandBuffer();
1047 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
1048 PrintAndLog("Write Command execute timeout");
1052 bool isOK
= resp
.arg
[0];
1054 PrintAndLog("Write Block Failed");
1059 PrintAndLog("Write Block Successful");
1064 static void usage_hf_iclass_writeblock(void) {
1065 PrintAndLog("Options:");
1066 PrintAndLog(" b <Block> : The block number as 2 hex symbols");
1067 PrintAndLog(" d <data> : Set the Data to write as 16 hex symbols");
1068 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
1069 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
1070 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
1071 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
1072 PrintAndLog("Samples:");
1073 PrintAndLog(" hf iclass writeblk b 0A d AAAAAAAAAAAAAAAA k 001122334455667B");
1074 PrintAndLog(" hf iclass writeblk b 1B d AAAAAAAAAAAAAAAA k 001122334455667B c");
1075 PrintAndLog(" hf iclass writeblk b 0A d AAAAAAAAAAAAAAAA n 0");
1079 static int CmdHFiClass_WriteBlock(const char *Cmd
) {
1081 uint8_t bldata
[8]={0,0,0,0,0,0,0,0};
1082 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1084 uint8_t dataLen
= 0;
1085 char tempStr
[50] = {0};
1086 bool use_credit_key
= false;
1089 bool errors
= false;
1091 while(param_getchar(Cmd
, cmdp
) != 0x00)
1093 switch(param_getchar(Cmd
, cmdp
))
1097 usage_hf_iclass_writeblock();
1101 if (param_gethex(Cmd
, cmdp
+1, &blockno
, 2)) {
1102 PrintAndLog("Block No must include 2 HEX symbols\n");
1109 use_credit_key
= true;
1114 if (param_gethex(Cmd
, cmdp
+1, bldata
, 16)) {
1115 PrintAndLog("Data must include 16 HEX symbols\n");
1127 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1128 if (dataLen
== 16) {
1129 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1130 } else if (dataLen
== 1) {
1131 keyNbr
= param_get8(Cmd
, cmdp
+1);
1132 if (keyNbr
< ICLASS_KEYS_MAX
) {
1133 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
1135 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1139 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1150 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1155 usage_hf_iclass_writeblock();
1161 usage_hf_iclass_writeblock();
1164 int ans
= WriteBlock(blockno
, bldata
, KEY
, use_credit_key
, elite
, rawkey
, true);
1170 static void usage_hf_iclass_clone(void) {
1171 PrintAndLog("Usage: hf iclass clone f <tagfile.bin> b <first block> l <last block> k <KEY> c e|r");
1172 PrintAndLog("Options:");
1173 PrintAndLog(" f <filename>: specify a filename to clone from");
1174 PrintAndLog(" b <Block> : The first block to clone as 2 hex symbols");
1175 PrintAndLog(" l <Last Blk>: Set the Data to write as 16 hex symbols");
1176 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
1177 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
1178 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
1179 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
1180 PrintAndLog("Samples:");
1181 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 1A k 1122334455667788 e");
1182 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 05 l 19 k 0");
1183 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 19 k 0 e");
1187 static int CmdHFiClassCloneTag(const char *Cmd
) {
1188 char filename
[FILE_PATH_SIZE
] = {0};
1189 char tempStr
[50]={0};
1190 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1192 uint8_t fileNameLen
= 0;
1193 uint8_t startblock
= 0;
1194 uint8_t endblock
= 0;
1195 uint8_t dataLen
= 0;
1196 bool use_credit_key
= false;
1198 bool rawkey
= false;
1199 bool errors
= false;
1201 while(param_getchar(Cmd
, cmdp
) != 0x00)
1203 switch(param_getchar(Cmd
, cmdp
))
1207 usage_hf_iclass_clone();
1211 if (param_gethex(Cmd
, cmdp
+1, &startblock
, 2)) {
1212 PrintAndLog("Start Block No must include 2 HEX symbols\n");
1219 use_credit_key
= true;
1229 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
1230 if (fileNameLen
< 1) {
1231 PrintAndLog("No filename found after f");
1238 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1239 if (dataLen
== 16) {
1240 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1241 } else if (dataLen
== 1) {
1242 keyNbr
= param_get8(Cmd
, cmdp
+1);
1243 if (keyNbr
< ICLASS_KEYS_MAX
) {
1244 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
1246 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1250 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1257 if (param_gethex(Cmd
, cmdp
+1, &endblock
, 2)) {
1258 PrintAndLog("Start Block No must include 2 HEX symbols\n");
1269 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1274 usage_hf_iclass_clone();
1280 usage_hf_iclass_clone();
1286 iclass_block_t tag_data
[USB_CMD_DATA_SIZE
/12];
1288 if ((endblock
-startblock
+1)*12 > USB_CMD_DATA_SIZE
) {
1289 PrintAndLog("Trying to write too many blocks at once. Max: %d", USB_CMD_DATA_SIZE
/8);
1291 // file handling and reading
1292 f
= fopen(filename
,"rb");
1294 PrintAndLog("Failed to read from file '%s'", filename
);
1299 PrintAndLog("You cannot write key blocks this way. yet... make your start block > 4");
1303 // now read data from the file from block 6 --- 19
1304 // ok we will use this struct [data 8 bytes][MAC 4 bytes] for each block calculate all mac number for each data
1305 // then copy to usbcommand->asbytes; the max is 32 - 6 = 24 block 12 bytes each block 288 bytes then we can only accept to clone 21 blocks at the time,
1306 // else we have to create a share memory
1308 fseek(f
, startblock
*8, SEEK_SET
);
1309 if (fread(tag_data
, sizeof(iclass_block_t
), endblock
- startblock
+ 1, f
) == 0 ) {
1310 PrintAndLog("File reading error.");
1315 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
1316 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1319 if (!iClass_select(CSN
, true, false, false) || !iClass_authenticate(CSN
, KEY
, MAC
, div_key
, use_credit_key
, elite
, rawkey
, true)) {
1324 UsbCommand w
= {CMD_ICLASS_CLONE
, {startblock
, endblock
}};
1326 // calculate all mac for every the block we will write
1327 for (i
= startblock
; i
<= endblock
; i
++){
1328 Calc_wb_mac(i
, tag_data
[i
- startblock
].d
, div_key
, MAC
);
1329 // usb command d start pointer = d + (i - 6) * 12
1330 // memcpy(pointer,tag_data[i - 6],8) 8 bytes
1331 // memcpy(pointer + 8,mac,sizoof(mac) 4 bytes;
1333 ptr
= w
.d
.asBytes
+ (i
- startblock
) * 12;
1334 memcpy(ptr
, &(tag_data
[i
- startblock
].d
[0]), 8);
1335 memcpy(ptr
+ 8,MAC
, 4);
1338 for (i
= 0; i
<= endblock
- startblock
;i
++){
1339 memcpy(p
,w
.d
.asBytes
+ (i
* 12),12);
1340 printf("Block |%02x|",i
+ startblock
);
1341 printf(" %02x%02x%02x%02x%02x%02x%02x%02x |",p
[0],p
[1],p
[2],p
[3],p
[4],p
[5],p
[6],p
[7]);
1342 printf(" MAC |%02x%02x%02x%02x|\n",p
[8],p
[9],p
[10],p
[11]);
1347 if (!WaitForResponseTimeout(CMD_ACK
,&resp
,4500))
1349 PrintAndLog("Command execute timeout");
1357 static int ReadBlock(uint8_t *KEY
, uint8_t blockno
, uint8_t keyType
, bool elite
, bool rawkey
, bool verbose
, bool auth
) {
1359 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
1360 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1363 if (!iClass_select(CSN
, verbose
, true, true)) {
1369 if (!iClass_authenticate(CSN
, KEY
, MAC
, div_key
, (keyType
==0x18), elite
, rawkey
, verbose
)) {
1376 UsbCommand w
= {CMD_ICLASS_READBLOCK
, {blockno
}};
1377 clearCommandBuffer();
1379 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
1380 PrintAndLog("Command execute timeout");
1384 bool isOK
= resp
.arg
[0];
1386 PrintAndLog("Read Block Failed");
1390 //data read is stored in: resp.d.asBytes[0-15]
1392 PrintAndLog("Block %02X: %s\n",blockno
, sprint_hex(resp
.d
.asBytes
,8));
1398 static void usage_hf_iclass_readblock(void) {
1399 PrintAndLog("Usage: hf iclass readblk b <Block> k <Key> [c] [e|r]\n");
1400 PrintAndLog("Options:");
1401 PrintAndLog(" b <Block> : The block number as 2 hex symbols");
1402 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
1403 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
1404 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
1405 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
1406 PrintAndLog("Samples:");
1407 PrintAndLog(" hf iclass readblk b 06 k 0011223344556677");
1408 PrintAndLog(" hf iclass readblk b 1B k 0011223344556677 c");
1409 PrintAndLog(" hf iclass readblk b 0A k 0");
1413 static int CmdHFiClass_ReadBlock(const char *Cmd
) {
1415 uint8_t keyType
= 0x88; //debit key
1416 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1418 uint8_t dataLen
= 0;
1419 char tempStr
[50] = {0};
1421 bool rawkey
= false;
1422 bool errors
= false;
1425 while (param_getchar(Cmd
, cmdp
) != 0x00) {
1426 switch (param_getchar(Cmd
, cmdp
)) {
1429 usage_hf_iclass_readblock();
1433 if (param_gethex(Cmd
, cmdp
+1, &blockno
, 2)) {
1434 PrintAndLog("Block No must include 2 HEX symbols\n");
1452 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1453 if (dataLen
== 16) {
1454 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1455 } else if (dataLen
== 1) {
1456 keyNbr
= param_get8(Cmd
, cmdp
+1);
1457 if (keyNbr
< ICLASS_KEYS_MAX
) {
1458 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
1460 PrintAndLog("\nERROR: KeyNbr is invalid\n");
1464 PrintAndLog("\nERROR: Key is incorrect length\n");
1475 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1480 usage_hf_iclass_readblock();
1486 usage_hf_iclass_readblock();
1490 PrintAndLog("warning: no authentication used with read, only a few specific blocks can be read accurately without authentication.");
1492 return ReadBlock(KEY
, blockno
, keyType
, elite
, rawkey
, true, auth
);
1496 static int CmdHFiClass_loclass(const char *Cmd
) {
1497 char opt
= param_getchar(Cmd
, 0);
1499 if (strlen(Cmd
)<1 || opt
== 'h') {
1500 PrintAndLog("Usage: hf iclass loclass [options]");
1501 PrintAndLog("Options:");
1502 PrintAndLog("h Show this help");
1503 PrintAndLog("t Perform self-test");
1504 PrintAndLog("f <filename> Bruteforce iclass dumpfile");
1505 PrintAndLog(" An iclass dumpfile is assumed to consist of an arbitrary number of");
1506 PrintAndLog(" malicious CSNs, and their protocol responses");
1507 PrintAndLog(" The binary format of the file is expected to be as follows: ");
1508 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1509 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1510 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1511 PrintAndLog(" ... totalling N*24 bytes");
1514 char fileName
[255] = {0};
1516 if(param_getstr(Cmd
, 1, fileName
, sizeof(fileName
)) > 0) {
1517 return bruteforceFileNoKeys(fileName
);
1519 PrintAndLog("You must specify a filename");
1521 } else if(opt
== 't') {
1522 int errors
= testCipherUtils();
1523 errors
+= testMAC();
1524 errors
+= doKeyTests(0);
1525 errors
+= testElite();
1527 prnlog("OBS! There were errors!!!");
1536 static void usage_hf_iclass_readtagfile() {
1537 PrintAndLog("Usage: hf iclass readtagfile <filename> [startblock] [endblock]");
1541 static int CmdHFiClassReadTagFile(const char *Cmd
) {
1546 char filename
[FILE_PATH_SIZE
];
1547 if (param_getstr(Cmd
, 0, filename
, sizeof(filename
)) < 1) {
1548 usage_hf_iclass_readtagfile();
1551 if (param_getstr(Cmd
, 1, tempnum
, sizeof(tempnum
)) < 1)
1554 sscanf(tempnum
,"%d",&startblock
);
1556 if (param_getstr(Cmd
,2, tempnum
, sizeof(tempnum
)) < 1)
1559 sscanf(tempnum
,"%d",&endblock
);
1560 // file handling and reading
1561 f
= fopen(filename
,"rb");
1563 PrintAndLog("Failed to read from file '%s'", filename
);
1566 fseek(f
, 0, SEEK_END
);
1567 long fsize
= ftell(f
);
1568 fseek(f
, 0, SEEK_SET
);
1571 PrintAndLog("Error, when getting filesize");
1576 uint8_t *dump
= malloc(fsize
);
1578 size_t bytes_read
= fread(dump
, 1, fsize
, f
);
1580 uint8_t *csn
= dump
;
1581 printf("------+--+-------------------------+\n");
1582 printf("CSN |00| %s|\n", sprint_hex(csn
, 8) );
1583 // printIclassDumpInfo(dump);
1584 printIclassDumpContents(dump
,startblock
,endblock
,bytes_read
);
1590 uint64_t xorcheck(uint64_t sdiv,uint64_t hdiv) {
1591 uint64_t new_div = 0x00;
1597 uint64_t hexarray_to_uint64(uint8_t *key) {
1600 for (int i = 0;i < 8;i++)
1601 sprintf(&temp[(i *2)],"%02X",key[i]);
1603 if (sscanf(temp,"%016" SCNx64,&uint_key) < 1)
1610 //when told CSN, oldkey, newkey, if new key is elite (elite), and if old key was elite (oldElite)
1611 //calculate and return xor_div_key (ready for a key write command)
1612 //print all div_keys if verbose
1613 static void HFiClassCalcNewKey(uint8_t *CSN
, uint8_t *OLDKEY
, uint8_t *NEWKEY
, uint8_t *xor_div_key
, bool elite
, bool oldElite
, bool verbose
){
1614 uint8_t old_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1615 uint8_t new_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1617 HFiClassCalcDivKey(CSN
, OLDKEY
, old_div_key
, oldElite
);
1619 HFiClassCalcDivKey(CSN
, NEWKEY
, new_div_key
, elite
);
1621 for (uint8_t i
= 0; i
< sizeof(old_div_key
); i
++){
1622 xor_div_key
[i
] = old_div_key
[i
] ^ new_div_key
[i
];
1625 printf("Old Div Key : %s\n",sprint_hex(old_div_key
,8));
1626 printf("New Div Key : %s\n",sprint_hex(new_div_key
,8));
1627 printf("Xor Div Key : %s\n",sprint_hex(xor_div_key
,8));
1632 static void usage_hf_iclass_calc_newkey(void) {
1633 PrintAndLog("HELP : Manage iClass Keys in client memory:\n");
1634 PrintAndLog("Usage: hf iclass calc_newkey o <Old key> n <New key> s [csn] e");
1635 PrintAndLog(" Options:");
1636 PrintAndLog(" o <oldkey> : *specify a key as 16 hex symbols or a key number as 1 symbol");
1637 PrintAndLog(" n <newkey> : *specify a key as 16 hex symbols or a key number as 1 symbol");
1638 PrintAndLog(" s <csn> : specify a card Serial number to diversify the key (if omitted will attempt to read a csn)");
1639 PrintAndLog(" e : specify new key as elite calc");
1640 PrintAndLog(" ee : specify old and new key as elite calc");
1641 PrintAndLog("Samples:");
1642 PrintAndLog(" e key to e key given csn : hf iclass calcnewkey o 1122334455667788 n 2233445566778899 s deadbeafdeadbeaf ee");
1643 PrintAndLog(" std key to e key read csn: hf iclass calcnewkey o 1122334455667788 n 2233445566778899 e");
1644 PrintAndLog(" std to std read csn : hf iclass calcnewkey o 1122334455667788 n 2233445566778899");
1645 PrintAndLog("NOTE: * = required\n");
1649 static int CmdHFiClassCalcNewKey(const char *Cmd
) {
1650 uint8_t OLDKEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1651 uint8_t NEWKEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1652 uint8_t xor_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1653 uint8_t CSN
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1655 uint8_t dataLen
= 0;
1656 char tempStr
[50] = {0};
1657 bool givenCSN
= false;
1658 bool oldElite
= false;
1660 bool errors
= false;
1662 while(param_getchar(Cmd
, cmdp
) != 0x00)
1664 switch(param_getchar(Cmd
, cmdp
))
1668 usage_hf_iclass_calc_newkey();
1672 dataLen
= param_getstr(Cmd
, cmdp
, tempStr
, sizeof(tempStr
));
1680 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1681 if (dataLen
== 16) {
1682 errors
= param_gethex(tempStr
, 0, NEWKEY
, dataLen
);
1683 } else if (dataLen
== 1) {
1684 keyNbr
= param_get8(Cmd
, cmdp
+1);
1685 if (keyNbr
< ICLASS_KEYS_MAX
) {
1686 memcpy(NEWKEY
, iClass_Key_Table
[keyNbr
], 8);
1688 PrintAndLog("\nERROR: NewKey Nbr is invalid\n");
1692 PrintAndLog("\nERROR: NewKey is incorrect length\n");
1699 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1700 if (dataLen
== 16) {
1701 errors
= param_gethex(tempStr
, 0, OLDKEY
, dataLen
);
1702 } else if (dataLen
== 1) {
1703 keyNbr
= param_get8(Cmd
, cmdp
+1);
1704 if (keyNbr
< ICLASS_KEYS_MAX
) {
1705 memcpy(OLDKEY
, iClass_Key_Table
[keyNbr
], 8);
1707 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1711 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1719 if (param_gethex(Cmd
, cmdp
+1, CSN
, 16)) {
1720 usage_hf_iclass_calc_newkey();
1726 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1731 usage_hf_iclass_calc_newkey();
1737 usage_hf_iclass_calc_newkey();
1742 if (!iClass_select(CSN
, true, true, true)) {
1748 HFiClassCalcNewKey(CSN
, OLDKEY
, NEWKEY
, xor_div_key
, elite
, oldElite
, true);
1753 static int loadKeys(char *filename
) {
1755 f
= fopen(filename
,"rb");
1757 PrintAndLog("Failed to read from file '%s'", filename
);
1760 fseek(f
, 0, SEEK_END
);
1761 long fsize
= ftell(f
);
1762 fseek(f
, 0, SEEK_SET
);
1765 PrintAndLog("Error, when getting filesize");
1770 uint8_t *dump
= malloc(fsize
);
1772 size_t bytes_read
= fread(dump
, 1, fsize
, f
);
1774 if (bytes_read
> ICLASS_KEYS_MAX
* 8){
1775 PrintAndLog("File is too long to load - bytes: %u", bytes_read
);
1780 for (; i
< bytes_read
/8; i
++){
1781 memcpy(iClass_Key_Table
[i
],dump
+(i
*8),8);
1784 PrintAndLog("%u keys loaded", i
);
1789 static int saveKeys(char *filename
) {
1791 f
= fopen(filename
,"wb");
1793 printf("error opening file %s\n",filename
);
1796 for (uint8_t i
= 0; i
< ICLASS_KEYS_MAX
; i
++){
1797 if (fwrite(iClass_Key_Table
[i
],8,1,f
) != 1){
1798 PrintAndLog("save key failed to write to file: %s", filename
);
1807 static int printKeys(void) {
1809 for (uint8_t i
= 0; i
< ICLASS_KEYS_MAX
; i
++){
1810 PrintAndLog("%u: %s",i
,sprint_hex(iClass_Key_Table
[i
],8));
1817 static void usage_hf_iclass_managekeys(void) {
1818 PrintAndLog("HELP : Manage iClass Keys in client memory:\n");
1819 PrintAndLog("Usage: hf iclass managekeys n [keynbr] k [key] f [filename] s l p\n");
1820 PrintAndLog(" Options:");
1821 PrintAndLog(" n <keynbr> : specify the keyNbr to set in memory");
1822 PrintAndLog(" k <key> : set a key in memory");
1823 PrintAndLog(" f <filename>: specify a filename to use with load or save operations");
1824 PrintAndLog(" s : save keys in memory to file specified by filename");
1825 PrintAndLog(" l : load keys to memory from file specified by filename");
1826 PrintAndLog(" p : print keys loaded into memory\n");
1827 PrintAndLog("Samples:");
1828 PrintAndLog(" set key : hf iclass managekeys n 0 k 1122334455667788");
1829 PrintAndLog(" save key file: hf iclass managekeys f mykeys.bin s");
1830 PrintAndLog(" load key file: hf iclass managekeys f mykeys.bin l");
1831 PrintAndLog(" print keys : hf iclass managekeys p\n");
1835 static int CmdHFiClassManageKeys(const char *Cmd
) {
1837 uint8_t dataLen
= 0;
1838 uint8_t KEY
[8] = {0};
1839 char filename
[FILE_PATH_SIZE
];
1840 uint8_t fileNameLen
= 0;
1841 bool errors
= false;
1842 uint8_t operation
= 0;
1846 while(param_getchar(Cmd
, cmdp
) != 0x00)
1848 switch(param_getchar(Cmd
, cmdp
))
1852 usage_hf_iclass_managekeys();
1856 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
1857 if (fileNameLen
< 1) {
1858 PrintAndLog("No filename found after f");
1865 keyNbr
= param_get8(Cmd
, cmdp
+1);
1866 if (keyNbr
>= ICLASS_KEYS_MAX
) {
1867 PrintAndLog("Invalid block number");
1874 operation
+= 3; //set key
1875 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1876 if (dataLen
== 16) { //ul-c or ev1/ntag key length
1877 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1879 PrintAndLog("\nERROR: Key is incorrect length\n");
1886 operation
+= 4; //print keys in memory
1891 operation
+= 5; //load keys from file
1896 operation
+= 6; //save keys to file
1900 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1905 usage_hf_iclass_managekeys();
1909 if (operation
== 0){
1910 PrintAndLog("no operation specified (load, save, or print)\n");
1911 usage_hf_iclass_managekeys();
1915 PrintAndLog("Too many operations specified\n");
1916 usage_hf_iclass_managekeys();
1919 if (operation
> 4 && fileNameLen
== 0){
1920 PrintAndLog("You must enter a filename when loading or saving\n");
1921 usage_hf_iclass_managekeys();
1926 case 3: memcpy(iClass_Key_Table
[keyNbr
], KEY
, 8); return 1;
1927 case 4: return printKeys();
1928 case 5: return loadKeys(filename
);
1929 case 6: return saveKeys(filename
);
1936 static int CmdHFiClassCheckKeys(const char *Cmd
) {
1938 uint8_t mac
[4] = {0x00,0x00,0x00,0x00};
1939 uint8_t key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1940 uint8_t div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1942 // elite key, raw key, standard key
1943 bool use_elite
= false;
1944 bool use_raw
= false;
1945 bool found_debit
= false;
1946 bool found_credit
= false;
1947 bool errors
= false;
1948 uint8_t cmdp
= 0x00;
1950 char filename
[FILE_PATH_SIZE
] = {0};
1951 uint8_t fileNameLen
= 0;
1953 uint8_t *keyBlock
= NULL
, *p
;
1954 int keyitems
= 0, keycnt
= 0;
1956 while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) {
1957 switch (param_getchar(Cmd
, cmdp
)) {
1960 usage_hf_iclass_chk();
1964 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
1965 if (fileNameLen
< 1) {
1966 PrintAndLog("No filename found after f");
1982 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1988 usage_hf_iclass_chk();
1992 if ( !(f
= fopen( filename
, "r")) ) {
1993 PrintAndLog("File: %s: not found or locked.", filename
);
1997 while( fgets(buf
, sizeof(buf
), f
) ){
1998 if (strlen(buf
) < 16 || buf
[15] == '\n')
2001 while (fgetc(f
) != '\n' && !feof(f
)) ; //goto next line
2003 if( buf
[0]=='#' ) continue; //The line start with # is comment, skip
2005 if (!isxdigit(buf
[0])){
2006 PrintAndLog("File content error. '%s' must include 16 HEX symbols",buf
);
2012 p
= realloc(keyBlock
, 8 * (keyitems
+= 64));
2014 PrintAndLog("Cannot allocate memory for default keys");
2021 memset(keyBlock
+ 8 * keycnt
, 0, 8);
2022 num_to_bytes(strtoull(buf
, NULL
, 16), 8, keyBlock
+ 8 * keycnt
);
2024 //PrintAndLog("check key[%2d] %016" PRIx64, keycnt, bytes_to_num(keyBlock + 8*keycnt, 8));
2026 memset(buf
, 0, sizeof(buf
));
2029 PrintAndLog("Loaded %2d keys from %s", keycnt
, filename
);
2032 uint64_t t1
= msclock();
2035 if (!iClass_select(CSN
, false, true, true)) {
2036 PrintAndLog("Couldn't select card");
2041 for (uint32_t c
= 0; c
< keycnt
; c
++) {
2042 printf("."); fflush(stdout
);
2044 int gc
= getchar(); (void)gc
;
2045 printf("\naborted via keyboard!\n");
2049 memcpy(key
, keyBlock
+ 8 * c
, 8);
2052 if (!iClass_authenticate(CSN
, key
, mac
, div_key
, false, use_elite
, use_raw
, false))
2056 PrintAndLog("\n--------------------------------------------------------");
2057 PrintAndLog(" Found AA1 debit key\t\t[%s]", sprint_hex(key
, 8));
2061 if (!iClass_authenticate(CSN
, key
, mac
, div_key
, true, use_elite
, use_raw
, false))
2065 PrintAndLog("\n--------------------------------------------------------");
2066 PrintAndLog(" Found AA2 credit key\t\t[%s]", sprint_hex(key
, 8));
2067 found_credit
= true;
2070 if (found_debit
&& found_credit
)
2074 t1
= msclock() - t1
;
2076 PrintAndLog("\nTime in iclass checkkeys: %.0f seconds\n", (float)t1
/1000.0);
2085 static void usage_hf_iclass_permutekey(void) {
2086 PrintAndLogEx(NORMAL
, "Convert keys from standard NIST to iClass format (and vice versa)");
2087 PrintAndLogEx(NORMAL
, "");
2088 PrintAndLogEx(NORMAL
, "Usage: hf iclass permute [h] [r] <key>");
2089 PrintAndLogEx(NORMAL
, "Options:");
2090 PrintAndLogEx(NORMAL
, " h This help");
2091 PrintAndLogEx(NORMAL
, " r reverse convert key from iClass to NIST format");
2092 PrintAndLogEx(NORMAL
, "");
2093 PrintAndLogEx(NORMAL
, "Examples:");
2094 PrintAndLogEx(NORMAL
, " hf iclass permute r 0123456789abcdef");
2098 static int CmdHFiClassPermuteKey(const char *Cmd
) {
2100 uint8_t key
[8] = {0};
2101 uint8_t data
[16] = {0};
2102 bool isReverse
= false;
2103 int len
= sizeof(data
);
2104 char cmdp
= tolower(param_getchar(Cmd
, 0));
2105 if (strlen(Cmd
) == 0 || cmdp
== 'h') {
2106 usage_hf_iclass_permutekey();
2112 param_gethex_ex(Cmd
, 1, data
, &len
);
2113 } else if (cmdp
== 'f') {
2114 param_gethex_ex(Cmd
, 1, data
, &len
);
2116 param_gethex_ex(Cmd
, 0, data
, &len
);
2121 usage_hf_iclass_permutekey();
2127 memcpy(key
, data
, 8);
2130 // generate_rev(data, len);
2131 uint8_t key_std_format
[8] = {0};
2132 permutekey_rev(key
, key_std_format
);
2133 PrintAndLogEx(SUCCESS
, "key in standard NIST format: %s \n", sprint_hex(key_std_format
, 8));
2134 // if (mbedtls_des_key_check_key_parity(key_std_format
2136 // generate(data, len);
2137 uint8_t key_iclass_format
[8] = {0};
2138 permutekey(key
, key_iclass_format
);
2139 PrintAndLogEx(SUCCESS
, "key in iClass (permuted) format: %s \n", sprint_hex(key_iclass_format
, 8));
2145 static int CmdHelp(const char *Cmd
);
2147 static command_t CommandTable
[] = {
2148 {"help", CmdHelp
, 1, "This help"},
2149 {"calcnewkey", CmdHFiClassCalcNewKey
, 1, "[options..] Calc Diversified keys (blocks 3 & 4) to write new keys"},
2150 {"chk", CmdHFiClassCheckKeys
, 0, " Check keys"},
2151 {"clone", CmdHFiClassCloneTag
, 0, "[options..] Authenticate and Clone from iClass bin file"},
2152 {"decrypt", CmdHFiClassDecrypt
, 1, "[f <fname>] Decrypt tagdump" },
2153 {"dump", CmdHFiClassReader_Dump
, 0, "[options..] Authenticate and Dump iClass tag's AA1"},
2154 {"eload", CmdHFiClassELoad
, 0, "[f <fname>] (experimental) Load data into iClass emulator memory"},
2155 {"encryptblk", CmdHFiClassEncryptBlk
, 1, "<BlockData> Encrypt given block data"},
2156 {"list", CmdHFiClassList
, 0, " (Deprecated) List iClass history"},
2157 {"loclass", CmdHFiClass_loclass
, 1, "[options..] Use loclass to perform bruteforce of reader attack dump"},
2158 {"managekeys", CmdHFiClassManageKeys
, 1, "[options..] Manage the keys to use with iClass"},
2159 {"permutekey", CmdHFiClassPermuteKey
, 1, " iClass key permutation"},
2160 {"readblk", CmdHFiClass_ReadBlock
, 0, "[options..] Authenticate and Read iClass block"},
2161 {"reader", CmdHFiClassReader
, 0, " Look for iClass tags until a key or the pm3 button is pressed"},
2162 {"readtagfile", CmdHFiClassReadTagFile
, 1, "[options..] Display Content from tagfile"},
2163 {"replay", CmdHFiClassReader_Replay
, 0, "<mac> Read an iClass tag via Reply Attack"},
2164 {"sim", CmdHFiClassSim
, 0, "[options..] Simulate iClass tag"},
2165 {"snoop", CmdHFiClassSnoop
, 0, " Eavesdrop iClass communication"},
2166 {"writeblk", CmdHFiClass_WriteBlock
, 0, "[options..] Authenticate and Write iClass block"},
2167 {NULL
, NULL
, 0, NULL
}
2171 int CmdHFiClass(const char *Cmd
) {
2172 clearCommandBuffer();
2173 CmdsParse(CommandTable
, Cmd
);
2178 int CmdHelp(const char *Cmd
) {
2179 CmdsHelp(CommandTable
);