From 40c6c8b59c3a13d28e441093dcd7f8ad493e67b8 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 9 Sep 2025 15:34:19 +0300 Subject: [PATCH] format --- applications/system/mfkey/crypto1.h | 360 ++--- applications/system/mfkey/mfkey.c | 2245 ++++++++++++--------------- applications/system/mfkey/mfkey.h | 176 +-- 3 files changed, 1269 insertions(+), 1512 deletions(-) diff --git a/applications/system/mfkey/crypto1.h b/applications/system/mfkey/crypto1.h index b9f7c7725..25205ed70 100644 --- a/applications/system/mfkey/crypto1.h +++ b/applications/system/mfkey/crypto1.h @@ -6,202 +6,185 @@ #include #include -#define LF_POLY_ODD (0x29CE5C) +#define LF_POLY_ODD (0x29CE5C) #define LF_POLY_EVEN (0x870804) -#define BIT(x, n) ((x) >> (n) & 1) -#define BEBIT(x, n) BIT(x, (n) ^ 24) +#define BIT(x, n) ((x) >> (n) & 1) +#define BEBIT(x, n) BIT(x, (n) ^ 24) #define SWAPENDIAN(x) \ - ((x) = ((x) >> 8 & 0xff00ff) | ((x) & 0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16) + ((x) = ((x) >> 8 & 0xff00ff) | ((x) & 0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16) static inline uint32_t prng_successor(uint32_t x, uint32_t n); static inline int filter(uint32_t const x); static inline uint8_t evenparity32(uint32_t x); static inline void update_contribution(unsigned int data[], int item, int mask1, int mask2); -void crypto1_get_lfsr(struct Crypto1State *state, MfClassicKey *lfsr); -static inline uint32_t crypt_word(struct Crypto1State *s); -static inline void crypt_word_noret(struct Crypto1State *s, uint32_t in, int x); -static inline uint32_t crypt_word_ret(struct Crypto1State *s, uint32_t in, int x); +void crypto1_get_lfsr(struct Crypto1State* state, MfClassicKey* lfsr); +static inline uint32_t crypt_word(struct Crypto1State* s); +static inline void crypt_word_noret(struct Crypto1State* s, uint32_t in, int x); +static inline uint32_t crypt_word_ret(struct Crypto1State* s, uint32_t in, int x); static uint32_t crypt_word_par( - struct Crypto1State *s, - uint32_t in, - int is_encrypted, - uint32_t nt_plain, - uint8_t *parity_keystream_bits); -static inline void rollback_word_noret(struct Crypto1State *s, uint32_t in, int x); -static inline uint8_t napi_lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb); -static inline uint32_t napi_lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb); + struct Crypto1State* s, + uint32_t in, + int is_encrypted, + uint32_t nt_plain, + uint8_t* parity_keystream_bits); +static inline void rollback_word_noret(struct Crypto1State* s, uint32_t in, int x); +static inline uint8_t napi_lfsr_rollback_bit(struct Crypto1State* s, uint32_t in, int fb); +static inline uint32_t napi_lfsr_rollback_word(struct Crypto1State* s, uint32_t in, int fb); static const uint8_t lookup1[256] = { - 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, - 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, - 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, 8, 8, 24, 24, 8, 24, 8, 8, - 8, 24, 8, 8, 24, 24, 24, 24, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, - 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, - 0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, - 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, - 0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, - 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, 0, 0, 16, 16, 0, 16, 0, 0, - 0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, - 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24}; + 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, + 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, + 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, 8, 8, 24, 24, 8, 24, 8, 8, + 8, 24, 8, 8, 24, 24, 24, 24, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, + 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, + 0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, + 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, + 0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, + 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, 0, 0, 16, 16, 0, 16, 0, 0, + 0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, + 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24}; static const uint8_t lookup2[256] = { - 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, - 4, 4, 4, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, - 2, 2, 6, 6, 6, 6, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 2, 2, 6, 6, 2, 6, 2, - 2, 2, 6, 2, 2, 6, 6, 6, 6, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 0, 0, 4, 4, - 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 2, - 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, - 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, - 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, - 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6}; + 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, + 4, 4, 4, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, + 2, 2, 6, 6, 6, 6, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 2, 2, 6, 6, 2, 6, 2, + 2, 2, 6, 2, 2, 6, 6, 6, 6, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 0, 0, 4, 4, + 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 2, + 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, + 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 4, 4, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, + 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, + 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6}; -static inline int filter(uint32_t const x) -{ - uint32_t f; - f = lookup1[x & 0xff] | lookup2[(x >> 8) & 0xff]; - f |= 0x0d938 >> (x >> 16 & 0xf) & 1; - return BIT(0xEC57E80A, f); +static inline int filter(uint32_t const x) { + uint32_t f; + f = lookup1[x & 0xff] | lookup2[(x >> 8) & 0xff]; + f |= 0x0d938 >> (x >> 16 & 0xf) & 1; + return BIT(0xEC57E80A, f); } #ifdef __ARM_ARCH_7EM__ -static inline uint8_t evenparity32(uint32_t x) -{ - // fold 32 bits -> 16 -> 8 -> 4 - x ^= x >> 16; - x ^= x >> 8; - x ^= x >> 4; - // magic 0x6996: bit i tells you parity of i (0 ≤ i < 16) - return (uint8_t)((0x6996u >> (x & 0xF)) & 1); +static inline uint8_t evenparity32(uint32_t x) { + // fold 32 bits -> 16 -> 8 -> 4 + x ^= x >> 16; + x ^= x >> 8; + x ^= x >> 4; + // magic 0x6996: bit i tells you parity of i (0 ≤ i < 16) + return (uint8_t)((0x6996u >> (x & 0xF)) & 1); } #endif -static inline void update_contribution(unsigned int data[], int item, int mask1, int mask2) -{ - int p = data[item] >> 25; - p = p << 1 | evenparity32(data[item] & mask1); - p = p << 1 | evenparity32(data[item] & mask2); - data[item] = p << 24 | (data[item] & 0xffffff); +static inline void update_contribution(unsigned int data[], int item, int mask1, int mask2) { + int p = data[item] >> 25; + p = p << 1 | evenparity32(data[item] & mask1); + p = p << 1 | evenparity32(data[item] & mask2); + data[item] = p << 24 | (data[item] & 0xffffff); } -static inline uint32_t crypt_word(struct Crypto1State *s) -{ - // "in" and "x" are always 0 (last iteration) - uint32_t res_ret = 0; - uint32_t feedin, t; - for (int i = 0; i <= 31; i++) - { - res_ret |= (filter(s->odd) << (24 ^ i)); //-V629 - feedin = LF_POLY_EVEN & s->even; - feedin ^= LF_POLY_ODD & s->odd; - s->even = s->even << 1 | (evenparity32(feedin)); - t = s->odd, s->odd = s->even, s->even = t; - } - return res_ret; +static inline uint32_t crypt_word(struct Crypto1State* s) { + // "in" and "x" are always 0 (last iteration) + uint32_t res_ret = 0; + uint32_t feedin, t; + for(int i = 0; i <= 31; i++) { + res_ret |= (filter(s->odd) << (24 ^ i)); //-V629 + feedin = LF_POLY_EVEN & s->even; + feedin ^= LF_POLY_ODD & s->odd; + s->even = s->even << 1 | (evenparity32(feedin)); + t = s->odd, s->odd = s->even, s->even = t; + } + return res_ret; } -static inline void crypt_word_noret(struct Crypto1State *s, uint32_t in, int x) -{ - uint8_t ret; - uint32_t feedin, t, next_in; - for (int i = 0; i <= 31; i++) - { - next_in = BEBIT(in, i); - ret = filter(s->odd); - feedin = ret & (!!x); - feedin ^= LF_POLY_EVEN & s->even; - feedin ^= LF_POLY_ODD & s->odd; - feedin ^= !!next_in; - s->even = s->even << 1 | (evenparity32(feedin)); - t = s->odd, s->odd = s->even, s->even = t; - } - return; +static inline void crypt_word_noret(struct Crypto1State* s, uint32_t in, int x) { + uint8_t ret; + uint32_t feedin, t, next_in; + for(int i = 0; i <= 31; i++) { + next_in = BEBIT(in, i); + ret = filter(s->odd); + feedin = ret & (!!x); + feedin ^= LF_POLY_EVEN & s->even; + feedin ^= LF_POLY_ODD & s->odd; + feedin ^= !!next_in; + s->even = s->even << 1 | (evenparity32(feedin)); + t = s->odd, s->odd = s->even, s->even = t; + } + return; } -static inline uint32_t crypt_word_ret(struct Crypto1State *s, uint32_t in, int x) -{ - uint32_t ret = 0; - uint32_t feedin, t, next_in; - uint8_t next_ret; - for (int i = 0; i <= 31; i++) - { - next_in = BEBIT(in, i); - next_ret = filter(s->odd); - feedin = next_ret & (!!x); - feedin ^= LF_POLY_EVEN & s->even; - feedin ^= LF_POLY_ODD & s->odd; - feedin ^= !!next_in; - s->even = s->even << 1 | (evenparity32(feedin)); - t = s->odd, s->odd = s->even, s->even = t; - ret |= next_ret << (24 ^ i); - } - return ret; +static inline uint32_t crypt_word_ret(struct Crypto1State* s, uint32_t in, int x) { + uint32_t ret = 0; + uint32_t feedin, t, next_in; + uint8_t next_ret; + for(int i = 0; i <= 31; i++) { + next_in = BEBIT(in, i); + next_ret = filter(s->odd); + feedin = next_ret & (!!x); + feedin ^= LF_POLY_EVEN & s->even; + feedin ^= LF_POLY_ODD & s->odd; + feedin ^= !!next_in; + s->even = s->even << 1 | (evenparity32(feedin)); + t = s->odd, s->odd = s->even, s->even = t; + ret |= next_ret << (24 ^ i); + } + return ret; } -static uint8_t get_nth_byte(uint32_t value, int n) -{ - if (n < 0 || n > 3) - { - // Handle invalid input - return 0; - } - return (value >> (8 * (3 - n))) & 0xFF; +static uint8_t get_nth_byte(uint32_t value, int n) { + if(n < 0 || n > 3) { + // Handle invalid input + return 0; + } + return (value >> (8 * (3 - n))) & 0xFF; } -static uint8_t crypt_bit(struct Crypto1State *s, uint8_t in, int is_encrypted) -{ - uint32_t feedin, t; - uint8_t ret = filter(s->odd); - feedin = ret & !!is_encrypted; - feedin ^= !!in; - feedin ^= LF_POLY_ODD & s->odd; - feedin ^= LF_POLY_EVEN & s->even; - s->even = s->even << 1 | evenparity32(feedin); - t = s->odd, s->odd = s->even, s->even = t; - return ret; +static uint8_t crypt_bit(struct Crypto1State* s, uint8_t in, int is_encrypted) { + uint32_t feedin, t; + uint8_t ret = filter(s->odd); + feedin = ret & !!is_encrypted; + feedin ^= !!in; + feedin ^= LF_POLY_ODD & s->odd; + feedin ^= LF_POLY_EVEN & s->even; + s->even = s->even << 1 | evenparity32(feedin); + t = s->odd, s->odd = s->even, s->even = t; + return ret; } static inline uint32_t crypt_word_par( - struct Crypto1State *s, - uint32_t in, - int is_encrypted, - uint32_t nt_plain, - uint8_t *parity_keystream_bits) -{ - uint32_t ret = 0; - *parity_keystream_bits = 0; // Reset parity keystream bits + struct Crypto1State* s, + uint32_t in, + int is_encrypted, + uint32_t nt_plain, + uint8_t* parity_keystream_bits) { + uint32_t ret = 0; + *parity_keystream_bits = 0; // Reset parity keystream bits - for (int i = 0; i < 32; i++) - { - uint8_t bit = crypt_bit(s, BEBIT(in, i), is_encrypted); - ret |= bit << (24 ^ i); - // Save keystream parity bit - if ((i + 1) % 8 == 0) - { - *parity_keystream_bits |= - (filter(s->odd) ^ nfc_util_even_parity8(get_nth_byte(nt_plain, i / 8))) - << (3 - (i / 8)); - } - } - return ret; + for(int i = 0; i < 32; i++) { + uint8_t bit = crypt_bit(s, BEBIT(in, i), is_encrypted); + ret |= bit << (24 ^ i); + // Save keystream parity bit + if((i + 1) % 8 == 0) { + *parity_keystream_bits |= + (filter(s->odd) ^ nfc_util_even_parity8(get_nth_byte(nt_plain, i / 8))) + << (3 - (i / 8)); + } + } + return ret; } -static inline void rollback_word_noret(struct Crypto1State *s, uint32_t in, int x) -{ - uint8_t ret; - uint32_t feedin, t, next_in; - for (int i = 31; i >= 0; i--) - { - next_in = BEBIT(in, i); - s->odd &= 0xffffff; - t = s->odd, s->odd = s->even, s->even = t; - ret = filter(s->odd); - feedin = ret & (!!x); - feedin ^= s->even & 1; - feedin ^= LF_POLY_EVEN & (s->even >>= 1); - feedin ^= LF_POLY_ODD & s->odd; - feedin ^= !!next_in; - s->even |= (evenparity32(feedin)) << 23; - } - return; +static inline void rollback_word_noret(struct Crypto1State* s, uint32_t in, int x) { + uint8_t ret; + uint32_t feedin, t, next_in; + for(int i = 31; i >= 0; i--) { + next_in = BEBIT(in, i); + s->odd &= 0xffffff; + t = s->odd, s->odd = s->even, s->even = t; + ret = filter(s->odd); + feedin = ret & (!!x); + feedin ^= s->even & 1; + feedin ^= LF_POLY_EVEN & (s->even >>= 1); + feedin ^= LF_POLY_ODD & s->odd; + feedin ^= !!next_in; + s->even |= (evenparity32(feedin)) << 23; + } + return; } // TODO: @@ -227,39 +210,36 @@ uint32_t rollback_word(struct Crypto1State *s, uint32_t in, int x) { } */ -uint8_t napi_lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb) -{ - int out; - uint8_t ret; - uint32_t t; - s->odd &= 0xffffff; - t = s->odd, s->odd = s->even, s->even = t; +uint8_t napi_lfsr_rollback_bit(struct Crypto1State* s, uint32_t in, int fb) { + int out; + uint8_t ret; + uint32_t t; + s->odd &= 0xffffff; + t = s->odd, s->odd = s->even, s->even = t; - out = s->even & 1; - out ^= LF_POLY_EVEN & (s->even >>= 1); - out ^= LF_POLY_ODD & s->odd; - out ^= !!in; - out ^= (ret = filter(s->odd)) & !!fb; + out = s->even & 1; + out ^= LF_POLY_EVEN & (s->even >>= 1); + out ^= LF_POLY_ODD & s->odd; + out ^= !!in; + out ^= (ret = filter(s->odd)) & !!fb; - s->even |= evenparity32(out) << 23; - return ret; + s->even |= evenparity32(out) << 23; + return ret; } -uint32_t napi_lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb) -{ - int i; - uint32_t ret = 0; - for (i = 31; i >= 0; --i) - ret |= napi_lfsr_rollback_bit(s, BEBIT(in, i), fb) << (i ^ 24); - return ret; +uint32_t napi_lfsr_rollback_word(struct Crypto1State* s, uint32_t in, int fb) { + int i; + uint32_t ret = 0; + for(i = 31; i >= 0; --i) + ret |= napi_lfsr_rollback_bit(s, BEBIT(in, i), fb) << (i ^ 24); + return ret; } -static inline uint32_t prng_successor(uint32_t x, uint32_t n) -{ - SWAPENDIAN(x); - while (n--) - x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; - return SWAPENDIAN(x); +static inline uint32_t prng_successor(uint32_t x, uint32_t n) { + SWAPENDIAN(x); + while(n--) + x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; + return SWAPENDIAN(x); } -#endif // CRYPTO1_H \ No newline at end of file +#endif // CRYPTO1_H diff --git a/applications/system/mfkey/mfkey.c b/applications/system/mfkey/mfkey.c index e49b96263..9e3e71847 100644 --- a/applications/system/mfkey/mfkey.c +++ b/applications/system/mfkey/mfkey.c @@ -34,29 +34,28 @@ #define TAG "MFKey" // TODO: Remove defines that are not needed -#define KEYS_DICT_SYSTEM_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc") -#define KEYS_DICT_USER_PATH EXT_PATH("nfc/assets/mf_classic_dict_user.nfc") -#define MAX_NAME_LEN 32 -#define MAX_PATH_LEN 64 +#define KEYS_DICT_SYSTEM_PATH EXT_PATH("nfc/assets/mf_classic_dict.nfc") +#define KEYS_DICT_USER_PATH EXT_PATH("nfc/assets/mf_classic_dict_user.nfc") +#define MAX_NAME_LEN 32 +#define MAX_PATH_LEN 64 #define STATIC_ENCRYPTED_RAM_THRESHOLD 4096 -#define LF_POLY_ODD (0x29CE5C) +#define LF_POLY_ODD (0x29CE5C) #define LF_POLY_EVEN (0x870804) -#define CONST_M1_1 (LF_POLY_EVEN << 1 | 1) -#define CONST_M2_1 (LF_POLY_ODD << 1) -#define CONST_M1_2 (LF_POLY_ODD) -#define CONST_M2_2 (LF_POLY_EVEN << 1 | 1) -#define BIT(x, n) ((x) >> (n) & 1) -#define BEBIT(x, n) BIT(x, (n) ^ 24) +#define CONST_M1_1 (LF_POLY_EVEN << 1 | 1) +#define CONST_M2_1 (LF_POLY_ODD << 1) +#define CONST_M1_2 (LF_POLY_ODD) +#define CONST_M2_2 (LF_POLY_EVEN << 1 | 1) +#define BIT(x, n) ((x) >> (n) & 1) +#define BEBIT(x, n) BIT(x, (n) ^ 24) #define SWAP(a, b) \ - do \ - { \ - unsigned int t = a; \ - a = b; \ - b = t; \ - } while (0) + do { \ + unsigned int t = a; \ + a = b; \ + b = t; \ + } while(0) #define SWAPENDIAN(x) \ - ((x) = ((x) >> 8 & 0xff00ff) | ((x) & 0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16) + ((x) = ((x) >> 8 & 0xff00ff) | ((x) & 0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16) // #define SIZEOF(arr) sizeof(arr) / sizeof(*arr) // Reduced to 16-bit as these values are small and don't need 32-bit @@ -65,1315 +64,1105 @@ static int16_t eta_total_time = 705; // MSB_LIMIT: Chunk size (out of 256) - can be 8-bit as it's a small value static uint8_t MSB_LIMIT = 16; -static inline void flush_key_buffer(ProgramState *program_state) -{ - if (program_state->key_buffer && program_state->key_buffer_count > 0 && program_state->cuid_dict) - { - // Pre-allocate exact size needed: 12 hex chars + 1 newline per key - size_t total_size = program_state->key_buffer_count * 13; - //FURI_LOG_I(TAG, "Flushing key buffer: %d keys", program_state->key_buffer_count); - //FURI_LOG_I(TAG, "Total size: %d bytes", total_size); - char* batch_buffer = malloc(total_size + 1); // +1 for null terminator - - char* ptr = batch_buffer; - const char hex_chars[] = "0123456789ABCDEF"; - - for (size_t i = 0; i < program_state->key_buffer_count; i++) - { - // Convert key to hex string directly into buffer - for (size_t j = 0; j < sizeof(MfClassicKey); j++) - { - uint8_t byte = program_state->key_buffer[i].data[j]; - *ptr++ = hex_chars[byte >> 4]; - *ptr++ = hex_chars[byte & 0x0F]; - } - *ptr++ = '\n'; - } - *ptr = '\0'; - - // Write all keys at once by directly accessing the stream - Stream* stream = program_state->cuid_dict->stream; - uint32_t actual_pos = stream_tell(stream); - - if (stream_seek(stream, 0, StreamOffsetFromEnd) && - stream_write(stream, (uint8_t*)batch_buffer, total_size) == total_size) - { - // Update total key count - program_state->cuid_dict->total_keys += program_state->key_buffer_count; - } - - // May not be needed - stream_seek(stream, actual_pos, StreamOffsetFromStart); - free(batch_buffer); - program_state->key_buffer_count = 0; - } +static inline void flush_key_buffer(ProgramState* program_state) { + if(program_state->key_buffer && program_state->key_buffer_count > 0 && + program_state->cuid_dict) { + // Pre-allocate exact size needed: 12 hex chars + 1 newline per key + size_t total_size = program_state->key_buffer_count * 13; + //FURI_LOG_I(TAG, "Flushing key buffer: %d keys", program_state->key_buffer_count); + //FURI_LOG_I(TAG, "Total size: %d bytes", total_size); + char* batch_buffer = malloc(total_size + 1); // +1 for null terminator + + char* ptr = batch_buffer; + const char hex_chars[] = "0123456789ABCDEF"; + + for(size_t i = 0; i < program_state->key_buffer_count; i++) { + // Convert key to hex string directly into buffer + for(size_t j = 0; j < sizeof(MfClassicKey); j++) { + uint8_t byte = program_state->key_buffer[i].data[j]; + *ptr++ = hex_chars[byte >> 4]; + *ptr++ = hex_chars[byte & 0x0F]; + } + *ptr++ = '\n'; + } + *ptr = '\0'; + + // Write all keys at once by directly accessing the stream + Stream* stream = program_state->cuid_dict->stream; + uint32_t actual_pos = stream_tell(stream); + + if(stream_seek(stream, 0, StreamOffsetFromEnd) && + stream_write(stream, (uint8_t*)batch_buffer, total_size) == total_size) { + // Update total key count + program_state->cuid_dict->total_keys += program_state->key_buffer_count; + } + + // May not be needed + stream_seek(stream, actual_pos, StreamOffsetFromStart); + free(batch_buffer); + program_state->key_buffer_count = 0; + } } static inline int -check_state(struct Crypto1State *t, MfClassicNonce *n, ProgramState *program_state) -{ - if (!(t->odd | t->even)) - return 0; - if (n->attack == mfkey32) - { - uint32_t rb = (napi_lfsr_rollback_word(t, 0, 0) ^ n->p64); - if (rb != n->ar0_enc) - { - return 0; - } - rollback_word_noret(t, n->nr0_enc, 1); - rollback_word_noret(t, n->uid_xor_nt0, 0); - struct Crypto1State temp = {t->odd, t->even}; - crypt_word_noret(t, n->uid_xor_nt1, 0); - crypt_word_noret(t, n->nr1_enc, 1); - if (n->ar1_enc == (crypt_word(t) ^ n->p64b)) - { - crypto1_get_lfsr(&temp, &(n->key)); - return 1; - } - } - else if (n->attack == static_nested) - { - struct Crypto1State temp = {t->odd, t->even}; - rollback_word_noret(t, n->uid_xor_nt1, 0); - if (n->ks1_1_enc == crypt_word_ret(t, n->uid_xor_nt0, 0)) - { - rollback_word_noret(&temp, n->uid_xor_nt1, 0); - crypto1_get_lfsr(&temp, &(n->key)); - return 1; - } - } - else if (n->attack == static_encrypted) - { - // TODO: Parity bits from rollback_word? - if (n->ks1_1_enc == napi_lfsr_rollback_word(t, n->uid_xor_nt0, 0)) - { - // Reduce with parity - uint8_t local_parity_keystream_bits; - struct Crypto1State temp = {t->odd, t->even}; - if ((crypt_word_par(&temp, n->uid_xor_nt0, 0, n->nt0, &local_parity_keystream_bits) == - n->ks1_1_enc) && - (local_parity_keystream_bits == n->par_1)) - { - // Found key candidate - crypto1_get_lfsr(t, &(n->key)); - program_state->num_candidates++; - - // Use key buffer - buffer is guaranteed to be available for static_encrypted - program_state->key_buffer[program_state->key_buffer_count] = n->key; - program_state->key_buffer_count++; - - // Flush buffer when full - if (program_state->key_buffer_count >= program_state->key_buffer_size) - { - flush_key_buffer(program_state); - } - } - } - } - return 0; + check_state(struct Crypto1State* t, MfClassicNonce* n, ProgramState* program_state) { + if(!(t->odd | t->even)) return 0; + if(n->attack == mfkey32) { + uint32_t rb = (napi_lfsr_rollback_word(t, 0, 0) ^ n->p64); + if(rb != n->ar0_enc) { + return 0; + } + rollback_word_noret(t, n->nr0_enc, 1); + rollback_word_noret(t, n->uid_xor_nt0, 0); + struct Crypto1State temp = {t->odd, t->even}; + crypt_word_noret(t, n->uid_xor_nt1, 0); + crypt_word_noret(t, n->nr1_enc, 1); + if(n->ar1_enc == (crypt_word(t) ^ n->p64b)) { + crypto1_get_lfsr(&temp, &(n->key)); + return 1; + } + } else if(n->attack == static_nested) { + struct Crypto1State temp = {t->odd, t->even}; + rollback_word_noret(t, n->uid_xor_nt1, 0); + if(n->ks1_1_enc == crypt_word_ret(t, n->uid_xor_nt0, 0)) { + rollback_word_noret(&temp, n->uid_xor_nt1, 0); + crypto1_get_lfsr(&temp, &(n->key)); + return 1; + } + } else if(n->attack == static_encrypted) { + // TODO: Parity bits from rollback_word? + if(n->ks1_1_enc == napi_lfsr_rollback_word(t, n->uid_xor_nt0, 0)) { + // Reduce with parity + uint8_t local_parity_keystream_bits; + struct Crypto1State temp = {t->odd, t->even}; + if((crypt_word_par(&temp, n->uid_xor_nt0, 0, n->nt0, &local_parity_keystream_bits) == + n->ks1_1_enc) && + (local_parity_keystream_bits == n->par_1)) { + // Found key candidate + crypto1_get_lfsr(t, &(n->key)); + program_state->num_candidates++; + + // Use key buffer - buffer is guaranteed to be available for static_encrypted + program_state->key_buffer[program_state->key_buffer_count] = n->key; + program_state->key_buffer_count++; + + // Flush buffer when full + if(program_state->key_buffer_count >= program_state->key_buffer_size) { + flush_key_buffer(program_state); + } + } + } + } + return 0; } -static inline __attribute__((hot)) int state_loop( - unsigned int *states_buffer, - int xks, - int m1, - int m2, - unsigned int in, - int and_val) -{ - int states_tail = 0; - int xks_bit = 0, round_in = 0; +static inline __attribute__((hot)) int + state_loop(unsigned int* states_buffer, int xks, int m1, int m2, unsigned int in, int and_val) { + int states_tail = 0; + int xks_bit = 0, round_in = 0; - // Unroll first 4 rounds (no round_in calculations needed) - // Hoist the filter() calls to just one iteration and reuse the results - // This avoids redundant calculations and improves performance and gives us 2000b of extra ram (11496b free on run) - // V.28/04. Aprox 3s speedup per round. Total 3 keys 7mins 17s!! - for (int round = 1; round <= 4; ++round) - { - xks_bit = BIT(xks, round); - for (int s = 0; s <= states_tail; ++s) - { - unsigned int v = states_buffer[s] << 1; - states_buffer[s] = v; - int f0 = filter(v); - int f1 = filter(v | 1); + // Unroll first 4 rounds (no round_in calculations needed) + // Hoist the filter() calls to just one iteration and reuse the results + // This avoids redundant calculations and improves performance and gives us 2000b of extra ram (11496b free on run) + // V.28/04. Aprox 3s speedup per round. Total 3 keys 7mins 17s!! + for(int round = 1; round <= 4; ++round) { + xks_bit = BIT(xks, round); + for(int s = 0; s <= states_tail; ++s) { + unsigned int v = states_buffer[s] << 1; + states_buffer[s] = v; + int f0 = filter(v); + int f1 = filter(v | 1); - if (__builtin_expect((f0 ^ f1) != 0, 0)) - { - states_buffer[s] |= f0 ^ xks_bit; - } - else if (__builtin_expect(f0 == xks_bit, 1)) - { - states_buffer[++states_tail] = states_buffer[++s]; - states_buffer[s] = states_buffer[s - 1] | 1; - } - else - { - states_buffer[s--] = states_buffer[states_tail--]; - } - } - } + if(__builtin_expect((f0 ^ f1) != 0, 0)) { + states_buffer[s] |= f0 ^ xks_bit; + } else if(__builtin_expect(f0 == xks_bit, 1)) { + states_buffer[++states_tail] = states_buffer[++s]; + states_buffer[s] = states_buffer[s - 1] | 1; + } else { + states_buffer[s--] = states_buffer[states_tail--]; + } + } + } - // Round 5 (unrolled) - { - xks_bit = BIT(xks, 5); - int r5_in = ((in >> 2) & and_val) << 24; // 2*(5-4)=2 - for (int s = 0; s <= states_tail; ++s) - { - unsigned int v = states_buffer[s] << 1; - states_buffer[s] = v; - int f0 = filter(v), f1 = filter(v | 1); - if (__builtin_expect((f0 ^ f1) != 0, 0)) - { - states_buffer[s] |= f0 ^ xks_bit; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s] ^= r5_in; - } - else if (__builtin_expect(f0 == xks_bit, 1)) - { - states_buffer[++states_tail] = states_buffer[s + 1]; - states_buffer[s + 1] = v | 1; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s++] ^= r5_in; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s] ^= r5_in; - } - else - { - states_buffer[s--] = states_buffer[states_tail--]; - } - } - } + // Round 5 (unrolled) + { + xks_bit = BIT(xks, 5); + int r5_in = ((in >> 2) & and_val) << 24; // 2*(5-4)=2 + for(int s = 0; s <= states_tail; ++s) { + unsigned int v = states_buffer[s] << 1; + states_buffer[s] = v; + int f0 = filter(v), f1 = filter(v | 1); + if(__builtin_expect((f0 ^ f1) != 0, 0)) { + states_buffer[s] |= f0 ^ xks_bit; + update_contribution(states_buffer, s, m1, m2); + states_buffer[s] ^= r5_in; + } else if(__builtin_expect(f0 == xks_bit, 1)) { + states_buffer[++states_tail] = states_buffer[s + 1]; + states_buffer[s + 1] = v | 1; + update_contribution(states_buffer, s, m1, m2); + states_buffer[s++] ^= r5_in; + update_contribution(states_buffer, s, m1, m2); + states_buffer[s] ^= r5_in; + } else { + states_buffer[s--] = states_buffer[states_tail--]; + } + } + } - // Round 6 (unrolled) - { - xks_bit = BIT(xks, 6); - int r6_in = ((in >> 4) & and_val) << 24; // 2*(6-4)=4 - for (int s = 0; s <= states_tail; ++s) - { - unsigned int v = states_buffer[s] << 1; - states_buffer[s] = v; - int f0 = filter(v), f1 = filter(v | 1); - if (__builtin_expect((f0 ^ f1) != 0, 0)) - { - states_buffer[s] |= f0 ^ xks_bit; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s] ^= r6_in; - } - else if (__builtin_expect(f0 == xks_bit, 1)) - { - states_buffer[++states_tail] = states_buffer[s + 1]; - states_buffer[s + 1] = v | 1; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s++] ^= r6_in; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s] ^= r6_in; - } - else - { - states_buffer[s--] = states_buffer[states_tail--]; - } - } - } + // Round 6 (unrolled) + { + xks_bit = BIT(xks, 6); + int r6_in = ((in >> 4) & and_val) << 24; // 2*(6-4)=4 + for(int s = 0; s <= states_tail; ++s) { + unsigned int v = states_buffer[s] << 1; + states_buffer[s] = v; + int f0 = filter(v), f1 = filter(v | 1); + if(__builtin_expect((f0 ^ f1) != 0, 0)) { + states_buffer[s] |= f0 ^ xks_bit; + update_contribution(states_buffer, s, m1, m2); + states_buffer[s] ^= r6_in; + } else if(__builtin_expect(f0 == xks_bit, 1)) { + states_buffer[++states_tail] = states_buffer[s + 1]; + states_buffer[s + 1] = v | 1; + update_contribution(states_buffer, s, m1, m2); + states_buffer[s++] ^= r6_in; + update_contribution(states_buffer, s, m1, m2); + states_buffer[s] ^= r6_in; + } else { + states_buffer[s--] = states_buffer[states_tail--]; + } + } + } - // Loop rounds 7–12 - for (int round = 7; round <= 12; ++round) - { - xks_bit = BIT(xks, round); - round_in = ((in >> (2 * (round - 4))) & and_val) << 24; - for (int s = 0; s <= states_tail; ++s) - { - unsigned int v = states_buffer[s] << 1; - states_buffer[s] = v; - int f0 = filter(v), f1 = filter(v | 1); - if (__builtin_expect((f0 ^ f1) != 0, 0)) - { - states_buffer[s] |= f0 ^ xks_bit; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s] ^= round_in; - } - else if (__builtin_expect(f0 == xks_bit, 1)) - { - states_buffer[++states_tail] = states_buffer[s + 1]; - states_buffer[s + 1] = v | 1; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s++] ^= round_in; - update_contribution(states_buffer, s, m1, m2); - states_buffer[s] ^= round_in; - } - else - { - states_buffer[s--] = states_buffer[states_tail--]; - } - } - } + // Loop rounds 7–12 + for(int round = 7; round <= 12; ++round) { + xks_bit = BIT(xks, round); + round_in = ((in >> (2 * (round - 4))) & and_val) << 24; + for(int s = 0; s <= states_tail; ++s) { + unsigned int v = states_buffer[s] << 1; + states_buffer[s] = v; + int f0 = filter(v), f1 = filter(v | 1); + if(__builtin_expect((f0 ^ f1) != 0, 0)) { + states_buffer[s] |= f0 ^ xks_bit; + update_contribution(states_buffer, s, m1, m2); + states_buffer[s] ^= round_in; + } else if(__builtin_expect(f0 == xks_bit, 1)) { + states_buffer[++states_tail] = states_buffer[s + 1]; + states_buffer[s + 1] = v | 1; + update_contribution(states_buffer, s, m1, m2); + states_buffer[s++] ^= round_in; + update_contribution(states_buffer, s, m1, m2); + states_buffer[s] ^= round_in; + } else { + states_buffer[s--] = states_buffer[states_tail--]; + } + } + } - return states_tail; + return states_tail; } -int binsearch(unsigned int data[], int start, int stop) -{ - int mid, val = data[stop] & 0xff000000; - while (start != stop) - { - mid = (stop - start) >> 1; - if ((data[start + mid] ^ 0x80000000) > (val ^ 0x80000000)) - stop = start + mid; - else - start += mid + 1; - } - return start; +int binsearch(unsigned int data[], int start, int stop) { + int mid, val = data[stop] & 0xff000000; + while(start != stop) { + mid = (stop - start) >> 1; + if((data[start + mid] ^ 0x80000000) > (val ^ 0x80000000)) + stop = start + mid; + else + start += mid + 1; + } + return start; } -void quicksort(unsigned int array[], int low, int high) -{ - // Use insertion sort for small arrays (threshold determined by testing) - if (high - low < 16) - { - // Insertion sort - for (int i = low + 1; i <= high; i++) - { - unsigned int key = array[i]; - int j = i - 1; - while (j >= low && array[j] > key) - { - array[j + 1] = array[j]; - j--; - } - array[j + 1] = key; - } - return; - } +void quicksort(unsigned int array[], int low, int high) { + // Use insertion sort for small arrays (threshold determined by testing) + if(high - low < 16) { + // Insertion sort + for(int i = low + 1; i <= high; i++) { + unsigned int key = array[i]; + int j = i - 1; + while(j >= low && array[j] > key) { + array[j + 1] = array[j]; + j--; + } + array[j + 1] = key; + } + return; + } - if (low >= high) - return; + if(low >= high) return; - // Median-of-three pivot selection - int middle = low + (high - low) / 2; - if (array[middle] < array[low]) - SWAP(array[middle], array[low]); - if (array[high] < array[low]) - SWAP(array[high], array[low]); - if (array[high] < array[middle]) - SWAP(array[high], array[middle]); + // Median-of-three pivot selection + int middle = low + (high - low) / 2; + if(array[middle] < array[low]) SWAP(array[middle], array[low]); + if(array[high] < array[low]) SWAP(array[high], array[low]); + if(array[high] < array[middle]) SWAP(array[high], array[middle]); - unsigned int pivot = array[middle]; + unsigned int pivot = array[middle]; - // Rest of quicksort with improved partitioning - int i = low, j = high; - while (i <= j) - { - while (array[i] < pivot) - i++; - while (array[j] > pivot) - j--; - if (i <= j) - { - // swap - unsigned int temp = array[i]; - array[i] = array[j]; - array[j] = temp; - i++; - j--; - } - } + // Rest of quicksort with improved partitioning + int i = low, j = high; + while(i <= j) { + while(array[i] < pivot) + i++; + while(array[j] > pivot) + j--; + if(i <= j) { + // swap + unsigned int temp = array[i]; + array[i] = array[j]; + array[j] = temp; + i++; + j--; + } + } - if (low < j) - quicksort(array, low, j); - if (high > i) - quicksort(array, i, high); + if(low < j) quicksort(array, low, j); + if(high > i) quicksort(array, i, high); } -int extend_table(unsigned int data[], int tbl, int end, int bit, int m1, int m2, unsigned int in) -{ - in <<= 24; - for (data[tbl] <<= 1; tbl <= end; data[++tbl] <<= 1) - { - if ((filter(data[tbl]) ^ filter(data[tbl] | 1)) != 0) - { - data[tbl] |= filter(data[tbl]) ^ bit; - update_contribution(data, tbl, m1, m2); - data[tbl] ^= in; - } - else if (filter(data[tbl]) == bit) - { - data[++end] = data[tbl + 1]; - data[tbl + 1] = data[tbl] | 1; - update_contribution(data, tbl, m1, m2); - data[tbl++] ^= in; - update_contribution(data, tbl, m1, m2); - data[tbl] ^= in; - } - else - { - data[tbl--] = data[end--]; - } - } - return end; +int extend_table(unsigned int data[], int tbl, int end, int bit, int m1, int m2, unsigned int in) { + in <<= 24; + for(data[tbl] <<= 1; tbl <= end; data[++tbl] <<= 1) { + if((filter(data[tbl]) ^ filter(data[tbl] | 1)) != 0) { + data[tbl] |= filter(data[tbl]) ^ bit; + update_contribution(data, tbl, m1, m2); + data[tbl] ^= in; + } else if(filter(data[tbl]) == bit) { + data[++end] = data[tbl + 1]; + data[tbl + 1] = data[tbl] | 1; + update_contribution(data, tbl, m1, m2); + data[tbl++] ^= in; + update_contribution(data, tbl, m1, m2); + data[tbl] ^= in; + } else { + data[tbl--] = data[end--]; + } + } + return end; } int old_recover( - unsigned int odd[], - int o_head, - int o_tail, - int oks, - unsigned int even[], - int e_head, - int e_tail, - int eks, - int rem, - int s, - MfClassicNonce *n, - unsigned int in, - int first_run, - ProgramState *program_state) -{ - int o, e, i; - if (rem == -1) - { - for (e = e_head; e <= e_tail; ++e) - { - even[e] = (even[e] << 1) ^ evenparity32(even[e] & LF_POLY_EVEN) ^ (!!(in & 4)); - for (o = o_head; o <= o_tail; ++o, ++s) - { - struct Crypto1State temp = {0, 0}; - temp.even = odd[o]; - temp.odd = even[e] ^ evenparity32(odd[o] & LF_POLY_ODD); - if (check_state(&temp, n, program_state)) - { - return -1; - } - } - } - return s; - } - if (first_run == 0) - { - for (i = 0; (i < 4) && (rem-- != 0); i++) - { - oks >>= 1; - eks >>= 1; - in >>= 2; - o_tail = extend_table( - odd, o_head, o_tail, oks & 1, LF_POLY_EVEN << 1 | 1, LF_POLY_ODD << 1, 0); - if (o_head > o_tail) - return s; - e_tail = extend_table( - even, e_head, e_tail, eks & 1, LF_POLY_ODD, LF_POLY_EVEN << 1 | 1, in & 3); - if (e_head > e_tail) - return s; - } - } - first_run = 0; - quicksort(odd, o_head, o_tail); - quicksort(even, e_head, e_tail); - while (o_tail >= o_head && e_tail >= e_head) - { - if (((odd[o_tail] ^ even[e_tail]) >> 24) == 0) - { - o_tail = binsearch(odd, o_head, o = o_tail); - e_tail = binsearch(even, e_head, e = e_tail); - s = old_recover( - odd, - o_tail--, - o, - oks, - even, - e_tail--, - e, - eks, - rem, - s, - n, - in, - first_run, - program_state); - if (s == -1) - { - break; - } - } - else if ((odd[o_tail] ^ 0x80000000) > (even[e_tail] ^ 0x80000000)) - { - o_tail = binsearch(odd, o_head, o_tail) - 1; - } - else - { - e_tail = binsearch(even, e_head, e_tail) - 1; - } - } - return s; + unsigned int odd[], + int o_head, + int o_tail, + int oks, + unsigned int even[], + int e_head, + int e_tail, + int eks, + int rem, + int s, + MfClassicNonce* n, + unsigned int in, + int first_run, + ProgramState* program_state) { + int o, e, i; + if(rem == -1) { + for(e = e_head; e <= e_tail; ++e) { + even[e] = (even[e] << 1) ^ evenparity32(even[e] & LF_POLY_EVEN) ^ (!!(in & 4)); + for(o = o_head; o <= o_tail; ++o, ++s) { + struct Crypto1State temp = {0, 0}; + temp.even = odd[o]; + temp.odd = even[e] ^ evenparity32(odd[o] & LF_POLY_ODD); + if(check_state(&temp, n, program_state)) { + return -1; + } + } + } + return s; + } + if(first_run == 0) { + for(i = 0; (i < 4) && (rem-- != 0); i++) { + oks >>= 1; + eks >>= 1; + in >>= 2; + o_tail = extend_table( + odd, o_head, o_tail, oks & 1, LF_POLY_EVEN << 1 | 1, LF_POLY_ODD << 1, 0); + if(o_head > o_tail) return s; + e_tail = extend_table( + even, e_head, e_tail, eks & 1, LF_POLY_ODD, LF_POLY_EVEN << 1 | 1, in & 3); + if(e_head > e_tail) return s; + } + } + first_run = 0; + quicksort(odd, o_head, o_tail); + quicksort(even, e_head, e_tail); + while(o_tail >= o_head && e_tail >= e_head) { + if(((odd[o_tail] ^ even[e_tail]) >> 24) == 0) { + o_tail = binsearch(odd, o_head, o = o_tail); + e_tail = binsearch(even, e_head, e = e_tail); + s = old_recover( + odd, + o_tail--, + o, + oks, + even, + e_tail--, + e, + eks, + rem, + s, + n, + in, + first_run, + program_state); + if(s == -1) { + break; + } + } else if((odd[o_tail] ^ 0x80000000) > (even[e_tail] ^ 0x80000000)) { + o_tail = binsearch(odd, o_head, o_tail) - 1; + } else { + e_tail = binsearch(even, e_head, e_tail) - 1; + } + } + return s; } -static inline int sync_state(ProgramState *program_state) -{ - int ts = furi_hal_rtc_get_timestamp(); - int elapsed_time = ts - program_state->eta_timestamp; - if (elapsed_time < program_state->eta_round) - { - program_state->eta_round -= elapsed_time; - } - else - { - program_state->eta_round = 0; - } - if (elapsed_time < program_state->eta_total) - { - program_state->eta_total -= elapsed_time; - } - else - { - program_state->eta_total = 0; - } - program_state->eta_timestamp = ts; - if (program_state->close_thread_please) - { - return 1; - } - return 0; +static inline int sync_state(ProgramState* program_state) { + int ts = furi_hal_rtc_get_timestamp(); + int elapsed_time = ts - program_state->eta_timestamp; + if(elapsed_time < program_state->eta_round) { + program_state->eta_round -= elapsed_time; + } else { + program_state->eta_round = 0; + } + if(elapsed_time < program_state->eta_total) { + program_state->eta_total -= elapsed_time; + } else { + program_state->eta_total = 0; + } + program_state->eta_timestamp = ts; + if(program_state->close_thread_please) { + return 1; + } + return 0; } int calculate_msb_tables( - int oks, - int eks, - int msb_round, - MfClassicNonce *n, - unsigned int *states_buffer, - struct Msb *odd_msbs, - struct Msb *even_msbs, - unsigned int *temp_states_odd, - unsigned int *temp_states_even, - unsigned int in, - ProgramState *program_state) -{ - unsigned int msb_head = (MSB_LIMIT * msb_round); - unsigned int msb_tail = (MSB_LIMIT * (msb_round + 1)); - int states_tail = 0; - int semi_state = 0; - unsigned int msb = 0; + int oks, + int eks, + int msb_round, + MfClassicNonce* n, + unsigned int* states_buffer, + struct Msb* odd_msbs, + struct Msb* even_msbs, + unsigned int* temp_states_odd, + unsigned int* temp_states_even, + unsigned int in, + ProgramState* program_state) { + unsigned int msb_head = (MSB_LIMIT * msb_round); + unsigned int msb_tail = (MSB_LIMIT * (msb_round + 1)); + int states_tail = 0; + int semi_state = 0; + unsigned int msb = 0; - // Preprocessed in value - in = ((in >> 16 & 0xff) | (in << 16) | (in & 0xff00)) << 1; + // Preprocessed in value + in = ((in >> 16 & 0xff) | (in << 16) | (in & 0xff00)) << 1; - // Clear MSB arrays once before loop instead of inside loop - memset(odd_msbs, 0, MSB_LIMIT * sizeof(struct Msb)); - memset(even_msbs, 0, MSB_LIMIT * sizeof(struct Msb)); + // Clear MSB arrays once before loop instead of inside loop + memset(odd_msbs, 0, MSB_LIMIT * sizeof(struct Msb)); + memset(even_msbs, 0, MSB_LIMIT * sizeof(struct Msb)); - // Bit values to check - calculate once outside the loop - int oks_bit = oks & 1; - int eks_bit = eks & 1; + // Bit values to check - calculate once outside the loop + int oks_bit = oks & 1; + int eks_bit = eks & 1; - // Check for stop request less frequently - int sync_check_interval = 32768 * 2; // Doubled the interval + // Check for stop request less frequently + int sync_check_interval = 32768 * 2; // Doubled the interval - for (semi_state = 1 << 20; semi_state >= 0; semi_state--) - { - if (semi_state % sync_check_interval == 0) - { - if (sync_state(program_state) == 1) - { - return 0; - } - } + for(semi_state = 1 << 20; semi_state >= 0; semi_state--) { + if(semi_state % sync_check_interval == 0) { + if(sync_state(program_state) == 1) { + return 0; + } + } - // Process both filter conditions in one pass when possible - int filter_semi_state = filter(semi_state); + // Process both filter conditions in one pass when possible + int filter_semi_state = filter(semi_state); - // Check oks condition - if (filter_semi_state == oks_bit) - { - states_buffer[0] = semi_state; - states_tail = state_loop(states_buffer, oks, CONST_M1_1, CONST_M2_1, 0, 0); + // Check oks condition + if(filter_semi_state == oks_bit) { + states_buffer[0] = semi_state; + states_tail = state_loop(states_buffer, oks, CONST_M1_1, CONST_M2_1, 0, 0); - for (int i = states_tail; i >= 0; i--) - { - msb = states_buffer[i] >> 24; - if ((msb >= msb_head) && (msb < msb_tail)) - { - // Calculate index once - int msb_idx = msb - msb_head; + for(int i = states_tail; i >= 0; i--) { + msb = states_buffer[i] >> 24; + if((msb >= msb_head) && (msb < msb_tail)) { + // Calculate index once + int msb_idx = msb - msb_head; - // Avoid sequential scan by using a direct flag - int found = 0; - for (int j = 0; j < odd_msbs[msb_idx].tail; j++) - { - if (odd_msbs[msb_idx].states[j] == states_buffer[i]) - { - found = 1; - break; - } - } + // Avoid sequential scan by using a direct flag + int found = 0; + for(int j = 0; j < odd_msbs[msb_idx].tail; j++) { + if(odd_msbs[msb_idx].states[j] == states_buffer[i]) { + found = 1; + break; + } + } - if (!found) - { - int tail = odd_msbs[msb_idx].tail++; - odd_msbs[msb_idx].states[tail] = states_buffer[i]; - } - } - } - } + if(!found) { + int tail = odd_msbs[msb_idx].tail++; + odd_msbs[msb_idx].states[tail] = states_buffer[i]; + } + } + } + } - // Check eks condition - if (filter_semi_state == eks_bit) - { - states_buffer[0] = semi_state; - states_tail = state_loop(states_buffer, eks, CONST_M1_2, CONST_M2_2, in, 3); + // Check eks condition + if(filter_semi_state == eks_bit) { + states_buffer[0] = semi_state; + states_tail = state_loop(states_buffer, eks, CONST_M1_2, CONST_M2_2, in, 3); - for (int i = 0; i <= states_tail; i++) - { - msb = states_buffer[i] >> 24; - if ((msb >= msb_head) && (msb < msb_tail)) - { - // Calculate index once - int msb_idx = msb - msb_head; + for(int i = 0; i <= states_tail; i++) { + msb = states_buffer[i] >> 24; + if((msb >= msb_head) && (msb < msb_tail)) { + // Calculate index once + int msb_idx = msb - msb_head; - // Avoid sequential scan - int found = 0; - for (int j = 0; j < even_msbs[msb_idx].tail; j++) - { - if (even_msbs[msb_idx].states[j] == states_buffer[i]) - { - found = 1; - break; - } - } + // Avoid sequential scan + int found = 0; + for(int j = 0; j < even_msbs[msb_idx].tail; j++) { + if(even_msbs[msb_idx].states[j] == states_buffer[i]) { + found = 1; + break; + } + } - if (!found) - { - int tail = even_msbs[msb_idx].tail++; - even_msbs[msb_idx].states[tail] = states_buffer[i]; - } - } - } - } - } + if(!found) { + int tail = even_msbs[msb_idx].tail++; + even_msbs[msb_idx].states[tail] = states_buffer[i]; + } + } + } + } + } - // Shift once outside the loop - oks >>= 12; - eks >>= 12; + // Shift once outside the loop + oks >>= 12; + eks >>= 12; - // Process results - for (int i = 0; i < MSB_LIMIT; i++) - { - if ((i % 4) == 0 && sync_state(program_state) == 1) - { - return 0; - } + // Process results + for(int i = 0; i < MSB_LIMIT; i++) { + if((i % 4) == 0 && sync_state(program_state) == 1) { + return 0; + } - // Only clear buffers if they're going to be used - if (odd_msbs[i].tail > 0 || even_msbs[i].tail > 0) - { - memset(temp_states_even, 0, sizeof(unsigned int) * (1280)); - memset(temp_states_odd, 0, sizeof(unsigned int) * (1280)); - memcpy(temp_states_odd, odd_msbs[i].states, odd_msbs[i].tail * sizeof(unsigned int)); - memcpy(temp_states_even, even_msbs[i].states, even_msbs[i].tail * sizeof(unsigned int)); + // Only clear buffers if they're going to be used + if(odd_msbs[i].tail > 0 || even_msbs[i].tail > 0) { + memset(temp_states_even, 0, sizeof(unsigned int) * (1280)); + memset(temp_states_odd, 0, sizeof(unsigned int) * (1280)); + memcpy(temp_states_odd, odd_msbs[i].states, odd_msbs[i].tail * sizeof(unsigned int)); + memcpy( + temp_states_even, even_msbs[i].states, even_msbs[i].tail * sizeof(unsigned int)); - int res = old_recover( - temp_states_odd, - 0, - odd_msbs[i].tail, - oks, - temp_states_even, - 0, - even_msbs[i].tail, - eks, - 3, - 0, - n, - in >> 16, - 1, - program_state); + int res = old_recover( + temp_states_odd, + 0, + odd_msbs[i].tail, + oks, + temp_states_even, + 0, + even_msbs[i].tail, + eks, + 3, + 0, + n, + in >> 16, + 1, + program_state); - if (res == -1) - { - return 1; - } - } - } + if(res == -1) { + return 1; + } + } + } - return 0; + return 0; } -void **allocate_blocks(const size_t *block_sizes, int num_blocks) -{ - void **block_pointers = malloc(num_blocks * sizeof(void *)); - if (!block_pointers) - { - return NULL; - } +void** allocate_blocks(const size_t* block_sizes, int num_blocks) { + void** block_pointers = malloc(num_blocks * sizeof(void*)); + if(!block_pointers) { + return NULL; + } - for (int i = 0; i < num_blocks; i++) - { - if (memmgr_heap_get_max_free_block() < block_sizes[i]) - { - // Not enough memory, free previously allocated blocks - for (int j = 0; j < i; j++) - { - free(block_pointers[j]); - } - free(block_pointers); - return NULL; - } + for(int i = 0; i < num_blocks; i++) { + if(memmgr_heap_get_max_free_block() < block_sizes[i]) { + // Not enough memory, free previously allocated blocks + for(int j = 0; j < i; j++) { + free(block_pointers[j]); + } + free(block_pointers); + return NULL; + } - block_pointers[i] = malloc(block_sizes[i]); - if (!block_pointers[i]) - { - // Allocation failed - for (int j = 0; j < i; j++) - { - free(block_pointers[j]); - } - free(block_pointers); - return NULL; - } - } + block_pointers[i] = malloc(block_sizes[i]); + if(!block_pointers[i]) { + // Allocation failed + for(int j = 0; j < i; j++) { + free(block_pointers[j]); + } + free(block_pointers); + return NULL; + } + } - return block_pointers; + return block_pointers; } -bool recover(MfClassicNonce *n, int ks2, unsigned int in, ProgramState *program_state) -{ - bool found = false; - const size_t block_sizes[] = {49216, 49216, 5120, 5120, 4096}; - const size_t reduced_block_sizes[] = {24608, 24608, 5120, 5120, 4096}; - const int num_blocks = sizeof(block_sizes) / sizeof(block_sizes[0]); - // Reset globals each nonce - eta_round_time = 44; +bool recover(MfClassicNonce* n, int ks2, unsigned int in, ProgramState* program_state) { + bool found = false; + const size_t block_sizes[] = {49216, 49216, 5120, 5120, 4096}; + const size_t reduced_block_sizes[] = {24608, 24608, 5120, 5120, 4096}; + const int num_blocks = sizeof(block_sizes) / sizeof(block_sizes[0]); + // Reset globals each nonce + eta_round_time = 44; eta_total_time = 705; - MSB_LIMIT = 16; - - // Use half speed (reduced block sizes) for static encrypted nonces so we can buffer keys - bool use_half_speed = (n->attack == static_encrypted); - if (use_half_speed) - { - //eta_round_time *= 2; - eta_total_time *= 2; - MSB_LIMIT /= 2; - } + MSB_LIMIT = 16; - void **block_pointers = allocate_blocks(use_half_speed ? reduced_block_sizes : block_sizes, num_blocks); - if (block_pointers == NULL) { - if (n->attack != static_encrypted) - { - // System has less than the guaranteed amount of RAM (140 KB) - adjust some parameters to run anyway at half speed - // eta_round_time *= 2; - eta_total_time *= 2; - MSB_LIMIT /= 2; - block_pointers = allocate_blocks(reduced_block_sizes, num_blocks); - if (block_pointers == NULL) - { - // System has less than 70 KB of RAM - should never happen so we don't reduce speed further - program_state->err = InsufficientRAM; - program_state->mfkey_state = Error; - return false; - } - } else - { - program_state->err = InsufficientRAM; - program_state->mfkey_state = Error; - return false; - } - } - struct Msb *odd_msbs = block_pointers[0]; - struct Msb *even_msbs = block_pointers[1]; - unsigned int *temp_states_odd = block_pointers[2]; - unsigned int *temp_states_even = block_pointers[3]; - unsigned int *states_buffer = block_pointers[4]; + // Use half speed (reduced block sizes) for static encrypted nonces so we can buffer keys + bool use_half_speed = (n->attack == static_encrypted); + if(use_half_speed) { + //eta_round_time *= 2; + eta_total_time *= 2; + MSB_LIMIT /= 2; + } - // Allocate key buffer for static encrypted nonces - if (n->attack == static_encrypted) - { - size_t available_ram = memmgr_heap_get_max_free_block(); - // Each key becomes 12 hex chars + 1 newline = 13 bytes in the batch string - // Plus original 6 bytes in buffer = 19 bytes total per key - // Add extra safety margin for string overhead and other allocations - const size_t safety_threshold = STATIC_ENCRYPTED_RAM_THRESHOLD; - const size_t bytes_per_key = sizeof(MfClassicKey) + 13; // buffer + string representation - if (available_ram > safety_threshold) - { - program_state->key_buffer_size = (available_ram - safety_threshold) / bytes_per_key; - program_state->key_buffer = malloc(program_state->key_buffer_size * sizeof(MfClassicKey)); - program_state->key_buffer_count = 0; - if (!program_state->key_buffer) - { - // Free the allocated blocks before returning - for (int i = 0; i < num_blocks; i++) - { - free(block_pointers[i]); - } - free(block_pointers); - program_state->err = InsufficientRAM; - program_state->mfkey_state = Error; - return false; - } - } - else - { - // Free the allocated blocks before returning - for (int i = 0; i < num_blocks; i++) - { - free(block_pointers[i]); - } - free(block_pointers); - program_state->err = InsufficientRAM; - program_state->mfkey_state = Error; - return false; - } - } - else - { - program_state->key_buffer = NULL; - program_state->key_buffer_size = 0; - program_state->key_buffer_count = 0; - } + void** block_pointers = + allocate_blocks(use_half_speed ? reduced_block_sizes : block_sizes, num_blocks); + if(block_pointers == NULL) { + if(n->attack != static_encrypted) { + // System has less than the guaranteed amount of RAM (140 KB) - adjust some parameters to run anyway at half speed + // eta_round_time *= 2; + eta_total_time *= 2; + MSB_LIMIT /= 2; + block_pointers = allocate_blocks(reduced_block_sizes, num_blocks); + if(block_pointers == NULL) { + // System has less than 70 KB of RAM - should never happen so we don't reduce speed further + program_state->err = InsufficientRAM; + program_state->mfkey_state = Error; + return false; + } + } else { + program_state->err = InsufficientRAM; + program_state->mfkey_state = Error; + return false; + } + } + struct Msb* odd_msbs = block_pointers[0]; + struct Msb* even_msbs = block_pointers[1]; + unsigned int* temp_states_odd = block_pointers[2]; + unsigned int* temp_states_even = block_pointers[3]; + unsigned int* states_buffer = block_pointers[4]; - int oks = 0, eks = 0; - int i = 0, msb = 0; - for (i = 31; i >= 0; i -= 2) - { - oks = oks << 1 | BEBIT(ks2, i); - } - for (i = 30; i >= 0; i -= 2) - { - eks = eks << 1 | BEBIT(ks2, i); - } - int bench_start = furi_hal_rtc_get_timestamp(); - program_state->eta_total = eta_total_time; - program_state->eta_timestamp = bench_start; - for (msb = 0; msb <= ((256 / MSB_LIMIT) - 1); msb++) - { - program_state->search = msb; - program_state->eta_round = eta_round_time; - program_state->eta_total = eta_total_time - (eta_round_time * msb); - if (calculate_msb_tables( - oks, - eks, - msb, - n, - states_buffer, - odd_msbs, - even_msbs, - temp_states_odd, - temp_states_even, - in, - program_state)) - { - // int bench_stop = furi_hal_rtc_get_timestamp(); - // FURI_LOG_I(TAG, "Cracked in %i seconds", bench_stop - bench_start); - found = true; - break; - } - if (program_state->close_thread_please) - { - break; - } - } + // Allocate key buffer for static encrypted nonces + if(n->attack == static_encrypted) { + size_t available_ram = memmgr_heap_get_max_free_block(); + // Each key becomes 12 hex chars + 1 newline = 13 bytes in the batch string + // Plus original 6 bytes in buffer = 19 bytes total per key + // Add extra safety margin for string overhead and other allocations + const size_t safety_threshold = STATIC_ENCRYPTED_RAM_THRESHOLD; + const size_t bytes_per_key = sizeof(MfClassicKey) + 13; // buffer + string representation + if(available_ram > safety_threshold) { + program_state->key_buffer_size = (available_ram - safety_threshold) / bytes_per_key; + program_state->key_buffer = + malloc(program_state->key_buffer_size * sizeof(MfClassicKey)); + program_state->key_buffer_count = 0; + if(!program_state->key_buffer) { + // Free the allocated blocks before returning + for(int i = 0; i < num_blocks; i++) { + free(block_pointers[i]); + } + free(block_pointers); + program_state->err = InsufficientRAM; + program_state->mfkey_state = Error; + return false; + } + } else { + // Free the allocated blocks before returning + for(int i = 0; i < num_blocks; i++) { + free(block_pointers[i]); + } + free(block_pointers); + program_state->err = InsufficientRAM; + program_state->mfkey_state = Error; + return false; + } + } else { + program_state->key_buffer = NULL; + program_state->key_buffer_size = 0; + program_state->key_buffer_count = 0; + } - // Final flush and cleanup for key buffer - if (n->attack == static_encrypted && program_state->key_buffer) - { - flush_key_buffer(program_state); - free(program_state->key_buffer); - program_state->key_buffer = NULL; - program_state->key_buffer_size = 0; - program_state->key_buffer_count = 0; - } + int oks = 0, eks = 0; + int i = 0, msb = 0; + for(i = 31; i >= 0; i -= 2) { + oks = oks << 1 | BEBIT(ks2, i); + } + for(i = 30; i >= 0; i -= 2) { + eks = eks << 1 | BEBIT(ks2, i); + } + int bench_start = furi_hal_rtc_get_timestamp(); + program_state->eta_total = eta_total_time; + program_state->eta_timestamp = bench_start; + for(msb = 0; msb <= ((256 / MSB_LIMIT) - 1); msb++) { + program_state->search = msb; + program_state->eta_round = eta_round_time; + program_state->eta_total = eta_total_time - (eta_round_time * msb); + if(calculate_msb_tables( + oks, + eks, + msb, + n, + states_buffer, + odd_msbs, + even_msbs, + temp_states_odd, + temp_states_even, + in, + program_state)) { + // int bench_stop = furi_hal_rtc_get_timestamp(); + // FURI_LOG_I(TAG, "Cracked in %i seconds", bench_stop - bench_start); + found = true; + break; + } + if(program_state->close_thread_please) { + break; + } + } - // Free the allocated blocks - for (int i = 0; i < num_blocks; i++) - { - free(block_pointers[i]); - } - free(block_pointers); - return found; + // Final flush and cleanup for key buffer + if(n->attack == static_encrypted && program_state->key_buffer) { + flush_key_buffer(program_state); + free(program_state->key_buffer); + program_state->key_buffer = NULL; + program_state->key_buffer_size = 0; + program_state->key_buffer_count = 0; + } + + // Free the allocated blocks + for(int i = 0; i < num_blocks; i++) { + free(block_pointers[i]); + } + free(block_pointers); + return found; } bool key_already_found_for_nonce_in_solved( - MfClassicKey *keyarray, - int keyarray_size, - MfClassicNonce *nonce) -{ - for (int k = 0; k < keyarray_size; k++) - { - uint64_t key_as_int = bit_lib_bytes_to_num_be(keyarray[k].data, sizeof(MfClassicKey)); - struct Crypto1State temp = {0, 0}; - for (int i = 0; i < 24; i++) - { - (&temp)->odd |= (BIT(key_as_int, 2 * i + 1) << (i ^ 3)); - (&temp)->even |= (BIT(key_as_int, 2 * i) << (i ^ 3)); - } - if (nonce->attack == mfkey32) - { - crypt_word_noret(&temp, nonce->uid_xor_nt1, 0); - crypt_word_noret(&temp, nonce->nr1_enc, 1); - if (nonce->ar1_enc == (crypt_word(&temp) ^ nonce->p64b)) - { - return true; - } - } - else if (nonce->attack == static_nested) - { - uint32_t expected_ks1 = crypt_word_ret(&temp, nonce->uid_xor_nt0, 0); - if (nonce->ks1_1_enc == expected_ks1) - { - return true; - } - } - } - return false; + MfClassicKey* keyarray, + int keyarray_size, + MfClassicNonce* nonce) { + for(int k = 0; k < keyarray_size; k++) { + uint64_t key_as_int = bit_lib_bytes_to_num_be(keyarray[k].data, sizeof(MfClassicKey)); + struct Crypto1State temp = {0, 0}; + for(int i = 0; i < 24; i++) { + (&temp)->odd |= (BIT(key_as_int, 2 * i + 1) << (i ^ 3)); + (&temp)->even |= (BIT(key_as_int, 2 * i) << (i ^ 3)); + } + if(nonce->attack == mfkey32) { + crypt_word_noret(&temp, nonce->uid_xor_nt1, 0); + crypt_word_noret(&temp, nonce->nr1_enc, 1); + if(nonce->ar1_enc == (crypt_word(&temp) ^ nonce->p64b)) { + return true; + } + } else if(nonce->attack == static_nested) { + uint32_t expected_ks1 = crypt_word_ret(&temp, nonce->uid_xor_nt0, 0); + if(nonce->ks1_1_enc == expected_ks1) { + return true; + } + } + } + return false; } #pragma GCC push_options #pragma GCC optimize("Os") -static void finished_beep() -{ - // Beep to indicate completion - NotificationApp *notification = furi_record_open("notification"); - notification_message(notification, &sequence_audiovisual_alert); - notification_message(notification, &sequence_display_backlight_on); - furi_record_close("notification"); +static void finished_beep() { + // Beep to indicate completion + NotificationApp* notification = furi_record_open("notification"); + notification_message(notification, &sequence_audiovisual_alert); + notification_message(notification, &sequence_display_backlight_on); + furi_record_close("notification"); } -void mfkey(ProgramState *program_state) -{ - uint32_t ks_enc = 0, nt_xor_uid = 0; - MfClassicKey found_key; // Recovered key - size_t keyarray_size = 0; - MfClassicKey *keyarray = malloc(sizeof(MfClassicKey) * 1); - if (!keyarray) - { - program_state->err = InsufficientRAM; - program_state->mfkey_state = Error; - return; - } +void mfkey(ProgramState* program_state) { + uint32_t ks_enc = 0, nt_xor_uid = 0; + MfClassicKey found_key; // Recovered key + size_t keyarray_size = 0; + MfClassicKey* keyarray = malloc(sizeof(MfClassicKey) * 1); + if(!keyarray) { + program_state->err = InsufficientRAM; + program_state->mfkey_state = Error; + return; + } - uint32_t i = 0, j = 0; - // FURI_LOG_I(TAG, "Free heap before alloc(): %zub", memmgr_get_free_heap()); - Storage *storage = furi_record_open(RECORD_STORAGE); - FlipperApplication *app = flipper_application_alloc(storage, firmware_api_interface); - flipper_application_preload(app, APP_ASSETS_PATH("plugins/mfkey_init_plugin.fal")); - flipper_application_map_to_memory(app); - const FlipperAppPluginDescriptor *app_descriptor = - flipper_application_plugin_get_descriptor(app); - const MfkeyPlugin *init_plugin = app_descriptor->entry_point; - // Check for nonces - program_state->mfkey32_present = init_plugin->napi_mf_classic_mfkey32_nonces_check_presence(); - program_state->nested_present = init_plugin->napi_mf_classic_nested_nonces_check_presence(); - if (!(program_state->mfkey32_present) && !(program_state->nested_present)) - { - program_state->err = MissingNonces; - program_state->mfkey_state = Error; - flipper_application_free(app); - furi_record_close(RECORD_STORAGE); - free(keyarray); - return; - } - // Read dictionaries (optional) - KeysDict *system_dict = {0}; - bool system_dict_exists = keys_dict_check_presence(KEYS_DICT_SYSTEM_PATH); - KeysDict *user_dict = {0}; - bool user_dict_exists = keys_dict_check_presence(KEYS_DICT_USER_PATH); - uint32_t total_dict_keys = 0; - if (system_dict_exists) - { - system_dict = - keys_dict_alloc(KEYS_DICT_SYSTEM_PATH, KeysDictModeOpenExisting, sizeof(MfClassicKey)); - total_dict_keys += keys_dict_get_total_keys(system_dict); - } - user_dict = keys_dict_alloc(KEYS_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey)); - if (user_dict_exists) - { - total_dict_keys += keys_dict_get_total_keys(user_dict); - } - user_dict_exists = true; - program_state->dict_count = total_dict_keys; - program_state->mfkey_state = DictionaryAttack; - // Read nonces - MfClassicNonceArray *nonce_arr; - nonce_arr = init_plugin->napi_mf_classic_nonce_array_alloc( - system_dict, system_dict_exists, user_dict, program_state); - if (system_dict_exists) - { - keys_dict_free(system_dict); - } - if (nonce_arr->total_nonces == 0) - { - // Nothing to crack - program_state->err = ZeroNonces; - program_state->mfkey_state = Error; - init_plugin->napi_mf_classic_nonce_array_free(nonce_arr); - flipper_application_free(app); - furi_record_close(RECORD_STORAGE); - keys_dict_free(user_dict); - free(keyarray); - return; - } - flipper_application_free(app); - furi_record_close(RECORD_STORAGE); - // TODO: Track free state at the time this is called to ensure double free does not happen - furi_assert(nonce_arr); - furi_assert(nonce_arr->stream); - // TODO: Already closed? - buffered_file_stream_close(nonce_arr->stream); - stream_free(nonce_arr->stream); - // FURI_LOG_I(TAG, "Free heap after free(): %zub", memmgr_get_free_heap()); - program_state->mfkey_state = MFKeyAttack; - // TODO: Work backwards on this array and free memory - for (i = 0; i < nonce_arr->total_nonces; i++) - { - MfClassicNonce next_nonce = nonce_arr->remaining_nonce_array[i]; - if (key_already_found_for_nonce_in_solved(keyarray, keyarray_size, &next_nonce)) - { - nonce_arr->remaining_nonces--; - (program_state->cracked)++; - (program_state->num_completed)++; - continue; - } - // FURI_LOG_I(TAG, "Beginning recovery for %8lx", next_nonce.uid); - FuriString *cuid_dict_path; - switch (next_nonce.attack) - { - case mfkey32: - ks_enc = next_nonce.ar0_enc ^ next_nonce.p64; - nt_xor_uid = 0; - break; - case static_nested: - ks_enc = next_nonce.ks1_2_enc; - nt_xor_uid = next_nonce.uid_xor_nt1; - break; - case static_encrypted: - ks_enc = next_nonce.ks1_1_enc; - nt_xor_uid = next_nonce.uid_xor_nt0; - cuid_dict_path = furi_string_alloc_printf( - "%s/mf_classic_dict_%08lx.nfc", EXT_PATH("nfc/assets"), next_nonce.uid); - // May need RECORD_STORAGE? - program_state->cuid_dict = keys_dict_alloc( - furi_string_get_cstr(cuid_dict_path), - KeysDictModeOpenAlways, - sizeof(MfClassicKey)); - furi_string_free(cuid_dict_path); - break; - } + uint32_t i = 0, j = 0; + // FURI_LOG_I(TAG, "Free heap before alloc(): %zub", memmgr_get_free_heap()); + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperApplication* app = flipper_application_alloc(storage, firmware_api_interface); + flipper_application_preload(app, APP_ASSETS_PATH("plugins/mfkey_init_plugin.fal")); + flipper_application_map_to_memory(app); + const FlipperAppPluginDescriptor* app_descriptor = + flipper_application_plugin_get_descriptor(app); + const MfkeyPlugin* init_plugin = app_descriptor->entry_point; + // Check for nonces + program_state->mfkey32_present = init_plugin->napi_mf_classic_mfkey32_nonces_check_presence(); + program_state->nested_present = init_plugin->napi_mf_classic_nested_nonces_check_presence(); + if(!(program_state->mfkey32_present) && !(program_state->nested_present)) { + program_state->err = MissingNonces; + program_state->mfkey_state = Error; + flipper_application_free(app); + furi_record_close(RECORD_STORAGE); + free(keyarray); + return; + } + // Read dictionaries (optional) + KeysDict* system_dict = {0}; + bool system_dict_exists = keys_dict_check_presence(KEYS_DICT_SYSTEM_PATH); + KeysDict* user_dict = {0}; + bool user_dict_exists = keys_dict_check_presence(KEYS_DICT_USER_PATH); + uint32_t total_dict_keys = 0; + if(system_dict_exists) { + system_dict = + keys_dict_alloc(KEYS_DICT_SYSTEM_PATH, KeysDictModeOpenExisting, sizeof(MfClassicKey)); + total_dict_keys += keys_dict_get_total_keys(system_dict); + } + user_dict = keys_dict_alloc(KEYS_DICT_USER_PATH, KeysDictModeOpenAlways, sizeof(MfClassicKey)); + if(user_dict_exists) { + total_dict_keys += keys_dict_get_total_keys(user_dict); + } + user_dict_exists = true; + program_state->dict_count = total_dict_keys; + program_state->mfkey_state = DictionaryAttack; + // Read nonces + MfClassicNonceArray* nonce_arr; + nonce_arr = init_plugin->napi_mf_classic_nonce_array_alloc( + system_dict, system_dict_exists, user_dict, program_state); + if(system_dict_exists) { + keys_dict_free(system_dict); + } + if(nonce_arr->total_nonces == 0) { + // Nothing to crack + program_state->err = ZeroNonces; + program_state->mfkey_state = Error; + init_plugin->napi_mf_classic_nonce_array_free(nonce_arr); + flipper_application_free(app); + furi_record_close(RECORD_STORAGE); + keys_dict_free(user_dict); + free(keyarray); + return; + } + flipper_application_free(app); + furi_record_close(RECORD_STORAGE); + // TODO: Track free state at the time this is called to ensure double free does not happen + furi_assert(nonce_arr); + furi_assert(nonce_arr->stream); + // TODO: Already closed? + buffered_file_stream_close(nonce_arr->stream); + stream_free(nonce_arr->stream); + // FURI_LOG_I(TAG, "Free heap after free(): %zub", memmgr_get_free_heap()); + program_state->mfkey_state = MFKeyAttack; + // TODO: Work backwards on this array and free memory + for(i = 0; i < nonce_arr->total_nonces; i++) { + MfClassicNonce next_nonce = nonce_arr->remaining_nonce_array[i]; + if(key_already_found_for_nonce_in_solved(keyarray, keyarray_size, &next_nonce)) { + nonce_arr->remaining_nonces--; + (program_state->cracked)++; + (program_state->num_completed)++; + continue; + } + // FURI_LOG_I(TAG, "Beginning recovery for %8lx", next_nonce.uid); + FuriString* cuid_dict_path; + switch(next_nonce.attack) { + case mfkey32: + ks_enc = next_nonce.ar0_enc ^ next_nonce.p64; + nt_xor_uid = 0; + break; + case static_nested: + ks_enc = next_nonce.ks1_2_enc; + nt_xor_uid = next_nonce.uid_xor_nt1; + break; + case static_encrypted: + ks_enc = next_nonce.ks1_1_enc; + nt_xor_uid = next_nonce.uid_xor_nt0; + cuid_dict_path = furi_string_alloc_printf( + "%s/mf_classic_dict_%08lx.nfc", EXT_PATH("nfc/assets"), next_nonce.uid); + // May need RECORD_STORAGE? + program_state->cuid_dict = keys_dict_alloc( + furi_string_get_cstr(cuid_dict_path), + KeysDictModeOpenAlways, + sizeof(MfClassicKey)); + furi_string_free(cuid_dict_path); + break; + } - if (!recover(&next_nonce, ks_enc, nt_xor_uid, program_state)) - { - // Check for non-recoverable errors and break the loop - if (program_state->mfkey_state == Error) - { - if ((next_nonce.attack == static_encrypted) && (program_state->cuid_dict)) - { - keys_dict_free(program_state->cuid_dict); - program_state->cuid_dict = NULL; - } - break; - } - if (program_state->close_thread_please) - { - if ((next_nonce.attack == static_encrypted) && (program_state->cuid_dict)) - { - keys_dict_free(program_state->cuid_dict); - program_state->cuid_dict = NULL; - } - break; - } - // No key found in recover() or static encrypted - (program_state->num_completed)++; - // Free CUID dictionary after each static_encrypted nonce processing - if ((next_nonce.attack == static_encrypted) && (program_state->cuid_dict)) - { - keys_dict_free(program_state->cuid_dict); - program_state->cuid_dict = NULL; - } - continue; - } - (program_state->cracked)++; - (program_state->num_completed)++; - found_key = next_nonce.key; - bool already_found = false; - for (j = 0; j < keyarray_size; j++) - { - if (memcmp(keyarray[j].data, found_key.data, MF_CLASSIC_KEY_SIZE) == 0) - { - already_found = true; - break; - } - } - if (already_found == false) - { - // New key - MfClassicKey *new_keyarray = realloc(keyarray, sizeof(MfClassicKey) * (keyarray_size + 1)); - if (!new_keyarray) - { - // Realloc failed - continue with existing keyarray - FURI_LOG_E(TAG, "Failed to realloc keyarray"); - } - else - { - keyarray = new_keyarray; - keyarray_size += 1; - keyarray[keyarray_size - 1] = found_key; - (program_state->unique_cracked)++; - } - } - } - // TODO: Update display to show all keys were found - // TODO: Prepend found key(s) to user dictionary file - // FURI_LOG_I(TAG, "Unique keys found:"); - for (i = 0; i < keyarray_size; i++) - { - // FURI_LOG_I(TAG, "%012" PRIx64, keyarray[i]); - keys_dict_add_key(user_dict, keyarray[i].data, sizeof(MfClassicKey)); - } - if (keyarray_size > 0) - { - dolphin_deed(DolphinDeedNfcKeyAdd); - } - free(nonce_arr); - keys_dict_free(user_dict); - free(keyarray); - if (program_state->mfkey_state == Error) - { - return; - } - // FURI_LOG_I(TAG, "mfkey function completed normally"); // DEBUG - program_state->mfkey_state = Complete; - // No need to alert the user if they asked it to stop - if (!(program_state->close_thread_please)) - { - finished_beep(); - } - return; + if(!recover(&next_nonce, ks_enc, nt_xor_uid, program_state)) { + // Check for non-recoverable errors and break the loop + if(program_state->mfkey_state == Error) { + if((next_nonce.attack == static_encrypted) && (program_state->cuid_dict)) { + keys_dict_free(program_state->cuid_dict); + program_state->cuid_dict = NULL; + } + break; + } + if(program_state->close_thread_please) { + if((next_nonce.attack == static_encrypted) && (program_state->cuid_dict)) { + keys_dict_free(program_state->cuid_dict); + program_state->cuid_dict = NULL; + } + break; + } + // No key found in recover() or static encrypted + (program_state->num_completed)++; + // Free CUID dictionary after each static_encrypted nonce processing + if((next_nonce.attack == static_encrypted) && (program_state->cuid_dict)) { + keys_dict_free(program_state->cuid_dict); + program_state->cuid_dict = NULL; + } + continue; + } + (program_state->cracked)++; + (program_state->num_completed)++; + found_key = next_nonce.key; + bool already_found = false; + for(j = 0; j < keyarray_size; j++) { + if(memcmp(keyarray[j].data, found_key.data, MF_CLASSIC_KEY_SIZE) == 0) { + already_found = true; + break; + } + } + if(already_found == false) { + // New key + MfClassicKey* new_keyarray = + realloc(keyarray, sizeof(MfClassicKey) * (keyarray_size + 1)); + if(!new_keyarray) { + // Realloc failed - continue with existing keyarray + FURI_LOG_E(TAG, "Failed to realloc keyarray"); + } else { + keyarray = new_keyarray; + keyarray_size += 1; + keyarray[keyarray_size - 1] = found_key; + (program_state->unique_cracked)++; + } + } + } + // TODO: Update display to show all keys were found + // TODO: Prepend found key(s) to user dictionary file + // FURI_LOG_I(TAG, "Unique keys found:"); + for(i = 0; i < keyarray_size; i++) { + // FURI_LOG_I(TAG, "%012" PRIx64, keyarray[i]); + keys_dict_add_key(user_dict, keyarray[i].data, sizeof(MfClassicKey)); + } + if(keyarray_size > 0) { + dolphin_deed(DolphinDeedNfcKeyAdd); + } + free(nonce_arr); + keys_dict_free(user_dict); + free(keyarray); + if(program_state->mfkey_state == Error) { + return; + } + // FURI_LOG_I(TAG, "mfkey function completed normally"); // DEBUG + program_state->mfkey_state = Complete; + // No need to alert the user if they asked it to stop + if(!(program_state->close_thread_please)) { + finished_beep(); + } + return; } // Screen is 128x64 px -static void render_callback(Canvas *const canvas, void *ctx) -{ - furi_assert(ctx); - ProgramState *program_state = ctx; - furi_mutex_acquire(program_state->mutex, FuriWaitForever); - char draw_str[44] = {}; +static void render_callback(Canvas* const canvas, void* ctx) { + furi_assert(ctx); + ProgramState* program_state = ctx; + furi_mutex_acquire(program_state->mutex, FuriWaitForever); + char draw_str[44] = {}; - canvas_draw_frame(canvas, 0, 0, 128, 64); - canvas_draw_frame(canvas, 0, 15, 128, 64); + canvas_draw_frame(canvas, 0, 0, 128, 64); + canvas_draw_frame(canvas, 0, 15, 128, 64); - // FontSecondary by default, title is drawn at the end - snprintf(draw_str, sizeof(draw_str), "RAM: %zub", memmgr_get_free_heap()); - canvas_draw_str_aligned(canvas, 48, 5, AlignLeft, AlignTop, draw_str); - canvas_draw_icon(canvas, 114, 4, &I_mfkey); - if (program_state->mfkey_state == MFKeyAttack) - { - float eta_round = (float)1 - ((float)program_state->eta_round / (float)eta_round_time); - float eta_total = (float)1 - ((float)program_state->eta_total / (float)eta_total_time); - float progress = (float)program_state->num_completed / (float)program_state->total; - if (eta_round < 0 || eta_round > 1) - { - // Round ETA miscalculated - eta_round = 1; - program_state->eta_round = 0; - } - if (eta_total < 0 || eta_round > 1) - { - // Total ETA miscalculated - eta_total = 1; - program_state->eta_total = 0; - } - snprintf( - draw_str, - sizeof(draw_str), - "Cracking: %d/%d - in prog.", - program_state->num_completed, - program_state->total); - elements_progress_bar_with_text(canvas, 5, 18, 118, progress, draw_str); - snprintf( - draw_str, - sizeof(draw_str), - "Round: %d/%d - ETA %02d Sec", - (program_state->search) + 1, // Zero indexed - 256 / MSB_LIMIT, - program_state->eta_round); - elements_progress_bar_with_text(canvas, 5, 31, 118, eta_round, draw_str); - snprintf(draw_str, sizeof(draw_str), "Total ETA %03d Sec", program_state->eta_total); - elements_progress_bar_with_text(canvas, 5, 44, 118, eta_total, draw_str); - } - else if (program_state->mfkey_state == DictionaryAttack) - { - snprintf( - draw_str, sizeof(draw_str), "Dict solves: %d (in progress)", program_state->cracked); - canvas_draw_str_aligned(canvas, 10, 18, AlignLeft, AlignTop, draw_str); - snprintf(draw_str, sizeof(draw_str), "Keys in dict: %d", program_state->dict_count); - canvas_draw_str_aligned(canvas, 26, 28, AlignLeft, AlignTop, draw_str); - } - else if (program_state->mfkey_state == Complete) - { - // TODO: Scrollable list view to see cracked keys if user presses down - elements_progress_bar(canvas, 5, 18, 118, 1); - canvas_draw_str_aligned(canvas, 64, 31, AlignCenter, AlignTop, "Complete"); - snprintf( - draw_str, - sizeof(draw_str), - "Keys added to user dict: %d", - program_state->unique_cracked); - canvas_draw_str_aligned(canvas, 64, 41, AlignCenter, AlignTop, draw_str); - if (program_state->num_candidates > 0) - { - snprintf( - draw_str, - sizeof(draw_str), - "SEN key candidates: %d", - program_state->num_candidates); - canvas_draw_str_aligned(canvas, 64, 51, AlignCenter, AlignTop, draw_str); - } - } - else if (program_state->mfkey_state == Ready) - { - canvas_draw_str_aligned(canvas, 50, 30, AlignLeft, AlignTop, "Ready"); - elements_button_center(canvas, "Start"); - elements_button_right(canvas, "Help"); - } - else if (program_state->mfkey_state == Help) - { - canvas_draw_str_aligned(canvas, 7, 20, AlignLeft, AlignTop, "Collect nonces by reading"); - canvas_draw_str_aligned(canvas, 7, 30, AlignLeft, AlignTop, "tag or reader in NFC app:"); - canvas_draw_str_aligned(canvas, 7, 40, AlignLeft, AlignTop, "https://docs.flipper.net/"); - canvas_draw_str_aligned(canvas, 7, 50, AlignLeft, AlignTop, "nfc/mfkey32"); - } - else if (program_state->mfkey_state == Error) - { - canvas_draw_str_aligned(canvas, 50, 25, AlignLeft, AlignTop, "Error"); - if (program_state->err == MissingNonces) - { - canvas_draw_str_aligned(canvas, 25, 36, AlignLeft, AlignTop, "No nonces found"); - } - else if (program_state->err == ZeroNonces) - { - canvas_draw_str_aligned(canvas, 15, 36, AlignLeft, AlignTop, "Nonces already cracked"); - } - else if (program_state->err == InsufficientRAM) - { - canvas_draw_str_aligned(canvas, 35, 36, AlignLeft, AlignTop, "No free RAM"); - } - else - { - // Unhandled error - } - } - else - { - // Unhandled program state - } - // Title - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 5, 4, AlignLeft, AlignTop, "MFKey"); - furi_mutex_release(program_state->mutex); + // FontSecondary by default, title is drawn at the end + snprintf(draw_str, sizeof(draw_str), "RAM: %zub", memmgr_get_free_heap()); + canvas_draw_str_aligned(canvas, 48, 5, AlignLeft, AlignTop, draw_str); + canvas_draw_icon(canvas, 114, 4, &I_mfkey); + if(program_state->mfkey_state == MFKeyAttack) { + float eta_round = (float)1 - ((float)program_state->eta_round / (float)eta_round_time); + float eta_total = (float)1 - ((float)program_state->eta_total / (float)eta_total_time); + float progress = (float)program_state->num_completed / (float)program_state->total; + if(eta_round < 0 || eta_round > 1) { + // Round ETA miscalculated + eta_round = 1; + program_state->eta_round = 0; + } + if(eta_total < 0 || eta_round > 1) { + // Total ETA miscalculated + eta_total = 1; + program_state->eta_total = 0; + } + snprintf( + draw_str, + sizeof(draw_str), + "Cracking: %d/%d - in prog.", + program_state->num_completed, + program_state->total); + elements_progress_bar_with_text(canvas, 5, 18, 118, progress, draw_str); + snprintf( + draw_str, + sizeof(draw_str), + "Round: %d/%d - ETA %02d Sec", + (program_state->search) + 1, // Zero indexed + 256 / MSB_LIMIT, + program_state->eta_round); + elements_progress_bar_with_text(canvas, 5, 31, 118, eta_round, draw_str); + snprintf(draw_str, sizeof(draw_str), "Total ETA %03d Sec", program_state->eta_total); + elements_progress_bar_with_text(canvas, 5, 44, 118, eta_total, draw_str); + } else if(program_state->mfkey_state == DictionaryAttack) { + snprintf( + draw_str, sizeof(draw_str), "Dict solves: %d (in progress)", program_state->cracked); + canvas_draw_str_aligned(canvas, 10, 18, AlignLeft, AlignTop, draw_str); + snprintf(draw_str, sizeof(draw_str), "Keys in dict: %d", program_state->dict_count); + canvas_draw_str_aligned(canvas, 26, 28, AlignLeft, AlignTop, draw_str); + } else if(program_state->mfkey_state == Complete) { + // TODO: Scrollable list view to see cracked keys if user presses down + elements_progress_bar(canvas, 5, 18, 118, 1); + canvas_draw_str_aligned(canvas, 64, 31, AlignCenter, AlignTop, "Complete"); + snprintf( + draw_str, + sizeof(draw_str), + "Keys added to user dict: %d", + program_state->unique_cracked); + canvas_draw_str_aligned(canvas, 64, 41, AlignCenter, AlignTop, draw_str); + if(program_state->num_candidates > 0) { + snprintf( + draw_str, + sizeof(draw_str), + "SEN key candidates: %d", + program_state->num_candidates); + canvas_draw_str_aligned(canvas, 64, 51, AlignCenter, AlignTop, draw_str); + } + } else if(program_state->mfkey_state == Ready) { + canvas_draw_str_aligned(canvas, 50, 30, AlignLeft, AlignTop, "Ready"); + elements_button_center(canvas, "Start"); + elements_button_right(canvas, "Help"); + } else if(program_state->mfkey_state == Help) { + canvas_draw_str_aligned(canvas, 7, 20, AlignLeft, AlignTop, "Collect nonces by reading"); + canvas_draw_str_aligned(canvas, 7, 30, AlignLeft, AlignTop, "tag or reader in NFC app:"); + canvas_draw_str_aligned(canvas, 7, 40, AlignLeft, AlignTop, "https://docs.flipper.net/"); + canvas_draw_str_aligned(canvas, 7, 50, AlignLeft, AlignTop, "nfc/mfkey32"); + } else if(program_state->mfkey_state == Error) { + canvas_draw_str_aligned(canvas, 50, 25, AlignLeft, AlignTop, "Error"); + if(program_state->err == MissingNonces) { + canvas_draw_str_aligned(canvas, 25, 36, AlignLeft, AlignTop, "No nonces found"); + } else if(program_state->err == ZeroNonces) { + canvas_draw_str_aligned(canvas, 15, 36, AlignLeft, AlignTop, "Nonces already cracked"); + } else if(program_state->err == InsufficientRAM) { + canvas_draw_str_aligned(canvas, 35, 36, AlignLeft, AlignTop, "No free RAM"); + } else { + // Unhandled error + } + } else { + // Unhandled program state + } + // Title + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 5, 4, AlignLeft, AlignTop, "MFKey"); + furi_mutex_release(program_state->mutex); } -static void input_callback(InputEvent *input_event, void *event_queue) -{ - furi_assert(event_queue); - furi_message_queue_put((FuriMessageQueue *)event_queue, input_event, FuriWaitForever); +static void input_callback(InputEvent* input_event, void* event_queue) { + furi_assert(event_queue); + furi_message_queue_put((FuriMessageQueue*)event_queue, input_event, FuriWaitForever); } -static void mfkey_state_init(ProgramState *program_state) -{ - program_state->mfkey_state = Ready; - program_state->cracked = 0; - program_state->unique_cracked = 0; - program_state->num_completed = 0; - program_state->num_candidates = 0; - program_state->total = 0; - program_state->dict_count = 0; +static void mfkey_state_init(ProgramState* program_state) { + program_state->mfkey_state = Ready; + program_state->cracked = 0; + program_state->unique_cracked = 0; + program_state->num_completed = 0; + program_state->num_candidates = 0; + program_state->total = 0; + program_state->dict_count = 0; } // Entrypoint for worker thread -static int32_t mfkey_worker_thread(void *ctx) -{ - ProgramState *program_state = ctx; - program_state->mfkey_state = Initializing; - mfkey(program_state); - return 0; +static int32_t mfkey_worker_thread(void* ctx) { + ProgramState* program_state = ctx; + program_state->mfkey_state = Initializing; + mfkey(program_state); + return 0; } -int32_t mfkey_main() -{ - FuriMessageQueue *event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); +int32_t mfkey_main() { + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); - ProgramState *program_state = malloc(sizeof(ProgramState)); + ProgramState* program_state = malloc(sizeof(ProgramState)); - mfkey_state_init(program_state); + mfkey_state_init(program_state); - program_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); + program_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - // Set system callbacks - ViewPort *view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, render_callback, program_state); - view_port_input_callback_set(view_port, input_callback, event_queue); + // Set system callbacks + ViewPort* view_port = view_port_alloc(); + view_port_draw_callback_set(view_port, render_callback, program_state); + view_port_input_callback_set(view_port, input_callback, event_queue); - // Open GUI and register view_port - Gui *gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); + // Open GUI and register view_port + Gui* gui = furi_record_open(RECORD_GUI); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); - program_state->mfkeythread = - furi_thread_alloc_ex("MFKeyWorker", 2048, mfkey_worker_thread, program_state); + program_state->mfkeythread = + furi_thread_alloc_ex("MFKeyWorker", 2048, mfkey_worker_thread, program_state); - InputEvent input_event; - for (bool main_loop = true; main_loop;) - { - FuriStatus event_status = furi_message_queue_get(event_queue, &input_event, 100); + InputEvent input_event; + for(bool main_loop = true; main_loop;) { + FuriStatus event_status = furi_message_queue_get(event_queue, &input_event, 100); - furi_mutex_acquire(program_state->mutex, FuriWaitForever); + furi_mutex_acquire(program_state->mutex, FuriWaitForever); - if (event_status == FuriStatusOk) - { - if (input_event.type == InputTypePress) - { - switch (input_event.key) - { - case InputKeyRight: - if (program_state->mfkey_state == Ready) - { - program_state->mfkey_state = Help; - } - break; - case InputKeyOk: - if (program_state->mfkey_state == Ready) - { - furi_thread_start(program_state->mfkeythread); - } - break; - case InputKeyBack: - if (program_state->mfkey_state == Help) - { - program_state->mfkey_state = Ready; - } - else - { - program_state->close_thread_please = true; - // Wait until thread is finished - furi_thread_join(program_state->mfkeythread); - main_loop = false; - } - break; - default: - break; - } - } - } + if(event_status == FuriStatusOk) { + if(input_event.type == InputTypePress) { + switch(input_event.key) { + case InputKeyRight: + if(program_state->mfkey_state == Ready) { + program_state->mfkey_state = Help; + } + break; + case InputKeyOk: + if(program_state->mfkey_state == Ready) { + furi_thread_start(program_state->mfkeythread); + } + break; + case InputKeyBack: + if(program_state->mfkey_state == Help) { + program_state->mfkey_state = Ready; + } else { + program_state->close_thread_please = true; + // Wait until thread is finished + furi_thread_join(program_state->mfkeythread); + main_loop = false; + } + break; + default: + break; + } + } + } - furi_mutex_release(program_state->mutex); - view_port_update(view_port); - } + furi_mutex_release(program_state->mutex); + view_port_update(view_port); + } - // Thread joined in back event handler - furi_thread_free(program_state->mfkeythread); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_message_queue_free(event_queue); - furi_mutex_free(program_state->mutex); - free(program_state); + // Thread joined in back event handler + furi_thread_free(program_state->mfkeythread); + view_port_enabled_set(view_port, false); + gui_remove_view_port(gui, view_port); + furi_record_close(RECORD_GUI); + view_port_free(view_port); + furi_message_queue_free(event_queue); + furi_mutex_free(program_state->mutex); + free(program_state); - return 0; + return 0; } #pragma GCC pop_options diff --git a/applications/system/mfkey/mfkey.h b/applications/system/mfkey/mfkey.h index 7b5be5c5a..43e558874 100644 --- a/applications/system/mfkey/mfkey.h +++ b/applications/system/mfkey/mfkey.h @@ -9,115 +9,103 @@ #include #include -struct Crypto1State -{ - uint32_t odd, even; +struct Crypto1State { + uint32_t odd, even; }; -struct Msb -{ - int tail; - uint32_t states[768]; +struct Msb { + int tail; + uint32_t states[768]; }; -typedef enum -{ - MissingNonces, - ZeroNonces, - InsufficientRAM, +typedef enum { + MissingNonces, + ZeroNonces, + InsufficientRAM, } MFKeyError; -typedef enum -{ - Ready, - Initializing, - DictionaryAttack, - MFKeyAttack, - Complete, - Error, - Help, +typedef enum { + Ready, + Initializing, + DictionaryAttack, + MFKeyAttack, + Complete, + Error, + Help, } MFKeyState; // TODO: Can we eliminate any of the members of this struct? -typedef struct -{ - FuriMutex *mutex; - MFKeyError err; - MFKeyState mfkey_state; - int cracked; - int unique_cracked; - int num_completed; - int num_candidates; - int total; - int dict_count; - int search; - int eta_timestamp; - int eta_total; - int eta_round; - bool mfkey32_present; - bool nested_present; - bool close_thread_please; - FuriThread *mfkeythread; - KeysDict *cuid_dict; - MfClassicKey *key_buffer; - size_t key_buffer_size; - size_t key_buffer_count; +typedef struct { + FuriMutex* mutex; + MFKeyError err; + MFKeyState mfkey_state; + int cracked; + int unique_cracked; + int num_completed; + int num_candidates; + int total; + int dict_count; + int search; + int eta_timestamp; + int eta_total; + int eta_round; + bool mfkey32_present; + bool nested_present; + bool close_thread_please; + FuriThread* mfkeythread; + KeysDict* cuid_dict; + MfClassicKey* key_buffer; + size_t key_buffer_size; + size_t key_buffer_count; } ProgramState; -typedef enum -{ - mfkey32, - static_nested, - static_encrypted +typedef enum { + mfkey32, + static_nested, + static_encrypted } AttackType; -typedef struct -{ - AttackType attack; - MfClassicKey key; // key - uint32_t uid; // serial number - uint32_t nt0; // tag challenge first - uint32_t nt1; // tag challenge second - uint32_t uid_xor_nt0; // uid ^ nt0 - uint32_t uid_xor_nt1; // uid ^ nt1 - union - { - // Mfkey32 - struct - { - uint32_t p64; // 64th successor of nt0 - uint32_t p64b; // 64th successor of nt1 - uint32_t nr0_enc; // first encrypted reader challenge - uint32_t ar0_enc; // first encrypted reader response - uint32_t nr1_enc; // second encrypted reader challenge - uint32_t ar1_enc; // second encrypted reader response - }; - // Nested - struct - { - uint32_t ks1_1_enc; // first encrypted keystream - uint32_t ks1_2_enc; // second encrypted keystream - char par_1_str[5]; // first parity bits (string representation) - char par_2_str[5]; // second parity bits (string representation) - uint8_t par_1; // first parity bits - uint8_t par_2; // second parity bits - }; - }; +typedef struct { + AttackType attack; + MfClassicKey key; // key + uint32_t uid; // serial number + uint32_t nt0; // tag challenge first + uint32_t nt1; // tag challenge second + uint32_t uid_xor_nt0; // uid ^ nt0 + uint32_t uid_xor_nt1; // uid ^ nt1 + union { + // Mfkey32 + struct { + uint32_t p64; // 64th successor of nt0 + uint32_t p64b; // 64th successor of nt1 + uint32_t nr0_enc; // first encrypted reader challenge + uint32_t ar0_enc; // first encrypted reader response + uint32_t nr1_enc; // second encrypted reader challenge + uint32_t ar1_enc; // second encrypted reader response + }; + // Nested + struct { + uint32_t ks1_1_enc; // first encrypted keystream + uint32_t ks1_2_enc; // second encrypted keystream + char par_1_str[5]; // first parity bits (string representation) + char par_2_str[5]; // second parity bits (string representation) + uint8_t par_1; // first parity bits + uint8_t par_2; // second parity bits + }; + }; } MfClassicNonce; -typedef struct -{ - Stream *stream; - uint32_t total_nonces; - MfClassicNonce *remaining_nonce_array; - size_t remaining_nonces; +typedef struct { + Stream* stream; + uint32_t total_nonces; + MfClassicNonce* remaining_nonce_array; + size_t remaining_nonces; } MfClassicNonceArray; -struct KeysDict -{ - Stream *stream; - size_t key_size; - size_t key_size_symbols; - size_t total_keys; +struct KeysDict { + Stream* stream; + size_t key_size; + size_t key_size_symbols; + size_t total_keys; }; -#endif // MFKEY_H \ No newline at end of file +#endif // MFKEY_H