1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-13 05:06:30 +04:00

upd mfkey

This commit is contained in:
MX
2025-09-09 15:31:43 +03:00
parent c091a58486
commit ffb8eb7cff
4 changed files with 1563 additions and 1075 deletions

View File

@@ -15,7 +15,7 @@ App(
fap_icon_assets="images", fap_icon_assets="images",
fap_weburl="https://github.com/noproto/FlipperMfkey", fap_weburl="https://github.com/noproto/FlipperMfkey",
fap_description="MIFARE Classic key recovery tool", fap_description="MIFARE Classic key recovery tool",
fap_version="3.0", fap_version="3.1",
) )
App( App(

View File

@@ -6,251 +6,260 @@
#include <nfc/helpers/nfc_util.h> #include <nfc/helpers/nfc_util.h>
#include <nfc/protocols/mf_classic/mf_classic.h> #include <nfc/protocols/mf_classic/mf_classic.h>
#define LF_POLY_ODD (0x29CE5C) #define LF_POLY_ODD (0x29CE5C)
#define LF_POLY_EVEN (0x870804) #define LF_POLY_EVEN (0x870804)
#define BIT(x, n) ((x) >> (n) & 1) #define BIT(x, n) ((x) >> (n) & 1)
#define BEBIT(x, n) BIT(x, (n) ^ 24) #define BEBIT(x, n) BIT(x, (n) ^ 24)
#define SWAPENDIAN(x) \ #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 uint32_t prng_successor(uint32_t x, uint32_t n);
static inline int filter(uint32_t const x); static inline int filter(uint32_t const x);
static inline uint8_t evenparity32(uint32_t x); static inline uint8_t evenparity32(uint32_t x);
static inline void update_contribution(unsigned int data[], int item, int mask1, int mask2); static inline void update_contribution(unsigned int data[], int item, int mask1, int mask2);
void crypto1_get_lfsr(struct Crypto1State* state, MfClassicKey* lfsr); void crypto1_get_lfsr(struct Crypto1State *state, MfClassicKey *lfsr);
static inline uint32_t crypt_word(struct Crypto1State* s); 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 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 inline uint32_t crypt_word_ret(struct Crypto1State *s, uint32_t in, int x);
static uint32_t crypt_word_par( static uint32_t crypt_word_par(
struct Crypto1State* s, struct Crypto1State *s,
uint32_t in, uint32_t in,
int is_encrypted, int is_encrypted,
uint32_t nt_plain, uint32_t nt_plain,
uint8_t* parity_keystream_bits); uint8_t *parity_keystream_bits);
static inline void rollback_word_noret(struct Crypto1State* s, uint32_t in, int x); 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 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 inline uint32_t napi_lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb);
static const uint8_t lookup1[256] = { 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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};
static const uint8_t lookup2[256] = { 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, 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, 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, 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, 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, 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, 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, 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, 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}; 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) { static inline int filter(uint32_t const x)
uint32_t f; {
f = lookup1[x & 0xff] | lookup2[(x >> 8) & 0xff]; uint32_t f;
f |= 0x0d938 >> (x >> 16 & 0xf) & 1; f = lookup1[x & 0xff] | lookup2[(x >> 8) & 0xff];
return BIT(0xEC57E80A, f); f |= 0x0d938 >> (x >> 16 & 0xf) & 1;
return BIT(0xEC57E80A, f);
} }
#ifndef __ARM_ARCH_7EM__
static inline uint8_t evenparity32(uint32_t x) {
return __builtin_parity(x);
}
#endif
#ifdef __ARM_ARCH_7EM__ #ifdef __ARM_ARCH_7EM__
static inline uint8_t evenparity32(uint32_t x) { static inline uint8_t evenparity32(uint32_t x)
uint32_t result; {
__asm__ volatile("eor r1, %[x], %[x], lsr #16 \n\t" // r1 = x ^ (x >> 16) // fold 32 bits -> 16 -> 8 -> 4
"eor r1, r1, r1, lsr #8 \n\t" // r1 = r1 ^ (r1 >> 8) x ^= x >> 16;
"eor r1, r1, r1, lsr #4 \n\t" // r1 = r1 ^ (r1 >> 4) x ^= x >> 8;
"eor r1, r1, r1, lsr #2 \n\t" // r1 = r1 ^ (r1 >> 2) x ^= x >> 4;
"eor r1, r1, r1, lsr #1 \n\t" // r1 = r1 ^ (r1 >> 1) // magic 0x6996: bit i tells you parity of i (0 ≤ i < 16)
"and %[result], r1, #1 \n\t" // result = r1 & 1 return (uint8_t)((0x6996u >> (x & 0xF)) & 1);
: [result] "=r"(result)
: [x] "r"(x)
: "r1");
return result;
} }
#endif #endif
static inline void update_contribution(unsigned int data[], int item, int mask1, int mask2) { 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); int p = data[item] >> 25;
p = p << 1 | evenparity32(data[item] & mask2); p = p << 1 | evenparity32(data[item] & mask1);
data[item] = p << 24 | (data[item] & 0xffffff); p = p << 1 | evenparity32(data[item] & mask2);
data[item] = p << 24 | (data[item] & 0xffffff);
} }
static inline uint32_t crypt_word(struct Crypto1State* s) { static inline uint32_t crypt_word(struct Crypto1State *s)
// "in" and "x" are always 0 (last iteration) {
uint32_t res_ret = 0; // "in" and "x" are always 0 (last iteration)
uint32_t feedin, t; uint32_t res_ret = 0;
for(int i = 0; i <= 31; i++) { uint32_t feedin, t;
res_ret |= (filter(s->odd) << (24 ^ i)); //-V629 for (int i = 0; i <= 31; i++)
feedin = LF_POLY_EVEN & s->even; {
feedin ^= LF_POLY_ODD & s->odd; res_ret |= (filter(s->odd) << (24 ^ i)); //-V629
s->even = s->even << 1 | (evenparity32(feedin)); feedin = LF_POLY_EVEN & s->even;
t = s->odd, s->odd = s->even, s->even = t; feedin ^= LF_POLY_ODD & s->odd;
} s->even = s->even << 1 | (evenparity32(feedin));
return res_ret; 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) { static inline void crypt_word_noret(struct Crypto1State *s, uint32_t in, int x)
uint8_t ret; {
uint32_t feedin, t, next_in; uint8_t ret;
for(int i = 0; i <= 31; i++) { uint32_t feedin, t, next_in;
next_in = BEBIT(in, i); for (int i = 0; i <= 31; i++)
ret = filter(s->odd); {
feedin = ret & (!!x); next_in = BEBIT(in, i);
feedin ^= LF_POLY_EVEN & s->even; ret = filter(s->odd);
feedin ^= LF_POLY_ODD & s->odd; feedin = ret & (!!x);
feedin ^= !!next_in; feedin ^= LF_POLY_EVEN & s->even;
s->even = s->even << 1 | (evenparity32(feedin)); feedin ^= LF_POLY_ODD & s->odd;
t = s->odd, s->odd = s->even, s->even = t; feedin ^= !!next_in;
} s->even = s->even << 1 | (evenparity32(feedin));
return; 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) { 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; uint32_t ret = 0;
uint8_t next_ret; uint32_t feedin, t, next_in;
for(int i = 0; i <= 31; i++) { uint8_t next_ret;
next_in = BEBIT(in, i); for (int i = 0; i <= 31; i++)
next_ret = filter(s->odd); {
feedin = next_ret & (!!x); next_in = BEBIT(in, i);
feedin ^= LF_POLY_EVEN & s->even; next_ret = filter(s->odd);
feedin ^= LF_POLY_ODD & s->odd; feedin = next_ret & (!!x);
feedin ^= !!next_in; feedin ^= LF_POLY_EVEN & s->even;
s->even = s->even << 1 | (evenparity32(feedin)); feedin ^= LF_POLY_ODD & s->odd;
t = s->odd, s->odd = s->even, s->even = t; feedin ^= !!next_in;
ret |= next_ret << (24 ^ i); s->even = s->even << 1 | (evenparity32(feedin));
} t = s->odd, s->odd = s->even, s->even = t;
return ret; ret |= next_ret << (24 ^ i);
}
return ret;
} }
static uint8_t get_nth_byte(uint32_t value, int n) { static uint8_t get_nth_byte(uint32_t value, int n)
if(n < 0 || n > 3) { {
// Handle invalid input if (n < 0 || n > 3)
return 0; {
} // Handle invalid input
return (value >> (8 * (3 - n))) & 0xFF; return 0;
}
return (value >> (8 * (3 - n))) & 0xFF;
} }
static uint8_t crypt_bit(struct Crypto1State* s, uint8_t in, int is_encrypted) { static uint8_t crypt_bit(struct Crypto1State *s, uint8_t in, int is_encrypted)
uint32_t feedin, t; {
uint8_t ret = filter(s->odd); uint32_t feedin, t;
feedin = ret & !!is_encrypted; uint8_t ret = filter(s->odd);
feedin ^= !!in; feedin = ret & !!is_encrypted;
feedin ^= LF_POLY_ODD & s->odd; feedin ^= !!in;
feedin ^= LF_POLY_EVEN & s->even; feedin ^= LF_POLY_ODD & s->odd;
s->even = s->even << 1 | evenparity32(feedin); feedin ^= LF_POLY_EVEN & s->even;
t = s->odd, s->odd = s->even, s->even = t; s->even = s->even << 1 | evenparity32(feedin);
return ret; t = s->odd, s->odd = s->even, s->even = t;
return ret;
} }
static inline uint32_t crypt_word_par( static inline uint32_t crypt_word_par(
struct Crypto1State* s, struct Crypto1State *s,
uint32_t in, uint32_t in,
int is_encrypted, int is_encrypted,
uint32_t nt_plain, uint32_t nt_plain,
uint8_t* parity_keystream_bits) { uint8_t *parity_keystream_bits)
uint32_t ret = 0; {
*parity_keystream_bits = 0; // Reset parity keystream bits uint32_t ret = 0;
*parity_keystream_bits = 0; // Reset parity keystream bits
for(int i = 0; i < 32; i++) { for (int i = 0; i < 32; i++)
uint8_t bit = crypt_bit(s, BEBIT(in, i), is_encrypted); {
ret |= bit << (24 ^ i); uint8_t bit = crypt_bit(s, BEBIT(in, i), is_encrypted);
// Save keystream parity bit ret |= bit << (24 ^ i);
if((i + 1) % 8 == 0) { // Save keystream parity bit
*parity_keystream_bits |= if ((i + 1) % 8 == 0)
(filter(s->odd) ^ nfc_util_even_parity8(get_nth_byte(nt_plain, i / 8))) {
<< (3 - (i / 8)); *parity_keystream_bits |=
} (filter(s->odd) ^ nfc_util_even_parity8(get_nth_byte(nt_plain, i / 8)))
} << (3 - (i / 8));
return ret; }
}
return ret;
} }
static inline void rollback_word_noret(struct Crypto1State* s, uint32_t in, int x) { static inline void rollback_word_noret(struct Crypto1State *s, uint32_t in, int x)
uint8_t ret; {
uint32_t feedin, t, next_in; uint8_t ret;
for(int i = 31; i >= 0; i--) { uint32_t feedin, t, next_in;
next_in = BEBIT(in, i); for (int i = 31; i >= 0; i--)
s->odd &= 0xffffff; {
t = s->odd, s->odd = s->even, s->even = t; next_in = BEBIT(in, i);
ret = filter(s->odd); s->odd &= 0xffffff;
feedin = ret & (!!x); t = s->odd, s->odd = s->even, s->even = t;
feedin ^= s->even & 1; ret = filter(s->odd);
feedin ^= LF_POLY_EVEN & (s->even >>= 1); feedin = ret & (!!x);
feedin ^= LF_POLY_ODD & s->odd; feedin ^= s->even & 1;
feedin ^= !!next_in; feedin ^= LF_POLY_EVEN & (s->even >>= 1);
s->even |= (evenparity32(feedin)) << 23; feedin ^= LF_POLY_ODD & s->odd;
} feedin ^= !!next_in;
return; s->even |= (evenparity32(feedin)) << 23;
}
return;
} }
// TODO: // TODO:
/* /*
uint32_t rollback_word(struct Crypto1State *s, uint32_t in, int x) { uint32_t rollback_word(struct Crypto1State *s, uint32_t in, int x) {
uint32_t res_ret = 0; uint32_t res_ret = 0;
uint8_t ret; uint8_t ret;
uint32_t feedin, t, next_in; uint32_t feedin, t, next_in;
for (int i = 31; i >= 0; i--) { for (int i = 31; i >= 0; i--) {
next_in = BEBIT(in, i); next_in = BEBIT(in, i);
s->odd &= 0xffffff; s->odd &= 0xffffff;
t = s->odd, s->odd = s->even, s->even = t; t = s->odd, s->odd = s->even, s->even = t;
ret = filter(s->odd); ret = filter(s->odd);
feedin = ret & (!!x); feedin = ret & (!!x);
feedin ^= s->even & 1; feedin ^= s->even & 1;
feedin ^= LF_POLY_EVEN & (s->even >>= 1); feedin ^= LF_POLY_EVEN & (s->even >>= 1);
feedin ^= LF_POLY_ODD & s->odd; feedin ^= LF_POLY_ODD & s->odd;
feedin ^= !!next_in; feedin ^= !!next_in;
s->even |= (evenparity32(feedin)) << 23; s->even |= (evenparity32(feedin)) << 23;
res_ret |= (ret << (24 ^ i)); res_ret |= (ret << (24 ^ i));
} }
return res_ret; return res_ret;
} }
*/ */
uint8_t napi_lfsr_rollback_bit(struct Crypto1State* s, uint32_t in, int fb) { uint8_t napi_lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb)
int out; {
uint8_t ret; int out;
uint32_t t; uint8_t ret;
s->odd &= 0xffffff; uint32_t t;
t = s->odd, s->odd = s->even, s->even = t; s->odd &= 0xffffff;
t = s->odd, s->odd = s->even, s->even = t;
out = s->even & 1; out = s->even & 1;
out ^= LF_POLY_EVEN & (s->even >>= 1); out ^= LF_POLY_EVEN & (s->even >>= 1);
out ^= LF_POLY_ODD & s->odd; out ^= LF_POLY_ODD & s->odd;
out ^= !!in; out ^= !!in;
out ^= (ret = filter(s->odd)) & !!fb; out ^= (ret = filter(s->odd)) & !!fb;
s->even |= evenparity32(out) << 23; s->even |= evenparity32(out) << 23;
return ret; return ret;
} }
uint32_t napi_lfsr_rollback_word(struct Crypto1State* s, uint32_t in, int fb) { uint32_t napi_lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb)
int i; {
uint32_t ret = 0; int i;
for(i = 31; i >= 0; --i) uint32_t ret = 0;
ret |= napi_lfsr_rollback_bit(s, BEBIT(in, i), fb) << (i ^ 24); for (i = 31; i >= 0; --i)
return ret; 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) { static inline uint32_t prng_successor(uint32_t x, uint32_t n)
SWAPENDIAN(x); {
while(n--) SWAPENDIAN(x);
x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; while (n--)
return SWAPENDIAN(x); x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31;
return SWAPENDIAN(x);
} }
#endif // CRYPTO1_H #endif // CRYPTO1_H

File diff suppressed because it is too large Load Diff

View File

@@ -9,100 +9,115 @@
#include <toolbox/stream/buffered_file_stream.h> #include <toolbox/stream/buffered_file_stream.h>
#include <nfc/protocols/mf_classic/mf_classic.h> #include <nfc/protocols/mf_classic/mf_classic.h>
struct Crypto1State { struct Crypto1State
uint32_t odd, even; {
uint32_t odd, even;
}; };
struct Msb { struct Msb
int tail; {
uint32_t states[768]; int tail;
uint32_t states[768];
}; };
typedef enum { typedef enum
MissingNonces, {
ZeroNonces, MissingNonces,
InsufficientRAM, ZeroNonces,
InsufficientRAM,
} MFKeyError; } MFKeyError;
typedef enum { typedef enum
Ready, {
Initializing, Ready,
DictionaryAttack, Initializing,
MFKeyAttack, DictionaryAttack,
Complete, MFKeyAttack,
Error, Complete,
Help, Error,
Help,
} MFKeyState; } MFKeyState;
// TODO: Can we eliminate any of the members of this struct? // TODO: Can we eliminate any of the members of this struct?
typedef struct { typedef struct
FuriMutex* mutex; {
MFKeyError err; FuriMutex *mutex;
MFKeyState mfkey_state; MFKeyError err;
int cracked; MFKeyState mfkey_state;
int unique_cracked; int cracked;
int num_completed; int unique_cracked;
int num_candidates; int num_completed;
int total; int num_candidates;
int dict_count; int total;
int search; int dict_count;
int eta_timestamp; int search;
int eta_total; int eta_timestamp;
int eta_round; int eta_total;
bool mfkey32_present; int eta_round;
bool nested_present; bool mfkey32_present;
bool close_thread_please; bool nested_present;
FuriThread* mfkeythread; bool close_thread_please;
KeysDict* cuid_dict; FuriThread *mfkeythread;
KeysDict *cuid_dict;
MfClassicKey *key_buffer;
size_t key_buffer_size;
size_t key_buffer_count;
} ProgramState; } ProgramState;
typedef enum { typedef enum
mfkey32, {
static_nested, mfkey32,
static_encrypted static_nested,
static_encrypted
} AttackType; } AttackType;
typedef struct { typedef struct
AttackType attack; {
MfClassicKey key; // key AttackType attack;
uint32_t uid; // serial number MfClassicKey key; // key
uint32_t nt0; // tag challenge first uint32_t uid; // serial number
uint32_t nt1; // tag challenge second uint32_t nt0; // tag challenge first
uint32_t uid_xor_nt0; // uid ^ nt0 uint32_t nt1; // tag challenge second
uint32_t uid_xor_nt1; // uid ^ nt1 uint32_t uid_xor_nt0; // uid ^ nt0
union { uint32_t uid_xor_nt1; // uid ^ nt1
// Mfkey32 union
struct { {
uint32_t p64; // 64th successor of nt0 // Mfkey32
uint32_t p64b; // 64th successor of nt1 struct
uint32_t nr0_enc; // first encrypted reader challenge {
uint32_t ar0_enc; // first encrypted reader response uint32_t p64; // 64th successor of nt0
uint32_t nr1_enc; // second encrypted reader challenge uint32_t p64b; // 64th successor of nt1
uint32_t ar1_enc; // second encrypted reader response uint32_t nr0_enc; // first encrypted reader challenge
}; uint32_t ar0_enc; // first encrypted reader response
// Nested uint32_t nr1_enc; // second encrypted reader challenge
struct { uint32_t ar1_enc; // second encrypted reader response
uint32_t ks1_1_enc; // first encrypted keystream };
uint32_t ks1_2_enc; // second encrypted keystream // Nested
char par_1_str[5]; // first parity bits (string representation) struct
char par_2_str[5]; // second parity bits (string representation) {
uint8_t par_1; // first parity bits uint32_t ks1_1_enc; // first encrypted keystream
uint8_t par_2; // second parity bits 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; } MfClassicNonce;
typedef struct { typedef struct
Stream* stream; {
uint32_t total_nonces; Stream *stream;
MfClassicNonce* remaining_nonce_array; uint32_t total_nonces;
size_t remaining_nonces; MfClassicNonce *remaining_nonce_array;
size_t remaining_nonces;
} MfClassicNonceArray; } MfClassicNonceArray;
struct KeysDict { struct KeysDict
Stream* stream; {
size_t key_size; Stream *stream;
size_t key_size_symbols; size_t key_size;
size_t total_keys; size_t key_size_symbols;
size_t total_keys;
}; };
#endif // MFKEY_H #endif // MFKEY_H