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 //-----------------------------------------------------------------------------
17 //-----------------------------------------------------------------------------
18 #include "generator.h"
23 #include <sys/types.h>
26 #include "commonutil.h" //BSWAP_16
27 #include "common.h" //BSWAP_32/64
30 #include "crc16.h" // crc16 ccitt
31 #include "mbedtls/sha1.h"
32 #include "mbedtls/md5.h"
33 #include "mbedtls/cmac.h"
34 #include "mbedtls/cipher.h"
35 #include "mbedtls/md.h"
36 #include "mbedtls/hkdf.h"
41 # define prnt(args...) PrintAndLogEx(DEBUG, ## args );
44 # define prnt Dbprintf
47 // Implementation tips:
48 // For each implementation of the algos, I recommend adding a self test for easy "simple unit" tests when Travis CI / Appveyor runs.
49 // See special note for MFC based algos.
51 //------------------------------------
52 // MFU/NTAG PWD/PACK generation stuff
53 // Italian transport system
58 //------------------------------------
59 static void transform_D(uint8_t *ru
) {
61 const uint32_t c_D
[] = {
62 0x6D835AFC, 0x7D15CD97, 0x0942B409, 0x32F9C923, 0xA811FB02, 0x64F121E8,
63 0xD1CC8B4E, 0xE8873E6F, 0x61399BBB, 0xF1B91926, 0xAC661520, 0xA21A31C9,
64 0xD424808D, 0xFE118E07, 0xD18E728D, 0xABAC9E17, 0x18066433, 0x00E18E79,
65 0x65A77305, 0x5AE9E297, 0x11FC628C, 0x7BB3431F, 0x942A8308, 0xB2F8FD20,
66 0x5728B869, 0x30726D5A
72 uint32_t v1
= ((ru
[3] << 24) | (ru
[2] << 16) | (ru
[1] << 8) | ru
[0]) + c_D
[p
++];
73 uint32_t v2
= ((ru
[7] << 24) | (ru
[6] << 16) | (ru
[5] << 8) | ru
[4]) + c_D
[p
++];
74 for (i
= 0; i
< 12; i
+= 2) {
75 uint32_t tempA
= v1
^ v2
;
76 uint32_t t1
= PM3_ROTL(tempA
, v2
& 0x1F) + c_D
[p
++];
77 uint32_t tempB
= v2
^ t1
;
78 uint32_t t2
= PM3_ROTL(tempB
, t1
& 0x1F) + c_D
[p
++];
80 v1
= PM3_ROTL(tempA
, t2
& 0x1F) + c_D
[p
++];
82 v2
= PM3_ROTL(tempB
, v1
& 0x1F) + c_D
[p
++];
87 ru
[1] = (v1
>> 8) & 0xFF;
88 ru
[2] = (v1
>> 16) & 0xFF;
89 ru
[3] = (v1
>> 24) & 0xFF;
91 ru
[5] = (v2
>> 8) & 0xFF;
92 ru
[6] = (v2
>> 16) & 0xFF;
93 ru
[7] = (v2
>> 24) & 0xFF;
96 // Transport system (IT) pwd generation algo nickname A.
97 uint32_t ul_ev1_pwdgenA(const uint8_t *uid
) {
99 uint8_t pos
= (uid
[3] ^ uid
[4] ^ uid
[5] ^ uid
[6]) % 32;
101 uint32_t xortable
[] = {
102 0x4f2711c1, 0x07D7BB83, 0x9636EF07, 0xB5F4460E, 0xF271141C, 0x7D7BB038, 0x636EF871, 0x5F4468E3,
103 0x271149C7, 0xD7BB0B8F, 0x36EF8F1E, 0xF446863D, 0x7114947A, 0x7BB0B0F5, 0x6EF8F9EB, 0x44686BD7,
104 0x11494fAF, 0xBB0B075F, 0xEF8F96BE, 0x4686B57C, 0x1494F2F9, 0xB0B07DF3, 0xF8F963E6, 0x686B5FCC,
105 0x494F2799, 0x0B07D733, 0x8F963667, 0x86B5F4CE, 0x94F2719C, 0xB07D7B38, 0xF9636E70, 0x6B5F44E0
108 uint8_t entry
[] = {0x00, 0x00, 0x00, 0x00};
109 uint8_t pwd
[] = {0x00, 0x00, 0x00, 0x00};
111 num_to_bytes(xortable
[pos
], 4, entry
);
113 pwd
[0] = entry
[0] ^ uid
[1] ^ uid
[2] ^ uid
[3];
114 pwd
[1] = entry
[1] ^ uid
[0] ^ uid
[2] ^ uid
[4];
115 pwd
[2] = entry
[2] ^ uid
[0] ^ uid
[1] ^ uid
[5];
116 pwd
[3] = entry
[3] ^ uid
[6];
118 return (uint32_t)bytes_to_num(pwd
, 4);
121 // Amiibo pwd generation algo nickname B. (very simple)
122 uint32_t ul_ev1_pwdgenB(const uint8_t *uid
) {
124 uint8_t pwd
[] = {0x00, 0x00, 0x00, 0x00};
126 pwd
[0] = uid
[1] ^ uid
[3] ^ 0xAA;
127 pwd
[1] = uid
[2] ^ uid
[4] ^ 0x55;
128 pwd
[2] = uid
[3] ^ uid
[5] ^ 0xAA;
129 pwd
[3] = uid
[4] ^ uid
[6] ^ 0x55;
130 return (uint32_t)bytes_to_num(pwd
, 4);
133 // Lego Dimension pwd generation algo nickname C.
134 uint32_t ul_ev1_pwdgenC(const uint8_t *uid
) {
137 0xffffffff, 0x28ffffff,
138 0x43202963, 0x7279706f,
139 0x74686769, 0x47454c20,
140 0x3032204f, 0xaaaa3431
143 memcpy(base
, uid
, 7);
145 for (int i
= 0; i
< 8; i
++) {
146 pwd
= base
[i
] + ROTR(pwd
, 25) + ROTR(pwd
, 10) - pwd
;
148 return BSWAP_32(pwd
);
151 // XYZ 3d printing pwd generation algo nickname D.
152 uint32_t ul_ev1_pwdgenD(const uint8_t *uid
) {
156 uint8_t r
= (uid
[1] + uid
[3] + uid
[5]) & 7;
159 uint8_t ru
[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
160 for (i
= 0; i
< 7; i
++)
161 ru
[(i
+ r
) & 7] = uid
[i
];
166 r
= (ru
[0] + ru
[2] + ru
[4] + ru
[6]) & 3;
170 for (i
= 0; i
< 4; i
++)
171 pwd
= ru
[i
+ r
] + (pwd
<< 8);
173 return BSWAP_32(pwd
);
176 // AIR purifier Xiaomi
177 uint32_t ul_ev1_pwdgenE(const uint8_t *uid
) {
178 uint8_t hash
[20] = {0};
179 mbedtls_sha1(uid
, 7, hash
);
181 pwd
|= (hash
[ hash
[0] % 20 ]) << 24 ;
182 pwd
|= (hash
[(hash
[0] + 5) % 20 ]) << 16;
183 pwd
|= (hash
[(hash
[0] + 13) % 20 ]) << 8;
184 pwd
|= (hash
[(hash
[0] + 17) % 20 ]);
188 // NDEF tools format password generator
189 uint32_t ul_ev1_pwdgenF(const uint8_t *uid
) {
190 uint8_t hash
[16] = {0};;
191 mbedtls_md5(uid
, 7, hash
);
193 pwd
|= hash
[0] << 24;
194 pwd
|= hash
[1] << 16;
200 // Solution from @atc1441
201 // https://gist.github.com/atc1441/41af75048e4c22af1f5f0d4c1d94bb56
202 // Philips Sonicare toothbrush NFC head
203 uint32_t ul_ev1_pwdgenG(const uint8_t *uid
, const uint8_t *mfg
) {
205 init_table(CRC_PHILIPS
);
207 uint32_t crc1
= crc16_philips(uid
, 7);
209 uint32_t crc2
= crc16_fast(mfg
, 10, crc1
, false, false);
211 return (BSWAP_16(crc2
) << 16 | BSWAP_16(crc1
));
214 // pack generation for algo 1-3
215 uint16_t ul_ev1_packgenA(const uint8_t *uid
) {
216 uint16_t pack
= (uid
[0] ^ uid
[1] ^ uid
[2]) << 8 | (uid
[2] ^ 8);
219 uint16_t ul_ev1_packgenB(const uint8_t *uid
) {
222 uint16_t ul_ev1_packgenC(const uint8_t *uid
) {
225 uint16_t ul_ev1_packgenD(const uint8_t *uid
) {
228 uint8_t r
= (uid
[2] + uid
[5]) & 7; //Rotation offset
229 uint8_t ru
[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; //Rotated UID
230 for (i
= 0; i
< 7; i
++)
231 ru
[(i
+ r
) & 7] = uid
[i
];
237 for (i
= 0; i
< 8; i
++)
241 return BSWAP_16(p
& 0xFFFF);
243 uint16_t ul_ev1_packgenE(const uint8_t *uid
) {
245 uint32_t pwd
= ul_ev1_pwdgenE(uid
);
246 return (0xAD << 8 | ((pwd
>> 24) & 0xFF));
249 uint16_t ul_ev1_packgenG(const uint8_t *uid
, const uint8_t *mfg
) {
250 init_table(CRC_PHILIPS
);
252 uint32_t crc1
= crc16_philips(uid
, 7);
254 uint32_t crc2
= crc16_fast(mfg
, 10, crc1
, false, false);
256 uint32_t pwd
= (BSWAP_16(crc2
) << 16 | BSWAP_16(crc1
));
259 num_to_bytes(pwd
, 4, pb
);
260 return BSWAP_16(crc16_fast(pb
, 4, crc2
, false, false));
265 uint32_t ul_ev1_pwdgen_def(const uint8_t *uid
) {
268 uint16_t ul_ev1_packgen_def(const uint8_t *uid
) {
272 // MIFARE ULTRALIGHT OTP generators
273 uint32_t ul_c_otpgenA(const uint8_t *uid
) {
278 //------------------------------------
279 // MFC key generation stuff
280 // Each algo implementation should offer two key generation functions.
281 // 1. function that returns all keys
282 // 2. function that returns one key, target sector | block
283 //------------------------------------
285 //------------------------------------
286 // MFC keyfile generation stuff
287 //------------------------------------
289 int mfc_algo_ving_one(uint8_t *uid
, uint8_t sector
, uint8_t keytype
, uint64_t *key
) {
290 if (sector
> 15) return PM3_EINVARG
;
291 if (key
== NULL
) return PM3_EINVARG
;
295 int mfc_algo_ving_all(uint8_t *uid
, uint8_t *keys
) {
296 if (keys
== NULL
) return PM3_EINVARG
;
297 for (int keytype
= 0; keytype
< 2; keytype
++) {
298 for (int sector
= 0; sector
< 16; sector
++) {
300 mfc_algo_ving_one(uid
, sector
, keytype
, &key
);
301 num_to_bytes(key
, 6, keys
+ (keytype
* 16 * 6) + (sector
* 6));
308 int mfc_algo_yale_one(uint8_t *uid
, uint8_t sector
, uint8_t keytype
, uint64_t *key
) {
309 if (sector
> 15) return PM3_EINVARG
;
310 if (key
== NULL
) return PM3_EINVARG
;
311 if (keytype
> 2) return PM3_EINVARG
;
315 int mfc_algo_yale_all(uint8_t *uid
, uint8_t *keys
) {
316 if (keys
== NULL
) return PM3_EINVARG
;
317 for (int keytype
= 0; keytype
< 2; keytype
++) {
318 for (int sector
= 0; sector
< 16; sector
++) {
320 mfc_algo_yale_one(uid
, sector
, keytype
, &key
);
321 num_to_bytes(key
, 6, keys
+ (keytype
* 16 * 6) + (sector
* 6));
327 // Saflok / Maid UID to key.
328 int mfc_algo_saflok_one(uint8_t *uid
, uint8_t sector
, uint8_t keytype
, uint64_t *key
) {
329 if (sector
> 15) return PM3_EINVARG
;
330 if (key
== NULL
) return PM3_EINVARG
;
334 *key
= 0xFFFFFFFFFFFF;
338 if (keytype
== 0 && sector
== 1) {
339 *key
= 0x2a2c13cc242a;
343 if (((sector
== 2) || (sector
== 3)) && (keytype
== 0)) {
344 *key
= 0xFFFFFFFFFFFF;
350 0xf057b39ee3d8ULL
, 0x969d954ac157ULL
, 0x8f43580d2c9dULL
, 0xffcce0050c43ULL
,
351 0x341b15a690ccULL
, 0x89585612e71bULL
, 0xbb74b0953658ULL
, 0xfb97f84b5b74ULL
,
352 0xc9d188359f92ULL
, 0x8f92e97f5897ULL
, 0x166ca2b09fd1ULL
, 0x27dd93101c6cULL
,
353 0xda3e3fd649ddULL
, 0x58dded078e3eULL
, 0x5cd005cfd907ULL
, 0x118dd00187d0ULL
356 uint8_t h
= (NIBBLE_HIGH(uid
[3]) & 0xF);
357 h
+= (NIBBLE_HIGH(uid
[2]) & 0xF);
360 uint64_t m
= lut
[h
& 0xF];
361 uint64_t id
= (bytes_to_num(uid
, 4) << 8);
363 *key
= (h
+ (id
+ m
+ ((uint64_t)h
<< 40ULL))) & 0xFFFFFFFFFFFFULL
;
368 int mfc_algo_saflok_all(uint8_t *uid
, uint8_t *keys
) {
369 if (keys
== NULL
) return PM3_EINVARG
;
371 for (int keytype
= 0; keytype
< 2; keytype
++) {
372 for (int sector
= 0; sector
< 16; sector
++) {
374 mfc_algo_saflok_one(uid
, sector
, keytype
, &key
);
375 num_to_bytes(key
, 6, keys
+ (keytype
* 16 * 6) + (sector
* 6));
382 int mfc_algo_mizip_one(const uint8_t *uid
, uint8_t sector
, uint8_t keytype
, uint64_t *key
) {
383 if (sector
> 4) return PM3_EINVARG
;
384 if (key
== NULL
) return PM3_EINVARG
;
385 if (keytype
> 2) return PM3_EINVARG
;
390 *key
= 0xA0A1A2A3A4A5U
;
392 *key
= 0xB4C132439eef;
400 uint64_t xor_tbl_a
[] = {
407 num_to_bytes(xor_tbl_a
[sector
- 1], 6, xor);
410 (uint64_t)(uid
[0] ^ xor[0]) << 40 |
411 (uint64_t)(uid
[1] ^ xor[1]) << 32 |
412 (uint64_t)(uid
[2] ^ xor[2]) << 24 |
413 (uint64_t)(uid
[3] ^ xor[3]) << 16 |
414 (uint64_t)(uid
[0] ^ xor[4]) << 8 |
415 (uint64_t)(uid
[1] ^ xor[5])
419 uint64_t xor_tbl_b
[] = {
427 num_to_bytes(xor_tbl_b
[sector
- 1], 6, xor);
430 (uint64_t)(uid
[2] ^ xor[0]) << 40 |
431 (uint64_t)(uid
[3] ^ xor[1]) << 32 |
432 (uint64_t)(uid
[0] ^ xor[2]) << 24 |
433 (uint64_t)(uid
[1] ^ xor[3]) << 16 |
434 (uint64_t)(uid
[2] ^ xor[4]) << 8 |
435 (uint64_t)(uid
[3] ^ xor[5])
442 // returns all Mifare Mini (MFM) 10 keys.
443 // keys must have 5*2*6 = 60bytes space
444 int mfc_algo_mizip_all(uint8_t *uid
, uint8_t *keys
) {
445 if (keys
== NULL
) return PM3_EINVARG
;
447 for (int keytype
= 0; keytype
< 2; keytype
++) {
448 for (int sector
= 0; sector
< 5; sector
++) {
450 mfc_algo_mizip_one(uid
, sector
, keytype
, &key
);
451 num_to_bytes(key
, 6, keys
+ (keytype
* 5 * 6) + (sector
* 6));
457 // Disney Infinity algo
458 int mfc_algo_di_one(uint8_t *uid
, uint8_t sector
, uint8_t keytype
, uint64_t *key
) {
459 if (sector
> 4) return PM3_EINVARG
;
460 if (key
== NULL
) return PM3_EINVARG
;
464 0x0A, 0x14, 0xFD, 0x05, 0x07, 0xFF, 0x4B, 0xCD,
465 0x02, 0x6B, 0xA8, 0x3F, 0x0A, 0x3B, 0x89, 0xA9,
466 uid
[0], uid
[1], uid
[2], uid
[3], uid
[4], uid
[5], uid
[6],
467 0x28, 0x63, 0x29, 0x20, 0x44, 0x69, 0x73, 0x6E,
468 0x65, 0x79, 0x20, 0x32, 0x30, 0x31, 0x33
471 mbedtls_sha1(input
, sizeof(input
), hash
);
474 (uint64_t)hash
[3] << 40 |
475 (uint64_t)hash
[2] << 32 |
476 (uint64_t)hash
[1] << 24 |
477 (uint64_t)hash
[0] << 16 |
478 (uint64_t)hash
[7] << 8 |
484 int mfc_algo_di_all(uint8_t *uid
, uint8_t *keys
) {
485 if (keys
== NULL
) return PM3_EINVARG
;
486 for (int keytype
= 0; keytype
< 2; keytype
++) {
487 for (int sector
= 0; sector
< 5; sector
++) {
489 mfc_algo_di_one(uid
, sector
, keytype
, &key
);
490 num_to_bytes(key
, 6, keys
+ (keytype
* 5 * 6) + (sector
* 6));
497 static uint64_t sky_crc64_like(uint64_t result
, uint8_t sector
) {
498 #define SKY_POLY UINT64_C(0x42f0e1eba9ea3693)
499 #define SKY_TOP UINT64_C(0x800000000000)
500 result
^= (uint64_t)sector
<< 40;
501 for (int i
= 0; i
< 8; i
++) {
502 result
= (result
& SKY_TOP
) ? (result
<< 1) ^ SKY_POLY
: result
<< 1;
506 int mfc_algo_sky_one(uint8_t *uid
, uint8_t sector
, uint8_t keytype
, uint64_t *key
) {
508 #define SKY_KEY_MASK 0xFFFFFFFFFFFF
510 if (sector
> 15) return PM3_EINVARG
;
511 if (key
== NULL
) return PM3_EINVARG
;
513 if (sector
== 0 && keytype
== 0) {
514 *key
= 0x4B0B20107CCB;
518 *key
= 0x000000000000;
523 uint64_t hash
= 0x9AE903260CC4;
524 for (int i
= 0; i
< 4; i
++) {
525 hash
= sky_crc64_like(hash
, uid
[i
]);
528 uint64_t sectorhash
= sky_crc64_like(hash
, sector
);
529 *key
= BSWAP_64(sectorhash
& SKY_KEY_MASK
) >> 16;
532 int mfc_algo_sky_all(uint8_t *uid
, uint8_t *keys
) {
533 if (keys
== NULL
) return PM3_EINVARG
;
534 for (int keytype
= 0; keytype
< 2; keytype
++) {
535 for (int sector
= 0; sector
< 16; sector
++) {
537 mfc_algo_sky_one(uid
, sector
, keytype
, &key
);
538 num_to_bytes(key
, 6, keys
+ (keytype
* 16 * 6) + (sector
* 6));
545 static const uint8_t bambu_salt
[] = { 0x9a, 0x75, 0x9c, 0xf2, 0xc4, 0xf7, 0xca, 0xff, 0x22, 0x2c, 0xb9, 0x76, 0x9b, 0x41, 0xbc, 0x96 };
546 static const uint8_t bambu_context_a
[] = "RFID-A";
547 static const uint8_t bambu_context_b
[] = "RFID-B";
549 int mfc_algo_bambu_one(uint8_t *uid
, uint8_t sector
, uint8_t keytype
, uint64_t *key
) {
550 if (uid
== NULL
) return PM3_EINVARG
;
551 if (key
== NULL
) return PM3_EINVARG
;
553 uint8_t keys
[16 * 6] = {0};
555 // prepare hmac context
556 const mbedtls_md_info_t
*info
= mbedtls_md_info_from_type(MBEDTLS_MD_SHA256
);
559 mbedtls_hkdf(info
, bambu_salt
, sizeof(bambu_salt
), uid
, 4, bambu_context_a
, sizeof(bambu_context_a
), keys
, sizeof(keys
));
561 mbedtls_hkdf(info
, bambu_salt
, sizeof(bambu_salt
), uid
, 4, bambu_context_b
, sizeof(bambu_context_b
), keys
, sizeof(keys
));
564 *key
= bytes_to_num(keys
+ (sector
* 6), 6);
568 int mfc_algo_bambu_all(uint8_t *uid
, uint8_t *keys
) {
569 if (uid
== NULL
) return PM3_EINVARG
;
570 if (keys
== NULL
) return PM3_EINVARG
;
572 // prepare hmac context
573 const mbedtls_md_info_t
*info
= mbedtls_md_info_from_type(MBEDTLS_MD_SHA256
);
574 mbedtls_hkdf(info
, bambu_salt
, sizeof(bambu_salt
), uid
, 4, bambu_context_a
, sizeof(bambu_context_a
), keys
, (16 * 6));
575 mbedtls_hkdf(info
, bambu_salt
, sizeof(bambu_salt
), uid
, 4, bambu_context_b
, sizeof(bambu_context_b
), keys
+ (16 * 6), (16 * 6));
579 // LF T55x7 White gun cloner algo
580 uint32_t lf_t55xx_white_pwdgen(uint32_t id
) {
581 uint32_t r1
= rotl(id
& 0x000000ec, 8);
582 uint32_t r2
= rotl(id
& 0x86000000, 16);
583 uint32_t pwd
= 0x10303;
584 pwd
+= ((id
& 0x86ee00ec) ^ r1
^ r2
);
588 // Gallagher Desfire Key Diversification Input for Cardax Card Data Application
589 int mfdes_kdf_input_gallagher(uint8_t *uid
, uint8_t uidLen
, uint8_t keyNo
, uint32_t aid
, uint8_t *kdfInputOut
, uint8_t *kdfInputLen
) {
590 if (uid
== NULL
|| (uidLen
!= 4 && uidLen
!= 7) || keyNo
> 2 || kdfInputOut
== NULL
|| kdfInputLen
== NULL
) {
591 prnt("Invalid arguments");
596 // If the keyNo == 1 or the aid is 000000, then omit the UID.
597 // On the other hand, if the aid is 1f81f4 (config card) always include the UID.
598 if ((keyNo
!= 1 && aid
!= 0x000000) || (aid
== 0x1f81f4)) {
599 if (*kdfInputLen
< (4 + uidLen
)) {
603 memcpy(kdfInputOut
, uid
, uidLen
);
605 } else if (*kdfInputLen
< 4) {
609 kdfInputOut
[len
++] = keyNo
;
611 kdfInputOut
[len
++] = aid
& 0xff;
612 kdfInputOut
[len
++] = (aid
>> 8) & 0xff;
613 kdfInputOut
[len
++] = (aid
>> 16) & 0xff;
620 int mfc_generate4b_nuid(uint8_t *uid
, uint8_t *nuid
) {
622 uint8_t b1
= 0, b2
= 0;
624 compute_crc(CRC_14443_A
, uid
, 3, &b1
, &b2
);
625 nuid
[0] = (b2
& 0xE0) | 0xF;
629 crc
= crc16_fast(&uid
[3], 4, reflect16(crc
), true, true);
630 nuid
[2] = (crc
>> 8) & 0xFF ;
631 nuid
[3] = crc
& 0xFF;
635 int mfc_algo_touch_one(uint8_t *uid
, uint8_t sector
, uint8_t keytype
, uint64_t *key
) {
636 if (uid
== NULL
) return PM3_EINVARG
;
637 if (key
== NULL
) return PM3_EINVARG
;
640 (uint64_t)(uid
[1] ^ uid
[2] ^ uid
[3]) << 40 |
641 (uint64_t)uid
[1] << 32 |
642 (uint64_t)uid
[2] << 24 |
643 (uint64_t)(((uid
[0] + uid
[1] + uid
[2] + uid
[3]) % 0x100) ^ uid
[3]) << 16 |
650 //------------------------------------
652 //------------------------------------
654 int generator_selftest(void) {
656 #define NUM_OF_TEST 11
658 PrintAndLogEx(INFO
, "------- " _CYAN_("PWD / KEY generator self tests") " --------");
660 uint8_t testresult
= 0;
662 uint8_t uid1
[] = {0x04, 0x11, 0x12, 0x11, 0x12, 0x11, 0x10};
663 uint32_t pwd1
= ul_ev1_pwdgenA(uid1
);
664 bool success
= (pwd1
== 0x8432EB17);
667 PrintAndLogEx(success
? SUCCESS
: WARNING
, "UID | %s | %08X - %s", sprint_hex(uid1
, 7), pwd1
, success
? _GREEN_("ok") : "->8432EB17<-");
669 uint8_t uid2
[] = {0x04, 0x1f, 0x98, 0xea, 0x1e, 0x3e, 0x81};
670 uint32_t pwd2
= ul_ev1_pwdgenB(uid2
);
671 success
= (pwd2
== 0x5fd37eca);
674 PrintAndLogEx(success
? SUCCESS
: WARNING
, "UID | %s | %08X - %s", sprint_hex(uid2
, 7), pwd2
, success
? _GREEN_("ok") : "->5fd37eca<--");
676 uint8_t uid3
[] = {0x04, 0x62, 0xB6, 0x8A, 0xB4, 0x42, 0x80};
677 uint32_t pwd3
= ul_ev1_pwdgenC(uid3
);
678 success
= (pwd3
== 0x5a349515);
681 PrintAndLogEx(success
? SUCCESS
: WARNING
, "UID | %s | %08X - %s", sprint_hex(uid3
, 7), pwd3
, success
? _GREEN_("ok") : "->5a349515<--");
683 uint8_t uid4
[] = {0x04, 0xC5, 0xDF, 0x4A, 0x6D, 0x51, 0x80};
684 uint32_t pwd4
= ul_ev1_pwdgenD(uid4
);
685 success
= (pwd4
== 0x72B1EC61);
688 PrintAndLogEx(success
? SUCCESS
: WARNING
, "UID | %s | %08X - %s", sprint_hex(uid4
, 7), pwd4
, success
? _GREEN_("ok") : "->72B1EC61<--");
690 uint8_t uid5
[] = {0x04, 0xA0, 0x3C, 0xAA, 0x1E, 0x70, 0x80};
691 uint32_t pwd5
= ul_ev1_pwdgenE(uid5
);
692 success
= (pwd5
== 0xCD91AFCC);
695 PrintAndLogEx(success
? SUCCESS
: WARNING
, "UID | %s | %08X - %s", sprint_hex(uid5
, 7), pwd5
, success
? _GREEN_("ok") : "->CD91AFCC<--");
697 uint8_t uid6
[] = {0x04, 0x77, 0x42, 0xAB, 0xEF, 0x42, 0x70};
698 uint32_t pwd6
= ul_ev1_pwdgenF(uid6
);
699 success
= (pwd6
== 0xA9C4C3C0);
702 PrintAndLogEx(success
? SUCCESS
: WARNING
, "UID | %s | %08X - %s", sprint_hex(uid6
, 7), pwd6
, success
? _GREEN_("ok") : "->A9C4C3C0<--");
704 uint8_t uid7
[] = {0x04, 0x0D, 0x4B, 0x5A, 0xC5, 0x71, 0x81};
705 uint8_t mfg
[] = {0x32, 0x31, 0x30, 0x36, 0x32, 0x38, 0x20, 0x35, 0x32, 0x4D};
706 uint32_t pwd7
= ul_ev1_pwdgenG(uid7
, mfg
);
707 success
= (pwd7
== 0xFBCFACC1);
710 PrintAndLogEx(success
? SUCCESS
: WARNING
, "UID | %s | %08X - %s", sprint_hex(uid7
, 7), pwd7
, success
? _GREEN_("ok") : "->FBCFACC1<--");
713 // uint8_t uid5[] = {0x11, 0x22, 0x33, 0x44};
714 // uint64_t key1 = mfc_algo_a(uid5);
715 // success = (key1 == 0xD1E2AA68E39A);
716 // PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %"PRIx64" - %s", sprint_hex(uid5, 4), key1, success ? _GREEN_("ok") : "->D1E2AA68E39A<--");
718 uint8_t uid8
[] = {0x74, 0x57, 0xCA, 0xA9};
720 mfc_algo_sky_one(uid8
, 15, 0, &key8
);
721 success
= (key8
== 0x82c7e64bc565);
724 PrintAndLogEx(success
? SUCCESS
: WARNING
, "UID | %s | %012"PRIx64
" - %s", sprint_hex(uid8
, 4), key8
, success
? _GREEN_("ok") : "->82C7E64BC565<--");
727 uint8_t uid9
[] = {0x11, 0x22, 0x33, 0x44};
729 mfc_algo_saflok_one(uid9
, 0, 0, &key9
);
730 success
= (key9
== 0xD1E2AA68E39A);
733 PrintAndLogEx(success
? SUCCESS
: WARNING
, "UID | %s | %012"PRIX64
" - %s", sprint_hex(uid9
, 4), key9
, success
? _GREEN_("ok") : _RED_(">> D1E2AA68E39A <<"));
735 uint32_t lf_id
= lf_t55xx_white_pwdgen(0x00000080);
736 success
= (lf_id
== 0x00018383);
739 PrintAndLogEx(success
? SUCCESS
: WARNING
, "ID | 0x00000080 | %08"PRIx32
" - %s", lf_id
, success
? _GREEN_("ok") : ">> 00018383 <<");
743 mfc_algo_bambu_one(uid9
, 0, 0, &key13
);
744 success
= (key13
== 0x0729F3B2D37A);
747 PrintAndLogEx(success
? SUCCESS
: WARNING
, "UID | %s | %012"PRIX64
" - %s", sprint_hex(uid9
, 4), key13
, success
? _GREEN_("ok") : _RED_(">> 0729F3B2D37A <<"));
750 PrintAndLogEx(SUCCESS
, "------------------- Selftest %s", (testresult
== NUM_OF_TEST
) ? _GREEN_("ok") : _RED_("fail"));