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 static void usage_hf_iclass_chk(void) {
58 PrintAndLog("Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag");
59 PrintAndLog("Usage: hf iclass chk [h|e|r] <f (*.dic)>");
60 PrintAndLog("Options:");
61 PrintAndLog("h Show this help");
62 PrintAndLog("f <filename> Dictionary file with default iclass keys");
63 PrintAndLog(" e target Elite / High security key scheme");
64 PrintAndLog(" r interpret dictionary file as raw (diversified keys)");
65 PrintAndLog("Samples:");
66 PrintAndLog(" hf iclass chk f default_iclass_keys.dic");
67 PrintAndLog(" hf iclass chk f default_iclass_keys.dic e");
71 static int CmdHFiClassList(const char *Cmd
) {
72 PrintAndLog("Deprecated command, use 'hf list iclass' instead");
77 static int CmdHFiClassSnoop(const char *Cmd
) {
78 UsbCommand c
= {CMD_SNOOP_ICLASS
};
84 static void usage_hf_iclass_sim(void) {
85 PrintAndLog("Usage: hf iclass sim <option> [CSN]");
86 PrintAndLog(" options");
87 PrintAndLog(" 0 <CSN> simulate the given CSN");
88 PrintAndLog(" 1 simulate default CSN");
89 PrintAndLog(" 2 Reader-attack, gather reader responses to extract elite key");
90 PrintAndLog(" 3 Full simulation using emulator memory (see 'hf iclass eload')");
91 PrintAndLog(" example: hf iclass sim 0 031FEC8AF7FF12E0");
92 PrintAndLog(" example: hf iclass sim 2");
93 PrintAndLog(" example: hf iclass eload 'tagdump.bin'");
94 PrintAndLog(" hf iclass sim 3");
98 // the original malicious IDs from Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult,
99 // and Milosch Meriac. Dismantling iClass and iClass Elite.
101 static uint8_t csns
[8 * NUM_CSNS
] = {
102 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
103 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0,
104 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0,
105 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0,
106 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0,
107 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0,
108 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0,
109 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0,
110 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0,
111 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0,
112 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0,
113 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0,
114 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0,
115 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0,
116 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 };
119 // pre-defined 9 CSNs by iceman.
120 // only one csn depend on several others.
121 // six depends only on the first csn, (0,1, 0x45)
123 // #define NUM_CSNS 9
124 // static uint8_t csns[8 * NUM_CSNS] = {
125 // 0x01, 0x0A, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
126 // 0x0C, 0x06, 0x0C, 0xFE, 0xF7, 0xFF, 0x12, 0xE0,
127 // 0x10, 0x97, 0x83, 0x7B, 0xF7, 0xFF, 0x12, 0xE0,
128 // 0x13, 0x97, 0x82, 0x7A, 0xF7, 0xFF, 0x12, 0xE0,
129 // 0x07, 0x0E, 0x0D, 0xF9, 0xF7, 0xFF, 0x12, 0xE0,
130 // 0x14, 0x96, 0x84, 0x76, 0xF7, 0xFF, 0x12, 0xE0,
131 // 0x17, 0x96, 0x85, 0x71, 0xF7, 0xFF, 0x12, 0xE0,
132 // 0xCE, 0xC5, 0x0F, 0x77, 0xF7, 0xFF, 0x12, 0xE0,
133 // 0xD2, 0x5A, 0x82, 0xF8, 0xF7, 0xFF, 0x12, 0xE0
134 // //0x04, 0x08, 0x9F, 0x78, 0x6E, 0xFF, 0x12, 0xE0
138 static int CmdHFiClassSim(const char *Cmd
) {
140 uint8_t CSN
[8] = {0, 0, 0, 0, 0, 0, 0, 0};
142 if (strlen(Cmd
) < 1) {
143 usage_hf_iclass_sim();
146 simType
= param_get8ex(Cmd
, 0, 0, 10);
148 if (simType
== ICLASS_SIM_MODE_CSN
) {
149 if (param_gethex(Cmd
, 1, CSN
, 16)) {
150 PrintAndLog("A CSN should consist of 16 HEX symbols");
151 usage_hf_iclass_sim();
154 PrintAndLog("--simtype:%02x csn:%s", simType
, sprint_hex(CSN
, 8));
157 if (simType
== ICLASS_SIM_MODE_READER_ATTACK
) {
158 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
, NUM_CSNS
}};
159 UsbCommand resp
= {0};
161 memcpy(c
.d
.asBytes
, csns
, 8 * NUM_CSNS
);
164 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, -1)) {
165 PrintAndLog("Command timed out");
169 uint8_t num_mac_responses
= resp
.arg
[1];
170 PrintAndLog("Mac responses: %d MACs obtained (should be %d)", num_mac_responses
, NUM_CSNS
);
172 size_t datalen
= NUM_CSNS
* 24;
174 * Now, time to dump to file. We'll use this format:
175 * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
176 * So, it should wind up as
179 * The returndata from the pm3 is on the following format
180 * <8 byte CC><4 byte NR><4 byte MAC>
181 * CSN is the same as was sent in
183 void* dump
= malloc(datalen
);
184 for(int i
= 0; i
< NUM_CSNS
; i
++) {
185 memcpy(dump
+ i
*24, csns
+i
*8, 8); //CSN
186 //copy CC from response
187 memcpy(dump
+ i
*24 + 8, resp
.d
.asBytes
+ i
*16, 8);
188 //Then comes NR_MAC (eight bytes from the response)
189 memcpy(dump
+ i
*24 + 16, resp
.d
.asBytes
+ i
*16 + 8, 8);
191 /** Now, save to dumpfile **/
192 saveFile("iclass_mac_attack", "bin", dump
,datalen
);
195 } else if (simType
== ICLASS_SIM_MODE_CSN
|| simType
== ICLASS_SIM_MODE_CSN_DEFAULT
|| simType
== ICLASS_SIM_MODE_FULL
) {
196 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
, 0}};
197 memcpy(c
.d
.asBytes
, CSN
, 8);
201 PrintAndLog("Undefined simtype %d", simType
);
202 usage_hf_iclass_sim();
210 int HFiClassReader(const char *Cmd
, bool loop
, bool verbose
) {
211 bool tagFound
= false;
212 UsbCommand c
= {CMD_READER_ICLASS
, {FLAG_ICLASS_READER_CSN
|
213 FLAG_ICLASS_READER_CC
| FLAG_ICLASS_READER_CONF
| FLAG_ICLASS_READER_AA
} };
214 // loop in client not device - else on windows have a communication error
218 if (WaitForResponseTimeout(CMD_ACK
,&resp
, 4500)) {
219 uint8_t readStatus
= resp
.arg
[0] & 0xff;
220 uint8_t *data
= resp
.d
.asBytes
;
222 // no tag found or button pressed
223 if( (readStatus
== 0 && !loop
) || readStatus
== 0xFF) {
225 if (verbose
) PrintAndLog("Quitting...");
229 if( readStatus
& FLAG_ICLASS_READER_CSN
) {
230 PrintAndLog(" CSN: %s",sprint_hex(data
,8));
233 if( readStatus
& FLAG_ICLASS_READER_CC
) {
234 PrintAndLog(" CC: %s",sprint_hex(data
+16,8));
236 if( readStatus
& FLAG_ICLASS_READER_CONF
) {
237 printIclassDumpInfo(data
);
239 if (readStatus
& FLAG_ICLASS_READER_AA
) {
241 PrintAndLog(" AppIA: %s",sprint_hex(data
+8*5,8));
242 for (int i
= 0; i
<8; i
++) {
243 if (data
[8*5+i
] != 0xFF) {
247 PrintAndLog(" : Possible iClass %s",(legacy
) ? "(legacy tag)" : "(NOT legacy tag)");
250 if (tagFound
&& !loop
) return 1;
252 if (verbose
) PrintAndLog("Command execute timeout");
260 static int CmdHFiClassReader(const char *Cmd
) {
261 return HFiClassReader(Cmd
, true, true);
265 static int CmdHFiClassReader_Replay(const char *Cmd
) {
266 uint8_t readerType
= 0;
267 uint8_t MAC
[4]={0x00, 0x00, 0x00, 0x00};
270 PrintAndLog("Usage: hf iclass replay <MAC>");
271 PrintAndLog(" sample: hf iclass replay 00112233");
275 if (param_gethex(Cmd
, 0, MAC
, 8)) {
276 PrintAndLog("MAC must include 8 HEX symbols");
280 UsbCommand c
= {CMD_READER_ICLASS_REPLAY
, {readerType
}};
281 memcpy(c
.d
.asBytes
, MAC
, 4);
288 static void usage_hf_iclass_eload(void) {
289 PrintAndLog("Loads iclass tag-dump into emulator memory on device");
290 PrintAndLog("Usage: hf iclass eload f <filename>");
292 PrintAndLog("Example: hf iclass eload f iclass_tagdump-aa162d30f8ff12f1.bin");
296 static int CmdHFiClassELoad(const char *Cmd
) {
298 char opt
= param_getchar(Cmd
, 0);
299 if (strlen(Cmd
)<1 || opt
== 'h') {
300 usage_hf_iclass_eload();
304 //File handling and reading
306 char filename
[FILE_PATH_SIZE
];
307 if (opt
== 'f' && param_getstr(Cmd
, 1, filename
, sizeof(filename
)) > 0) {
308 f
= fopen(filename
, "rb");
310 usage_hf_iclass_eload();
315 PrintAndLog("Failed to read from file '%s'", filename
);
319 fseek(f
, 0, SEEK_END
);
320 long fsize
= ftell(f
);
321 fseek(f
, 0, SEEK_SET
);
324 PrintAndLog("Error, when getting filesize");
329 uint8_t *dump
= malloc(fsize
);
331 size_t bytes_read
= fread(dump
, 1, fsize
, f
);
334 printIclassDumpInfo(dump
);
337 if (bytes_read
< fsize
) {
338 prnlog("Error, could only read %d bytes (should be %d)",bytes_read
, fsize
);
343 uint32_t bytes_sent
= 0;
344 uint32_t bytes_remaining
= bytes_read
;
346 while (bytes_remaining
> 0) {
347 uint32_t bytes_in_packet
= MIN(USB_CMD_DATA_SIZE
, bytes_remaining
);
348 UsbCommand c
= {CMD_ICLASS_EML_MEMSET
, {bytes_sent
,bytes_in_packet
,0}};
349 memcpy(c
.d
.asBytes
, dump
+bytes_sent
, bytes_in_packet
);
351 bytes_remaining
-= bytes_in_packet
;
352 bytes_sent
+= bytes_in_packet
;
355 PrintAndLog("Sent %d bytes of data to device emulator memory", bytes_sent
);
360 static int readKeyfile(const char *filename
, size_t len
, uint8_t* buffer
) {
361 FILE *f
= fopen(filename
, "rb");
363 PrintAndLog("Failed to read from file '%s'", filename
);
366 fseek(f
, 0, SEEK_END
);
367 long fsize
= ftell(f
);
368 fseek(f
, 0, SEEK_SET
);
369 size_t bytes_read
= fread(buffer
, 1, len
, f
);
373 PrintAndLog("Warning, file size is %d, expected %d", fsize
, len
);
376 if(bytes_read
!= len
)
378 PrintAndLog("Warning, could only read %d bytes, expected %d" ,bytes_read
, len
);
385 static void usage_hf_iclass_decrypt(void) {
386 PrintAndLog("Usage: hf iclass decrypt f <tagdump>");
388 PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside");
389 PrintAndLog("in the working directory. The file should be 16 bytes binary data");
391 PrintAndLog("example: hf iclass decrypt f tagdump_12312342343.bin");
393 PrintAndLog("OBS! This is pretty stupid implementation, it tries to decrypt every block after block 6. ");
394 PrintAndLog("Correct behaviour would be to decrypt only the application areas where the key is valid,");
395 PrintAndLog("which is defined by the configuration block.");
399 static int CmdHFiClassDecrypt(const char *Cmd
) {
400 uint8_t key
[16] = { 0 };
401 if(readKeyfile("iclass_decryptionkey.bin", 16, key
))
403 usage_hf_iclass_decrypt();
406 PrintAndLog("Decryption file found... ");
407 char opt
= param_getchar(Cmd
, 0);
408 if (strlen(Cmd
)<1 || opt
== 'h') {
409 usage_hf_iclass_decrypt();
413 //Open the tagdump-file
415 char filename
[FILE_PATH_SIZE
];
416 if(opt
== 'f' && param_getstr(Cmd
, 1, filename
, sizeof(filename
)) > 0) {
417 f
= fopen(filename
, "rb");
419 PrintAndLog("Could not find file %s", filename
);
423 usage_hf_iclass_decrypt();
427 fseek(f
, 0, SEEK_END
);
428 long fsize
= ftell(f
);
429 fseek(f
, 0, SEEK_SET
);
430 uint8_t enc_dump
[8] = {0};
431 uint8_t *decrypted
= malloc(fsize
);
432 mbedtls_des3_context ctx
= { {0} };
433 mbedtls_des3_set2key_dec( &ctx
, key
);
434 size_t bytes_read
= fread(enc_dump
, 1, 8, f
);
436 //Use the first block (CSN) for filename
437 char outfilename
[FILE_PATH_SIZE
] = { 0 };
438 snprintf(outfilename
,FILE_PATH_SIZE
,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x-decrypted",
439 enc_dump
[0],enc_dump
[1],enc_dump
[2],enc_dump
[3],
440 enc_dump
[4],enc_dump
[5],enc_dump
[6],enc_dump
[7]);
443 while(bytes_read
== 8)
447 memcpy(decrypted
+(blocknum
*8), enc_dump
, 8);
449 mbedtls_des3_crypt_ecb(&ctx
, enc_dump
,decrypted
+(blocknum
*8) );
451 printvar("decrypted block", decrypted
+(blocknum
*8), 8);
452 bytes_read
= fread(enc_dump
, 1, 8, f
);
457 saveFile(outfilename
,"bin", decrypted
, blocknum
*8);
463 static void usage_hf_iclass_encrypt(void) {
464 PrintAndLog("Usage: hf iclass encrypt <BlockData>");
466 PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside");
467 PrintAndLog("in the working directory. The file should be 16 bytes binary data");
469 PrintAndLog("example: hf iclass encrypt 0102030405060708");
474 static int iClassEncryptBlkData(uint8_t *blkData
) {
475 uint8_t key
[16] = { 0 };
476 if(readKeyfile("iclass_decryptionkey.bin", 16, key
))
478 usage_hf_iclass_encrypt();
481 PrintAndLog("Decryption file found... ");
483 uint8_t encryptedData
[16];
484 uint8_t *encrypted
= encryptedData
;
485 mbedtls_des3_context ctx
= { {0} };
486 mbedtls_des3_set2key_enc( &ctx
, key
);
488 mbedtls_des3_crypt_ecb(&ctx
, blkData
,encrypted
);
489 //printvar("decrypted block", decrypted, 8);
490 memcpy(blkData
,encrypted
,8);
496 static int CmdHFiClassEncryptBlk(const char *Cmd
) {
497 uint8_t blkData
[8] = {0};
498 char opt
= param_getchar(Cmd
, 0);
499 if (strlen(Cmd
)<1 || opt
== 'h') {
500 usage_hf_iclass_encrypt();
503 //get the bytes to encrypt
504 if (param_gethex(Cmd
, 0, blkData
, 16)) {
505 PrintAndLog("BlockData must include 16 HEX symbols");
508 if (!iClassEncryptBlkData(blkData
)) return 0;
509 printvar("encrypted block", blkData
, 8);
514 static void Calc_wb_mac(uint8_t blockno
, uint8_t *data
, uint8_t *div_key
, uint8_t MAC
[4]) {
517 memcpy(WB
+ 1,data
,8);
518 doMAC_N(WB
,sizeof(WB
),div_key
,MAC
);
519 //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]);
523 static bool select_only(uint8_t *CSN
, bool verbose
) {
526 UsbCommand c
= {CMD_READER_ICLASS
, {0}};
528 clearCommandBuffer();
530 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
531 PrintAndLog("Command execute timeout");
535 uint8_t isOK
= resp
.arg
[0] & 0xff;
536 uint8_t *data
= resp
.d
.asBytes
;
538 memcpy(CSN
, data
, 8);
541 if (verbose
) PrintAndLog("CSN: %s", sprint_hex(CSN
, 8));
543 PrintAndLog("Failed to select card! Aborting");
550 static void HFiClassCalcDivKey(uint8_t *CSN
, uint8_t *KEY
, uint8_t *div_key
, bool elite
){
551 uint8_t keytable
[128] = {0};
552 uint8_t key_index
[8] = {0};
554 uint8_t key_sel
[8] = { 0 };
555 uint8_t key_sel_p
[8] = { 0 };
556 hash2(KEY
, keytable
);
557 hash1(CSN
, key_index
);
558 for(uint8_t i
= 0; i
< 8 ; i
++)
559 key_sel
[i
] = keytable
[key_index
[i
]] & 0xFF;
561 //Permute from iclass format to standard format
562 permutekey_rev(key_sel
, key_sel_p
);
563 diversifyKey(CSN
, key_sel_p
, div_key
);
565 diversifyKey(CSN
, KEY
, div_key
);
570 static bool select_and_auth(uint8_t *KEY
, uint8_t *MAC
, uint8_t *div_key
, bool use_credit_key
, bool elite
, bool rawkey
, bool verbose
) {
571 uint8_t CSN
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
572 uint8_t CCNR
[12] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
574 if (!select_only(CSN
, verbose
))
579 memcpy(div_key
, KEY
, 8);
581 HFiClassCalcDivKey(CSN
, KEY
, div_key
, elite
);
583 if (verbose
) PrintAndLog("Authenticating with %s: %s", rawkey
? "raw key" : "diversified key", sprint_hex(div_key
, 8));
586 UsbCommand d
= {CMD_ICLASS_READCHECK
, {2, use_credit_key
, 0}};
588 clearCommandBuffer();
591 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
592 if (verbose
) PrintAndLog("Auth Command (READCHECK[2]) execute timeout");
595 bool isOK
= resp
.arg
[0];
597 if (verbose
) PrintAndLog("Couldn't get Card Challenge");
600 memcpy(CCNR
, resp
.d
.asBytes
, 8);
602 doMAC(CCNR
, div_key
, MAC
);
604 d
.cmd
= CMD_ICLASS_CHECK
;
605 memcpy(d
.d
.asBytes
, MAC
, 4);
606 clearCommandBuffer();
608 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
609 if (verbose
) PrintAndLog("Auth Command (CHECK) execute timeout");
614 if (verbose
) PrintAndLog("Authentication error");
621 static void usage_hf_iclass_dump(void) {
622 PrintAndLog("Usage: hf iclass dump f <fileName> k <Key> c <CreditKey> e|r\n");
623 PrintAndLog("Options:");
624 PrintAndLog(" f <filename> : specify a filename to save dump to");
625 PrintAndLog(" k <Key> : *Access Key as 16 hex symbols or 1 hex to select key from memory");
626 PrintAndLog(" c <CreditKey>: Credit Key as 16 hex symbols or 1 hex to select key from memory");
627 PrintAndLog(" e : If 'e' is specified, the key is interpreted as the 16 byte");
628 PrintAndLog(" Custom Key (KCus), which can be obtained via reader-attack");
629 PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format");
630 PrintAndLog(" r : If 'r' is specified, the key is interpreted as raw block 3/4");
631 PrintAndLog(" NOTE: * = required");
632 PrintAndLog("Samples:");
633 PrintAndLog(" hf iclass dump k 001122334455667B");
634 PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA c 001122334455667B");
635 PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA e");
639 static void printIclassDumpContents(uint8_t *iclass_dump
, uint8_t startblock
, uint8_t endblock
, size_t filesize
) {
641 memcpy(&mem_config
, iclass_dump
+ 13,1);
643 uint8_t filemaxblock
= filesize
/ 8;
644 if (mem_config
& 0x80)
648 //PrintAndLog ("endblock: %d, filesize: %d, maxmemcount: %d, filemaxblock: %d", endblock,filesize, maxmemcount, filemaxblock);
652 if ((endblock
> maxmemcount
) || (endblock
== 0))
653 endblock
= maxmemcount
;
655 // remember endblock need to relate to zero-index arrays.
656 if (endblock
> filemaxblock
-1)
657 endblock
= filemaxblock
;
660 printf("------+--+-------------------------+\n");
661 while (i
<= endblock
) {
662 uint8_t *blk
= iclass_dump
+ (i
* 8);
663 printf("Block |%02X| %s|\n", i
, sprint_hex(blk
, 8) );
666 printf("------+--+-------------------------+\n");
670 static int CmdHFiClassReader_Dump(const char *Cmd
) {
672 uint8_t MAC
[4] = {0x00,0x00,0x00,0x00};
673 uint8_t div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
674 uint8_t c_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
678 uint8_t app_areas
= 1;
680 uint8_t KEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
681 uint8_t CreditKEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
684 uint8_t fileNameLen
= 0;
685 char filename
[FILE_PATH_SIZE
]={0};
686 char tempStr
[50] = {0};
687 bool have_debit_key
= false;
688 bool have_credit_key
= false;
689 bool use_credit_key
= false;
695 while(param_getchar(Cmd
, cmdp
) != 0x00)
697 switch(param_getchar(Cmd
, cmdp
))
701 usage_hf_iclass_dump();
705 have_credit_key
= true;
706 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
708 errors
= param_gethex(tempStr
, 0, CreditKEY
, dataLen
);
709 } else if (dataLen
== 1) {
710 keyNbr
= param_get8(Cmd
, cmdp
+1);
711 if (keyNbr
< ICLASS_KEYS_MAX
) {
712 memcpy(CreditKEY
, iClass_Key_Table
[keyNbr
], 8);
714 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
718 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
730 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
731 if (fileNameLen
< 1) {
732 PrintAndLog("No filename found after f");
739 have_debit_key
= true;
740 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
742 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
743 } else if (dataLen
== 1) {
744 keyNbr
= param_get8(Cmd
, cmdp
+1);
745 if (keyNbr
< ICLASS_KEYS_MAX
) {
746 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
748 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
752 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
763 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
768 usage_hf_iclass_dump();
774 usage_hf_iclass_dump();
777 // if no debit key given try credit key on AA1 (not for iclass but for some picopass this will work)
778 if (!have_debit_key
&& have_credit_key
) use_credit_key
= true;
780 //get config and first 3 blocks
781 UsbCommand c
= {CMD_READER_ICLASS
, {FLAG_ICLASS_READER_CSN
| FLAG_ICLASS_READER_CONF
}};
783 uint8_t tag_data
[255*8];
785 clearCommandBuffer();
787 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
788 PrintAndLog("Command execute timeout");
792 uint8_t readStatus
= resp
.arg
[0] & 0xff;
793 uint8_t *data
= resp
.d
.asBytes
;
796 PrintAndLog("No tag found...");
800 if( readStatus
& (FLAG_ICLASS_READER_CSN
|FLAG_ICLASS_READER_CONF
|FLAG_ICLASS_READER_CC
)){
801 memcpy(tag_data
, data
, 8*3);
802 blockno
+=2; // 2 to force re-read of block 2 later. (seems to respond differently..)
804 getMemConfig(data
[13], data
[12], &maxBlk
, &app_areas
, &kb
);
805 // large memory - not able to dump pages currently
806 if (numblks
> maxBlk
) numblks
= maxBlk
;
809 // authenticate debit key and get div_key - later store in dump block 3
810 if (!select_and_auth(KEY
, MAC
, div_key
, use_credit_key
, elite
, rawkey
, false)){
811 //try twice - for some reason it sometimes fails the first time...
812 if (!select_and_auth(KEY
, MAC
, div_key
, use_credit_key
, elite
, rawkey
, false)){
819 UsbCommand w
= {CMD_ICLASS_DUMP
, {blockno
, numblks
-blockno
+1}};
820 clearCommandBuffer();
822 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
823 PrintAndLog("Command execute time-out 1");
827 uint32_t blocksRead
= resp
.arg
[1];
828 uint8_t isOK
= resp
.arg
[0] & 0xff;
829 if (!isOK
&& !blocksRead
) {
830 PrintAndLog("Read Block Failed");
834 uint32_t startindex
= resp
.arg
[2];
835 if (blocksRead
*8 > sizeof(tag_data
)-(blockno
*8)) {
836 PrintAndLog("Data exceeded Buffer size!");
837 blocksRead
= (sizeof(tag_data
)/8) - blockno
;
839 // response ok - now get bigbuf content of the dump
840 GetFromBigBuf(tag_data
+(blockno
*8), blocksRead
*8, startindex
, NULL
, -1, false);
841 size_t gotBytes
= blocksRead
*8 + blockno
*8;
844 if (have_credit_key
) {
845 //turn off hf field before authenticating with different key
848 // AA2 authenticate credit key and git c_div_key - later store in dump block 4
849 if (!select_and_auth(CreditKEY
, MAC
, c_div_key
, true, false, false, false)){
850 //try twice - for some reason it sometimes fails the first time...
851 if (!select_and_auth(CreditKEY
, MAC
, c_div_key
, true, false, false, false)){
856 // do we still need to read more block? (aa2 enabled?)
857 if (maxBlk
> blockno
+numblks
+1) {
858 // setup dump and start
859 w
.arg
[0] = blockno
+ blocksRead
;
860 w
.arg
[1] = maxBlk
- (blockno
+ blocksRead
);
861 clearCommandBuffer();
863 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
864 PrintAndLog("Command execute timeout 2");
868 uint8_t isOK
= resp
.arg
[0] & 0xff;
869 blocksRead
= resp
.arg
[1];
870 if (!isOK
&& !blocksRead
) {
871 PrintAndLog("Read Block Failed 2");
876 startindex
= resp
.arg
[2];
877 if (blocksRead
*8 > sizeof(tag_data
)-gotBytes
) {
878 PrintAndLog("Data exceeded Buffer size!");
879 blocksRead
= (sizeof(tag_data
) - gotBytes
)/8;
881 // get dumped data from bigbuf
882 GetFromBigBuf(tag_data
+gotBytes
, blocksRead
*8, startindex
, NULL
, -1, false);
884 gotBytes
+= blocksRead
*8;
885 } else { //field is still on - turn it off...
890 // add diversified keys to dump
891 if (have_debit_key
) memcpy(tag_data
+(3*8),div_key
,8);
892 if (have_credit_key
) memcpy(tag_data
+(4*8),c_div_key
,8);
894 printf("------+--+-------------------------+\n");
895 printf("CSN |00| %s|\n",sprint_hex(tag_data
, 8));
896 printIclassDumpContents(tag_data
, 1, (gotBytes
/8), gotBytes
);
898 if (filename
[0] == 0){
899 snprintf(filename
, FILE_PATH_SIZE
,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x",
900 tag_data
[0],tag_data
[1],tag_data
[2],tag_data
[3],
901 tag_data
[4],tag_data
[5],tag_data
[6],tag_data
[7]);
904 // save the dump to .bin file
905 PrintAndLog("Saving dump file - %d blocks read", gotBytes
/8);
906 saveFile(filename
, "bin", tag_data
, gotBytes
);
911 static int WriteBlock(uint8_t blockno
, uint8_t *bldata
, uint8_t *KEY
, bool use_credit_key
, bool elite
, bool rawkey
, bool verbose
) {
912 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
913 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
914 if (!select_and_auth(KEY
, MAC
, div_key
, use_credit_key
, elite
, rawkey
, verbose
))
919 Calc_wb_mac(blockno
,bldata
,div_key
,MAC
);
920 UsbCommand w
= {CMD_ICLASS_WRITEBLOCK
, {blockno
}};
921 memcpy(w
.d
.asBytes
, bldata
, 8);
922 memcpy(w
.d
.asBytes
+ 8, MAC
, 4);
924 clearCommandBuffer();
926 if (!WaitForResponseTimeout(CMD_ACK
,&resp
,4500))
928 PrintAndLog("Write Command execute timeout");
931 uint8_t isOK
= resp
.arg
[0] & 0xff;
933 PrintAndLog("Write Block Failed");
936 PrintAndLog("Write Block Successful");
941 static void usage_hf_iclass_writeblock(void) {
942 PrintAndLog("Options:");
943 PrintAndLog(" b <Block> : The block number as 2 hex symbols");
944 PrintAndLog(" d <data> : Set the Data to write as 16 hex symbols");
945 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
946 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
947 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
948 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
949 PrintAndLog("Samples:");
950 PrintAndLog(" hf iclass writeblk b 0A d AAAAAAAAAAAAAAAA k 001122334455667B");
951 PrintAndLog(" hf iclass writeblk b 1B d AAAAAAAAAAAAAAAA k 001122334455667B c");
952 PrintAndLog(" hf iclass writeblk b 0A d AAAAAAAAAAAAAAAA n 0");
956 static int CmdHFiClass_WriteBlock(const char *Cmd
) {
958 uint8_t bldata
[8]={0,0,0,0,0,0,0,0};
959 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
962 char tempStr
[50] = {0};
963 bool use_credit_key
= false;
968 while(param_getchar(Cmd
, cmdp
) != 0x00)
970 switch(param_getchar(Cmd
, cmdp
))
974 usage_hf_iclass_writeblock();
978 if (param_gethex(Cmd
, cmdp
+1, &blockno
, 2)) {
979 PrintAndLog("Block No must include 2 HEX symbols\n");
986 use_credit_key
= true;
991 if (param_gethex(Cmd
, cmdp
+1, bldata
, 16))
993 PrintAndLog("KEY must include 16 HEX symbols\n");
1005 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1006 if (dataLen
== 16) {
1007 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1008 } else if (dataLen
== 1) {
1009 keyNbr
= param_get8(Cmd
, cmdp
+1);
1010 if (keyNbr
< ICLASS_KEYS_MAX
) {
1011 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
1013 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1017 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1028 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1033 usage_hf_iclass_writeblock();
1039 usage_hf_iclass_writeblock();
1042 int ans
= WriteBlock(blockno
, bldata
, KEY
, use_credit_key
, elite
, rawkey
, true);
1048 static void usage_hf_iclass_clone(void) {
1049 PrintAndLog("Usage: hf iclass clone f <tagfile.bin> b <first block> l <last block> k <KEY> c e|r");
1050 PrintAndLog("Options:");
1051 PrintAndLog(" f <filename>: specify a filename to clone from");
1052 PrintAndLog(" b <Block> : The first block to clone as 2 hex symbols");
1053 PrintAndLog(" l <Last Blk>: Set the Data to write as 16 hex symbols");
1054 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
1055 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
1056 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
1057 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
1058 PrintAndLog("Samples:");
1059 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 1A k 1122334455667788 e");
1060 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 05 l 19 k 0");
1061 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 19 k 0 e");
1065 static int CmdHFiClassCloneTag(const char *Cmd
) {
1066 char filename
[FILE_PATH_SIZE
] = {0};
1067 char tempStr
[50]={0};
1068 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1070 uint8_t fileNameLen
= 0;
1071 uint8_t startblock
= 0;
1072 uint8_t endblock
= 0;
1073 uint8_t dataLen
= 0;
1074 bool use_credit_key
= false;
1076 bool rawkey
= false;
1077 bool errors
= false;
1079 while(param_getchar(Cmd
, cmdp
) != 0x00)
1081 switch(param_getchar(Cmd
, cmdp
))
1085 usage_hf_iclass_clone();
1089 if (param_gethex(Cmd
, cmdp
+1, &startblock
, 2)) {
1090 PrintAndLog("Start Block No must include 2 HEX symbols\n");
1097 use_credit_key
= true;
1107 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
1108 if (fileNameLen
< 1) {
1109 PrintAndLog("No filename found after f");
1116 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1117 if (dataLen
== 16) {
1118 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1119 } else if (dataLen
== 1) {
1120 keyNbr
= param_get8(Cmd
, cmdp
+1);
1121 if (keyNbr
< ICLASS_KEYS_MAX
) {
1122 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
1124 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1128 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1135 if (param_gethex(Cmd
, cmdp
+1, &endblock
, 2)) {
1136 PrintAndLog("Start Block No must include 2 HEX symbols\n");
1147 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1152 usage_hf_iclass_clone();
1158 usage_hf_iclass_clone();
1164 iclass_block_t tag_data
[USB_CMD_DATA_SIZE
/12];
1166 if ((endblock
-startblock
+1)*12 > USB_CMD_DATA_SIZE
) {
1167 PrintAndLog("Trying to write too many blocks at once. Max: %d", USB_CMD_DATA_SIZE
/8);
1169 // file handling and reading
1170 f
= fopen(filename
,"rb");
1172 PrintAndLog("Failed to read from file '%s'", filename
);
1177 PrintAndLog("You cannot write key blocks this way. yet... make your start block > 4");
1181 // now read data from the file from block 6 --- 19
1182 // ok we will use this struct [data 8 bytes][MAC 4 bytes] for each block calculate all mac number for each data
1183 // 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,
1184 // else we have to create a share memory
1186 fseek(f
,startblock
*8,SEEK_SET
);
1187 if ( fread(tag_data
,sizeof(iclass_block_t
),endblock
- startblock
+ 1,f
) == 0 ) {
1188 PrintAndLog("File reading error.");
1193 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
1194 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1196 if (!select_and_auth(KEY
, MAC
, div_key
, use_credit_key
, elite
, rawkey
, true))
1199 UsbCommand w
= {CMD_ICLASS_CLONE
,{startblock
,endblock
}};
1201 // calculate all mac for every the block we will write
1202 for (i
= startblock
; i
<= endblock
; i
++){
1203 Calc_wb_mac(i
,tag_data
[i
- startblock
].d
,div_key
,MAC
);
1204 // usb command d start pointer = d + (i - 6) * 12
1205 // memcpy(pointer,tag_data[i - 6],8) 8 bytes
1206 // memcpy(pointer + 8,mac,sizoof(mac) 4 bytes;
1208 ptr
= w
.d
.asBytes
+ (i
- startblock
) * 12;
1209 memcpy(ptr
, &(tag_data
[i
- startblock
].d
[0]), 8);
1210 memcpy(ptr
+ 8,MAC
, 4);
1213 for (i
= 0; i
<= endblock
- startblock
;i
++){
1214 memcpy(p
,w
.d
.asBytes
+ (i
* 12),12);
1215 printf("Block |%02x|",i
+ startblock
);
1216 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]);
1217 printf(" MAC |%02x%02x%02x%02x|\n",p
[8],p
[9],p
[10],p
[11]);
1221 if (!WaitForResponseTimeout(CMD_ACK
,&resp
,4500))
1223 PrintAndLog("Command execute timeout");
1230 static int ReadBlock(uint8_t *KEY
, uint8_t blockno
, uint8_t keyType
, bool elite
, bool rawkey
, bool verbose
, bool auth
) {
1232 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
1233 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1236 if (!select_and_auth(KEY
, MAC
, div_key
, (keyType
==0x18), elite
, rawkey
, verbose
))
1240 if (!select_only(CSN
, verbose
))
1245 UsbCommand w
= {CMD_ICLASS_READBLOCK
, {blockno
}};
1246 clearCommandBuffer();
1248 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 4500)) {
1249 PrintAndLog("Command execute timeout");
1252 uint8_t isOK
= resp
.arg
[0] & 0xff;
1254 PrintAndLog("Read Block Failed");
1257 //data read is stored in: resp.d.asBytes[0-15]
1258 if (verbose
) PrintAndLog("Block %02X: %s\n",blockno
, sprint_hex(resp
.d
.asBytes
,8));
1263 static void usage_hf_iclass_readblock(void) {
1264 PrintAndLog("Usage: hf iclass readblk b <Block> k <Key> [c] [e|r]\n");
1265 PrintAndLog("Options:");
1266 PrintAndLog(" b <Block> : The block number as 2 hex symbols");
1267 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
1268 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
1269 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
1270 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
1271 PrintAndLog("Samples:");
1272 PrintAndLog(" hf iclass readblk b 06 k 0011223344556677");
1273 PrintAndLog(" hf iclass readblk b 1B k 0011223344556677 c");
1274 PrintAndLog(" hf iclass readblk b 0A k 0");
1278 static int CmdHFiClass_ReadBlock(const char *Cmd
) {
1280 uint8_t keyType
= 0x88; //debit key
1281 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1283 uint8_t dataLen
= 0;
1284 char tempStr
[50] = {0};
1286 bool rawkey
= false;
1287 bool errors
= false;
1290 while (param_getchar(Cmd
, cmdp
) != 0x00) {
1291 switch (param_getchar(Cmd
, cmdp
)) {
1294 usage_hf_iclass_readblock();
1298 if (param_gethex(Cmd
, cmdp
+1, &blockno
, 2)) {
1299 PrintAndLog("Block No must include 2 HEX symbols\n");
1317 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1318 if (dataLen
== 16) {
1319 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1320 } else if (dataLen
== 1) {
1321 keyNbr
= param_get8(Cmd
, cmdp
+1);
1322 if (keyNbr
< ICLASS_KEYS_MAX
) {
1323 memcpy(KEY
, iClass_Key_Table
[keyNbr
], 8);
1325 PrintAndLog("\nERROR: KeyNbr is invalid\n");
1329 PrintAndLog("\nERROR: Key is incorrect length\n");
1340 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1345 usage_hf_iclass_readblock();
1351 usage_hf_iclass_readblock();
1355 PrintAndLog("warning: no authentication used with read, only a few specific blocks can be read accurately without authentication.");
1357 return ReadBlock(KEY
, blockno
, keyType
, elite
, rawkey
, true, auth
);
1361 static int CmdHFiClass_loclass(const char *Cmd
) {
1362 char opt
= param_getchar(Cmd
, 0);
1364 if (strlen(Cmd
)<1 || opt
== 'h') {
1365 PrintAndLog("Usage: hf iclass loclass [options]");
1366 PrintAndLog("Options:");
1367 PrintAndLog("h Show this help");
1368 PrintAndLog("t Perform self-test");
1369 PrintAndLog("f <filename> Bruteforce iclass dumpfile");
1370 PrintAndLog(" An iclass dumpfile is assumed to consist of an arbitrary number of");
1371 PrintAndLog(" malicious CSNs, and their protocol responses");
1372 PrintAndLog(" The binary format of the file is expected to be as follows: ");
1373 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1374 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1375 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1376 PrintAndLog(" ... totalling N*24 bytes");
1379 char fileName
[255] = {0};
1381 if(param_getstr(Cmd
, 1, fileName
, sizeof(fileName
)) > 0) {
1382 return bruteforceFileNoKeys(fileName
);
1384 PrintAndLog("You must specify a filename");
1386 } else if(opt
== 't') {
1387 int errors
= testCipherUtils();
1388 errors
+= testMAC();
1389 errors
+= doKeyTests(0);
1390 errors
+= testElite();
1392 prnlog("OBS! There were errors!!!");
1401 static void usage_hf_iclass_readtagfile() {
1402 PrintAndLog("Usage: hf iclass readtagfile <filename> [startblock] [endblock]");
1406 static int CmdHFiClassReadTagFile(const char *Cmd
) {
1411 char filename
[FILE_PATH_SIZE
];
1412 if (param_getstr(Cmd
, 0, filename
, sizeof(filename
)) < 1) {
1413 usage_hf_iclass_readtagfile();
1416 if (param_getstr(Cmd
, 1, tempnum
, sizeof(tempnum
)) < 1)
1419 sscanf(tempnum
,"%d",&startblock
);
1421 if (param_getstr(Cmd
,2, tempnum
, sizeof(tempnum
)) < 1)
1424 sscanf(tempnum
,"%d",&endblock
);
1425 // file handling and reading
1426 f
= fopen(filename
,"rb");
1428 PrintAndLog("Failed to read from file '%s'", filename
);
1431 fseek(f
, 0, SEEK_END
);
1432 long fsize
= ftell(f
);
1433 fseek(f
, 0, SEEK_SET
);
1436 PrintAndLog("Error, when getting filesize");
1441 uint8_t *dump
= malloc(fsize
);
1443 size_t bytes_read
= fread(dump
, 1, fsize
, f
);
1445 uint8_t *csn
= dump
;
1446 printf("------+--+-------------------------+\n");
1447 printf("CSN |00| %s|\n", sprint_hex(csn
, 8) );
1448 // printIclassDumpInfo(dump);
1449 printIclassDumpContents(dump
,startblock
,endblock
,bytes_read
);
1455 uint64_t xorcheck(uint64_t sdiv,uint64_t hdiv) {
1456 uint64_t new_div = 0x00;
1462 uint64_t hexarray_to_uint64(uint8_t *key) {
1465 for (int i = 0;i < 8;i++)
1466 sprintf(&temp[(i *2)],"%02X",key[i]);
1468 if (sscanf(temp,"%016" SCNx64,&uint_key) < 1)
1475 //when told CSN, oldkey, newkey, if new key is elite (elite), and if old key was elite (oldElite)
1476 //calculate and return xor_div_key (ready for a key write command)
1477 //print all div_keys if verbose
1478 static void HFiClassCalcNewKey(uint8_t *CSN
, uint8_t *OLDKEY
, uint8_t *NEWKEY
, uint8_t *xor_div_key
, bool elite
, bool oldElite
, bool verbose
){
1479 uint8_t old_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1480 uint8_t new_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1482 HFiClassCalcDivKey(CSN
, OLDKEY
, old_div_key
, oldElite
);
1484 HFiClassCalcDivKey(CSN
, NEWKEY
, new_div_key
, elite
);
1486 for (uint8_t i
= 0; i
< sizeof(old_div_key
); i
++){
1487 xor_div_key
[i
] = old_div_key
[i
] ^ new_div_key
[i
];
1490 printf("Old Div Key : %s\n",sprint_hex(old_div_key
,8));
1491 printf("New Div Key : %s\n",sprint_hex(new_div_key
,8));
1492 printf("Xor Div Key : %s\n",sprint_hex(xor_div_key
,8));
1497 static void usage_hf_iclass_calc_newkey(void) {
1498 PrintAndLog("HELP : Manage iClass Keys in client memory:\n");
1499 PrintAndLog("Usage: hf iclass calc_newkey o <Old key> n <New key> s [csn] e");
1500 PrintAndLog(" Options:");
1501 PrintAndLog(" o <oldkey> : *specify a key as 16 hex symbols or a key number as 1 symbol");
1502 PrintAndLog(" n <newkey> : *specify a key as 16 hex symbols or a key number as 1 symbol");
1503 PrintAndLog(" s <csn> : specify a card Serial number to diversify the key (if omitted will attempt to read a csn)");
1504 PrintAndLog(" e : specify new key as elite calc");
1505 PrintAndLog(" ee : specify old and new key as elite calc");
1506 PrintAndLog("Samples:");
1507 PrintAndLog(" e key to e key given csn : hf iclass calcnewkey o 1122334455667788 n 2233445566778899 s deadbeafdeadbeaf ee");
1508 PrintAndLog(" std key to e key read csn: hf iclass calcnewkey o 1122334455667788 n 2233445566778899 e");
1509 PrintAndLog(" std to std read csn : hf iclass calcnewkey o 1122334455667788 n 2233445566778899");
1510 PrintAndLog("NOTE: * = required\n");
1514 static int CmdHFiClassCalcNewKey(const char *Cmd
) {
1515 uint8_t OLDKEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1516 uint8_t NEWKEY
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1517 uint8_t xor_div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1518 uint8_t CSN
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1520 uint8_t dataLen
= 0;
1521 char tempStr
[50] = {0};
1522 bool givenCSN
= false;
1523 bool oldElite
= false;
1525 bool errors
= false;
1527 while(param_getchar(Cmd
, cmdp
) != 0x00)
1529 switch(param_getchar(Cmd
, cmdp
))
1533 usage_hf_iclass_calc_newkey();
1537 dataLen
= param_getstr(Cmd
, cmdp
, tempStr
, sizeof(tempStr
));
1545 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1546 if (dataLen
== 16) {
1547 errors
= param_gethex(tempStr
, 0, NEWKEY
, dataLen
);
1548 } else if (dataLen
== 1) {
1549 keyNbr
= param_get8(Cmd
, cmdp
+1);
1550 if (keyNbr
< ICLASS_KEYS_MAX
) {
1551 memcpy(NEWKEY
, iClass_Key_Table
[keyNbr
], 8);
1553 PrintAndLog("\nERROR: NewKey Nbr is invalid\n");
1557 PrintAndLog("\nERROR: NewKey is incorrect length\n");
1564 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1565 if (dataLen
== 16) {
1566 errors
= param_gethex(tempStr
, 0, OLDKEY
, dataLen
);
1567 } else if (dataLen
== 1) {
1568 keyNbr
= param_get8(Cmd
, cmdp
+1);
1569 if (keyNbr
< ICLASS_KEYS_MAX
) {
1570 memcpy(OLDKEY
, iClass_Key_Table
[keyNbr
], 8);
1572 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1576 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1584 if (param_gethex(Cmd
, cmdp
+1, CSN
, 16)) {
1585 usage_hf_iclass_calc_newkey();
1591 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1596 usage_hf_iclass_calc_newkey();
1602 usage_hf_iclass_calc_newkey();
1607 if (!select_only(CSN
, true))
1610 HFiClassCalcNewKey(CSN
, OLDKEY
, NEWKEY
, xor_div_key
, elite
, oldElite
, true);
1615 static int loadKeys(char *filename
) {
1617 f
= fopen(filename
,"rb");
1619 PrintAndLog("Failed to read from file '%s'", filename
);
1622 fseek(f
, 0, SEEK_END
);
1623 long fsize
= ftell(f
);
1624 fseek(f
, 0, SEEK_SET
);
1627 PrintAndLog("Error, when getting filesize");
1632 uint8_t *dump
= malloc(fsize
);
1634 size_t bytes_read
= fread(dump
, 1, fsize
, f
);
1636 if (bytes_read
> ICLASS_KEYS_MAX
* 8){
1637 PrintAndLog("File is too long to load - bytes: %u", bytes_read
);
1642 for (; i
< bytes_read
/8; i
++){
1643 memcpy(iClass_Key_Table
[i
],dump
+(i
*8),8);
1646 PrintAndLog("%u keys loaded", i
);
1651 static int saveKeys(char *filename
) {
1653 f
= fopen(filename
,"wb");
1655 printf("error opening file %s\n",filename
);
1658 for (uint8_t i
= 0; i
< ICLASS_KEYS_MAX
; i
++){
1659 if (fwrite(iClass_Key_Table
[i
],8,1,f
) != 1){
1660 PrintAndLog("save key failed to write to file: %s", filename
);
1669 static int printKeys(void) {
1671 for (uint8_t i
= 0; i
< ICLASS_KEYS_MAX
; i
++){
1672 PrintAndLog("%u: %s",i
,sprint_hex(iClass_Key_Table
[i
],8));
1679 static void usage_hf_iclass_managekeys(void) {
1680 PrintAndLog("HELP : Manage iClass Keys in client memory:\n");
1681 PrintAndLog("Usage: hf iclass managekeys n [keynbr] k [key] f [filename] s l p\n");
1682 PrintAndLog(" Options:");
1683 PrintAndLog(" n <keynbr> : specify the keyNbr to set in memory");
1684 PrintAndLog(" k <key> : set a key in memory");
1685 PrintAndLog(" f <filename>: specify a filename to use with load or save operations");
1686 PrintAndLog(" s : save keys in memory to file specified by filename");
1687 PrintAndLog(" l : load keys to memory from file specified by filename");
1688 PrintAndLog(" p : print keys loaded into memory\n");
1689 PrintAndLog("Samples:");
1690 PrintAndLog(" set key : hf iclass managekeys n 0 k 1122334455667788");
1691 PrintAndLog(" save key file: hf iclass managekeys f mykeys.bin s");
1692 PrintAndLog(" load key file: hf iclass managekeys f mykeys.bin l");
1693 PrintAndLog(" print keys : hf iclass managekeys p\n");
1697 static int CmdHFiClassManageKeys(const char *Cmd
) {
1699 uint8_t dataLen
= 0;
1700 uint8_t KEY
[8] = {0};
1701 char filename
[FILE_PATH_SIZE
];
1702 uint8_t fileNameLen
= 0;
1703 bool errors
= false;
1704 uint8_t operation
= 0;
1708 while(param_getchar(Cmd
, cmdp
) != 0x00)
1710 switch(param_getchar(Cmd
, cmdp
))
1714 usage_hf_iclass_managekeys();
1718 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
1719 if (fileNameLen
< 1) {
1720 PrintAndLog("No filename found after f");
1727 keyNbr
= param_get8(Cmd
, cmdp
+1);
1728 if (keyNbr
>= ICLASS_KEYS_MAX
) {
1729 PrintAndLog("Invalid block number");
1736 operation
+= 3; //set key
1737 dataLen
= param_getstr(Cmd
, cmdp
+1, tempStr
, sizeof(tempStr
));
1738 if (dataLen
== 16) { //ul-c or ev1/ntag key length
1739 errors
= param_gethex(tempStr
, 0, KEY
, dataLen
);
1741 PrintAndLog("\nERROR: Key is incorrect length\n");
1748 operation
+= 4; //print keys in memory
1753 operation
+= 5; //load keys from file
1758 operation
+= 6; //save keys to file
1762 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1767 usage_hf_iclass_managekeys();
1771 if (operation
== 0){
1772 PrintAndLog("no operation specified (load, save, or print)\n");
1773 usage_hf_iclass_managekeys();
1777 PrintAndLog("Too many operations specified\n");
1778 usage_hf_iclass_managekeys();
1781 if (operation
> 4 && fileNameLen
== 0){
1782 PrintAndLog("You must enter a filename when loading or saving\n");
1783 usage_hf_iclass_managekeys();
1788 case 3: memcpy(iClass_Key_Table
[keyNbr
], KEY
, 8); return 1;
1789 case 4: return printKeys();
1790 case 5: return loadKeys(filename
);
1791 case 6: return saveKeys(filename
);
1798 static int CmdHFiClassCheckKeys(const char *Cmd
) {
1800 uint8_t mac
[4] = {0x00,0x00,0x00,0x00};
1801 uint8_t key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1802 uint8_t div_key
[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1804 // elite key, raw key, standard key
1805 bool use_elite
= false;
1806 bool use_raw
= false;
1807 bool found_debit
= false;
1808 bool found_credit
= false;
1809 bool errors
= false;
1810 uint8_t cmdp
= 0x00;
1812 char filename
[FILE_PATH_SIZE
] = {0};
1813 uint8_t fileNameLen
= 0;
1815 uint8_t *keyBlock
= NULL
, *p
;
1816 int keyitems
= 0, keycnt
= 0;
1818 while (param_getchar(Cmd
, cmdp
) != 0x00 && !errors
) {
1819 switch (param_getchar(Cmd
, cmdp
)) {
1822 usage_hf_iclass_chk();
1826 fileNameLen
= param_getstr(Cmd
, cmdp
+1, filename
, sizeof(filename
));
1827 if (fileNameLen
< 1) {
1828 PrintAndLog("No filename found after f");
1844 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd
, cmdp
));
1850 usage_hf_iclass_chk();
1854 if ( !(f
= fopen( filename
, "r")) ) {
1855 PrintAndLog("File: %s: not found or locked.", filename
);
1859 while( fgets(buf
, sizeof(buf
), f
) ){
1860 if (strlen(buf
) < 16 || buf
[15] == '\n')
1863 while (fgetc(f
) != '\n' && !feof(f
)) ; //goto next line
1865 if( buf
[0]=='#' ) continue; //The line start with # is comment, skip
1867 if (!isxdigit(buf
[0])){
1868 PrintAndLog("File content error. '%s' must include 16 HEX symbols",buf
);
1874 p
= realloc(keyBlock
, 8 * (keyitems
+= 64));
1876 PrintAndLog("Cannot allocate memory for default keys");
1883 memset(keyBlock
+ 8 * keycnt
, 0, 8);
1884 num_to_bytes(strtoull(buf
, NULL
, 16), 8, keyBlock
+ 8 * keycnt
);
1886 //PrintAndLog("check key[%2d] %016" PRIx64, keycnt, bytes_to_num(keyBlock + 8*keycnt, 8));
1888 memset(buf
, 0, sizeof(buf
));
1891 PrintAndLog("Loaded %2d keys from %s", keycnt
, filename
);
1894 uint64_t t1
= msclock();
1896 for (uint32_t c
= 0; c
< keycnt
; c
+= 1) {
1897 printf("."); fflush(stdout
);
1899 int gc
= getchar(); (void)gc
;
1900 printf("\naborted via keyboard!\n");
1904 memcpy(key
, keyBlock
+ 8 * c
, 8);
1906 // debit key. try twice
1907 for (int foo
= 0; foo
< 2 && !found_debit
; foo
++) {
1908 if (!select_and_auth(key
, mac
, div_key
, false, use_elite
, use_raw
, false))
1912 PrintAndLog("\n--------------------------------------------------------");
1913 PrintAndLog(" Found AA1 debit key\t\t[%s]", sprint_hex(key
, 8));
1917 // credit key. try twice
1918 for (int foo
= 0; foo
< 2 && !found_credit
; foo
++) {
1919 if (!select_and_auth(key
, mac
, div_key
, true, use_elite
, use_raw
, false))
1923 PrintAndLog("\n--------------------------------------------------------");
1924 PrintAndLog(" Found AA2 credit key\t\t[%s]", sprint_hex(key
, 8));
1925 found_credit
= true;
1929 if ( found_debit
&& found_credit
)
1933 t1
= msclock() - t1
;
1935 PrintAndLog("\nTime in iclass checkkeys: %.0f seconds\n", (float)t1
/1000.0);
1944 static void usage_hf_iclass_permutekey(void) {
1945 PrintAndLogEx(NORMAL
, "Convert keys from standard NIST to iClass format (and vice versa)");
1946 PrintAndLogEx(NORMAL
, "");
1947 PrintAndLogEx(NORMAL
, "Usage: hf iclass permute [h] [r] <key>");
1948 PrintAndLogEx(NORMAL
, "Options:");
1949 PrintAndLogEx(NORMAL
, " h This help");
1950 PrintAndLogEx(NORMAL
, " r reverse convert key from iClass to NIST format");
1951 PrintAndLogEx(NORMAL
, "");
1952 PrintAndLogEx(NORMAL
, "Examples:");
1953 PrintAndLogEx(NORMAL
, " hf iclass permute r 0123456789abcdef");
1957 static int CmdHFiClassPermuteKey(const char *Cmd
) {
1959 uint8_t key
[8] = {0};
1960 uint8_t data
[16] = {0};
1961 bool isReverse
= false;
1962 int len
= sizeof(data
);
1963 char cmdp
= tolower(param_getchar(Cmd
, 0));
1964 if (strlen(Cmd
) == 0 || cmdp
== 'h') {
1965 usage_hf_iclass_permutekey();
1971 param_gethex_ex(Cmd
, 1, data
, &len
);
1972 } else if (cmdp
== 'f') {
1973 param_gethex_ex(Cmd
, 1, data
, &len
);
1975 param_gethex_ex(Cmd
, 0, data
, &len
);
1980 usage_hf_iclass_permutekey();
1986 memcpy(key
, data
, 8);
1989 // generate_rev(data, len);
1990 uint8_t key_std_format
[8] = {0};
1991 permutekey_rev(key
, key_std_format
);
1992 PrintAndLogEx(SUCCESS
, "key in standard NIST format: %s \n", sprint_hex(key_std_format
, 8));
1993 // if (mbedtls_des_key_check_key_parity(key_std_format
1995 // generate(data, len);
1996 uint8_t key_iclass_format
[8] = {0};
1997 permutekey(key
, key_iclass_format
);
1998 PrintAndLogEx(SUCCESS
, "key in iClass (permuted) format: %s \n", sprint_hex(key_iclass_format
, 8));
2004 static int CmdHelp(const char *Cmd
);
2006 static command_t CommandTable
[] = {
2007 {"help", CmdHelp
, 1, "This help"},
2008 {"calcnewkey", CmdHFiClassCalcNewKey
, 1, "[options..] Calc Diversified keys (blocks 3 & 4) to write new keys"},
2009 {"chk", CmdHFiClassCheckKeys
, 0, " Check keys"},
2010 {"clone", CmdHFiClassCloneTag
, 0, "[options..] Authenticate and Clone from iClass bin file"},
2011 {"decrypt", CmdHFiClassDecrypt
, 1, "[f <fname>] Decrypt tagdump" },
2012 {"dump", CmdHFiClassReader_Dump
, 0, "[options..] Authenticate and Dump iClass tag's AA1"},
2013 {"eload", CmdHFiClassELoad
, 0, "[f <fname>] (experimental) Load data into iClass emulator memory"},
2014 {"encryptblk", CmdHFiClassEncryptBlk
, 1, "<BlockData> Encrypt given block data"},
2015 {"list", CmdHFiClassList
, 0, " (Deprecated) List iClass history"},
2016 {"loclass", CmdHFiClass_loclass
, 1, "[options..] Use loclass to perform bruteforce of reader attack dump"},
2017 {"managekeys", CmdHFiClassManageKeys
, 1, "[options..] Manage the keys to use with iClass"},
2018 {"permutekey", CmdHFiClassPermuteKey
, 1, " iClass key permutation"},
2019 {"readblk", CmdHFiClass_ReadBlock
, 0, "[options..] Authenticate and Read iClass block"},
2020 {"reader", CmdHFiClassReader
, 0, " Look for iClass tags until a key or the pm3 button is pressed"},
2021 {"readtagfile", CmdHFiClassReadTagFile
, 1, "[options..] Display Content from tagfile"},
2022 {"replay", CmdHFiClassReader_Replay
, 0, "<mac> Read an iClass tag via Reply Attack"},
2023 {"sim", CmdHFiClassSim
, 0, "[options..] Simulate iClass tag"},
2024 {"snoop", CmdHFiClassSnoop
, 0, " Eavesdrop iClass communication"},
2025 {"writeblk", CmdHFiClass_WriteBlock
, 0, "[options..] Authenticate and Write iClass block"},
2026 {NULL
, NULL
, 0, NULL
}
2030 int CmdHFiClass(const char *Cmd
) {
2031 clearCommandBuffer();
2032 CmdsParse(CommandTable
, Cmd
);
2037 int CmdHelp(const char *Cmd
) {
2038 CmdsHelp(CommandTable
);