fix little endian vs big endian in the macros... again... but this time correct
[RRG-proxmark3.git] / client / src / cmdhficlass.c
blob08c4e9360a1e4f17d2d0aab2cf10da64aec6ccab
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
7 //
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
10 // the license.
11 //-----------------------------------------------------------------------------
12 // High frequency iClass commands
13 //-----------------------------------------------------------------------------
15 #include "cmdhficlass.h"
16 #include <ctype.h>
17 #include "cliparser.h"
18 #include "cmdparser.h" // command_t
19 #include "commonutil.h" // ARRAYLEN
20 #include "cmdtrace.h"
21 #include "util_posix.h"
22 #include "comms.h"
23 #include "des.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
35 #define NUM_CSNS 9
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);
69 if (mx < my)
70 return -1;
71 else
72 return mx > my;
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) {
79 return false;
82 uint8_t ccnr[12];
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);
92 // binsearch
93 iclass_prekey_t *item = (iclass_prekey_t *) bsearch(&lookup, prekey, ICLASS_KEYS_MAX, sizeof(iclass_prekey_t), cmp_uint32);
94 if (item != NULL) {
95 memcpy(key, item->key, 8);
96 return true;
98 return false;
101 typedef enum {
102 None = 0,
103 DES,
104 RFU,
105 TRIPLEDES
106 } BLOCK79ENCRYPTION;
108 static inline uint32_t leadingzeros(uint64_t a) {
109 #if defined __GNUC__
110 return __builtin_clzll(a);
111 #else
112 return 0;
113 #endif
116 static void iclass_upload_emul(uint8_t *d, uint16_t n, uint16_t *bytes_sent) {
118 struct p {
119 uint16_t offset;
120 uint16_t len;
121 uint8_t data[];
122 } PACKED;
124 // fast push mode
125 conn.block_after_ACK = true;
127 //Send to device
128 *bytes_sent = 0;
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);
145 free(payload);
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[] = {
164 0xff,
165 0xff,
166 0xff,
167 0xff,
168 0x1f,
169 0xff,
170 0xff,
171 0xff,
174 iclass_config_card_item_t iclass_config_types[14] = {
175 {"", ""},
176 {"", ""},
177 {"", ""},
178 {"", ""},
179 {"", ""},
180 {"", ""},
181 {"", ""},
182 {"", ""},
183 {"", ""},
184 {"", ""},
185 {"", ""},
186 {"", ""},
187 {"", ""},
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");
196 return false;
198 return true;
201 static int load_config_cards(void) {
202 PrintAndLogEx(INFO, "detecting cardhelper...");
203 if (IsCardHelperPresent(false) == false) {
204 PrintAndLogEx(FAILED, "failed to detect cardhelper");
205 return PM3_ENODATA;
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");
225 return PM3_SUCCESS;
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) {
254 return PM3_EINVARG;
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...");
262 return res;
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;
270 // normal size
271 uint8_t *data = calloc(1, tot_bytes);
272 if (data == NULL) {
273 PrintAndLogEx(FAILED, "failed to allocate memory");
274 return PM3_EMALLOC;
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!");
289 free(data);
290 return PM3_EINVARG;
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..");
297 app1_limit = 0x16;
298 iclass_last_known_card.conf.app_limit = 0x16;
299 tot_bytes = (app1_limit + 1) * 8;
301 uint8_t *p = realloc(data, tot_bytes);
302 if (p == NULL) {
303 PrintAndLogEx(FAILED, "failed to allocate memory");
304 free(data);
305 return PM3_EMALLOC;
307 data = p;
308 memset(data, 0xFF, tot_bytes);
311 // need to encrypt
312 PrintAndLogEx(INFO, "Detecting cardhelper...");
313 if (IsCardHelperPresent(false) == false) {
314 PrintAndLogEx(FAILED, "failed to detect cardhelper");
315 free(data);
316 return PM3_ENODATA;
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");
324 uint8_t enckey1[8];
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));
334 // encrypted 0xFF
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);
342 uint8_t enckey2[8];
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));
350 foo[0] = key[7];
351 if (Encrypt(foo, enckey2) == false) {
352 PrintAndLogEx(WARNING, "failed to encrypt partial 2");
354 memcpy(data + (0x15 * 8), enckey2, sizeof(enckey2));
356 // encrypted 0xFF
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;
365 } else {
366 memcpy(data, &iclass_last_known_card, sizeof(picopass_hdr_t));
367 memcpy(data + (6 * 8), o->data, sizeof(o->data));
370 //Send to device
371 uint16_t bytes_sent = 0;
372 iclass_upload_emul(data, tot_bytes, &bytes_sent);
373 free(data);
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");
378 return PM3_SUCCESS;
381 static uint8_t isset(uint8_t val, uint8_t mask) {
382 return (val & 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)"));
411 else
412 PrintAndLogEx(SUCCESS, " mode......... " _YELLOW_("Application (locked)"));
414 if (isset(fuses, FUSE_CODING1)) {
415 PrintAndLogEx(SUCCESS, " coding...... RFU");
416 } else {
417 if (isset(fuses, FUSE_CODING0))
418 PrintAndLogEx(SUCCESS, " coding....... " _YELLOW_("ISO 14443-2 B / 15693"));
419 else
420 PrintAndLogEx(SUCCESS, " coding....... " _YELLOW_("ISO 14443-B only"));
423 uint8_t pagemap = get_pagemap(hdr);
424 switch (pagemap) {
425 case 0x0:
426 PrintAndLogEx(INFO, " crypt........ No auth possible. Read only if RA is enabled");
427 break;
428 case 0x1:
429 PrintAndLogEx(SUCCESS, " crypt........ Non secured page");
430 break;
431 case 0x2:
432 PrintAndLogEx(INFO, " crypt........ Secured page, keys locked");
433 break;
434 case 0x03:
435 PrintAndLogEx(SUCCESS, " crypt........ Secured page, " _GREEN_("keys not locked"));
436 break;
439 if (isset(fuses, FUSE_RA))
440 PrintAndLogEx(SUCCESS, " RA........... Read access enabled (non-secure mode)");
441 else
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
448 // mem-bit 7 = 16K
449 // mem-bit 5 = Book
450 // mem-bit 4 = 2K
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) {
458 *kb = 2;
459 *app_areas = 2;
460 } else if (isset(chip_cfg, 0x10) && k16 && !book) {
461 *kb = 16;
462 *app_areas = 2;
463 } else if (notset(chip_cfg, 0x10) && !k16 && !book) {
464 *kb = 16;
465 *app_areas = 16;
466 } else if (isset(chip_cfg, 0x10) && k16 && book) {
467 *kb = 32;
468 *app_areas = 3;
469 } else if (notset(chip_cfg, 0x10) && !k16 && book) {
470 *kb = 32;
471 *app_areas = 17;
472 } else {
473 *kb = 32;
474 *app_areas = 2;
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;
481 // 16K bit 0 == 1==
482 type |= (hdr->conf.mem_config & 0x80) >> 6;
483 // BOOK bit 0 == 1==
484 type |= (hdr->conf.mem_config & 0x20) >> 5;
485 // 2K
486 //type |= (hdr->conf.mem_config & 0x10) >> 5;
487 return type;
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;
493 uint8_t kb = 2;
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");
508 return;
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);
518 if (book) {
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");
525 } else {
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") " --------------------");
537 fuse_config(hdr);
538 mem_app_config(hdr);
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",
560 "hf iclass sniff\n"
561 "hf iclass sniff -j --> jam e-purse updates\n"
564 void *argtable[] = {
565 arg_param_begin,
566 arg_lit0("j", "jam", "Jam (prevent) e-purse updates"),
567 arg_param_end
570 CLIExecWithReturn(ctx, Cmd, argtable, true);
571 bool jam_epurse_update = arg_get_lit(ctx, 1);
572 CLIParserFree(ctx);
574 const uint8_t update_epurse_sequence[2] = {0x87, 0x02};
576 struct {
577 uint8_t jam_search_len;
578 uint8_t jam_search_string[2];
579 } PACKED payload;
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");
594 return PM3_SUCCESS;
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");
607 void *argtable[] = {
608 arg_param_begin,
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"),
611 arg_param_end
613 CLIExecWithReturn(ctx, Cmd, argtable, false);
615 int sim_type = arg_get_int(ctx, 1);
617 int csn_len = 0;
618 uint8_t csn[8] = {0};
619 CLIGetHexWithReturn(ctx, 2, csn, &csn_len);
621 if (sim_type == 0 && csn_len > 0) {
622 if (csn_len != 8) {
623 PrintAndLogEx(ERR, "CSN is incorrect length");
624 CLIParserFree(ctx);
625 return PM3_EINVARG;
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)");
630 CLIParserFree(ctx);
631 return PM3_EINVARG;
634 CLIParserFree(ctx);
636 if (sim_type > 4) {
637 PrintAndLogEx(ERR, "Undefined simtype %d", sim_type);
638 return PM3_EINVARG;
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
657 /* DUMPFILE FORMAT:
659 * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
660 * So, it should wind up as
661 * 8 * 24 bytes.
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
667 uint8_t tries = 0;
669 switch (sim_type) {
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) {
679 tries++;
680 if (kbd_enter_pressed()) {
681 PrintAndLogEx(WARNING, "\naborted via keyboard.");
682 return PM3_EOPABORTED;
684 if (tries > 20) {
685 PrintAndLogEx(WARNING, "\ntimeout while waiting for reply.");
686 return PM3_ETIMEOUT;
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");
693 if (num_mac == 0)
694 break;
696 size_t datalen = NUM_CSNS * 24;
697 uint8_t *dump = calloc(datalen, sizeof(uint8_t));
698 if (!dump) {
699 PrintAndLogEx(WARNING, "Failed to allocate memory");
700 return PM3_EMALLOC;
703 memset(dump, 0, datalen);//<-- Need zeroes for the EPURSE - field (official)
705 uint8_t i = 0;
706 for (i = 0 ; i < NUM_CSNS ; i++) {
707 //copy CSN
708 memcpy(dump + i * 24, csns + i * 8, 8);
709 //copy epurse
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);
716 free(dump);
718 PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass -f iclass_mac_attack.bin") "` to recover elite key");
719 break;
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) {
730 tries++;
731 if (kbd_enter_pressed()) {
732 PrintAndLogEx(WARNING, "\naborted via keyboard.");
733 return PM3_EOPABORTED;
735 if (tries > 20) {
736 PrintAndLogEx(WARNING, "\ntimeout while waiting for reply.");
737 return PM3_ETIMEOUT;
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");
744 if (num_mac == 0)
745 break;
747 size_t datalen = NUM_CSNS * 24;
748 uint8_t *dump = calloc(datalen, sizeof(uint8_t));
749 if (!dump) {
750 PrintAndLogEx(WARNING, "Failed to allocate memory");
751 return PM3_EMALLOC;
754 #define MAC_ITEM_SIZE 24
756 //KEYROLL 1
757 //Need zeroes for the CC-field
758 memset(dump, 0, datalen);
759 for (uint8_t i = 0; i < NUM_CSNS ; i++) {
760 // copy CSN
761 memcpy(dump + i * MAC_ITEM_SIZE, csns + i * 8, 8); //CSN
762 // copy EPURSE
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);
769 //KEYROLL 2
770 memset(dump, 0, datalen);
771 for (uint8_t i = 0; i < NUM_CSNS; i++) {
772 uint8_t resp_index = (i + NUM_CSNS) * 16;
773 // Copy CSN
774 memcpy(dump + i * MAC_ITEM_SIZE, csns + i * 8, 8);
775 // copy EPURSE
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);
779 resp_index++;
781 saveFile("iclass_mac_attack_keyroll_B", ".bin", dump, datalen);
782 free(dump);
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");
786 break;
788 case ICLASS_SIM_MODE_CSN:
789 case ICLASS_SIM_MODE_CSN_DEFAULT:
790 case ICLASS_SIM_MODE_FULL:
791 default: {
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");
800 break;
803 return PM3_SUCCESS;
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.",
810 "hf iclass info");
812 void *argtable[] = {
813 arg_param_begin,
814 arg_param_end
816 CLIExecWithReturn(ctx, Cmd, argtable, true);
817 CLIParserFree(ctx);
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;
826 do {
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;
834 if (loop) {
835 if (status == 0xFF) {
836 continue;
838 } else {
840 if (status == 0 || status == 0xFF) {
841 if (verbose) PrintAndLogEx(WARNING, "iCLASS / ISO15693 card select failed");
842 res = PM3_EOPABORTED;
843 break;
847 picopass_hdr_t *card = calloc(1, sizeof(picopass_hdr_t));
848 if (card) {
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);
853 free(card);
854 } else {
855 PrintAndLogEx(FAILED, "failed to allocate memory");
858 } while (loop && kbd_enter_pressed() == false);
860 DropField();
861 return res;
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"
872 void *argtable[] = {
873 arg_param_begin,
874 arg_lit0("@", NULL, "optional - continuous reader mode"),
875 arg_param_end
877 CLIExecWithReturn(ctx, Cmd, argtable, true);
878 bool cm = arg_get_lit(ctx, 1);
879 CLIParserFree(ctx);
881 if (cm) {
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"
896 void *argtable[] = {
897 arg_param_begin,
898 arg_str1("f", "file", "<fn>", "filename of dump (bin/eml/json)"),
899 arg_param_end
901 CLIExecWithReturn(ctx, Cmd, argtable, false);
903 int fnlen = 0;
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");
909 CLIParserFree(ctx);
910 return PM3_EINVARG;
913 CLIParserFree(ctx);
915 size_t bytes_read = 2048;
916 uint8_t *dump = NULL;
917 int res = 0;
918 DumpFileType_t dftype = getfiletype(filename);
919 switch (dftype) {
920 case BIN: {
921 res = loadFile_safe(filename, ".bin", (void **)&dump, &bytes_read);
922 break;
924 case EML: {
925 res = loadFileEML_safe(filename, (void **)&dump, &bytes_read);
926 break;
928 case JSON: {
929 dump = calloc(2048, sizeof(uint8_t));
930 if (dump == NULL) {
931 PrintAndLogEx(ERR, "error, cannot allocate memory ");
932 return PM3_EMALLOC;
934 res = loadFileJSON(filename, (void *)dump, 2048, &bytes_read, NULL);
935 break;
937 case DICTIONARY: {
938 free(dump);
939 PrintAndLogEx(ERR, "Error: Only BIN/JSON/EML formats allowed");
940 return PM3_EINVARG;
944 if (res != PM3_SUCCESS) {
945 free(dump);
946 return PM3_EFILE;
949 uint8_t *newdump = realloc(dump, bytes_read);
950 if (newdump == NULL) {
951 free(dump);
952 return PM3_EMALLOC;
953 } else {
954 dump = newdump;
957 print_picopass_header((picopass_hdr_t *) dump);
958 print_picopass_info((picopass_hdr_t *) dump);
960 //Send to device
961 uint16_t bytes_sent = 0;
962 iclass_upload_emul(dump, bytes_read, &bytes_sent);
963 free(dump);
964 PrintAndLogEx(SUCCESS, "sent %u bytes of data to device emulator memory", bytes_sent);
965 return PM3_SUCCESS;
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.",
973 "hf iclass esave\n"
974 "hf iclass esave -f hf-iclass-dump\n"
975 "hf iclass esave -s 2048 -f hf-iclass-dump");
977 void *argtable[] = {
978 arg_param_begin,
979 arg_str0("f", "file", "<fn>", "filename of dump file"),
980 arg_int0("s", "size", "<256|2048>", "number of bytes to save (default 256)"),
981 arg_param_end
983 CLIExecWithReturn(ctx, Cmd, argtable, true);
985 int fnlen = 0;
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);
990 if (bytes > 4096) {
991 PrintAndLogEx(WARNING, "Emulator memory is max 4096bytes. Truncating %u to 4096", bytes);
992 bytes = 4096;
995 CLIParserFree(ctx);
997 uint8_t *dump = calloc(bytes, sizeof(uint8_t));
998 if (dump == NULL) {
999 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
1000 return PM3_EMALLOC;
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");
1006 free(dump);
1007 return PM3_ETIMEOUT;
1010 // user supplied filename?
1011 if (fnlen < 1) {
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);
1020 free(dump);
1022 PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view -f") "` to view dump file");
1023 return PM3_SUCCESS;
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.",
1031 "hf iclass eview\n"
1032 "hf iclass eview -s 2048\n"
1033 "hf iclass eview -s 2048 -v");
1035 void *argtable[] = {
1036 arg_param_begin,
1037 arg_int0("s", "size", "<256|2048>", "number of bytes to save (default 256)"),
1038 arg_lit0("v", "verbose", "verbose output"),
1039 arg_param_end
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);
1046 blocks = bytes / 8;
1048 CLIParserFree(ctx);
1050 if (bytes > 4096) {
1051 PrintAndLogEx(WARNING, "Emulator memory is max 4096bytes. Truncating %u to 4096", bytes);
1052 bytes = 4096;
1055 if (bytes % 8 != 0) {
1056 bytes &= 0xFFF8;
1057 PrintAndLogEx(WARNING, "Number not divided by 8, truncating to %u", bytes);
1060 uint8_t *dump = calloc(bytes, sizeof(uint8_t));
1061 if (dump == NULL) {
1062 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
1063 return PM3_EMALLOC;
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");
1070 free(dump);
1071 return PM3_ETIMEOUT;
1074 if (verbose) {
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);
1081 free(dump);
1082 return PM3_SUCCESS;
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"
1092 "\nOBS!\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"
1095 "or...\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[] = {
1102 arg_param_begin,
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"),
1108 arg_param_end
1110 CLIExecWithReturn(clictx, Cmd, argtable, false);
1112 int fnlen = 0;
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);
1122 int key_len = 0;
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);
1133 // sanity checks
1134 if (enc_data_len > 0) {
1135 if (enc_data_len != 8) {
1136 PrintAndLogEx(ERR, "Data must be 8 hex bytes (16 HEX symbols)");
1137 return PM3_EINVARG;
1139 have_data = true;
1142 if (key_len > 0) {
1143 if (key_len != 16) {
1144 PrintAndLogEx(ERR, "Transport key must be 16 hex bytes (32 HEX characters)");
1145 return PM3_EINVARG;
1147 have_key = true;
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
1156 if (fnlen > 0) {
1158 DumpFileType_t dftype = getfiletype(filename);
1159 switch (dftype) {
1160 case BIN: {
1161 res = loadFile_safe(filename, ".bin", (void **)&decrypted, &decryptedlen);
1162 break;
1164 case EML: {
1165 res = loadFileEML_safe(filename, (void **)&decrypted, &decryptedlen);
1166 break;
1168 case JSON: {
1169 decrypted = calloc(2048, sizeof(uint8_t));
1170 if (decrypted == NULL) {
1171 PrintAndLogEx(ERR, "error, cannot allocate memory ");
1172 return PM3_EMALLOC;
1174 res = loadFileJSON(filename, (void *)decrypted, 2048, &decryptedlen, NULL);
1175 break;
1177 case DICTIONARY: {
1178 free(decrypted);
1179 PrintAndLogEx(ERR, "Error: Only BIN/JSON/EML formats allowed");
1180 return PM3_EINVARG;
1184 if (res != PM3_SUCCESS) {
1185 free(decrypted);
1186 return PM3_EFILE;
1189 have_file = true;
1192 // load transport key
1193 bool use_sc = false;
1194 if (have_key == false) {
1195 use_sc = IsCardHelperPresent(verbose);
1196 if (use_sc == false) {
1197 size_t keylen = 0;
1198 res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen);
1199 if (res != PM3_SUCCESS) {
1200 PrintAndLogEx(INFO, "Couldn't find any decryption methods");
1201 free(decrypted);
1202 return PM3_EINVARG;
1205 if (keylen != 16) {
1206 PrintAndLogEx(ERR, "Failed to load transport key from file");
1207 free(keyptr);
1208 free(decrypted);
1209 return PM3_EINVARG;
1211 memcpy(key, keyptr, sizeof(key));
1212 free(keyptr);
1216 // tripledes
1217 mbedtls_des3_context ctx;
1218 mbedtls_des3_set2key_dec(&ctx, key);
1220 // decrypt user supplied data
1221 if (have_data) {
1223 uint8_t dec_data[8] = {0};
1224 if (use_sc) {
1225 Decrypt(enc_data, dec_data);
1226 } else {
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
1236 if (have_file) {
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;
1243 uint8_t kb = 2;
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)
1264 continue;
1266 // Decrypted block 7,8,9 if configured.
1267 if (blocknum > 6 && blocknum <= 9 && memcmp(enc_data, empty, 8) != 0) {
1268 if (use_sc) {
1269 Decrypt(enc_data, decrypted + idx);
1270 } else {
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");
1280 free(decrypted);
1281 return PM3_EMALLOC;
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, "");
1295 // decode block 6
1296 bool has_values = (memcmp(decrypted + (8 * 6), empty, 8) != 0) && (memcmp(decrypted + (8 * 6), zeros, 8) != 0);
1297 if (has_values) {
1298 if (use_sc) {
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);
1305 if (has_values) {
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);
1319 uint8_t i = 0;
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);
1328 } else {
1329 PrintAndLogEx(INFO, "No credential found");
1332 // decode block 9
1333 has_values = (memcmp(decrypted + (8 * 9), empty, 8) != 0) && (memcmp(decrypted + (8 * 9), zeros, 8) != 0);
1334 if (has_values) {
1336 uint8_t usr_blk_len = GetNumberBlocksForUserId(decrypted + (8 * 6));
1337 if (usr_blk_len < 3) {
1338 if (use_sc) {
1340 PrintAndLogEx(NORMAL, "");
1341 PrintAndLogEx(INFO, "Block 9 decoder");
1343 uint8_t pinsize = GetPinSize(decrypted + (8 * 6));
1344 if (pinsize > 0) {
1346 uint64_t pin = bytes_to_num(decrypted + (8 * 9), 5);
1347 char tmp[17] = {0};
1348 snprintf(tmp, sizeof(tmp), "%."PRIu64, BCD2DEC(pin));
1349 PrintAndLogEx(INFO, "PIN........................ " _GREEN_("%.*s"), pinsize, tmp);
1355 PrintAndLogEx(INFO, "-----------------------------------------------------------------");
1356 free(decrypted);
1357 free(fptr);
1360 mbedtls_des3_free(&ctx);
1361 return PM3_SUCCESS;
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[] = {
1384 arg_param_begin,
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"),
1388 arg_param_end
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);
1400 return PM3_EINVARG;
1403 int key_len = 0;
1404 uint8_t key[16] = {0};
1405 uint8_t *keyptr = NULL;
1406 bool have_key = false;
1408 CLIGetHexWithReturn(clictx, 2, key, &key_len);
1410 if (key_len > 0) {
1411 if (key_len != 16) {
1412 PrintAndLogEx(ERR, "Transport key must be 16 hex bytes (32 HEX characters)");
1413 CLIParserFree(clictx);
1414 return PM3_EINVARG;
1416 have_key = true;
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) {
1427 size_t keylen = 0;
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");
1431 return PM3_EINVARG;
1434 if (keylen != 16) {
1435 PrintAndLogEx(ERR, "Failed to load transport key from file");
1436 free(keyptr);
1437 return PM3_EINVARG;
1439 memcpy(key, keyptr, sizeof(key));
1440 free(keyptr);
1444 if (use_sc) {
1445 Encrypt(blk_data, blk_data);
1446 } else {
1447 iclass_encrypt_block_data(blk_data, key);
1449 PrintAndLogEx(SUCCESS, "encrypted block %s", sprint_hex(blk_data, 8));
1450 return PM3_SUCCESS;
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");
1462 return false;
1465 uint8_t isok = resp.oldarg[0] & 0xff;
1467 // no tag found or button pressed
1468 if ((isok == 0) || isok == 0xFF) {
1469 if (verbose) {
1470 PrintAndLogEx(FAILED, "failed tag-select, aborting... (%d)", isok);
1472 return false;
1475 picopass_hdr_t *hdr = (picopass_hdr_t *)resp.data.asBytes;
1477 if (CSN != NULL)
1478 memcpy(CSN, hdr->csn, 8);
1480 if (CCNR != NULL)
1481 memcpy(CCNR, hdr->epurse, 8);
1483 if (verbose) {
1484 PrintAndLogEx(SUCCESS, "CSN %s", sprint_hex(CSN, 8));
1485 PrintAndLogEx(SUCCESS, "epurse %s", sprint_hex(CCNR, 8));
1487 return true;
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[] = {
1501 arg_param_begin,
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"),
1510 arg_param_end
1512 CLIExecWithReturn(ctx, Cmd, argtable, true);
1514 int fnlen = 0;
1515 char filename[FILE_PATH_SIZE] = {0};
1516 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
1518 int key_len = 0;
1519 uint8_t key[8] = {0};
1520 bool auth = false;
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");
1528 CLIParserFree(ctx);
1529 return PM3_EINVARG;
1532 if (key_len > 0) {
1533 auth = true;
1534 if (key_len != 8) {
1535 PrintAndLogEx(ERR, "Debit key is incorrect length");
1536 CLIParserFree(ctx);
1537 return PM3_EINVARG;
1541 if (deb_key_nr >= 0) {
1542 if (deb_key_nr < ICLASS_KEYS_MAX) {
1543 auth = true;
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));
1546 } else {
1547 PrintAndLogEx(ERR, "Key number is invalid");
1548 CLIParserFree(ctx);
1549 return PM3_EINVARG;
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");
1563 CLIParserFree(ctx);
1564 return PM3_EINVARG;
1567 if (credit_key_len > 0) {
1568 auth = true;
1569 have_credit_key = true;
1570 if (credit_key_len != 8) {
1571 PrintAndLogEx(ERR, "Credit key is incorrect length");
1572 CLIParserFree(ctx);
1573 return PM3_EINVARG;
1577 if (credit_key_nr >= 0) {
1578 if (credit_key_nr < ICLASS_KEYS_MAX) {
1579 auth = true;
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));
1583 } else {
1584 PrintAndLogEx(ERR, "Key number is invalid");
1585 CLIParserFree(ctx);
1586 return PM3_EINVARG;
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);
1594 CLIParserFree(ctx);
1596 if ((use_replay + rawkey + elite) > 1) {
1597 PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw', 'nr'");
1598 return PM3_EINVARG;
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");
1614 DropField();
1615 return PM3_ESOFT;
1617 DropField();
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");
1624 DropField();
1625 return PM3_ESOFT;
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];
1642 app_limit2 = 0;
1643 } else {
1644 app_limit1 = hdr->conf.app_limit;
1645 app_limit2 = card_app2_limit[type];
1648 } else {
1649 PrintAndLogEx(FAILED, "failed to read block 0,1,2");
1650 DropField();
1651 return PM3_ESOFT;
1654 if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
1655 PrintAndLogEx(INFO, "Dumping all available memory, block 3 - %u (0x%02x)", app_limit1, app_limit1);
1656 if (auth) {
1657 PrintAndLogEx(INFO, "No keys needed, ignoring user supplied key");
1659 } else {
1660 if (auth == false) {
1661 PrintAndLogEx(FAILED, "Run command with keys");
1662 return PM3_ESOFT;
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;
1682 } else {
1683 payload.start_block = 6;
1686 clearCommandBuffer();
1687 SendCommandNG(CMD_HF_ICLASS_DUMP, (uint8_t *)&payload, sizeof(payload));
1689 while (true) {
1691 PrintAndLogEx(NORMAL, "." NOLF);
1692 if (kbd_enter_pressed()) {
1693 PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
1694 DropField();
1695 return PM3_EOPABORTED;
1698 if (WaitForResponseTimeout(CMD_HF_ICLASS_DUMP, &resp, 2000))
1699 break;
1702 PrintAndLogEx(NORMAL, "");
1703 if (resp.status != PM3_SUCCESS) {
1704 PrintAndLogEx(ERR, "failed to communicate with card");
1705 return resp.status;
1708 struct p_resp {
1709 bool isOK;
1710 uint16_t block_cnt;
1711 uint32_t bb_offset;
1712 } PACKED;
1713 struct p_resp *packet = (struct p_resp *)resp.data.asBytes;
1715 if (packet->isOK == false) {
1716 PrintAndLogEx(WARNING, "read AA1 blocks failed");
1717 return PM3_ESOFT;
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));
1734 } else {
1735 // div key KD
1736 memcpy(tag_data + (8 * 3), tempbuf + (8 * 3), 8);
1737 // AIA data
1738 memcpy(tag_data + (8 * 5), tempbuf + (8 * 5), 8);
1739 // AA1 data
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));
1761 while (true) {
1762 PrintAndLogEx(NORMAL, "." NOLF);
1763 if (kbd_enter_pressed()) {
1764 PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
1765 DropField();
1766 return PM3_EOPABORTED;
1769 if (WaitForResponseTimeout(CMD_HF_ICLASS_DUMP, &resp, 2000))
1770 break;
1772 PrintAndLogEx(NORMAL, "");
1773 if (resp.status != PM3_SUCCESS) {
1774 PrintAndLogEx(ERR, "failed to communicate with card");
1775 goto write_dump;
1778 packet = (struct p_resp *)resp.data.asBytes;
1779 if (packet->isOK == false) {
1780 PrintAndLogEx(WARNING, "failed read block using credit key");
1781 goto write_dump;
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");
1795 goto write_dump;
1798 // div key KC
1799 memcpy(tag_data + (8 * 4), tempbuf + (8 * 4), 8);
1801 // AA2 data
1802 memcpy(tag_data + (8 * (app_limit1 + 1)), tempbuf + (8 * (app_limit1 + 1)), (blocks_read * 8));
1804 bytes_got = (blocks_read * 8);
1806 aa2_success = true;
1809 write_dump:
1811 if (have_credit_key && pagemap != 0x01 && aa2_success == false)
1812 PrintAndLogEx(INFO, "Reading AA2 failed. dumping AA1 data to file");
1814 // print the dump
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, "");
1832 return PM3_SUCCESS;
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");
1860 return resp.status;
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[] = {
1874 arg_param_begin,
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"),
1884 arg_param_end
1886 CLIExecWithReturn(ctx, Cmd, argtable, false);
1888 int key_len = 0;
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");
1897 CLIParserFree(ctx);
1898 return PM3_EINVARG;
1901 bool auth = false;
1903 if (key_len > 0) {
1904 auth = true;
1905 if (key_len != 8) {
1906 PrintAndLogEx(ERR, "Key is incorrect length");
1907 CLIParserFree(ctx);
1908 return PM3_EINVARG;
1910 } else if (key_nr >= 0) {
1911 if (key_nr < ICLASS_KEYS_MAX) {
1912 auth = true;
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));
1915 } else {
1916 PrintAndLogEx(ERR, "Key number is invalid");
1917 CLIParserFree(ctx);
1918 return PM3_EINVARG;
1922 int blockno = arg_get_int_def(ctx, 3, 0);
1924 int data_len = 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)");
1930 CLIParserFree(ctx);
1931 return PM3_EINVARG;
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);
1940 CLIParserFree(ctx);
1942 if ((use_replay + rawkey + elite) > 1) {
1943 PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw', 'nr'");
1944 return PM3_EINVARG;
1947 int isok = iclass_write_block(blockno, data, key, use_credit_key, elite, rawkey, use_replay, verbose, auth);
1948 switch (isok) {
1949 case PM3_SUCCESS:
1950 PrintAndLogEx(SUCCESS, "Wrote block %3d/0x%02X successful", blockno, blockno);
1951 break;
1952 case PM3_ETEAROFF:
1953 if (verbose)
1954 PrintAndLogEx(INFO, "Writing tear off triggered");
1955 break;
1956 default:
1957 PrintAndLogEx(FAILED, "Writing failed");
1958 break;
1960 return isok;
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[] = {
1973 arg_param_begin,
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"),
1983 arg_param_end
1985 CLIExecWithReturn(ctx, Cmd, argtable, false);
1987 int fnlen = 0;
1988 char filename[FILE_PATH_SIZE] = {0};
1989 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
1991 int key_len = 0;
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");
2000 CLIParserFree(ctx);
2001 return PM3_EINVARG;
2004 if (key_len > 0) {
2005 if (key_len != 8) {
2006 PrintAndLogEx(ERR, "Key is incorrect length");
2007 CLIParserFree(ctx);
2008 return PM3_EINVARG;
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));
2014 } else {
2015 PrintAndLogEx(ERR, "Key number is invalid");
2016 CLIParserFree(ctx);
2017 return PM3_EINVARG;
2019 } else {
2020 PrintAndLogEx(ERR, "Please specify a key or key index");
2021 CLIParserFree(ctx);
2022 return PM3_EINVARG;
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);
2033 CLIParserFree(ctx);
2035 if (rawkey + elite > 1) {
2036 PrintAndLogEx(FAILED, "Can not use both 'e', 'r'");
2037 return PM3_EINVARG;
2040 if (startblock < 5) {
2041 PrintAndLogEx(WARNING, "you cannot write key blocks this way. yet... make your start block > 4");
2042 return PM3_EINVARG;
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);
2049 return PM3_EINVARG;
2052 size_t bytes_read = 2048;
2053 uint8_t *dump = NULL;
2054 int res = PM3_SUCCESS;
2055 DumpFileType_t dftype = getfiletype(filename);
2056 switch (dftype) {
2057 case BIN: {
2058 res = loadFile_safe(filename, ".bin", (void **)&dump, &bytes_read);
2059 break;
2061 case EML: {
2062 res = loadFileEML_safe(filename, (void **)&dump, &bytes_read);
2063 break;
2065 case JSON: {
2066 dump = calloc(2048, sizeof(uint8_t));
2067 if (dump == NULL) {
2068 PrintAndLogEx(ERR, "error, cannot allocate memory ");
2069 return PM3_EMALLOC;
2071 res = loadFileJSON(filename, (void *)dump, 2048, &bytes_read, NULL);
2072 break;
2074 case DICTIONARY: {
2075 free(dump);
2076 PrintAndLogEx(ERR, "Error: Only BIN/JSON/EML formats allowed");
2077 return PM3_EINVARG;
2081 if (res != PM3_SUCCESS) {
2082 free(dump);
2083 return PM3_EFILE;
2086 if (bytes_read == 0) {
2087 PrintAndLogEx(ERR, "file reading error");
2088 free(dump);
2089 return PM3_EFILE;
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
2096 free(dump);
2097 return PM3_EFILE;
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));
2122 free(dump);
2124 if (verbose) {
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");
2145 DropField();
2146 free(payload);
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");
2153 } else {
2154 PrintAndLogEx(WARNING, "iCLASS restore " _RED_("failed"));
2157 free(payload);
2158 return resp.status;
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 = {
2164 .use_raw = rawkey,
2165 .use_elite = elite,
2166 .use_credit_key = (keyType == 0x18),
2167 .use_replay = replay,
2168 .blockno = blockno,
2169 .send_reply = true,
2170 .do_auth = auth,
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;
2188 // return data.
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");
2193 return PM3_ESOFT;
2196 PrintAndLogEx(NORMAL, "");
2197 PrintAndLogEx(SUCCESS, " block %3d/0x%02X : " _GREEN_("%s"), blockno, blockno, sprint_hex(packet->data, sizeof(packet->data)));
2198 PrintAndLogEx(NORMAL, "");
2200 if (out)
2201 memcpy(out, packet->data, sizeof(packet->data));
2203 return PM3_SUCCESS;
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[] = {
2215 arg_param_begin,
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"),
2224 arg_param_end
2226 CLIExecWithReturn(ctx, Cmd, argtable, false);
2228 int key_len = 0;
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");
2237 CLIParserFree(ctx);
2238 return PM3_EINVARG;
2241 bool auth = false;
2243 if (key_len > 0) {
2244 auth = true;
2245 if (key_len != 8) {
2246 PrintAndLogEx(ERR, "Key is incorrect length");
2247 CLIParserFree(ctx);
2248 return PM3_EINVARG;
2250 } else if (key_nr >= 0) {
2251 if (key_nr < ICLASS_KEYS_MAX) {
2252 auth = true;
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));
2255 } else {
2256 PrintAndLogEx(ERR, "Key number is invalid");
2257 CLIParserFree(ctx);
2258 return PM3_EINVARG;
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);
2275 CLIParserFree(ctx);
2277 if ((use_replay + rawkey + elite) > 1) {
2278 PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw', 'nr'");
2279 return PM3_EINVARG;
2282 if (verbose) {
2283 if (key_len > 0)
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)
2295 return res;
2297 if (blockno < 6 || blockno > 7)
2298 return PM3_SUCCESS;
2300 if (memcmp(data, empty, 8) == 0)
2301 return PM3_SUCCESS;
2303 bool use_sc = IsCardHelperPresent(verbose);
2304 if (use_sc == false)
2305 return PM3_SUCCESS;
2307 // crypto helper available.
2308 PrintAndLogEx(INFO, "----------------------------- " _CYAN_("cardhelper") " -----------------------------");
2310 switch (blockno) {
2311 case 6: {
2312 DecodeBlock6(data);
2313 break;
2315 case 7: {
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)));
2327 } else {
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);
2344 uint8_t i = 0;
2345 while (i < strlen(binstr) && binstr[i++] == '0');
2347 i &= 0x3C;
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);
2353 } else {
2354 PrintAndLogEx(INFO, "no credential found");
2356 break;
2359 PrintAndLogEx(INFO, "----------------------------------------------------------------------");
2360 return PM3_SUCCESS;
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[] = {
2378 arg_param_begin,
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"),
2382 arg_param_end
2384 CLIExecWithReturn(ctx, Cmd, argtable, false);
2386 int fnlen = 0;
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);
2393 CLIParserFree(ctx);
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!!!");
2404 return PM3_ESOFT;
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)
2427 maxmemcount = 255;
2428 else
2429 maxmemcount = 31;
2431 if (startblock == 0)
2432 startblock = 6;
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"
2443 , startblock
2444 , endblock
2445 , filesize
2446 , maxmemcount
2447 , filemaxblock
2450 uint8_t pagemap = get_pagemap(hdr);
2454 int i = startblock;
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));
2461 if (i != 1)
2462 PrintAndLogEx(INFO, "....");
2464 while (i <= endblock) {
2465 uint8_t *blk = iclass_dump + (i * 8);
2467 bool bl_lock = false;
2468 if (ro == false) {
2469 switch (i) {
2470 case 12: {
2471 bl_lock = ((lock & 0x40) == 0);
2472 break;
2474 case 11: {
2475 bl_lock = ((lock & 0x20) == 0);
2476 break;
2478 case 10: {
2479 bl_lock = ((lock & 0x10) == 0);
2480 break;
2482 case 9: {
2483 bl_lock = ((lock & 0x08) == 0);
2484 break;
2486 case 8: {
2487 bl_lock = ((lock & 0x04) == 0);
2488 break;
2490 case 7: {
2491 bl_lock = ((lock & 0x02) == 0);
2492 break;
2494 case 6: {
2495 bl_lock = ((lock & 0x01) == 0);
2496 break;
2499 } else {
2500 bl_lock = true;
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];
2508 if (i < 3) {
2509 s = info_nonks[i];
2512 PrintAndLogEx(INFO, "%3d/0x%02X | %s | %s | %s ", i, i, sprint_hex_ascii(blk, 8), lockstr, s);
2513 } else {
2514 const char *info_ks[] = {"CSN", "Config", "E-purse", "Debit", "Credit", "AIA", "User"};
2515 const char *s = info_ks[6];
2516 if (i < 6) {
2517 s = info_ks[i];
2519 PrintAndLogEx(INFO, "%3d/0x%02X | %s | %s | %s ", i, i, sprint_hex_ascii(blk, 8), lockstr, s);
2521 i++;
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[] = {
2535 arg_param_begin,
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"),
2540 arg_param_end
2542 CLIExecWithReturn(ctx, Cmd, argtable, false);
2544 int fnlen = 0;
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);
2552 CLIParserFree(ctx);
2554 size_t bytes_read = 2048;
2555 uint8_t *dump = NULL;
2556 int res = 0;
2557 DumpFileType_t dftype = getfiletype(filename);
2558 switch (dftype) {
2559 case BIN: {
2560 res = loadFile_safe(filename, ".bin", (void **)&dump, &bytes_read);
2561 break;
2563 case EML: {
2564 res = loadFileEML_safe(filename, (void **)&dump, &bytes_read);
2565 break;
2567 case JSON: {
2568 dump = calloc(2048, sizeof(uint8_t));
2569 if (dump == NULL) {
2570 PrintAndLogEx(ERR, "error, cannot allocate memory ");
2571 return PM3_EMALLOC;
2573 res = loadFileJSON(filename, (void *)dump, 2048, &bytes_read, NULL);
2574 break;
2576 case DICTIONARY: {
2577 free(dump);
2578 PrintAndLogEx(ERR, "Error: Only BIN/JSON/EML formats allowed");
2579 return PM3_EINVARG;
2583 if (res != PM3_SUCCESS) {
2584 free(dump);
2585 return PM3_EFILE;
2588 if (verbose) {
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);
2598 free(dump);
2599 return PM3_SUCCESS;
2602 void HFiClassCalcDivKey(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key, bool elite) {
2603 if (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);
2616 } else {
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};
2627 //get old div key
2628 HFiClassCalcDivKey(CSN, OLDKEY, old_div_key, oldElite);
2629 //get new div key
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];
2635 if (verbose) {
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[] = {
2651 arg_param_begin,
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"),
2659 arg_param_end
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");
2671 CLIParserFree(ctx);
2672 return PM3_EINVARG;
2675 if (old_key_len > 0) {
2676 if (old_key_len != 8) {
2677 PrintAndLogEx(ERR, "Old key is incorrect length");
2678 CLIParserFree(ctx);
2679 return PM3_EINVARG;
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));
2685 } else {
2686 PrintAndLogEx(ERR, "Key number is invalid");
2687 CLIParserFree(ctx);
2688 return PM3_EINVARG;
2690 } else {
2691 PrintAndLogEx(ERR, "Please specify an old key or old key index");
2692 CLIParserFree(ctx);
2693 return PM3_EINVARG;
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");
2704 CLIParserFree(ctx);
2705 return PM3_EINVARG;
2708 if (new_key_len > 0) {
2709 if (new_key_len != 8) {
2710 PrintAndLogEx(ERR, "New key is incorrect length");
2711 CLIParserFree(ctx);
2712 return PM3_EINVARG;
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));
2718 } else {
2719 PrintAndLogEx(ERR, "Key number is invalid");
2720 CLIParserFree(ctx);
2721 return PM3_EINVARG;
2723 } else {
2724 PrintAndLogEx(ERR, "Please specify an new key or old key index");
2725 CLIParserFree(ctx);
2726 return PM3_EINVARG;
2729 int csn_len = 0;
2730 uint8_t csn[8] = {0};
2731 CLIGetHexWithReturn(ctx, 5, csn, &csn_len);
2732 bool givenCSN = false;
2734 if (csn_len > 0) {
2735 givenCSN = true;
2736 if (csn_len != 8) {
2737 PrintAndLogEx(ERR, "CSN is incorrect length");
2738 CLIParserFree(ctx);
2739 return PM3_EINVARG;
2743 bool elite = arg_get_lit(ctx, 6);
2744 bool old_elite = false;
2746 if (arg_get_lit(ctx, 7)) {
2747 elite = true;
2748 old_elite = true;
2751 CLIParserFree(ctx);
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) {
2758 DropField();
2759 return PM3_ESOFT;
2763 HFiClassCalcNewKey(csn, old_key, new_key, xor_div_key, elite, old_elite, true);
2765 return PM3_SUCCESS;
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);
2774 return PM3_EFILE;
2777 if (bytes_read > ICLASS_KEYS_MAX * 8) {
2778 PrintAndLogEx(WARNING, "File is too long to load - bytes: %zu", bytes_read);
2779 free(dump);
2780 return PM3_EFILE;
2782 uint8_t i = 0;
2783 for (; i < bytes_read / 8; i++)
2784 memcpy(iClass_Key_Table[i], dump + (i * 8), 8);
2786 free(dump);
2787 PrintAndLogEx(SUCCESS, "Loaded " _GREEN_("%2d") " keys from %s", i, filename);
2788 return PM3_SUCCESS;
2791 static int saveKeys(char *filename) {
2792 FILE *f;
2793 f = fopen(filename, "wb");
2794 if (!f) {
2795 PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", filename);
2796 return PM3_EFILE;
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);
2801 break;
2804 fclose(f);
2805 return PM3_SUCCESS;
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);
2815 else
2816 PrintAndLogEx(INFO, " %u | " _YELLOW_("%s"), i, sprint_hex(iClass_Key_Table[i], 8));
2818 PrintAndLogEx(INFO, "---+------------------------");
2819 PrintAndLogEx(NORMAL, "");
2820 return PM3_SUCCESS;
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[] = {
2833 arg_param_begin,
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"),
2840 arg_param_end
2842 CLIExecWithReturn(ctx, Cmd, argtable, false);
2844 int fnlen = 0;
2845 char filename[FILE_PATH_SIZE] = {0};
2846 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
2848 int key_len = 0;
2849 uint8_t key[8] = {0};
2850 CLIGetHexWithReturn(ctx, 2, key, &key_len);
2851 uint8_t operation = 0;
2853 if (key_len > 0) {
2854 operation += 3;
2855 if (key_len != 8) {
2856 PrintAndLogEx(ERR, "Key is incorrect length");
2857 CLIParserFree(ctx);
2858 return PM3_EINVARG;
2862 int key_nr = arg_get_int_def(ctx, 3, -1);
2864 if (key_nr >= 0) {
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));
2867 } else {
2868 PrintAndLogEx(ERR, "Key index is out-of-range");
2869 CLIParserFree(ctx);
2870 return PM3_EINVARG;
2874 if (arg_get_lit(ctx, 4)) { //save
2875 operation += 6;
2877 if (arg_get_lit(ctx, 5)) { //load
2878 operation += 5;
2880 if (arg_get_lit(ctx, 6)) { //print
2881 operation += 4;
2884 CLIParserFree(ctx);
2886 if (operation == 0) {
2887 PrintAndLogEx(ERR, "No operation specified (load, save, or print)\n");
2888 return PM3_EINVARG;
2890 if (operation > 6) {
2891 PrintAndLogEx(ERR, "Too many operations specified\n");
2892 return PM3_EINVARG;
2894 if (operation > 4 && fnlen == 0) {
2895 PrintAndLogEx(ERR, "You must enter a filename when loading or saving\n");
2896 return PM3_EINVARG;
2898 if (key_len > 0 && key_nr == -1) {
2899 PrintAndLogEx(ERR, "Please specify key index when specifying key");
2900 return PM3_EINVARG;
2903 switch (operation) {
2904 case 3:
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));
2907 return PM3_SUCCESS;
2908 case 4:
2909 return printKeys();
2910 case 5:
2911 return loadKeys(filename);
2912 case 6:
2913 return saveKeys(filename);
2915 return PM3_SUCCESS;
2918 static void add_key(uint8_t *key) {
2920 uint8_t i;
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);
2925 break;
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);
2931 break;
2935 if (i == ICLASS_KEYS_MAX) {
2936 PrintAndLogEx(INFO, "Couldn't find an empty keyslot");
2937 } else {
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[] = {
2950 arg_param_begin,
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)"),
2955 arg_param_end
2957 CLIExecWithReturn(ctx, Cmd, argtable, false);
2959 int fnlen = 0;
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);
2967 CLIParserFree(ctx);
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();
2974 // load keys
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) {
2979 free(keyBlock);
2980 return res;
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...");
2986 free(keyBlock);
2987 return PM3_EFILE;
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");
2998 else
2999 break;
3002 if (got_csn == false) {
3003 PrintAndLogEx(WARNING, "Tried %d times. Can't select card, aborting...", ICLASS_AUTH_RETRY);
3004 free(keyBlock);
3005 DropField();
3006 return PM3_ESOFT;
3009 // allocate memory for the pre calculated macs
3010 iclass_premac_t *pre = calloc(keycount, sizeof(iclass_premac_t));
3011 if (pre == NULL) {
3012 PrintAndLogEx(WARNING, "failed to allocate memory");
3013 return PM3_EMALLOC;
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 : "");
3020 if (use_elite)
3021 PrintAndLogEx(NORMAL, "using " _YELLOW_("elite algo"));
3022 if (use_raw)
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;
3033 else
3034 max_chunk_size = keycount;
3036 // fast push mode
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;
3044 // We have
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!");
3055 goto out;
3058 uint32_t curr_chunk_cnt = keycount - chunk_offset;
3059 if ((keycount - chunk_offset) > max_chunk_size) {
3060 curr_chunk_cnt = max_chunk_size;
3063 // last chunk?
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");
3073 break;
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);
3082 free(packet);
3084 bool looped = false;
3085 uint8_t timeout = 0;
3087 PacketResponseNG resp;
3088 while (WaitForResponseTimeout(CMD_HF_ICLASS_CHKKEYS, &resp, 2000) == false) {
3089 timeout++;
3090 PrintAndLogEx(NORMAL, "." NOLF);
3091 if (timeout > 10) {
3092 PrintAndLogEx(WARNING, "\ncommand execute timeout, aborting...");
3093 goto out;
3095 looped = true;
3098 if (looped)
3099 PrintAndLogEx(NORMAL, "");
3101 if (resp.status == PM3_SUCCESS) {
3102 found_offset = resp.data.asBytes[0];
3103 found_key = true;
3104 PrintAndLogEx(NORMAL, "");
3105 PrintAndLogEx(SUCCESS,
3106 "Found valid key " _GREEN_("%s")
3107 , sprint_hex(keyBlock + (chunk_offset + found_offset) * 8, 8)
3109 break;
3110 } else {
3111 PrintAndLogEx(INPLACE, "Chunk [%03d/%d]", chunk_offset, keycount);
3112 fflush(stdout);
3116 out:
3117 t1 = msclock() - t1;
3119 PrintAndLogEx(NORMAL, "");
3120 PrintAndLogEx(SUCCESS, "time in iclass chk " _YELLOW_("%.1f") " seconds", (float)t1 / 1000.0);
3121 DropField();
3123 if (found_key) {
3124 uint8_t *key = keyBlock + (chunk_offset + found_offset) * 8;
3125 add_key(key);
3128 free(pre);
3129 free(keyBlock);
3130 PrintAndLogEx(NORMAL, "");
3131 return PM3_SUCCESS;
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[] = {
3145 arg_param_begin,
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"),
3152 arg_param_end
3154 CLIExecWithReturn(ctx, Cmd, argtable, false);
3156 int fnlen = 0;
3157 char filename[FILE_PATH_SIZE] = {0};
3158 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
3160 int csn_len = 0;
3161 uint8_t csn[8] = {0};
3162 CLIGetHexWithReturn(ctx, 2, csn, &csn_len);
3164 if (csn_len > 0) {
3165 if (csn_len != 8) {
3166 PrintAndLogEx(ERR, "CSN is incorrect length");
3167 CLIParserFree(ctx);
3168 return PM3_EINVARG;
3172 int epurse_len = 0;
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");
3179 CLIParserFree(ctx);
3180 return PM3_EINVARG;
3184 int macs_len = 0;
3185 uint8_t macs[8] = {0};
3186 CLIGetHexWithReturn(ctx, 4, macs, &macs_len);
3188 if (macs_len > 0) {
3189 if (macs_len != 8) {
3190 PrintAndLogEx(ERR, "MAC is incorrect length");
3191 CLIParserFree(ctx);
3192 return PM3_EINVARG;
3196 bool use_elite = arg_get_lit(ctx, 5);
3197 bool use_raw = arg_get_lit(ctx, 6);
3199 CLIParserFree(ctx);
3201 uint8_t CCNR[12];
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)));
3215 // run time
3216 uint64_t t1 = msclock();
3218 uint8_t *keyBlock = NULL;
3219 uint32_t keycount = 0;
3221 // load keys
3222 int res = loadFileDICTIONARY_safe(filename, (void **)&keyBlock, 8, &keycount);
3223 if (res != PM3_SUCCESS || keycount == 0) {
3224 free(keyBlock);
3225 return res;
3228 //iclass_prekey_t
3229 iclass_prekey_t *prekey = calloc(keycount, sizeof(iclass_prekey_t));
3230 if (!prekey) {
3231 free(keyBlock);
3232 return PM3_EMALLOC;
3235 PrintAndLogEx(INFO, "Generating diversified keys...");
3236 GenerateMacKeyFrom(csn, CCNR, use_raw, use_elite, keyBlock, keycount, prekey);
3238 if (use_elite)
3239 PrintAndLogEx(INFO, "Using " _YELLOW_("elite algo"));
3240 if (use_raw)
3241 PrintAndLogEx(INFO, "Using " _YELLOW_("raw mode"));
3243 PrintAndLogEx(INFO, "Sorting...");
3245 // sort mac list.
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);
3253 // binsearch
3254 item = (iclass_prekey_t *) bsearch(&lookup, prekey, keycount, sizeof(iclass_prekey_t), cmp_uint32);
3256 if (item != NULL) {
3257 PrintAndLogEx(SUCCESS, "Found valid key " _GREEN_("%s"), sprint_hex(item->key, 8));
3258 add_key(item->key);
3261 t1 = msclock() - t1;
3262 PrintAndLogEx(SUCCESS, "time in iclass lookup " _YELLOW_("%.3f") " seconds", (float)t1 / 1000.0);
3264 free(prekey);
3265 free(keyBlock);
3266 PrintAndLogEx(NORMAL, "");
3267 return PM3_SUCCESS;
3270 typedef struct {
3271 uint8_t thread_idx;
3272 uint8_t use_raw;
3273 uint8_t use_elite;
3274 uint32_t keycnt;
3275 uint8_t csn[8];
3276 uint8_t cc_nr[12];
3277 uint8_t *keys;
3278 union {
3279 iclass_premac_t *premac;
3280 iclass_prekey_t *prekey;
3281 } list;
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;
3298 uint8_t csn[8];
3299 uint8_t cc_nr[12];
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);
3311 if (use_raw)
3312 memcpy(div_key, key, 8);
3313 else
3314 HFiClassCalcDivKey(csn, key, div_key, use_elite);
3316 doMAC(cc_nr, div_key, list[i].mac);
3317 pthread_mutex_unlock(&generator_mutex);
3319 return NULL;
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]);
3345 if (res) {
3346 PrintAndLogEx(NORMAL, "");
3347 PrintAndLogEx(WARNING, "Failed to create pthreads. Quitting");
3348 return;
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;
3367 uint8_t csn[8];
3368 uint8_t cc_nr[12];
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);
3379 if (use_raw)
3380 memcpy(div_key, list[i].key, 8);
3381 else
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);
3387 return NULL;
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]);
3411 if (res) {
3412 PrintAndLogEx(NORMAL, "");
3413 PrintAndLogEx(WARNING, "Failed to create pthreads. Quitting");
3414 return;
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));
3428 if (!b)
3429 return;
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);
3436 free(b);
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++) {
3445 if (i < 10) {
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) {
3454 #define KEY_SIZE 8
3456 if (len > KEY_SIZE) {
3457 for (uint8_t m = 0; m < len; m += KEY_SIZE) {
3458 permute(data + m, KEY_SIZE, output + m);
3460 return;
3462 if (len != KEY_SIZE) {
3463 PrintAndLogEx(WARNING, "wrong key size\n");
3464 return;
3466 for (uint8_t i = 0; i < KEY_SIZE; ++i) {
3467 uint8_t p = 0;
3468 uint8_t mask = 0x80 >> i;
3469 for (uint8_t j = 0; j < KEY_SIZE; ++j) {
3470 p >>= 1;
3471 if (data[j] & mask)
3472 p |= 0x80;
3474 output[i] = p;
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) {
3483 uint8_t crc = 0;
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;
3488 crc = 0;
3489 } else {
3490 output[i] = data[i];
3491 crc ^= 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)
3498 data[i] &= 0xFE;
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));
3505 shave(key, len);
3506 PrintAndLogEx(SUCCESS, " key | %s \n", sprint_hex(key, len));
3507 free(key);
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));
3517 free(key);
3518 free(pkey);
3521 static int CmdHFiClassPermuteKey(const char *Cmd) {
3523 uint8_t key[8] = {0};
3524 uint8_t data[16] = {0};
3525 int len = 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[] = {
3534 arg_param_begin,
3535 arg_lit0("r", "reverse", "reverse permuted key"),
3536 arg_str1(NULL, "key", "<hex>", "input key, 8 hex bytes"),
3537 arg_param_end
3539 CLIExecWithReturn(ctx, Cmd, argtable, false);
3540 bool isReverse = arg_get_lit(ctx, 1);
3541 CLIGetHexWithReturn(ctx, 2, data, &len);
3542 CLIParserFree(ctx);
3544 memcpy(key, data, 8);
3546 if (isReverse) {
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));
3551 } else {
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));
3557 return PM3_SUCCESS;
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[] = {
3570 arg_param_begin,
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"),
3577 arg_param_end
3579 CLIExecWithReturn(ctx, Cmd, argtable, false);
3581 int bin_len = 63;
3582 uint8_t bin[70] = {0};
3583 CLIGetStrWithReturn(ctx, 1, bin, &bin_len);
3585 int key_nr = arg_get_int_def(ctx, 2, -1);
3586 bool auth = false;
3588 uint8_t key[8] = {0};
3589 if (key_nr >= 0) {
3590 if (key_nr < ICLASS_KEYS_MAX) {
3591 auth = true;
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));
3594 } else {
3595 PrintAndLogEx(ERR, "Key number is invalid");
3596 CLIParserFree(ctx);
3597 return PM3_EINVARG;
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);
3612 CLIParserFree(ctx);
3614 if ((rawkey + elite) > 1) {
3615 PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw'");
3616 return PM3_EINVARG;
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)");
3622 return PM3_EINVARG;
3624 have_enc_key = true;
3627 if (bin_len > 127) {
3628 PrintAndLogEx(ERR, "Binary wiegand string must be less than 128 bits");
3629 return PM3_EINVARG;
3632 if (have_enc_key == false) {
3633 use_sc = IsCardHelperPresent(false);
3634 if (use_sc == false) {
3635 size_t keylen = 0;
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");
3639 return PM3_EINVARG;
3641 if (keylen != 16) {
3642 PrintAndLogEx(ERR, "Failed to load transport key from file");
3643 free(enckeyptr);
3644 return PM3_EINVARG;
3646 memcpy(enc_key, enckeyptr, sizeof(enc_key));
3647 free(enckeyptr);
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,
3658 uint8_t data[8];
3659 memset(data, 0, sizeof(data));
3660 BitstreamOut bout = {data, 0, 0 };
3662 for (int i = 0; i < 64 - bin_len - 1; i++) {
3663 pushBit(&bout, 0);
3665 // add binary sentinel bit.
3666 pushBit(&bout, 1);
3668 // convert binary string to hex bytes
3669 for (int i = 0; i < bin_len; i++) {
3670 char c = bin[i];
3671 if (c == '1')
3672 pushBit(&bout, 1);
3673 else if (c == '0')
3674 pushBit(&bout, 0);
3675 else {
3676 PrintAndLogEx(WARNING, "Ignoring '%c'", c);
3679 memcpy(credential + 8, data, sizeof(data));
3681 // encrypt with transport key
3682 if (use_sc) {
3683 Encrypt(credential + 8, credential + 8);
3684 Encrypt(credential + 16, credential + 16);
3685 Encrypt(credential + 24, credential + 24);
3686 } else {
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;
3693 // write
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);
3696 switch (isok) {
3697 case PM3_SUCCESS:
3698 PrintAndLogEx(SUCCESS, "Write block %d/0x0%x ( " _GREEN_("ok") " ) --> " _YELLOW_("%s"), 6 + i, 6 + i, sprint_hex_inrow(credential + (i * 8), 8));
3699 break;
3700 default:
3701 PrintAndLogEx(SUCCESS, "Write block %d/0x0%x ( " _RED_("fail") " )", 6 + i, 6 + i);
3702 break;
3705 return isok;
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[] = {
3717 arg_param_begin,
3718 arg_param_end
3720 CLIExecWithReturn(ctx, Cmd, argtable, true);
3721 CLIParserFree(ctx);
3723 // Check keys.
3725 // dump
3727 PrintAndLogEx(INFO, "to be implemented");
3728 return PM3_SUCCESS;
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[] = {
3745 arg_param_begin,
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"),
3751 arg_param_end
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);
3760 CLIParserFree(ctx);
3762 bool got_kr = false;
3763 uint8_t key[8] = {0};
3764 if (kidx >= 0) {
3765 if (kidx < ICLASS_KEYS_MAX) {
3766 got_kr = true;
3767 memcpy(key, iClass_Key_Table[kidx], 8);
3768 PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), kidx, sprint_hex(iClass_Key_Table[kidx], 8));
3769 } else {
3770 PrintAndLogEx(ERR, "--ki number is invalid");
3771 return PM3_EINVARG;
3775 if (do_load) {
3776 if (load_config_cards() != PM3_SUCCESS) {
3777 PrintAndLogEx(INFO, "failed to load, check your cardhelper");
3781 if (do_print) {
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);
3790 if (do_generate) {
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!");
3795 return PM3_EINVARG;
3798 generate_config_card(item, key, got_kr);
3801 return PM3_SUCCESS;
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);
3843 return PM3_SUCCESS;
3846 int CmdHFiClass(const char *Cmd) {
3847 clearCommandBuffer();
3848 return CmdsParse(CommandTable, Cmd);
3851 //static void test_credential_type(void) {
3852 // need AA1 key
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) |
3861 // SEOS | | |
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) {
3878 DropField();
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)));
3901 } else {
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") " -----------------------");
3921 uint8_t aia[8];
3922 if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
3923 memcpy(aia, ns_hdr->app_issuer_area, sizeof(aia));
3924 } else {
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);
3934 if (isHidRange) {
3935 PrintAndLogEx(SUCCESS, " CSN.......... " _YELLOW_("HID range"));
3936 if (legacy)
3937 PrintAndLogEx(SUCCESS, " Credential... " _GREEN_("iCLASS legacy"));
3938 if (se_enabled)
3939 PrintAndLogEx(SUCCESS, " Credential... " _GREEN_("iCLASS SE"));
3940 } else {
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]);
3947 DropField();
3948 return PM3_SUCCESS;