1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch
3 // Copyright (C) 2011 Gerhard de Koning Gans
4 // Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende
5 // Copyright (C) 2019 piwi
6 // Copyright (C) 2020 Iceman
8 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
9 // at your option, any later version. See the LICENSE.txt file for the text of
11 //-----------------------------------------------------------------------------
12 // High frequency iClass commands
13 //-----------------------------------------------------------------------------
15 #include "cmdhficlass.h"
17 #include "cliparser.h"
18 #include "cmdparser.h" // command_t
19 #include "commonutil.h" // ARRAYLEN
21 #include "util_posix.h"
24 #include "loclass/cipherutils.h"
25 #include "loclass/cipher.h"
26 #include "loclass/ikeys.h"
27 #include "loclass/elite_crack.h"
28 #include "fileutils.h"
29 #include "protocols.h"
30 #include "cardhelper.h"
31 #include "wiegand_formats.h"
32 #include "wiegand_formatutils.h"
33 #include "cmdsmartcard.h" // smart select fct
36 #define ICLASS_KEYS_MAX 8
37 #define ICLASS_AUTH_RETRY 10
38 #define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin"
40 static picopass_hdr_t iclass_last_known_card
;
41 static void iclass_set_last_known_card(picopass_hdr_t
*card
) {
42 memcpy(&iclass_last_known_card
, card
, sizeof(picopass_hdr_t
));
45 static uint8_t empty
[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
46 static uint8_t zeros
[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
48 static int CmdHelp(const char *Cmd
);
50 static uint8_t iClass_Key_Table
[ICLASS_KEYS_MAX
][8] = {
51 { 0xAE, 0xA6, 0x84, 0xA6, 0xDA, 0xB2, 0x32, 0x78 },
52 { 0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x10, 0x00 },
53 { 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87 },
54 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
55 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
56 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
57 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
58 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
61 static int cmp_uint32(const void *a
, const void *b
) {
63 const iclass_prekey_t
*x
= (const iclass_prekey_t
*)a
;
64 const iclass_prekey_t
*y
= (const iclass_prekey_t
*)b
;
66 uint32_t mx
= bytes_to_num((uint8_t *)x
->mac
, 4);
67 uint32_t my
= bytes_to_num((uint8_t *)y
->mac
, 4);
75 bool check_known_default(uint8_t *csn
, uint8_t *epurse
, uint8_t *rmac
, uint8_t *tmac
, uint8_t *key
) {
77 iclass_prekey_t
*prekey
= calloc(ICLASS_KEYS_MAX
, sizeof(iclass_prekey_t
));
78 if (prekey
== false) {
83 memcpy(ccnr
, epurse
, 8);
84 memcpy(ccnr
+ 8, rmac
, 4);
86 GenerateMacKeyFrom(csn
, ccnr
, false, false, (uint8_t *)iClass_Key_Table
, ICLASS_KEYS_MAX
, prekey
);
87 qsort(prekey
, ICLASS_KEYS_MAX
, sizeof(iclass_prekey_t
), cmp_uint32
);
89 iclass_prekey_t lookup
;
90 memcpy(lookup
.mac
, tmac
, 4);
93 iclass_prekey_t
*item
= (iclass_prekey_t
*) bsearch(&lookup
, prekey
, ICLASS_KEYS_MAX
, sizeof(iclass_prekey_t
), cmp_uint32
);
95 memcpy(key
, item
->key
, 8);
108 static inline uint32_t leadingzeros(uint64_t a
) {
110 return __builtin_clzll(a
);
116 static void iclass_upload_emul(uint8_t *d
, uint16_t n
, uint16_t *bytes_sent
) {
125 conn
.block_after_ACK
= true;
129 uint16_t bytes_remaining
= n
;
131 while (bytes_remaining
> 0) {
132 uint32_t bytes_in_packet
= MIN(PM3_CMD_DATA_SIZE
, bytes_remaining
);
133 if (bytes_in_packet
== bytes_remaining
) {
134 // Disable fast mode on last packet
135 conn
.block_after_ACK
= false;
137 clearCommandBuffer();
139 struct p
*payload
= calloc(4 + bytes_in_packet
, sizeof(uint8_t));
140 payload
->offset
= *bytes_sent
;
141 payload
->len
= bytes_in_packet
;
142 memcpy(payload
->data
, d
+ *bytes_sent
, bytes_in_packet
);
144 SendCommandNG(CMD_HF_ICLASS_EML_MEMSET
, (uint8_t *)payload
, 4 + bytes_in_packet
);
147 bytes_remaining
-= bytes_in_packet
;
148 *bytes_sent
+= bytes_in_packet
;
152 const char *card_types
[] = {
153 "PicoPass 16K / 16", // 000
154 "PicoPass 32K with current book 16K / 16", // 001
155 "Unknown Card Type!", // 010
156 "Unknown Card Type!", // 011
157 "PicoPass 2K", // 100
158 "Unknown Card Type!", // 101
159 "PicoPass 16K / 2", // 110
160 "PicoPass 32K with current book 16K / 2", // 111
163 uint8_t card_app2_limit
[] = {
174 iclass_config_card_item_t iclass_config_types
[14] = {
188 // must be the last entry
189 {"no config card info available", ""}
192 static bool check_config_card(const iclass_config_card_item_t
*o
) {
193 if (o
== NULL
|| strlen(o
->desc
) == 0) {
194 PrintAndLogEx(INFO
, "No data available");
195 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf iclass config -l") "` to download from cardhelper");
201 static int load_config_cards(void) {
202 PrintAndLogEx(INFO
, "detecting cardhelper...");
203 if (IsCardHelperPresent(false) == false) {
204 PrintAndLogEx(FAILED
, "failed to detect cardhelper");
208 for (int i
= 0; i
< ARRAYLEN(iclass_config_types
); ++i
) {
210 PrintAndLogEx(INPLACE
, "loading setting %i", i
);
211 iclass_config_card_item_t
*ret
= &iclass_config_types
[i
];
213 uint8_t desc
[70] = {0};
214 if (GetConfigCardStrByIdx(i
, desc
) == PM3_SUCCESS
) {
215 memcpy(ret
->desc
, desc
, sizeof(desc
));
218 uint8_t blocks
[16] = {0};
219 if (GetConfigCardByIdx(i
, blocks
) == PM3_SUCCESS
) {
220 memcpy(ret
->data
, blocks
, sizeof(blocks
));
223 PrintAndLogEx(NORMAL
, "");
224 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf iclass configcard -p") "` to list all");
228 static const iclass_config_card_item_t
*get_config_card_item(int idx
) {
229 if (idx
> -1 && idx
< 14) {
230 return &iclass_config_types
[idx
];
232 return &iclass_config_types
[13];
235 static void print_config_cards(void) {
236 if (check_config_card(&iclass_config_types
[0])) {
237 PrintAndLogEx(INFO
, "---- " _CYAN_("Config cards available") " ------------");
238 for (int i
= 0; i
< ARRAYLEN(iclass_config_types
) - 1 ; ++i
) {
239 PrintAndLogEx(INFO
, "%2d, %s", i
, iclass_config_types
[i
].desc
);
241 PrintAndLogEx(NORMAL
, "");
245 static void print_config_card(const iclass_config_card_item_t
*o
) {
246 if (check_config_card(o
)) {
247 PrintAndLogEx(INFO
, "description... %s", o
->desc
);
248 PrintAndLogEx(INFO
, "data....... " _YELLOW_("%s"), sprint_hex_inrow(o
->data
, sizeof(o
->data
)));
252 static int generate_config_card(const iclass_config_card_item_t
*o
, uint8_t *key
, bool got_kr
) {
253 if (check_config_card(o
) == false) {
256 // get header from card
257 //bool have = memcmp(iclass_last_known_card.csn, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
258 PrintAndLogEx(INFO
, "trying to read a card..");
259 int res
= read_iclass_csn(false, false);
260 if (res
!= PM3_SUCCESS
) {
261 PrintAndLogEx(FAILED
, "Put a card on antenna and try again...");
265 // generate dump file
266 uint8_t app1_limit
= iclass_last_known_card
.conf
.app_limit
;
267 uint8_t old_limit
= app1_limit
;
268 uint8_t tot_bytes
= (app1_limit
+ 1) * 8;
271 uint8_t *data
= calloc(1, tot_bytes
);
273 PrintAndLogEx(FAILED
, "failed to allocate memory");
278 // calc diversified key for selected card
279 HFiClassCalcDivKey(iclass_last_known_card
.csn
, iClass_Key_Table
[0], iclass_last_known_card
.key_d
, false);
281 memset(data
, 0x00, tot_bytes
);
282 memcpy(data
, (uint8_t *)&iclass_last_known_card
, sizeof(picopass_hdr_t
));
284 // Keyrolling configuration cards are special.
285 if (strstr(o
->desc
, "Keyroll") != NULL
) {
287 if (got_kr
== false) {
288 PrintAndLogEx(ERR
, "please specifiy KEYROLL key!");
293 if (app1_limit
< 0x16) {
294 // if card wasn't large enough before, adapt to new size
295 PrintAndLogEx(WARNING
, "Adapting applimit1 for KEY rolling..");
298 iclass_last_known_card
.conf
.app_limit
= 0x16;
299 tot_bytes
= (app1_limit
+ 1) * 8;
301 uint8_t *p
= realloc(data
, tot_bytes
);
303 PrintAndLogEx(FAILED
, "failed to allocate memory");
308 memset(data
, 0xFF, tot_bytes
);
312 PrintAndLogEx(INFO
, "Detecting cardhelper...");
313 if (IsCardHelperPresent(false) == false) {
314 PrintAndLogEx(FAILED
, "failed to detect cardhelper");
319 uint8_t ffs
[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
320 if (Encrypt(ffs
, ffs
) == false) {
321 PrintAndLogEx(WARNING
, "failed to encrypt FF");
325 if (Encrypt(key
, enckey1
) == false) {
326 PrintAndLogEx(WARNING
, "failed to encrypt key1");
329 memcpy(data
, &iclass_last_known_card
, sizeof(picopass_hdr_t
));
330 memcpy(data
+ (6 * 8), o
->data
, sizeof(o
->data
));
332 // encrypted keyroll key 0D
333 memcpy(data
+ (0xD * 8), enckey1
, sizeof(enckey1
));
335 for (uint8_t i
= 0xe; i
< 0x14; i
++) {
336 memcpy(data
+ (i
* 8), ffs
, sizeof(ffs
));
339 // encrypted partial keyroll key 14
340 uint8_t foo
[8] = {0x15};
341 memcpy(foo
+ 1, key
, 7);
343 if (Encrypt(foo
, enckey2
) == false) {
344 PrintAndLogEx(WARNING
, "failed to encrypt partial 1");
346 memcpy(data
+ (0x14 * 8), enckey2
, sizeof(enckey2
));
348 // encrypted partial keyroll key 15
349 memset(foo
, 0xFF, sizeof(foo
));
351 if (Encrypt(foo
, enckey2
) == false) {
352 PrintAndLogEx(WARNING
, "failed to encrypt partial 2");
354 memcpy(data
+ (0x15 * 8), enckey2
, sizeof(enckey2
));
357 for (uint8_t i
= 0x16; i
<= app1_limit
; i
++) {
358 memcpy(data
+ (i
* 8), ffs
, sizeof(ffs
));
362 // revert potential modified app1_limit
363 iclass_last_known_card
.conf
.app_limit
= old_limit
;
366 memcpy(data
, &iclass_last_known_card
, sizeof(picopass_hdr_t
));
367 memcpy(data
+ (6 * 8), o
->data
, sizeof(o
->data
));
371 uint16_t bytes_sent
= 0;
372 iclass_upload_emul(data
, tot_bytes
, &bytes_sent
);
375 PrintAndLogEx(SUCCESS
, "sent %u bytes of data to device emulator memory", bytes_sent
);
376 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf iclass eview") "` to view dump file");
377 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf iclass sim -t 3") "` to start simulating config card");
381 static uint8_t isset(uint8_t val
, uint8_t mask
) {
385 static uint8_t notset(uint8_t val
, uint8_t mask
) {
386 return !(val
& mask
);
389 uint8_t get_pagemap(const picopass_hdr_t
*hdr
) {
390 return (hdr
->conf
.fuses
& (FUSE_CRYPT0
| FUSE_CRYPT1
)) >> 3;
393 static void fuse_config(const picopass_hdr_t
*hdr
) {
395 uint16_t otp
= (hdr
->conf
.otp
[1] << 8 | hdr
->conf
.otp
[0]);
397 PrintAndLogEx(INFO
, " Raw: " _YELLOW_("%s"), sprint_hex((uint8_t *)&hdr
->conf
, 8));
398 PrintAndLogEx(INFO
, " " _YELLOW_("%02X") "..................... app limit", hdr
->conf
.app_limit
);
399 PrintAndLogEx(INFO
, " " _YELLOW_("%04X") " ( %5u )...... OTP", otp
, otp
);
400 PrintAndLogEx(INFO
, " " _YELLOW_("%02X") "............ block write lock", hdr
->conf
.block_writelock
);
401 PrintAndLogEx(INFO
, " " _YELLOW_("%02X") "......... chip", hdr
->conf
.chip_config
);
402 PrintAndLogEx(INFO
, " " _YELLOW_("%02X") "...... mem", hdr
->conf
.mem_config
);
403 PrintAndLogEx(INFO
, " " _YELLOW_("%02X") "... EAS", hdr
->conf
.eas
);
404 PrintAndLogEx(INFO
, " " _YELLOW_("%02X") " fuses", hdr
->conf
.fuses
);
406 uint8_t fuses
= hdr
->conf
.fuses
;
408 PrintAndLogEx(INFO
, " Fuses:");
409 if (isset(fuses
, FUSE_FPERS
))
410 PrintAndLogEx(SUCCESS
, " mode......... " _GREEN_("Personalization (programmable)"));
412 PrintAndLogEx(SUCCESS
, " mode......... " _YELLOW_("Application (locked)"));
414 if (isset(fuses
, FUSE_CODING1
)) {
415 PrintAndLogEx(SUCCESS
, " coding...... RFU");
417 if (isset(fuses
, FUSE_CODING0
))
418 PrintAndLogEx(SUCCESS
, " coding....... " _YELLOW_("ISO 14443-2 B / 15693"));
420 PrintAndLogEx(SUCCESS
, " coding....... " _YELLOW_("ISO 14443-B only"));
423 uint8_t pagemap
= get_pagemap(hdr
);
426 PrintAndLogEx(INFO
, " crypt........ No auth possible. Read only if RA is enabled");
429 PrintAndLogEx(SUCCESS
, " crypt........ Non secured page");
432 PrintAndLogEx(INFO
, " crypt........ Secured page, keys locked");
435 PrintAndLogEx(SUCCESS
, " crypt........ Secured page, " _GREEN_("keys not locked"));
439 if (isset(fuses
, FUSE_RA
))
440 PrintAndLogEx(SUCCESS
, " RA........... Read access enabled (non-secure mode)");
442 PrintAndLogEx(INFO
, " RA........... Read access not enabled");
445 static void getMemConfig(uint8_t mem_cfg
, uint8_t chip_cfg
, uint8_t *app_areas
, uint8_t *kb
) {
446 // How to determine chip type
451 // chip-bit 4 = Multi App
453 uint8_t k16
= isset(mem_cfg
, 0x80);
454 //uint8_t k2 = isset(mem_cfg, 0x10);
455 uint8_t book
= isset(mem_cfg
, 0x20);
457 if (isset(chip_cfg
, 0x10) && !k16
&& !book
) {
460 } else if (isset(chip_cfg
, 0x10) && k16
&& !book
) {
463 } else if (notset(chip_cfg
, 0x10) && !k16
&& !book
) {
466 } else if (isset(chip_cfg
, 0x10) && k16
&& book
) {
469 } else if (notset(chip_cfg
, 0x10) && !k16
&& book
) {
478 static uint8_t get_mem_config(const picopass_hdr_t
*hdr
) {
479 // three configuration bits that decides sizes
480 uint8_t type
= (hdr
->conf
.chip_config
& 0x10) >> 2;
482 type
|= (hdr
->conf
.mem_config
& 0x80) >> 6;
484 type
|= (hdr
->conf
.mem_config
& 0x20) >> 5;
486 //type |= (hdr->conf.mem_config & 0x10) >> 5;
490 static void mem_app_config(const picopass_hdr_t
*hdr
) {
491 uint8_t mem
= hdr
->conf
.mem_config
;
492 uint8_t chip
= hdr
->conf
.chip_config
;
494 uint8_t app_areas
= 2;
496 getMemConfig(mem
, chip
, &app_areas
, &kb
);
498 uint8_t type
= get_mem_config(hdr
);
499 uint8_t app1_limit
= hdr
->conf
.app_limit
- 5; // minus header blocks
500 uint8_t app2_limit
= card_app2_limit
[type
];
501 uint8_t pagemap
= get_pagemap(hdr
);
503 PrintAndLogEx(INFO
, "-------------------------- " _CYAN_("Memory") " --------------------------");
505 if (pagemap
== PICOPASS_NON_SECURE_PAGEMODE
) {
506 PrintAndLogEx(INFO
, " %u KBits ( " _YELLOW_("%u") " bytes )", kb
, app2_limit
* 8);
507 PrintAndLogEx(INFO
, " Tag has not App Areas");
511 PrintAndLogEx(INFO
, " %u KBits/%u App Areas ( " _YELLOW_("%u") " bytes )", kb
, app_areas
, (app2_limit
+ 1) * 8);
512 PrintAndLogEx(INFO
, " AA1 blocks %u { 0x06 - 0x%02X (06 - %02d) }", app1_limit
, app1_limit
+ 5, app1_limit
+ 5);
513 PrintAndLogEx(INFO
, " AA2 blocks %u { 0x%02X - 0x%02X (%02d - %02d) }", app2_limit
- app1_limit
, app1_limit
+ 5 + 1, app2_limit
, app1_limit
+ 5 + 1, app2_limit
);
515 PrintAndLogEx(INFO
, "------------------------- " _CYAN_("KeyAccess") " ------------------------");
516 PrintAndLogEx(INFO
, " * Kd, Debit key, AA1 Kc, Credit key, AA2 *");
517 uint8_t book
= isset(mem
, 0x20);
519 PrintAndLogEx(INFO
, " Read A....... debit");
520 PrintAndLogEx(INFO
, " Read B....... credit");
521 PrintAndLogEx(INFO
, " Write A...... debit");
522 PrintAndLogEx(INFO
, " Write B...... credit");
523 PrintAndLogEx(INFO
, " Debit........ debit or credit");
524 PrintAndLogEx(INFO
, " Credit....... credit");
526 PrintAndLogEx(INFO
, " Read A....... debit or credit");
527 PrintAndLogEx(INFO
, " Read B....... debit or credit");
528 PrintAndLogEx(INFO
, " Write A...... credit");
529 PrintAndLogEx(INFO
, " Write B...... credit");
530 PrintAndLogEx(INFO
, " Debit........ debit or credit");
531 PrintAndLogEx(INFO
, " Credit....... credit");
535 static void print_picopass_info(const picopass_hdr_t
*hdr
) {
536 PrintAndLogEx(INFO
, "-------------------- " _CYAN_("card configuration") " --------------------");
541 static void print_picopass_header(const picopass_hdr_t
*hdr
) {
542 PrintAndLogEx(INFO
, "--------------------------- " _CYAN_("card") " ---------------------------");
543 PrintAndLogEx(SUCCESS
, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr
->csn
, sizeof(hdr
->csn
)));
544 PrintAndLogEx(SUCCESS
, " Config: %s Card configuration", sprint_hex((uint8_t *)&hdr
->conf
, sizeof(hdr
->conf
)));
545 PrintAndLogEx(SUCCESS
, "E-purse: %s Card challenge, CC", sprint_hex(hdr
->epurse
, sizeof(hdr
->epurse
)));
546 PrintAndLogEx(SUCCESS
, " Kd: %s Debit key, hidden", sprint_hex(hdr
->key_d
, sizeof(hdr
->key_d
)));
547 PrintAndLogEx(SUCCESS
, " Kc: %s Credit key, hidden", sprint_hex(hdr
->key_c
, sizeof(hdr
->key_c
)));
548 PrintAndLogEx(SUCCESS
, " AIA: %s Application Issuer area", sprint_hex(hdr
->app_issuer_area
, sizeof(hdr
->app_issuer_area
)));
551 static int CmdHFiClassList(const char *Cmd
) {
552 return CmdTraceListAlias(Cmd
, "hf iclass", "iclass");
555 static int CmdHFiClassSniff(const char *Cmd
) {
557 CLIParserContext
*ctx
;
558 CLIParserInit(&ctx
, "hf iclass sniff",
559 "Sniff the communication reader and tag",
561 "hf iclass sniff -j --> jam e-purse updates\n"
566 arg_lit0("j", "jam", "Jam (prevent) e-purse updates"),
570 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
571 bool jam_epurse_update
= arg_get_lit(ctx
, 1);
574 const uint8_t update_epurse_sequence
[2] = {0x87, 0x02};
577 uint8_t jam_search_len
;
578 uint8_t jam_search_string
[2];
581 if (jam_epurse_update
) {
582 payload
.jam_search_len
= sizeof(update_epurse_sequence
);
583 memcpy(payload
.jam_search_string
, update_epurse_sequence
, sizeof(payload
.jam_search_string
));
586 PacketResponseNG resp
;
587 clearCommandBuffer();
588 SendCommandNG(CMD_HF_ICLASS_SNIFF
, (uint8_t *)&payload
, sizeof(payload
));
590 WaitForResponse(CMD_HF_ICLASS_SNIFF
, &resp
);
592 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf iclass list") "` to view captured tracelog");
593 PrintAndLogEx(HINT
, "Try `" _YELLOW_("trace save -f hf_iclass_mytrace") "` to save tracelog for later analysing");
597 static int CmdHFiClassSim(const char *Cmd
) {
598 CLIParserContext
*ctx
;
599 CLIParserInit(&ctx
, "hf iclass sim",
600 "Simulate a iCLASS legacy/standard tag",
601 "hf iclass sim -t 0 --csn 031FEC8AF7FF12E0 --> simulate with specficied CSN\n"
602 "hf iclass sim -t 1 --> simulate with default CSN\n"
603 "hf iclass sim -t 2 --> execute loclass attack online part\n"
604 "hf iclass sim -t 3 --> simulate full iCLASS 2k tag\n"
605 "hf iclass sim -t 4 --> Reader-attack, adapted for KeyRoll mode, gather reader responses to extract elite key");
609 arg_int1("t", "type", "<0-4> ", "Simulation type to use"),
610 arg_str0(NULL
, "csn", "<hex>", "Specify CSN as 8 hex bytes to use with sim type 0"),
613 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
615 int sim_type
= arg_get_int(ctx
, 1);
618 uint8_t csn
[8] = {0};
619 CLIGetHexWithReturn(ctx
, 2, csn
, &csn_len
);
621 if (sim_type
== 0 && csn_len
> 0) {
623 PrintAndLogEx(ERR
, "CSN is incorrect length");
627 PrintAndLogEx(INFO
, " simtype: %02x CSN: %s", sim_type
, sprint_hex(csn
, 8));
628 } else if (sim_type
== 0 && csn_len
== 0) {
629 PrintAndLogEx(ERR
, "Simtype 0 requires CSN argument (--csn)");
637 PrintAndLogEx(ERR
, "Undefined simtype %d", sim_type
);
641 // remember to change the define NUM_CSNS to match.
643 // pre-defined 9 CSN by iceman
644 uint8_t csns
[8 * NUM_CSNS
] = {
645 0x01, 0x0A, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
646 0x0C, 0x06, 0x0C, 0xFE, 0xF7, 0xFF, 0x12, 0xE0,
647 0x10, 0x97, 0x83, 0x7B, 0xF7, 0xFF, 0x12, 0xE0,
648 0x13, 0x97, 0x82, 0x7A, 0xF7, 0xFF, 0x12, 0xE0,
649 0x07, 0x0E, 0x0D, 0xF9, 0xF7, 0xFF, 0x12, 0xE0,
650 0x14, 0x96, 0x84, 0x76, 0xF7, 0xFF, 0x12, 0xE0,
651 0x17, 0x96, 0x85, 0x71, 0xF7, 0xFF, 0x12, 0xE0,
652 0xCE, 0xC5, 0x0F, 0x77, 0xF7, 0xFF, 0x12, 0xE0,
653 0xD2, 0x5A, 0x82, 0xF8, 0xF7, 0xFF, 0x12, 0xE0
654 //0x04, 0x08, 0x9F, 0x78, 0x6E, 0xFF, 0x12, 0xE0
659 * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
660 * So, it should wind up as
663 * The returndata from the pm3 is on the following format
664 * <4 byte NR><4 byte MAC>
665 * CC are all zeroes, CSN is the same as was sent in
671 case ICLASS_SIM_MODE_READER_ATTACK
: {
672 PrintAndLogEx(INFO
, "Starting iCLASS sim 2 attack (elite mode)");
673 PrintAndLogEx(INFO
, "press " _YELLOW_("`enter`") " to cancel");
674 PacketResponseNG resp
;
675 clearCommandBuffer();
676 SendCommandMIX(CMD_HF_ICLASS_SIMULATE
, sim_type
, NUM_CSNS
, 1, csns
, 8 * NUM_CSNS
);
678 while (WaitForResponseTimeout(CMD_ACK
, &resp
, 2000) == false) {
680 if (kbd_enter_pressed()) {
681 PrintAndLogEx(WARNING
, "\naborted via keyboard.");
682 return PM3_EOPABORTED
;
685 PrintAndLogEx(WARNING
, "\ntimeout while waiting for reply.");
689 uint8_t num_mac
= resp
.oldarg
[1];
690 bool success
= (NUM_CSNS
== num_mac
);
691 PrintAndLogEx((success
) ? SUCCESS
: WARNING
, "[%c] %d out of %d MAC obtained [%s]", (success
) ? '+' : '!', num_mac
, NUM_CSNS
, (success
) ? "OK" : "FAIL");
696 size_t datalen
= NUM_CSNS
* 24;
697 uint8_t *dump
= calloc(datalen
, sizeof(uint8_t));
699 PrintAndLogEx(WARNING
, "Failed to allocate memory");
703 memset(dump
, 0, datalen
);//<-- Need zeroes for the EPURSE - field (official)
706 for (i
= 0 ; i
< NUM_CSNS
; i
++) {
708 memcpy(dump
+ i
* 24, csns
+ i
* 8, 8);
710 memcpy(dump
+ i
* 24 + 8, resp
.data
.asBytes
+ i
* 16, 8);
711 // NR_MAC (eight bytes from the response) ( 8b csn + 8b epurse == 16)
712 memcpy(dump
+ i
* 24 + 16, resp
.data
.asBytes
+ i
* 16 + 8, 8);
714 /** Now, save to dumpfile **/
715 saveFile("iclass_mac_attack", ".bin", dump
, datalen
);
718 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf iclass loclass -f iclass_mac_attack.bin") "` to recover elite key");
721 case ICLASS_SIM_MODE_READER_ATTACK_KEYROLL
: {
722 // reader in key roll mode, when it has two keys it alternates when trying to verify.
723 PrintAndLogEx(INFO
, "Starting iCLASS sim 4 attack (elite mode, reader in key roll mode)");
724 PrintAndLogEx(INFO
, "press Enter to cancel");
725 PacketResponseNG resp
;
726 clearCommandBuffer();
727 SendCommandMIX(CMD_HF_ICLASS_SIMULATE
, sim_type
, NUM_CSNS
, 1, csns
, 8 * NUM_CSNS
);
729 while (WaitForResponseTimeout(CMD_ACK
, &resp
, 2000) == false) {
731 if (kbd_enter_pressed()) {
732 PrintAndLogEx(WARNING
, "\naborted via keyboard.");
733 return PM3_EOPABORTED
;
736 PrintAndLogEx(WARNING
, "\ntimeout while waiting for reply.");
740 uint8_t num_mac
= resp
.oldarg
[1];
741 bool success
= ((NUM_CSNS
* 2) == num_mac
);
742 PrintAndLogEx((success
) ? SUCCESS
: WARNING
, "[%c] %d out of %d MAC obtained [%s]", (success
) ? '+' : '!', num_mac
, NUM_CSNS
* 2, (success
) ? "OK" : "FAIL");
747 size_t datalen
= NUM_CSNS
* 24;
748 uint8_t *dump
= calloc(datalen
, sizeof(uint8_t));
750 PrintAndLogEx(WARNING
, "Failed to allocate memory");
754 #define MAC_ITEM_SIZE 24
757 //Need zeroes for the CC-field
758 memset(dump
, 0, datalen
);
759 for (uint8_t i
= 0; i
< NUM_CSNS
; i
++) {
761 memcpy(dump
+ i
* MAC_ITEM_SIZE
, csns
+ i
* 8, 8); //CSN
763 memcpy(dump
+ i
* MAC_ITEM_SIZE
+ 8, resp
.data
.asBytes
+ i
* 16, 8);
764 // copy NR_MAC (eight bytes from the response) ( 8b csn + 8b epurse == 16)
765 memcpy(dump
+ i
* MAC_ITEM_SIZE
+ 16, resp
.data
.asBytes
+ i
* 16 + 8, 8);
767 saveFile("iclass_mac_attack_keyroll_A", ".bin", dump
, datalen
);
770 memset(dump
, 0, datalen
);
771 for (uint8_t i
= 0; i
< NUM_CSNS
; i
++) {
772 uint8_t resp_index
= (i
+ NUM_CSNS
) * 16;
774 memcpy(dump
+ i
* MAC_ITEM_SIZE
, csns
+ i
* 8, 8);
776 memcpy(dump
+ i
* MAC_ITEM_SIZE
+ 8, resp
.data
.asBytes
+ resp_index
, 8);
777 // copy NR_MAC (eight bytes from the response) ( 8b csn + 8 epurse == 16)
778 memcpy(dump
+ i
* MAC_ITEM_SIZE
+ 16, resp
.data
.asBytes
+ resp_index
+ 8, 8);
781 saveFile("iclass_mac_attack_keyroll_B", ".bin", dump
, datalen
);
784 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf iclass loclass -f iclass_mac_attack_keyroll_A.bin") "` to recover elite key");
785 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf iclass loclass -f iclass_mac_attack_keyroll_B.bin") "` to recover elite key");
788 case ICLASS_SIM_MODE_CSN
:
789 case ICLASS_SIM_MODE_CSN_DEFAULT
:
790 case ICLASS_SIM_MODE_FULL
:
792 PrintAndLogEx(INFO
, "Starting iCLASS simulation");
793 PrintAndLogEx(INFO
, "press " _YELLOW_("`button`") " to cancel");
794 uint8_t numberOfCSNs
= 0;
795 clearCommandBuffer();
796 SendCommandMIX(CMD_HF_ICLASS_SIMULATE
, sim_type
, numberOfCSNs
, 1, csn
, 8);
798 if (sim_type
== ICLASS_SIM_MODE_FULL
)
799 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf iclass esave -h") "` to save the emulator memory to file");
806 static int CmdHFiClassInfo(const char *Cmd
) {
807 CLIParserContext
*ctx
;
808 CLIParserInit(&ctx
, "hf iclass info",
809 "Act as a iCLASS reader. Reads / fingerprints a iCLASS tag.",
816 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
818 return info_iclass();
821 int read_iclass_csn(bool loop
, bool verbose
) {
823 uint32_t flags
= (FLAG_ICLASS_READER_INIT
| FLAG_ICLASS_READER_CLEARTRACE
);
824 int res
= PM3_SUCCESS
;
827 clearCommandBuffer();
828 SendCommandMIX(CMD_HF_ICLASS_READER
, flags
, 0, 0, NULL
, 0);
829 PacketResponseNG resp
;
830 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2000)) {
832 uint8_t status
= resp
.oldarg
[0] & 0xff;
835 if (status
== 0xFF) {
840 if (status
== 0 || status
== 0xFF) {
841 if (verbose
) PrintAndLogEx(WARNING
, "iCLASS / ISO15693 card select failed");
842 res
= PM3_EOPABORTED
;
847 picopass_hdr_t
*card
= calloc(1, sizeof(picopass_hdr_t
));
849 memcpy(card
, (picopass_hdr_t
*)resp
.data
.asBytes
, sizeof(picopass_hdr_t
));
850 PrintAndLogEx(NORMAL
, "");
851 PrintAndLogEx(SUCCESS
, "iCLASS / Picopass CSN: " _GREEN_("%s"), sprint_hex(card
->csn
, sizeof(card
->csn
)));
852 iclass_set_last_known_card(card
);
855 PrintAndLogEx(FAILED
, "failed to allocate memory");
858 } while (loop
&& kbd_enter_pressed() == false);
864 static int CmdHFiClassReader(const char *Cmd
) {
866 CLIParserContext
*ctx
;
867 CLIParserInit(&ctx
, "hf iclass reader",
868 "Act as a iCLASS reader. Look for iCLASS tags until Enter or the pm3 button is pressed",
869 "hf iclass reader -@ -> continuous reader mode"
874 arg_lit0("@", NULL
, "optional - continuous reader mode"),
877 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
878 bool cm
= arg_get_lit(ctx
, 1);
882 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " to exit");
885 return read_iclass_csn(cm
, true);
888 static int CmdHFiClassELoad(const char *Cmd
) {
889 CLIParserContext
*ctx
;
890 CLIParserInit(&ctx
, "hf iclass eload",
891 "Load emulator memory with data from (bin/eml/json) iCLASS dump file",
892 "hf iclass eload -f hf-iclass-AA162D30F8FF12F1-dump.bin\n"
893 "hf iclass eload -f hf-iclass-AA162D30F8FF12F1-dump.eml\n"
898 arg_str1("f", "file", "<fn>", "filename of dump (bin/eml/json)"),
901 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
904 char filename
[FILE_PATH_SIZE
] = {0};
905 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
907 if (strlen(filename
) == 0) {
908 PrintAndLogEx(ERR
, "Error: Please specify a filename");
915 size_t bytes_read
= 2048;
916 uint8_t *dump
= NULL
;
918 DumpFileType_t dftype
= getfiletype(filename
);
921 res
= loadFile_safe(filename
, ".bin", (void **)&dump
, &bytes_read
);
925 res
= loadFileEML_safe(filename
, (void **)&dump
, &bytes_read
);
929 dump
= calloc(2048, sizeof(uint8_t));
931 PrintAndLogEx(ERR
, "error, cannot allocate memory ");
934 res
= loadFileJSON(filename
, (void *)dump
, 2048, &bytes_read
, NULL
);
939 PrintAndLogEx(ERR
, "Error: Only BIN/JSON/EML formats allowed");
944 if (res
!= PM3_SUCCESS
) {
949 uint8_t *newdump
= realloc(dump
, bytes_read
);
950 if (newdump
== NULL
) {
957 print_picopass_header((picopass_hdr_t
*) dump
);
958 print_picopass_info((picopass_hdr_t
*) dump
);
961 uint16_t bytes_sent
= 0;
962 iclass_upload_emul(dump
, bytes_read
, &bytes_sent
);
964 PrintAndLogEx(SUCCESS
, "sent %u bytes of data to device emulator memory", bytes_sent
);
968 static int CmdHFiClassESave(const char *Cmd
) {
969 CLIParserContext
*ctx
;
970 CLIParserInit(&ctx
, "hf iclass esave",
971 "Save emulator memory to file.\n"
972 "if filename is not supplied, CSN will be used.",
974 "hf iclass esave -f hf-iclass-dump\n"
975 "hf iclass esave -s 2048 -f hf-iclass-dump");
979 arg_str0("f", "file", "<fn>", "filename of dump file"),
980 arg_int0("s", "size", "<256|2048>", "number of bytes to save (default 256)"),
983 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
986 char filename
[FILE_PATH_SIZE
] = {0};
987 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
988 uint16_t bytes
= arg_get_int_def(ctx
, 2, 256);
991 PrintAndLogEx(WARNING
, "Emulator memory is max 4096bytes. Truncating %u to 4096", bytes
);
997 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
999 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
1003 PrintAndLogEx(INFO
, "downloading from emulator memory");
1004 if (!GetFromDevice(BIG_BUF_EML
, dump
, bytes
, 0, NULL
, 0, NULL
, 2500, false)) {
1005 PrintAndLogEx(WARNING
, "Fail, transfer from device time-out");
1007 return PM3_ETIMEOUT
;
1010 // user supplied filename?
1012 char *fptr
= filename
;
1013 fptr
+= snprintf(fptr
, sizeof(filename
), "hf-iclass-");
1014 FillFileNameByUID(fptr
, dump
, "-dump", 8);
1017 saveFile(filename
, ".bin", dump
, bytes
);
1018 saveFileEML(filename
, dump
, bytes
, 8);
1019 saveFileJSON(filename
, jsfIclass
, dump
, bytes
, NULL
);
1022 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf iclass view -f") "` to view dump file");
1026 static int CmdHFiClassEView(const char *Cmd
) {
1027 CLIParserContext
*ctx
;
1028 CLIParserInit(&ctx
, "hf iclass eview",
1029 "Display emulator memory.\n"
1030 "Number of bytes to download defaults to 256. Other value is 2048.",
1032 "hf iclass eview -s 2048\n"
1033 "hf iclass eview -s 2048 -v");
1035 void *argtable
[] = {
1037 arg_int0("s", "size", "<256|2048>", "number of bytes to save (default 256)"),
1038 arg_lit0("v", "verbose", "verbose output"),
1041 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1043 uint16_t blocks
= 32;
1044 uint16_t bytes
= arg_get_int_def(ctx
, 1, 256);
1045 bool verbose
= arg_get_lit(ctx
, 2);
1051 PrintAndLogEx(WARNING
, "Emulator memory is max 4096bytes. Truncating %u to 4096", bytes
);
1055 if (bytes
% 8 != 0) {
1057 PrintAndLogEx(WARNING
, "Number not divided by 8, truncating to %u", bytes
);
1060 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
1062 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
1065 memset(dump
, 0, bytes
);
1067 PrintAndLogEx(INFO
, "downloading from emulator memory");
1068 if (!GetFromDevice(BIG_BUF_EML
, dump
, bytes
, 0, NULL
, 0, NULL
, 2500, false)) {
1069 PrintAndLogEx(WARNING
, "Fail, transfer from device time-out");
1071 return PM3_ETIMEOUT
;
1075 print_picopass_header((picopass_hdr_t
*) dump
);
1076 print_picopass_info((picopass_hdr_t
*) dump
);
1079 PrintAndLogEx(NORMAL
, "");
1080 printIclassDumpContents(dump
, 1, blocks
, bytes
);
1085 static int CmdHFiClassDecrypt(const char *Cmd
) {
1086 CLIParserContext
*clictx
;
1087 CLIParserInit(&clictx
, "hf iclass decrypt",
1088 "3DES decrypt data\n"
1089 "This is a naive implementation, it tries to decrypt every block after block 6.\n"
1090 "Correct behaviour would be to decrypt only the application areas where the key is valid,\n"
1091 "which is defined by the configuration block.\n"
1093 "In order to use this function, the file `iclass_decryptionkey.bin` must reside\n"
1094 "in the resources directory. The file should be 16 bytes binary data\n"
1096 "make sure your cardhelper is placed in the sim module",
1097 "hf iclass decrypt -f hf-iclass-AA162D30F8FF12F1-dump.bin\n"
1098 "hf iclass decrypt -f hf-iclass-AA162D30F8FF12F1-dump.bin -k 000102030405060708090a0b0c0d0e0f\n"
1099 "hf iclass decrypt -d 1122334455667788 -k 000102030405060708090a0b0c0d0e0f");
1101 void *argtable
[] = {
1103 arg_str0("f", "file", "<fn>", "filename of dump file (bin/eml/json)"),
1104 arg_str0("d", "data", "<hex>", "3DES encrypted data"),
1105 arg_str0("k", "key", "<hex>", "3DES transport key"),
1106 arg_lit0("v", "verbose", "verbose output"),
1107 arg_lit0(NULL
, "d6", "decode as block 6"),
1110 CLIExecWithReturn(clictx
, Cmd
, argtable
, false);
1113 char filename
[FILE_PATH_SIZE
] = {0};
1114 CLIParamStrToBuf(arg_get_str(clictx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
1116 int enc_data_len
= 0;
1117 uint8_t enc_data
[8] = {0};
1118 bool have_data
= false;
1120 CLIGetHexWithReturn(clictx
, 2, enc_data
, &enc_data_len
);
1123 uint8_t key
[16] = {0};
1124 uint8_t *keyptr
= NULL
;
1125 bool have_key
= false;
1127 CLIGetHexWithReturn(clictx
, 3, key
, &key_len
);
1129 bool verbose
= arg_get_lit(clictx
, 4);
1130 bool use_decode6
= arg_get_lit(clictx
, 5);
1131 CLIParserFree(clictx
);
1134 if (enc_data_len
> 0) {
1135 if (enc_data_len
!= 8) {
1136 PrintAndLogEx(ERR
, "Data must be 8 hex bytes (16 HEX symbols)");
1143 if (key_len
!= 16) {
1144 PrintAndLogEx(ERR
, "Transport key must be 16 hex bytes (32 HEX characters)");
1150 size_t decryptedlen
= 2048;
1151 uint8_t *decrypted
= NULL
;
1152 bool have_file
= false;
1153 int res
= PM3_SUCCESS
;
1155 // if user supplied dump file, time to load it
1158 DumpFileType_t dftype
= getfiletype(filename
);
1161 res
= loadFile_safe(filename
, ".bin", (void **)&decrypted
, &decryptedlen
);
1165 res
= loadFileEML_safe(filename
, (void **)&decrypted
, &decryptedlen
);
1169 decrypted
= calloc(2048, sizeof(uint8_t));
1170 if (decrypted
== NULL
) {
1171 PrintAndLogEx(ERR
, "error, cannot allocate memory ");
1174 res
= loadFileJSON(filename
, (void *)decrypted
, 2048, &decryptedlen
, NULL
);
1179 PrintAndLogEx(ERR
, "Error: Only BIN/JSON/EML formats allowed");
1184 if (res
!= PM3_SUCCESS
) {
1192 // load transport key
1193 bool use_sc
= false;
1194 if (have_key
== false) {
1195 use_sc
= IsCardHelperPresent(verbose
);
1196 if (use_sc
== false) {
1198 res
= loadFile_safe(ICLASS_DECRYPTION_BIN
, "", (void **)&keyptr
, &keylen
);
1199 if (res
!= PM3_SUCCESS
) {
1200 PrintAndLogEx(INFO
, "Couldn't find any decryption methods");
1206 PrintAndLogEx(ERR
, "Failed to load transport key from file");
1211 memcpy(key
, keyptr
, sizeof(key
));
1217 mbedtls_des3_context ctx
;
1218 mbedtls_des3_set2key_dec(&ctx
, key
);
1220 // decrypt user supplied data
1223 uint8_t dec_data
[8] = {0};
1225 Decrypt(enc_data
, dec_data
);
1227 mbedtls_des3_crypt_ecb(&ctx
, enc_data
, dec_data
);
1229 PrintAndLogEx(SUCCESS
, "Data: %s", sprint_hex(dec_data
, sizeof(dec_data
)));
1231 if (use_sc
&& use_decode6
)
1232 DecodeBlock6(dec_data
);
1235 // decrypt dump file data
1238 picopass_hdr_t
*hdr
= (picopass_hdr_t
*)decrypted
;
1240 uint8_t mem
= hdr
->conf
.mem_config
;
1241 uint8_t chip
= hdr
->conf
.chip_config
;
1242 uint8_t applimit
= hdr
->conf
.app_limit
;
1244 uint8_t app_areas
= 2;
1245 getMemConfig(mem
, chip
, &app_areas
, &kb
);
1247 BLOCK79ENCRYPTION aa1_encryption
= (decrypted
[(6 * 8) + 7] & 0x03);
1249 uint32_t limit
= MIN(applimit
, decryptedlen
/ 8);
1251 if (decryptedlen
/ 8 != applimit
) {
1252 PrintAndLogEx(WARNING
, "Actual file len " _YELLOW_("%zu") " vs HID app-limit len " _YELLOW_("%u"), decryptedlen
, applimit
* 8);
1253 PrintAndLogEx(INFO
, "Setting limit to " _GREEN_("%u"), limit
* 8);
1256 //uint8_t numblocks4userid = GetNumberBlocksForUserId(decrypted + (6 * 8));
1258 for (uint16_t blocknum
= 0; blocknum
< limit
; ++blocknum
) {
1260 uint8_t idx
= blocknum
* 8;
1261 memcpy(enc_data
, decrypted
+ idx
, 8);
1263 if (aa1_encryption
== RFU
|| aa1_encryption
== None
)
1266 // Decrypted block 7,8,9 if configured.
1267 if (blocknum
> 6 && blocknum
<= 9 && memcmp(enc_data
, empty
, 8) != 0) {
1269 Decrypt(enc_data
, decrypted
+ idx
);
1271 mbedtls_des3_crypt_ecb(&ctx
, enc_data
, decrypted
+ idx
);
1276 // use the first block (CSN) for filename
1277 char *fptr
= calloc(50, sizeof(uint8_t));
1278 if (fptr
== false) {
1279 PrintAndLogEx(WARNING
, "Failed to allocate memory");
1284 strcat(fptr
, "hf-iclass-");
1285 FillFileNameByUID(fptr
, hdr
->csn
, "-dump-decrypted", sizeof(hdr
->csn
));
1287 saveFile(fptr
, ".bin", decrypted
, decryptedlen
);
1288 saveFileEML(fptr
, decrypted
, decryptedlen
, 8);
1289 saveFileJSON(fptr
, jsfIclass
, decrypted
, decryptedlen
, NULL
);
1291 printIclassDumpContents(decrypted
, 1, (decryptedlen
/ 8), decryptedlen
);
1293 PrintAndLogEx(NORMAL
, "");
1296 bool has_values
= (memcmp(decrypted
+ (8 * 6), empty
, 8) != 0) && (memcmp(decrypted
+ (8 * 6), zeros
, 8) != 0);
1299 DecodeBlock6(decrypted
+ (8 * 6));
1303 // decode block 7-8-9
1304 has_values
= (memcmp(decrypted
+ (8 * 7), empty
, 8) != 0) && (memcmp(decrypted
+ (8 * 7), zeros
, 8) != 0);
1307 //todo: remove preamble/sentinal
1308 uint32_t top
= 0, mid
, bot
;
1309 mid
= bytes_to_num(decrypted
+ (8 * 7), 4);
1310 bot
= bytes_to_num(decrypted
+ (8 * 7) + 4, 4);
1312 PrintAndLogEx(INFO
, "Block 7 decoder");
1314 char hexstr
[16 + 1] = {0};
1315 hex_to_buffer((uint8_t *)hexstr
, decrypted
+ (8 * 7), 8, sizeof(hexstr
) - 1, 0, 0, true);
1317 char binstr
[8 * 8 + 1] = {0};
1318 hextobinstring(binstr
, hexstr
);
1320 while (i
< strlen(binstr
) && binstr
[i
++] == '0');
1322 PrintAndLogEx(SUCCESS
, "Binary..................... " _GREEN_("%s"), binstr
+ i
);
1324 PrintAndLogEx(INFO
, "Wiegand decode");
1325 wiegand_message_t packed
= initialize_message_object(top
, mid
, bot
, strlen(binstr
+ i
));
1326 HIDTryUnpack(&packed
);
1329 PrintAndLogEx(INFO
, "No credential found");
1333 has_values
= (memcmp(decrypted
+ (8 * 9), empty
, 8) != 0) && (memcmp(decrypted
+ (8 * 9), zeros
, 8) != 0);
1336 uint8_t usr_blk_len
= GetNumberBlocksForUserId(decrypted
+ (8 * 6));
1337 if (usr_blk_len
< 3) {
1340 PrintAndLogEx(NORMAL
, "");
1341 PrintAndLogEx(INFO
, "Block 9 decoder");
1343 uint8_t pinsize
= GetPinSize(decrypted
+ (8 * 6));
1346 uint64_t pin
= bytes_to_num(decrypted
+ (8 * 9), 5);
1348 snprintf(tmp
, sizeof(tmp
), "%."PRIu64
, BCD2DEC(pin
));
1349 PrintAndLogEx(INFO
, "PIN........................ " _GREEN_("%.*s"), pinsize
, tmp
);
1355 PrintAndLogEx(INFO
, "-----------------------------------------------------------------");
1360 mbedtls_des3_free(&ctx
);
1364 static void iclass_encrypt_block_data(uint8_t *blk_data
, uint8_t *key
) {
1365 uint8_t encrypted_data
[16];
1366 uint8_t *encrypted
= encrypted_data
;
1367 mbedtls_des3_context ctx
;
1368 mbedtls_des3_set2key_enc(&ctx
, key
);
1369 mbedtls_des3_crypt_ecb(&ctx
, blk_data
, encrypted
);
1370 memcpy(blk_data
, encrypted
, 8);
1371 mbedtls_des3_free(&ctx
);
1374 static int CmdHFiClassEncryptBlk(const char *Cmd
) {
1375 CLIParserContext
*clictx
;
1376 CLIParserInit(&clictx
, "hf iclass encrypt",
1377 "3DES encrypt data\n"
1378 "OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside\n"
1379 "in the resources directory. The file should be 16 hex bytes of binary data",
1380 "hf iclass encrypt -d 0102030405060708\n"
1381 "hf iclass encrypt -d 0102030405060708 -k 00112233445566778899AABBCCDDEEFF");
1383 void *argtable
[] = {
1385 arg_str1("d", "data", "<hex>", "data to encrypt"),
1386 arg_str0("k", "key", "<hex>", "3DES transport key"),
1387 arg_lit0("v", "verbose", "verbose output"),
1390 CLIExecWithReturn(clictx
, Cmd
, argtable
, false);
1392 int blk_data_len
= 0;
1393 uint8_t blk_data
[8] = {0};
1395 CLIGetHexWithReturn(clictx
, 1, blk_data
, &blk_data_len
);
1397 if (blk_data_len
!= 8) {
1398 PrintAndLogEx(ERR
, "Block data must be 8 hex bytes (16 HEX symbols)");
1399 CLIParserFree(clictx
);
1404 uint8_t key
[16] = {0};
1405 uint8_t *keyptr
= NULL
;
1406 bool have_key
= false;
1408 CLIGetHexWithReturn(clictx
, 2, key
, &key_len
);
1411 if (key_len
!= 16) {
1412 PrintAndLogEx(ERR
, "Transport key must be 16 hex bytes (32 HEX characters)");
1413 CLIParserFree(clictx
);
1419 bool verbose
= arg_get_lit(clictx
, 3);
1421 CLIParserFree(clictx
);
1423 bool use_sc
= false;
1424 if (have_key
== false) {
1425 use_sc
= IsCardHelperPresent(verbose
);
1426 if (use_sc
== false) {
1428 int res
= loadFile_safe(ICLASS_DECRYPTION_BIN
, "", (void **)&keyptr
, &keylen
);
1429 if (res
!= PM3_SUCCESS
) {
1430 PrintAndLogEx(ERR
, "Failed to find any encryption methods");
1435 PrintAndLogEx(ERR
, "Failed to load transport key from file");
1439 memcpy(key
, keyptr
, sizeof(key
));
1445 Encrypt(blk_data
, blk_data
);
1447 iclass_encrypt_block_data(blk_data
, key
);
1449 PrintAndLogEx(SUCCESS
, "encrypted block %s", sprint_hex(blk_data
, 8));
1453 static bool select_only(uint8_t *CSN
, uint8_t *CCNR
, bool verbose
) {
1455 uint8_t flags
= (FLAG_ICLASS_READER_INIT
| FLAG_ICLASS_READER_CLEARTRACE
);
1457 clearCommandBuffer();
1458 PacketResponseNG resp
;
1459 SendCommandMIX(CMD_HF_ICLASS_READER
, flags
, 0, 0, NULL
, 0);
1460 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2000) == false) {
1461 PrintAndLogEx(WARNING
, "command execute timeout");
1465 uint8_t isok
= resp
.oldarg
[0] & 0xff;
1467 // no tag found or button pressed
1468 if ((isok
== 0) || isok
== 0xFF) {
1470 PrintAndLogEx(FAILED
, "failed tag-select, aborting... (%d)", isok
);
1475 picopass_hdr_t
*hdr
= (picopass_hdr_t
*)resp
.data
.asBytes
;
1478 memcpy(CSN
, hdr
->csn
, 8);
1481 memcpy(CCNR
, hdr
->epurse
, 8);
1484 PrintAndLogEx(SUCCESS
, "CSN %s", sprint_hex(CSN
, 8));
1485 PrintAndLogEx(SUCCESS
, "epurse %s", sprint_hex(CCNR
, 8));
1490 static int CmdHFiClassDump(const char *Cmd
) {
1491 CLIParserContext
*ctx
;
1492 CLIParserInit(&ctx
, "hf iclass dump",
1493 "Dump all memory from a iCLASS tag",
1494 "hf iclass dump -k 001122334455667B\n"
1495 "hf iclass dump -k AAAAAAAAAAAAAAAA --credit 001122334455667B\n"
1496 "hf iclass dump -k AAAAAAAAAAAAAAAA --elite\n"
1497 "hf iclass dump --ki 0\n"
1498 "hf iclass dump --ki 0 --ci 2");
1500 void *argtable
[] = {
1502 arg_str0("f", "file", "<fn>", "save filename"),
1503 arg_str0("k", "key", "<hex>", "debit key or NR/MAC for replay as 8 hex bytes"),
1504 arg_int0(NULL
, "ki", "<dec>", "debit key index to select key from memory 'hf iclass managekeys'"),
1505 arg_str0(NULL
, "credit", "<hex>", "credit key as 8 hex bytes"),
1506 arg_int0(NULL
, "ci", "<dec>", "credit key index to select key from memory 'hf iclass managekeys'"),
1507 arg_lit0(NULL
, "elite", "elite computations applied to key"),
1508 arg_lit0(NULL
, "raw", "raw, the key is interpreted as raw block 3/4"),
1509 arg_lit0(NULL
, "nr", "replay of NR/MAC"),
1512 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1515 char filename
[FILE_PATH_SIZE
] = {0};
1516 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
1519 uint8_t key
[8] = {0};
1522 CLIGetHexWithReturn(ctx
, 2, key
, &key_len
);
1524 int deb_key_nr
= arg_get_int_def(ctx
, 3, -1);
1526 if (key_len
> 0 && deb_key_nr
>= 0) {
1527 PrintAndLogEx(ERR
, "Please specify debit key or index, not both");
1535 PrintAndLogEx(ERR
, "Debit key is incorrect length");
1541 if (deb_key_nr
>= 0) {
1542 if (deb_key_nr
< ICLASS_KEYS_MAX
) {
1544 memcpy(key
, iClass_Key_Table
[deb_key_nr
], 8);
1545 PrintAndLogEx(SUCCESS
, "Using AA1 (debit) key[%d] " _GREEN_("%s"), deb_key_nr
, sprint_hex(iClass_Key_Table
[deb_key_nr
], 8));
1547 PrintAndLogEx(ERR
, "Key number is invalid");
1553 int credit_key_len
= 0;
1554 uint8_t credit_key
[8] = {0};
1555 bool have_credit_key
= false;
1557 CLIGetHexWithReturn(ctx
, 4, credit_key
, &credit_key_len
);
1559 int credit_key_nr
= arg_get_int_def(ctx
, 5, -1);
1561 if (credit_key_len
> 0 && credit_key_nr
>= 0) {
1562 PrintAndLogEx(ERR
, "Please specify credit key or index, not both");
1567 if (credit_key_len
> 0) {
1569 have_credit_key
= true;
1570 if (credit_key_len
!= 8) {
1571 PrintAndLogEx(ERR
, "Credit key is incorrect length");
1577 if (credit_key_nr
>= 0) {
1578 if (credit_key_nr
< ICLASS_KEYS_MAX
) {
1580 have_credit_key
= true;
1581 memcpy(key
, iClass_Key_Table
[credit_key_nr
], 8);
1582 PrintAndLogEx(SUCCESS
, "Using AA2 (credit) key[%d] " _GREEN_("%s"), credit_key_nr
, sprint_hex(iClass_Key_Table
[credit_key_nr
], 8));
1584 PrintAndLogEx(ERR
, "Key number is invalid");
1590 bool elite
= arg_get_lit(ctx
, 6);
1591 bool rawkey
= arg_get_lit(ctx
, 7);
1592 bool use_replay
= arg_get_lit(ctx
, 8);
1596 if ((use_replay
+ rawkey
+ elite
) > 1) {
1597 PrintAndLogEx(ERR
, "Can not use a combo of 'elite', 'raw', 'nr'");
1601 uint8_t app_limit1
= 0, app_limit2
= 0;
1603 uint32_t flags
= (FLAG_ICLASS_READER_INIT
| FLAG_ICLASS_READER_CLEARTRACE
);
1605 //get CSN and config
1606 PacketResponseNG resp
;
1607 uint8_t tag_data
[0x100 * 8];
1608 memset(tag_data
, 0xFF, sizeof(tag_data
));
1610 clearCommandBuffer();
1611 SendCommandMIX(CMD_HF_ICLASS_READER
, flags
, 0, 0, NULL
, 0);
1612 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 2000)) {
1613 PrintAndLogEx(WARNING
, "command execute timeout");
1619 uint8_t readStatus
= resp
.oldarg
[0] & 0xff;
1620 picopass_hdr_t
*hdr
= (picopass_hdr_t
*)resp
.data
.asBytes
;
1622 if (readStatus
== 0) {
1623 PrintAndLogEx(FAILED
, "no tag found");
1628 uint8_t pagemap
= get_pagemap(hdr
);
1630 if (readStatus
& (FLAG_ICLASS_CSN
| FLAG_ICLASS_CONF
| FLAG_ICLASS_CC
)) {
1632 memcpy(tag_data
, hdr
, 24);
1634 uint8_t type
= get_mem_config(hdr
);
1636 // tags configured for NON SECURE PAGE, acts different
1637 if (pagemap
== PICOPASS_NON_SECURE_PAGEMODE
) {
1639 PrintAndLogEx(INFO
, "Card in non-secure page mode detected");
1641 app_limit1
= card_app2_limit
[type
];
1644 app_limit1
= hdr
->conf
.app_limit
;
1645 app_limit2
= card_app2_limit
[type
];
1649 PrintAndLogEx(FAILED
, "failed to read block 0,1,2");
1654 if (pagemap
== PICOPASS_NON_SECURE_PAGEMODE
) {
1655 PrintAndLogEx(INFO
, "Dumping all available memory, block 3 - %u (0x%02x)", app_limit1
, app_limit1
);
1657 PrintAndLogEx(INFO
, "No keys needed, ignoring user supplied key");
1660 if (auth
== false) {
1661 PrintAndLogEx(FAILED
, "Run command with keys");
1664 PrintAndLogEx(INFO
, "Card has atleast 2 application areas. AA1 limit %u (0x%02X) AA2 limit %u (0x%02X)", app_limit1
, app_limit1
, app_limit2
, app_limit2
);
1667 iclass_dump_req_t payload
= {
1668 .req
.use_raw
= rawkey
,
1669 .req
.use_elite
= elite
,
1670 .req
.use_credit_key
= false,
1671 .req
.use_replay
= use_replay
,
1672 .req
.send_reply
= true,
1673 .req
.do_auth
= auth
,
1674 .end_block
= app_limit1
,
1676 memcpy(payload
.req
.key
, key
, 8);
1678 // tags configured for NON SECURE PAGE, acts different
1679 if (pagemap
== PICOPASS_NON_SECURE_PAGEMODE
) {
1680 payload
.start_block
= 3;
1681 payload
.req
.do_auth
= false;
1683 payload
.start_block
= 6;
1686 clearCommandBuffer();
1687 SendCommandNG(CMD_HF_ICLASS_DUMP
, (uint8_t *)&payload
, sizeof(payload
));
1691 PrintAndLogEx(NORMAL
, "." NOLF
);
1692 if (kbd_enter_pressed()) {
1693 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
1695 return PM3_EOPABORTED
;
1698 if (WaitForResponseTimeout(CMD_HF_ICLASS_DUMP
, &resp
, 2000))
1702 PrintAndLogEx(NORMAL
, "");
1703 if (resp
.status
!= PM3_SUCCESS
) {
1704 PrintAndLogEx(ERR
, "failed to communicate with card");
1713 struct p_resp
*packet
= (struct p_resp
*)resp
.data
.asBytes
;
1715 if (packet
->isOK
== false) {
1716 PrintAndLogEx(WARNING
, "read AA1 blocks failed");
1720 uint32_t startindex
= packet
->bb_offset
;
1721 uint32_t blocks_read
= packet
->block_cnt
;
1723 uint8_t tempbuf
[0x100 * 8];
1725 // response ok - now get bigbuf content of the dump
1726 if (!GetFromDevice(BIG_BUF
, tempbuf
, sizeof(tempbuf
), startindex
, NULL
, 0, NULL
, 2500, false)) {
1727 PrintAndLogEx(WARNING
, "command execution time out");
1728 return PM3_ETIMEOUT
;
1731 if (pagemap
== PICOPASS_NON_SECURE_PAGEMODE
) {
1732 // all memory available
1733 memcpy(tag_data
+ (8 * 3), tempbuf
+ (8 * 3), (blocks_read
* 8));
1736 memcpy(tag_data
+ (8 * 3), tempbuf
+ (8 * 3), 8);
1738 memcpy(tag_data
+ (8 * 5), tempbuf
+ (8 * 5), 8);
1740 memcpy(tag_data
+ (8 * 6), tempbuf
+ (8 * 6), (blocks_read
* 8));
1743 uint16_t bytes_got
= (app_limit1
+ 1) * 8;
1745 // try AA2 Kc, Credit
1746 bool aa2_success
= false;
1748 if (have_credit_key
&& pagemap
!= 0x01) {
1750 // AA2 authenticate credit key
1751 memcpy(payload
.req
.key
, credit_key
, 8);
1753 payload
.req
.use_credit_key
= true;
1754 payload
.start_block
= app_limit1
+ 1;
1755 payload
.end_block
= app_limit2
;
1756 payload
.req
.do_auth
= true;
1758 clearCommandBuffer();
1759 SendCommandNG(CMD_HF_ICLASS_DUMP
, (uint8_t *)&payload
, sizeof(payload
));
1762 PrintAndLogEx(NORMAL
, "." NOLF
);
1763 if (kbd_enter_pressed()) {
1764 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
1766 return PM3_EOPABORTED
;
1769 if (WaitForResponseTimeout(CMD_HF_ICLASS_DUMP
, &resp
, 2000))
1772 PrintAndLogEx(NORMAL
, "");
1773 if (resp
.status
!= PM3_SUCCESS
) {
1774 PrintAndLogEx(ERR
, "failed to communicate with card");
1778 packet
= (struct p_resp
*)resp
.data
.asBytes
;
1779 if (packet
->isOK
== false) {
1780 PrintAndLogEx(WARNING
, "failed read block using credit key");
1784 blocks_read
= packet
->block_cnt
;
1785 startindex
= packet
->bb_offset
;
1787 if (blocks_read
* 8 > sizeof(tag_data
) - bytes_got
) {
1788 PrintAndLogEx(WARNING
, "data exceeded buffer size! ");
1789 blocks_read
= (sizeof(tag_data
) - bytes_got
) / 8;
1792 // get dumped data from bigbuf
1793 if (!GetFromDevice(BIG_BUF
, tempbuf
, sizeof(tempbuf
), startindex
, NULL
, 0, NULL
, 2500, false)) {
1794 PrintAndLogEx(WARNING
, "command execution time out");
1799 memcpy(tag_data
+ (8 * 4), tempbuf
+ (8 * 4), 8);
1802 memcpy(tag_data
+ (8 * (app_limit1
+ 1)), tempbuf
+ (8 * (app_limit1
+ 1)), (blocks_read
* 8));
1804 bytes_got
= (blocks_read
* 8);
1811 if (have_credit_key
&& pagemap
!= 0x01 && aa2_success
== false)
1812 PrintAndLogEx(INFO
, "Reading AA2 failed. dumping AA1 data to file");
1815 printIclassDumpContents(tag_data
, 1, (bytes_got
/ 8), bytes_got
);
1817 // use CSN as filename
1818 if (filename
[0] == 0) {
1819 strcat(filename
, "hf-iclass-");
1820 FillFileNameByUID(filename
, tag_data
, "-dump", 8);
1823 // save the dump to .bin file
1824 PrintAndLogEx(SUCCESS
, "saving dump file - %u blocks read", bytes_got
/ 8);
1825 saveFile(filename
, ".bin", tag_data
, bytes_got
);
1826 saveFileEML(filename
, tag_data
, bytes_got
, 8);
1827 saveFileJSON(filename
, jsfIclass
, tag_data
, bytes_got
, NULL
);
1829 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf iclass decrypt -f") "` to decrypt dump file");
1830 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf iclass view -f") "` to view dump file");
1831 PrintAndLogEx(NORMAL
, "");
1835 static int iclass_write_block(uint8_t blockno
, uint8_t *bldata
, uint8_t *KEY
, bool use_credit_key
, bool elite
, bool rawkey
, bool replay
, bool verbose
, bool use_secure_pagemode
) {
1837 iclass_writeblock_req_t payload
= {
1838 .req
.use_raw
= rawkey
,
1839 .req
.use_elite
= elite
,
1840 .req
.use_credit_key
= use_credit_key
,
1841 .req
.use_replay
= replay
,
1842 .req
.blockno
= blockno
,
1843 .req
.send_reply
= true,
1844 .req
.do_auth
= use_secure_pagemode
,
1846 memcpy(payload
.req
.key
, KEY
, 8);
1847 memcpy(payload
.data
, bldata
, sizeof(payload
.data
));
1849 clearCommandBuffer();
1850 SendCommandNG(CMD_HF_ICLASS_WRITEBL
, (uint8_t *)&payload
, sizeof(payload
));
1851 PacketResponseNG resp
;
1853 if (WaitForResponseTimeout(CMD_HF_ICLASS_WRITEBL
, &resp
, 2000) == 0) {
1854 if (verbose
) PrintAndLogEx(WARNING
, "Command execute timeout");
1855 return PM3_ETIMEOUT
;
1858 if (resp
.status
!= PM3_SUCCESS
) {
1859 if (verbose
) PrintAndLogEx(ERR
, "failed to communicate with card");
1862 return (resp
.data
.asBytes
[0] == 1) ? PM3_SUCCESS
: PM3_ESOFT
;
1865 static int CmdHFiClass_WriteBlock(const char *Cmd
) {
1866 CLIParserContext
*ctx
;
1867 CLIParserInit(&ctx
, "hf iclass wrbl",
1868 "Write data to an iCLASS tag",
1869 "hf iclass wrbl -b 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B\n"
1870 "hf iclass wrbl -b 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B --credit\n"
1871 "hf iclass wrbl -b 10 -d AAAAAAAAAAAAAAAA --ki 0");
1873 void *argtable
[] = {
1875 arg_str0("k", "key", "<hex>", "Access key as 8 hex bytes"),
1876 arg_int0(NULL
, "ki", "<dec>", "Key index to select key from memory 'hf iclass managekeys'"),
1877 arg_int1("b", "block", "<dec>", "The block number to read"),
1878 arg_str1("d", "data", "<hex>", "data to write as 8 hex bytes"),
1879 arg_lit0(NULL
, "credit", "key is assumed to be the credit key"),
1880 arg_lit0(NULL
, "elite", "elite computations applied to key"),
1881 arg_lit0(NULL
, "raw", "no computations applied to key"),
1882 arg_lit0(NULL
, "nr", "replay of NR/MAC"),
1883 arg_lit0("v", "verbose", "verbose output"),
1886 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1889 uint8_t key
[8] = {0};
1891 CLIGetHexWithReturn(ctx
, 1, key
, &key_len
);
1893 int key_nr
= arg_get_int_def(ctx
, 2, -1);
1895 if (key_len
> 0 && key_nr
>= 0) {
1896 PrintAndLogEx(ERR
, "Please specify key or index, not both");
1906 PrintAndLogEx(ERR
, "Key is incorrect length");
1910 } else if (key_nr
>= 0) {
1911 if (key_nr
< ICLASS_KEYS_MAX
) {
1913 memcpy(key
, iClass_Key_Table
[key_nr
], 8);
1914 PrintAndLogEx(SUCCESS
, "Using key[%d] " _GREEN_("%s"), key_nr
, sprint_hex(iClass_Key_Table
[key_nr
], 8));
1916 PrintAndLogEx(ERR
, "Key number is invalid");
1922 int blockno
= arg_get_int_def(ctx
, 3, 0);
1925 uint8_t data
[8] = {0};
1926 CLIGetHexWithReturn(ctx
, 4, data
, &data_len
);
1928 if (data_len
!= 8) {
1929 PrintAndLogEx(ERR
, "Data must be 8 hex bytes (16 hex symbols)");
1934 bool use_credit_key
= arg_get_lit(ctx
, 5);
1935 bool elite
= arg_get_lit(ctx
, 6);
1936 bool rawkey
= arg_get_lit(ctx
, 7);
1937 bool use_replay
= arg_get_lit(ctx
, 8);
1938 bool verbose
= arg_get_lit(ctx
, 9);
1942 if ((use_replay
+ rawkey
+ elite
) > 1) {
1943 PrintAndLogEx(ERR
, "Can not use a combo of 'elite', 'raw', 'nr'");
1947 int isok
= iclass_write_block(blockno
, data
, key
, use_credit_key
, elite
, rawkey
, use_replay
, verbose
, auth
);
1950 PrintAndLogEx(SUCCESS
, "Wrote block %3d/0x%02X successful", blockno
, blockno
);
1954 PrintAndLogEx(INFO
, "Writing tear off triggered");
1957 PrintAndLogEx(FAILED
, "Writing failed");
1963 static int CmdHFiClassRestore(const char *Cmd
) {
1964 CLIParserContext
*ctx
;
1965 CLIParserInit(&ctx
, "hf iclass restore",
1966 "Restore data from dumpfile onto a iCLASS tag",
1967 "hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 6 --last 18 --ki 0\n"
1968 "hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 6 --last 18 --ki 0 --elite\n"
1969 "hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 6 --last 18 -k 1122334455667788 --elite\n"
1972 void *argtable
[] = {
1974 arg_str1("f", "file", "<fn>", "specify a filename to restore (bin/eml/json)"),
1975 arg_str0("k", "key", "<hex>", "Access key as 8 hex bytes"),
1976 arg_int0(NULL
, "ki", "<dec>", "Key index to select key from memory 'hf iclass managekeys'"),
1977 arg_int1(NULL
, "first", "<dec>", "The first block number to restore"),
1978 arg_int1(NULL
, "last", "<dec>", "The last block number to restore"),
1979 arg_lit0(NULL
, "credit", "key is assumed to be the credit key"),
1980 arg_lit0(NULL
, "elite", "elite computations applied to key"),
1981 arg_lit0(NULL
, "raw", "no computations applied to key"),
1982 arg_lit0("v", "verbose", "verbose output"),
1985 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1988 char filename
[FILE_PATH_SIZE
] = {0};
1989 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
1992 uint8_t key
[8] = {0};
1994 CLIGetHexWithReturn(ctx
, 2, key
, &key_len
);
1996 int key_nr
= arg_get_int_def(ctx
, 3, -1);
1998 if (key_len
> 0 && key_nr
>= 0) {
1999 PrintAndLogEx(ERR
, "Please specify key or index, not both");
2006 PrintAndLogEx(ERR
, "Key is incorrect length");
2010 } else if (key_nr
>= 0) {
2011 if (key_nr
< ICLASS_KEYS_MAX
) {
2012 memcpy(key
, iClass_Key_Table
[key_nr
], 8);
2013 PrintAndLogEx(SUCCESS
, "Using key[%d] " _GREEN_("%s"), key_nr
, sprint_hex(iClass_Key_Table
[key_nr
], 8));
2015 PrintAndLogEx(ERR
, "Key number is invalid");
2020 PrintAndLogEx(ERR
, "Please specify a key or key index");
2025 int startblock
= arg_get_int_def(ctx
, 4, 0);
2026 int endblock
= arg_get_int_def(ctx
, 5, 0);
2028 bool use_credit_key
= arg_get_lit(ctx
, 6);
2029 bool elite
= arg_get_lit(ctx
, 7);
2030 bool rawkey
= arg_get_lit(ctx
, 8);
2031 bool verbose
= arg_get_lit(ctx
, 9);
2035 if (rawkey
+ elite
> 1) {
2036 PrintAndLogEx(FAILED
, "Can not use both 'e', 'r'");
2040 if (startblock
< 5) {
2041 PrintAndLogEx(WARNING
, "you cannot write key blocks this way. yet... make your start block > 4");
2045 uint32_t payload_size
= sizeof(iclass_restore_req_t
) + (sizeof(iclass_restore_item_t
) * (endblock
- startblock
+ 1));
2047 if (payload_size
> PM3_CMD_DATA_SIZE
) {
2048 PrintAndLogEx(NORMAL
, "Trying to write too many blocks at once. Max: %d", PM3_CMD_DATA_SIZE
/ 8);
2052 size_t bytes_read
= 2048;
2053 uint8_t *dump
= NULL
;
2054 int res
= PM3_SUCCESS
;
2055 DumpFileType_t dftype
= getfiletype(filename
);
2058 res
= loadFile_safe(filename
, ".bin", (void **)&dump
, &bytes_read
);
2062 res
= loadFileEML_safe(filename
, (void **)&dump
, &bytes_read
);
2066 dump
= calloc(2048, sizeof(uint8_t));
2068 PrintAndLogEx(ERR
, "error, cannot allocate memory ");
2071 res
= loadFileJSON(filename
, (void *)dump
, 2048, &bytes_read
, NULL
);
2076 PrintAndLogEx(ERR
, "Error: Only BIN/JSON/EML formats allowed");
2081 if (res
!= PM3_SUCCESS
) {
2086 if (bytes_read
== 0) {
2087 PrintAndLogEx(ERR
, "file reading error");
2092 if (bytes_read
< ((endblock
- startblock
+ 1) * 8)) {
2093 PrintAndLogEx(ERR
, "file is smaller than your suggested block range ( " _RED_("0x%02x..0x%02x")" )",
2094 startblock
, endblock
2100 iclass_restore_req_t
*payload
= calloc(1, payload_size
);
2101 payload
->req
.use_raw
= rawkey
;
2102 payload
->req
.use_elite
= elite
;
2103 payload
->req
.use_credit_key
= use_credit_key
;
2104 payload
->req
.use_replay
= false;
2105 payload
->req
.blockno
= startblock
;
2106 payload
->req
.send_reply
= true;
2107 payload
->req
.do_auth
= true;
2108 memcpy(payload
->req
.key
, key
, 8);
2110 payload
->item_cnt
= (endblock
- startblock
+ 1);
2112 // read data from file from block 6 --- 19
2113 // we will use this struct [data 8 bytes][MAC 4 bytes] for each block calculate all mac number for each data
2114 // then copy to usbcommand->asbytes;
2115 // max is 32 - 6 = 28 block. 28 x 12 bytes gives 336 bytes
2117 for (uint8_t i
= 0; i
< payload
->item_cnt
; i
++) {
2118 payload
->blocks
[i
].blockno
= startblock
+ i
;
2119 memcpy(payload
->blocks
[i
].data
, dump
+ (startblock
* 8) + (i
* 8), sizeof(payload
->blocks
[i
].data
));
2125 PrintAndLogEx(INFO
, "Preparing to restore block range %02d..%02d", startblock
, endblock
);
2127 PrintAndLogEx(INFO
, "---------+----------------------");
2128 PrintAndLogEx(INFO
, " block# | data");
2129 PrintAndLogEx(INFO
, "---------+----------------------");
2131 for (uint8_t i
= 0; i
< payload
->item_cnt
; i
++) {
2132 iclass_restore_item_t item
= payload
->blocks
[i
];
2133 PrintAndLogEx(INFO
, "%3d/0x%02X | %s", item
.blockno
, item
.blockno
, sprint_hex_inrow(item
.data
, sizeof(item
.data
)));
2137 PrintAndLogEx(INFO
, "restore started...");
2139 PacketResponseNG resp
;
2140 clearCommandBuffer();
2141 SendCommandNG(CMD_HF_ICLASS_RESTORE
, (uint8_t *)payload
, payload_size
);
2143 if (WaitForResponseTimeout(CMD_HF_ICLASS_RESTORE
, &resp
, 2500) == 0) {
2144 PrintAndLogEx(WARNING
, "command execute timeout");
2147 return PM3_ETIMEOUT
;
2150 if (resp
.status
== PM3_SUCCESS
) {
2151 PrintAndLogEx(SUCCESS
, "iCLASS restore " _GREEN_("successful"));
2152 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf iclass rdbl") "` to verify data on card");
2154 PrintAndLogEx(WARNING
, "iCLASS restore " _RED_("failed"));
2161 static int iclass_read_block(uint8_t *KEY
, uint8_t blockno
, uint8_t keyType
, bool elite
, bool rawkey
, bool replay
, bool verbose
, bool auth
, uint8_t *out
) {
2163 iclass_auth_req_t payload
= {
2166 .use_credit_key
= (keyType
== 0x18),
2167 .use_replay
= replay
,
2172 memcpy(payload
.key
, KEY
, 8);
2174 PacketResponseNG resp
;
2175 clearCommandBuffer();
2176 SendCommandNG(CMD_HF_ICLASS_READBL
, (uint8_t *)&payload
, sizeof(payload
));
2178 if (WaitForResponseTimeout(CMD_HF_ICLASS_READBL
, &resp
, 2000) == false) {
2179 if (verbose
) PrintAndLogEx(WARNING
, "Command execute timeout");
2180 return PM3_ETIMEOUT
;
2183 if (resp
.status
!= PM3_SUCCESS
) {
2184 if (verbose
) PrintAndLogEx(ERR
, "failed to communicate with card");
2185 return PM3_EWRONGANSWER
;
2189 iclass_readblock_resp_t
*packet
= (iclass_readblock_resp_t
*)resp
.data
.asBytes
;
2191 if (packet
->isOK
== false) {
2192 if (verbose
) PrintAndLogEx(FAILED
, "authentication error");
2196 PrintAndLogEx(NORMAL
, "");
2197 PrintAndLogEx(SUCCESS
, " block %3d/0x%02X : " _GREEN_("%s"), blockno
, blockno
, sprint_hex(packet
->data
, sizeof(packet
->data
)));
2198 PrintAndLogEx(NORMAL
, "");
2201 memcpy(out
, packet
->data
, sizeof(packet
->data
));
2206 static int CmdHFiClass_ReadBlock(const char *Cmd
) {
2207 CLIParserContext
*ctx
;
2208 CLIParserInit(&ctx
, "hf iclass rdbl",
2209 "Read a iCLASS block from tag",
2210 "hf iclass rdbl -b 6 -k 0011223344556677\n"
2211 "hf iclass rdbl -b 27 -k 0011223344556677 --credit\n"
2212 "hf iclass rdbl -b 10 --ki 0");
2214 void *argtable
[] = {
2216 arg_str0("k", "key", "<hex>", "Access key as 8 hex bytes"),
2217 arg_int0(NULL
, "ki", "<dec>", "Key index to select key from memory 'hf iclass managekeys'"),
2218 arg_int1("b", "block", "<dec>", "The block number to read"),
2219 arg_lit0(NULL
, "credit", "key is assumed to be the credit key"),
2220 arg_lit0(NULL
, "elite", "elite computations applied to key"),
2221 arg_lit0(NULL
, "raw", "no computations applied to key"),
2222 arg_lit0(NULL
, "nr", "replay of NR/MAC"),
2223 arg_lit0("v", "verbose", "verbose output"),
2226 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2229 uint8_t key
[8] = {0};
2231 CLIGetHexWithReturn(ctx
, 1, key
, &key_len
);
2233 int key_nr
= arg_get_int_def(ctx
, 2, -1);
2235 if (key_len
> 0 && key_nr
>= 0) {
2236 PrintAndLogEx(ERR
, "Please specify key or index, not both");
2246 PrintAndLogEx(ERR
, "Key is incorrect length");
2250 } else if (key_nr
>= 0) {
2251 if (key_nr
< ICLASS_KEYS_MAX
) {
2253 memcpy(key
, iClass_Key_Table
[key_nr
], 8);
2254 PrintAndLogEx(SUCCESS
, "Using key[%d] " _GREEN_("%s"), key_nr
, sprint_hex(iClass_Key_Table
[key_nr
], 8));
2256 PrintAndLogEx(ERR
, "Key number is invalid");
2262 int blockno
= arg_get_int_def(ctx
, 3, 0);
2264 uint8_t keyType
= 0x88; //debit key
2265 if (arg_get_lit(ctx
, 4)) {
2266 PrintAndLogEx(SUCCESS
, "Using " _YELLOW_("credit") " key");
2267 keyType
= 0x18; //credit key
2270 bool elite
= arg_get_lit(ctx
, 5);
2271 bool rawkey
= arg_get_lit(ctx
, 6);
2272 bool use_replay
= arg_get_lit(ctx
, 7);
2273 bool verbose
= arg_get_lit(ctx
, 8);
2277 if ((use_replay
+ rawkey
+ elite
) > 1) {
2278 PrintAndLogEx(ERR
, "Can not use a combo of 'elite', 'raw', 'nr'");
2284 PrintAndLogEx(SUCCESS
, "Using key %s", sprint_hex(key
, 8));
2287 if (auth
== false && verbose
) {
2288 PrintAndLogEx(WARNING
, "warning: no authentication used with read. Typical for cards configured into `non-secure page`");
2292 uint8_t data
[8] = {0};
2293 int res
= iclass_read_block(key
, blockno
, keyType
, elite
, rawkey
, use_replay
, verbose
, auth
, data
);
2294 if (res
!= PM3_SUCCESS
)
2297 if (blockno
< 6 || blockno
> 7)
2300 if (memcmp(data
, empty
, 8) == 0)
2303 bool use_sc
= IsCardHelperPresent(verbose
);
2304 if (use_sc
== false)
2307 // crypto helper available.
2308 PrintAndLogEx(INFO
, "----------------------------- " _CYAN_("cardhelper") " -----------------------------");
2317 uint8_t dec_data
[8];
2319 uint64_t a
= bytes_to_num(data
, 8);
2320 bool starts
= (leadingzeros(a
) < 12);
2321 bool ones
= (bitcount64(a
) > 16 && bitcount64(a
) < 48);
2323 if (starts
&& ones
) {
2324 PrintAndLogEx(INFO
, "data looks encrypted, False Positives " _YELLOW_("ARE") " possible");
2325 Decrypt(data
, dec_data
);
2326 PrintAndLogEx(SUCCESS
, "decrypted : " _GREEN_("%s"), sprint_hex(dec_data
, sizeof(dec_data
)));
2328 memcpy(dec_data
, data
, sizeof(dec_data
));
2329 PrintAndLogEx(INFO
, "data looks unencrypted, trying to decode");
2332 if (memcmp(dec_data
, empty
, 8) != 0) {
2334 //todo: remove preamble/sentinal
2336 uint32_t top
= 0, mid
, bot
;
2337 mid
= bytes_to_num(dec_data
, 4);
2338 bot
= bytes_to_num(dec_data
+ 4, 4);
2340 char hexstr
[16 + 1] = {0};
2341 hex_to_buffer((uint8_t *)hexstr
, dec_data
, 8, sizeof(hexstr
) - 1, 0, 0, true);
2342 char binstr
[64 + 1] = {0};
2343 hextobinstring(binstr
, hexstr
);
2345 while (i
< strlen(binstr
) && binstr
[i
++] == '0');
2348 PrintAndLogEx(SUCCESS
, " bin : %s", binstr
+ i
);
2349 PrintAndLogEx(INFO
, "");
2350 PrintAndLogEx(INFO
, "------------------------------ " _CYAN_("wiegand") " -------------------------------");
2351 wiegand_message_t packed
= initialize_message_object(top
, mid
, bot
, strlen(binstr
+ i
));
2352 HIDTryUnpack(&packed
);
2354 PrintAndLogEx(INFO
, "no credential found");
2359 PrintAndLogEx(INFO
, "----------------------------------------------------------------------");
2363 static int CmdHFiClass_loclass(const char *Cmd
) {
2364 CLIParserContext
*ctx
;
2365 CLIParserInit(&ctx
, "hf iclass loclass",
2366 "Execute the offline part of loclass attack\n"
2367 " An iclass dumpfile is assumed to consist of an arbitrary number of\n"
2368 " malicious CSNs, and their protocol responses\n"
2369 " The binary format of the file is expected to be as follows: \n"
2370 " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>\n"
2371 " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>\n"
2372 " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>\n"
2373 " ... totalling N*24 bytes",
2374 "hf iclass loclass -f iclass_dump.bin\n"
2375 "hf iclass loclass --test");
2377 void *argtable
[] = {
2379 arg_str0("f", "file", "<fn>", "filename with nr/mac data from `hf iclass sim -t 2` "),
2380 arg_lit0(NULL
, "test", "Perform self-test"),
2381 arg_lit0(NULL
, "long", "Perform self-test, including long ones"),
2384 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2387 char filename
[FILE_PATH_SIZE
] = {0};
2388 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
2390 bool test
= arg_get_lit(ctx
, 2);
2391 bool longtest
= arg_get_lit(ctx
, 3);
2395 if (test
|| longtest
) {
2396 int errors
= testCipherUtils();
2397 errors
+= testMAC();
2398 errors
+= doKeyTests();
2399 errors
+= testElite(longtest
);
2401 if (errors
!= PM3_SUCCESS
)
2402 PrintAndLogEx(ERR
, "There were errors!!!");
2407 return bruteforceFileNoKeys(filename
);
2410 void printIclassDumpContents(uint8_t *iclass_dump
, uint8_t startblock
, uint8_t endblock
, size_t filesize
) {
2412 picopass_hdr_t
*hdr
= (picopass_hdr_t
*)iclass_dump
;
2413 // picopass_ns_hdr_t *ns_hdr = (picopass_ns_hdr_t *)iclass_dump;
2414 // uint8_t pagemap = get_pagemap(hdr);
2415 // if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { }
2417 uint8_t lock
= hdr
->conf
.block_writelock
;
2419 // is chip in ReadOnly (RO)
2420 bool ro
= ((lock
& 0x80) == 0);
2422 uint8_t maxmemcount
;
2423 uint8_t filemaxblock
= filesize
/ 8;
2424 uint8_t mem_config
= iclass_dump
[13];
2426 if (mem_config
& 0x80)
2431 if (startblock
== 0)
2434 if ((endblock
> maxmemcount
) || (endblock
== 0))
2435 endblock
= maxmemcount
;
2437 // remember endblock needs to relate to zero-index arrays.
2438 if (endblock
> filemaxblock
- 1)
2439 endblock
= filemaxblock
- 1;
2442 PrintAndLogEx(INFO, "startblock: %u, endblock: %u, filesize: %zu, maxmemcount: %u, filemaxblock: %u"
2450 uint8_t pagemap
= get_pagemap(hdr
);
2456 PrintAndLogEx(NORMAL
, "");
2457 PrintAndLogEx(INFO
, " block# | data | ascii |lck| info");
2458 PrintAndLogEx(INFO
, "---------+-------------------------+----------+---+--------------");
2459 PrintAndLogEx(INFO
, " 0/0x00 | " _GREEN_("%s") " | | CSN ", sprint_hex_ascii(iclass_dump
, 8));
2462 PrintAndLogEx(INFO
, "....");
2464 while (i
<= endblock
) {
2465 uint8_t *blk
= iclass_dump
+ (i
* 8);
2467 bool bl_lock
= false;
2471 bl_lock
= ((lock
& 0x40) == 0);
2475 bl_lock
= ((lock
& 0x20) == 0);
2479 bl_lock
= ((lock
& 0x10) == 0);
2483 bl_lock
= ((lock
& 0x08) == 0);
2487 bl_lock
= ((lock
& 0x04) == 0);
2491 bl_lock
= ((lock
& 0x02) == 0);
2495 bl_lock
= ((lock
& 0x01) == 0);
2503 const char *lockstr
= (bl_lock
) ? _RED_("x") : " ";
2505 if (pagemap
== PICOPASS_NON_SECURE_PAGEMODE
) {
2506 const char *info_nonks
[] = {"CSN", "Config", "AIA", "User"};
2507 const char *s
= info_nonks
[3];
2512 PrintAndLogEx(INFO
, "%3d/0x%02X | %s | %s | %s ", i
, i
, sprint_hex_ascii(blk
, 8), lockstr
, s
);
2514 const char *info_ks
[] = {"CSN", "Config", "E-purse", "Debit", "Credit", "AIA", "User"};
2515 const char *s
= info_ks
[6];
2519 PrintAndLogEx(INFO
, "%3d/0x%02X | %s | %s | %s ", i
, i
, sprint_hex_ascii(blk
, 8), lockstr
, s
);
2523 PrintAndLogEx(INFO
, "---------+-------------------------+----------+---+--------------");
2524 PrintAndLogEx(NORMAL
, "");
2527 static int CmdHFiClassView(const char *Cmd
) {
2528 CLIParserContext
*ctx
;
2529 CLIParserInit(&ctx
, "hf iclass view",
2530 "Print a iCLASS tag dump file (bin/eml/json)",
2531 "hf iclass view -f hf-iclass-AA162D30F8FF12F1-dump.bin\n"
2532 "hf iclass view --first 1 -f hf-iclass-AA162D30F8FF12F1-dump.bin\n");
2534 void *argtable
[] = {
2536 arg_str1("f", "file", "<fn>", "filename of dump (bin/eml/json)"),
2537 arg_int0(NULL
, "first", "<dec>", "Begin printing from this block (default block 6)"),
2538 arg_int0(NULL
, "last", "<dec>", "End printing at this block (default 0, ALL)"),
2539 arg_lit0("v", "verbose", "verbose output"),
2542 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2545 char filename
[FILE_PATH_SIZE
];
2546 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
2548 int startblock
= arg_get_int_def(ctx
, 2, 0);
2549 int endblock
= arg_get_int_def(ctx
, 3, 0);
2550 bool verbose
= arg_get_lit(ctx
, 4);
2554 size_t bytes_read
= 2048;
2555 uint8_t *dump
= NULL
;
2557 DumpFileType_t dftype
= getfiletype(filename
);
2560 res
= loadFile_safe(filename
, ".bin", (void **)&dump
, &bytes_read
);
2564 res
= loadFileEML_safe(filename
, (void **)&dump
, &bytes_read
);
2568 dump
= calloc(2048, sizeof(uint8_t));
2570 PrintAndLogEx(ERR
, "error, cannot allocate memory ");
2573 res
= loadFileJSON(filename
, (void *)dump
, 2048, &bytes_read
, NULL
);
2578 PrintAndLogEx(ERR
, "Error: Only BIN/JSON/EML formats allowed");
2583 if (res
!= PM3_SUCCESS
) {
2589 PrintAndLogEx(INFO
, "File: " _YELLOW_("%s"), filename
);
2590 PrintAndLogEx(INFO
, "File size %zu bytes, file blocks %d (0x%x)", bytes_read
, (uint16_t)(bytes_read
>> 3), (uint16_t)(bytes_read
>> 3));
2591 PrintAndLogEx(INFO
, "Printing blocks from: " _YELLOW_("%02d") " to: " _YELLOW_("%02d"), (startblock
== 0) ? 6 : startblock
, endblock
);
2594 PrintAndLogEx(NORMAL
, "");
2595 print_picopass_header((picopass_hdr_t
*) dump
);
2596 print_picopass_info((picopass_hdr_t
*) dump
);
2597 printIclassDumpContents(dump
, startblock
, endblock
, bytes_read
);
2602 void HFiClassCalcDivKey(uint8_t *CSN
, uint8_t *KEY
, uint8_t *div_key
, bool elite
) {
2604 uint8_t keytable
[128] = {0};
2605 uint8_t key_index
[8] = {0};
2606 uint8_t key_sel
[8] = { 0 };
2607 uint8_t key_sel_p
[8] = { 0 };
2608 hash2(KEY
, keytable
);
2609 hash1(CSN
, key_index
);
2610 for (uint8_t i
= 0; i
< 8 ; i
++)
2611 key_sel
[i
] = keytable
[key_index
[i
]];
2613 //Permute from iclass format to standard format
2614 permutekey_rev(key_sel
, key_sel_p
);
2615 diversifyKey(CSN
, key_sel_p
, div_key
);
2617 diversifyKey(CSN
, KEY
, div_key
);
2621 //when told CSN, oldkey, newkey, if new key is elite (elite), and if old key was elite (oldElite)
2622 //calculate and return xor_div_key (ready for a key write command)
2623 //print all div_keys if verbose
2624 static void HFiClassCalcNewKey(uint8_t *CSN
, uint8_t *OLDKEY
, uint8_t *NEWKEY
, uint8_t *xor_div_key
, bool elite
, bool oldElite
, bool verbose
) {
2625 uint8_t old_div_key
[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
2626 uint8_t new_div_key
[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
2628 HFiClassCalcDivKey(CSN
, OLDKEY
, old_div_key
, oldElite
);
2630 HFiClassCalcDivKey(CSN
, NEWKEY
, new_div_key
, elite
);
2632 for (uint8_t i
= 0; i
< ARRAYLEN(old_div_key
); i
++) {
2633 xor_div_key
[i
] = old_div_key
[i
] ^ new_div_key
[i
];
2636 PrintAndLogEx(SUCCESS
, "Old div key......... %s", sprint_hex(old_div_key
, 8));
2637 PrintAndLogEx(SUCCESS
, "New div key......... %s", sprint_hex(new_div_key
, 8));
2638 PrintAndLogEx(SUCCESS
, "Xor div key......... " _YELLOW_("%s") "\n", sprint_hex(xor_div_key
, 8));
2642 static int CmdHFiClassCalcNewKey(const char *Cmd
) {
2643 CLIParserContext
*ctx
;
2644 CLIParserInit(&ctx
, "hf iclass calcnewkey",
2645 "Calculate new keys for updating (blocks 3 & 4)",
2646 "hf iclass calcnewkey --old 1122334455667788 --new 2233445566778899 --csn deadbeafdeadbeaf --elite2 -> e key to e key given csn\n"
2647 "hf iclass calcnewkey --old 1122334455667788 --new 2233445566778899 --elite -> std key to e key read csn\n"
2648 "hf iclass calcnewkey --old 1122334455667788 --new 2233445566778899 -> std to std read csn");
2650 void *argtable
[] = {
2652 arg_str0(NULL
, "old", "<hex>", "Specify key as 8 hex bytes"),
2653 arg_int0(NULL
, "oki", "<dec>", "Old key index to select key from memory 'hf iclass managekeys'"),
2654 arg_str0(NULL
, "new", "<hex>", "Specify key as 8 hex bytes"),
2655 arg_int0(NULL
, "nki", "<dec>", "New key index to select key from memory 'hf iclass managekeys'"),
2656 arg_str0(NULL
, "csn", "<hex>", "Specify a Card Serial Number (CSN) to diversify the key (if omitted will attempt to read a CSN)"),
2657 arg_lit0(NULL
, "elite", "Elite computations applied to new key"),
2658 arg_lit0(NULL
, "elite2", "Elite computations applied to both old and new key"),
2661 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2663 int old_key_len
= 0;
2664 uint8_t old_key
[8] = {0};
2665 CLIGetHexWithReturn(ctx
, 1, old_key
, &old_key_len
);
2667 int old_key_nr
= arg_get_int_def(ctx
, 2, -1);
2669 if (old_key_len
> 0 && old_key_nr
>= 0) {
2670 PrintAndLogEx(ERR
, "Please specify old key or index, not both");
2675 if (old_key_len
> 0) {
2676 if (old_key_len
!= 8) {
2677 PrintAndLogEx(ERR
, "Old key is incorrect length");
2681 } else if (old_key_nr
>= 0) {
2682 if (old_key_nr
< ICLASS_KEYS_MAX
) {
2683 memcpy(old_key
, iClass_Key_Table
[old_key_nr
], 8);
2684 PrintAndLogEx(SUCCESS
, "Using old key[%d]... " _GREEN_("%s"), old_key_nr
, sprint_hex(iClass_Key_Table
[old_key_nr
], 8));
2686 PrintAndLogEx(ERR
, "Key number is invalid");
2691 PrintAndLogEx(ERR
, "Please specify an old key or old key index");
2696 int new_key_len
= 0;
2697 uint8_t new_key
[8] = {0};
2698 CLIGetHexWithReturn(ctx
, 3, new_key
, &new_key_len
);
2700 int new_key_nr
= arg_get_int_def(ctx
, 4, -1);
2702 if (new_key_len
> 0 && new_key_nr
>= 0) {
2703 PrintAndLogEx(ERR
, "Please specify new key or index, not both");
2708 if (new_key_len
> 0) {
2709 if (new_key_len
!= 8) {
2710 PrintAndLogEx(ERR
, "New key is incorrect length");
2714 } else if (new_key_nr
>= 0) {
2715 if (new_key_nr
< ICLASS_KEYS_MAX
) {
2716 memcpy(new_key
, iClass_Key_Table
[new_key_nr
], 8);
2717 PrintAndLogEx(SUCCESS
, "Using new key[%d]... " _GREEN_("%s"), new_key_nr
, sprint_hex(iClass_Key_Table
[new_key_nr
], 8));
2719 PrintAndLogEx(ERR
, "Key number is invalid");
2724 PrintAndLogEx(ERR
, "Please specify an new key or old key index");
2730 uint8_t csn
[8] = {0};
2731 CLIGetHexWithReturn(ctx
, 5, csn
, &csn_len
);
2732 bool givenCSN
= false;
2737 PrintAndLogEx(ERR
, "CSN is incorrect length");
2743 bool elite
= arg_get_lit(ctx
, 6);
2744 bool old_elite
= false;
2746 if (arg_get_lit(ctx
, 7)) {
2753 uint8_t xor_div_key
[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
2755 if (givenCSN
== false) {
2756 uint8_t CCNR
[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
2757 if (select_only(csn
, CCNR
, true) == false) {
2763 HFiClassCalcNewKey(csn
, old_key
, new_key
, xor_div_key
, elite
, old_elite
, true);
2768 static int loadKeys(char *filename
) {
2770 uint8_t *dump
= NULL
;
2771 size_t bytes_read
= 0;
2772 if (loadFile_safe(filename
, "", (void **)&dump
, &bytes_read
) != PM3_SUCCESS
) {
2773 PrintAndLogEx(FAILED
, "File: " _YELLOW_("%s") ": not found or locked.", filename
);
2777 if (bytes_read
> ICLASS_KEYS_MAX
* 8) {
2778 PrintAndLogEx(WARNING
, "File is too long to load - bytes: %zu", bytes_read
);
2783 for (; i
< bytes_read
/ 8; i
++)
2784 memcpy(iClass_Key_Table
[i
], dump
+ (i
* 8), 8);
2787 PrintAndLogEx(SUCCESS
, "Loaded " _GREEN_("%2d") " keys from %s", i
, filename
);
2791 static int saveKeys(char *filename
) {
2793 f
= fopen(filename
, "wb");
2795 PrintAndLogEx(FAILED
, "File: " _YELLOW_("%s") ": not found or locked.", filename
);
2798 for (uint8_t i
= 0; i
< ICLASS_KEYS_MAX
; i
++) {
2799 if (fwrite(iClass_Key_Table
[i
], 8, 1, f
) != 1) {
2800 PrintAndLogEx(WARNING
, "save key failed to write to file:" _YELLOW_("%s"), filename
);
2808 static int printKeys(void) {
2809 PrintAndLogEx(NORMAL
, "");
2810 PrintAndLogEx(INFO
, "idx| key");
2811 PrintAndLogEx(INFO
, "---+------------------------");
2812 for (uint8_t i
= 0; i
< ICLASS_KEYS_MAX
; i
++) {
2813 if (memcmp(iClass_Key_Table
[i
], "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0)
2814 PrintAndLogEx(INFO
, " %u |", i
);
2816 PrintAndLogEx(INFO
, " %u | " _YELLOW_("%s"), i
, sprint_hex(iClass_Key_Table
[i
], 8));
2818 PrintAndLogEx(INFO
, "---+------------------------");
2819 PrintAndLogEx(NORMAL
, "");
2823 static int CmdHFiClassManageKeys(const char *Cmd
) {
2824 CLIParserContext
*ctx
;
2825 CLIParserInit(&ctx
, "hf iclass managekeys",
2826 "Manage iCLASS Keys in client memory",
2827 "hf iclass managekeys --ki 0 -k 1122334455667788 --> set key 1122334455667788 at index 0\n"
2828 "hf iclass managekeys -f mykeys.bin --save --> save key file\n"
2829 "hf iclass managekeys -f mykeys.bin --load --> load key file\n"
2830 "hf iclass managekeys -p --> print keys");
2832 void *argtable
[] = {
2834 arg_str0("f", "file", "<fn>", "Specify a filename for load / save operations"),
2835 arg_str0("k", "key", "<hex>", "Access key as 8 hex bytes"),
2836 arg_int0(NULL
, "ki", "<dec>", "Specify key index to set key in memory"),
2837 arg_lit0(NULL
, "save", "Save keys in memory to file specified by filename"),
2838 arg_lit0(NULL
, "load", "Load keys to memory from file specified by filename"),
2839 arg_lit0("p", "print", "Print keys loaded into memory"),
2842 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2845 char filename
[FILE_PATH_SIZE
] = {0};
2846 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
2849 uint8_t key
[8] = {0};
2850 CLIGetHexWithReturn(ctx
, 2, key
, &key_len
);
2851 uint8_t operation
= 0;
2856 PrintAndLogEx(ERR
, "Key is incorrect length");
2862 int key_nr
= arg_get_int_def(ctx
, 3, -1);
2865 if (key_nr
< ICLASS_KEYS_MAX
) {
2866 PrintAndLogEx(SUCCESS
, "Current key[%d] " _YELLOW_("%s"), key_nr
, sprint_hex_inrow(iClass_Key_Table
[key_nr
], 8));
2868 PrintAndLogEx(ERR
, "Key index is out-of-range");
2874 if (arg_get_lit(ctx
, 4)) { //save
2877 if (arg_get_lit(ctx
, 5)) { //load
2880 if (arg_get_lit(ctx
, 6)) { //print
2886 if (operation
== 0) {
2887 PrintAndLogEx(ERR
, "No operation specified (load, save, or print)\n");
2890 if (operation
> 6) {
2891 PrintAndLogEx(ERR
, "Too many operations specified\n");
2894 if (operation
> 4 && fnlen
== 0) {
2895 PrintAndLogEx(ERR
, "You must enter a filename when loading or saving\n");
2898 if (key_len
> 0 && key_nr
== -1) {
2899 PrintAndLogEx(ERR
, "Please specify key index when specifying key");
2903 switch (operation
) {
2905 memcpy(iClass_Key_Table
[key_nr
], key
, 8);
2906 PrintAndLogEx(SUCCESS
, " New key[%d] " _GREEN_("%s"), key_nr
, sprint_hex_inrow(iClass_Key_Table
[key_nr
], 8));
2911 return loadKeys(filename
);
2913 return saveKeys(filename
);
2918 static void add_key(uint8_t *key
) {
2921 for (i
= 0; i
< ICLASS_KEYS_MAX
; i
++) {
2923 if (memcmp(iClass_Key_Table
[i
], key
, 8) == 0) {
2924 PrintAndLogEx(SUCCESS
, "Key already at keyslot " _GREEN_("%d"), i
);
2928 if (memcmp(iClass_Key_Table
[i
], "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) {
2929 memcpy(iClass_Key_Table
[i
], key
, 8);
2930 PrintAndLogEx(SUCCESS
, "Added key to keyslot " _GREEN_("%d"), i
);
2935 if (i
== ICLASS_KEYS_MAX
) {
2936 PrintAndLogEx(INFO
, "Couldn't find an empty keyslot");
2938 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf iclass managekeys -p") "` to view keys");
2942 static int CmdHFiClassCheckKeys(const char *Cmd
) {
2943 CLIParserContext
*ctx
;
2944 CLIParserInit(&ctx
, "hf iclass chk",
2945 "Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag",
2946 "hf iclass chk -f iclass_default_keys.dic\n"
2947 "hf iclass chk -f iclass_default_keys.dic --elite");
2949 void *argtable
[] = {
2951 arg_str1("f", "file", "<fn>", "Dictionary file with default iclass keys"),
2952 arg_lit0(NULL
, "credit", "key is assumed to be the credit key"),
2953 arg_lit0(NULL
, "elite", "elite computations applied to key"),
2954 arg_lit0(NULL
, "raw", "no computations applied to key (raw)"),
2957 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2960 char filename
[FILE_PATH_SIZE
] = {0};
2961 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
2963 bool use_credit_key
= arg_get_lit(ctx
, 2);
2964 bool use_elite
= arg_get_lit(ctx
, 3);
2965 bool use_raw
= arg_get_lit(ctx
, 4);
2969 uint8_t CSN
[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
2970 uint8_t CCNR
[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
2972 uint64_t t1
= msclock();
2975 uint8_t *keyBlock
= NULL
;
2976 uint32_t keycount
= 0;
2977 int res
= loadFileDICTIONARY_safe(filename
, (void **)&keyBlock
, 8, &keycount
);
2978 if (res
!= PM3_SUCCESS
|| keycount
== 0) {
2983 // limit size of keys that can be held in memory
2984 if (keycount
> 100000) {
2985 PrintAndLogEx(FAILED
, "File contains more than 100 000 keys, aborting...");
2990 // Get CSN / UID and CCNR
2991 PrintAndLogEx(SUCCESS
, "Reading tag CSN / CCNR...");
2993 bool got_csn
= false;
2994 for (uint8_t i
= 0; i
< ICLASS_AUTH_RETRY
; i
++) {
2995 got_csn
= select_only(CSN
, CCNR
, false);
2996 if (got_csn
== false)
2997 PrintAndLogEx(WARNING
, "one more try");
3002 if (got_csn
== false) {
3003 PrintAndLogEx(WARNING
, "Tried %d times. Can't select card, aborting...", ICLASS_AUTH_RETRY
);
3009 // allocate memory for the pre calculated macs
3010 iclass_premac_t
*pre
= calloc(keycount
, sizeof(iclass_premac_t
));
3012 PrintAndLogEx(WARNING
, "failed to allocate memory");
3016 PrintAndLogEx(SUCCESS
, " CSN: " _GREEN_("%s"), sprint_hex(CSN
, sizeof(CSN
)));
3017 PrintAndLogEx(SUCCESS
, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR
, sizeof(CCNR
)));
3019 PrintAndLogEx(INFO
, "Generating diversified keys %s", (use_elite
|| use_raw
) ? NOLF
: "");
3021 PrintAndLogEx(NORMAL
, "using " _YELLOW_("elite algo"));
3023 PrintAndLogEx(NORMAL
, "using " _YELLOW_("raw mode"));
3025 GenerateMacFrom(CSN
, CCNR
, use_raw
, use_elite
, keyBlock
, keycount
, pre
);
3027 PrintAndLogEx(SUCCESS
, "Searching for " _YELLOW_("%s") " key...", (use_credit_key
) ? "CREDIT" : "DEBIT");
3029 // USB_COMMAND. 512/4 = 103 mac
3030 uint32_t max_chunk_size
= 0;
3031 if (keycount
> ((PM3_CMD_DATA_SIZE
- sizeof(iclass_chk_t
)) / 4))
3032 max_chunk_size
= (PM3_CMD_DATA_SIZE
- sizeof(iclass_chk_t
)) / 4;
3034 max_chunk_size
= keycount
;
3037 conn
.block_after_ACK
= true;
3039 // keep track of position of found key
3040 uint32_t chunk_offset
= 0;
3041 uint8_t found_offset
= 0;
3042 bool found_key
= false;
3045 // - a list of keys.
3046 // - a list of precalculated macs that corresponds to the key list
3047 // We send a chunk of macs to the device each time
3049 // main keychunk loop
3050 for (chunk_offset
= 0; chunk_offset
< keycount
; chunk_offset
+= max_chunk_size
) {
3052 if (kbd_enter_pressed()) {
3053 PrintAndLogEx(NORMAL
, "");
3054 PrintAndLogEx(WARNING
, "aborted via keyboard!");
3058 uint32_t curr_chunk_cnt
= keycount
- chunk_offset
;
3059 if ((keycount
- chunk_offset
) > max_chunk_size
) {
3060 curr_chunk_cnt
= max_chunk_size
;
3064 if (curr_chunk_cnt
== keycount
- chunk_offset
) {
3065 // Disable fast mode on last command
3066 conn
.block_after_ACK
= false;
3069 uint32_t tmp_plen
= sizeof(iclass_chk_t
) + (4 * curr_chunk_cnt
);
3070 iclass_chk_t
*packet
= calloc(tmp_plen
, sizeof(uint8_t));
3071 if (packet
== NULL
) {
3072 PrintAndLogEx(WARNING
, "failed to allocate memory");
3075 packet
->use_credit_key
= use_credit_key
;
3076 packet
->count
= curr_chunk_cnt
;
3077 // copy chunk of pre calculated macs to packet
3078 memcpy(packet
->items
, (pre
+ chunk_offset
), (4 * curr_chunk_cnt
));
3080 clearCommandBuffer();
3081 SendCommandNG(CMD_HF_ICLASS_CHKKEYS
, (uint8_t *)packet
, tmp_plen
);
3084 bool looped
= false;
3085 uint8_t timeout
= 0;
3087 PacketResponseNG resp
;
3088 while (WaitForResponseTimeout(CMD_HF_ICLASS_CHKKEYS
, &resp
, 2000) == false) {
3090 PrintAndLogEx(NORMAL
, "." NOLF
);
3092 PrintAndLogEx(WARNING
, "\ncommand execute timeout, aborting...");
3099 PrintAndLogEx(NORMAL
, "");
3101 if (resp
.status
== PM3_SUCCESS
) {
3102 found_offset
= resp
.data
.asBytes
[0];
3104 PrintAndLogEx(NORMAL
, "");
3105 PrintAndLogEx(SUCCESS
,
3106 "Found valid key " _GREEN_("%s")
3107 , sprint_hex(keyBlock
+ (chunk_offset
+ found_offset
) * 8, 8)
3111 PrintAndLogEx(INPLACE
, "Chunk [%03d/%d]", chunk_offset
, keycount
);
3117 t1
= msclock() - t1
;
3119 PrintAndLogEx(NORMAL
, "");
3120 PrintAndLogEx(SUCCESS
, "time in iclass chk " _YELLOW_("%.1f") " seconds", (float)t1
/ 1000.0);
3124 uint8_t *key
= keyBlock
+ (chunk_offset
+ found_offset
) * 8;
3130 PrintAndLogEx(NORMAL
, "");
3135 // this method tries to identify in which configuration mode a iCLASS / iCLASS SE reader is in.
3136 // Standard or Elite / HighSecurity mode. It uses a default key dictionary list in order to work.
3137 static int CmdHFiClassLookUp(const char *Cmd
) {
3138 CLIParserContext
*ctx
;
3139 CLIParserInit(&ctx
, "hf iclass lookup",
3140 "Lookup keys takes some sniffed trace data and tries to verify what key was used against a dictionary file",
3141 "hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic\n"
3142 "hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic --elite");
3144 void *argtable
[] = {
3146 arg_str1("f", "file", "<fn>", "Dictionary file with default iclass keys"),
3147 arg_str1(NULL
, "csn", "<hex>", "Specify CSN as 8 hex bytes"),
3148 arg_str1(NULL
, "epurse", "<hex>", "Specify ePurse as 8 hex bytes"),
3149 arg_str1(NULL
, "macs", "<hex>", "MACs"),
3150 arg_lit0(NULL
, "elite", "Elite computations applied to key"),
3151 arg_lit0(NULL
, "raw", "no computations applied to key"),
3154 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3157 char filename
[FILE_PATH_SIZE
] = {0};
3158 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
3161 uint8_t csn
[8] = {0};
3162 CLIGetHexWithReturn(ctx
, 2, csn
, &csn_len
);
3166 PrintAndLogEx(ERR
, "CSN is incorrect length");
3173 uint8_t epurse
[8] = {0};
3174 CLIGetHexWithReturn(ctx
, 3, epurse
, &epurse_len
);
3176 if (epurse_len
> 0) {
3177 if (epurse_len
!= 8) {
3178 PrintAndLogEx(ERR
, "ePurse is incorrect length");
3185 uint8_t macs
[8] = {0};
3186 CLIGetHexWithReturn(ctx
, 4, macs
, &macs_len
);
3189 if (macs_len
!= 8) {
3190 PrintAndLogEx(ERR
, "MAC is incorrect length");
3196 bool use_elite
= arg_get_lit(ctx
, 5);
3197 bool use_raw
= arg_get_lit(ctx
, 6);
3202 uint8_t MAC_TAG
[4] = { 0, 0, 0, 0 };
3204 // stupid copy.. CCNR is a combo of epurse and reader nonce
3205 memcpy(CCNR
, epurse
, 8);
3206 memcpy(CCNR
+ 8, macs
, 4);
3207 memcpy(MAC_TAG
, macs
+ 4, 4);
3209 PrintAndLogEx(SUCCESS
, " CSN: " _GREEN_("%s"), sprint_hex(csn
, sizeof(csn
)));
3210 PrintAndLogEx(SUCCESS
, " Epurse: %s", sprint_hex(epurse
, sizeof(epurse
)));
3211 PrintAndLogEx(SUCCESS
, " MACS: %s", sprint_hex(macs
, sizeof(macs
)));
3212 PrintAndLogEx(SUCCESS
, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR
, sizeof(CCNR
)));
3213 PrintAndLogEx(SUCCESS
, "TAG MAC: %s", sprint_hex(MAC_TAG
, sizeof(MAC_TAG
)));
3216 uint64_t t1
= msclock();
3218 uint8_t *keyBlock
= NULL
;
3219 uint32_t keycount
= 0;
3222 int res
= loadFileDICTIONARY_safe(filename
, (void **)&keyBlock
, 8, &keycount
);
3223 if (res
!= PM3_SUCCESS
|| keycount
== 0) {
3229 iclass_prekey_t
*prekey
= calloc(keycount
, sizeof(iclass_prekey_t
));
3235 PrintAndLogEx(INFO
, "Generating diversified keys...");
3236 GenerateMacKeyFrom(csn
, CCNR
, use_raw
, use_elite
, keyBlock
, keycount
, prekey
);
3239 PrintAndLogEx(INFO
, "Using " _YELLOW_("elite algo"));
3241 PrintAndLogEx(INFO
, "Using " _YELLOW_("raw mode"));
3243 PrintAndLogEx(INFO
, "Sorting...");
3246 qsort(prekey
, keycount
, sizeof(iclass_prekey_t
), cmp_uint32
);
3248 PrintAndLogEx(SUCCESS
, "Searching for " _YELLOW_("%s") " key...", "DEBIT");
3249 iclass_prekey_t
*item
;
3250 iclass_prekey_t lookup
;
3251 memcpy(lookup
.mac
, MAC_TAG
, 4);
3254 item
= (iclass_prekey_t
*) bsearch(&lookup
, prekey
, keycount
, sizeof(iclass_prekey_t
), cmp_uint32
);
3257 PrintAndLogEx(SUCCESS
, "Found valid key " _GREEN_("%s"), sprint_hex(item
->key
, 8));
3261 t1
= msclock() - t1
;
3262 PrintAndLogEx(SUCCESS
, "time in iclass lookup " _YELLOW_("%.3f") " seconds", (float)t1
/ 1000.0);
3266 PrintAndLogEx(NORMAL
, "");
3279 iclass_premac_t
*premac
;
3280 iclass_prekey_t
*prekey
;
3282 } PACKED iclass_thread_arg_t
;
3284 static size_t iclass_tc
= 1;
3286 static pthread_mutex_t generator_mutex
= PTHREAD_MUTEX_INITIALIZER
;
3287 static void *bf_generate_mac(void *thread_arg
) {
3289 iclass_thread_arg_t
*targ
= (iclass_thread_arg_t
*)thread_arg
;
3290 const uint8_t idx
= targ
->thread_idx
;
3291 const uint8_t use_raw
= targ
->use_raw
;
3292 const uint8_t use_elite
= targ
->use_elite
;
3293 const uint32_t keycnt
= targ
->keycnt
;
3295 uint8_t *keys
= targ
->keys
;
3296 iclass_premac_t
*list
= targ
->list
.premac
;
3300 memcpy(csn
, targ
->csn
, sizeof(csn
));
3301 memcpy(cc_nr
, targ
->cc_nr
, sizeof(cc_nr
));
3303 uint8_t key
[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
3304 uint8_t div_key
[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
3306 for (uint32_t i
= idx
; i
< keycnt
; i
+= iclass_tc
) {
3308 memcpy(key
, keys
+ 8 * i
, 8);
3310 pthread_mutex_lock(&generator_mutex
);
3312 memcpy(div_key
, key
, 8);
3314 HFiClassCalcDivKey(csn
, key
, div_key
, use_elite
);
3316 doMAC(cc_nr
, div_key
, list
[i
].mac
);
3317 pthread_mutex_unlock(&generator_mutex
);
3322 // precalc diversified keys and their MAC
3323 void GenerateMacFrom(uint8_t *CSN
, uint8_t *CCNR
, bool use_raw
, bool use_elite
, uint8_t *keys
, uint32_t keycnt
, iclass_premac_t
*list
) {
3325 pthread_mutex_init(&generator_mutex
, NULL
);
3327 iclass_tc
= num_CPUs();
3328 pthread_t threads
[iclass_tc
];
3329 iclass_thread_arg_t args
[iclass_tc
];
3330 // init thread arguments
3331 for (uint8_t i
= 0; i
< iclass_tc
; i
++) {
3332 args
[i
].thread_idx
= i
;
3333 args
[i
].use_raw
= use_raw
;
3334 args
[i
].use_elite
= use_elite
;
3335 args
[i
].keycnt
= keycnt
;
3336 args
[i
].keys
= keys
;
3337 args
[i
].list
.premac
= list
;
3339 memcpy(args
[i
].csn
, CSN
, sizeof(args
[i
].csn
));
3340 memcpy(args
[i
].cc_nr
, CCNR
, sizeof(args
[i
].cc_nr
));
3343 for (int i
= 0; i
< iclass_tc
; i
++) {
3344 int res
= pthread_create(&threads
[i
], NULL
, bf_generate_mac
, (void *)&args
[i
]);
3346 PrintAndLogEx(NORMAL
, "");
3347 PrintAndLogEx(WARNING
, "Failed to create pthreads. Quitting");
3352 for (int i
= 0; i
< iclass_tc
; i
++)
3353 pthread_join(threads
[i
], NULL
);
3356 static void *bf_generate_mackey(void *thread_arg
) {
3358 iclass_thread_arg_t
*targ
= (iclass_thread_arg_t
*)thread_arg
;
3359 const uint8_t idx
= targ
->thread_idx
;
3360 const uint8_t use_raw
= targ
->use_raw
;
3361 const uint8_t use_elite
= targ
->use_elite
;
3362 const uint32_t keycnt
= targ
->keycnt
;
3364 uint8_t *keys
= targ
->keys
;
3365 iclass_prekey_t
*list
= targ
->list
.prekey
;
3369 memcpy(csn
, targ
->csn
, sizeof(csn
));
3370 memcpy(cc_nr
, targ
->cc_nr
, sizeof(cc_nr
));
3372 uint8_t div_key
[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
3374 for (uint32_t i
= idx
; i
< keycnt
; i
+= iclass_tc
) {
3376 memcpy(list
[i
].key
, keys
+ 8 * i
, 8);
3378 pthread_mutex_lock(&generator_mutex
);
3380 memcpy(div_key
, list
[i
].key
, 8);
3382 HFiClassCalcDivKey(csn
, list
[i
].key
, div_key
, use_elite
);
3384 doMAC(cc_nr
, div_key
, list
[i
].mac
);
3385 pthread_mutex_unlock(&generator_mutex
);
3390 void GenerateMacKeyFrom(uint8_t *CSN
, uint8_t *CCNR
, bool use_raw
, bool use_elite
, uint8_t *keys
, uint32_t keycnt
, iclass_prekey_t
*list
) {
3392 pthread_mutex_init(&generator_mutex
, NULL
);
3393 iclass_tc
= num_CPUs();
3394 pthread_t threads
[iclass_tc
];
3395 iclass_thread_arg_t args
[iclass_tc
];
3396 // init thread arguments
3397 for (uint8_t i
= 0; i
< iclass_tc
; i
++) {
3398 args
[i
].thread_idx
= i
;
3399 args
[i
].use_raw
= use_raw
;
3400 args
[i
].use_elite
= use_elite
;
3401 args
[i
].keycnt
= keycnt
;
3402 args
[i
].keys
= keys
;
3403 args
[i
].list
.prekey
= list
;
3405 memcpy(args
[i
].csn
, CSN
, sizeof(args
[i
].csn
));
3406 memcpy(args
[i
].cc_nr
, CCNR
, sizeof(args
[i
].cc_nr
));
3409 for (int i
= 0; i
< iclass_tc
; i
++) {
3410 int res
= pthread_create(&threads
[i
], NULL
, bf_generate_mackey
, (void *)&args
[i
]);
3412 PrintAndLogEx(NORMAL
, "");
3413 PrintAndLogEx(WARNING
, "Failed to create pthreads. Quitting");
3418 for (int i
= 0; i
< iclass_tc
; i
++)
3419 pthread_join(threads
[i
], NULL
);
3421 PrintAndLogEx(NORMAL
, "");
3424 // print diversified keys
3425 void PrintPreCalcMac(uint8_t *keys
, uint32_t keycnt
, iclass_premac_t
*pre_list
) {
3427 iclass_prekey_t
*b
= calloc(keycnt
, sizeof(iclass_prekey_t
));
3431 for (uint32_t i
= 0; i
< keycnt
; i
++) {
3432 memcpy(b
[i
].key
, keys
+ 8 * i
, 8);
3433 memcpy(b
[i
].mac
, pre_list
[i
].mac
, 4);
3435 PrintPreCalc(b
, keycnt
);
3439 void PrintPreCalc(iclass_prekey_t
*list
, uint32_t itemcnt
) {
3440 PrintAndLogEx(NORMAL
, "-----+------------------+---------");
3441 PrintAndLogEx(NORMAL
, "#key | key | mac");
3442 PrintAndLogEx(NORMAL
, "-----+------------------+---------");
3443 for (int i
= 0; i
< itemcnt
; i
++) {
3446 PrintAndLogEx(NORMAL
, "[%2d] | %016" PRIx64
" | %08" PRIx64
, i
, bytes_to_num(list
[i
].key
, 8), bytes_to_num(list
[i
].mac
, 4));
3447 } else if (i
== 10) {
3448 PrintAndLogEx(SUCCESS
, "... skip printing the rest");
3453 static void permute(uint8_t *data
, uint8_t len
, uint8_t *output
) {
3456 if (len
> KEY_SIZE
) {
3457 for (uint8_t m
= 0; m
< len
; m
+= KEY_SIZE
) {
3458 permute(data
+ m
, KEY_SIZE
, output
+ m
);
3462 if (len
!= KEY_SIZE
) {
3463 PrintAndLogEx(WARNING
, "wrong key size\n");
3466 for (uint8_t i
= 0; i
< KEY_SIZE
; ++i
) {
3468 uint8_t mask
= 0x80 >> i
;
3469 for (uint8_t j
= 0; j
< KEY_SIZE
; ++j
) {
3477 static void permute_rev(uint8_t *data
, uint8_t len
, uint8_t *output
) {
3478 permute(data
, len
, output
);
3479 permute(output
, len
, data
);
3480 permute(data
, len
, output
);
3482 static void simple_crc(uint8_t *data
, uint8_t len
, uint8_t *output
) {
3484 for (uint8_t i
= 0; i
< len
; ++i
) {
3485 // seventh byte contains the crc.
3486 if ((i
& 0x7) == 0x7) {
3487 output
[i
] = crc
^ 0xFF;
3490 output
[i
] = data
[i
];
3495 // DES doesn't use the MSB.
3496 static void shave(uint8_t *data
, uint8_t len
) {
3497 for (uint8_t i
= 0; i
< len
; ++i
)
3500 static void generate_rev(uint8_t *data
, uint8_t len
) {
3501 uint8_t *key
= calloc(len
, sizeof(uint8_t));
3502 PrintAndLogEx(SUCCESS
, "input permuted key | %s \n", sprint_hex(data
, len
));
3503 permute_rev(data
, len
, key
);
3504 PrintAndLogEx(SUCCESS
, " unpermuted key | %s \n", sprint_hex(key
, len
));
3506 PrintAndLogEx(SUCCESS
, " key | %s \n", sprint_hex(key
, len
));
3509 static void generate(uint8_t *data
, uint8_t len
) {
3510 uint8_t *key
= calloc(len
, sizeof(uint8_t));
3511 uint8_t *pkey
= calloc(len
, sizeof(uint8_t));
3512 PrintAndLogEx(SUCCESS
, " input key | %s \n", sprint_hex(data
, len
));
3513 permute(data
, len
, pkey
);
3514 PrintAndLogEx(SUCCESS
, "permuted key | %s \n", sprint_hex(pkey
, len
));
3515 simple_crc(pkey
, len
, key
);
3516 PrintAndLogEx(SUCCESS
, " CRC'ed key | %s \n", sprint_hex(key
, len
));
3521 static int CmdHFiClassPermuteKey(const char *Cmd
) {
3523 uint8_t key
[8] = {0};
3524 uint8_t data
[16] = {0};
3527 CLIParserContext
*ctx
;
3528 CLIParserInit(&ctx
, "hf iclass permutekey",
3529 "Permute function from 'heart of darkness' paper.",
3530 "hf iclass permutekey --reverse --key 0123456789abcdef\n"
3531 "hf iclass permutekey --key ff55330f0055330f\n");
3533 void *argtable
[] = {
3535 arg_lit0("r", "reverse", "reverse permuted key"),
3536 arg_str1(NULL
, "key", "<hex>", "input key, 8 hex bytes"),
3539 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3540 bool isReverse
= arg_get_lit(ctx
, 1);
3541 CLIGetHexWithReturn(ctx
, 2, data
, &len
);
3544 memcpy(key
, data
, 8);
3547 generate_rev(data
, len
);
3548 uint8_t key_std_format
[8] = {0};
3549 permutekey_rev(key
, key_std_format
);
3550 PrintAndLogEx(SUCCESS
, "Standard NIST format key " _YELLOW_("%s") " \n", sprint_hex(key_std_format
, 8));
3552 generate(data
, len
);
3553 uint8_t key_iclass_format
[8] = {0};
3554 permutekey(key
, key_iclass_format
);
3555 PrintAndLogEx(SUCCESS
, "HID permuted iCLASS format: %s \n", sprint_hex(key_iclass_format
, 8));
3560 static int CmdHFiClassEncode(const char *Cmd
) {
3562 CLIParserContext
*ctx
;
3563 CLIParserInit(&ctx
, "hf iclass encode",
3564 "Encode binary wiegand to block 7",
3565 "hf iclass encode --bin 10001111100000001010100011 --ki 0 -> FC 31 CN 337\n"
3566 "hf iclass encode --bin 10001111100000001010100011 --ki 0 --elite -> FC 31 CN 337, writing w elite key"
3569 void *argtable
[] = {
3571 arg_str1(NULL
, "bin", "<bin>", "Binary string i.e 0001001001"),
3572 arg_int1(NULL
, "ki", "<dec>", "Key index to select key from memory 'hf iclass managekeys'"),
3573 arg_lit0(NULL
, "credit", "key is assumed to be the credit key"),
3574 arg_lit0(NULL
, "elite", "elite computations applied to key"),
3575 arg_lit0(NULL
, "raw", "no computations applied to key"),
3576 arg_str0(NULL
, "enckey", "<hex>", "3DES transport key, 16 hex bytes"),
3579 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3582 uint8_t bin
[70] = {0};
3583 CLIGetStrWithReturn(ctx
, 1, bin
, &bin_len
);
3585 int key_nr
= arg_get_int_def(ctx
, 2, -1);
3588 uint8_t key
[8] = {0};
3590 if (key_nr
< ICLASS_KEYS_MAX
) {
3592 memcpy(key
, iClass_Key_Table
[key_nr
], 8);
3593 PrintAndLogEx(SUCCESS
, "Using key[%d] " _GREEN_("%s"), key_nr
, sprint_hex(iClass_Key_Table
[key_nr
], 8));
3595 PrintAndLogEx(ERR
, "Key number is invalid");
3601 bool use_credit_key
= arg_get_lit(ctx
, 3);
3602 bool elite
= arg_get_lit(ctx
, 4);
3603 bool rawkey
= arg_get_lit(ctx
, 5);
3605 int enc_key_len
= 0;
3606 uint8_t enc_key
[16] = {0};
3607 uint8_t *enckeyptr
= NULL
;
3608 bool have_enc_key
= false;
3609 bool use_sc
= false;
3610 CLIGetHexWithReturn(ctx
, 6, enc_key
, &enc_key_len
);
3614 if ((rawkey
+ elite
) > 1) {
3615 PrintAndLogEx(ERR
, "Can not use a combo of 'elite', 'raw'");
3619 if (enc_key_len
> 0) {
3620 if (enc_key_len
!= 16) {
3621 PrintAndLogEx(ERR
, "Transport key must be 16 hex bytes (32 HEX characters)");
3624 have_enc_key
= true;
3627 if (bin_len
> 127) {
3628 PrintAndLogEx(ERR
, "Binary wiegand string must be less than 128 bits");
3632 if (have_enc_key
== false) {
3633 use_sc
= IsCardHelperPresent(false);
3634 if (use_sc
== false) {
3636 int res
= loadFile_safe(ICLASS_DECRYPTION_BIN
, "", (void **)&enckeyptr
, &keylen
);
3637 if (res
!= PM3_SUCCESS
) {
3638 PrintAndLogEx(ERR
, "Failed to find the transport key");
3642 PrintAndLogEx(ERR
, "Failed to load transport key from file");
3646 memcpy(enc_key
, enckeyptr
, sizeof(enc_key
));
3651 uint8_t credential
[] = {
3652 0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0xE0, 0x17,
3653 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3654 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3655 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3659 memset(data
, 0, sizeof(data
));
3660 BitstreamOut bout
= {data
, 0, 0 };
3662 for (int i
= 0; i
< 64 - bin_len
- 1; i
++) {
3665 // add binary sentinel bit.
3668 // convert binary string to hex bytes
3669 for (int i
= 0; i
< bin_len
; i
++) {
3676 PrintAndLogEx(WARNING
, "Ignoring '%c'", c
);
3679 memcpy(credential
+ 8, data
, sizeof(data
));
3681 // encrypt with transport key
3683 Encrypt(credential
+ 8, credential
+ 8);
3684 Encrypt(credential
+ 16, credential
+ 16);
3685 Encrypt(credential
+ 24, credential
+ 24);
3687 iclass_encrypt_block_data(credential
+ 8, enc_key
);
3688 iclass_encrypt_block_data(credential
+ 16, enc_key
);
3689 iclass_encrypt_block_data(credential
+ 24, enc_key
);
3692 int isok
= PM3_SUCCESS
;
3694 for (uint8_t i
= 0; i
< 4; i
++) {
3695 isok
= iclass_write_block(6 + i
, credential
+ (i
* 8), key
, use_credit_key
, elite
, rawkey
, false, false, auth
);
3698 PrintAndLogEx(SUCCESS
, "Write block %d/0x0%x ( " _GREEN_("ok") " ) --> " _YELLOW_("%s"), 6 + i
, 6 + i
, sprint_hex_inrow(credential
+ (i
* 8), 8));
3701 PrintAndLogEx(SUCCESS
, "Write block %d/0x0%x ( " _RED_("fail") " )", 6 + i
, 6 + i
);
3709 static int CmdHFiClassAutopwn(const char *Cmd) {
3711 CLIParserContext *ctx;
3712 CLIParserInit(&ctx, "hf iclass autopwn",
3713 "Tries to check keys, if found, dump card and save file",
3714 "hf iclass autopwn\n");
3716 void *argtable[] = {
3720 CLIExecWithReturn(ctx, Cmd, argtable, true);
3727 PrintAndLogEx(INFO, "to be implemented");
3732 static int CmdHFiClassConfigCard(const char *Cmd
) {
3733 CLIParserContext
*ctx
;
3734 CLIParserInit(&ctx
, "hf iclass configcard",
3735 "Manage reader configuration card via Cardhelper,\n"
3736 "The generated config card will be uploaded to device emulator memory.\n"
3737 "You can start simulating `hf iclass sim -t 3` or use the emul commands",
3738 "hf iclass configcard -l --> download config card settings\n"
3739 "hf iclass configcard -p --> print all config cards\n"
3740 "hf iclass configcard --ci 1 --> view config card setting in slot 1\n"
3741 "hf iclass configcard -g --ci 0 --> generate config file from slot 0"
3744 void *argtable
[] = {
3746 arg_int0(NULL
, "ci", "<dec>", "use config slot at index"),
3747 arg_int0(NULL
, "ki", "<dec>", "Key index to select key from memory 'hf iclass managekeys'"),
3748 arg_lit0("g", NULL
, "generate card dump file"),
3749 arg_lit0("l", NULL
, "load available cards"),
3750 arg_lit0("p", NULL
, "print available cards"),
3753 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3755 int ccidx
= arg_get_int_def(ctx
, 1, -1);
3756 int kidx
= arg_get_int_def(ctx
, 2, -1);
3757 bool do_generate
= arg_get_lit(ctx
, 3);
3758 bool do_load
= arg_get_lit(ctx
, 4);
3759 bool do_print
= arg_get_lit(ctx
, 5);
3762 bool got_kr
= false;
3763 uint8_t key
[8] = {0};
3765 if (kidx
< ICLASS_KEYS_MAX
) {
3767 memcpy(key
, iClass_Key_Table
[kidx
], 8);
3768 PrintAndLogEx(SUCCESS
, "Using key[%d] " _GREEN_("%s"), kidx
, sprint_hex(iClass_Key_Table
[kidx
], 8));
3770 PrintAndLogEx(ERR
, "--ki number is invalid");
3776 if (load_config_cards() != PM3_SUCCESS
) {
3777 PrintAndLogEx(INFO
, "failed to load, check your cardhelper");
3782 print_config_cards();
3785 if (ccidx
> -1 && ccidx
< 14) {
3786 const iclass_config_card_item_t
*item
= get_config_card_item(ccidx
);
3787 print_config_card(item
);
3791 const iclass_config_card_item_t
*item
= get_config_card_item(ccidx
);
3792 if (strstr(item
->desc
, "Keyroll") != NULL
) {
3793 if (got_kr
== false) {
3794 PrintAndLogEx(ERR
, "please specifiy KEYROLL key!");
3798 generate_config_card(item
, key
, got_kr
);
3804 static command_t CommandTable
[] = {
3805 {"-----------", CmdHelp
, AlwaysAvailable
, "--------------------- " _CYAN_("operations") " ---------------------"},
3806 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
3807 // {"clone", CmdHFiClassClone, IfPm3Iclass, "Create a HID credential to Picopass / iCLASS tag"},
3808 {"dump", CmdHFiClassDump
, IfPm3Iclass
, "Dump Picopass / iCLASS tag to file"},
3809 {"info", CmdHFiClassInfo
, AlwaysAvailable
, "Tag information"},
3810 {"list", CmdHFiClassList
, AlwaysAvailable
, "List iclass history"},
3811 {"rdbl", CmdHFiClass_ReadBlock
, IfPm3Iclass
, "Read Picopass / iCLASS block"},
3812 {"reader", CmdHFiClassReader
, IfPm3Iclass
, "Act like an Picopass / iCLASS reader"},
3813 {"restore", CmdHFiClassRestore
, IfPm3Iclass
, "Restore a dump file onto a Picopass / iCLASS tag"},
3814 {"sniff", CmdHFiClassSniff
, IfPm3Iclass
, "Eavesdrop Picopass / iCLASS communication"},
3815 {"wrbl", CmdHFiClass_WriteBlock
, IfPm3Iclass
, "Write Picopass / iCLASS block"},
3817 {"-----------", CmdHelp
, AlwaysAvailable
, "--------------------- " _CYAN_("recovery") " ---------------------"},
3818 // {"autopwn", CmdHFiClassAutopwn, IfPm3Iclass, "Automatic key recovery tool for iCLASS"},
3819 {"chk", CmdHFiClassCheckKeys
, IfPm3Iclass
, "Check keys"},
3820 {"loclass", CmdHFiClass_loclass
, AlwaysAvailable
, "Use loclass to perform bruteforce reader attack"},
3821 {"lookup", CmdHFiClassLookUp
, AlwaysAvailable
, "Uses authentication trace to check for key in dictionary file"},
3822 {"-----------", CmdHelp
, AlwaysAvailable
, "--------------------- " _CYAN_("simulation") " ---------------------"},
3823 {"sim", CmdHFiClassSim
, IfPm3Iclass
, "Simulate iCLASS tag"},
3824 {"eload", CmdHFiClassELoad
, IfPm3Iclass
, "Load Picopass / iCLASS dump file into emulator memory"},
3825 {"esave", CmdHFiClassESave
, IfPm3Iclass
, "Save emulator memory to file"},
3826 {"eview", CmdHFiClassEView
, IfPm3Iclass
, "View emulator memory"},
3828 {"-----------", CmdHelp
, AlwaysAvailable
, "--------------------- " _CYAN_("utils") " ---------------------"},
3829 {"configcard", CmdHFiClassConfigCard
, AlwaysAvailable
, "Reader configuration card"},
3830 {"calcnewkey", CmdHFiClassCalcNewKey
, AlwaysAvailable
, "Calc diversified keys (blocks 3 & 4) to write new keys"},
3831 {"encode", CmdHFiClassEncode
, AlwaysAvailable
, "Encode binary wiegand to block 7"},
3832 {"encrypt", CmdHFiClassEncryptBlk
, AlwaysAvailable
, "Encrypt given block data"},
3833 {"decrypt", CmdHFiClassDecrypt
, AlwaysAvailable
, "Decrypt given block data or tag dump file" },
3834 {"managekeys", CmdHFiClassManageKeys
, AlwaysAvailable
, "Manage keys to use with iclass commands"},
3835 {"permutekey", CmdHFiClassPermuteKey
, IfPm3Iclass
, "Permute function from 'heart of darkness' paper"},
3836 {"view", CmdHFiClassView
, AlwaysAvailable
, "Display content from tag dump file"},
3837 {NULL
, NULL
, NULL
, NULL
}
3840 static int CmdHelp(const char *Cmd
) {
3841 (void)Cmd
; // Cmd is not used so far
3842 CmdsHelp(CommandTable
);
3846 int CmdHFiClass(const char *Cmd
) {
3847 clearCommandBuffer();
3848 return CmdsParse(CommandTable
, Cmd
);
3851 //static void test_credential_type(void) {
3853 // Block 5 -> tells if its a legacy or SIO, also tells which key to use.
3855 // tech | blocks used | desc | num of payloads
3856 // -------+-----------------------+-----------------------------------+------
3857 // legacy | 6,7,8,9 | AA!, Access control payload | 1
3858 // SE | 6,7,8,9,10,11,12 | AA1, Secure identity object (SIO) | 1
3859 // SR | 6,7,8,9, | AA1, Access control payload | 2
3860 // | 10,11,12,13,14,15,16 | AA1, Secure identity object (SIO) |
3864 int info_iclass(void) {
3866 uint32_t flags
= (FLAG_ICLASS_READER_INIT
| FLAG_ICLASS_READER_CLEARTRACE
);
3868 clearCommandBuffer();
3869 SendCommandMIX(CMD_HF_ICLASS_READER
, flags
, 0, 0, NULL
, 0);
3870 PacketResponseNG resp
;
3872 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2000)) {
3874 uint8_t readStatus
= resp
.oldarg
[0] & 0xff;
3876 // no tag found or button pressed
3877 if (readStatus
== 0 || readStatus
== 0xFF) {
3879 return PM3_EOPABORTED
;
3882 picopass_hdr_t
*hdr
= (picopass_hdr_t
*)resp
.data
.asBytes
;
3883 picopass_ns_hdr_t
*ns_hdr
= (picopass_ns_hdr_t
*)resp
.data
.asBytes
;
3885 PrintAndLogEx(NORMAL
, "");
3886 PrintAndLogEx(INFO
, "--------------------- " _CYAN_("Tag Information") " ----------------------");
3888 if (readStatus
& FLAG_ICLASS_CSN
) {
3889 PrintAndLogEx(SUCCESS
, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr
->csn
, sizeof(hdr
->csn
)));
3892 if (readStatus
& FLAG_ICLASS_CONF
) {
3893 PrintAndLogEx(SUCCESS
, " Config: %s card configuration", sprint_hex((uint8_t *)&hdr
->conf
, sizeof(hdr
->conf
)));
3896 // page mapping. If fuse0|1 == 0x01, card is in non-secure mode, with CSN, CONF, AIA as top 3 blocks.
3897 // page9 in http://www.proxmark.org/files/Documents/13.56%20MHz%20-%20iClass/DS%20Picopass%202KS%20V1-0.pdf
3898 uint8_t pagemap
= get_pagemap(hdr
);
3899 if (pagemap
== PICOPASS_NON_SECURE_PAGEMODE
) {
3900 PrintAndLogEx(SUCCESS
, " AIA: %s application issuer area", sprint_hex(ns_hdr
->app_issuer_area
, sizeof(ns_hdr
->app_issuer_area
)));
3903 if (readStatus
& FLAG_ICLASS_CC
) {
3904 PrintAndLogEx(SUCCESS
, "E-purse: %s Card challenge, CC", sprint_hex(hdr
->epurse
, sizeof(hdr
->epurse
)));
3907 PrintAndLogEx(SUCCESS
, " Kd: %s debit key, hidden", sprint_hex(hdr
->key_d
, sizeof(hdr
->key_d
)));
3908 PrintAndLogEx(SUCCESS
, " Kc: %s credit key, hidden", sprint_hex(hdr
->key_c
, sizeof(hdr
->key_c
)));
3910 if (readStatus
& FLAG_ICLASS_AIA
) {
3911 PrintAndLogEx(SUCCESS
, " AIA: %s application issuer area", sprint_hex(hdr
->app_issuer_area
, sizeof(hdr
->app_issuer_area
)));
3915 if (readStatus
& FLAG_ICLASS_CONF
) {
3916 print_picopass_info(hdr
);
3919 PrintAndLogEx(INFO
, "------------------------ " _CYAN_("Fingerprint") " -----------------------");
3922 if (pagemap
== PICOPASS_NON_SECURE_PAGEMODE
) {
3923 memcpy(aia
, ns_hdr
->app_issuer_area
, sizeof(aia
));
3925 memcpy(aia
, hdr
->app_issuer_area
, sizeof(aia
));
3928 // if CSN ends with FF12E0, it's inside HID CSN range.
3929 bool isHidRange
= (memcmp(hdr
->csn
+ 5, "\xFF\x12\xE0", 3) == 0);
3931 bool legacy
= (memcmp(aia
, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0);
3932 bool se_enabled
= (memcmp(aia
, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);
3935 PrintAndLogEx(SUCCESS
, " CSN.......... " _YELLOW_("HID range"));
3937 PrintAndLogEx(SUCCESS
, " Credential... " _GREEN_("iCLASS legacy"));
3939 PrintAndLogEx(SUCCESS
, " Credential... " _GREEN_("iCLASS SE"));
3941 PrintAndLogEx(SUCCESS
, " CSN.......... " _YELLOW_("outside HID range"));
3944 uint8_t cardtype
= get_mem_config(hdr
);
3945 PrintAndLogEx(SUCCESS
, " Card type.... " _GREEN_("%s"), card_types
[cardtype
]);