Merge pull request #2654 from Antiklesys/master
[RRG-proxmark3.git] / client / src / cmdhficlass.c
blob9ad0e76e262629b5a75773cd4b2cbf72cda9da94
1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // High frequency iClass commands
17 //-----------------------------------------------------------------------------
19 #include "cmdhficlass.h"
20 #include <ctype.h>
21 #include "cliparser.h"
22 #include "cmdparser.h" // command_t
23 #include "commonutil.h" // ARRAYLEN
24 #include "cmdtrace.h"
25 #include "util_posix.h"
26 #include "comms.h"
27 #include "des.h"
28 #include "loclass/cipherutils.h"
29 #include "loclass/cipher.h"
30 #include "loclass/ikeys.h"
31 #include "loclass/elite_crack.h"
32 #include "fileutils.h"
33 #include "protocols.h"
34 #include "cardhelper.h"
35 #include "wiegand_formats.h"
36 #include "wiegand_formatutils.h"
37 #include "cmdsmartcard.h" // smart select fct
38 #include "proxendian.h"
39 #include "iclass_cmd.h"
40 #include "crypto/asn1utils.h" // ASN1 decoder
41 #include "preferences.h"
42 #include "generator.h"
43 #include "cmdhf14b.h"
46 #define NUM_CSNS 9
47 #define MAC_ITEM_SIZE 24 // csn(8) + epurse(8) + nr(4) + mac(4) = 24 bytes
48 #define ICLASS_KEYS_MAX 8
49 #define ICLASS_AUTH_RETRY 10
50 #define ICLASS_CFG_BLK_SR_BIT 0xA0 // indicates SIO present when set in block6[0] (legacy tags)
51 #define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin"
52 #define ICLASS_DEFAULT_KEY_DIC "iclass_default_keys.dic"
53 #define ICLASS_DEFAULT_KEY_ELITE_DIC "iclass_elite_keys.dic"
55 static void print_picopass_info(const picopass_hdr_t *hdr);
56 void print_picopass_header(const picopass_hdr_t *hdr);
58 static picopass_hdr_t iclass_last_known_card;
59 static void iclass_set_last_known_card(picopass_hdr_t *card) {
60 memcpy(&iclass_last_known_card, card, sizeof(picopass_hdr_t));
63 static uint8_t empty[PICOPASS_BLOCK_SIZE] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
64 static uint8_t zeros[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
66 static int CmdHelp(const char *Cmd);
67 static void print_iclass_sio(uint8_t *iclass_dump, size_t dump_len);
69 static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][PICOPASS_BLOCK_SIZE] = {
70 { 0xAE, 0xA6, 0x84, 0xA6, 0xDA, 0xB2, 0x32, 0x78 },
71 { 0xFD, 0xCB, 0x5A, 0x52, 0xEA, 0x8F, 0x30, 0x90 },
72 { 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87 },
73 { 0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x10, 0x00 },
74 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
75 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
76 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
77 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
80 static int cmp_uint32(const void *a, const void *b) {
82 const iclass_prekey_t *x = (const iclass_prekey_t *)a;
83 const iclass_prekey_t *y = (const iclass_prekey_t *)b;
85 uint32_t mx = bytes_to_num((uint8_t *)x->mac, 4);
86 uint32_t my = bytes_to_num((uint8_t *)y->mac, 4);
88 if (mx < my)
89 return -1;
90 else
91 return mx > my;
94 bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t *rmac, uint8_t *tmac, uint8_t *key) {
96 iclass_prekey_t *prekey = calloc(ICLASS_KEYS_MAX * 2, sizeof(iclass_prekey_t));
97 if (prekey == NULL) {
98 return false;
101 uint8_t ccnr[12];
102 memcpy(ccnr, epurse, 8);
103 memcpy(ccnr + 8, rmac, 4);
105 GenerateMacKeyFrom(csn, ccnr, false, false, (uint8_t *)iClass_Key_Table, ICLASS_KEYS_MAX, prekey);
106 GenerateMacKeyFrom(csn, ccnr, false, true, (uint8_t *)iClass_Key_Table, ICLASS_KEYS_MAX, prekey + ICLASS_KEYS_MAX);
107 qsort(prekey, ICLASS_KEYS_MAX * 2, sizeof(iclass_prekey_t), cmp_uint32);
109 iclass_prekey_t lookup;
110 memcpy(lookup.mac, tmac, 4);
112 // binsearch
113 iclass_prekey_t *item = (iclass_prekey_t *) bsearch(&lookup, prekey, ICLASS_KEYS_MAX * 2, sizeof(iclass_prekey_t), cmp_uint32);
114 if (item != NULL) {
115 memcpy(key, item->key, 8);
116 free(prekey);
117 return true;
119 free(prekey);
120 return false;
123 typedef enum {
124 None = 0,
125 DES,
126 RFU,
127 TRIPLEDES
128 } BLOCK79ENCRYPTION;
130 // 16 bytes key
131 static int iclass_load_transport(uint8_t *key, uint8_t n) {
132 size_t keylen = 0;
133 uint8_t *keyptr = NULL;
134 int res = loadFile_safeEx(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen, false);
135 if (res != PM3_SUCCESS) {
136 PrintAndLogEx(INFO, "Couldn't find any decryption methods");
137 return PM3_EINVARG;
140 if (keylen != 16) {
141 PrintAndLogEx(ERR, "Failed to load transport key from file");
142 free(keyptr);
143 return PM3_EINVARG;
146 if (keylen != n) {
147 PrintAndLogEx(ERR, "Array size mismatch");
148 free(keyptr);
149 return PM3_EINVARG;
152 memcpy(key, keyptr, n);
153 free(keyptr);
154 return PM3_SUCCESS;
157 static void iclass_decrypt_transport(uint8_t *key, uint8_t limit, uint8_t *enc_data, uint8_t *dec_data, BLOCK79ENCRYPTION aa1_encryption) {
159 // tripledes
160 mbedtls_des3_context ctx;
161 mbedtls_des3_set2key_dec(&ctx, key);
163 bool decrypted_block789 = false;
164 for (uint8_t i = 0; i < limit; ++i) {
166 uint16_t idx = i * PICOPASS_BLOCK_SIZE;
168 switch (aa1_encryption) {
169 // Right now, only 3DES is supported
170 case TRIPLEDES:
171 // Decrypt block 7,8,9 if configured.
172 if (i > 6 && i <= 9 && memcmp(enc_data + idx, empty, PICOPASS_BLOCK_SIZE) != 0) {
173 mbedtls_des3_crypt_ecb(&ctx, enc_data + idx, dec_data + idx);
174 decrypted_block789 = true;
176 break;
177 case DES:
178 case RFU:
179 case None:
180 // Nothing to do for None anyway...
181 default:
182 continue;
185 if (decrypted_block789) {
186 // Set the 2 last bits of block6 to 0 to mark the data as decrypted
187 dec_data[(6 * PICOPASS_BLOCK_SIZE) + 7] &= 0xFC;
191 mbedtls_des3_free(&ctx);
194 static inline uint32_t leadingzeros(uint64_t a) {
195 #if defined __GNUC__
196 return __builtin_clzll(a);
197 #else
198 return 0;
199 #endif
202 static void iclass_upload_emul(uint8_t *d, uint16_t n, uint16_t offset, uint16_t *bytes_sent) {
204 struct p {
205 uint16_t offset;
206 uint16_t len;
207 uint8_t data[];
208 } PACKED;
210 // fast push mode
211 g_conn.block_after_ACK = true;
213 //Send to device
214 *bytes_sent = 0;
215 uint16_t bytes_remaining = n;
217 PrintAndLogEx(INFO, "Uploading to emulator memory");
218 PrintAndLogEx(INFO, "." NOLF);
220 while (bytes_remaining > 0) {
221 uint32_t bytes_in_packet = MIN(PM3_CMD_DATA_SIZE - 4, bytes_remaining);
222 if (bytes_in_packet == bytes_remaining) {
223 // Disable fast mode on last packet
224 g_conn.block_after_ACK = false;
227 struct p *payload = calloc(4 + bytes_in_packet, sizeof(uint8_t));
228 payload->offset = offset + *bytes_sent;
229 payload->len = bytes_in_packet;
230 memcpy(payload->data, d + *bytes_sent, bytes_in_packet);
232 clearCommandBuffer();
233 SendCommandNG(CMD_HF_ICLASS_EML_MEMSET, (uint8_t *)payload, 4 + bytes_in_packet);
234 free(payload);
236 bytes_remaining -= bytes_in_packet;
237 *bytes_sent += bytes_in_packet;
239 PrintAndLogEx(NORMAL, "." NOLF);
240 fflush(stdout);
242 PrintAndLogEx(NORMAL, "");
245 static const char *card_types[] = {
246 "PicoPass 16K / 16", // 000
247 "PicoPass 32K with current book 16K / 16", // 001
248 "Unknown Card Type!", // 010
249 "Unknown Card Type!", // 011
250 "PicoPass 2K", // 100
251 "Unknown Card Type!", // 101
252 "PicoPass 16K / 2", // 110
253 "PicoPass 32K with current book 16K / 2", // 111
256 static uint8_t card_app2_limit[] = {
257 0x1f,
258 0xff,
259 0xff,
260 0xff,
261 0x1f,
262 0xff,
263 0xff,
264 0xff,
267 static iclass_config_card_item_t iclass_config_options[30] = {
268 //Byte A8 - LED Operations
269 {"(LED) - Led idle (Off) / Led read (Off)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
270 {"(LED) - Led idle (Red) / Led read (Off)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
271 {"(LED) - Led idle (Grn) / Led read (Off)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
272 {"(LED) - Led idle (Amber) / Led read (Off)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
273 {"(LED) - Led idle (Off) / Led read (Red)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
274 {"(LED) - Led idle (Red) / Led read (Red)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
275 {"(LED) - Led idle (Grn) / Led read (Red)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
276 {"(LED) - Led idle (Amber) / Led read (Red)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
277 {"(LED) - Led idle (Off) / Led read (Grn)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0x8F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
278 {"(LED) - Led idle (Red) / Led read (Grn)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
279 {"(LED) - Led idle (Grn) / Led read (Grn)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0xAF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
280 {"(LED) - Led idle (Amber) / Led read (Red)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
281 {"(LED) - Led idle (Off) / Led read (Amber)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
282 {"(LED) - Led idle (Red) / Led read (Amber)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
283 {"(LED) - Led idle (Grn) / Led read (Amber)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
284 {"(LED) - Led idle (Amber) / Led read (Amber)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA8, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
285 //Byte A9 - Potentially associated with led blinking / led heartbeat operations?
286 //Byte A6 - Potentially associated with beep pitch?
287 //Byte A7 - BEEP Operations
288 {"(BEEP) - Beep on Read (On)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA7, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
289 {"(BEEP) - Beep on Read (Off)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xA7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
290 //Byte AC - MIFARE CSN Operations
291 {"(MIFARE) - CSN Default Output", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
292 {"(MIFARE) - CSN 32 bit Reverse Output", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xAC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
293 {"(MIFARE) - CSN 16 bit Output", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xAC, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
294 {"(MIFARE) - CSN 34 bit Output", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xAC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
295 //Bytes AD, AE, AF, B3 - Keypad Operations + not fully mapped
296 {"(KEYPAD Output) - Buffer ONE key (8 bit Dorado)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xAE, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
297 {"(KEYPAD Output) - Buffer ONE to FIVE keys (standard 26 bit)", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xAE, 0x0B, 0xAF, 0xFF, 0xAD, 0x15, 0xB3, 0x03}},
298 {"(KEYPAD Output) - Local PIN verify", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x18, 0xAD, 0x6D, 0xB3, 0x03, 0x00, 0x00, 0x00, 0x00}},
299 //iClass Elite Key Operations
300 {"(ELITE Key) - Set ELITE Key and Enable Dual key (Elite + Standard)", {0x0C, 0x00, 0x00, 0x01, 0x00, 0x00, 0xBF, 0x18, 0xBF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
301 {"(ELITE Key) - Set ELITE Key and ENABLE Keyrolling", {0x0C, 0x00, 0x00, 0x01, 0x00, 0x00, 0xBF, 0x18, 0xBF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
302 {"(ELITE Key) - Set ELITE Key and DISABLE Standard Key", {0x0C, 0x00, 0x00, 0x01, 0x00, 0x00, 0xBF, 0x18, 0xBF, 0x05, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
303 //Erroneous / incorrect reader behaviors
304 //Reset Operations
305 {"(RESET) - Reset READER to defaults", {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
306 {"(RESET) - Reset ENROLLER to defaults", {0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF}}
307 //Reader Master Key Operations
310 static const iclass_config_card_item_t *get_config_card_item(int idx) {
311 if (idx > -1 && idx < ARRAYLEN(iclass_config_options)) {
312 return &iclass_config_options[idx];
314 return &iclass_config_options[ARRAYLEN(iclass_config_options)];
317 static void print_config_cards(void) {
318 PrintAndLogEx(INFO, "---- " _CYAN_("Config cards options") " ------------");
319 for (int i = 0; i < ARRAYLEN(iclass_config_options) ; ++i) {
320 PrintAndLogEx(INFO, "%2d, %s", i, iclass_config_options[i].desc);
322 PrintAndLogEx(NORMAL, "");
325 static void iclass_encrypt_block_data(uint8_t *blk_data, uint8_t *key) {
326 uint8_t encrypted_data[16];
327 uint8_t *encrypted = encrypted_data;
328 mbedtls_des3_context ctx;
329 mbedtls_des3_set2key_enc(&ctx, key);
330 mbedtls_des3_crypt_ecb(&ctx, blk_data, encrypted);
331 memcpy(blk_data, encrypted, 8);
332 mbedtls_des3_free(&ctx);
335 static int generate_config_card(const iclass_config_card_item_t *o, uint8_t *key, bool got_kr, uint8_t *card_key, bool got_eki, bool use_elite, bool got_mk, uint8_t *master_key) {
337 // generated config card header
338 picopass_hdr_t configcard;
339 memset(&configcard, 0xFF, sizeof(picopass_hdr_t));
340 memcpy(configcard.csn, "\x41\x87\x66\x00\xFB\xFF\x12\xE0", 8);
341 memcpy(&configcard.conf, "\xFF\xFF\xFF\xFF\xF9\xFF\xFF\xBC", 8);
342 memcpy(&configcard.epurse, "\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8);
344 if (got_eki) {
345 HFiClassCalcDivKey(configcard.csn, card_key, configcard.key_d, use_elite);
346 } else {
347 // defaulting to AA1 ki 0
348 HFiClassCalcDivKey(configcard.csn, iClass_Key_Table[0], configcard.key_d, use_elite);
351 // reference
352 picopass_hdr_t *cc = &configcard;
354 // get header from card
355 PrintAndLogEx(INFO, "trying to read a card..");
356 int res = read_iclass_csn(false, false, false);
357 if (res == PM3_SUCCESS) {
358 cc = &iclass_last_known_card;
359 // calc diversified key for selected card
360 if (got_eki) {
361 HFiClassCalcDivKey(cc->csn, card_key, cc->key_d, use_elite);
362 } else {
363 // defaulting to AA1 ki 0
364 HFiClassCalcDivKey(cc->csn, iClass_Key_Table[0], cc->key_d, use_elite);
366 } else {
367 PrintAndLogEx(FAILED, "failed to read a card");
368 PrintAndLogEx(INFO, "falling back to default config card");
370 PrintAndLogEx(INFO, "Generating "_YELLOW_("%s"), o->desc);
372 // generate dump file
373 uint8_t app1_limit = cc->conf.app_limit;
374 uint8_t old_limit = app1_limit;
375 uint16_t tot_bytes = (app1_limit + 1) * 8;
377 PrintAndLogEx(INFO, " APP1 limit: %u", app1_limit);
378 PrintAndLogEx(INFO, "total bytes: %u", tot_bytes);
379 // normal size
380 uint8_t *data = calloc(1, tot_bytes);
381 if (data == NULL) {
382 PrintAndLogEx(FAILED, "failed to allocate memory");
383 return PM3_EMALLOC;
386 memcpy(data, cc, sizeof(picopass_hdr_t));
388 print_picopass_header(cc);
389 // KEYROLL need to encrypt
390 uint8_t key_en[16] = {0};
391 uint8_t *keyptr_en = NULL;
392 size_t keylen = 0;
393 int res_key = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr_en, &keylen);
394 if (res_key != PM3_SUCCESS) {
395 PrintAndLogEx(ERR, "Failed to find iclass_decryptionkey.bin");
396 free(data);
397 return PM3_EINVARG;
400 if (keylen != 16) {
401 PrintAndLogEx(ERR, "Failed to load transport key from file");
402 free(keyptr_en);
403 free(data);
404 return PM3_EINVARG;
406 memcpy(key_en, keyptr_en, sizeof(key_en));
407 free(keyptr_en);
409 // Keyrolling configuration cards are special.
410 if (strstr(o->desc, "ELITE") != NULL) {
412 if (got_kr == false) {
413 PrintAndLogEx(ERR, "please specify ELITE key!");
414 free(data);
415 return PM3_EINVARG;
418 if (app1_limit < 0x16) {
419 // if card wasn't large enough before, adapt to new size
420 PrintAndLogEx(WARNING, "Adapting applimit1 for KEY rolling..");
422 app1_limit = 0x16;
423 cc->conf.app_limit = 0x16;
424 tot_bytes = (app1_limit + 1) * 8;
426 uint8_t *p = realloc(data, tot_bytes);
427 if (p == NULL) {
428 PrintAndLogEx(FAILED, "failed to allocate memory");
429 free(data);
430 return PM3_EMALLOC;
432 data = p;
435 memset(data + sizeof(picopass_hdr_t), 0xFF, tot_bytes - sizeof(picopass_hdr_t));
437 bool old = GetFlushAfterWrite();
438 SetFlushAfterWrite(true);
440 PrintAndLogEx(INFO, "Setting up encryption... " NOLF);
441 uint8_t ffs[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
442 if (IsCardHelperPresent(false) != false) {
443 if (Encrypt(ffs, ffs) == false) {
444 PrintAndLogEx(WARNING, "failed to encrypt FF");
445 } else {
446 PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
448 } else {
449 iclass_encrypt_block_data(ffs, key_en);
450 PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
453 // local key copy
454 PrintAndLogEx(INFO, "Encrypting local key... " NOLF);
455 uint8_t lkey[8];
456 memcpy(lkey, key, sizeof(lkey));
457 uint8_t enckey1[8];
458 if (IsCardHelperPresent(false) != false) {
459 if (Encrypt(lkey, enckey1) == false) {
460 PrintAndLogEx(WARNING, "failed to encrypt key1");
461 } else {
462 PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
464 } else {
465 iclass_encrypt_block_data(lkey, key_en);
466 PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
469 PrintAndLogEx(INFO, "Copy data... " NOLF);
470 memcpy(data, cc, sizeof(picopass_hdr_t));
471 memcpy(data + (6 * 8), o->data, sizeof(o->data));
473 // encrypted keyroll key 0D
474 if (IsCardHelperPresent(false) != false) {
475 memcpy(data + (0x0D * 8), enckey1, sizeof(enckey1));
476 } else {
477 memcpy(data + (0x0D * 8), lkey, sizeof(enckey1));
479 // encrypted 0xFF
480 for (uint8_t i = 0x0E; i < 0x13; i++) {
481 memcpy(data + (i * 8), ffs, sizeof(ffs));
483 PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
485 //Block 13 (This is needed for Rev.C readers!)
486 uint8_t block_0x13[PICOPASS_BLOCK_SIZE] = {0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C};
487 memcpy(data + (0x13 * 8), block_0x13, sizeof(block_0x13));
489 // encrypted partial keyroll key 14
490 PrintAndLogEx(INFO, "Setting encrypted partial key14... " NOLF);
491 uint8_t foo[8] = {0x15};
492 memcpy(foo + 1, key, 7);
493 uint8_t enckey2[8];
494 if (IsCardHelperPresent(false) != false) {
495 if (Encrypt(foo, enckey2) == false) {
496 PrintAndLogEx(WARNING, "failed to encrypt partial 1");
497 } else {
498 PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
499 memcpy(data + (0x14 * 8), enckey2, sizeof(enckey2));
501 } else {
502 iclass_encrypt_block_data(foo, key_en);
503 PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
504 memcpy(data + (0x14 * 8), foo, sizeof(enckey2));
507 // encrypted partial keyroll key 15
508 PrintAndLogEx(INFO, "Setting encrypted partial key15... " NOLF);
509 memset(foo, 0xFF, sizeof(foo));
510 foo[0] = key[7];
511 if (IsCardHelperPresent(false) != false) {
512 if (Encrypt(foo, enckey2) == false) {
513 PrintAndLogEx(WARNING, "failed to encrypt partial 2");
514 } else {
515 PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
516 memcpy(data + (0x15 * 8), enckey2, sizeof(enckey2));
518 } else {
519 iclass_encrypt_block_data(foo, key_en);
520 PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
521 memcpy(data + (0x15 * 8), foo, sizeof(enckey2));
524 // encrypted 0xFF
525 PrintAndLogEx(INFO, "Setting 0xFF's... " NOLF);
526 for (uint16_t i = 0x16; i < (app1_limit + 1); i++) {
527 memcpy(data + (i * 8), ffs, sizeof(ffs));
530 PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
532 // revert potential modified app1_limit
533 cc->conf.app_limit = old_limit;
535 SetFlushAfterWrite(old);
536 } else {
537 memcpy(data, cc, sizeof(picopass_hdr_t));
538 memcpy(data + (6 * 8), o->data, sizeof(o->data));
539 if (strstr(o->desc, "Custom") != NULL) {
540 if (got_mk == false) {
541 PrintAndLogEx(ERR, "please specify New Master Key!");
542 free(data);
543 return PM3_EINVARG;
545 iclass_encrypt_block_data(master_key, key_en);
546 memcpy(data + (0x07 * 8), master_key, PICOPASS_BLOCK_SIZE);
550 //Send to device
551 PrintAndLogEx(INFO, "Uploading to device... ");
552 uint16_t bytes_sent = 0;
553 iclass_upload_emul(data, tot_bytes, 0, &bytes_sent);
554 free(data);
556 PrintAndLogEx(NORMAL, "");
557 PrintAndLogEx(SUCCESS, "sent " _YELLOW_("%u") " bytes of data to device emulator memory", bytes_sent);
558 PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass eview") "` to view dump file");
559 PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass sim -t 3") "` to start simulating config card");
560 return PM3_SUCCESS;
563 static uint8_t isset(uint8_t val, uint8_t mask) {
564 return (val & mask);
567 static uint8_t notset(uint8_t val, uint8_t mask) {
568 return !(val & mask);
571 uint8_t get_pagemap(const picopass_hdr_t *hdr) {
572 return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3;
575 static void fuse_config(const picopass_hdr_t *hdr) {
577 uint16_t otp = (hdr->conf.otp[1] << 8 | hdr->conf.otp[0]);
579 PrintAndLogEx(INFO, " Raw... " _YELLOW_("%s"), sprint_hex((uint8_t *)&hdr->conf, 8));
580 PrintAndLogEx(INFO, " " _YELLOW_("%02X") " ( %3u )............. app limit", hdr->conf.app_limit, hdr->conf.app_limit);
581 PrintAndLogEx(INFO, " " _YELLOW_("%04X") " ( %5u )...... OTP", otp, otp);
582 PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ block write lock", hdr->conf.block_writelock);
583 PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... chip", hdr->conf.chip_config);
584 PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... mem", hdr->conf.mem_config);
585 PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... EAS", hdr->conf.eas);
586 PrintAndLogEx(INFO, " " _YELLOW_("%02X") " fuses", hdr->conf.fuses);
588 uint8_t fuses = hdr->conf.fuses;
590 PrintAndLogEx(INFO, " Fuses:");
591 if (isset(fuses, FUSE_FPERS))
592 PrintAndLogEx(SUCCESS, " mode......... " _GREEN_("Personalization (programmable)"));
593 else
594 PrintAndLogEx(SUCCESS, " mode......... " _YELLOW_("Application (locked)"));
596 if (isset(fuses, FUSE_CODING1)) {
597 PrintAndLogEx(SUCCESS, " coding...... RFU");
598 } else {
599 if (isset(fuses, FUSE_CODING0))
600 PrintAndLogEx(SUCCESS, " coding....... " _YELLOW_("ISO 14443-2 B / 15693"));
601 else
602 PrintAndLogEx(SUCCESS, " coding....... " _YELLOW_("ISO 14443-B only"));
605 uint8_t pagemap = get_pagemap(hdr);
606 switch (pagemap) {
607 case 0x0:
608 PrintAndLogEx(INFO, " crypt........ No auth possible. Read only if RA is enabled");
609 break;
610 case 0x1:
611 PrintAndLogEx(SUCCESS, " crypt........ Non secured page");
612 break;
613 case 0x2:
614 PrintAndLogEx(INFO, " crypt........ Secured page, keys locked");
615 break;
616 case 0x03:
617 PrintAndLogEx(SUCCESS, " crypt........ Secured page, " _GREEN_("keys not locked"));
618 break;
621 if (isset(fuses, FUSE_RA))
622 PrintAndLogEx(SUCCESS, " RA........... Read access enabled (non-secure mode)");
623 else
624 PrintAndLogEx(INFO, " RA........... Read access not enabled");
626 if (notset(fuses, FUSE_FPROD0) && isset(fuses, FUSE_FPROD1)) {
627 PrintAndLogEx(INFO, " PROD0/1...... Default production fuses");
631 static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *app_areas, uint8_t *kb, uint8_t *books, uint8_t *pages) {
632 // How to determine chip type
634 // mem-bit 7 = 16K
635 // mem-bit 5 = Book
636 // mem-bit 4 = 2K
637 // chip-bit 4 = Multi App
638 *books = 1;
639 *pages = 1;
641 uint8_t k16 = isset(mem_cfg, 0x80);
642 //uint8_t k2 = isset(mem_cfg, 0x10);
643 uint8_t book = isset(mem_cfg, 0x20);
645 if (isset(chip_cfg, 0x10) && !k16 && !book) {
646 *kb = 2;
647 *app_areas = 2;
648 } else if (isset(chip_cfg, 0x10) && k16 && !book) {
649 *kb = 16;
650 *app_areas = 2;
651 } else if (notset(chip_cfg, 0x10) && !k16 && !book) {
652 *kb = 16;
653 *app_areas = 16;
654 *pages = 8;
655 } else if (isset(chip_cfg, 0x10) && k16 && book) {
656 *kb = 32;
657 *app_areas = 3;
658 *books = 2;
659 } else if (notset(chip_cfg, 0x10) && !k16 && book) {
660 *kb = 32;
661 *app_areas = 17;
662 *pages = 8;
663 *books = 2;
664 } else {
665 *kb = 32;
666 *app_areas = 2;
670 static uint8_t get_mem_config(const picopass_hdr_t *hdr) {
671 // three configuration bits that decides sizes
672 uint8_t type = (hdr->conf.chip_config & 0x10) >> 2;
673 // 16K bit 0 == 1==
674 type |= (hdr->conf.mem_config & 0x80) >> 6;
675 // BOOK bit 0 == 1==
676 type |= (hdr->conf.mem_config & 0x20) >> 5;
677 // 2K
678 //type |= (hdr->conf.mem_config & 0x10) >> 5;
679 return type;
682 static void mem_app_config(const picopass_hdr_t *hdr) {
683 uint8_t mem = hdr->conf.mem_config;
684 uint8_t chip = hdr->conf.chip_config;
685 uint8_t kb = 2;
686 uint8_t app_areas = 2;
687 uint8_t books = 1;
688 uint8_t pages = 1;
690 getMemConfig(mem, chip, &app_areas, &kb, &books, &pages);
692 uint8_t type = get_mem_config(hdr);
693 uint8_t app1_limit = hdr->conf.app_limit - 5; // minus header blocks
694 uint8_t app2_limit = card_app2_limit[type];
695 uint8_t pagemap = get_pagemap(hdr);
697 PrintAndLogEx(INFO, "-------------------------- " _CYAN_("Memory") " --------------------------");
699 if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
700 PrintAndLogEx(INFO, " %u KBits ( " _YELLOW_("%u") " bytes )", kb, app2_limit * 8);
701 PrintAndLogEx(INFO, " Tag has not App Areas");
702 return;
705 PrintAndLogEx(INFO, " %u KBits/%u App Areas ( " _YELLOW_("%u") " bytes )"
706 , kb
707 , app_areas
708 , ((app2_limit + 1) * 8) * books * pages);
710 PrintAndLogEx(INFO, " %u books / %u pages"
711 , books
712 , pages
714 PrintAndLogEx(INFO, " First book / first page configuration");
715 PrintAndLogEx(INFO, " Config | 0 - 5 ( 0x00 - 0x05 ) - 6 blocks ");
716 PrintAndLogEx(INFO, " AA1 | 6 - %2d ( 0x06 - 0x%02X ) - %u blocks", app1_limit + 5, app1_limit + 5, app1_limit);
717 if (app1_limit + 5 < app2_limit) {
718 PrintAndLogEx(INFO, " AA2 | %2d - %2d ( 0x%02X - 0x%02X ) - %u blocks", app1_limit + 5 + 1, app2_limit, app1_limit + 5 + 1, app2_limit, app2_limit - app1_limit);
721 [=] 32 KBits/3 App Areas ( 2048 bytes )
722 [=] AA1 blocks 250 { 0x06 - 0xFF (06 - 255) }
723 [=] AA2 blocks 5 { 0x100 - 0xFF (256 - 255) }
726 PrintAndLogEx(INFO, "------------------------- " _CYAN_("KeyAccess") " ------------------------");
727 PrintAndLogEx(INFO, " * Kd, Debit key, AA1 Kc, Credit key, AA2 *");
728 uint8_t keyAccess = isset(mem, 0x01);
729 if (keyAccess) {
730 PrintAndLogEx(INFO, " Read AA1..... debit");
731 PrintAndLogEx(INFO, " Write AA1.... debit");
732 PrintAndLogEx(INFO, " Read AA2..... credit");
733 PrintAndLogEx(INFO, " Write AA2.... credit");
734 PrintAndLogEx(INFO, " Debit........ debit or credit");
735 PrintAndLogEx(INFO, " Credit....... credit");
736 } else {
737 PrintAndLogEx(INFO, " Read AA1..... debit or credit");
738 PrintAndLogEx(INFO, " Write AA1.... credit");
739 PrintAndLogEx(INFO, " Read AA2..... debit or credit");
740 PrintAndLogEx(INFO, " Write AA2.... credit");
741 PrintAndLogEx(INFO, " Debit........ debit or credit");
742 PrintAndLogEx(INFO, " Credit....... credit");
746 void print_picopass_info(const picopass_hdr_t *hdr) {
747 PrintAndLogEx(INFO, "-------------------- " _CYAN_("Card configuration") " --------------------");
748 fuse_config(hdr);
749 mem_app_config(hdr);
752 void print_picopass_header(const picopass_hdr_t *hdr) {
753 PrintAndLogEx(INFO, "--------------------------- " _CYAN_("Card") " ---------------------------");
754 PrintAndLogEx(SUCCESS, " CSN... " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn)));
755 PrintAndLogEx(SUCCESS, " Config... %s card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf)));
756 PrintAndLogEx(SUCCESS, "E-purse... %s card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse)));
758 if (memcmp(hdr->key_d, zeros, sizeof(zeros)) && memcmp(hdr->key_d, empty, sizeof(empty))) {
759 PrintAndLogEx(SUCCESS, " Kd... " _YELLOW_("%s") " debit key", sprint_hex(hdr->key_d, sizeof(hdr->key_d)));
760 } else {
761 PrintAndLogEx(SUCCESS, " Kd... %s debit key ( hidden )", sprint_hex(hdr->key_d, sizeof(hdr->key_d)));
764 if (memcmp(hdr->key_c, zeros, sizeof(zeros)) && memcmp(hdr->key_c, empty, sizeof(empty))) {
765 PrintAndLogEx(SUCCESS, " Kc... " _YELLOW_("%s") " credit key", sprint_hex(hdr->key_c, sizeof(hdr->key_c)));
766 } else {
767 PrintAndLogEx(SUCCESS, " Kc... %s credit key ( hidden )", sprint_hex(hdr->key_c, sizeof(hdr->key_c)));
770 PrintAndLogEx(SUCCESS, " AIA... %s application issuer area", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area)));
773 static int CmdHFiClassList(const char *Cmd) {
774 return CmdTraceListAlias(Cmd, "hf iclass", "iclass -c");
777 static int CmdHFiClassSniff(const char *Cmd) {
779 CLIParserContext *ctx;
780 CLIParserInit(&ctx, "hf iclass sniff",
781 "Sniff the communication between reader and tag",
782 "hf iclass sniff\n"
783 "hf iclass sniff -j --> jam e-purse updates\n"
786 void *argtable[] = {
787 arg_param_begin,
788 arg_lit0("j", "jam", "Jam (prevent) e-purse updates"),
789 arg_param_end
792 CLIExecWithReturn(ctx, Cmd, argtable, true);
793 bool jam_epurse_update = arg_get_lit(ctx, 1);
794 CLIParserFree(ctx);
796 if (jam_epurse_update) {
797 PrintAndLogEx(INFO, "Sniff with jam of iCLASS e-purse updates...");
800 struct {
801 uint8_t jam_search_len;
802 uint8_t jam_search_string[2];
803 } PACKED payload;
805 memset(&payload, 0, sizeof(payload));
807 if (jam_epurse_update) {
808 const uint8_t update_epurse_sequence[2] = {0x87, 0x02};
809 payload.jam_search_len = sizeof(update_epurse_sequence);
810 memcpy(payload.jam_search_string, update_epurse_sequence, sizeof(payload.jam_search_string));
813 PacketResponseNG resp;
814 clearCommandBuffer();
815 SendCommandNG(CMD_HF_ICLASS_SNIFF, (uint8_t *)&payload, sizeof(payload));
817 WaitForResponse(CMD_HF_ICLASS_SNIFF, &resp);
819 PrintAndLogEx(NORMAL, "");
820 PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass list") "` to view captured tracelog");
821 PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save -f hf_iclass_mytrace") "` to save tracelog for later analysing");
822 if (jam_epurse_update) {
823 PrintAndLogEx(HINT, "Verify if the jam worked by comparing value in trace and block 2");
825 PrintAndLogEx(NORMAL, "");
826 return PM3_SUCCESS;
829 static int CmdHFiClassSim(const char *Cmd) {
830 CLIParserContext *ctx;
831 CLIParserInit(&ctx, "hf iclass sim",
832 "Simulate a iCLASS legacy/standard tag",
833 "hf iclass sim -t 0 --csn 031FEC8AF7FF12E0 --> simulate with specified CSN\n"
834 "hf iclass sim -t 1 --> simulate with default CSN\n"
835 "hf iclass sim -t 2 --> execute loclass attack online part\n"
836 "hf iclass sim -t 3 --> simulate full iCLASS 2k tag\n"
837 "hf iclass sim -t 4 --> Reader-attack, adapted for KeyRoll mode, gather reader responses to extract elite key");
839 void *argtable[] = {
840 arg_param_begin,
841 arg_int1("t", "type", "<0-4> ", "Simulation type to use"),
842 arg_str0(NULL, "csn", "<hex>", "Specify CSN as 8 hex bytes to use with sim type 0"),
843 arg_param_end
845 CLIExecWithReturn(ctx, Cmd, argtable, false);
847 int sim_type = arg_get_int_def(ctx, 1, 3);
849 int csn_len = 0;
850 uint8_t csn[8] = {0};
851 CLIGetHexWithReturn(ctx, 2, csn, &csn_len);
853 if (sim_type == 0 && csn_len > 0) {
854 if (csn_len != 8) {
855 PrintAndLogEx(ERR, "CSN is incorrect length");
856 CLIParserFree(ctx);
857 return PM3_EINVARG;
859 PrintAndLogEx(INFO, " simtype: %02x CSN: %s", sim_type, sprint_hex(csn, 8));
860 } else if (sim_type == 0 && csn_len == 0) {
861 PrintAndLogEx(ERR, "Simtype 0 requires CSN argument (--csn)");
862 CLIParserFree(ctx);
863 return PM3_EINVARG;
866 CLIParserFree(ctx);
868 if (sim_type > 4) {
869 PrintAndLogEx(ERR, "Undefined simtype %d", sim_type);
870 return PM3_EINVARG;
873 // remember to change the define NUM_CSNS to match.
875 // pre-defined 9 CSN by iceman
876 uint8_t csns[NUM_CSNS * PICOPASS_BLOCK_SIZE] = {
877 0x01, 0x0A, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
878 0x0C, 0x06, 0x0C, 0xFE, 0xF7, 0xFF, 0x12, 0xE0,
879 0x10, 0x97, 0x83, 0x7B, 0xF7, 0xFF, 0x12, 0xE0,
880 0x13, 0x97, 0x82, 0x7A, 0xF7, 0xFF, 0x12, 0xE0,
881 0x07, 0x0E, 0x0D, 0xF9, 0xF7, 0xFF, 0x12, 0xE0,
882 0x14, 0x96, 0x84, 0x76, 0xF7, 0xFF, 0x12, 0xE0,
883 0x17, 0x96, 0x85, 0x71, 0xF7, 0xFF, 0x12, 0xE0,
884 0xCE, 0xC5, 0x0F, 0x77, 0xF7, 0xFF, 0x12, 0xE0,
885 0xD2, 0x5A, 0x82, 0xF8, 0xF7, 0xFF, 0x12, 0xE0
886 //0x04, 0x08, 0x9F, 0x78, 0x6E, 0xFF, 0x12, 0xE0
889 /* DUMPFILE FORMAT:
891 * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
892 * So, it should wind up as
893 * 8 * 24 bytes.
895 * The returndata from the pm3 is on the following format
896 * <4 byte NR><4 byte MAC>
897 * CC are all zeroes, CSN is the same as was sent in
899 uint8_t tries = 0;
901 switch (sim_type) {
903 case ICLASS_SIM_MODE_READER_ATTACK: {
904 PrintAndLogEx(INFO, "Starting iCLASS sim 2 attack (elite mode)");
905 PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to abort");
906 PacketResponseNG resp;
907 clearCommandBuffer();
908 SendCommandMIX(CMD_HF_ICLASS_SIMULATE, sim_type, NUM_CSNS, 1, csns, NUM_CSNS * PICOPASS_BLOCK_SIZE);
910 while (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
911 tries++;
912 if (kbd_enter_pressed()) {
913 PrintAndLogEx(WARNING, "\naborted via keyboard.");
914 return PM3_EOPABORTED;
916 if (tries > 20) {
917 PrintAndLogEx(WARNING, "\ntimeout while waiting for reply.");
918 return PM3_ETIMEOUT;
921 uint8_t num_mac = resp.oldarg[1];
922 bool success = (NUM_CSNS == num_mac);
923 PrintAndLogEx((success) ? SUCCESS : WARNING, "[%c] %d out of %d MAC obtained [%s]", (success) ? '+' : '!', num_mac, NUM_CSNS, (success) ? "OK" : "FAIL");
925 if (num_mac == 0)
926 break;
928 size_t datalen = NUM_CSNS * MAC_ITEM_SIZE;
929 uint8_t *dump = calloc(datalen, sizeof(uint8_t));
930 if (!dump) {
931 PrintAndLogEx(WARNING, "Failed to allocate memory");
932 return PM3_EMALLOC;
935 memset(dump, 0, datalen);//<-- Need zeroes for the EPURSE - field (official)
937 uint8_t i = 0;
938 for (i = 0 ; i < NUM_CSNS ; i++) {
939 //copy CSN
940 memcpy(dump + (i * MAC_ITEM_SIZE), csns + i * 8, 8);
941 //copy epurse
942 memcpy(dump + (i * MAC_ITEM_SIZE) + 8, resp.data.asBytes + i * 16, 8);
943 // NR_MAC (eight bytes from the response) ( 8b csn + 8b epurse == 16)
944 memcpy(dump + (i * MAC_ITEM_SIZE) + 16, resp.data.asBytes + i * 16 + 8, 8);
946 /** Now, save to dumpfile **/
947 saveFile("iclass_mac_attack", ".bin", dump, datalen);
948 free(dump);
950 PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass -f iclass_mac_attack.bin") "` to recover elite key");
951 break;
953 case ICLASS_SIM_MODE_READER_ATTACK_KEYROLL: {
954 // reader in key roll mode, when it has two keys it alternates when trying to verify.
955 PrintAndLogEx(INFO, "Starting iCLASS sim 4 attack (elite mode, reader in key roll mode)");
956 PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to abort");
957 PacketResponseNG resp;
958 clearCommandBuffer();
959 SendCommandMIX(CMD_HF_ICLASS_SIMULATE, sim_type, NUM_CSNS, 1, csns, NUM_CSNS * PICOPASS_BLOCK_SIZE);
961 while (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
962 tries++;
963 if (kbd_enter_pressed()) {
964 PrintAndLogEx(WARNING, "\naborted via keyboard.");
965 return PM3_EOPABORTED;
967 if (tries > 20) {
968 PrintAndLogEx(WARNING, "\ntimeout while waiting for reply.");
969 return PM3_ETIMEOUT;
972 uint8_t num_mac = resp.oldarg[1];
973 bool success = ((NUM_CSNS * 2) == num_mac);
974 PrintAndLogEx((success) ? SUCCESS : WARNING, "[%c] %d out of %d MAC obtained [%s]", (success) ? '+' : '!', num_mac, NUM_CSNS * 2, (success) ? "OK" : "FAIL");
976 if (num_mac == 0)
977 break;
979 size_t datalen = NUM_CSNS * MAC_ITEM_SIZE;
980 uint8_t *dump = calloc(datalen, sizeof(uint8_t));
981 if (!dump) {
982 PrintAndLogEx(WARNING, "Failed to allocate memory");
983 return PM3_EMALLOC;
986 //KEYROLL 1
987 //Need zeroes for the CC-field
988 memset(dump, 0, datalen);
989 for (uint8_t i = 0; i < NUM_CSNS ; i++) {
990 // copy CSN
991 memcpy(dump + (i * MAC_ITEM_SIZE), csns + i * 8, 8); //CSN
992 // copy EPURSE
993 memcpy(dump + (i * MAC_ITEM_SIZE) + 8, resp.data.asBytes + i * 16, 8);
994 // copy NR_MAC (eight bytes from the response) ( 8b csn + 8b epurse == 16)
995 memcpy(dump + (i * MAC_ITEM_SIZE) + 16, resp.data.asBytes + i * 16 + 8, 8);
997 saveFile("iclass_mac_attack_keyroll_A", ".bin", dump, datalen);
999 //KEYROLL 2
1000 memset(dump, 0, datalen);
1001 for (uint8_t i = 0; i < NUM_CSNS; i++) {
1002 uint8_t resp_index = (i + NUM_CSNS) * 16;
1003 // Copy CSN
1004 memcpy(dump + (i * MAC_ITEM_SIZE), csns + i * 8, 8);
1005 // copy EPURSE
1006 memcpy(dump + (i * MAC_ITEM_SIZE) + 8, resp.data.asBytes + resp_index, 8);
1007 // copy NR_MAC (eight bytes from the response) ( 8b csn + 8 epurse == 16)
1008 memcpy(dump + (i * MAC_ITEM_SIZE) + 16, resp.data.asBytes + resp_index + 8, 8);
1009 resp_index++;
1011 saveFile("iclass_mac_attack_keyroll_B", ".bin", dump, datalen);
1012 free(dump);
1014 PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass -f iclass_mac_attack_keyroll_A.bin") "` to recover elite key");
1015 PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass loclass -f iclass_mac_attack_keyroll_B.bin") "` to recover elite key");
1016 break;
1018 case ICLASS_SIM_MODE_CSN:
1019 case ICLASS_SIM_MODE_CSN_DEFAULT:
1020 case ICLASS_SIM_MODE_FULL:
1021 default: {
1022 PrintAndLogEx(INFO, "Starting iCLASS simulation");
1023 PrintAndLogEx(INFO, "Press " _GREEN_("`pm3 button`") " to abort");
1024 uint8_t numberOfCSNs = 0;
1025 clearCommandBuffer();
1026 SendCommandMIX(CMD_HF_ICLASS_SIMULATE, sim_type, numberOfCSNs, 1, csn, 8);
1028 if (sim_type == ICLASS_SIM_MODE_FULL)
1029 PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass esave -h") "` to save the emulator memory to file");
1030 break;
1033 return PM3_SUCCESS;
1036 static int CmdHFiClassInfo(const char *Cmd) {
1037 CLIParserContext *ctx;
1038 CLIParserInit(&ctx, "hf iclass info",
1039 "Act as a iCLASS reader. Reads / fingerprints a iCLASS tag.",
1040 "hf iclass info");
1042 void *argtable[] = {
1043 arg_param_begin,
1044 arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
1045 arg_param_end
1047 CLIExecWithReturn(ctx, Cmd, argtable, true);
1048 bool shallow_mod = arg_get_lit(ctx, 1);
1049 CLIParserFree(ctx);
1050 return info_iclass(shallow_mod);
1053 int read_iclass_csn(bool loop, bool verbose, bool shallow_mod) {
1055 iclass_card_select_t payload = {
1056 .flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE)
1059 if (shallow_mod) {
1060 payload.flags |= FLAG_ICLASS_READER_SHALLOW_MOD;
1063 int res = PM3_SUCCESS;
1065 do {
1066 clearCommandBuffer();
1067 PacketResponseNG resp;
1068 SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t *)&payload, sizeof(iclass_card_select_t));
1070 if (WaitForResponseTimeout(CMD_HF_ICLASS_READER, &resp, 2000)) {
1072 iclass_card_select_resp_t *r = (iclass_card_select_resp_t *)resp.data.asBytes;
1073 if (loop) {
1074 if (resp.status == PM3_ERFTRANS) {
1075 continue;
1077 } else {
1079 if (r->status == FLAG_ICLASS_NULL || resp.status == PM3_ERFTRANS) {
1080 if (verbose) PrintAndLogEx(WARNING, "iCLASS / Picopass card select failed ( %d , %d)", r->status, resp.status);
1081 res = PM3_EOPABORTED;
1082 break;
1086 picopass_hdr_t *card = calloc(1, sizeof(picopass_hdr_t));
1087 if (card) {
1088 memcpy(card, &r->header.hdr, sizeof(picopass_hdr_t));
1089 if (loop == false) {
1090 PrintAndLogEx(NORMAL, "");
1092 PrintAndLogEx(SUCCESS, "iCLASS / Picopass CSN: " _GREEN_("%s"), sprint_hex(card->csn, sizeof(card->csn)));
1093 iclass_set_last_known_card(card);
1094 free(card);
1095 res = PM3_SUCCESS;
1096 } else {
1097 PrintAndLogEx(FAILED, "failed to allocate memory");
1098 res = PM3_EMALLOC;
1101 } while (loop && kbd_enter_pressed() == false);
1103 DropField();
1104 return res;
1107 static int CmdHFiClassReader(const char *Cmd) {
1109 CLIParserContext *ctx;
1110 CLIParserInit(&ctx, "hf iclass reader",
1111 "Act as a iCLASS reader. Look for iCLASS tags until Enter or the pm3 button is pressed",
1112 "hf iclass reader -@ -> continuous reader mode"
1115 void *argtable[] = {
1116 arg_param_begin,
1117 arg_lit0("@", NULL, "optional - continuous reader mode"),
1118 arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
1119 arg_param_end
1121 CLIExecWithReturn(ctx, Cmd, argtable, true);
1122 bool cm = arg_get_lit(ctx, 1);
1123 bool shallow_mod = arg_get_lit(ctx, 2);
1124 CLIParserFree(ctx);
1126 if (cm) {
1127 PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
1130 return read_iclass_csn(cm, false, shallow_mod);
1133 static int CmdHFiClassELoad(const char *Cmd) {
1134 CLIParserContext *ctx;
1135 CLIParserInit(&ctx, "hf iclass eload",
1136 "Load emulator memory with data from (bin/json) iCLASS dump file",
1137 "hf iclass eload -f hf-iclass-AA162D30F8FF12F1-dump.json\n"
1138 "hf iclass eload -f hf-iclass-AA162D30F8FF12F1-dump.bin -m\n"
1141 void *argtable[] = {
1142 arg_param_begin,
1143 arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
1144 arg_lit0("m", "mem", "use RDV4 spiffs"),
1145 arg_lit0("v", "verbose", "verbose output"),
1146 arg_param_end
1148 CLIExecWithReturn(ctx, Cmd, argtable, false);
1150 int fnlen = 0;
1151 char filename[FILE_PATH_SIZE] = {0};
1152 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
1154 if (strlen(filename) == 0) {
1155 PrintAndLogEx(ERR, "Error: Please specify a filename");
1156 CLIParserFree(ctx);
1157 return PM3_EINVARG;
1160 bool use_spiffs = arg_get_lit(ctx, 2);
1161 bool verbose = arg_get_lit(ctx, 3);
1162 CLIParserFree(ctx);
1164 // use RDV4 spiffs
1165 if (use_spiffs && IfPm3Flash() == false) {
1166 PrintAndLogEx(WARNING, "Device not compiled to support spiffs");
1167 return PM3_EINVARG;
1170 if (use_spiffs) {
1172 if (fnlen > 32) {
1173 PrintAndLogEx(WARNING, "filename too long for spiffs, expected 32, got %u", fnlen);
1174 return PM3_EINVARG;
1177 clearCommandBuffer();
1178 SendCommandNG(CMD_SPIFFS_ELOAD, (uint8_t *)filename, fnlen);
1179 PacketResponseNG resp;
1180 if (WaitForResponseTimeout(CMD_SPIFFS_ELOAD, &resp, 2000) == false) {
1181 PrintAndLogEx(WARNING, "timeout while waiting for reply.");
1182 return PM3_ETIMEOUT;
1185 if (resp.status != PM3_SUCCESS) {
1186 PrintAndLogEx(FAILED, "Loading file from spiffs to emulatore memory failed");
1187 return PM3_EFLASH;
1190 PrintAndLogEx(SUCCESS, "File transfered from spiffs to device emulator memory");
1191 return PM3_SUCCESS;
1194 // read dump file
1195 uint8_t *dump = NULL;
1196 size_t bytes_read = 2048;
1197 int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, 2048);
1198 if (res != PM3_SUCCESS) {
1199 return res;
1202 uint8_t *newdump = realloc(dump, bytes_read);
1203 if (newdump == NULL) {
1204 free(dump);
1205 return PM3_EMALLOC;
1206 } else {
1207 dump = newdump;
1210 if (verbose) {
1211 print_picopass_header((picopass_hdr_t *) dump);
1212 print_picopass_info((picopass_hdr_t *) dump);
1215 PrintAndLogEx(NORMAL, "");
1217 //Send to device
1218 uint16_t bytes_sent = 0;
1219 iclass_upload_emul(dump, bytes_read, 0, &bytes_sent);
1220 free(dump);
1221 PrintAndLogEx(SUCCESS, "uploaded " _YELLOW_("%d") " bytes to emulator memory", bytes_sent);
1222 PrintAndLogEx(HINT, "You are ready to simulate. See " _YELLOW_("`hf iclass sim -h`"));
1223 PrintAndLogEx(INFO, "Done!");
1224 return PM3_SUCCESS;
1227 static int CmdHFiClassESave(const char *Cmd) {
1228 CLIParserContext *ctx;
1229 CLIParserInit(&ctx, "hf iclass esave",
1230 "Save emulator memory to file (bin/json)\n"
1231 "if filename is not supplied, CSN will be used.",
1232 "hf iclass esave\n"
1233 "hf iclass esave -f hf-iclass-dump\n"
1234 "hf iclass esave -s 2048 -f hf-iclass-dump");
1236 void *argtable[] = {
1237 arg_param_begin,
1238 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
1239 arg_int0("s", "size", "<256|2048>", "number of bytes to save (default 256)"),
1240 arg_param_end
1242 CLIExecWithReturn(ctx, Cmd, argtable, true);
1244 int fnlen = 0;
1245 char filename[FILE_PATH_SIZE] = {0};
1246 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
1247 uint16_t bytes = arg_get_int_def(ctx, 2, 256);
1249 if (bytes > 4096) {
1250 PrintAndLogEx(WARNING, "Emulator memory is max 4096bytes. Truncating %u to 4096", bytes);
1251 bytes = 4096;
1254 CLIParserFree(ctx);
1256 uint8_t *dump = calloc(bytes, sizeof(uint8_t));
1257 if (dump == NULL) {
1258 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
1259 return PM3_EMALLOC;
1262 PrintAndLogEx(INFO, "downloading from emulator memory");
1263 if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) {
1264 PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
1265 free(dump);
1266 return PM3_ETIMEOUT;
1269 // user supplied filename?
1270 if (fnlen < 1) {
1271 char *fptr = filename;
1272 fptr += snprintf(fptr, sizeof(filename), "hf-iclass-");
1273 FillFileNameByUID(fptr, dump, "-dump", 8);
1276 pm3_save_dump(filename, dump, bytes, jsfIclass);
1277 free(dump);
1279 PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view -f") "` to view dump file");
1280 return PM3_SUCCESS;
1283 static int CmdHFiClassEView(const char *Cmd) {
1284 CLIParserContext *ctx;
1285 CLIParserInit(&ctx, "hf iclass eview",
1286 "Display emulator memory.\n"
1287 "Number of bytes to download defaults to 256. Other value is 2048.",
1288 "hf iclass eview\n"
1289 "hf iclass eview -s 2048\n"
1290 "hf iclass eview -s 2048 -v");
1292 void *argtable[] = {
1293 arg_param_begin,
1294 arg_int0("s", "size", "<256|2048>", "number of bytes to save (default 256)"),
1295 arg_lit0("v", "verbose", "verbose output"),
1296 arg_lit0("z", "dense", "dense dump output style"),
1297 arg_param_end
1299 CLIExecWithReturn(ctx, Cmd, argtable, true);
1301 uint16_t blocks = 32;
1302 uint16_t bytes = arg_get_int_def(ctx, 1, 256);
1303 bool verbose = arg_get_lit(ctx, 2);
1304 bool dense_output = g_session.dense_output || arg_get_lit(ctx, 3);
1305 blocks = bytes / 8;
1307 CLIParserFree(ctx);
1309 if (bytes > 4096) {
1310 PrintAndLogEx(WARNING, "Emulator memory is max 4096bytes. Truncating %u to 4096", bytes);
1311 bytes = 4096;
1314 if (bytes % 8 != 0) {
1315 bytes &= 0xFFF8;
1316 PrintAndLogEx(WARNING, "Number not divided by 8, truncating to %u", bytes);
1319 uint8_t *dump = calloc(bytes, sizeof(uint8_t));
1320 if (dump == NULL) {
1321 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
1322 return PM3_EMALLOC;
1324 memset(dump, 0, bytes);
1326 PrintAndLogEx(INFO, "downloading from emulator memory");
1327 if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) {
1328 PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
1329 free(dump);
1330 return PM3_ETIMEOUT;
1333 if (verbose) {
1334 print_picopass_header((picopass_hdr_t *) dump);
1335 print_picopass_info((picopass_hdr_t *) dump);
1338 PrintAndLogEx(NORMAL, "");
1339 printIclassDumpContents(dump, 1, blocks, bytes, dense_output);
1341 if (verbose) {
1342 print_iclass_sio(dump, bytes);
1345 free(dump);
1346 return PM3_SUCCESS;
1349 static int CmdHFiClassESetBlk(const char *Cmd) {
1350 CLIParserContext *ctx;
1351 CLIParserInit(&ctx, "hf iclass esetblk",
1352 "Sets an individual block in emulator memory.",
1353 "hf iclass esetblk --blk 7 -d 0000000000000000");
1355 void *argtable[] = {
1356 arg_param_begin,
1357 arg_int1(NULL, "blk", "<dec>", "block number"),
1358 arg_str0("d", "data", "<hex>", "bytes to write, 8 hex bytes"),
1359 arg_param_end
1361 CLIExecWithReturn(ctx, Cmd, argtable, true);
1363 int blk = arg_get_int_def(ctx, 1, 0);
1365 if (blk > 255 || blk < 0) {
1366 PrintAndLogEx(WARNING, "block number must be between 0 and 255. Got " _RED_("%i"), blk);
1367 CLIParserFree(ctx);
1368 return PM3_EINVARG;
1371 uint8_t data[PICOPASS_BLOCK_SIZE] = {0x00};
1372 int datalen = 0;
1373 int res = CLIParamHexToBuf(arg_get_str(ctx, 2), data, sizeof(data), &datalen);
1374 CLIParserFree(ctx);
1376 if (res) {
1377 PrintAndLogEx(FAILED, "Error parsing bytes");
1378 return PM3_EINVARG;
1381 if (datalen != PICOPASS_BLOCK_SIZE) {
1382 PrintAndLogEx(WARNING, "block data must include 8 HEX bytes. Got " _RED_("%i"), datalen);
1383 return PM3_EINVARG;
1386 uint16_t bytes_sent = 0;
1387 iclass_upload_emul(data, sizeof(data), blk * PICOPASS_BLOCK_SIZE, &bytes_sent);
1389 return PM3_SUCCESS;
1392 static bool iclass_detect_new_pacs(uint8_t *d) {
1393 uint8_t n = 0;
1394 while (n++ < (PICOPASS_BLOCK_SIZE / 2)) {
1395 if (d[n] && d[n + 1] == 0xA6) {
1396 return true;
1399 return false;
1402 // block 7 decoder for PACS
1403 static int iclass_decode_credentials_new_pacs(uint8_t *d) {
1405 uint8_t offset = 0;
1406 while (d[offset] == 0 && (offset < PICOPASS_BLOCK_SIZE / 2)) {
1407 offset++;
1410 uint8_t pad = d[offset];
1412 PrintAndLogEx(INFO, "%u , %u", offset, pad);
1414 char *binstr = (char *)calloc((PICOPASS_BLOCK_SIZE * 8) + 1, sizeof(uint8_t));
1415 if (binstr == NULL) {
1416 return PM3_EMALLOC;
1419 uint8_t n = PICOPASS_BLOCK_SIZE - offset - 2;
1420 bytes_2_binstr(binstr, d + offset + 2, n);
1422 PrintAndLogEx(NORMAL, "");
1423 PrintAndLogEx(SUCCESS, "PACS......... " _GREEN_("%s"), sprint_hex_inrow(d + offset + 2, n));
1424 PrintAndLogEx(SUCCESS, "padded bin... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr));
1426 binstr[strlen(binstr) - pad] = '\0';
1427 PrintAndLogEx(SUCCESS, "bin.......... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr));
1429 size_t hexlen = 0;
1430 uint8_t hex[16] = {0};
1431 binstr_2_bytes(hex, &hexlen, binstr);
1432 PrintAndLogEx(SUCCESS, "hex.......... " _GREEN_("%s"), sprint_hex_inrow(hex, hexlen));
1434 uint32_t top = 0, mid = 0, bot = 0;
1435 if (binstring_to_u96(&top, &mid, &bot, binstr) != strlen(binstr)) {
1436 PrintAndLogEx(ERR, "Binary string contains none <0|1> chars");
1437 free(binstr);
1438 return PM3_EINVARG;
1441 free(binstr);
1443 PrintAndLogEx(NORMAL, "");
1444 PrintAndLogEx(INFO, "Wiegand decode");
1445 wiegand_message_t packed = initialize_message_object(top, mid, bot, 0);
1446 HIDTryUnpack(&packed);
1448 return PM3_SUCCESS;
1451 static void iclass_decode_credentials(uint8_t *data) {
1452 picopass_hdr_t *hdr = (picopass_hdr_t *)data;
1453 if (memcmp(hdr->app_issuer_area, empty, PICOPASS_BLOCK_SIZE)) {
1454 // Not a Legacy or SR card, nothing to do here.
1455 return;
1458 BLOCK79ENCRYPTION encryption = (data[(6 * PICOPASS_BLOCK_SIZE) + 7] & 0x03);
1460 uint8_t *b7 = data + (PICOPASS_BLOCK_SIZE * 7);
1462 bool has_new_pacs = iclass_detect_new_pacs(b7);
1463 bool has_values = (memcmp(b7, empty, PICOPASS_BLOCK_SIZE) != 0) && (memcmp(b7, zeros, PICOPASS_BLOCK_SIZE) != 0);
1464 if (has_values && encryption == None) {
1466 // todo: remove preamble/sentinel
1467 PrintAndLogEx(INFO, "Block 7 decoder");
1469 if (has_new_pacs) {
1470 iclass_decode_credentials_new_pacs(b7);
1471 } else {
1472 char hexstr[16 + 1] = {0};
1473 hex_to_buffer((uint8_t *)hexstr, b7, PICOPASS_BLOCK_SIZE, sizeof(hexstr) - 1, 0, 0, true);
1475 uint32_t top = 0, mid = 0, bot = 0;
1476 hexstring_to_u96(&top, &mid, &bot, hexstr);
1478 char binstr[64 + 1];
1479 hextobinstring(binstr, hexstr);
1480 char *pbin = binstr;
1481 while (strlen(pbin) && *(++pbin) == '0');
1483 PrintAndLogEx(SUCCESS, "Binary..................... " _GREEN_("%s"), pbin);
1485 PrintAndLogEx(INFO, "Wiegand decode");
1486 wiegand_message_t packed = initialize_message_object(top, mid, bot, 0);
1487 HIDTryUnpack(&packed);
1490 } else {
1491 PrintAndLogEx(INFO, "No unencrypted legacy credential found");
1495 static int CmdHFiClassDecrypt(const char *Cmd) {
1496 CLIParserContext *clictx;
1497 CLIParserInit(&clictx, "hf iclass decrypt",
1498 "3DES decrypt data\n"
1499 "This is a naive implementation, it tries to decrypt every block after block 6.\n"
1500 "Correct behaviour would be to decrypt only the application areas where the key is valid,\n"
1501 "which is defined by the configuration block.\n"
1502 "\nOBS!\n"
1503 "In order to use this function, the file `iclass_decryptionkey.bin` must reside\n"
1504 "in the resources directory. The file must be 16 bytes binary data\n"
1505 "or...\n"
1506 "make sure your cardhelper is placed in the sim module",
1507 "hf iclass decrypt -f hf-iclass-AA162D30F8FF12F1-dump.bin\n"
1508 "hf iclass decrypt -f hf-iclass-AA162D30F8FF12F1-dump.bin -k 000102030405060708090a0b0c0d0e0f\n"
1509 "hf iclass decrypt -d 1122334455667788 -k 000102030405060708090a0b0c0d0e0f");
1511 void *argtable[] = {
1512 arg_param_begin,
1513 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
1514 arg_str0("d", "data", "<hex>", "3DES encrypted data"),
1515 arg_str0("k", "key", "<hex>", "3DES transport key"),
1516 arg_lit0("v", "verbose", "verbose output"),
1517 arg_lit0(NULL, "d6", "decode as block 6"),
1518 arg_lit0("z", "dense", "dense dump output style"),
1519 arg_lit0(NULL, "ns", "no save to file"),
1520 arg_param_end
1522 CLIExecWithReturn(clictx, Cmd, argtable, false);
1524 int fnlen = 0;
1525 char filename[FILE_PATH_SIZE] = {0};
1526 CLIParamStrToBuf(arg_get_str(clictx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
1528 int enc_data_len = 0;
1529 uint8_t enc_data[PICOPASS_BLOCK_SIZE] = {0};
1530 bool have_data = false;
1532 CLIGetHexWithReturn(clictx, 2, enc_data, &enc_data_len);
1534 int key_len = 0;
1535 uint8_t key[16] = {0};
1536 uint8_t *keyptr = NULL;
1537 bool have_key = false;
1539 CLIGetHexWithReturn(clictx, 3, key, &key_len);
1541 bool verbose = arg_get_lit(clictx, 4);
1542 bool use_decode6 = arg_get_lit(clictx, 5);
1543 bool dense_output = g_session.dense_output || arg_get_lit(clictx, 6);
1544 bool nosave = arg_get_lit(clictx, 7);
1545 CLIParserFree(clictx);
1547 // sanity checks
1548 if (enc_data_len > 0) {
1549 if (enc_data_len != PICOPASS_BLOCK_SIZE) {
1550 PrintAndLogEx(ERR, "Data must be 8 hex bytes (16 HEX symbols)");
1551 return PM3_EINVARG;
1553 have_data = true;
1556 if (key_len > 0) {
1557 if (key_len != 16) {
1558 PrintAndLogEx(ERR, "Transport key must be 16 hex bytes (32 HEX characters)");
1559 return PM3_EINVARG;
1561 have_key = true;
1564 size_t decryptedlen = 2048;
1565 uint8_t *decrypted = NULL;
1566 bool have_file = false;
1567 int res = PM3_SUCCESS;
1569 // if user supplied dump file, time to load it
1570 if (fnlen > 0) {
1572 // read dump file
1573 res = pm3_load_dump(filename, (void **)&decrypted, &decryptedlen, 2048);
1574 if (res != PM3_SUCCESS) {
1575 return res;
1578 have_file = true;
1581 // load transport key
1582 bool use_sc = false;
1583 if (have_key == false) {
1584 use_sc = IsCardHelperPresent(verbose);
1585 if (use_sc == false) {
1586 size_t keylen = 0;
1587 res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen);
1588 if (res != PM3_SUCCESS) {
1589 PrintAndLogEx(INFO, "Couldn't find any decryption methods");
1590 free(decrypted);
1591 return PM3_EINVARG;
1594 if (keylen != 16) {
1595 PrintAndLogEx(ERR, "Failed to load transport key from file");
1596 free(keyptr);
1597 free(decrypted);
1598 return PM3_EINVARG;
1600 memcpy(key, keyptr, sizeof(key));
1601 free(keyptr);
1605 // tripledes
1606 mbedtls_des3_context ctx;
1607 mbedtls_des3_set2key_dec(&ctx, key);
1609 // decrypt user supplied data
1610 if (have_data) {
1612 uint8_t dec_data[PICOPASS_BLOCK_SIZE] = {0};
1613 if (use_sc) {
1614 Decrypt(enc_data, dec_data);
1615 } else {
1616 mbedtls_des3_crypt_ecb(&ctx, enc_data, dec_data);
1619 PrintAndLogEx(SUCCESS, "encrypted... %s", sprint_hex_inrow(enc_data, sizeof(enc_data)));
1620 PrintAndLogEx(SUCCESS, "plain....... " _YELLOW_("%s"), sprint_hex_inrow(dec_data, sizeof(dec_data)));
1622 if (use_sc && use_decode6) {
1623 DecodeBlock6(dec_data);
1627 // decrypt dump file data
1628 if (have_file) {
1630 picopass_hdr_t *hdr = (picopass_hdr_t *)decrypted;
1632 uint8_t mem = hdr->conf.mem_config;
1633 uint8_t chip = hdr->conf.chip_config;
1634 uint8_t applimit = hdr->conf.app_limit;
1635 uint8_t kb = 2;
1636 uint8_t app_areas = 2;
1637 uint8_t books = 1;
1638 uint8_t pages = 1;
1639 getMemConfig(mem, chip, &app_areas, &kb, &books, &pages);
1641 BLOCK79ENCRYPTION aa1_encryption = (decrypted[(6 * PICOPASS_BLOCK_SIZE) + 7] & 0x03);
1643 uint8_t limit = MIN(applimit, decryptedlen / 8);
1645 if (decryptedlen / PICOPASS_BLOCK_SIZE != applimit) {
1646 PrintAndLogEx(WARNING, "Actual file len " _YELLOW_("%zu") " vs HID app-limit len " _YELLOW_("%u"), decryptedlen, applimit * PICOPASS_BLOCK_SIZE);
1647 PrintAndLogEx(INFO, "Setting limit to " _GREEN_("%u"), limit * PICOPASS_BLOCK_SIZE);
1650 //uint8_t numblocks4userid = GetNumberBlocksForUserId(decrypted + (6 * 8));
1652 bool decrypted_block789 = false;
1653 for (uint8_t blocknum = 0; blocknum < limit; ++blocknum) {
1655 uint16_t idx = blocknum * PICOPASS_BLOCK_SIZE;
1656 memcpy(enc_data, decrypted + idx, PICOPASS_BLOCK_SIZE);
1658 switch (aa1_encryption) {
1659 // Right now, only 3DES is supported
1660 case TRIPLEDES:
1661 // Decrypt block 7,8,9 if configured.
1662 if (blocknum > 6 && blocknum <= 9 && memcmp(enc_data, empty, PICOPASS_BLOCK_SIZE) != 0) {
1663 if (use_sc) {
1664 Decrypt(enc_data, decrypted + idx);
1665 } else {
1666 mbedtls_des3_crypt_ecb(&ctx, enc_data, decrypted + idx);
1668 decrypted_block789 = true;
1670 break;
1671 case DES:
1672 case RFU:
1673 case None:
1674 // Nothing to do for None anyway...
1675 default:
1676 continue;
1679 if (decrypted_block789) {
1680 // Set the 2 last bits of block6 to 0 to mark the data as decrypted
1681 decrypted[(6 * PICOPASS_BLOCK_SIZE) + 7] &= 0xFC;
1685 if (nosave) {
1686 PrintAndLogEx(INFO, "Called with no save option");
1687 PrintAndLogEx(NORMAL, "");
1688 } else {
1690 // use the first block (CSN) for filename
1691 char *fptr = calloc(50, sizeof(uint8_t));
1692 if (fptr == false) {
1693 PrintAndLogEx(WARNING, "Failed to allocate memory");
1694 free(decrypted);
1695 return PM3_EMALLOC;
1698 strcat(fptr, "hf-iclass-");
1699 FillFileNameByUID(fptr, hdr->csn, "-dump-decrypted", sizeof(hdr->csn));
1701 pm3_save_dump(fptr, decrypted, decryptedlen, jsfIclass);
1702 free(fptr);
1705 printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen, dense_output);
1707 if (verbose) {
1708 print_iclass_sio(decrypted, decryptedlen);
1711 PrintAndLogEx(NORMAL, "");
1713 // decode block 6
1714 bool has_values = (memcmp(decrypted + (PICOPASS_BLOCK_SIZE * 6), empty, 8) != 0) && (memcmp(decrypted + (PICOPASS_BLOCK_SIZE * 6), zeros, PICOPASS_BLOCK_SIZE) != 0);
1715 if (has_values && use_sc) {
1716 DecodeBlock6(decrypted + (PICOPASS_BLOCK_SIZE * 6));
1719 // decode block 7-8-9
1720 iclass_decode_credentials(decrypted);
1722 // decode block 9
1723 has_values = (memcmp(decrypted + (PICOPASS_BLOCK_SIZE * 9), empty, PICOPASS_BLOCK_SIZE) != 0) && (memcmp(decrypted + (PICOPASS_BLOCK_SIZE * 9), zeros, PICOPASS_BLOCK_SIZE) != 0);
1724 if (has_values && use_sc) {
1725 uint8_t usr_blk_len = GetNumberBlocksForUserId(decrypted + (PICOPASS_BLOCK_SIZE * 6));
1726 if (usr_blk_len < 3) {
1727 PrintAndLogEx(NORMAL, "");
1728 PrintAndLogEx(INFO, "Block 9 decoder");
1730 uint8_t pinsize = GetPinSize(decrypted + (PICOPASS_BLOCK_SIZE * 6));
1731 if (pinsize > 0) {
1733 uint64_t pin = bytes_to_num(decrypted + (PICOPASS_BLOCK_SIZE * 9), 5);
1734 char tmp[17] = {0};
1735 snprintf(tmp, sizeof(tmp), "%."PRIu64, BCD2DEC(pin));
1736 PrintAndLogEx(INFO, "PIN........................ " _GREEN_("%.*s"), pinsize, tmp);
1741 PrintAndLogEx(INFO, "-----------------------------------------------------------------");
1742 free(decrypted);
1745 mbedtls_des3_free(&ctx);
1746 return PM3_SUCCESS;
1749 static int CmdHFiClassEncryptBlk(const char *Cmd) {
1750 CLIParserContext *clictx;
1751 CLIParserInit(&clictx, "hf iclass encrypt",
1752 "3DES encrypt data\n"
1753 "OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside\n"
1754 "in the resources directory. The file should be 16 hex bytes of binary data",
1755 "hf iclass encrypt -d 0102030405060708\n"
1756 "hf iclass encrypt -d 0102030405060708 -k 00112233445566778899AABBCCDDEEFF");
1758 void *argtable[] = {
1759 arg_param_begin,
1760 arg_str1("d", "data", "<hex>", "data to encrypt"),
1761 arg_str0("k", "key", "<hex>", "3DES transport key"),
1762 arg_lit0("v", "verbose", "verbose output"),
1763 arg_param_end
1765 CLIExecWithReturn(clictx, Cmd, argtable, false);
1767 int blk_data_len = 0;
1768 uint8_t blk_data[8] = {0};
1770 CLIGetHexWithReturn(clictx, 1, blk_data, &blk_data_len);
1772 if (blk_data_len != 8) {
1773 PrintAndLogEx(ERR, "Block data must be 8 hex bytes (16 HEX symbols)");
1774 CLIParserFree(clictx);
1775 return PM3_EINVARG;
1778 int key_len = 0;
1779 uint8_t key[16] = {0};
1780 uint8_t *keyptr = NULL;
1781 bool have_key = false;
1783 CLIGetHexWithReturn(clictx, 2, key, &key_len);
1785 if (key_len > 0) {
1786 if (key_len != 16) {
1787 PrintAndLogEx(ERR, "Transport key must be 16 hex bytes (32 HEX characters)");
1788 CLIParserFree(clictx);
1789 return PM3_EINVARG;
1791 have_key = true;
1794 bool verbose = arg_get_lit(clictx, 3);
1796 CLIParserFree(clictx);
1798 bool use_sc = false;
1799 if (have_key == false) {
1800 use_sc = IsCardHelperPresent(verbose);
1801 if (use_sc == false) {
1802 size_t keylen = 0;
1803 int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen);
1804 if (res != PM3_SUCCESS) {
1805 PrintAndLogEx(ERR, "Failed to find any encryption methods");
1806 return PM3_EINVARG;
1809 if (keylen != 16) {
1810 PrintAndLogEx(ERR, "Failed to load transport key from file");
1811 free(keyptr);
1812 return PM3_EINVARG;
1814 memcpy(key, keyptr, sizeof(key));
1815 free(keyptr);
1820 PrintAndLogEx(SUCCESS, "plain....... %s", sprint_hex_inrow(blk_data, sizeof(blk_data)));
1822 if (use_sc) {
1823 Encrypt(blk_data, blk_data);
1824 } else {
1825 iclass_encrypt_block_data(blk_data, key);
1828 PrintAndLogEx(SUCCESS, "encrypted... " _YELLOW_("%s"), sprint_hex_inrow(blk_data, sizeof(blk_data)));
1829 return PM3_SUCCESS;
1832 static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool verbose, bool shallow_mod) {
1834 iclass_card_select_t payload = {
1835 .flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE)
1838 if (shallow_mod) {
1839 payload.flags |= FLAG_ICLASS_READER_SHALLOW_MOD;
1842 clearCommandBuffer();
1843 PacketResponseNG resp;
1844 SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t *)&payload, sizeof(iclass_card_select_t));
1846 if (WaitForResponseTimeout(CMD_HF_ICLASS_READER, &resp, 2000) == false) {
1847 PrintAndLogEx(WARNING, "command execution time out");
1848 return false;
1851 iclass_card_select_resp_t *r = (iclass_card_select_resp_t *)resp.data.asBytes;
1852 picopass_hdr_t *hdr = &r->header.hdr;
1854 // no tag found or button pressed
1855 if (r->status == FLAG_ICLASS_NULL || resp.status == PM3_ERFTRANS) {
1856 if (verbose) {
1857 PrintAndLogEx(FAILED, "failed tag-select, aborting... (%d)", r->status);
1859 return false;
1862 if (CSN != NULL)
1863 memcpy(CSN, hdr->csn, 8);
1865 if (CCNR != NULL)
1866 memcpy(CCNR, hdr->epurse, 8);
1868 if (verbose) {
1869 PrintAndLogEx(SUCCESS, "CSN %s", sprint_hex(CSN, 8));
1870 PrintAndLogEx(SUCCESS, "epurse %s", sprint_hex(CCNR, 8));
1872 return true;
1875 static int CmdHFiClassDump(const char *Cmd) {
1876 CLIParserContext *ctx;
1877 CLIParserInit(&ctx, "hf iclass dump",
1878 "Dump all memory from a iCLASS tag",
1879 "hf iclass dump -k 001122334455667B\n"
1880 "hf iclass dump -k AAAAAAAAAAAAAAAA --credit 001122334455667B\n"
1881 "hf iclass dump -k AAAAAAAAAAAAAAAA --elite\n"
1882 "hf iclass dump --ki 0\n"
1883 "hf iclass dump --ki 0 --ci 2");
1885 void *argtable[] = {
1886 arg_param_begin,
1887 arg_str0("f", "file", "<fn>", "save filename"),
1888 arg_str0("k", "key", "<hex>", "debit key or NR/MAC for replay as 8 hex bytes"),
1889 arg_int0(NULL, "ki", "<dec>", "debit key index to select key from memory 'hf iclass managekeys'"),
1890 arg_str0(NULL, "credit", "<hex>", "credit key as 8 hex bytes"),
1891 arg_int0(NULL, "ci", "<dec>", "credit key index to select key from memory 'hf iclass managekeys'"),
1892 arg_lit0(NULL, "elite", "elite computations applied to key"),
1893 arg_lit0(NULL, "raw", "raw, the key is interpreted as raw block 3/4"),
1894 arg_lit0(NULL, "nr", "replay of NR/MAC"),
1895 arg_lit0("z", "dense", "dense dump output style"),
1896 arg_lit0(NULL, "force", "force unsecure card read"),
1897 arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
1898 arg_lit0(NULL, "ns", "no save to file"),
1899 arg_param_end
1901 CLIExecWithReturn(ctx, Cmd, argtable, true);
1903 int fnlen = 0;
1904 char filename[FILE_PATH_SIZE] = {0};
1905 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
1907 int key_len = 0;
1908 uint8_t key[8] = {0};
1909 bool auth = false;
1911 CLIGetHexWithReturn(ctx, 2, key, &key_len);
1913 int deb_key_nr = arg_get_int_def(ctx, 3, -1);
1915 if (key_len > 0 && deb_key_nr >= 0) {
1916 PrintAndLogEx(ERR, "Please specify debit key or index, not both");
1917 CLIParserFree(ctx);
1918 return PM3_EINVARG;
1921 if (key_len > 0) {
1922 auth = true;
1923 if (key_len != 8) {
1924 PrintAndLogEx(ERR, "Debit key is incorrect length");
1925 CLIParserFree(ctx);
1926 return PM3_EINVARG;
1930 if (deb_key_nr >= 0) {
1931 if (deb_key_nr < ICLASS_KEYS_MAX) {
1932 auth = true;
1933 memcpy(key, iClass_Key_Table[deb_key_nr], 8);
1934 PrintAndLogEx(SUCCESS, "Using AA1 (debit) key[%d] " _GREEN_("%s"), deb_key_nr, sprint_hex(iClass_Key_Table[deb_key_nr], 8));
1935 } else {
1936 PrintAndLogEx(ERR, "Key number is invalid");
1937 CLIParserFree(ctx);
1938 return PM3_EINVARG;
1942 int credit_key_len = 0;
1943 uint8_t credit_key[8] = {0};
1944 bool have_credit_key = false;
1946 CLIGetHexWithReturn(ctx, 4, credit_key, &credit_key_len);
1948 int credit_key_nr = arg_get_int_def(ctx, 5, -1);
1950 if (credit_key_len > 0 && credit_key_nr >= 0) {
1951 PrintAndLogEx(ERR, "Please specify credit key or index, not both");
1952 CLIParserFree(ctx);
1953 return PM3_EINVARG;
1956 if (credit_key_len > 0) {
1957 auth = true;
1958 have_credit_key = true;
1959 if (credit_key_len != 8) {
1960 PrintAndLogEx(ERR, "Credit key is incorrect length");
1961 CLIParserFree(ctx);
1962 return PM3_EINVARG;
1966 if (credit_key_nr >= 0) {
1967 if (credit_key_nr < ICLASS_KEYS_MAX) {
1968 auth = true;
1969 have_credit_key = true;
1970 memcpy(credit_key, iClass_Key_Table[credit_key_nr], 8);
1971 PrintAndLogEx(SUCCESS, "Using AA2 (credit) key[%d] " _GREEN_("%s"), credit_key_nr, sprint_hex(iClass_Key_Table[credit_key_nr], 8));
1972 } else {
1973 PrintAndLogEx(ERR, "Key number is invalid");
1974 CLIParserFree(ctx);
1975 return PM3_EINVARG;
1979 bool elite = arg_get_lit(ctx, 6);
1980 bool rawkey = arg_get_lit(ctx, 7);
1981 bool use_replay = arg_get_lit(ctx, 8);
1982 bool dense_output = g_session.dense_output || arg_get_lit(ctx, 9);
1983 bool force = arg_get_lit(ctx, 10);
1984 bool shallow_mod = arg_get_lit(ctx, 11);
1985 bool nosave = arg_get_lit(ctx, 12);
1987 CLIParserFree(ctx);
1989 if ((use_replay + rawkey + elite) > 1) {
1990 PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw', 'nr'");
1991 return PM3_EINVARG;
1994 uint8_t app_limit1 = 0, app_limit2 = 0;
1996 //get CSN and config
1997 uint8_t tag_data[0x100 * 8];
1998 memset(tag_data, 0xFF, sizeof(tag_data));
2000 iclass_card_select_t payload_rdr = {
2001 .flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE)
2004 if (shallow_mod) {
2005 payload_rdr.flags |= FLAG_ICLASS_READER_SHALLOW_MOD;
2008 clearCommandBuffer();
2009 PacketResponseNG resp;
2010 SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t *)&payload_rdr, sizeof(iclass_card_select_t));
2012 if (WaitForResponseTimeout(CMD_HF_ICLASS_READER, &resp, 2000) == false) {
2013 PrintAndLogEx(WARNING, "command execution time out");
2014 DropField();
2015 return PM3_ESOFT;
2017 DropField();
2019 if (resp.status == PM3_ERFTRANS) {
2020 PrintAndLogEx(FAILED, "no tag found");
2021 DropField();
2022 return PM3_ESOFT;
2025 iclass_card_select_resp_t *r = (iclass_card_select_resp_t *)resp.data.asBytes;
2026 if (r->status == FLAG_ICLASS_NULL) {
2027 PrintAndLogEx(FAILED, "failed to read block 0,1,2");
2028 return PM3_ESOFT;
2031 picopass_hdr_t *hdr = &r->header.hdr;
2032 uint8_t pagemap = get_pagemap(hdr);
2034 if (r->status & (FLAG_ICLASS_CSN | FLAG_ICLASS_CONF | FLAG_ICLASS_CC)) {
2036 memcpy(tag_data, hdr, 24);
2038 uint8_t type = get_mem_config(hdr);
2040 // tags configured for NON SECURE PAGE, acts different
2041 if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
2043 PrintAndLogEx(INFO, "Card in non-secure page mode detected");
2045 app_limit1 = card_app2_limit[type];
2046 app_limit2 = 0;
2047 } else if (hdr->conf.app_limit >= hdr->conf.mem_config) {
2048 PrintAndLogEx(WARNING, "AA1 config is >= card size, using card size as AA1 limit");
2049 app_limit1 = card_app2_limit[type];
2050 } else {
2051 app_limit1 = hdr->conf.app_limit;
2052 app_limit2 = card_app2_limit[type];
2057 if (force) {
2058 pagemap = PICOPASS_NON_SECURE_PAGEMODE;
2059 PrintAndLogEx(INFO, "Forcing NON SECURE PAGE dumping");
2062 if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
2063 PrintAndLogEx(INFO, "Dumping all available memory, block 3 - %u (0x%02x)", app_limit1, app_limit1);
2064 if (auth) {
2065 PrintAndLogEx(INFO, "No keys needed, ignoring user supplied key");
2067 } else {
2068 if (auth == false) {
2069 PrintAndLogEx(FAILED, "Run command with keys");
2070 return PM3_ESOFT;
2073 if (app_limit2 != 0) {
2074 PrintAndLogEx(INFO, "Card has at least 2 application areas. AA1 limit %u (0x%02X) AA2 limit %u (0x%02X)", app_limit1, app_limit1, app_limit2, app_limit2);
2075 } else {
2076 PrintAndLogEx(INFO, "Card has 1 application area. AA1 limit %u (0x%02X)", app_limit1, app_limit1);
2080 iclass_dump_req_t payload = {
2081 .req.use_raw = rawkey,
2082 .req.use_elite = elite,
2083 .req.use_credit_key = false,
2084 .req.use_replay = use_replay,
2085 .req.send_reply = true,
2086 .req.do_auth = auth,
2087 .req.shallow_mod = shallow_mod,
2088 .end_block = app_limit1,
2090 memcpy(payload.req.key, key, 8);
2092 // tags configured for NON SECURE PAGE, acts different
2093 if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
2094 payload.start_block = 3;
2095 payload.req.do_auth = false;
2096 } else {
2097 payload.start_block = 5;
2100 clearCommandBuffer();
2101 SendCommandNG(CMD_HF_ICLASS_DUMP, (uint8_t *)&payload, sizeof(payload));
2103 while (true) {
2105 PrintAndLogEx(NORMAL, "." NOLF);
2106 if (kbd_enter_pressed()) {
2107 PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
2108 DropField();
2109 return PM3_EOPABORTED;
2112 if (WaitForResponseTimeout(CMD_HF_ICLASS_DUMP, &resp, 2000))
2113 break;
2116 PrintAndLogEx(NORMAL, "");
2117 if (resp.status != PM3_SUCCESS) {
2118 PrintAndLogEx(ERR, "failed to communicate with card");
2119 return resp.status;
2122 struct p_resp {
2123 bool isOK;
2124 uint16_t block_cnt;
2125 uint32_t bb_offset;
2126 } PACKED;
2127 struct p_resp *packet = (struct p_resp *)resp.data.asBytes;
2129 if (packet->isOK == false) {
2130 PrintAndLogEx(WARNING, "read AA1 blocks failed");
2131 return PM3_ESOFT;
2134 uint32_t startindex = packet->bb_offset;
2135 uint32_t blocks_read = packet->block_cnt;
2137 uint8_t tempbuf[0x100 * 8];
2139 // response ok - now get bigbuf content of the dump
2140 if (!GetFromDevice(BIG_BUF, tempbuf, sizeof(tempbuf), startindex, NULL, 0, NULL, 2500, false)) {
2141 PrintAndLogEx(WARNING, "command execution time out");
2142 return PM3_ETIMEOUT;
2145 if (pagemap != PICOPASS_NON_SECURE_PAGEMODE) {
2146 // div key KD
2147 memcpy(tag_data + (PICOPASS_BLOCK_SIZE * 3),
2148 tempbuf + (PICOPASS_BLOCK_SIZE * 3), PICOPASS_BLOCK_SIZE);
2150 // all memory available
2151 memcpy(tag_data + (PICOPASS_BLOCK_SIZE * payload.start_block),
2152 tempbuf + (PICOPASS_BLOCK_SIZE * payload.start_block),
2153 blocks_read * PICOPASS_BLOCK_SIZE);
2155 uint16_t bytes_got = (app_limit1 + 1) * 8;
2157 // try AA2 Kc, Credit
2158 bool aa2_success = false;
2160 if (have_credit_key && pagemap != PICOPASS_NON_SECURE_PAGEMODE && app_limit2 != 0) {
2162 // AA2 authenticate credit key
2163 memcpy(payload.req.key, credit_key, 8);
2165 payload.req.use_credit_key = true;
2166 payload.start_block = app_limit1 + 1;
2167 payload.end_block = app_limit2;
2168 payload.req.do_auth = true;
2170 clearCommandBuffer();
2171 SendCommandNG(CMD_HF_ICLASS_DUMP, (uint8_t *)&payload, sizeof(payload));
2173 while (true) {
2174 PrintAndLogEx(NORMAL, "." NOLF);
2175 if (kbd_enter_pressed()) {
2176 PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
2177 DropField();
2178 return PM3_EOPABORTED;
2181 if (WaitForResponseTimeout(CMD_HF_ICLASS_DUMP, &resp, 2000))
2182 break;
2184 PrintAndLogEx(NORMAL, "");
2185 if (resp.status != PM3_SUCCESS) {
2186 PrintAndLogEx(ERR, "failed to communicate with card");
2187 goto write_dump;
2190 packet = (struct p_resp *)resp.data.asBytes;
2191 if (packet->isOK == false) {
2192 PrintAndLogEx(WARNING, "failed read block using credit key");
2193 goto write_dump;
2196 blocks_read = packet->block_cnt;
2197 startindex = packet->bb_offset;
2199 if (blocks_read * 8 > sizeof(tag_data) - bytes_got) {
2200 PrintAndLogEx(WARNING, "data exceeded buffer size! ");
2201 blocks_read = (sizeof(tag_data) - bytes_got) / 8;
2204 // get dumped data from bigbuf
2205 if (!GetFromDevice(BIG_BUF, tempbuf, sizeof(tempbuf), startindex, NULL, 0, NULL, 2500, false)) {
2206 PrintAndLogEx(WARNING, "command execution time out");
2207 goto write_dump;
2210 // div key KC
2211 memcpy(tag_data + (PICOPASS_BLOCK_SIZE * 4), tempbuf + (PICOPASS_BLOCK_SIZE * 4), PICOPASS_BLOCK_SIZE);
2213 // AA2 data
2214 memcpy(tag_data + (PICOPASS_BLOCK_SIZE * payload.start_block),
2215 tempbuf + (PICOPASS_BLOCK_SIZE * payload.start_block),
2216 blocks_read * PICOPASS_BLOCK_SIZE);
2218 bytes_got += (blocks_read * PICOPASS_BLOCK_SIZE);
2220 aa2_success = true;
2223 write_dump:
2225 if (have_credit_key && pagemap != 0x01 && aa2_success == false) {
2226 PrintAndLogEx(INFO, "Reading AA2 failed. dumping AA1 data to file");
2229 // print the dump
2230 printIclassDumpContents(tag_data, 1, (bytes_got / 8), bytes_got, dense_output);
2232 if (nosave) {
2233 PrintAndLogEx(INFO, "Called with no save option");
2234 PrintAndLogEx(NORMAL, "");
2235 return PM3_SUCCESS;
2238 // use CSN as filename
2239 if (filename[0] == 0) {
2240 strcat(filename, "hf-iclass-");
2241 FillFileNameByUID(filename, tag_data, "-dump", 8);
2244 // save the dump to .bin file
2245 PrintAndLogEx(SUCCESS, "saving dump file - %u blocks read", bytes_got / 8);
2247 pm3_save_dump(filename, tag_data, bytes_got, jsfIclass);
2249 PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass decrypt -f") "` to decrypt dump file");
2250 PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view -f") "` to view dump file");
2251 PrintAndLogEx(NORMAL, "");
2252 return PM3_SUCCESS;
2255 static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *macdata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool replay, bool verbose, bool use_secure_pagemode, bool shallow_mod) {
2257 iclass_writeblock_req_t payload = {
2258 .req.use_raw = rawkey,
2259 .req.use_elite = elite,
2260 .req.use_credit_key = use_credit_key,
2261 .req.use_replay = replay,
2262 .req.blockno = blockno,
2263 .req.send_reply = true,
2264 .req.do_auth = use_secure_pagemode,
2265 .req.shallow_mod = shallow_mod,
2267 memcpy(payload.req.key, KEY, 8);
2268 memcpy(payload.data, bldata, sizeof(payload.data));
2270 if (replay) {
2271 memcpy(payload.mac, macdata, sizeof(payload.mac));
2274 clearCommandBuffer();
2275 SendCommandNG(CMD_HF_ICLASS_WRITEBL, (uint8_t *)&payload, sizeof(payload));
2276 PacketResponseNG resp;
2278 if (WaitForResponseTimeout(CMD_HF_ICLASS_WRITEBL, &resp, 2000) == 0) {
2279 if (verbose) PrintAndLogEx(WARNING, "command execution time out");
2280 return PM3_ETIMEOUT;
2283 if (resp.status != PM3_SUCCESS) {
2284 if (verbose) PrintAndLogEx(ERR, "failed to communicate with card");
2285 return resp.status;
2288 return (resp.data.asBytes[0] == 1) ? PM3_SUCCESS : PM3_ESOFT;
2291 static int CmdHFiClass_WriteBlock(const char *Cmd) {
2292 CLIParserContext *ctx;
2293 CLIParserInit(&ctx, "hf iclass wrbl",
2294 "Write data to an iCLASS tag",
2295 "hf iclass wrbl --blk 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B\n"
2296 "hf iclass wrbl --blk 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B --credit\n"
2297 "hf iclass wrbl --blk 10 -d AAAAAAAAAAAAAAAA --ki 0");
2299 void *argtable[] = {
2300 arg_param_begin,
2301 arg_str0("k", "key", "<hex>", "Access key as 8 hex bytes"),
2302 arg_int0(NULL, "ki", "<dec>", "Key index to select key from memory 'hf iclass managekeys'"),
2303 arg_int1(NULL, "blk", "<dec>", "block number"),
2304 arg_str1("d", "data", "<hex>", "data to write as 8 hex bytes"),
2305 arg_str0("m", "mac", "<hex>", "replay mac data (4 hex bytes)"),
2306 arg_lit0(NULL, "credit", "key is assumed to be the credit key"),
2307 arg_lit0(NULL, "elite", "elite computations applied to key"),
2308 arg_lit0(NULL, "raw", "no computations applied to key"),
2309 arg_lit0(NULL, "nr", "replay of NR/MAC"),
2310 arg_lit0("v", "verbose", "verbose output"),
2311 arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
2312 arg_param_end
2314 CLIExecWithReturn(ctx, Cmd, argtable, false);
2316 int key_len = 0;
2317 uint8_t key[8] = {0};
2319 CLIGetHexWithReturn(ctx, 1, key, &key_len);
2321 int key_nr = arg_get_int_def(ctx, 2, -1);
2323 if (key_len > 0 && key_nr >= 0) {
2324 PrintAndLogEx(ERR, "Please specify key or index, not both");
2325 CLIParserFree(ctx);
2326 return PM3_EINVARG;
2329 bool auth = false;
2331 if (key_len > 0) {
2332 auth = true;
2333 if (key_len != 8) {
2334 PrintAndLogEx(ERR, "Key is incorrect length");
2335 CLIParserFree(ctx);
2336 return PM3_EINVARG;
2338 } else if (key_nr >= 0) {
2339 if (key_nr < ICLASS_KEYS_MAX) {
2340 auth = true;
2341 memcpy(key, iClass_Key_Table[key_nr], 8);
2342 PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex(iClass_Key_Table[key_nr], 8));
2343 } else {
2344 PrintAndLogEx(ERR, "Key number is invalid");
2345 CLIParserFree(ctx);
2346 return PM3_EINVARG;
2350 int blockno = arg_get_int_def(ctx, 3, 0);
2352 int data_len = 0;
2353 uint8_t data[8] = {0};
2354 CLIGetHexWithReturn(ctx, 4, data, &data_len);
2356 if (data_len != 8) {
2357 PrintAndLogEx(ERR, "Data must be 8 hex bytes (16 hex symbols)");
2358 CLIParserFree(ctx);
2359 return PM3_EINVARG;
2362 int mac_len = 0;
2363 uint8_t mac[4] = {0};
2364 CLIGetHexWithReturn(ctx, 5, mac, &mac_len);
2366 if (mac_len) {
2367 if (mac_len != 4) {
2368 PrintAndLogEx(ERR, "MAC must be 4 hex bytes (8 hex symbols)");
2369 CLIParserFree(ctx);
2370 return PM3_EINVARG;
2375 bool use_credit_key = arg_get_lit(ctx, 6);
2376 bool elite = arg_get_lit(ctx, 7);
2377 bool rawkey = arg_get_lit(ctx, 8);
2378 bool use_replay = arg_get_lit(ctx, 9);
2379 bool verbose = arg_get_lit(ctx, 10);
2380 bool shallow_mod = arg_get_lit(ctx, 11);
2382 CLIParserFree(ctx);
2384 if ((use_replay + rawkey + elite) > 1) {
2385 PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw', 'nr'");
2386 return PM3_EINVARG;
2389 int isok = iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod);
2390 switch (isok) {
2391 case PM3_SUCCESS:
2392 PrintAndLogEx(SUCCESS, "Wrote block " _YELLOW_("%d") " / " _YELLOW_("0x%02X") " ( " _GREEN_("ok") " )", blockno, blockno);
2393 break;
2394 case PM3_ETEAROFF:
2395 if (verbose)
2396 PrintAndLogEx(INFO, "Writing tear off triggered");
2397 break;
2398 default:
2399 PrintAndLogEx(FAILED, "Writing failed");
2400 break;
2402 PrintAndLogEx(NORMAL, "");
2403 return isok;
2406 static int CmdHFiClassCreditEpurse(const char *Cmd) {
2407 CLIParserContext *ctx;
2408 CLIParserInit(&ctx, "hf iclass creditepurse",
2409 "Credit the epurse on an iCLASS tag. The provided key must be the credit key.\n"
2410 "The first two bytes of the epurse are the debit value (big endian) and may be any value except FFFF.\n"
2411 "The remaining two bytes of the epurse are the credit value and must be smaller than the previous value.",
2412 "hf iclass creditepurse -d FEFFFFFF -k 001122334455667B\n"
2413 "hf iclass creditepurse -d FEFFFFFF --ki 0");
2415 void *argtable[] = {
2416 arg_param_begin,
2417 arg_str0("k", "key", "<hex>", "Credit key as 8 hex bytes"),
2418 arg_int0(NULL, "ki", "<dec>", "Key index to select key from memory 'hf iclass managekeys'"),
2419 arg_str1("d", "data", "<hex>", "data to write as 8 hex bytes"),
2420 arg_lit0(NULL, "elite", "elite computations applied to key"),
2421 arg_lit0(NULL, "raw", "no computations applied to key"),
2422 arg_lit0("v", "verbose", "verbose output"),
2423 arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
2424 arg_param_end
2426 CLIExecWithReturn(ctx, Cmd, argtable, false);
2428 int key_len = 0;
2429 uint8_t key[8] = {0};
2431 CLIGetHexWithReturn(ctx, 1, key, &key_len);
2433 int key_nr = arg_get_int_def(ctx, 2, -1);
2435 if (key_len > 0 && key_nr >= 0) {
2436 PrintAndLogEx(ERR, "Please specify key or index, not both");
2437 CLIParserFree(ctx);
2438 return PM3_EINVARG;
2441 if (key_len > 0) {
2442 if (key_len != 8) {
2443 PrintAndLogEx(ERR, "Key is incorrect length");
2444 CLIParserFree(ctx);
2445 return PM3_EINVARG;
2447 } else if (key_nr >= 0) {
2448 if (key_nr < ICLASS_KEYS_MAX) {
2449 memcpy(key, iClass_Key_Table[key_nr], 8);
2450 PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex(iClass_Key_Table[key_nr], 8));
2451 } else {
2452 PrintAndLogEx(ERR, "Key number is invalid");
2453 CLIParserFree(ctx);
2454 return PM3_EINVARG;
2456 } else {
2457 PrintAndLogEx(ERR, "Key or key number must be provided");
2458 CLIParserFree(ctx);
2459 return PM3_EINVARG;
2462 int blockno = 2;
2464 int data_len = 0;
2465 uint8_t data[4] = {0};
2466 CLIGetHexWithReturn(ctx, 3, data, &data_len);
2468 if (data_len != 4) {
2469 PrintAndLogEx(ERR, "Data must be 4 hex bytes (8 hex symbols)");
2470 CLIParserFree(ctx);
2471 return PM3_EINVARG;
2474 bool elite = arg_get_lit(ctx, 4);
2475 bool rawkey = arg_get_lit(ctx, 5);
2476 bool verbose = arg_get_lit(ctx, 6);
2477 bool shallow_mod = arg_get_lit(ctx, 7);
2479 CLIParserFree(ctx);
2481 if ((rawkey + elite) > 1) {
2482 PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw'");
2483 return PM3_EINVARG;
2486 iclass_credit_epurse_t payload = {
2487 .req.use_raw = rawkey,
2488 .req.use_elite = elite,
2489 .req.use_credit_key = true,
2490 .req.use_replay = false,
2491 .req.blockno = blockno,
2492 .req.send_reply = true,
2493 .req.do_auth = true,
2494 .req.shallow_mod = shallow_mod,
2496 memcpy(payload.req.key, key, 8);
2497 memcpy(payload.epurse, data, sizeof(payload.epurse));
2499 clearCommandBuffer();
2500 SendCommandNG(CMD_HF_ICLASS_CREDIT_EPURSE, (uint8_t *)&payload, sizeof(payload));
2501 PacketResponseNG resp;
2503 int isok;
2504 if (WaitForResponseTimeout(CMD_HF_ICLASS_CREDIT_EPURSE, &resp, 2000) == 0) {
2505 if (verbose) PrintAndLogEx(WARNING, "command execution time out");
2506 isok = PM3_ETIMEOUT;
2507 } else if (resp.status != PM3_SUCCESS) {
2508 if (verbose) PrintAndLogEx(ERR, "failed to communicate with card");
2509 isok = resp.status;
2510 } else {
2511 isok = (resp.data.asBytes[0] == 1) ? PM3_SUCCESS : PM3_ESOFT;
2514 switch (isok) {
2515 case PM3_SUCCESS:
2516 PrintAndLogEx(SUCCESS, "Credited epurse successfully");
2517 break;
2518 case PM3_ETEAROFF:
2519 if (verbose)
2520 PrintAndLogEx(INFO, "Writing tear off triggered");
2521 break;
2522 default:
2523 PrintAndLogEx(FAILED, "Writing failed");
2524 break;
2526 return isok;
2529 static int CmdHFiClassRestore(const char *Cmd) {
2530 CLIParserContext *ctx;
2531 CLIParserInit(&ctx, "hf iclass restore",
2532 "Restore data from dumpfile (bin/eml/json) onto a iCLASS tag",
2533 "hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 6 --last 18 --ki 0\n"
2534 "hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 6 --last 18 --ki 0 --elite\n"
2535 "hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 6 --last 18 -k 1122334455667788 --elite\n"
2538 void *argtable[] = {
2539 arg_param_begin,
2540 arg_str1("f", "file", "<fn>", "specify a filename to restore"),
2541 arg_str0("k", "key", "<hex>", "Access key as 8 hex bytes"),
2542 arg_int0(NULL, "ki", "<dec>", "Key index to select key from memory 'hf iclass managekeys'"),
2543 arg_int1(NULL, "first", "<dec>", "The first block number to restore"),
2544 arg_int1(NULL, "last", "<dec>", "The last block number to restore"),
2545 arg_lit0(NULL, "credit", "key is assumed to be the credit key"),
2546 arg_lit0(NULL, "elite", "elite computations applied to key"),
2547 arg_lit0(NULL, "raw", "no computations applied to key"),
2548 arg_lit0("v", "verbose", "verbose output"),
2549 arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
2550 arg_param_end
2552 CLIExecWithReturn(ctx, Cmd, argtable, false);
2554 int fnlen = 0;
2555 char filename[FILE_PATH_SIZE] = {0};
2556 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
2558 int key_len = 0;
2559 uint8_t key[8] = {0};
2561 CLIGetHexWithReturn(ctx, 2, key, &key_len);
2563 int key_nr = arg_get_int_def(ctx, 3, -1);
2565 if (key_len > 0 && key_nr >= 0) {
2566 PrintAndLogEx(ERR, "Please specify key or index, not both");
2567 CLIParserFree(ctx);
2568 return PM3_EINVARG;
2571 if (key_len > 0) {
2572 if (key_len != 8) {
2573 PrintAndLogEx(ERR, "Key is incorrect length");
2574 CLIParserFree(ctx);
2575 return PM3_EINVARG;
2577 } else if (key_nr >= 0) {
2578 if (key_nr < ICLASS_KEYS_MAX) {
2579 memcpy(key, iClass_Key_Table[key_nr], 8);
2580 PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex(iClass_Key_Table[key_nr], 8));
2581 } else {
2582 PrintAndLogEx(ERR, "Key number is invalid");
2583 CLIParserFree(ctx);
2584 return PM3_EINVARG;
2586 } else {
2587 PrintAndLogEx(ERR, "Please specify a key or key index");
2588 CLIParserFree(ctx);
2589 return PM3_EINVARG;
2592 int startblock = arg_get_int_def(ctx, 4, 0);
2593 int endblock = arg_get_int_def(ctx, 5, 0);
2595 bool use_credit_key = arg_get_lit(ctx, 6);
2596 bool elite = arg_get_lit(ctx, 7);
2597 bool rawkey = arg_get_lit(ctx, 8);
2598 bool verbose = arg_get_lit(ctx, 9);
2599 bool shallow_mod = arg_get_lit(ctx, 10);
2601 CLIParserFree(ctx);
2603 if (rawkey + elite > 1) {
2604 PrintAndLogEx(FAILED, "Can not use both 'e', 'r'");
2605 return PM3_EINVARG;
2608 if (startblock < 5) {
2609 PrintAndLogEx(WARNING, "you cannot write key blocks this way. yet... make your start block > 4");
2610 return PM3_EINVARG;
2613 uint32_t payload_size = sizeof(iclass_restore_req_t) + (sizeof(iclass_restore_item_t) * (endblock - startblock + 1));
2615 if (payload_size > PM3_CMD_DATA_SIZE) {
2616 PrintAndLogEx(NORMAL, "Trying to write too many blocks at once. Max: %d", PM3_CMD_DATA_SIZE / 8);
2617 return PM3_EINVARG;
2620 // read dump file
2621 uint8_t *dump = NULL;
2622 size_t bytes_read = 2048;
2623 int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, 2048);
2624 if (res != PM3_SUCCESS) {
2625 return res;
2628 if (bytes_read == 0) {
2629 PrintAndLogEx(ERR, "file reading error");
2630 free(dump);
2631 return PM3_EFILE;
2634 if (bytes_read < ((endblock - startblock + 1) * 8)) {
2635 PrintAndLogEx(ERR, "file is smaller than your suggested block range ( " _RED_("0x%02x..0x%02x")" )",
2636 startblock, endblock
2638 free(dump);
2639 return PM3_EFILE;
2642 iclass_restore_req_t *payload = calloc(1, payload_size);
2643 payload->req.use_raw = rawkey;
2644 payload->req.use_elite = elite;
2645 payload->req.use_credit_key = use_credit_key;
2646 payload->req.use_replay = false;
2647 payload->req.blockno = startblock;
2648 payload->req.send_reply = true;
2649 payload->req.do_auth = true;
2650 payload->req.shallow_mod = shallow_mod;
2651 memcpy(payload->req.key, key, 8);
2653 payload->item_cnt = (endblock - startblock + 1);
2655 // read data from file from block 6 --- 19
2656 // we will use this struct [data 8 bytes][MAC 4 bytes] for each block calculate all mac number for each data
2657 // then copy to usbcommand->asbytes;
2658 // max is 32 - 6 = 28 block. 28 x 12 bytes gives 336 bytes
2660 for (uint8_t i = 0; i < payload->item_cnt; i++) {
2661 payload->blocks[i].blockno = startblock + i;
2662 memcpy(payload->blocks[i].data, dump + (startblock * 8) + (i * 8), sizeof(payload->blocks[i].data));
2665 free(dump);
2667 if (verbose) {
2668 PrintAndLogEx(INFO, "Preparing to restore block range %02d..%02d", startblock, endblock);
2670 PrintAndLogEx(INFO, "---------+----------------------");
2671 PrintAndLogEx(INFO, " block# | data");
2672 PrintAndLogEx(INFO, "---------+----------------------");
2674 for (uint8_t i = 0; i < payload->item_cnt; i++) {
2675 iclass_restore_item_t item = payload->blocks[i];
2676 PrintAndLogEx(INFO, "%3d/0x%02X | %s", item.blockno, item.blockno, sprint_hex_inrow(item.data, sizeof(item.data)));
2680 PrintAndLogEx(INFO, "restore started...");
2682 PacketResponseNG resp;
2683 clearCommandBuffer();
2684 SendCommandNG(CMD_HF_ICLASS_RESTORE, (uint8_t *)payload, payload_size);
2686 if (WaitForResponseTimeout(CMD_HF_ICLASS_RESTORE, &resp, 2500) == 0) {
2687 PrintAndLogEx(WARNING, "command execution time out");
2688 DropField();
2689 free(payload);
2690 return PM3_ETIMEOUT;
2693 if (resp.status == PM3_SUCCESS) {
2694 PrintAndLogEx(SUCCESS, "iCLASS restore " _GREEN_("successful"));
2695 PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass rdbl") "` to verify data on card");
2696 } else {
2697 PrintAndLogEx(WARNING, "iCLASS restore " _RED_("failed"));
2700 free(payload);
2701 return resp.status;
2704 static int iclass_read_block_ex(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool replay, bool verbose,
2705 bool auth, bool shallow_mod, uint8_t *out, bool print) {
2707 iclass_auth_req_t payload = {
2708 .use_raw = rawkey,
2709 .use_elite = elite,
2710 .use_credit_key = (keyType == 0x18),
2711 .use_replay = replay,
2712 .blockno = blockno,
2713 .send_reply = true,
2714 .do_auth = auth,
2715 .shallow_mod = shallow_mod,
2717 memcpy(payload.key, KEY, 8);
2719 PacketResponseNG resp;
2720 clearCommandBuffer();
2721 SendCommandNG(CMD_HF_ICLASS_READBL, (uint8_t *)&payload, sizeof(payload));
2723 if (WaitForResponseTimeout(CMD_HF_ICLASS_READBL, &resp, 2000) == false) {
2724 if (verbose) PrintAndLogEx(WARNING, "command execution time out");
2725 return PM3_ETIMEOUT;
2728 if (resp.status != PM3_SUCCESS) {
2729 if (verbose) PrintAndLogEx(ERR, "failed to communicate with card");
2730 return PM3_EWRONGANSWER;
2733 // return data.
2734 iclass_readblock_resp_t *packet = (iclass_readblock_resp_t *)resp.data.asBytes;
2736 if (packet->isOK == false) {
2737 if (verbose) PrintAndLogEx(FAILED, "authentication error");
2738 return PM3_ESOFT;
2741 if (print) {
2742 PrintAndLogEx(NORMAL, "");
2743 PrintAndLogEx(SUCCESS, " block %3d/0x%02X : " _GREEN_("%s"), blockno, blockno, sprint_hex(packet->data, sizeof(packet->data)));
2744 PrintAndLogEx(NORMAL, "");
2747 if (out) {
2748 memcpy(out, packet->data, sizeof(packet->data));
2751 return PM3_SUCCESS;
2754 static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool replay, bool verbose,
2755 bool auth, bool shallow_mod, uint8_t *out) {
2756 return iclass_read_block_ex(KEY, blockno, keyType, elite, rawkey, replay, verbose, auth, shallow_mod, out, true);
2759 static int CmdHFiClass_ReadBlock(const char *Cmd) {
2760 CLIParserContext *ctx;
2761 CLIParserInit(&ctx, "hf iclass rdbl",
2762 "Read a iCLASS block from tag",
2763 "hf iclass rdbl --blk 6 -k 0011223344556677\n"
2764 "hf iclass rdbl --blk 27 -k 0011223344556677 --credit\n"
2765 "hf iclass rdbl --blk 10 --ki 0");
2767 void *argtable[] = {
2768 arg_param_begin,
2769 arg_str0("k", "key", "<hex>", "Access key as 8 hex bytes"),
2770 arg_int0(NULL, "ki", "<dec>", "Key index to select key from memory 'hf iclass managekeys'"),
2771 arg_int1(NULL, "blk", "<dec>", "Block number"),
2772 arg_lit0(NULL, "credit", "key is assumed to be the credit key"),
2773 arg_lit0(NULL, "elite", "elite computations applied to key"),
2774 arg_lit0(NULL, "raw", "no computations applied to key"),
2775 arg_lit0(NULL, "nr", "replay of NR/MAC"),
2776 arg_lit0("v", "verbose", "verbose output"),
2777 arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
2778 arg_param_end
2780 CLIExecWithReturn(ctx, Cmd, argtable, false);
2782 int key_len = 0;
2783 uint8_t key[8] = {0};
2785 CLIGetHexWithReturn(ctx, 1, key, &key_len);
2787 int key_nr = arg_get_int_def(ctx, 2, -1);
2789 if (key_len > 0 && key_nr >= 0) {
2790 PrintAndLogEx(ERR, "Please specify key or index, not both");
2791 CLIParserFree(ctx);
2792 return PM3_EINVARG;
2795 bool auth = false;
2797 if (key_len > 0) {
2798 auth = true;
2799 if (key_len != 8) {
2800 PrintAndLogEx(ERR, "Key is incorrect length");
2801 CLIParserFree(ctx);
2802 return PM3_EINVARG;
2804 } else if (key_nr >= 0) {
2805 if (key_nr < ICLASS_KEYS_MAX) {
2806 auth = true;
2807 memcpy(key, iClass_Key_Table[key_nr], 8);
2808 PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex(iClass_Key_Table[key_nr], 8));
2809 } else {
2810 PrintAndLogEx(ERR, "Key number is invalid");
2811 CLIParserFree(ctx);
2812 return PM3_EINVARG;
2816 int blockno = arg_get_int_def(ctx, 3, 0);
2818 uint8_t keyType = 0x88; //debit key
2819 if (arg_get_lit(ctx, 4)) {
2820 PrintAndLogEx(SUCCESS, "Using " _YELLOW_("credit") " key");
2821 keyType = 0x18; //credit key
2824 bool elite = arg_get_lit(ctx, 5);
2825 bool rawkey = arg_get_lit(ctx, 6);
2826 bool use_replay = arg_get_lit(ctx, 7);
2827 bool verbose = arg_get_lit(ctx, 8);
2828 bool shallow_mod = arg_get_lit(ctx, 9);
2830 CLIParserFree(ctx);
2832 if ((use_replay + rawkey + elite) > 1) {
2833 PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw', 'nr'");
2834 return PM3_EINVARG;
2837 if (verbose) {
2838 if (key_len > 0)
2839 PrintAndLogEx(SUCCESS, "Using key %s", sprint_hex(key, 8));
2842 if (auth == false && verbose) {
2843 PrintAndLogEx(WARNING, "warning: no authentication used with read. Typical for cards configured into `non-secure page`");
2847 uint8_t data[8] = {0};
2848 int res = iclass_read_block(key, blockno, keyType, elite, rawkey, use_replay, verbose, auth, shallow_mod, data);
2849 if (res != PM3_SUCCESS)
2850 return res;
2852 if (blockno < 6 || blockno > 7)
2853 return PM3_SUCCESS;
2855 if (memcmp(data, empty, 8) == 0)
2856 return PM3_SUCCESS;
2858 bool use_sc = IsCardHelperPresent(verbose);
2859 if (use_sc == false)
2860 return PM3_SUCCESS;
2862 // crypto helper available.
2863 PrintAndLogEx(INFO, "----------------------------- " _CYAN_("Cardhelper") " -----------------------------");
2865 switch (blockno) {
2866 case 6: {
2867 DecodeBlock6(data);
2868 break;
2870 case 7: {
2872 uint8_t dec_data[PICOPASS_BLOCK_SIZE];
2874 uint64_t a = bytes_to_num(data, PICOPASS_BLOCK_SIZE);
2875 bool starts = (leadingzeros(a) < 12);
2876 bool ones = (bitcount64(a) > 16 && bitcount64(a) < 48);
2878 if (starts && ones) {
2879 PrintAndLogEx(INFO, "data looks encrypted, False Positives " _YELLOW_("ARE") " possible");
2880 Decrypt(data, dec_data);
2881 PrintAndLogEx(SUCCESS, "decrypted : " _GREEN_("%s"), sprint_hex(dec_data, sizeof(dec_data)));
2882 } else {
2883 memcpy(dec_data, data, sizeof(dec_data));
2884 PrintAndLogEx(INFO, "data looks unencrypted, trying to decode");
2887 bool has_new_pacs = iclass_detect_new_pacs(dec_data);
2888 bool has_values = (memcmp(dec_data, empty, PICOPASS_BLOCK_SIZE) != 0) && (memcmp(dec_data, zeros, PICOPASS_BLOCK_SIZE) != 0);
2890 if (has_values) {
2892 if (has_new_pacs) {
2893 iclass_decode_credentials_new_pacs(dec_data);
2894 } else {
2895 //todo: remove preamble/sentinel
2896 uint32_t top = 0, mid = 0, bot = 0;
2898 char hexstr[16 + 1] = {0};
2899 hex_to_buffer((uint8_t *)hexstr, dec_data, PICOPASS_BLOCK_SIZE, sizeof(hexstr) - 1, 0, 0, true);
2900 hexstring_to_u96(&top, &mid, &bot, hexstr);
2902 char binstr[64 + 1];
2903 hextobinstring(binstr, hexstr);
2904 char *pbin = binstr;
2905 while (strlen(pbin) && *(++pbin) == '0');
2907 PrintAndLogEx(SUCCESS, " bin : %s", pbin);
2908 PrintAndLogEx(INFO, "");
2909 PrintAndLogEx(INFO, "------------------------------ " _CYAN_("Wiegand") " -------------------------------");
2910 wiegand_message_t packed = initialize_message_object(top, mid, bot, 0);
2911 HIDTryUnpack(&packed);
2913 } else {
2914 PrintAndLogEx(INFO, "no credential found");
2916 break;
2919 PrintAndLogEx(INFO, "----------------------------------------------------------------------");
2920 return PM3_SUCCESS;
2923 static int CmdHFiClass_loclass(const char *Cmd) {
2924 CLIParserContext *ctx;
2925 CLIParserInit(&ctx, "hf iclass loclass",
2926 "Execute the offline part of loclass attack\n"
2927 " An iclass dumpfile is assumed to consist of an arbitrary number of\n"
2928 " malicious CSNs, and their protocol responses\n"
2929 " The binary format of the file is expected to be as follows: \n"
2930 " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>\n"
2931 " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>\n"
2932 " <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>\n"
2933 " ... totalling N*24 bytes",
2934 "hf iclass loclass -f iclass_dump.bin\n"
2935 "hf iclass loclass --test");
2937 void *argtable[] = {
2938 arg_param_begin,
2939 arg_str0("f", "file", "<fn>", "filename with nr/mac data from `hf iclass sim -t 2` "),
2940 arg_lit0(NULL, "test", "Perform self test"),
2941 arg_lit0(NULL, "long", "Perform self test, including long ones"),
2942 arg_param_end
2944 CLIExecWithReturn(ctx, Cmd, argtable, false);
2946 int fnlen = 0;
2947 char filename[FILE_PATH_SIZE] = {0};
2948 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
2950 bool test = arg_get_lit(ctx, 2);
2951 bool longtest = arg_get_lit(ctx, 3);
2953 CLIParserFree(ctx);
2955 if (test || longtest) {
2956 int errors = testCipherUtils();
2957 errors += testMAC();
2958 errors += doKeyTests();
2959 errors += testElite(longtest);
2961 if (errors != PM3_SUCCESS)
2962 PrintAndLogEx(ERR, "There were errors!!!");
2964 return PM3_ESOFT;
2967 return bruteforceFileNoKeys(filename);
2970 static void detect_credential(uint8_t *iclass_dump, size_t dump_len, bool *is_legacy, bool *is_se, bool *is_sr, uint8_t **sio_start_ptr, size_t *sio_length) {
2971 *is_legacy = false;
2972 *is_sr = false;
2973 *is_se = false;
2974 if (sio_start_ptr != NULL) {
2975 *sio_start_ptr = NULL;
2977 if (sio_length != NULL) {
2978 *sio_length = 0;
2981 if (dump_len < sizeof(picopass_hdr_t)) {
2982 // Can't really do anything with a dump that doesn't include the header
2983 return;
2986 picopass_hdr_t *hdr = (picopass_hdr_t *)iclass_dump;
2988 if (!memcmp(hdr->app_issuer_area, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", PICOPASS_BLOCK_SIZE)) {
2989 // Legacy AIA
2990 *is_legacy = true;
2992 if (dump_len < 11 * PICOPASS_BLOCK_SIZE) {
2993 // Can't reliably detect if the card is SR without checking
2994 // blocks 6 and 10
2995 return;
2998 // SR bit set in legacy config block
2999 if ((iclass_dump[6 * PICOPASS_BLOCK_SIZE] & ICLASS_CFG_BLK_SR_BIT) == ICLASS_CFG_BLK_SR_BIT) {
3000 // If the card is blank (all FF's) then we'll reach here too, so check for an empty block 10
3001 // to avoid false positivies
3002 if (memcmp(iclass_dump + (10 * PICOPASS_BLOCK_SIZE), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", PICOPASS_BLOCK_SIZE)) {
3003 *is_sr = true;
3004 if (sio_start_ptr != NULL) {
3005 // SR SIO starts at block 10
3006 *sio_start_ptr = iclass_dump + (10 * PICOPASS_BLOCK_SIZE);
3010 } else if (!memcmp(hdr->app_issuer_area, "\xFF\xFF\xFF\x00\x06\xFF\xFF\xFF", PICOPASS_BLOCK_SIZE)) {
3011 // SE AIA
3012 *is_se = true;
3014 if (sio_start_ptr != NULL) {
3015 // SE SIO starts at block 6
3016 *sio_start_ptr = iclass_dump + (6 * PICOPASS_BLOCK_SIZE);
3020 if (sio_length == NULL || sio_start_ptr == NULL || *sio_start_ptr == NULL) {
3021 // No need to calculate length
3022 return;
3025 uint8_t *sio_start = *sio_start_ptr;
3027 if (sio_start[0] != 0x30) {
3028 // SIOs always start with a SEQUENCE(P), if this is missing then bail
3029 return;
3032 if (sio_start[1] >= 0x80 || sio_start[1] == 0x00) {
3033 // We only support definite short form lengths
3034 return;
3037 // Length of bytes within the SEQUENCE, plus tag and length bytes for the SEQUENCE tag
3038 *sio_length = sio_start[1] + 2;
3041 // print ASN1 decoded array in TLV view
3042 static void print_iclass_sio(uint8_t *iclass_dump, size_t dump_len) {
3043 bool is_legacy, is_se, is_sr;
3044 uint8_t *sio_start;
3045 size_t sio_length;
3046 detect_credential(iclass_dump, dump_len, &is_legacy, &is_se, &is_sr, &sio_start, &sio_length);
3048 if (sio_start == NULL) {
3049 return;
3052 if (dump_len < sio_length + (sio_start - iclass_dump)) {
3053 // SIO length exceeds the size of the dump we have, bail
3054 return;
3057 PrintAndLogEx(NORMAL, "");
3058 PrintAndLogEx(INFO, "---------------------------- " _CYAN_("SIO - RAW") " ----------------------------");
3059 print_hex_noascii_break(sio_start, sio_length, 32);
3060 PrintAndLogEx(NORMAL, "");
3061 PrintAndLogEx(INFO, "------------------------- " _CYAN_("SIO - ASN1 TLV") " --------------------------");
3062 asn1_print(sio_start, sio_length, " ");
3063 PrintAndLogEx(NORMAL, "");
3066 void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize, bool dense_output) {
3068 picopass_hdr_t *hdr = (picopass_hdr_t *)iclass_dump;
3069 // picopass_ns_hdr_t *ns_hdr = (picopass_ns_hdr_t *)iclass_dump;
3070 // uint8_t pagemap = get_pagemap(hdr);
3071 // if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { }
3073 uint8_t lock = hdr->conf.block_writelock;
3075 // is chip in ReadOnly (RO)
3076 bool ro = ((lock & 0x80) == 0);
3078 uint8_t maxmemcount;
3079 uint8_t filemaxblock = filesize / 8;
3080 uint8_t mem_config = iclass_dump[13];
3082 if (mem_config & 0x80)
3083 maxmemcount = 255;
3084 else
3085 maxmemcount = 31;
3087 uint8_t pagemap = get_pagemap(hdr);
3089 if (startblock == 0) {
3090 if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
3091 startblock = 3;
3092 } else {
3093 startblock = 6;
3097 if ((endblock > maxmemcount) || (endblock == 0))
3098 endblock = maxmemcount;
3100 // remember endblock needs to relate to zero-index arrays.
3101 if (endblock > filemaxblock - 1)
3102 endblock = filemaxblock - 1;
3105 PrintAndLogEx(INFO, "startblock: %u, endblock: %u, filesize: %zu, maxmemcount: %u, filemaxblock: %u"
3106 , startblock
3107 , endblock
3108 , filesize
3109 , maxmemcount
3110 , filemaxblock
3114 bool is_legacy, is_se, is_sr;
3115 uint8_t *sio_start;
3116 size_t sio_length;
3117 detect_credential(iclass_dump, endblock * 8, &is_legacy, &is_se, &is_sr, &sio_start, &sio_length);
3119 bool is_legacy_decrypted = is_legacy && (iclass_dump[(6 * PICOPASS_BLOCK_SIZE) + 7] & 0x03) == 0x00;
3121 int sio_start_block = 0, sio_end_block = 0;
3122 if (sio_start && sio_length > 0) {
3123 sio_start_block = (sio_start - iclass_dump) / PICOPASS_BLOCK_SIZE;
3124 sio_end_block = sio_start_block + ((sio_length + PICOPASS_BLOCK_SIZE - 1) / PICOPASS_BLOCK_SIZE) - 1;
3127 int i = startblock;
3128 PrintAndLogEx(NORMAL, "");
3129 PrintAndLogEx(INFO, "--------------------------- " _CYAN_("Tag memory") " ----------------------------");
3130 PrintAndLogEx(NORMAL, "");
3131 PrintAndLogEx(INFO, " block# | data | ascii |lck| info");
3132 PrintAndLogEx(INFO, "---------+-------------------------+----------+---+----------------");
3133 PrintAndLogEx(INFO, " 0/0x00 | " _GREEN_("%s") "| " _GREEN_("%s") " | | CSN "
3134 , sprint_hex(iclass_dump, 8)
3135 , sprint_ascii(iclass_dump, 8)
3138 if (i != 1)
3139 PrintAndLogEx(INFO, " ......");
3141 bool in_repeated_block = false;
3142 while (i <= endblock) {
3143 uint8_t *blk = iclass_dump + (i * 8);
3145 bool bl_lock = false;
3146 if (ro == false) {
3147 switch (i) {
3148 case 12: {
3149 bl_lock = ((lock & 0x40) == 0);
3150 break;
3152 case 11: {
3153 bl_lock = ((lock & 0x20) == 0);
3154 break;
3156 case 10: {
3157 bl_lock = ((lock & 0x10) == 0);
3158 break;
3160 case 9: {
3161 bl_lock = ((lock & 0x08) == 0);
3162 break;
3164 case 8: {
3165 bl_lock = ((lock & 0x04) == 0);
3166 break;
3168 case 7: {
3169 bl_lock = ((lock & 0x02) == 0);
3170 break;
3172 case 6: {
3173 bl_lock = ((lock & 0x01) == 0);
3174 break;
3177 } else {
3178 bl_lock = true;
3181 const char *lockstr = (bl_lock) ? _RED_("x") : " ";
3183 const char *block_info;
3184 bool regular_print_block = false;
3185 if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
3186 const char *info_nonks[] = {"CSN", "Config", "AIA", "User"};
3187 if (i < 3) {
3188 block_info = info_nonks[i];
3189 } else {
3190 block_info = info_nonks[3];
3193 regular_print_block = true;
3194 } else {
3195 const char *info_ks[] = {"CSN", "Config", "E-purse", "Debit", "Credit", "AIA", "User", "User AA2"};
3197 if (i >= 6 && i <= 9 && is_legacy) {
3198 // legacy credential
3199 PrintAndLogEx(INFO, "%3d/0x%02X | " _YELLOW_("%s") "| " _YELLOW_("%s") " | %s | User / %s "
3202 , sprint_hex(blk, 8)
3203 , sprint_ascii(blk, 8)
3204 , lockstr
3205 , i == 6 ? "HID CFG" : (is_legacy_decrypted ? "Cred" : "Enc Cred")
3207 } else if (sio_start_block != 0 && i >= sio_start_block && i <= sio_end_block) {
3208 // SIO credential
3209 PrintAndLogEx(INFO, "%3d/0x%02X | " _CYAN_("%s") "| " _CYAN_("%s") " | %s | User / SIO / %s"
3212 , sprint_hex(blk, 8)
3213 , sprint_ascii(blk, 8)
3214 , lockstr
3215 , is_se ? "SE" : "SR"
3217 } else {
3218 if (i < 6) {
3219 block_info = info_ks[i];
3220 } else if (i > hdr->conf.app_limit) {
3221 block_info = info_ks[7];
3222 } else {
3223 block_info = info_ks[6];
3226 regular_print_block = true;
3230 if (regular_print_block) {
3231 // suppress repeating blocks, truncate as such that the first and last block with the same data is shown
3232 // but the blocks in between are replaced with a single line of "......" if dense_output is enabled
3233 if (dense_output && i > 6 && i < (endblock - 1) && !in_repeated_block && !memcmp(blk, blk - 8, 8) &&
3234 !memcmp(blk, blk + 8, 8) && !memcmp(blk, blk + 16, 8)) {
3235 // we're in a user block that isn't the first user block nor last two user blocks,
3236 // and the current block data is the same as the previous and next two block
3237 in_repeated_block = true;
3238 PrintAndLogEx(INFO, " ......");
3239 } else if (in_repeated_block && (memcmp(blk, blk + 8, 8) || i == endblock)) {
3240 // in a repeating block, but the next block doesn't match anymore, or we're at the end block
3241 in_repeated_block = false;
3244 if (in_repeated_block == false) {
3245 PrintAndLogEx(INFO,
3246 "%3d/0x%02X | %s | %s | %s",
3249 sprint_hex_ascii(blk, 8),
3250 lockstr,
3251 block_info);
3255 i++;
3257 PrintAndLogEx(INFO, "---------+-------------------------+----------+---+----------------");
3258 if (is_legacy)
3259 PrintAndLogEx(HINT, _YELLOW_("yellow") " = legacy credential");
3261 if (is_se)
3262 PrintAndLogEx(HINT, _CYAN_("cyan") " = SIO / SE credential");
3264 if (is_sr)
3265 PrintAndLogEx(HINT, _CYAN_("cyan") " = SIO / SR credential");
3267 PrintAndLogEx(NORMAL, "");
3270 static int CmdHFiClassView(const char *Cmd) {
3271 CLIParserContext *ctx;
3272 CLIParserInit(&ctx, "hf iclass view",
3273 "Print a iCLASS tag dump file (bin/eml/json)",
3274 "hf iclass view -f hf-iclass-AA162D30F8FF12F1-dump.bin\n"
3275 "hf iclass view --first 1 -f hf-iclass-AA162D30F8FF12F1-dump.bin\n\n"
3276 "If --first is not specified it will default to the first user block\n"
3277 "which is block 6 for secured chips or block 3 for non-secured chips");
3279 void *argtable[] = {
3280 arg_param_begin,
3281 arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
3282 arg_int0(NULL, "first", "<dec>", "Begin printing from this block (default first user block)"),
3283 arg_int0(NULL, "last", "<dec>", "End printing at this block (default 0, ALL)"),
3284 arg_lit0("v", "verbose", "verbose output"),
3285 arg_lit0("z", "dense", "dense dump output style"),
3286 arg_param_end
3288 CLIExecWithReturn(ctx, Cmd, argtable, false);
3290 int fnlen = 0;
3291 char filename[FILE_PATH_SIZE];
3292 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
3294 int startblock = arg_get_int_def(ctx, 2, 0);
3295 int endblock = arg_get_int_def(ctx, 3, 0);
3296 bool verbose = arg_get_lit(ctx, 4);
3297 bool dense_output = g_session.dense_output || arg_get_lit(ctx, 5);
3299 CLIParserFree(ctx);
3301 // read dump file
3302 uint8_t *dump = NULL;
3303 size_t bytes_read = 2048;
3304 int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, 2048);
3305 if (res != PM3_SUCCESS) {
3306 return res;
3309 if (verbose) {
3310 PrintAndLogEx(INFO, "File: " _YELLOW_("%s"), filename);
3311 PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, (uint16_t)(bytes_read >> 3), (uint16_t)(bytes_read >> 3));
3312 PrintAndLogEx(INFO, "Printing blocks from: " _YELLOW_("%02d") " to: " _YELLOW_("%02d"), (startblock == 0) ? 6 : startblock, endblock);
3315 PrintAndLogEx(NORMAL, "");
3316 print_picopass_header((picopass_hdr_t *) dump);
3317 print_picopass_info((picopass_hdr_t *) dump);
3318 printIclassDumpContents(dump, startblock, endblock, bytes_read, dense_output);
3319 iclass_decode_credentials(dump);
3321 if (verbose) {
3322 print_iclass_sio(dump, bytes_read);
3325 free(dump);
3326 return PM3_SUCCESS;
3329 void HFiClassCalcDivKey(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key, bool elite) {
3330 if (elite) {
3331 uint8_t keytable[128] = {0};
3332 uint8_t key_index[8] = {0};
3333 uint8_t key_sel[8] = { 0 };
3334 uint8_t key_sel_p[8] = { 0 };
3335 hash2(KEY, keytable);
3336 hash1(CSN, key_index);
3337 for (uint8_t i = 0; i < 8 ; i++)
3338 key_sel[i] = keytable[key_index[i]];
3340 //Permute from iclass format to standard format
3341 permutekey_rev(key_sel, key_sel_p);
3342 diversifyKey(CSN, key_sel_p, div_key);
3343 } else {
3344 diversifyKey(CSN, KEY, div_key);
3348 //when told CSN, oldkey, newkey, if new key is elite (elite), and if old key was elite (oldElite)
3349 //calculate and return xor_div_key (ready for a key write command)
3350 //print all div_keys if verbose
3351 static void HFiClassCalcNewKey(uint8_t *CSN, uint8_t *OLDKEY, uint8_t *NEWKEY, uint8_t *xor_div_key, bool elite, bool oldElite, bool verbose) {
3352 uint8_t old_div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
3353 uint8_t new_div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
3354 //get old div key
3355 HFiClassCalcDivKey(CSN, OLDKEY, old_div_key, oldElite);
3356 //get new div key
3357 HFiClassCalcDivKey(CSN, NEWKEY, new_div_key, elite);
3359 for (uint8_t i = 0; i < ARRAYLEN(old_div_key); i++) {
3360 xor_div_key[i] = old_div_key[i] ^ new_div_key[i];
3362 if (verbose) {
3363 PrintAndLogEx(SUCCESS, "Old div key......... %s", sprint_hex(old_div_key, 8));
3364 PrintAndLogEx(SUCCESS, "New div key......... %s", sprint_hex(new_div_key, 8));
3365 PrintAndLogEx(SUCCESS, "Xor div key......... " _YELLOW_("%s") "\n", sprint_hex(xor_div_key, 8));
3369 static int CmdHFiClassCalcNewKey(const char *Cmd) {
3370 CLIParserContext *ctx;
3371 CLIParserInit(&ctx, "hf iclass calcnewkey",
3372 "Calculate new keys for updating (blocks 3 & 4)",
3373 "hf iclass calcnewkey --old 1122334455667788 --new 2233445566778899 --csn deadbeafdeadbeaf --elite2 -> e key to e key given csn\n"
3374 "hf iclass calcnewkey --old 1122334455667788 --new 2233445566778899 --elite -> std key to e key read csn\n"
3375 "hf iclass calcnewkey --old 1122334455667788 --new 2233445566778899 -> std to std read csn");
3377 void *argtable[] = {
3378 arg_param_begin,
3379 arg_str0(NULL, "old", "<hex>", "Specify key as 8 hex bytes"),
3380 arg_int0(NULL, "oki", "<dec>", "Old key index to select key from memory 'hf iclass managekeys'"),
3381 arg_str0(NULL, "new", "<hex>", "Specify key as 8 hex bytes"),
3382 arg_int0(NULL, "nki", "<dec>", "New key index to select key from memory 'hf iclass managekeys'"),
3383 arg_str0(NULL, "csn", "<hex>", "Specify a Card Serial Number (CSN) to diversify the key (if omitted will attempt to read a CSN)"),
3384 arg_lit0(NULL, "elite", "Elite computations applied to new key"),
3385 arg_lit0(NULL, "elite2", "Elite computations applied to both old and new key"),
3386 arg_lit0(NULL, "oldelite", "Elite computations applied only to old key"),
3387 arg_param_end
3389 CLIExecWithReturn(ctx, Cmd, argtable, false);
3391 int old_key_len = 0;
3392 uint8_t old_key[8] = {0};
3393 CLIGetHexWithReturn(ctx, 1, old_key, &old_key_len);
3395 int old_key_nr = arg_get_int_def(ctx, 2, -1);
3397 if (old_key_len > 0 && old_key_nr >= 0) {
3398 PrintAndLogEx(ERR, "Please specify old key or index, not both");
3399 CLIParserFree(ctx);
3400 return PM3_EINVARG;
3403 if (old_key_len > 0) {
3404 if (old_key_len != 8) {
3405 PrintAndLogEx(ERR, "Old key is incorrect length");
3406 CLIParserFree(ctx);
3407 return PM3_EINVARG;
3409 } else if (old_key_nr >= 0) {
3410 if (old_key_nr < ICLASS_KEYS_MAX) {
3411 memcpy(old_key, iClass_Key_Table[old_key_nr], 8);
3412 PrintAndLogEx(SUCCESS, "Using old key[%d]... " _GREEN_("%s"), old_key_nr, sprint_hex(iClass_Key_Table[old_key_nr], 8));
3413 } else {
3414 PrintAndLogEx(ERR, "Key number is invalid");
3415 CLIParserFree(ctx);
3416 return PM3_EINVARG;
3418 } else {
3419 PrintAndLogEx(ERR, "Please specify an old key or old key index");
3420 CLIParserFree(ctx);
3421 return PM3_EINVARG;
3424 int new_key_len = 0;
3425 uint8_t new_key[8] = {0};
3426 CLIGetHexWithReturn(ctx, 3, new_key, &new_key_len);
3428 int new_key_nr = arg_get_int_def(ctx, 4, -1);
3430 if (new_key_len > 0 && new_key_nr >= 0) {
3431 PrintAndLogEx(ERR, "Please specify new key or index, not both");
3432 CLIParserFree(ctx);
3433 return PM3_EINVARG;
3436 if (new_key_len > 0) {
3437 if (new_key_len != 8) {
3438 PrintAndLogEx(ERR, "New key is incorrect length");
3439 CLIParserFree(ctx);
3440 return PM3_EINVARG;
3442 } else if (new_key_nr >= 0) {
3443 if (new_key_nr < ICLASS_KEYS_MAX) {
3444 memcpy(new_key, iClass_Key_Table[new_key_nr], 8);
3445 PrintAndLogEx(SUCCESS, "Using new key[%d]... " _GREEN_("%s"), new_key_nr, sprint_hex(iClass_Key_Table[new_key_nr], 8));
3446 } else {
3447 PrintAndLogEx(ERR, "Key number is invalid");
3448 CLIParserFree(ctx);
3449 return PM3_EINVARG;
3451 } else {
3452 PrintAndLogEx(ERR, "Please specify an new key or old key index");
3453 CLIParserFree(ctx);
3454 return PM3_EINVARG;
3457 int csn_len = 0;
3458 uint8_t csn[8] = {0};
3459 CLIGetHexWithReturn(ctx, 5, csn, &csn_len);
3460 bool givenCSN = false;
3462 if (csn_len > 0) {
3463 givenCSN = true;
3464 if (csn_len != 8) {
3465 PrintAndLogEx(ERR, "CSN is incorrect length");
3466 CLIParserFree(ctx);
3467 return PM3_EINVARG;
3471 bool elite = arg_get_lit(ctx, 6);
3472 bool old_elite = false;
3474 if (arg_get_lit(ctx, 7)) {
3475 elite = true;
3476 old_elite = true;
3479 if (arg_get_lit(ctx, 8)) {
3480 elite = false;
3481 old_elite = true;
3484 CLIParserFree(ctx);
3486 uint8_t xor_div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
3488 if (givenCSN == false) {
3489 uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
3490 if (select_only(csn, CCNR, true, false) == false) {
3491 DropField();
3492 return PM3_ESOFT;
3496 HFiClassCalcNewKey(csn, old_key, new_key, xor_div_key, elite, old_elite, true);
3498 return PM3_SUCCESS;
3501 static int iclass_load_keys(char *filename) {
3503 uint8_t *dump = NULL;
3504 size_t bytes_read = 0;
3505 if (loadFile_safe(filename, "", (void **)&dump, &bytes_read) != PM3_SUCCESS) {
3506 PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", filename);
3507 return PM3_EFILE;
3510 if (bytes_read > ICLASS_KEYS_MAX * PICOPASS_BLOCK_SIZE) {
3511 PrintAndLogEx(WARNING, "File is too long to load - bytes: %zu", bytes_read);
3512 free(dump);
3513 return PM3_EFILE;
3515 size_t i = 0;
3516 for (; i < bytes_read / PICOPASS_BLOCK_SIZE; i++) {
3517 memcpy(iClass_Key_Table[i], dump + (i * PICOPASS_BLOCK_SIZE), PICOPASS_BLOCK_SIZE);
3520 free(dump);
3521 PrintAndLogEx(SUCCESS, "Loaded " _GREEN_("%2zd") " keys from %s", i, filename);
3522 return PM3_SUCCESS;
3525 static int iclass_print_keys(void) {
3526 PrintAndLogEx(NORMAL, "");
3527 PrintAndLogEx(INFO, "idx| key");
3528 PrintAndLogEx(INFO, "---+------------------------");
3529 for (uint8_t i = 0; i < ICLASS_KEYS_MAX; i++) {
3530 if (memcmp(iClass_Key_Table[i], zeros, sizeof(zeros)) == 0)
3531 PrintAndLogEx(INFO, " %u |", i);
3532 else
3533 PrintAndLogEx(INFO, " %u | " _YELLOW_("%s"), i, sprint_hex(iClass_Key_Table[i], PICOPASS_BLOCK_SIZE));
3535 PrintAndLogEx(INFO, "---+------------------------");
3536 PrintAndLogEx(NORMAL, "");
3537 return PM3_SUCCESS;
3540 static int CmdHFiClassManageKeys(const char *Cmd) {
3541 CLIParserContext *ctx;
3542 CLIParserInit(&ctx, "hf iclass managekeys",
3543 "Manage iCLASS Keys in client memory",
3544 "hf iclass managekeys --ki 0 -k 1122334455667788 --> set key 1122334455667788 at index 0\n"
3545 "hf iclass managekeys -f mykeys.bin --save --> save key file\n"
3546 "hf iclass managekeys -f mykeys.bin --load --> load key file\n"
3547 "hf iclass managekeys -p --> print keys");
3549 void *argtable[] = {
3550 arg_param_begin,
3551 arg_str0("f", "file", "<fn>", "Specify a filename for load / save operations"),
3552 arg_str0("k", "key", "<hex>", "Access key as 8 hex bytes"),
3553 arg_int0(NULL, "ki", "<dec>", "Specify key index to set key in memory"),
3554 arg_lit0(NULL, "save", "Save keys in memory to file specified by filename"),
3555 arg_lit0(NULL, "load", "Load keys to memory from file specified by filename"),
3556 arg_lit0("p", "print", "Print keys loaded into memory"),
3557 arg_param_end
3559 CLIExecWithReturn(ctx, Cmd, argtable, false);
3561 int fnlen = 0;
3562 char filename[FILE_PATH_SIZE] = {0};
3563 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
3565 int key_len = 0;
3566 uint8_t key[8] = {0};
3567 CLIGetHexWithReturn(ctx, 2, key, &key_len);
3568 uint8_t operation = 0;
3570 if (key_len > 0) {
3571 operation += 3;
3572 if (key_len != 8) {
3573 PrintAndLogEx(ERR, "Key is incorrect length");
3574 CLIParserFree(ctx);
3575 return PM3_EINVARG;
3579 int key_nr = arg_get_int_def(ctx, 3, -1);
3581 if (key_nr >= 0) {
3582 if (key_nr < ICLASS_KEYS_MAX) {
3583 PrintAndLogEx(SUCCESS, "Current key[%d] " _YELLOW_("%s"), key_nr, sprint_hex_inrow(iClass_Key_Table[key_nr], 8));
3584 } else {
3585 PrintAndLogEx(ERR, "Key index is out-of-range");
3586 CLIParserFree(ctx);
3587 return PM3_EINVARG;
3591 if (arg_get_lit(ctx, 4)) { //save
3592 operation += 6;
3594 if (arg_get_lit(ctx, 5)) { //load
3595 operation += 5;
3597 if (arg_get_lit(ctx, 6)) { //print
3598 operation += 4;
3601 CLIParserFree(ctx);
3603 if (operation == 0) {
3604 PrintAndLogEx(ERR, "No operation specified (load, save, or print)\n");
3605 return PM3_EINVARG;
3607 if (operation > 6) {
3608 PrintAndLogEx(ERR, "Too many operations specified\n");
3609 return PM3_EINVARG;
3611 if (operation > 4 && fnlen == 0) {
3612 PrintAndLogEx(ERR, "You must enter a filename when loading or saving\n");
3613 return PM3_EINVARG;
3615 if (key_len > 0 && key_nr == -1) {
3616 PrintAndLogEx(ERR, "Please specify key index when specifying key");
3617 return PM3_EINVARG;
3620 switch (operation) {
3621 case 3:
3622 memcpy(iClass_Key_Table[key_nr], key, 8);
3623 PrintAndLogEx(SUCCESS, " New key[%d] " _GREEN_("%s"), key_nr, sprint_hex_inrow(iClass_Key_Table[key_nr], 8));
3624 return PM3_SUCCESS;
3625 case 4:
3626 return iclass_print_keys();
3627 case 5:
3628 return iclass_load_keys(filename);
3629 case 6: {
3630 bool isOK = saveFile(filename, ".bin", iClass_Key_Table, sizeof(iClass_Key_Table));
3631 if (isOK == false) {
3632 return PM3_EFILE;
3636 return PM3_SUCCESS;
3639 static void add_key(uint8_t *key) {
3641 uint8_t i;
3642 for (i = 0; i < ICLASS_KEYS_MAX; i++) {
3644 if (memcmp(iClass_Key_Table[i], key, 8) == 0) {
3645 PrintAndLogEx(SUCCESS, "Key already at keyslot " _GREEN_("%d"), i);
3646 break;
3649 if (memcmp(iClass_Key_Table[i], "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) {
3650 memcpy(iClass_Key_Table[i], key, 8);
3651 PrintAndLogEx(SUCCESS, "Added key to keyslot " _GREEN_("%d"), i);
3652 break;
3656 if (i == ICLASS_KEYS_MAX) {
3657 PrintAndLogEx(INFO, "Couldn't find an empty keyslot");
3658 } else {
3659 PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass managekeys -p") "` to view keys");
3663 static int CmdHFiClassCheckKeys(const char *Cmd) {
3664 CLIParserContext *ctx;
3665 CLIParserInit(&ctx, "hf iclass chk",
3666 "Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag",
3667 "hf iclass chk -f iclass_default_keys.dic\n"
3668 "hf iclass chk -f iclass_elite_keys.dic --elite\n"
3669 "hf iclass chk --vb6kdf\n");
3671 void *argtable[] = {
3672 arg_param_begin,
3673 arg_str0("f", "file", "<fn>", "Dictionary file with default iclass keys"),
3674 arg_lit0(NULL, "credit", "key is assumed to be the credit key"),
3675 arg_lit0(NULL, "elite", "elite computations applied to key"),
3676 arg_lit0(NULL, "raw", "no computations applied to key (raw)"),
3677 arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
3678 arg_lit0(NULL, "vb6kdf", "use the VB6 elite KDF instead of a file"),
3679 arg_param_end
3681 CLIExecWithReturn(ctx, Cmd, argtable, true);
3683 int fnlen = 0;
3684 char filename[FILE_PATH_SIZE] = {0};
3685 bool use_vb6kdf = arg_get_lit(ctx, 6);
3686 bool use_elite = arg_get_lit(ctx, 3);
3687 bool use_raw = arg_get_lit(ctx, 4);
3688 if (use_vb6kdf) {
3689 use_elite = true;
3690 } else {
3691 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
3694 bool use_credit_key = arg_get_lit(ctx, 2);
3695 bool shallow_mod = arg_get_lit(ctx, 5);
3697 CLIParserFree(ctx);
3699 uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
3700 uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
3702 // no filename and don't use algorithm for elite
3703 // just add the default dictionary
3704 if ((strlen(filename) == 0) && (use_vb6kdf == false)) {
3706 if (use_elite) {
3707 PrintAndLogEx(INFO, "Using default elite dictionary");
3708 snprintf(filename, sizeof(filename), ICLASS_DEFAULT_KEY_ELITE_DIC);
3709 } else {
3710 PrintAndLogEx(INFO, "Using default dictionary");
3711 snprintf(filename, sizeof(filename), ICLASS_DEFAULT_KEY_DIC);
3715 uint64_t t1 = msclock();
3717 // load keys
3718 uint8_t *keyBlock = NULL;
3719 uint32_t keycount = 0;
3721 if (use_vb6kdf) {
3722 // Generate 5000 keys using VB6 KDF
3723 keycount = 5000;
3724 keyBlock = calloc(1, keycount * 8);
3725 if (keyBlock == NULL) {
3726 return PM3_EMALLOC;
3729 picopass_elite_reset();
3730 for (uint32_t i = 0; i < keycount; i++) {
3731 picopass_elite_nextKey(keyBlock + (i * 8));
3733 } else {
3734 // Load keys
3735 int res = loadFileDICTIONARY_safe(filename, (void **)&keyBlock, 8, &keycount);
3736 if (res != PM3_SUCCESS || keycount == 0) {
3737 free(keyBlock);
3738 return res;
3742 // limit size of keys that can be held in memory
3743 if (keycount > 100000) {
3744 PrintAndLogEx(FAILED, "File contains more than 100 000 keys, aborting...");
3745 free(keyBlock);
3746 return PM3_EFILE;
3749 // Get CSN / UID and CCNR
3750 PrintAndLogEx(SUCCESS, "Reading tag CSN / CCNR...");
3752 bool got_csn = false;
3753 for (uint8_t i = 0; i < ICLASS_AUTH_RETRY; i++) {
3754 got_csn = select_only(CSN, CCNR, false, shallow_mod);
3755 if (got_csn == false)
3756 PrintAndLogEx(WARNING, "one more try");
3757 else
3758 break;
3761 if (got_csn == false) {
3762 PrintAndLogEx(WARNING, "Tried %d times. Can't select card, aborting...", ICLASS_AUTH_RETRY);
3763 free(keyBlock);
3764 DropField();
3765 return PM3_ESOFT;
3768 // allocate memory for the pre calculated macs
3769 iclass_premac_t *pre = calloc(keycount, sizeof(iclass_premac_t));
3770 if (pre == NULL) {
3771 PrintAndLogEx(WARNING, "failed to allocate memory");
3772 return PM3_EMALLOC;
3775 PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s"), sprint_hex(CSN, sizeof(CSN)));
3776 PrintAndLogEx(SUCCESS, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR)));
3778 PrintAndLogEx(INFO, "Generating diversified keys %s", (use_elite || use_raw) ? NOLF : "");
3780 if (use_elite)
3781 PrintAndLogEx(NORMAL, "using " _YELLOW_("elite algo"));
3783 if (use_raw)
3784 PrintAndLogEx(NORMAL, "using " _YELLOW_("raw mode"));
3786 GenerateMacFrom(CSN, CCNR, use_raw, use_elite, keyBlock, keycount, pre);
3788 PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key...", (use_credit_key) ? "CREDIT" : "DEBIT");
3790 // USB_COMMAND. 512/4 = 103 mac
3791 uint32_t max_chunk_size = 0;
3792 if (keycount > ((PM3_CMD_DATA_SIZE - sizeof(iclass_chk_t)) / 4))
3793 max_chunk_size = (PM3_CMD_DATA_SIZE - sizeof(iclass_chk_t)) / 4;
3794 else
3795 max_chunk_size = keycount;
3797 // fast push mode
3798 g_conn.block_after_ACK = true;
3800 // keep track of position of found key
3801 uint32_t chunk_offset = 0;
3802 uint8_t found_offset = 0;
3803 bool found_key = false;
3805 // We have
3806 // - a list of keys.
3807 // - a list of precalculated macs that corresponds to the key list
3808 // We send a chunk of macs to the device each time
3810 // main keychunk loop
3811 for (chunk_offset = 0; chunk_offset < keycount; chunk_offset += max_chunk_size) {
3813 if (kbd_enter_pressed()) {
3814 PrintAndLogEx(NORMAL, "");
3815 PrintAndLogEx(WARNING, "aborted via keyboard!");
3816 goto out;
3819 uint32_t curr_chunk_cnt = keycount - chunk_offset;
3820 if ((keycount - chunk_offset) > max_chunk_size) {
3821 curr_chunk_cnt = max_chunk_size;
3824 // last chunk?
3825 if (curr_chunk_cnt == keycount - chunk_offset) {
3826 // Disable fast mode on last command
3827 g_conn.block_after_ACK = false;
3830 uint32_t tmp_plen = sizeof(iclass_chk_t) + (4 * curr_chunk_cnt);
3831 iclass_chk_t *packet = calloc(tmp_plen, sizeof(uint8_t));
3832 if (packet == NULL) {
3833 PrintAndLogEx(WARNING, "failed to allocate memory");
3834 break;
3836 packet->use_credit_key = use_credit_key;
3837 packet->count = curr_chunk_cnt;
3838 packet->shallow_mod = shallow_mod;
3839 // copy chunk of pre calculated macs to packet
3840 memcpy(packet->items, (pre + chunk_offset), (4 * curr_chunk_cnt));
3842 clearCommandBuffer();
3843 SendCommandNG(CMD_HF_ICLASS_CHKKEYS, (uint8_t *)packet, tmp_plen);
3844 free(packet);
3846 bool looped = false;
3847 uint8_t timeout = 0;
3849 PacketResponseNG resp;
3850 while (WaitForResponseTimeout(CMD_HF_ICLASS_CHKKEYS, &resp, 2000) == false) {
3851 timeout++;
3852 PrintAndLogEx(NORMAL, "." NOLF);
3853 if (timeout > 10) {
3854 PrintAndLogEx(WARNING, "\ncommand execution time out, aborting...");
3855 goto out;
3857 looped = true;
3860 if (looped)
3861 PrintAndLogEx(NORMAL, "");
3863 if (resp.status == PM3_SUCCESS) {
3864 found_offset = resp.data.asBytes[0];
3865 found_key = true;
3866 PrintAndLogEx(NORMAL, "");
3867 PrintAndLogEx(SUCCESS,
3868 "Found valid key " _GREEN_("%s")
3869 , sprint_hex(keyBlock + (chunk_offset + found_offset) * 8, 8)
3871 break;
3872 } else {
3873 PrintAndLogEx(INPLACE, "Chunk [%03d/%d]", chunk_offset, keycount);
3874 fflush(stdout);
3878 out:
3879 t1 = msclock() - t1;
3881 PrintAndLogEx(NORMAL, "");
3882 PrintAndLogEx(SUCCESS, "time in iclass chk " _YELLOW_("%.1f") " seconds", (float)t1 / 1000.0);
3883 DropField();
3885 if (found_key) {
3886 uint8_t *key = keyBlock + (chunk_offset + found_offset) * 8;
3887 add_key(key);
3890 free(pre);
3891 free(keyBlock);
3892 PrintAndLogEx(NORMAL, "");
3893 return PM3_SUCCESS;
3897 // this method tries to identify in which configuration mode a iCLASS / iCLASS SE reader is in.
3898 // Standard or Elite / HighSecurity mode. It uses a default key dictionary list in order to work.
3899 #define INITIAL_SEED 0x429080 // VB6 KDF Seed Value
3901 // Functions for generating keys using RNG
3902 uint32_t seed = INITIAL_SEED;
3903 uint8_t key_state[8];
3904 bool prepared = false;
3906 void picopass_elite_reset(void) {
3907 memset(key_state, 0, sizeof(key_state));
3908 seed = INITIAL_SEED;
3909 prepared = false;
3912 uint32_t picopass_elite_lcg(void) {
3913 uint32_t mod = 0x1000000; // 2^24
3914 uint32_t a = 0xFD43FD;
3915 uint32_t c = 0xC39EC3;
3917 return (a * seed + c) % mod;
3920 uint32_t picopass_elite_rng(void) {
3921 seed = picopass_elite_lcg();
3922 return seed;
3925 uint8_t picopass_elite_nextByte(void) {
3926 return (picopass_elite_rng() >> 16) & 0xFF;
3929 void picopass_elite_nextKey(uint8_t *key) {
3930 if (prepared) {
3931 for (size_t i = 0; i < 7; i++) {
3932 key_state[i] = key_state[i + 1];
3934 key_state[7] = picopass_elite_nextByte();
3935 } else {
3936 for (size_t i = 0; i < 8; i++) {
3937 key_state[i] = picopass_elite_nextByte();
3939 prepared = true;
3941 memcpy(key, key_state, 8);
3944 static int iclass_recover(uint8_t key[8], uint32_t index_start, uint32_t loop, uint8_t no_first_auth[8], bool debug, bool test, bool allnight) {
3946 int runs = 1;
3947 int cycle = 1;
3948 bool repeat = true;
3949 if (allnight) {
3950 runs = 10;
3953 while (repeat == true) {
3954 uint32_t payload_size = sizeof(iclass_recover_req_t);
3955 uint8_t aa2_standard_key[PICOPASS_BLOCK_SIZE] = {0};
3956 memcpy(aa2_standard_key, iClass_Key_Table[1], PICOPASS_BLOCK_SIZE);
3957 iclass_recover_req_t *payload = calloc(1, payload_size);
3958 payload->req.use_raw = true;
3959 payload->req.use_elite = false;
3960 payload->req.use_credit_key = false;
3961 payload->req.use_replay = true;
3962 payload->req.send_reply = true;
3963 payload->req.do_auth = true;
3964 payload->req.shallow_mod = false;
3965 payload->req2.use_raw = false;
3966 payload->req2.use_elite = false;
3967 payload->req2.use_credit_key = true;
3968 payload->req2.use_replay = false;
3969 payload->req2.send_reply = true;
3970 payload->req2.do_auth = true;
3971 payload->req2.shallow_mod = false;
3972 payload->index = index_start;
3973 payload->loop = loop;
3974 payload->debug = debug;
3975 payload->test = test;
3976 memcpy(payload->nfa, no_first_auth, PICOPASS_BLOCK_SIZE);
3977 memcpy(payload->req.key, key, PICOPASS_BLOCK_SIZE);
3978 memcpy(payload->req2.key, aa2_standard_key, PICOPASS_BLOCK_SIZE);
3980 PrintAndLogEx(INFO, "Recover started...");
3982 PacketResponseNG resp;
3983 clearCommandBuffer();
3984 SendCommandNG(CMD_HF_ICLASS_RECOVER, (uint8_t *)payload, payload_size);
3985 WaitForResponse(CMD_HF_ICLASS_RECOVER, &resp);
3987 if (resp.status == PM3_SUCCESS) {
3988 PrintAndLogEx(SUCCESS, "iCLASS Key Bits Recovery: " _GREEN_("completed!"));
3989 repeat = false;
3990 } else if (resp.status == PM3_ESOFT) {
3991 PrintAndLogEx(WARNING, "iCLASS Key Bits Recovery: " _RED_("failed/errors"));
3992 repeat = false;
3993 } else if (resp.status == PM3_EINVARG) {
3994 if (allnight) {
3995 if (runs <= cycle) {
3996 repeat = false;
3997 } else {
3998 index_start = index_start + loop;
3999 cycle++;
4001 } else {
4002 repeat = false;
4005 free(payload);
4006 if (!repeat) {
4007 return resp.status;
4010 return PM3_SUCCESS;
4013 void generate_key_block_inverted(const uint8_t *startingKey, uint64_t index, uint8_t *keyBlock) {
4014 uint64_t carry = index;
4015 memcpy(keyBlock, startingKey, PICOPASS_BLOCK_SIZE);
4017 for (int j = PICOPASS_BLOCK_SIZE - 1; j >= 0; j--) {
4018 uint8_t increment_value = (carry & 0x1F) << 3; // Use the first 5 bits of carry and shift left by 3 to occupy the first 5 bits
4019 keyBlock[j] = (keyBlock[j] & 0x07) | increment_value; // Preserve last 3 bits, modify the first 5 bits
4021 carry >>= 5; // Shift right by 5 bits for the next byte
4022 if (carry == 0) {
4023 // If no more carry, break early to avoid unnecessary loops
4024 break;
4029 static int CmdHFiClassLegRecLookUp(const char *Cmd) {
4031 //Standalone Command Start
4032 CLIParserContext *ctx;
4033 CLIParserInit(&ctx, "hf iclass legbrute",
4034 "This command take sniffed trace data and partial raw key and bruteforces the remaining 40 bits of the raw key.",
4035 "hf iclass legbrute --epurse feffffffffffffff --macs1 1306cad9b6c24466 --macs2 f0bf905e35f97923 --pk B4F12AADC5301225"
4038 void *argtable[] = {
4039 arg_param_begin,
4040 arg_str1(NULL, "epurse", "<hex>", "Specify ePurse as 8 hex bytes"),
4041 arg_str1(NULL, "macs1", "<hex>", "MACs captured from the reader"),
4042 arg_str1(NULL, "macs2", "<hex>", "MACs captured from the reader, different than the first set (with the same csn and epurse value)"),
4043 arg_str1(NULL, "pk", "<hex>", "Partial Key from legrec or starting key of keyblock from legbrute"),
4044 arg_int0(NULL, "index", "<dec>", "Where to start from to retrieve the key, default 0 - value in millions e.g. 1 is 1 million"),
4045 arg_param_end
4047 CLIExecWithReturn(ctx, Cmd, argtable, false);
4049 int epurse_len = 0;
4050 uint8_t epurse[PICOPASS_BLOCK_SIZE] = {0};
4051 CLIGetHexWithReturn(ctx, 1, epurse, &epurse_len);
4053 int macs_len = 0;
4054 uint8_t macs[PICOPASS_BLOCK_SIZE] = {0};
4055 CLIGetHexWithReturn(ctx, 2, macs, &macs_len);
4057 int macs2_len = 0;
4058 uint8_t macs2[PICOPASS_BLOCK_SIZE] = {0};
4059 CLIGetHexWithReturn(ctx, 3, macs2, &macs2_len);
4061 int startingkey_len = 0;
4062 uint8_t startingKey[PICOPASS_BLOCK_SIZE] = {0};
4063 CLIGetHexWithReturn(ctx, 4, startingKey, &startingkey_len);
4065 uint64_t index = arg_get_int_def(ctx, 6, 0); //has to be 64 as we're bruteforcing 40 bits
4066 index = index * 1000000;
4068 CLIParserFree(ctx);
4070 if (epurse_len && epurse_len != PICOPASS_BLOCK_SIZE) {
4071 PrintAndLogEx(ERR, "ePurse is incorrect length");
4072 return PM3_EINVARG;
4075 if (macs_len && macs_len != PICOPASS_BLOCK_SIZE) {
4076 PrintAndLogEx(ERR, "MAC1 is incorrect length");
4077 return PM3_EINVARG;
4080 if (macs2_len && macs2_len != PICOPASS_BLOCK_SIZE) {
4081 PrintAndLogEx(ERR, "MAC2 is incorrect length");
4082 return PM3_EINVARG;
4085 if (startingkey_len && startingkey_len != PICOPASS_BLOCK_SIZE) {
4086 PrintAndLogEx(ERR, "Partial Key is incorrect length");
4087 return PM3_EINVARG;
4089 //Standalone Command End
4091 uint8_t CCNR[12];
4092 uint8_t MAC_TAG[4] = {0, 0, 0, 0};
4093 uint8_t CCNR2[12];
4094 uint8_t MAC_TAG2[4] = {0, 0, 0, 0};
4096 // Copy CCNR and MAC_TAG
4097 memcpy(CCNR, epurse, 8);
4098 memcpy(CCNR2, epurse, 8);
4099 memcpy(CCNR + 8, macs, 4);
4100 memcpy(CCNR2 + 8, macs2, 4);
4101 memcpy(MAC_TAG, macs + 4, 4);
4102 memcpy(MAC_TAG2, macs2 + 4, 4);
4104 PrintAndLogEx(SUCCESS, " Epurse: %s", sprint_hex(epurse, 8));
4105 PrintAndLogEx(SUCCESS, " MACS1: %s", sprint_hex(macs, 8));
4106 PrintAndLogEx(SUCCESS, " MACS2: %s", sprint_hex(macs2, 8));
4107 PrintAndLogEx(SUCCESS, " CCNR1: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR)));
4108 PrintAndLogEx(SUCCESS, " CCNR2: " _GREEN_("%s"), sprint_hex(CCNR2, sizeof(CCNR2)));
4109 PrintAndLogEx(SUCCESS, "TAG MAC1: %s", sprint_hex(MAC_TAG, sizeof(MAC_TAG)));
4110 PrintAndLogEx(SUCCESS, "TAG MAC2: %s", sprint_hex(MAC_TAG2, sizeof(MAC_TAG2)));
4111 PrintAndLogEx(SUCCESS, "Starting Key: %s", sprint_hex(startingKey, 8));
4113 bool verified = false;
4114 uint8_t div_key[PICOPASS_BLOCK_SIZE] = {0};
4115 uint8_t generated_mac[4] = {0, 0, 0, 0};
4117 while (!verified) {
4119 //generate the key block
4120 generate_key_block_inverted(startingKey, index, div_key);
4122 //generate the relevant macs
4124 doMAC(CCNR, div_key, generated_mac);
4125 bool mac_match = true;
4126 for (int i = 0; i < 4; i++) {
4127 if (MAC_TAG[i] != generated_mac[i]) {
4128 mac_match = false;
4132 if (mac_match) {
4133 //verify this against macs2
4134 PrintAndLogEx(WARNING, _YELLOW_("Found potentially valid RAW key ") _GREEN_("%s")_YELLOW_(" verifying it..."), sprint_hex(div_key, 8));
4135 //generate the macs from the key and not the other way around, so we can quickly validate it
4136 uint8_t verification_mac[4] = {0, 0, 0, 0};
4137 doMAC(CCNR2, div_key, verification_mac);
4138 PrintAndLogEx(INFO, "Usr Provided Mac2: " _GREEN_("%s"), sprint_hex(MAC_TAG2, sizeof(MAC_TAG2)));
4139 PrintAndLogEx(INFO, "Verification Mac: " _GREEN_("%s"), sprint_hex(verification_mac, sizeof(verification_mac)));
4140 bool check_values = true;
4141 for (int i = 0; i < 4; i++) {
4142 if (MAC_TAG2[i] != verification_mac[i]) {
4143 check_values = false;
4146 if (check_values) {
4147 PrintAndLogEx(SUCCESS, _GREEN_("CONFIRMED VALID RAW key ") _RED_("%s"), sprint_hex(div_key, 8));
4148 verified = true;
4149 } else {
4150 PrintAndLogEx(INFO, _YELLOW_("Raw Key Invalid"));
4154 if (index % 1000000 == 0) {
4155 PrintAndLogEx(INFO, "Tested: " _YELLOW_("%" PRIu64)" million keys", index / 1000000);
4156 PrintAndLogEx(INFO, "Last Generated Key Value: " _YELLOW_("%s"), sprint_hex(div_key, 8));
4158 index++;
4161 PrintAndLogEx(NORMAL, "");
4162 return PM3_SUCCESS;
4165 static void generate_single_key_block_inverted_opt(const uint8_t *startingKey, uint32_t index, uint8_t *keyBlock) {
4167 uint8_t bits_index = index / 16383;
4168 uint8_t ending_bits[] = { //all possible 70 combinations of 4x0 and 4x1 as key ending bits
4169 0x0F, 0x17, 0x1B, 0x1D, 0x1E, 0x27, 0x2B, 0x2D, 0x2E, 0x33,
4170 0x35, 0x36, 0x39, 0x3A, 0x3C, 0x47, 0x4B, 0x4D, 0x4E, 0x53,
4171 0x55, 0x56, 0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x69, 0x6A,
4172 0x6C, 0x71, 0x72, 0x74, 0x78, 0x87, 0x8B, 0x8D, 0x8E, 0x93,
4173 0x95, 0x96, 0x99, 0x9A, 0x9C, 0xA3, 0xA5, 0xA6, 0xA9, 0xAA,
4174 0xAC, 0xB1, 0xB2, 0xB4, 0xB8, 0xC3, 0xC5, 0xC6, 0xC9, 0xCA,
4175 0xCC, 0xD1, 0xD2, 0xD4, 0xD8, 0xE1, 0xE2, 0xE4, 0xE8, 0xF0
4178 uint8_t binary_endings[8]; // Array to store binary values for each ending bit
4179 // Extract each bit from the ending_bits[k] and store it in binary_endings
4180 uint8_t ending = ending_bits[bits_index];
4181 for (int i = 7; i >= 0; i--) {
4182 binary_endings[i] = ending & 1;
4183 ending >>= 1;
4186 uint8_t binary_mids[8]; // Array to store the 2-bit chunks of index
4187 // Iterate over the 16-bit integer and store 2 bits at a time in the result array
4188 for (int i = 0; i < 8; i++) {
4189 // Shift and mask to get 2 bits and store them as an 8-bit value
4190 binary_mids[7 - i] = (index >> (i * 2)) & 0x03; // 0x03 is a mask for 2 bits (binary 11)
4193 memcpy(keyBlock, startingKey, PICOPASS_BLOCK_SIZE);
4195 // Start from the second byte, index 1 as we're never gonna touch the first byte
4196 for (int i = 1; i < PICOPASS_BLOCK_SIZE; i++) {
4197 // Clear the last bit of the current byte (AND with 0xFE)
4198 keyBlock[i] &= 0xF8;
4199 // Set the last bit to the corresponding value from binary_endings (OR with binary_endings[i])
4200 keyBlock[i] |= ((binary_mids[i] & 0x03) << 1) | (binary_endings[i] & 0x01);
4205 static int CmdHFiClassLegacyRecSim(void) {
4207 PrintAndLogEx(INFO, _YELLOW_("This simulation assumes the card is standard keyed."));
4209 uint8_t key[PICOPASS_BLOCK_SIZE] = {0};
4210 uint8_t original_key[PICOPASS_BLOCK_SIZE];
4212 uint8_t csn[8] = {0};
4213 uint8_t new_div_key[8] = {0};
4214 uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
4216 if (select_only(csn, CCNR, true, false) == false) {
4217 DropField();
4218 return PM3_ESOFT;
4220 HFiClassCalcDivKey(csn, iClass_Key_Table[0], new_div_key, false);
4221 memcpy(key,new_div_key,PICOPASS_BLOCK_SIZE);
4222 memcpy(original_key, key, PICOPASS_BLOCK_SIZE);
4224 uint8_t zero_key[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
4225 uint8_t zero_key_two[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
4226 int bits_found = -1;
4227 uint32_t index = 0;
4228 #define MAX_UPDATES 16777216
4229 while (bits_found == -1 && index < MAX_UPDATES) {
4230 uint8_t genkeyblock[PICOPASS_BLOCK_SIZE];
4231 uint8_t xorkeyblock[PICOPASS_BLOCK_SIZE] = {0};
4233 generate_single_key_block_inverted_opt(zero_key, index, genkeyblock);
4234 memcpy(xorkeyblock, genkeyblock, PICOPASS_BLOCK_SIZE);
4236 for (int i = 0; i < 8 ; i++) {
4237 key[i] = xorkeyblock[i] ^ original_key[i];
4238 memcpy(zero_key_two, xorkeyblock, PICOPASS_BLOCK_SIZE);
4241 // Extract the last 3 bits of the first byte
4242 uint8_t last_three_bits = key[0] & 0x07; // 0x07 is 00000111 in binary - bitmask
4243 bool same_bits = true;
4244 // Check if the last 3 bits of all bytes are the same
4245 for (int i = 1; i < PICOPASS_BLOCK_SIZE; i++) {
4246 if ((key[i] & 0x07) != last_three_bits) {
4247 same_bits = false;
4250 if (same_bits){
4251 bits_found = index;
4252 PrintAndLogEx(SUCCESS, "Original Key: " _GREEN_("%s"), sprint_hex(original_key, sizeof(original_key)));
4253 PrintAndLogEx(SUCCESS, "Weak Key: " _GREEN_("%s"), sprint_hex(key, sizeof(key)));
4254 PrintAndLogEx(SUCCESS, "Key Updates Required to Weak Key: " _GREEN_("%d"), index);
4255 PrintAndLogEx(SUCCESS, "Estimated Time: ~" _GREEN_("%d")" hours", index/6545);
4258 index++;
4259 }//end while
4261 PrintAndLogEx(NORMAL, "");
4262 return PM3_SUCCESS;
4266 static int CmdHFiClassLegacyRecover(const char *Cmd) {
4268 CLIParserContext *ctx;
4269 CLIParserInit(&ctx, "hf iclass legrec",
4270 "Attempts to recover the diversified key of a specific iClass card. This may take a long time. The Card must remain be on the PM3 antenna during the whole process! This process may brick the card!",
4271 "hf iclass legrec --macs 0000000089cb984b\n"
4272 "hf iclass legrec --macs 0000000089cb984b --index 0 --loop 100 --notest"
4275 void *argtable[] = {
4276 arg_param_begin,
4277 arg_str1(NULL, "macs", "<hex>", "AA1 Authentication MACs"),
4278 arg_int0(NULL, "index", "<dec>", "Where to start from to retrieve the key, default 0"),
4279 arg_int0(NULL, "loop", "<dec>", "The number of key retrieval cycles to perform, max 10000, default 100"),
4280 arg_lit0(NULL, "debug", "Re-enables tracing for debugging. Limits cycles to 1."),
4281 arg_lit0(NULL, "notest", "Perform real writes on the card!"),
4282 arg_lit0(NULL, "allnight", "Loops the loop for 10 times, recommended loop value of 5000."),
4283 arg_lit0(NULL, "sim", "Runs a simulation based on the card's CSN assuming standard key."),
4284 arg_param_end
4286 CLIExecWithReturn(ctx, Cmd, argtable, false);
4288 int macs_len = 0;
4289 uint8_t macs[PICOPASS_BLOCK_SIZE] = {0};
4290 CLIGetHexWithReturn(ctx, 1, macs, &macs_len);
4291 uint32_t index = arg_get_int_def(ctx, 2, 0);
4292 uint32_t loop = arg_get_int_def(ctx, 3, 100);
4293 uint8_t no_first_auth[PICOPASS_BLOCK_SIZE] = {0};
4294 bool debug = arg_get_lit(ctx, 4);
4295 bool test = true;
4296 bool no_test = arg_get_lit(ctx, 5);
4297 bool allnight = arg_get_lit(ctx, 6);
4298 bool sim = arg_get_lit(ctx, 7);
4300 if (sim){
4301 CmdHFiClassLegacyRecSim();
4302 return PM3_SUCCESS;
4305 if (no_test) {
4306 test = false;
4309 if (loop > 10000) {
4310 PrintAndLogEx(ERR, "Too many loops, arm prone to crashes. For safety specify a number lower than 10000");
4311 CLIParserFree(ctx);
4312 return PM3_EINVARG;
4313 } else if (debug || test) {
4314 loop = 1;
4317 uint8_t csn[PICOPASS_BLOCK_SIZE] = {0};
4318 uint8_t new_div_key[PICOPASS_BLOCK_SIZE] = {0};
4319 uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
4320 if (select_only(csn, CCNR, true, false) == false) {
4321 DropField();
4322 return PM3_ESOFT;
4324 diversifyKey(csn, iClass_Key_Table[1], new_div_key);
4325 memcpy(no_first_auth, new_div_key, PICOPASS_BLOCK_SIZE);
4327 CLIParserFree(ctx);
4329 if (macs_len && macs_len != PICOPASS_BLOCK_SIZE) {
4330 PrintAndLogEx(ERR, "MAC is incorrect length");
4331 return PM3_EINVARG;
4334 iclass_recover(macs, index, loop, no_first_auth, debug, test, allnight);
4336 PrintAndLogEx(WARNING, _YELLOW_("If the process completed successfully, you can now run 'hf iclass legbrute' with the partial key found."));
4338 PrintAndLogEx(NORMAL, "");
4339 return PM3_SUCCESS;
4343 static int CmdHFiClassUnhash(const char *Cmd) {
4345 CLIParserContext *ctx;
4346 CLIParserInit(&ctx, "hf iclass unhash",
4347 "Reverses the hash0 function used generate iclass diversified keys after DES encryption,\n"
4348 "Function returns the DES crypted CSN. Next step bruteforcing.",
4349 "hf iclass unhash -k B4F12AADC5301A2D"
4352 void *argtable[] = {
4353 arg_param_begin,
4354 arg_str1("k", "divkey", "<hex>", "Card diversified key"),
4355 arg_param_end
4357 CLIExecWithReturn(ctx, Cmd, argtable, false);
4359 int dk_len = 0;
4360 uint8_t div_key[PICOPASS_BLOCK_SIZE] = {0};
4361 CLIGetHexWithReturn(ctx, 1, div_key, &dk_len);
4363 CLIParserFree(ctx);
4365 if (dk_len && dk_len != PICOPASS_BLOCK_SIZE) {
4366 PrintAndLogEx(ERR, "Diversified key is incorrect length");
4367 return PM3_EINVARG;
4370 PrintAndLogEx(INFO, "Diversified key... %s", sprint_hex_inrow(div_key, sizeof(div_key)));
4372 invert_hash0(div_key);
4374 PrintAndLogEx(SUCCESS, "You can now retrieve the master key by cracking DES with hashcat!");
4375 PrintAndLogEx(SUCCESS, "hashcat.exe -a 3 -m 14000 preimage:csn -1 charsets/DES_full.hcchr --hex-charset ?1?1?1?1?1?1?1?1");
4377 PrintAndLogEx(NORMAL, "");
4378 return PM3_SUCCESS;
4381 static int CmdHFiClassLookUp(const char *Cmd) {
4382 CLIParserContext *ctx;
4383 CLIParserInit(&ctx, "hf iclass lookup",
4384 "This command take sniffed trace data and try to recovery a iCLASS Standard or iCLASS Elite key.",
4385 "hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic\n"
4386 "hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic --elite\n"
4387 "hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b --vb6rng"
4390 void *argtable[] = {
4391 arg_param_begin,
4392 arg_str0("f", "file", "<fn>", "Dictionary file with default iclass keys"),
4393 arg_str1(NULL, "csn", "<hex>", "Specify CSN as 8 hex bytes"),
4394 arg_str1(NULL, "epurse", "<hex>", "Specify ePurse as 8 hex bytes"),
4395 arg_str1(NULL, "macs", "<hex>", "MACs"),
4396 arg_lit0(NULL, "elite", "Elite computations applied to key"),
4397 arg_lit0(NULL, "raw", "no computations applied to key"),
4398 arg_lit0(NULL, "vb6rng", "use the VB6 rng for elite keys instead of a dictionary file"),
4399 arg_param_end
4401 CLIExecWithReturn(ctx, Cmd, argtable, false);
4403 bool use_vb6kdf = arg_get_lit(ctx, 7);
4404 int fnlen = 0;
4405 char filename[FILE_PATH_SIZE] = {0};
4407 bool use_elite = arg_get_lit(ctx, 5);
4408 bool use_raw = arg_get_lit(ctx, 6);
4409 if (use_vb6kdf) {
4410 use_elite = true;
4411 } else {
4412 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
4415 int csn_len = 0;
4416 uint8_t csn[8] = {0};
4417 CLIGetHexWithReturn(ctx, 2, csn, &csn_len);
4419 if (csn_len > 0) {
4420 if (csn_len != 8) {
4421 PrintAndLogEx(ERR, "CSN is incorrect length");
4422 CLIParserFree(ctx);
4423 return PM3_EINVARG;
4427 int epurse_len = 0;
4428 uint8_t epurse[8] = {0};
4429 CLIGetHexWithReturn(ctx, 3, epurse, &epurse_len);
4431 if (epurse_len > 0) {
4432 if (epurse_len != 8) {
4433 PrintAndLogEx(ERR, "ePurse is incorrect length");
4434 CLIParserFree(ctx);
4435 return PM3_EINVARG;
4439 int macs_len = 0;
4440 uint8_t macs[8] = {0};
4441 CLIGetHexWithReturn(ctx, 4, macs, &macs_len);
4443 if (macs_len > 0) {
4444 if (macs_len != 8) {
4445 PrintAndLogEx(ERR, "MAC is incorrect length");
4446 CLIParserFree(ctx);
4447 return PM3_EINVARG;
4451 CLIParserFree(ctx);
4453 uint8_t CCNR[12];
4454 uint8_t MAC_TAG[4] = { 0, 0, 0, 0 };
4456 // Stupid copy.. CCNR is a combo of epurse and reader nonce
4457 memcpy(CCNR, epurse, 8);
4458 memcpy(CCNR + 8, macs, 4);
4459 memcpy(MAC_TAG, macs + 4, 4);
4461 PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s"), sprint_hex(csn, sizeof(csn)));
4462 PrintAndLogEx(SUCCESS, " Epurse: %s", sprint_hex(epurse, sizeof(epurse)));
4463 PrintAndLogEx(SUCCESS, " MACS: %s", sprint_hex(macs, sizeof(macs)));
4464 PrintAndLogEx(SUCCESS, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR)));
4465 PrintAndLogEx(SUCCESS, "TAG MAC: %s", sprint_hex(MAC_TAG, sizeof(MAC_TAG)));
4467 // Run time
4468 uint64_t t1 = msclock();
4470 uint8_t *keyBlock = NULL;
4471 uint32_t keycount = 0;
4473 if (!use_vb6kdf) {
4474 // Load keys
4475 int res = loadFileDICTIONARY_safe(filename, (void **)&keyBlock, 8, &keycount);
4476 if (res != PM3_SUCCESS || keycount == 0) {
4477 free(keyBlock);
4478 return res;
4480 } else {
4481 // Generate 5000 keys using VB6 KDF
4482 keycount = 5000;
4483 keyBlock = calloc(1, keycount * 8);
4484 if (keyBlock == NULL) {
4485 return PM3_EMALLOC;
4488 picopass_elite_reset();
4489 for (uint32_t i = 0; i < keycount; i++) {
4490 picopass_elite_nextKey(keyBlock + (i * 8));
4494 // Iclass_prekey_t
4495 iclass_prekey_t *prekey = calloc(keycount, sizeof(iclass_prekey_t));
4496 if (!prekey) {
4497 free(keyBlock);
4498 return PM3_EMALLOC;
4501 PrintAndLogEx(INFO, "Generating diversified keys...");
4502 GenerateMacKeyFrom(csn, CCNR, use_raw, use_elite, keyBlock, keycount, prekey);
4504 if (use_elite) {
4505 PrintAndLogEx(INFO, "Using " _YELLOW_("elite algo"));
4508 if (use_raw) {
4509 PrintAndLogEx(INFO, "Using " _YELLOW_("raw mode"));
4512 PrintAndLogEx(INFO, "Sorting...");
4514 // Sort mac list
4515 qsort(prekey, keycount, sizeof(iclass_prekey_t), cmp_uint32);
4517 PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key...", "DEBIT");
4518 iclass_prekey_t *item;
4519 iclass_prekey_t lookup;
4520 memcpy(lookup.mac, MAC_TAG, 4);
4522 // Binsearch
4523 item = (iclass_prekey_t *) bsearch(&lookup, prekey, keycount, sizeof(iclass_prekey_t), cmp_uint32);
4525 if (item != NULL) {
4526 PrintAndLogEx(SUCCESS, "Found valid key " _GREEN_("%s"), sprint_hex(item->key, 8));
4527 add_key(item->key);
4530 t1 = msclock() - t1;
4531 PrintAndLogEx(SUCCESS, "Time in iclass lookup " _YELLOW_("%.3f") " seconds", (float)t1 / 1000.0);
4533 free(prekey);
4534 free(keyBlock);
4535 PrintAndLogEx(NORMAL, "");
4536 return PM3_SUCCESS;
4539 typedef struct {
4540 uint8_t thread_idx;
4541 uint8_t use_raw;
4542 uint8_t use_elite;
4543 uint32_t keycnt;
4544 uint8_t csn[8];
4545 uint8_t cc_nr[12];
4546 uint8_t *keys;
4547 union {
4548 iclass_premac_t *premac;
4549 iclass_prekey_t *prekey;
4550 } list;
4551 } PACKED iclass_thread_arg_t;
4553 static size_t iclass_tc = 1;
4555 static pthread_mutex_t generator_mutex = PTHREAD_MUTEX_INITIALIZER;
4556 static void *bf_generate_mac(void *thread_arg) {
4558 iclass_thread_arg_t *targ = (iclass_thread_arg_t *)thread_arg;
4559 const uint8_t idx = targ->thread_idx;
4560 const uint8_t use_raw = targ->use_raw;
4561 const uint8_t use_elite = targ->use_elite;
4562 const uint32_t keycnt = targ->keycnt;
4564 uint8_t *keys = targ->keys;
4565 iclass_premac_t *list = targ->list.premac;
4567 uint8_t csn[8];
4568 uint8_t cc_nr[12];
4569 memcpy(csn, targ->csn, sizeof(csn));
4570 memcpy(cc_nr, targ->cc_nr, sizeof(cc_nr));
4572 uint8_t key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
4573 uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
4575 for (uint32_t i = idx; i < keycnt; i += iclass_tc) {
4577 memcpy(key, keys + 8 * i, 8);
4579 pthread_mutex_lock(&generator_mutex);
4580 if (use_raw)
4581 memcpy(div_key, key, 8);
4582 else
4583 HFiClassCalcDivKey(csn, key, div_key, use_elite);
4585 doMAC(cc_nr, div_key, list[i].mac);
4586 pthread_mutex_unlock(&generator_mutex);
4588 return NULL;
4591 // precalc diversified keys and their MAC
4592 void GenerateMacFrom(uint8_t *CSN, uint8_t *CCNR, bool use_raw, bool use_elite, uint8_t *keys, uint32_t keycnt, iclass_premac_t *list) {
4594 pthread_mutex_init(&generator_mutex, NULL);
4596 iclass_tc = num_CPUs();
4597 pthread_t threads[iclass_tc];
4598 iclass_thread_arg_t args[iclass_tc];
4599 // init thread arguments
4600 for (size_t i = 0; i < iclass_tc; i++) {
4601 args[i].thread_idx = i;
4602 args[i].use_raw = use_raw;
4603 args[i].use_elite = use_elite;
4604 args[i].keycnt = keycnt;
4605 args[i].keys = keys;
4606 args[i].list.premac = list;
4608 memcpy(args[i].csn, CSN, sizeof(args[i].csn));
4609 memcpy(args[i].cc_nr, CCNR, sizeof(args[i].cc_nr));
4612 for (int i = 0; i < iclass_tc; i++) {
4613 int res = pthread_create(&threads[i], NULL, bf_generate_mac, (void *)&args[i]);
4614 if (res) {
4615 PrintAndLogEx(NORMAL, "");
4616 PrintAndLogEx(WARNING, "Failed to create pthreads. Quitting");
4617 return;
4621 for (int i = 0; i < iclass_tc; i++)
4622 pthread_join(threads[i], NULL);
4625 static void *bf_generate_mackey(void *thread_arg) {
4627 iclass_thread_arg_t *targ = (iclass_thread_arg_t *)thread_arg;
4628 const uint8_t idx = targ->thread_idx;
4629 const uint8_t use_raw = targ->use_raw;
4630 const uint8_t use_elite = targ->use_elite;
4631 const uint32_t keycnt = targ->keycnt;
4633 uint8_t *keys = targ->keys;
4634 iclass_prekey_t *list = targ->list.prekey;
4636 uint8_t csn[8];
4637 uint8_t cc_nr[12];
4638 memcpy(csn, targ->csn, sizeof(csn));
4639 memcpy(cc_nr, targ->cc_nr, sizeof(cc_nr));
4641 uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
4643 for (uint32_t i = idx; i < keycnt; i += iclass_tc) {
4645 memcpy(list[i].key, keys + 8 * i, 8);
4647 pthread_mutex_lock(&generator_mutex);
4648 if (use_raw)
4649 memcpy(div_key, list[i].key, 8);
4650 else
4651 HFiClassCalcDivKey(csn, list[i].key, div_key, use_elite);
4653 doMAC(cc_nr, div_key, list[i].mac);
4654 pthread_mutex_unlock(&generator_mutex);
4656 return NULL;
4659 void GenerateMacKeyFrom(uint8_t *CSN, uint8_t *CCNR, bool use_raw, bool use_elite, uint8_t *keys, uint32_t keycnt, iclass_prekey_t *list) {
4661 pthread_mutex_init(&generator_mutex, NULL);
4662 iclass_tc = num_CPUs();
4663 pthread_t threads[iclass_tc];
4664 iclass_thread_arg_t args[iclass_tc];
4665 // init thread arguments
4666 for (size_t i = 0; i < iclass_tc; i++) {
4667 args[i].thread_idx = i;
4668 args[i].use_raw = use_raw;
4669 args[i].use_elite = use_elite;
4670 args[i].keycnt = keycnt;
4671 args[i].keys = keys;
4672 args[i].list.prekey = list;
4674 memcpy(args[i].csn, CSN, sizeof(args[i].csn));
4675 memcpy(args[i].cc_nr, CCNR, sizeof(args[i].cc_nr));
4678 for (size_t i = 0; i < iclass_tc; i++) {
4679 int res = pthread_create(&threads[i], NULL, bf_generate_mackey, (void *)&args[i]);
4680 if (res) {
4681 PrintAndLogEx(NORMAL, "");
4682 PrintAndLogEx(WARNING, "Failed to create pthreads. Quitting");
4683 return;
4687 for (int i = 0; i < iclass_tc; i++)
4688 pthread_join(threads[i], NULL);
4692 // print diversified keys
4693 void PrintPreCalcMac(uint8_t *keys, uint32_t keycnt, iclass_premac_t *pre_list) {
4695 iclass_prekey_t *b = calloc(keycnt, sizeof(iclass_prekey_t));
4696 if (!b)
4697 return;
4699 for (uint32_t i = 0; i < keycnt; i++) {
4700 memcpy(b[i].key, keys + 8 * i, 8);
4701 memcpy(b[i].mac, pre_list[i].mac, 4);
4703 PrintPreCalc(b, keycnt);
4704 free(b);
4707 void PrintPreCalc(iclass_prekey_t *list, uint32_t itemcnt) {
4708 PrintAndLogEx(NORMAL, "-----+------------------+---------");
4709 PrintAndLogEx(NORMAL, "#key | key | mac");
4710 PrintAndLogEx(NORMAL, "-----+------------------+---------");
4711 for (int i = 0; i < itemcnt; i++) {
4713 if (i < 10) {
4714 PrintAndLogEx(NORMAL, "[%2d] | %016" PRIx64 " | %08" PRIx64, i, bytes_to_num(list[i].key, 8), bytes_to_num(list[i].mac, 4));
4715 } else if (i == 10) {
4716 PrintAndLogEx(SUCCESS, "... skip printing the rest");
4721 static void permute(uint8_t *data, uint8_t len, uint8_t *output) {
4722 #define KEY_SIZE 8
4724 if (len > KEY_SIZE) {
4725 for (uint8_t m = 0; m < len; m += KEY_SIZE) {
4726 permute(data + m, KEY_SIZE, output + m);
4728 return;
4730 if (len != KEY_SIZE) {
4731 PrintAndLogEx(WARNING, "wrong key size\n");
4732 return;
4734 for (uint8_t i = 0; i < KEY_SIZE; ++i) {
4735 uint8_t p = 0;
4736 uint8_t mask = 0x80 >> i;
4737 for (uint8_t j = 0; j < KEY_SIZE; ++j) {
4738 p >>= 1;
4739 if (data[j] & mask)
4740 p |= 0x80;
4742 output[i] = p;
4745 static void permute_rev(uint8_t *data, uint8_t len, uint8_t *output) {
4746 permute(data, len, output);
4747 permute(output, len, data);
4748 permute(data, len, output);
4750 static void simple_crc(const uint8_t *data, uint8_t len, uint8_t *output) {
4751 uint8_t crc = 0;
4752 for (uint8_t i = 0; i < len; ++i) {
4753 // seventh byte contains the crc.
4754 if ((i & 0x7) == 0x7) {
4755 output[i] = crc ^ 0xFF;
4756 crc = 0;
4757 } else {
4758 output[i] = data[i];
4759 crc ^= data[i];
4763 // DES doesn't use the MSB.
4764 static void shave(uint8_t *data, uint8_t len) {
4765 for (uint8_t i = 0; i < len; ++i)
4766 data[i] &= 0xFE;
4768 static void generate_rev(uint8_t *data, uint8_t len) {
4769 uint8_t *key = calloc(len, sizeof(uint8_t));
4770 PrintAndLogEx(SUCCESS, "input permuted key | %s \n", sprint_hex(data, len));
4771 permute_rev(data, len, key);
4772 PrintAndLogEx(SUCCESS, " unpermuted key | %s \n", sprint_hex(key, len));
4773 shave(key, len);
4774 PrintAndLogEx(SUCCESS, " key | %s \n", sprint_hex(key, len));
4775 free(key);
4777 static void generate(uint8_t *data, uint8_t len) {
4778 uint8_t *key = calloc(len, sizeof(uint8_t));
4779 uint8_t *pkey = calloc(len, sizeof(uint8_t));
4780 PrintAndLogEx(SUCCESS, " input key | %s \n", sprint_hex(data, len));
4781 permute(data, len, pkey);
4782 PrintAndLogEx(SUCCESS, "permuted key | %s \n", sprint_hex(pkey, len));
4783 simple_crc(pkey, len, key);
4784 PrintAndLogEx(SUCCESS, " CRC'ed key | %s \n", sprint_hex(key, len));
4785 free(key);
4786 free(pkey);
4789 static int CmdHFiClassPermuteKey(const char *Cmd) {
4791 uint8_t key[8] = {0};
4792 uint8_t data[16] = {0};
4793 int len = 0;
4795 CLIParserContext *ctx;
4796 CLIParserInit(&ctx, "hf iclass permutekey",
4797 "Permute function from 'heart of darkness' paper.",
4798 "hf iclass permutekey --reverse --key 0123456789abcdef\n"
4799 "hf iclass permutekey --key ff55330f0055330f\n");
4801 void *argtable[] = {
4802 arg_param_begin,
4803 arg_lit0("r", "reverse", "reverse permuted key"),
4804 arg_str1(NULL, "key", "<hex>", "input key, 8 hex bytes"),
4805 arg_param_end
4807 CLIExecWithReturn(ctx, Cmd, argtable, false);
4808 bool isReverse = arg_get_lit(ctx, 1);
4809 CLIGetHexWithReturn(ctx, 2, data, &len);
4810 CLIParserFree(ctx);
4812 memcpy(key, data, 8);
4814 if (isReverse) {
4815 generate_rev(data, len);
4816 uint8_t key_std_format[8] = {0};
4817 permutekey_rev(key, key_std_format);
4818 PrintAndLogEx(SUCCESS, "Standard NIST format key " _YELLOW_("%s") " \n", sprint_hex(key_std_format, 8));
4819 } else {
4820 generate(data, len);
4821 uint8_t key_iclass_format[8] = {0};
4822 permutekey(key, key_iclass_format);
4823 PrintAndLogEx(SUCCESS, "HID permuted iCLASS format: %s \n", sprint_hex(key_iclass_format, 8));
4825 return PM3_SUCCESS;
4828 static int CmdHFiClassEncode(const char *Cmd) {
4830 CLIParserContext *ctx;
4831 CLIParserInit(&ctx, "hf iclass encode",
4832 "Encode binary wiegand to block 7,8,9\n"
4833 "Use either --bin or --wiegand/--fc/--cn",
4834 "hf iclass encode --bin 10001111100000001010100011 --ki 0 -> FC 31 CN 337 (H10301)\n"
4835 "hf iclass encode -w H10301 --fc 31 --cn 337 --ki 0 -> FC 31 CN 337 (H10301)\n"
4836 "hf iclass encode --bin 10001111100000001010100011 --ki 0 --elite -> FC 31 CN 337 (H10301), writing w elite key\n"
4837 "hf iclass encode -w H10301 --fc 31 --cn 337 --emu -> Writes the ecoded data to emulator memory\n"
4838 "When using emulator you have to first load a credential into emulator memory"
4841 void *argtable[] = {
4842 arg_param_begin,
4843 arg_str0(NULL, "bin", "<bin>", "Binary string i.e 0001001001"),
4844 arg_int0(NULL, "ki", "<dec>", "Key index to select key from memory 'hf iclass managekeys'"),
4845 arg_lit0(NULL, "credit", "key is assumed to be the credit key"),
4846 arg_lit0(NULL, "elite", "elite computations applied to key"),
4847 arg_lit0(NULL, "raw", "no computations applied to key"),
4848 arg_str0(NULL, "enckey", "<hex>", "3DES transport key, 16 hex bytes"),
4849 arg_u64_0(NULL, "fc", "<dec>", "facility code"),
4850 arg_u64_0(NULL, "cn", "<dec>", "card number"),
4851 arg_u64_0(NULL, "issue", "<dec>", "issue level"),
4852 arg_str0("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"),
4853 arg_lit0(NULL, "emu", "Write to emulation memory instead of card"),
4854 arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
4855 arg_lit0("v", NULL, "verbose (print encoded blocks)"),
4856 arg_param_end
4858 CLIExecWithReturn(ctx, Cmd, argtable, false);
4860 // can only do one block of 8 bytes currently. There are room for two blocks in the specs.
4861 uint8_t bin[65] = {0};
4862 int bin_len = sizeof(bin) - 1; // CLIGetStrWithReturn does not guarantee string to be null-terminated
4863 CLIGetStrWithReturn(ctx, 1, bin, &bin_len);
4865 int key_nr = arg_get_int_def(ctx, 2, -1);
4866 bool use_emulator_memory = arg_get_lit(ctx, 11);
4868 bool auth = false;
4869 uint8_t key[8] = {0};
4871 // If we use emulator memory skip key requirement
4872 if (use_emulator_memory == false) {
4873 if (key_nr < 0) {
4874 PrintAndLogEx(ERR, "Missing required arg for --ki or --emu");
4875 return PM3_EINVARG;
4878 if (key_nr >= 0) {
4879 if (key_nr < ICLASS_KEYS_MAX) {
4880 auth = true;
4881 memcpy(key, iClass_Key_Table[key_nr], 8);
4882 PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex(iClass_Key_Table[key_nr], 8));
4883 } else {
4884 PrintAndLogEx(ERR, "Key number is invalid");
4885 CLIParserFree(ctx);
4886 return PM3_EINVARG;
4891 bool use_credit_key = arg_get_lit(ctx, 3);
4892 bool elite = arg_get_lit(ctx, 4);
4893 bool rawkey = arg_get_lit(ctx, 5);
4895 int enc_key_len = 0;
4896 uint8_t enc_key[16] = {0};
4897 uint8_t *enckeyptr = NULL;
4898 bool have_enc_key = false;
4899 bool use_sc = false;
4900 CLIGetHexWithReturn(ctx, 6, enc_key, &enc_key_len);
4902 // FC / CN / Issue Level
4903 wiegand_card_t card;
4904 memset(&card, 0, sizeof(wiegand_card_t));
4906 card.FacilityCode = arg_get_u32_def(ctx, 7, 0);
4907 card.CardNumber = arg_get_u32_def(ctx, 8, 0);
4908 card.IssueLevel = arg_get_u32_def(ctx, 9, 0);
4910 char format[16] = {0};
4911 int format_len = 0;
4913 CLIParamStrToBuf(arg_get_str(ctx, 10), (uint8_t *)format, sizeof(format), &format_len);
4915 bool shallow_mod = arg_get_lit(ctx, 12);
4916 bool verbose = arg_get_lit(ctx, 13);
4918 CLIParserFree(ctx);
4920 if ((rawkey + elite) > 1) {
4921 PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw'");
4922 return PM3_EINVARG;
4925 if (enc_key_len > 0) {
4926 if (enc_key_len != 16) {
4927 PrintAndLogEx(ERR, "Transport key must be 16 hex bytes (32 HEX characters)");
4928 return PM3_EINVARG;
4930 have_enc_key = true;
4933 if (bin_len > 64) {
4934 PrintAndLogEx(ERR, "Binary wiegand string must be less than 64 bits");
4935 return PM3_EINVARG;
4938 if (bin_len == 0 && card.FacilityCode == 0 && card.CardNumber == 0) {
4939 PrintAndLogEx(ERR, "Must provide either --cn/--fc or --bin");
4940 return PM3_EINVARG;
4943 if (have_enc_key == false) {
4944 // The IsCardHelperPresent function clears the emulator memory
4945 if (use_emulator_memory) {
4946 use_sc = false;
4947 } else {
4948 use_sc = IsCardHelperPresent(false);
4950 if (use_sc == false) {
4951 size_t keylen = 0;
4952 int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&enckeyptr, &keylen);
4953 if (res != PM3_SUCCESS) {
4954 PrintAndLogEx(ERR, "Failed to find the transport key");
4955 return PM3_EINVARG;
4957 if (keylen != 16) {
4958 PrintAndLogEx(ERR, "Failed to load transport key from file");
4959 free(enckeyptr);
4960 return PM3_EINVARG;
4962 memcpy(enc_key, enckeyptr, sizeof(enc_key));
4963 free(enckeyptr);
4967 uint8_t credential[] = {
4968 0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0xE0, 0x17,
4969 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4970 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4971 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4974 uint8_t data[8];
4975 memset(data, 0, sizeof(data));
4976 BitstreamOut_t bout = {data, 0, 0 };
4978 for (int i = 0; i < 64 - bin_len - 1; i++) {
4979 pushBit(&bout, 0);
4981 // add binary sentinel bit.
4982 pushBit(&bout, 1);
4984 // convert binary string to hex bytes
4985 for (int i = 0; i < bin_len; i++) {
4986 char c = bin[i];
4987 if (c == '1')
4988 pushBit(&bout, 1);
4989 else if (c == '0')
4990 pushBit(&bout, 0);
4991 else {
4992 PrintAndLogEx(WARNING, "Ignoring '%c'", c);
4996 if (bin_len) {
4997 memcpy(credential + 8, data, sizeof(data));
4998 } else {
4999 wiegand_message_t packed;
5000 memset(&packed, 0, sizeof(wiegand_message_t));
5002 int format_idx = HIDFindCardFormat(format);
5003 if (format_idx == -1) {
5004 PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format);
5005 return PM3_EINVARG;
5008 if (HIDPack(format_idx, &card, &packed, false) == false) {
5009 PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
5010 return PM3_ESOFT;
5013 // iceman: only for formats w length smaller than 37.
5014 // Needs a check.
5016 // increase length to allow setting bit just above real data
5017 packed.Length++;
5018 // Set sentinel bit
5019 set_bit_by_position(&packed, true, 0);
5021 #ifdef HOST_LITTLE_ENDIAN
5022 packed.Mid = BSWAP_32(packed.Mid);
5023 packed.Bot = BSWAP_32(packed.Bot);
5024 #endif
5026 memcpy(credential + 8, &packed.Mid, sizeof(packed.Mid));
5027 memcpy(credential + 12, &packed.Bot, sizeof(packed.Bot));
5030 // encrypt with transport key
5031 if (use_sc) {
5032 Encrypt(credential + 8, credential + 8);
5033 Encrypt(credential + 16, credential + 16);
5034 Encrypt(credential + 24, credential + 24);
5035 } else {
5036 iclass_encrypt_block_data(credential + 8, enc_key);
5037 iclass_encrypt_block_data(credential + 16, enc_key);
5038 iclass_encrypt_block_data(credential + 24, enc_key);
5041 if (verbose) {
5042 for (uint8_t i = 0; i < 4; i++) {
5043 PrintAndLogEx(INFO, "Block %d/0x0%x -> " _YELLOW_("%s"), 6 + i, 6 + i, sprint_hex_inrow(credential + (i * 8), 8));
5047 if (!g_session.pm3_present) {
5048 PrintAndLogEx(ERR, "Device offline\n");
5049 return PM3_EFAILED;
5052 int isok = PM3_SUCCESS;
5053 // write
5054 if (use_emulator_memory) {
5055 uint16_t byte_sent = 0;
5056 iclass_upload_emul(credential, sizeof(credential), 6 * PICOPASS_BLOCK_SIZE, &byte_sent);
5057 PrintAndLogEx(SUCCESS, "uploaded " _YELLOW_("%d") " bytes to emulator memory", byte_sent);
5058 PrintAndLogEx(HINT, "You are now ready to simulate. See " _YELLOW_("`hf iclass sim -h`"));
5059 } else {
5060 for (uint8_t i = 0; i < 4; i++) {
5061 isok = iclass_write_block(6 + i, credential + (i * 8), NULL, key, use_credit_key, elite, rawkey, false, false, auth, shallow_mod);
5062 switch (isok) {
5063 case PM3_SUCCESS:
5064 PrintAndLogEx(SUCCESS, "Write block %d/0x0%x ( " _GREEN_("ok") " ) --> " _YELLOW_("%s"), 6 + i, 6 + i, sprint_hex_inrow(credential + (i * 8), 8));
5065 break;
5066 default:
5067 PrintAndLogEx(INFO, "Write block %d/0x0%x ( " _RED_("fail") " )", 6 + i, 6 + i);
5068 break;
5072 return isok;
5076 static int CmdHFiClassAutopwn(const char *Cmd) {
5078 CLIParserContext *ctx;
5079 CLIParserInit(&ctx, "hf iclass autopwn",
5080 "Tries to check keys, if found, dump card and save file",
5081 "hf iclass autopwn\n");
5083 void *argtable[] = {
5084 arg_param_begin,
5085 arg_param_end
5087 CLIExecWithReturn(ctx, Cmd, argtable, true);
5088 CLIParserFree(ctx);
5090 // Check keys.
5092 // dump
5094 PrintAndLogEx(INFO, "to be implemented");
5095 return PM3_SUCCESS;
5099 static int CmdHFiClassConfigCard(const char *Cmd) {
5100 CLIParserContext *ctx;
5101 CLIParserInit(&ctx, "hf iclass configcard",
5102 "Manage reader configuration card via Cardhelper or internal database,\n"
5103 "The generated config card will be uploaded to device emulator memory.\n"
5104 "You can start simulating `hf iclass sim -t 3` or use the emul commands",
5105 "hf iclass configcard -p --> print all config cards in the database\n"
5106 "hf iclass configcard --g 0 --> generate config file with option 0"
5109 void *argtable[] = {
5110 arg_param_begin,
5111 arg_int0(NULL, "g", "<dec>", "use config option"),
5112 arg_int0(NULL, "ki", "<dec>", "Card Key - index to select key from memory 'hf iclass managekeys'"),
5113 arg_int0(NULL, "eki", "<dec>", "Elite Key - index to select key from memory 'hf iclass managekeys'"),
5114 arg_int0(NULL, "mrki", "<dec>", "Standard Master Key - index to select key from memory 'hf iclass managekeys'"),
5115 arg_lit0(NULL, "elite", "Use elite key for the the Card Key ki"),
5116 arg_lit0("p", NULL, "print available cards"),
5117 arg_param_end
5119 CLIExecWithReturn(ctx, Cmd, argtable, false);
5121 int ccidx = arg_get_int_def(ctx, 1, -1);
5122 int card_kidx = arg_get_int_def(ctx, 2, -1);
5123 int kidx = arg_get_int_def(ctx, 3, -1);
5124 int midx = arg_get_int_def(ctx, 4, -1);
5125 bool elite = arg_get_lit(ctx, 5);
5126 bool do_print = arg_get_lit(ctx, 6);
5127 CLIParserFree(ctx);
5129 bool got_eki = false;
5130 uint8_t card_key[8] = {0};
5131 if (card_kidx >= 0) {
5132 if (card_kidx < ICLASS_KEYS_MAX) {
5133 got_eki = true;
5134 memcpy(card_key, iClass_Key_Table[card_kidx], 8);
5135 PrintAndLogEx(SUCCESS, "Using card key[%d] " _GREEN_("%s"), card_kidx, sprint_hex(iClass_Key_Table[card_kidx], 8));
5136 } else {
5137 PrintAndLogEx(ERR, "--ki number is invalid");
5138 return PM3_EINVARG;
5142 bool got_kr = false;
5143 uint8_t keyroll_key[8] = {0};
5144 if (kidx >= 0) {
5145 if (kidx < ICLASS_KEYS_MAX) {
5146 got_kr = true;
5147 memcpy(keyroll_key, iClass_Key_Table[kidx], 8);
5148 PrintAndLogEx(SUCCESS, "Using keyroll key[%d] " _GREEN_("%s"), kidx, sprint_hex(iClass_Key_Table[kidx], 8));
5149 } else {
5150 PrintAndLogEx(ERR, "--eki number is invalid");
5151 return PM3_EINVARG;
5155 bool got_mk = false;
5156 uint8_t master_key[8] = {0};
5157 if (midx >= 0) {
5158 if (midx < ICLASS_KEYS_MAX) {
5159 got_mk = true;
5160 uint8_t key_iclass_format[8] = {0};
5161 permutekey(iClass_Key_Table[midx], key_iclass_format);
5162 memcpy(master_key, key_iclass_format, 8);
5163 PrintAndLogEx(SUCCESS, "Using key[%d] as new Reader's Master Key" _GREEN_("%s"), midx, sprint_hex(iClass_Key_Table[midx], 8));
5164 } else {
5165 PrintAndLogEx(ERR, "--mrki number is invalid");
5166 return PM3_EINVARG;
5170 if (do_print) {
5171 print_config_cards();
5174 if (ccidx > -1 && ccidx < ARRAYLEN(iclass_config_options)) {
5175 const iclass_config_card_item_t *item = get_config_card_item(ccidx);
5176 if (strstr(item->desc, "ELITE") != NULL && got_kr == false) {
5177 PrintAndLogEx(ERR, "please specify ELITE Key (--eki) !");
5178 return PM3_EINVARG;
5180 if (strstr(item->desc, "Custom") != NULL && got_mk == false) {
5181 PrintAndLogEx(ERR, "please specify New Standard Master Key (--mrki) !");
5182 return PM3_EINVARG;
5184 if (strstr(item->desc, "Restore") != NULL && card_kidx == -1) {
5185 PrintAndLogEx(ERR, "please specify the Current Reader's Key (--ki) !");
5186 return PM3_EINVARG;
5188 generate_config_card(item, keyroll_key, got_kr, card_key, got_eki, elite, got_mk, master_key);
5191 return PM3_SUCCESS;
5194 static int CmdHFiClassSAM(const char *Cmd) {
5195 CLIParserContext *ctx;
5196 CLIParserInit(&ctx, "hf iclass sam",
5197 "Extract PACS via a HID SAM\n",
5198 "hf iclass sam\n"
5201 void *argtable[] = {
5202 arg_param_begin,
5203 arg_lit0("v", "verbose", "verbose output"),
5204 arg_param_end
5206 CLIExecWithReturn(ctx, Cmd, argtable, true);
5207 bool verbose = arg_get_lit(ctx, 1);
5208 CLIParserFree(ctx);
5210 if (IsHIDSamPresent(verbose) == false) {
5211 return PM3_ESOFT;
5214 clearCommandBuffer();
5215 SendCommandNG(CMD_HF_SAM_PICOPASS, NULL, 0);
5216 PacketResponseNG resp;
5217 if (WaitForResponseTimeout(CMD_HF_SAM_PICOPASS, &resp, 4000) == false) {
5218 PrintAndLogEx(WARNING, "SAM timeout");
5219 return PM3_ETIMEOUT;
5222 switch (resp.status) {
5223 case PM3_SUCCESS:
5224 break;
5225 case PM3_ENOPACS:
5226 PrintAndLogEx(SUCCESS, "No PACS data found. Card empty?");
5227 return resp.status;
5228 default:
5229 PrintAndLogEx(WARNING, "SAM select failed");
5230 return resp.status;
5233 // CSN, config, epurse, NR/MAC, AIA
5234 // PACS
5235 // first byte skip
5236 // second byte length
5237 // third padded
5238 // fourth ..
5239 uint8_t *d = resp.data.asBytes;
5240 uint8_t n = d[1] - 1; // skip length byte
5241 uint8_t pad = d[2];
5242 char *binstr = (char *)calloc((n * 8) + 1, sizeof(uint8_t));
5243 if (binstr == NULL) {
5244 return PM3_EMALLOC;
5247 bytes_2_binstr(binstr, d + 3, n);
5249 PrintAndLogEx(NORMAL, "");
5250 PrintAndLogEx(SUCCESS, "PACS......... " _GREEN_("%s"), sprint_hex_inrow(d + 2, resp.length - 2));
5251 PrintAndLogEx(SUCCESS, "padded bin... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr));
5253 binstr[strlen(binstr) - pad] = '\0';
5254 PrintAndLogEx(SUCCESS, "bin.......... " _GREEN_("%s") " ( %zu )", binstr, strlen(binstr));
5256 size_t hexlen = 0;
5257 uint8_t hex[16] = {0};
5258 binstr_2_bytes(hex, &hexlen, binstr);
5259 PrintAndLogEx(SUCCESS, "hex.......... " _GREEN_("%s"), sprint_hex_inrow(hex, hexlen));
5261 uint32_t top = 0, mid = 0, bot = 0;
5262 if (binstring_to_u96(&top, &mid, &bot, binstr) != strlen(binstr)) {
5263 PrintAndLogEx(ERR, "Binary string contains none <0|1> chars");
5264 free(binstr);
5265 return PM3_EINVARG;
5268 PrintAndLogEx(NORMAL, "");
5269 PrintAndLogEx(INFO, "Wiegand decode");
5270 wiegand_message_t packed = initialize_message_object(top, mid, bot, strlen(binstr));
5271 HIDTryUnpack(&packed);
5273 PrintAndLogEx(NORMAL, "");
5275 if (strlen(binstr) >= 26 && verbose) {
5277 // iCLASS Legacy
5278 PrintAndLogEx(INFO, "Clone to " _YELLOW_("iCLASS Legacy"));
5279 PrintAndLogEx(SUCCESS, " hf iclass encode --ki 0 --bin %s", binstr);
5280 PrintAndLogEx(NORMAL, "");
5282 // HID Prox II
5283 PrintAndLogEx(INFO, "Downgrade to " _YELLOW_("HID Prox II"));
5284 PrintAndLogEx(SUCCESS, " lf hid clone -w H10301 --bin %s", binstr);
5285 PrintAndLogEx(NORMAL, "");
5287 // MIFARE Classic
5288 char mfcbin[28] = {0};
5289 mfcbin[0] = '1';
5290 memcpy(mfcbin + 1, binstr, strlen(binstr));
5291 binstr_2_bytes(hex, &hexlen, mfcbin);
5293 PrintAndLogEx(INFO, "Downgrade to " _YELLOW_("MIFARE Classic") " (Pm3 simulation)");
5294 PrintAndLogEx(SUCCESS, " hf mf eclr;");
5295 PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 0 -d 049DBA42A23E80884400C82000000000;");
5296 PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 1 -d 1B014D48000000000000000000000000;");
5297 PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 3 -d A0A1A2A3A4A5787788C189ECA97F8C2A;");
5298 PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 5 -d 020000000000000000000000%s;", sprint_hex_inrow(hex, hexlen));
5299 PrintAndLogEx(SUCCESS, " hf mf esetblk --blk 7 -d 484944204953787788AA204752454154;");
5300 PrintAndLogEx(SUCCESS, " hf mf sim --1k -i;");
5301 PrintAndLogEx(NORMAL, "");
5303 PrintAndLogEx(INFO, "Downgrade to " _YELLOW_("MIFARE Classic 1K"));
5304 PrintAndLogEx(SUCCESS, " hf mf encodehid --bin %s", binstr);
5305 PrintAndLogEx(NORMAL, "");
5307 free(binstr);
5309 return PM3_SUCCESS;
5312 static command_t CommandTable[] = {
5313 {"help", CmdHelp, AlwaysAvailable, "This help"},
5314 {"list", CmdHFiClassList, AlwaysAvailable, "List iclass history"},
5315 // {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"},
5316 {"-----------", CmdHelp, IfPm3Iclass, "------------------- " _CYAN_("Operations") " -------------------"},
5317 // {"clone", CmdHFiClassClone, IfPm3Iclass, "Create a HID credential to Picopass / iCLASS tag"},
5318 {"dump", CmdHFiClassDump, IfPm3Iclass, "Dump Picopass / iCLASS tag to file"},
5319 {"info", CmdHFiClassInfo, IfPm3Iclass, "Tag information"},
5320 {"rdbl", CmdHFiClass_ReadBlock, IfPm3Iclass, "Read Picopass / iCLASS block"},
5321 {"reader", CmdHFiClassReader, IfPm3Iclass, "Act like a Picopass / iCLASS reader"},
5322 {"restore", CmdHFiClassRestore, IfPm3Iclass, "Restore a dump file onto a Picopass / iCLASS tag"},
5323 {"sniff", CmdHFiClassSniff, IfPm3Iclass, "Eavesdrop Picopass / iCLASS communication"},
5324 {"view", CmdHFiClassView, AlwaysAvailable, "Display content from tag dump file"},
5325 {"wrbl", CmdHFiClass_WriteBlock, IfPm3Iclass, "Write Picopass / iCLASS block"},
5326 {"creditepurse", CmdHFiClassCreditEpurse, IfPm3Iclass, "Credit epurse value"},
5327 {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("Recovery") " --------------------"},
5328 // {"autopwn", CmdHFiClassAutopwn, IfPm3Iclass, "Automatic key recovery tool for iCLASS"},
5329 {"chk", CmdHFiClassCheckKeys, IfPm3Iclass, "Check keys"},
5330 {"loclass", CmdHFiClass_loclass, AlwaysAvailable, "Use loclass to perform bruteforce reader attack"},
5331 {"lookup", CmdHFiClassLookUp, AlwaysAvailable, "Uses authentication trace to check for key in dictionary file"},
5332 {"legrec", CmdHFiClassLegacyRecover, IfPm3Iclass, "Recovers 24 bits of the diversified key of a legacy card provided a valid nr-mac combination"},
5333 {"legbrute", CmdHFiClassLegRecLookUp, AlwaysAvailable, "Bruteforces 40 bits of a partial diversified key, provided 24 bits of the key and two valid nr-macs"},
5334 {"unhash", CmdHFiClassUnhash, AlwaysAvailable, "Reverses a diversified key to retrieve hash0 pre-images after DES encryption"},
5335 {"-----------", CmdHelp, IfPm3Iclass, "-------------------- " _CYAN_("Simulation") " -------------------"},
5336 {"sim", CmdHFiClassSim, IfPm3Iclass, "Simulate iCLASS tag"},
5337 {"eload", CmdHFiClassELoad, IfPm3Iclass, "Upload file into emulator memory"},
5338 {"esave", CmdHFiClassESave, IfPm3Iclass, "Save emulator memory to file"},
5339 {"esetblk", CmdHFiClassESetBlk, IfPm3Iclass, "Set emulator memory block data"},
5340 {"eview", CmdHFiClassEView, IfPm3Iclass, "View emulator memory"},
5341 {"-----------", CmdHelp, AlwaysAvailable, "---------------------- " _CYAN_("Utils") " ----------------------"},
5342 {"configcard", CmdHFiClassConfigCard, IfPm3Iclass, "Reader configuration card generator"},
5343 {"calcnewkey", CmdHFiClassCalcNewKey, AlwaysAvailable, "Calc diversified keys (blocks 3 & 4) to write new keys"},
5344 {"encode", CmdHFiClassEncode, AlwaysAvailable, "Encode binary wiegand to block 7"},
5345 {"encrypt", CmdHFiClassEncryptBlk, AlwaysAvailable, "Encrypt given block data"},
5346 {"decrypt", CmdHFiClassDecrypt, AlwaysAvailable, "Decrypt given block data or tag dump file" },
5347 {"managekeys", CmdHFiClassManageKeys, AlwaysAvailable, "Manage keys to use with iclass commands"},
5348 {"permutekey", CmdHFiClassPermuteKey, AlwaysAvailable, "Permute function from 'heart of darkness' paper"},
5349 {"-----------", CmdHelp, IfPm3Smartcard, "----------------------- " _CYAN_("SAM") " -----------------------"},
5350 {"sam", CmdHFiClassSAM, IfPm3Smartcard, "SAM tests"},
5351 {NULL, NULL, NULL, NULL}
5354 static int CmdHelp(const char *Cmd) {
5355 (void)Cmd; // Cmd is not used so far
5356 CmdsHelp(CommandTable);
5357 return PM3_SUCCESS;
5360 int CmdHFiClass(const char *Cmd) {
5361 clearCommandBuffer();
5362 return CmdsParse(CommandTable, Cmd);
5365 // static void test_credential_type(void) {
5366 // need AA1 key
5367 // Block 5 -> tells if its a legacy or SIO, also tells which key to use.
5369 // tech | blocks used | desc | num of payloads
5370 // -------+-----------------------+-----------------------------------+------
5371 // legacy | 6,7,8,9 | AA!, Access control payload | 1
5372 // SE | 6,7,8,9,10,11,12 | AA1, Secure identity object (SIO) | 1
5373 // SR | 6,7,8,9, | AA1, Access control payload | 2
5374 // | 10,11,12,13,14,15,16 | AA1, Secure identity object (SIO) |
5375 // SEOS | | |
5376 // MFC SIO| | |
5377 // DESFIRE| | |
5380 int info_iclass(bool shallow_mod) {
5382 iclass_card_select_t payload = {
5383 .flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE)
5386 if (shallow_mod) {
5387 payload.flags |= FLAG_ICLASS_READER_SHALLOW_MOD;
5390 clearCommandBuffer();
5391 PacketResponseNG resp;
5392 SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t *)&payload, sizeof(iclass_card_select_t));
5394 if (WaitForResponseTimeout(CMD_HF_ICLASS_READER, &resp, 2000) == false) {
5395 DropField();
5396 return PM3_ETIMEOUT;
5398 DropField();
5400 iclass_card_select_resp_t *r = (iclass_card_select_resp_t *)resp.data.asBytes;
5402 uint8_t *p_response = (uint8_t *)&r->header.hdr;
5403 // no tag found or button pressed
5404 if (r->status == FLAG_ICLASS_NULL || resp.status == PM3_ERFTRANS) {
5405 return PM3_EOPABORTED;
5408 picopass_hdr_t *hdr = &r->header.hdr;
5409 picopass_ns_hdr_t *ns_hdr = &r->header.ns_hdr;
5411 PrintAndLogEx(NORMAL, "");
5412 PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ----------------------------------------");
5414 if ((r->status & FLAG_ICLASS_CSN) == FLAG_ICLASS_CSN) {
5415 PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn)));
5418 if ((r->status & FLAG_ICLASS_CONF) == FLAG_ICLASS_CONF) {
5419 PrintAndLogEx(SUCCESS, " Config: %s card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf)));
5422 // page mapping. If fuse0|1 == 0x01, card is in non-secure mode, with CSN, CONF, AIA as top 3 blocks.
5423 // page9 in http://www.proxmark.org/files/Documents/13.56%20MHz%20-%20iClass/DS%20Picopass%202KS%20V1-0.pdf
5424 uint8_t pagemap = get_pagemap(hdr);
5425 if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
5426 PrintAndLogEx(SUCCESS, " AIA: %s application issuer area", sprint_hex(ns_hdr->app_issuer_area, sizeof(ns_hdr->app_issuer_area)));
5427 } else {
5429 if ((r->status & FLAG_ICLASS_CC) == FLAG_ICLASS_CC) {
5430 PrintAndLogEx(SUCCESS, "E-purse: %s Card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse)));
5433 if (memcmp(hdr->key_d, zeros, sizeof(zeros))) {
5434 PrintAndLogEx(SUCCESS, " Kd: " _YELLOW_("%s") " debit key", sprint_hex(hdr->key_d, sizeof(hdr->key_d)));
5435 } else {
5436 PrintAndLogEx(SUCCESS, " Kd: %s debit key ( hidden )", sprint_hex(hdr->key_d, sizeof(hdr->key_d)));
5439 if (memcmp(hdr->key_c, zeros, sizeof(zeros))) {
5440 PrintAndLogEx(SUCCESS, " Kc: " _YELLOW_("%s") " credit key", sprint_hex(hdr->key_c, sizeof(hdr->key_c)));
5441 } else {
5442 PrintAndLogEx(SUCCESS, " Kc: %s credit key ( hidden )", sprint_hex(hdr->key_c, sizeof(hdr->key_c)));
5446 if ((r->status & FLAG_ICLASS_AIA) == FLAG_ICLASS_AIA) {
5447 PrintAndLogEx(SUCCESS, " AIA: %s application issuer area", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area)));
5451 if ((r->status & FLAG_ICLASS_CONF) == FLAG_ICLASS_CONF) {
5452 print_picopass_info(hdr);
5455 PrintAndLogEx(INFO, "------------------------ " _CYAN_("Fingerprint") " -----------------------");
5457 uint8_t aia[8];
5458 if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
5459 memcpy(aia, ns_hdr->app_issuer_area, sizeof(aia));
5460 } else {
5461 memcpy(aia, hdr->app_issuer_area, sizeof(aia));
5464 // if CSN starts with E012FFF (big endian), it's inside HID CSN range.
5465 bool is_hid_range = (hdr->csn[4] & 0xF0) == 0xF0 && (memcmp(hdr->csn + 5, "\xFF\x12\xE0", 3) == 0);
5467 bool legacy = (memcmp(aia, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0);
5468 bool se_enabled = (memcmp(aia, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0);
5470 if (is_hid_range) {
5471 PrintAndLogEx(SUCCESS, " CSN.......... " _YELLOW_("HID range"));
5473 if (legacy) {
5474 PrintAndLogEx(SUCCESS, " Credential... " _GREEN_("iCLASS legacy"));
5477 if (se_enabled) {
5478 PrintAndLogEx(SUCCESS, " Credential... " _GREEN_("iCLASS SE"));
5480 } else {
5481 PrintAndLogEx(SUCCESS, " CSN.......... " _YELLOW_("outside HID range"));
5484 uint8_t cardtype = get_mem_config(hdr);
5485 PrintAndLogEx(SUCCESS, " Card type.... " _GREEN_("%s"), card_types[cardtype]);
5487 if (HF14B_picopass_reader(false, false)) {
5488 PrintAndLogEx(SUCCESS, " Card chip.... "_YELLOW_("Old Silicon (14b support)"));
5489 } else {
5490 PrintAndLogEx(SUCCESS, " Card chip.... "_YELLOW_("NEW Silicon (No 14b support)"));
5492 if (legacy) {
5494 int res = PM3_ESOFT;
5495 uint8_t key_type = 0x88; // debit key
5497 uint8_t dump[PICOPASS_BLOCK_SIZE * 8] = {0};
5498 // we take all raw bytes from response
5499 memcpy(dump, p_response, sizeof(picopass_hdr_t));
5501 uint8_t key[8] = {0};
5502 for (uint8_t i = 0; i < ARRAYLEN(iClass_Key_Table); i++) {
5504 memcpy(key, iClass_Key_Table[i], sizeof(key));
5505 res = iclass_read_block_ex(key, 6, key_type, false, false, false, false, true, false, dump + (PICOPASS_BLOCK_SIZE * 6), false);
5506 if (res == PM3_SUCCESS) {
5507 PrintAndLogEx(SUCCESS, " AA1 Key...... " _GREEN_("%s"), sprint_hex_inrow(key, sizeof(key)));
5508 break;
5512 if (res == PM3_SUCCESS) {
5513 res = iclass_read_block_ex(key, 7, key_type, false, false, false, false, true, false, dump + (PICOPASS_BLOCK_SIZE * 7), false);
5514 if (res == PM3_SUCCESS) {
5516 BLOCK79ENCRYPTION aa1_encryption = (dump[(6 * PICOPASS_BLOCK_SIZE) + 7] & 0x03);
5518 uint8_t decrypted[PICOPASS_BLOCK_SIZE * 8] = {0};
5519 memcpy(decrypted, dump, 7 * PICOPASS_BLOCK_SIZE);
5521 uint8_t transport[16] = {0};
5522 iclass_load_transport(transport, sizeof(transport));
5523 iclass_decrypt_transport(transport, 8, dump, decrypted, aa1_encryption);
5524 iclass_decode_credentials(decrypted);
5529 return PM3_SUCCESS;