1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
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.
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"
21 #include "cliparser.h"
22 #include "cmdparser.h" // command_t
23 #include "commonutil.h" // ARRAYLEN
25 #include "util_posix.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"
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);
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
));
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);
113 iclass_prekey_t
*item
= (iclass_prekey_t
*) bsearch(&lookup
, prekey
, ICLASS_KEYS_MAX
* 2, sizeof(iclass_prekey_t
), cmp_uint32
);
115 memcpy(key
, item
->key
, 8);
131 static int iclass_load_transport(uint8_t *key
, uint8_t n
) {
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");
141 PrintAndLogEx(ERR
, "Failed to load transport key from file");
147 PrintAndLogEx(ERR
, "Array size mismatch");
152 memcpy(key
, keyptr
, n
);
157 static void iclass_decrypt_transport(uint8_t *key
, uint8_t limit
, uint8_t *enc_data
, uint8_t *dec_data
, BLOCK79ENCRYPTION aa1_encryption
) {
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
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;
180 // Nothing to do for None anyway...
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
) {
196 return __builtin_clzll(a
);
202 static void iclass_upload_emul(uint8_t *d
, uint16_t n
, uint16_t offset
, uint16_t *bytes_sent
) {
211 g_conn
.block_after_ACK
= true;
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
);
236 bytes_remaining
-= bytes_in_packet
;
237 *bytes_sent
+= bytes_in_packet
;
239 PrintAndLogEx(NORMAL
, "." NOLF
);
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
[] = {
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
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);
345 HFiClassCalcDivKey(configcard
.csn
, card_key
, configcard
.key_d
, use_elite
);
347 // defaulting to AA1 ki 0
348 HFiClassCalcDivKey(configcard
.csn
, iClass_Key_Table
[0], configcard
.key_d
, use_elite
);
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
361 HFiClassCalcDivKey(cc
->csn
, card_key
, cc
->key_d
, use_elite
);
363 // defaulting to AA1 ki 0
364 HFiClassCalcDivKey(cc
->csn
, iClass_Key_Table
[0], cc
->key_d
, use_elite
);
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
);
380 uint8_t *data
= calloc(1, tot_bytes
);
382 PrintAndLogEx(FAILED
, "failed to allocate memory");
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
;
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");
401 PrintAndLogEx(ERR
, "Failed to load transport key from file");
406 memcpy(key_en
, keyptr_en
, sizeof(key_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!");
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..");
423 cc
->conf
.app_limit
= 0x16;
424 tot_bytes
= (app1_limit
+ 1) * 8;
426 uint8_t *p
= realloc(data
, tot_bytes
);
428 PrintAndLogEx(FAILED
, "failed to allocate memory");
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");
446 PrintAndLogEx(NORMAL
, "( " _GREEN_("ok") " )");
449 iclass_encrypt_block_data(ffs
, key_en
);
450 PrintAndLogEx(NORMAL
, "( " _GREEN_("ok") " )");
454 PrintAndLogEx(INFO
, "Encrypting local key... " NOLF
);
456 memcpy(lkey
, key
, sizeof(lkey
));
458 if (IsCardHelperPresent(false) != false) {
459 if (Encrypt(lkey
, enckey1
) == false) {
460 PrintAndLogEx(WARNING
, "failed to encrypt key1");
462 PrintAndLogEx(NORMAL
, "( " _GREEN_("ok") " )");
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
));
477 memcpy(data
+ (0x0D * 8), lkey
, sizeof(enckey1
));
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);
494 if (IsCardHelperPresent(false) != false) {
495 if (Encrypt(foo
, enckey2
) == false) {
496 PrintAndLogEx(WARNING
, "failed to encrypt partial 1");
498 PrintAndLogEx(NORMAL
, "( " _GREEN_("ok") " )");
499 memcpy(data
+ (0x14 * 8), enckey2
, sizeof(enckey2
));
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
));
511 if (IsCardHelperPresent(false) != false) {
512 if (Encrypt(foo
, enckey2
) == false) {
513 PrintAndLogEx(WARNING
, "failed to encrypt partial 2");
515 PrintAndLogEx(NORMAL
, "( " _GREEN_("ok") " )");
516 memcpy(data
+ (0x15 * 8), enckey2
, sizeof(enckey2
));
519 iclass_encrypt_block_data(foo
, key_en
);
520 PrintAndLogEx(NORMAL
, "( " _GREEN_("ok") " )");
521 memcpy(data
+ (0x15 * 8), foo
, sizeof(enckey2
));
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
);
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!");
545 iclass_encrypt_block_data(master_key
, key_en
);
546 memcpy(data
+ (0x07 * 8), master_key
, PICOPASS_BLOCK_SIZE
);
551 PrintAndLogEx(INFO
, "Uploading to device... ");
552 uint16_t bytes_sent
= 0;
553 iclass_upload_emul(data
, tot_bytes
, 0, &bytes_sent
);
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");
563 static uint8_t isset(uint8_t val
, uint8_t 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)"));
594 PrintAndLogEx(SUCCESS
, " mode......... " _YELLOW_("Application (locked)"));
596 if (isset(fuses
, FUSE_CODING1
)) {
597 PrintAndLogEx(SUCCESS
, " coding...... RFU");
599 if (isset(fuses
, FUSE_CODING0
))
600 PrintAndLogEx(SUCCESS
, " coding....... " _YELLOW_("ISO 14443-2 B / 15693"));
602 PrintAndLogEx(SUCCESS
, " coding....... " _YELLOW_("ISO 14443-B only"));
605 uint8_t pagemap
= get_pagemap(hdr
);
608 PrintAndLogEx(INFO
, " crypt........ No auth possible. Read only if RA is enabled");
611 PrintAndLogEx(SUCCESS
, " crypt........ Non secured page");
614 PrintAndLogEx(INFO
, " crypt........ Secured page, keys locked");
617 PrintAndLogEx(SUCCESS
, " crypt........ Secured page, " _GREEN_("keys not locked"));
621 if (isset(fuses
, FUSE_RA
))
622 PrintAndLogEx(SUCCESS
, " RA........... Read access enabled (non-secure mode)");
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
637 // chip-bit 4 = Multi App
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
) {
648 } else if (isset(chip_cfg
, 0x10) && k16
&& !book
) {
651 } else if (notset(chip_cfg
, 0x10) && !k16
&& !book
) {
655 } else if (isset(chip_cfg
, 0x10) && k16
&& book
) {
659 } else if (notset(chip_cfg
, 0x10) && !k16
&& book
) {
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;
674 type
|= (hdr
->conf
.mem_config
& 0x80) >> 6;
676 type
|= (hdr
->conf
.mem_config
& 0x20) >> 5;
678 //type |= (hdr->conf.mem_config & 0x10) >> 5;
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
;
686 uint8_t app_areas
= 2;
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");
705 PrintAndLogEx(INFO
, " %u KBits/%u App Areas ( " _YELLOW_("%u") " bytes )"
708 , ((app2_limit
+ 1) * 8) * books
* pages
);
710 PrintAndLogEx(INFO
, " %u books / %u 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);
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");
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") " --------------------");
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
)));
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
)));
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",
783 "hf iclass sniff -j --> jam e-purse updates\n"
788 arg_lit0("j", "jam", "Jam (prevent) e-purse updates"),
792 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
793 bool jam_epurse_update
= arg_get_lit(ctx
, 1);
796 if (jam_epurse_update
) {
797 PrintAndLogEx(INFO
, "Sniff with jam of iCLASS e-purse updates...");
801 uint8_t jam_search_len
;
802 uint8_t jam_search_string
[2];
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
, "");
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");
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"),
845 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
847 int sim_type
= arg_get_int_def(ctx
, 1, 3);
850 uint8_t csn
[8] = {0};
851 CLIGetHexWithReturn(ctx
, 2, csn
, &csn_len
);
853 if (sim_type
== 0 && csn_len
> 0) {
855 PrintAndLogEx(ERR
, "CSN is incorrect length");
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)");
869 PrintAndLogEx(ERR
, "Undefined simtype %d", sim_type
);
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
891 * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
892 * So, it should wind up as
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
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) {
912 if (kbd_enter_pressed()) {
913 PrintAndLogEx(WARNING
, "\naborted via keyboard.");
914 return PM3_EOPABORTED
;
917 PrintAndLogEx(WARNING
, "\ntimeout while waiting for reply.");
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");
928 size_t datalen
= NUM_CSNS
* MAC_ITEM_SIZE
;
929 uint8_t *dump
= calloc(datalen
, sizeof(uint8_t));
931 PrintAndLogEx(WARNING
, "Failed to allocate memory");
935 memset(dump
, 0, datalen
);//<-- Need zeroes for the EPURSE - field (official)
938 for (i
= 0 ; i
< NUM_CSNS
; i
++) {
940 memcpy(dump
+ (i
* MAC_ITEM_SIZE
), csns
+ i
* 8, 8);
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
);
950 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf iclass loclass -f iclass_mac_attack.bin") "` to recover elite key");
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) {
963 if (kbd_enter_pressed()) {
964 PrintAndLogEx(WARNING
, "\naborted via keyboard.");
965 return PM3_EOPABORTED
;
968 PrintAndLogEx(WARNING
, "\ntimeout while waiting for reply.");
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");
979 size_t datalen
= NUM_CSNS
* MAC_ITEM_SIZE
;
980 uint8_t *dump
= calloc(datalen
, sizeof(uint8_t));
982 PrintAndLogEx(WARNING
, "Failed to allocate memory");
987 //Need zeroes for the CC-field
988 memset(dump
, 0, datalen
);
989 for (uint8_t i
= 0; i
< NUM_CSNS
; i
++) {
991 memcpy(dump
+ (i
* MAC_ITEM_SIZE
), csns
+ i
* 8, 8); //CSN
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
);
1000 memset(dump
, 0, datalen
);
1001 for (uint8_t i
= 0; i
< NUM_CSNS
; i
++) {
1002 uint8_t resp_index
= (i
+ NUM_CSNS
) * 16;
1004 memcpy(dump
+ (i
* MAC_ITEM_SIZE
), csns
+ i
* 8, 8);
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);
1011 saveFile("iclass_mac_attack_keyroll_B", ".bin", dump
, datalen
);
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");
1018 case ICLASS_SIM_MODE_CSN
:
1019 case ICLASS_SIM_MODE_CSN_DEFAULT
:
1020 case ICLASS_SIM_MODE_FULL
:
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");
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.",
1042 void *argtable
[] = {
1044 arg_lit0(NULL
, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
1047 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1048 bool shallow_mod
= arg_get_lit(ctx
, 1);
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
)
1060 payload
.flags
|= FLAG_ICLASS_READER_SHALLOW_MOD
;
1063 int res
= PM3_SUCCESS
;
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
;
1074 if (resp
.status
== PM3_ERFTRANS
) {
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
;
1086 picopass_hdr_t
*card
= calloc(1, sizeof(picopass_hdr_t
));
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
);
1097 PrintAndLogEx(FAILED
, "failed to allocate memory");
1101 } while (loop
&& kbd_enter_pressed() == false);
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
[] = {
1117 arg_lit0("@", NULL
, "optional - continuous reader mode"),
1118 arg_lit0(NULL
, "shallow", "use shallow (ASK) reader modulation instead of OOK"),
1121 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1122 bool cm
= arg_get_lit(ctx
, 1);
1123 bool shallow_mod
= arg_get_lit(ctx
, 2);
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
[] = {
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"),
1148 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
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");
1160 bool use_spiffs
= arg_get_lit(ctx
, 2);
1161 bool verbose
= arg_get_lit(ctx
, 3);
1165 if (use_spiffs
&& IfPm3Flash() == false) {
1166 PrintAndLogEx(WARNING
, "Device not compiled to support spiffs");
1173 PrintAndLogEx(WARNING
, "filename too long for spiffs, expected 32, got %u", fnlen
);
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");
1190 PrintAndLogEx(SUCCESS
, "File transfered from spiffs to device emulator memory");
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
) {
1202 uint8_t *newdump
= realloc(dump
, bytes_read
);
1203 if (newdump
== NULL
) {
1211 print_picopass_header((picopass_hdr_t
*) dump
);
1212 print_picopass_info((picopass_hdr_t
*) dump
);
1215 PrintAndLogEx(NORMAL
, "");
1218 uint16_t bytes_sent
= 0;
1219 iclass_upload_emul(dump
, bytes_read
, 0, &bytes_sent
);
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!");
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.",
1233 "hf iclass esave -f hf-iclass-dump\n"
1234 "hf iclass esave -s 2048 -f hf-iclass-dump");
1236 void *argtable
[] = {
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)"),
1242 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
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);
1250 PrintAndLogEx(WARNING
, "Emulator memory is max 4096bytes. Truncating %u to 4096", bytes
);
1256 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
1258 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
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");
1266 return PM3_ETIMEOUT
;
1269 // user supplied filename?
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
);
1279 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf iclass view -f") "` to view dump file");
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.",
1289 "hf iclass eview -s 2048\n"
1290 "hf iclass eview -s 2048 -v");
1292 void *argtable
[] = {
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"),
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);
1310 PrintAndLogEx(WARNING
, "Emulator memory is max 4096bytes. Truncating %u to 4096", bytes
);
1314 if (bytes
% 8 != 0) {
1316 PrintAndLogEx(WARNING
, "Number not divided by 8, truncating to %u", bytes
);
1319 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
1321 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
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");
1330 return PM3_ETIMEOUT
;
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
);
1342 print_iclass_sio(dump
, bytes
);
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
[] = {
1357 arg_int1(NULL
, "blk", "<dec>", "block number"),
1358 arg_str0("d", "data", "<hex>", "bytes to write, 8 hex bytes"),
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
);
1371 uint8_t data
[PICOPASS_BLOCK_SIZE
] = {0x00};
1373 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 2), data
, sizeof(data
), &datalen
);
1377 PrintAndLogEx(FAILED
, "Error parsing bytes");
1381 if (datalen
!= PICOPASS_BLOCK_SIZE
) {
1382 PrintAndLogEx(WARNING
, "block data must include 8 HEX bytes. Got " _RED_("%i"), datalen
);
1386 uint16_t bytes_sent
= 0;
1387 iclass_upload_emul(data
, sizeof(data
), blk
* PICOPASS_BLOCK_SIZE
, &bytes_sent
);
1392 static bool iclass_detect_new_pacs(uint8_t *d
) {
1394 while (n
++ < (PICOPASS_BLOCK_SIZE
/ 2)) {
1395 if (d
[n
] && d
[n
+ 1] == 0xA6) {
1402 // block 7 decoder for PACS
1403 static int iclass_decode_credentials_new_pacs(uint8_t *d
) {
1406 while (d
[offset
] == 0 && (offset
< PICOPASS_BLOCK_SIZE
/ 2)) {
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
) {
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
));
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");
1443 PrintAndLogEx(NORMAL
, "");
1444 PrintAndLogEx(INFO
, "Wiegand decode");
1445 wiegand_message_t packed
= initialize_message_object(top
, mid
, bot
, 0);
1446 HIDTryUnpack(&packed
);
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.
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");
1470 iclass_decode_credentials_new_pacs(b7
);
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
);
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"
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"
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
[] = {
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"),
1522 CLIExecWithReturn(clictx
, Cmd
, argtable
, false);
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
);
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
);
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)");
1557 if (key_len
!= 16) {
1558 PrintAndLogEx(ERR
, "Transport key must be 16 hex bytes (32 HEX characters)");
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
1573 res
= pm3_load_dump(filename
, (void **)&decrypted
, &decryptedlen
, 2048);
1574 if (res
!= PM3_SUCCESS
) {
1581 // load transport key
1582 bool use_sc
= false;
1583 if (have_key
== false) {
1584 use_sc
= IsCardHelperPresent(verbose
);
1585 if (use_sc
== false) {
1587 res
= loadFile_safe(ICLASS_DECRYPTION_BIN
, "", (void **)&keyptr
, &keylen
);
1588 if (res
!= PM3_SUCCESS
) {
1589 PrintAndLogEx(INFO
, "Couldn't find any decryption methods");
1595 PrintAndLogEx(ERR
, "Failed to load transport key from file");
1600 memcpy(key
, keyptr
, sizeof(key
));
1606 mbedtls_des3_context ctx
;
1607 mbedtls_des3_set2key_dec(&ctx
, key
);
1609 // decrypt user supplied data
1612 uint8_t dec_data
[PICOPASS_BLOCK_SIZE
] = {0};
1614 Decrypt(enc_data
, dec_data
);
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
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
;
1636 uint8_t app_areas
= 2;
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
1661 // Decrypt block 7,8,9 if configured.
1662 if (blocknum
> 6 && blocknum
<= 9 && memcmp(enc_data
, empty
, PICOPASS_BLOCK_SIZE
) != 0) {
1664 Decrypt(enc_data
, decrypted
+ idx
);
1666 mbedtls_des3_crypt_ecb(&ctx
, enc_data
, decrypted
+ idx
);
1668 decrypted_block789
= true;
1674 // Nothing to do for None anyway...
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;
1686 PrintAndLogEx(INFO
, "Called with no save option");
1687 PrintAndLogEx(NORMAL
, "");
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");
1698 strcat(fptr
, "hf-iclass-");
1699 FillFileNameByUID(fptr
, hdr
->csn
, "-dump-decrypted", sizeof(hdr
->csn
));
1701 pm3_save_dump(fptr
, decrypted
, decryptedlen
, jsfIclass
);
1705 printIclassDumpContents(decrypted
, 1, (decryptedlen
/ 8), decryptedlen
, dense_output
);
1708 print_iclass_sio(decrypted
, decryptedlen
);
1711 PrintAndLogEx(NORMAL
, "");
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
);
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));
1733 uint64_t pin
= bytes_to_num(decrypted
+ (PICOPASS_BLOCK_SIZE
* 9), 5);
1735 snprintf(tmp
, sizeof(tmp
), "%."PRIu64
, BCD2DEC(pin
));
1736 PrintAndLogEx(INFO
, "PIN........................ " _GREEN_("%.*s"), pinsize
, tmp
);
1741 PrintAndLogEx(INFO
, "-----------------------------------------------------------------");
1745 mbedtls_des3_free(&ctx
);
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
[] = {
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"),
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
);
1779 uint8_t key
[16] = {0};
1780 uint8_t *keyptr
= NULL
;
1781 bool have_key
= false;
1783 CLIGetHexWithReturn(clictx
, 2, key
, &key_len
);
1786 if (key_len
!= 16) {
1787 PrintAndLogEx(ERR
, "Transport key must be 16 hex bytes (32 HEX characters)");
1788 CLIParserFree(clictx
);
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) {
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");
1810 PrintAndLogEx(ERR
, "Failed to load transport key from file");
1814 memcpy(key
, keyptr
, sizeof(key
));
1820 PrintAndLogEx(SUCCESS
, "plain....... %s", sprint_hex_inrow(blk_data
, sizeof(blk_data
)));
1823 Encrypt(blk_data
, blk_data
);
1825 iclass_encrypt_block_data(blk_data
, key
);
1828 PrintAndLogEx(SUCCESS
, "encrypted... " _YELLOW_("%s"), sprint_hex_inrow(blk_data
, sizeof(blk_data
)));
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
)
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");
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
) {
1857 PrintAndLogEx(FAILED
, "failed tag-select, aborting... (%d)", r
->status
);
1863 memcpy(CSN
, hdr
->csn
, 8);
1866 memcpy(CCNR
, hdr
->epurse
, 8);
1869 PrintAndLogEx(SUCCESS
, "CSN %s", sprint_hex(CSN
, 8));
1870 PrintAndLogEx(SUCCESS
, "epurse %s", sprint_hex(CCNR
, 8));
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
[] = {
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"),
1901 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1904 char filename
[FILE_PATH_SIZE
] = {0};
1905 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
1908 uint8_t key
[8] = {0};
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");
1924 PrintAndLogEx(ERR
, "Debit key is incorrect length");
1930 if (deb_key_nr
>= 0) {
1931 if (deb_key_nr
< ICLASS_KEYS_MAX
) {
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));
1936 PrintAndLogEx(ERR
, "Key number is invalid");
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");
1956 if (credit_key_len
> 0) {
1958 have_credit_key
= true;
1959 if (credit_key_len
!= 8) {
1960 PrintAndLogEx(ERR
, "Credit key is incorrect length");
1966 if (credit_key_nr
>= 0) {
1967 if (credit_key_nr
< ICLASS_KEYS_MAX
) {
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));
1973 PrintAndLogEx(ERR
, "Key number is invalid");
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);
1989 if ((use_replay
+ rawkey
+ elite
) > 1) {
1990 PrintAndLogEx(ERR
, "Can not use a combo of 'elite', 'raw', 'nr'");
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
)
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");
2019 if (resp
.status
== PM3_ERFTRANS
) {
2020 PrintAndLogEx(FAILED
, "no tag found");
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");
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
];
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
];
2051 app_limit1
= hdr
->conf
.app_limit
;
2052 app_limit2
= card_app2_limit
[type
];
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
);
2065 PrintAndLogEx(INFO
, "No keys needed, ignoring user supplied key");
2068 if (auth
== false) {
2069 PrintAndLogEx(FAILED
, "Run command with keys");
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
);
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;
2097 payload
.start_block
= 5;
2100 clearCommandBuffer();
2101 SendCommandNG(CMD_HF_ICLASS_DUMP
, (uint8_t *)&payload
, sizeof(payload
));
2105 PrintAndLogEx(NORMAL
, "." NOLF
);
2106 if (kbd_enter_pressed()) {
2107 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
2109 return PM3_EOPABORTED
;
2112 if (WaitForResponseTimeout(CMD_HF_ICLASS_DUMP
, &resp
, 2000))
2116 PrintAndLogEx(NORMAL
, "");
2117 if (resp
.status
!= PM3_SUCCESS
) {
2118 PrintAndLogEx(ERR
, "failed to communicate with card");
2127 struct p_resp
*packet
= (struct p_resp
*)resp
.data
.asBytes
;
2129 if (packet
->isOK
== false) {
2130 PrintAndLogEx(WARNING
, "read AA1 blocks failed");
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
) {
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
));
2174 PrintAndLogEx(NORMAL
, "." NOLF
);
2175 if (kbd_enter_pressed()) {
2176 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
2178 return PM3_EOPABORTED
;
2181 if (WaitForResponseTimeout(CMD_HF_ICLASS_DUMP
, &resp
, 2000))
2184 PrintAndLogEx(NORMAL
, "");
2185 if (resp
.status
!= PM3_SUCCESS
) {
2186 PrintAndLogEx(ERR
, "failed to communicate with card");
2190 packet
= (struct p_resp
*)resp
.data
.asBytes
;
2191 if (packet
->isOK
== false) {
2192 PrintAndLogEx(WARNING
, "failed read block using credit key");
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");
2211 memcpy(tag_data
+ (PICOPASS_BLOCK_SIZE
* 4), tempbuf
+ (PICOPASS_BLOCK_SIZE
* 4), PICOPASS_BLOCK_SIZE
);
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
);
2225 if (have_credit_key
&& pagemap
!= 0x01 && aa2_success
== false) {
2226 PrintAndLogEx(INFO
, "Reading AA2 failed. dumping AA1 data to file");
2230 printIclassDumpContents(tag_data
, 1, (bytes_got
/ 8), bytes_got
, dense_output
);
2233 PrintAndLogEx(INFO
, "Called with no save option");
2234 PrintAndLogEx(NORMAL
, "");
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
, "");
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
));
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");
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
[] = {
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"),
2314 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
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");
2334 PrintAndLogEx(ERR
, "Key is incorrect length");
2338 } else if (key_nr
>= 0) {
2339 if (key_nr
< ICLASS_KEYS_MAX
) {
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));
2344 PrintAndLogEx(ERR
, "Key number is invalid");
2350 int blockno
= arg_get_int_def(ctx
, 3, 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)");
2363 uint8_t mac
[4] = {0};
2364 CLIGetHexWithReturn(ctx
, 5, mac
, &mac_len
);
2368 PrintAndLogEx(ERR
, "MAC must be 4 hex bytes (8 hex symbols)");
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);
2384 if ((use_replay
+ rawkey
+ elite
) > 1) {
2385 PrintAndLogEx(ERR
, "Can not use a combo of 'elite', 'raw', 'nr'");
2389 int isok
= iclass_write_block(blockno
, data
, mac
, key
, use_credit_key
, elite
, rawkey
, use_replay
, verbose
, auth
, shallow_mod
);
2392 PrintAndLogEx(SUCCESS
, "Wrote block " _YELLOW_("%d") " / " _YELLOW_("0x%02X") " ( " _GREEN_("ok") " )", blockno
, blockno
);
2396 PrintAndLogEx(INFO
, "Writing tear off triggered");
2399 PrintAndLogEx(FAILED
, "Writing failed");
2402 PrintAndLogEx(NORMAL
, "");
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
[] = {
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"),
2426 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
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");
2443 PrintAndLogEx(ERR
, "Key is incorrect length");
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));
2452 PrintAndLogEx(ERR
, "Key number is invalid");
2457 PrintAndLogEx(ERR
, "Key or key number must be provided");
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)");
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);
2481 if ((rawkey
+ elite
) > 1) {
2482 PrintAndLogEx(ERR
, "Can not use a combo of 'elite', 'raw'");
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
;
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");
2511 isok
= (resp
.data
.asBytes
[0] == 1) ? PM3_SUCCESS
: PM3_ESOFT
;
2516 PrintAndLogEx(SUCCESS
, "Credited epurse successfully");
2520 PrintAndLogEx(INFO
, "Writing tear off triggered");
2523 PrintAndLogEx(FAILED
, "Writing failed");
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
[] = {
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"),
2552 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2555 char filename
[FILE_PATH_SIZE
] = {0};
2556 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
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");
2573 PrintAndLogEx(ERR
, "Key is incorrect length");
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));
2582 PrintAndLogEx(ERR
, "Key number is invalid");
2587 PrintAndLogEx(ERR
, "Please specify a key or key index");
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);
2603 if (rawkey
+ elite
> 1) {
2604 PrintAndLogEx(FAILED
, "Can not use both 'e', 'r'");
2608 if (startblock
< 5) {
2609 PrintAndLogEx(WARNING
, "you cannot write key blocks this way. yet... make your start block > 4");
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);
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
) {
2628 if (bytes_read
== 0) {
2629 PrintAndLogEx(ERR
, "file reading error");
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
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
));
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");
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");
2697 PrintAndLogEx(WARNING
, "iCLASS restore " _RED_("failed"));
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
= {
2710 .use_credit_key
= (keyType
== 0x18),
2711 .use_replay
= replay
,
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
;
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");
2742 PrintAndLogEx(NORMAL
, "");
2743 PrintAndLogEx(SUCCESS
, " block %3d/0x%02X : " _GREEN_("%s"), blockno
, blockno
, sprint_hex(packet
->data
, sizeof(packet
->data
)));
2744 PrintAndLogEx(NORMAL
, "");
2748 memcpy(out
, packet
->data
, sizeof(packet
->data
));
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
[] = {
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"),
2780 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
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");
2800 PrintAndLogEx(ERR
, "Key is incorrect length");
2804 } else if (key_nr
>= 0) {
2805 if (key_nr
< ICLASS_KEYS_MAX
) {
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));
2810 PrintAndLogEx(ERR
, "Key number is invalid");
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);
2832 if ((use_replay
+ rawkey
+ elite
) > 1) {
2833 PrintAndLogEx(ERR
, "Can not use a combo of 'elite', 'raw', 'nr'");
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
)
2852 if (blockno
< 6 || blockno
> 7)
2855 if (memcmp(data
, empty
, 8) == 0)
2858 bool use_sc
= IsCardHelperPresent(verbose
);
2859 if (use_sc
== false)
2862 // crypto helper available.
2863 PrintAndLogEx(INFO
, "----------------------------- " _CYAN_("Cardhelper") " -----------------------------");
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
)));
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);
2893 iclass_decode_credentials_new_pacs(dec_data
);
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
);
2914 PrintAndLogEx(INFO
, "no credential found");
2919 PrintAndLogEx(INFO
, "----------------------------------------------------------------------");
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
[] = {
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"),
2944 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
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);
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!!!");
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
) {
2974 if (sio_start_ptr
!= NULL
) {
2975 *sio_start_ptr
= NULL
;
2977 if (sio_length
!= NULL
) {
2981 if (dump_len
< sizeof(picopass_hdr_t
)) {
2982 // Can't really do anything with a dump that doesn't include the header
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
)) {
2992 if (dump_len
< 11 * PICOPASS_BLOCK_SIZE
) {
2993 // Can't reliably detect if the card is SR without checking
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
)) {
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
)) {
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
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
3032 if (sio_start
[1] >= 0x80 || sio_start
[1] == 0x00) {
3033 // We only support definite short form lengths
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
;
3046 detect_credential(iclass_dump
, dump_len
, &is_legacy
, &is_se
, &is_sr
, &sio_start
, &sio_length
);
3048 if (sio_start
== NULL
) {
3052 if (dump_len
< sio_length
+ (sio_start
- iclass_dump
)) {
3053 // SIO length exceeds the size of the dump we have, bail
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)
3087 uint8_t pagemap
= get_pagemap(hdr
);
3089 if (startblock
== 0) {
3090 if (pagemap
== PICOPASS_NON_SECURE_PAGEMODE
) {
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"
3114 bool is_legacy
, is_se
, is_sr
;
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;
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)
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;
3149 bl_lock
= ((lock
& 0x40) == 0);
3153 bl_lock
= ((lock
& 0x20) == 0);
3157 bl_lock
= ((lock
& 0x10) == 0);
3161 bl_lock
= ((lock
& 0x08) == 0);
3165 bl_lock
= ((lock
& 0x04) == 0);
3169 bl_lock
= ((lock
& 0x02) == 0);
3173 bl_lock
= ((lock
& 0x01) == 0);
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"};
3188 block_info
= info_nonks
[i
];
3190 block_info
= info_nonks
[3];
3193 regular_print_block
= true;
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)
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
) {
3209 PrintAndLogEx(INFO
, "%3d/0x%02X | " _CYAN_("%s") "| " _CYAN_("%s") " | %s | User / SIO / %s"
3212 , sprint_hex(blk
, 8)
3213 , sprint_ascii(blk
, 8)
3215 , is_se
? "SE" : "SR"
3219 block_info
= info_ks
[i
];
3220 } else if (i
> hdr
->conf
.app_limit
) {
3221 block_info
= info_ks
[7];
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) {
3246 "%3d/0x%02X | %s | %s | %s",
3249 sprint_hex_ascii(blk
, 8),
3257 PrintAndLogEx(INFO
, "---------+-------------------------+----------+---+----------------");
3259 PrintAndLogEx(HINT
, _YELLOW_("yellow") " = legacy credential");
3262 PrintAndLogEx(HINT
, _CYAN_("cyan") " = SIO / SE credential");
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
[] = {
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"),
3288 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
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);
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
) {
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
);
3322 print_iclass_sio(dump
, bytes_read
);
3329 void HFiClassCalcDivKey(uint8_t *CSN
, uint8_t *KEY
, uint8_t *div_key
, bool 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
);
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};
3355 HFiClassCalcDivKey(CSN
, OLDKEY
, old_div_key
, oldElite
);
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
];
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
[] = {
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"),
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");
3403 if (old_key_len
> 0) {
3404 if (old_key_len
!= 8) {
3405 PrintAndLogEx(ERR
, "Old key is incorrect length");
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));
3414 PrintAndLogEx(ERR
, "Key number is invalid");
3419 PrintAndLogEx(ERR
, "Please specify an old key or old key index");
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");
3436 if (new_key_len
> 0) {
3437 if (new_key_len
!= 8) {
3438 PrintAndLogEx(ERR
, "New key is incorrect length");
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));
3447 PrintAndLogEx(ERR
, "Key number is invalid");
3452 PrintAndLogEx(ERR
, "Please specify an new key or old key index");
3458 uint8_t csn
[8] = {0};
3459 CLIGetHexWithReturn(ctx
, 5, csn
, &csn_len
);
3460 bool givenCSN
= false;
3465 PrintAndLogEx(ERR
, "CSN is incorrect length");
3471 bool elite
= arg_get_lit(ctx
, 6);
3472 bool old_elite
= false;
3474 if (arg_get_lit(ctx
, 7)) {
3479 if (arg_get_lit(ctx
, 8)) {
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) {
3496 HFiClassCalcNewKey(csn
, old_key
, new_key
, xor_div_key
, elite
, old_elite
, true);
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
);
3510 if (bytes_read
> ICLASS_KEYS_MAX
* PICOPASS_BLOCK_SIZE
) {
3511 PrintAndLogEx(WARNING
, "File is too long to load - bytes: %zu", bytes_read
);
3516 for (; i
< bytes_read
/ PICOPASS_BLOCK_SIZE
; i
++) {
3517 memcpy(iClass_Key_Table
[i
], dump
+ (i
* PICOPASS_BLOCK_SIZE
), PICOPASS_BLOCK_SIZE
);
3521 PrintAndLogEx(SUCCESS
, "Loaded " _GREEN_("%2zd") " keys from %s", i
, filename
);
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
);
3533 PrintAndLogEx(INFO
, " %u | " _YELLOW_("%s"), i
, sprint_hex(iClass_Key_Table
[i
], PICOPASS_BLOCK_SIZE
));
3535 PrintAndLogEx(INFO
, "---+------------------------");
3536 PrintAndLogEx(NORMAL
, "");
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
[] = {
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"),
3559 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3562 char filename
[FILE_PATH_SIZE
] = {0};
3563 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
3566 uint8_t key
[8] = {0};
3567 CLIGetHexWithReturn(ctx
, 2, key
, &key_len
);
3568 uint8_t operation
= 0;
3573 PrintAndLogEx(ERR
, "Key is incorrect length");
3579 int key_nr
= arg_get_int_def(ctx
, 3, -1);
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));
3585 PrintAndLogEx(ERR
, "Key index is out-of-range");
3591 if (arg_get_lit(ctx
, 4)) { //save
3594 if (arg_get_lit(ctx
, 5)) { //load
3597 if (arg_get_lit(ctx
, 6)) { //print
3603 if (operation
== 0) {
3604 PrintAndLogEx(ERR
, "No operation specified (load, save, or print)\n");
3607 if (operation
> 6) {
3608 PrintAndLogEx(ERR
, "Too many operations specified\n");
3611 if (operation
> 4 && fnlen
== 0) {
3612 PrintAndLogEx(ERR
, "You must enter a filename when loading or saving\n");
3615 if (key_len
> 0 && key_nr
== -1) {
3616 PrintAndLogEx(ERR
, "Please specify key index when specifying key");
3620 switch (operation
) {
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));
3626 return iclass_print_keys();
3628 return iclass_load_keys(filename
);
3630 bool isOK
= saveFile(filename
, ".bin", iClass_Key_Table
, sizeof(iClass_Key_Table
));
3631 if (isOK
== false) {
3639 static void add_key(uint8_t *key
) {
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
);
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
);
3656 if (i
== ICLASS_KEYS_MAX
) {
3657 PrintAndLogEx(INFO
, "Couldn't find an empty keyslot");
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
[] = {
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"),
3681 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
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);
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);
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)) {
3707 PrintAndLogEx(INFO
, "Using default elite dictionary");
3708 snprintf(filename
, sizeof(filename
), ICLASS_DEFAULT_KEY_ELITE_DIC
);
3710 PrintAndLogEx(INFO
, "Using default dictionary");
3711 snprintf(filename
, sizeof(filename
), ICLASS_DEFAULT_KEY_DIC
);
3715 uint64_t t1
= msclock();
3718 uint8_t *keyBlock
= NULL
;
3719 uint32_t keycount
= 0;
3722 // Generate 5000 keys using VB6 KDF
3724 keyBlock
= calloc(1, keycount
* 8);
3725 if (keyBlock
== NULL
) {
3729 picopass_elite_reset();
3730 for (uint32_t i
= 0; i
< keycount
; i
++) {
3731 picopass_elite_nextKey(keyBlock
+ (i
* 8));
3735 int res
= loadFileDICTIONARY_safe(filename
, (void **)&keyBlock
, 8, &keycount
);
3736 if (res
!= PM3_SUCCESS
|| keycount
== 0) {
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...");
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");
3761 if (got_csn
== false) {
3762 PrintAndLogEx(WARNING
, "Tried %d times. Can't select card, aborting...", ICLASS_AUTH_RETRY
);
3768 // allocate memory for the pre calculated macs
3769 iclass_premac_t
*pre
= calloc(keycount
, sizeof(iclass_premac_t
));
3771 PrintAndLogEx(WARNING
, "failed to allocate memory");
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
: "");
3781 PrintAndLogEx(NORMAL
, "using " _YELLOW_("elite algo"));
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;
3795 max_chunk_size
= keycount
;
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;
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!");
3819 uint32_t curr_chunk_cnt
= keycount
- chunk_offset
;
3820 if ((keycount
- chunk_offset
) > max_chunk_size
) {
3821 curr_chunk_cnt
= max_chunk_size
;
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");
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
);
3846 bool looped
= false;
3847 uint8_t timeout
= 0;
3849 PacketResponseNG resp
;
3850 while (WaitForResponseTimeout(CMD_HF_ICLASS_CHKKEYS
, &resp
, 2000) == false) {
3852 PrintAndLogEx(NORMAL
, "." NOLF
);
3854 PrintAndLogEx(WARNING
, "\ncommand execution time out, aborting...");
3861 PrintAndLogEx(NORMAL
, "");
3863 if (resp
.status
== PM3_SUCCESS
) {
3864 found_offset
= resp
.data
.asBytes
[0];
3866 PrintAndLogEx(NORMAL
, "");
3867 PrintAndLogEx(SUCCESS
,
3868 "Found valid key " _GREEN_("%s")
3869 , sprint_hex(keyBlock
+ (chunk_offset
+ found_offset
) * 8, 8)
3873 PrintAndLogEx(INPLACE
, "Chunk [%03d/%d]", chunk_offset
, keycount
);
3879 t1
= msclock() - t1
;
3881 PrintAndLogEx(NORMAL
, "");
3882 PrintAndLogEx(SUCCESS
, "time in iclass chk " _YELLOW_("%.1f") " seconds", (float)t1
/ 1000.0);
3886 uint8_t *key
= keyBlock
+ (chunk_offset
+ found_offset
) * 8;
3892 PrintAndLogEx(NORMAL
, "");
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
;
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();
3925 uint8_t picopass_elite_nextByte(void) {
3926 return (picopass_elite_rng() >> 16) & 0xFF;
3929 void picopass_elite_nextKey(uint8_t *key
) {
3931 for (size_t i
= 0; i
< 7; i
++) {
3932 key_state
[i
] = key_state
[i
+ 1];
3934 key_state
[7] = picopass_elite_nextByte();
3936 for (size_t i
= 0; i
< 8; i
++) {
3937 key_state
[i
] = picopass_elite_nextByte();
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
) {
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!"));
3990 } else if (resp
.status
== PM3_ESOFT
) {
3991 PrintAndLogEx(WARNING
, "iCLASS Key Bits Recovery: " _RED_("failed/errors"));
3993 } else if (resp
.status
== PM3_EINVARG
) {
3995 if (runs
<= cycle
) {
3998 index_start
= index_start
+ loop
;
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
4023 // If no more carry, break early to avoid unnecessary loops
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
[] = {
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"),
4047 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4050 uint8_t epurse
[PICOPASS_BLOCK_SIZE
] = {0};
4051 CLIGetHexWithReturn(ctx
, 1, epurse
, &epurse_len
);
4054 uint8_t macs
[PICOPASS_BLOCK_SIZE
] = {0};
4055 CLIGetHexWithReturn(ctx
, 2, macs
, &macs_len
);
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;
4070 if (epurse_len
&& epurse_len
!= PICOPASS_BLOCK_SIZE
) {
4071 PrintAndLogEx(ERR
, "ePurse is incorrect length");
4075 if (macs_len
&& macs_len
!= PICOPASS_BLOCK_SIZE
) {
4076 PrintAndLogEx(ERR
, "MAC1 is incorrect length");
4080 if (macs2_len
&& macs2_len
!= PICOPASS_BLOCK_SIZE
) {
4081 PrintAndLogEx(ERR
, "MAC2 is incorrect length");
4085 if (startingkey_len
&& startingkey_len
!= PICOPASS_BLOCK_SIZE
) {
4086 PrintAndLogEx(ERR
, "Partial Key is incorrect length");
4089 //Standalone Command End
4092 uint8_t MAC_TAG
[4] = {0, 0, 0, 0};
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};
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
]) {
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;
4147 PrintAndLogEx(SUCCESS
, _GREEN_("CONFIRMED VALID RAW key ") _RED_("%s"), sprint_hex(div_key
, 8));
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));
4161 PrintAndLogEx(NORMAL
, "");
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;
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) {
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;
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
) {
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);
4261 PrintAndLogEx(NORMAL
, "");
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
[] = {
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."),
4286 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
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);
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);
4301 CmdHFiClassLegacyRecSim();
4310 PrintAndLogEx(ERR
, "Too many loops, arm prone to crashes. For safety specify a number lower than 10000");
4313 } else if (debug
|| test
) {
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) {
4324 diversifyKey(csn
, iClass_Key_Table
[1], new_div_key
);
4325 memcpy(no_first_auth
, new_div_key
, PICOPASS_BLOCK_SIZE
);
4329 if (macs_len
&& macs_len
!= PICOPASS_BLOCK_SIZE
) {
4330 PrintAndLogEx(ERR
, "MAC is incorrect length");
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
, "");
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
[] = {
4354 arg_str1("k", "divkey", "<hex>", "Card diversified key"),
4357 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4360 uint8_t div_key
[PICOPASS_BLOCK_SIZE
] = {0};
4361 CLIGetHexWithReturn(ctx
, 1, div_key
, &dk_len
);
4365 if (dk_len
&& dk_len
!= PICOPASS_BLOCK_SIZE
) {
4366 PrintAndLogEx(ERR
, "Diversified key is incorrect length");
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
, "");
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
[] = {
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"),
4401 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4403 bool use_vb6kdf
= arg_get_lit(ctx
, 7);
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);
4412 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
4416 uint8_t csn
[8] = {0};
4417 CLIGetHexWithReturn(ctx
, 2, csn
, &csn_len
);
4421 PrintAndLogEx(ERR
, "CSN is incorrect length");
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");
4440 uint8_t macs
[8] = {0};
4441 CLIGetHexWithReturn(ctx
, 4, macs
, &macs_len
);
4444 if (macs_len
!= 8) {
4445 PrintAndLogEx(ERR
, "MAC is incorrect length");
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
)));
4468 uint64_t t1
= msclock();
4470 uint8_t *keyBlock
= NULL
;
4471 uint32_t keycount
= 0;
4475 int res
= loadFileDICTIONARY_safe(filename
, (void **)&keyBlock
, 8, &keycount
);
4476 if (res
!= PM3_SUCCESS
|| keycount
== 0) {
4481 // Generate 5000 keys using VB6 KDF
4483 keyBlock
= calloc(1, keycount
* 8);
4484 if (keyBlock
== NULL
) {
4488 picopass_elite_reset();
4489 for (uint32_t i
= 0; i
< keycount
; i
++) {
4490 picopass_elite_nextKey(keyBlock
+ (i
* 8));
4495 iclass_prekey_t
*prekey
= calloc(keycount
, sizeof(iclass_prekey_t
));
4501 PrintAndLogEx(INFO
, "Generating diversified keys...");
4502 GenerateMacKeyFrom(csn
, CCNR
, use_raw
, use_elite
, keyBlock
, keycount
, prekey
);
4505 PrintAndLogEx(INFO
, "Using " _YELLOW_("elite algo"));
4509 PrintAndLogEx(INFO
, "Using " _YELLOW_("raw mode"));
4512 PrintAndLogEx(INFO
, "Sorting...");
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);
4523 item
= (iclass_prekey_t
*) bsearch(&lookup
, prekey
, keycount
, sizeof(iclass_prekey_t
), cmp_uint32
);
4526 PrintAndLogEx(SUCCESS
, "Found valid key " _GREEN_("%s"), sprint_hex(item
->key
, 8));
4530 t1
= msclock() - t1
;
4531 PrintAndLogEx(SUCCESS
, "Time in iclass lookup " _YELLOW_("%.3f") " seconds", (float)t1
/ 1000.0);
4535 PrintAndLogEx(NORMAL
, "");
4548 iclass_premac_t
*premac
;
4549 iclass_prekey_t
*prekey
;
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
;
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
);
4581 memcpy(div_key
, key
, 8);
4583 HFiClassCalcDivKey(csn
, key
, div_key
, use_elite
);
4585 doMAC(cc_nr
, div_key
, list
[i
].mac
);
4586 pthread_mutex_unlock(&generator_mutex
);
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
]);
4615 PrintAndLogEx(NORMAL
, "");
4616 PrintAndLogEx(WARNING
, "Failed to create pthreads. Quitting");
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
;
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
);
4649 memcpy(div_key
, list
[i
].key
, 8);
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
);
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
]);
4681 PrintAndLogEx(NORMAL
, "");
4682 PrintAndLogEx(WARNING
, "Failed to create pthreads. Quitting");
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
));
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
);
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
++) {
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
) {
4724 if (len
> KEY_SIZE
) {
4725 for (uint8_t m
= 0; m
< len
; m
+= KEY_SIZE
) {
4726 permute(data
+ m
, KEY_SIZE
, output
+ m
);
4730 if (len
!= KEY_SIZE
) {
4731 PrintAndLogEx(WARNING
, "wrong key size\n");
4734 for (uint8_t i
= 0; i
< KEY_SIZE
; ++i
) {
4736 uint8_t mask
= 0x80 >> i
;
4737 for (uint8_t j
= 0; j
< KEY_SIZE
; ++j
) {
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
) {
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;
4758 output
[i
] = 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
)
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
));
4774 PrintAndLogEx(SUCCESS
, " key | %s \n", sprint_hex(key
, len
));
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
));
4789 static int CmdHFiClassPermuteKey(const char *Cmd
) {
4791 uint8_t key
[8] = {0};
4792 uint8_t data
[16] = {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
[] = {
4803 arg_lit0("r", "reverse", "reverse permuted key"),
4804 arg_str1(NULL
, "key", "<hex>", "input key, 8 hex bytes"),
4807 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4808 bool isReverse
= arg_get_lit(ctx
, 1);
4809 CLIGetHexWithReturn(ctx
, 2, data
, &len
);
4812 memcpy(key
, data
, 8);
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));
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));
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
[] = {
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)"),
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);
4869 uint8_t key
[8] = {0};
4871 // If we use emulator memory skip key requirement
4872 if (use_emulator_memory
== false) {
4874 PrintAndLogEx(ERR
, "Missing required arg for --ki or --emu");
4879 if (key_nr
< ICLASS_KEYS_MAX
) {
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));
4884 PrintAndLogEx(ERR
, "Key number is invalid");
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};
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);
4920 if ((rawkey
+ elite
) > 1) {
4921 PrintAndLogEx(ERR
, "Can not use a combo of 'elite', 'raw'");
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)");
4930 have_enc_key
= true;
4934 PrintAndLogEx(ERR
, "Binary wiegand string must be less than 64 bits");
4938 if (bin_len
== 0 && card
.FacilityCode
== 0 && card
.CardNumber
== 0) {
4939 PrintAndLogEx(ERR
, "Must provide either --cn/--fc or --bin");
4943 if (have_enc_key
== false) {
4944 // The IsCardHelperPresent function clears the emulator memory
4945 if (use_emulator_memory
) {
4948 use_sc
= IsCardHelperPresent(false);
4950 if (use_sc
== false) {
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");
4958 PrintAndLogEx(ERR
, "Failed to load transport key from file");
4962 memcpy(enc_key
, enckeyptr
, sizeof(enc_key
));
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,
4975 memset(data
, 0, sizeof(data
));
4976 BitstreamOut_t bout
= {data
, 0, 0 };
4978 for (int i
= 0; i
< 64 - bin_len
- 1; i
++) {
4981 // add binary sentinel bit.
4984 // convert binary string to hex bytes
4985 for (int i
= 0; i
< bin_len
; i
++) {
4992 PrintAndLogEx(WARNING
, "Ignoring '%c'", c
);
4997 memcpy(credential
+ 8, data
, sizeof(data
));
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
);
5008 if (HIDPack(format_idx
, &card
, &packed
, false) == false) {
5009 PrintAndLogEx(WARNING
, "The card data could not be encoded in the selected format.");
5013 // iceman: only for formats w length smaller than 37.
5016 // increase length to allow setting bit just above real data
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
);
5026 memcpy(credential
+ 8, &packed
.Mid
, sizeof(packed
.Mid
));
5027 memcpy(credential
+ 12, &packed
.Bot
, sizeof(packed
.Bot
));
5030 // encrypt with transport key
5032 Encrypt(credential
+ 8, credential
+ 8);
5033 Encrypt(credential
+ 16, credential
+ 16);
5034 Encrypt(credential
+ 24, credential
+ 24);
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
);
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");
5052 int isok
= PM3_SUCCESS
;
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`"));
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
);
5064 PrintAndLogEx(SUCCESS
, "Write block %d/0x0%x ( " _GREEN_("ok") " ) --> " _YELLOW_("%s"), 6 + i
, 6 + i
, sprint_hex_inrow(credential
+ (i
* 8), 8));
5067 PrintAndLogEx(INFO
, "Write block %d/0x0%x ( " _RED_("fail") " )", 6 + i
, 6 + i
);
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[] = {
5087 CLIExecWithReturn(ctx, Cmd, argtable, true);
5094 PrintAndLogEx(INFO, "to be implemented");
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
[] = {
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"),
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);
5129 bool got_eki
= false;
5130 uint8_t card_key
[8] = {0};
5131 if (card_kidx
>= 0) {
5132 if (card_kidx
< ICLASS_KEYS_MAX
) {
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));
5137 PrintAndLogEx(ERR
, "--ki number is invalid");
5142 bool got_kr
= false;
5143 uint8_t keyroll_key
[8] = {0};
5145 if (kidx
< ICLASS_KEYS_MAX
) {
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));
5150 PrintAndLogEx(ERR
, "--eki number is invalid");
5155 bool got_mk
= false;
5156 uint8_t master_key
[8] = {0};
5158 if (midx
< ICLASS_KEYS_MAX
) {
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));
5165 PrintAndLogEx(ERR
, "--mrki number is invalid");
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) !");
5180 if (strstr(item
->desc
, "Custom") != NULL
&& got_mk
== false) {
5181 PrintAndLogEx(ERR
, "please specify New Standard Master Key (--mrki) !");
5184 if (strstr(item
->desc
, "Restore") != NULL
&& card_kidx
== -1) {
5185 PrintAndLogEx(ERR
, "please specify the Current Reader's Key (--ki) !");
5188 generate_config_card(item
, keyroll_key
, got_kr
, card_key
, got_eki
, elite
, got_mk
, master_key
);
5194 static int CmdHFiClassSAM(const char *Cmd
) {
5195 CLIParserContext
*ctx
;
5196 CLIParserInit(&ctx
, "hf iclass sam",
5197 "Extract PACS via a HID SAM\n",
5201 void *argtable
[] = {
5203 arg_lit0("v", "verbose", "verbose output"),
5206 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5207 bool verbose
= arg_get_lit(ctx
, 1);
5210 if (IsHIDSamPresent(verbose
) == false) {
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
) {
5226 PrintAndLogEx(SUCCESS
, "No PACS data found. Card empty?");
5229 PrintAndLogEx(WARNING
, "SAM select failed");
5233 // CSN, config, epurse, NR/MAC, AIA
5236 // second byte length
5239 uint8_t *d
= resp
.data
.asBytes
;
5240 uint8_t n
= d
[1] - 1; // skip length byte
5242 char *binstr
= (char *)calloc((n
* 8) + 1, sizeof(uint8_t));
5243 if (binstr
== NULL
) {
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
));
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");
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
) {
5278 PrintAndLogEx(INFO
, "Clone to " _YELLOW_("iCLASS Legacy"));
5279 PrintAndLogEx(SUCCESS
, " hf iclass encode --ki 0 --bin %s", binstr
);
5280 PrintAndLogEx(NORMAL
, "");
5283 PrintAndLogEx(INFO
, "Downgrade to " _YELLOW_("HID Prox II"));
5284 PrintAndLogEx(SUCCESS
, " lf hid clone -w H10301 --bin %s", binstr
);
5285 PrintAndLogEx(NORMAL
, "");
5288 char mfcbin
[28] = {0};
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
, "");
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
);
5360 int CmdHFiClass(const char *Cmd
) {
5361 clearCommandBuffer();
5362 return CmdsParse(CommandTable
, Cmd
);
5365 // static void test_credential_type(void) {
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) |
5380 int info_iclass(bool shallow_mod
) {
5382 iclass_card_select_t payload
= {
5383 .flags
= (FLAG_ICLASS_READER_INIT
| FLAG_ICLASS_READER_CLEARTRACE
)
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) {
5396 return PM3_ETIMEOUT
;
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
)));
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
)));
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
)));
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") " -----------------------");
5458 if (pagemap
== PICOPASS_NON_SECURE_PAGEMODE
) {
5459 memcpy(aia
, ns_hdr
->app_issuer_area
, sizeof(aia
));
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);
5471 PrintAndLogEx(SUCCESS
, " CSN.......... " _YELLOW_("HID range"));
5474 PrintAndLogEx(SUCCESS
, " Credential... " _GREEN_("iCLASS legacy"));
5478 PrintAndLogEx(SUCCESS
, " Credential... " _GREEN_("iCLASS SE"));
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)"));
5490 PrintAndLogEx(SUCCESS
, " Card chip.... "_YELLOW_("NEW Silicon (No 14b support)"));
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
)));
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
);