Skip to content

Commit 7b4b27b

Browse files
committed
Replace Mfkey32 with MFKey
1 parent 8245889 commit 7b4b27b

File tree

18 files changed

+1632
-3006
lines changed

18 files changed

+1632
-3006
lines changed
Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
App(
2-
appid="mfkeynested",
3-
name="MFKey Nested",
2+
appid="mfkey",
3+
name="MFKey",
44
apptype=FlipperAppType.EXTERNAL,
55
targets=["f7"],
66
entry_point="mfkey_main",
@@ -11,7 +11,17 @@ App(
1111
stack_size=1 * 1024,
1212
fap_icon="mfkey.png",
1313
fap_category="NFC",
14-
fap_author="noproto",
14+
fap_author="@noproto",
1515
fap_icon_assets="images",
1616
fap_weburl="https://github.com/noproto/FlipperMfkey",
17+
fap_description="MIFARE Classic key recovery tool",
18+
fap_version="2.0",
19+
)
20+
21+
App(
22+
appid="mfkey_init_plugin",
23+
apptype=FlipperAppType.PLUGIN,
24+
entry_point="init_plugin_ep",
25+
requires=["mfkey"],
26+
sources=["init_plugin.c"],
1727
)

base_pack/mfkey/common.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#ifndef COMMON_H
2+
#define COMMON_H
3+
4+
#include <inttypes.h>
5+
6+
inline uint64_t napi_nfc_util_bytes2num(const uint8_t* src, uint8_t len);
7+
8+
inline uint64_t napi_nfc_util_bytes2num(const uint8_t* src, uint8_t len) {
9+
furi_assert(src);
10+
furi_assert(len <= 8);
11+
12+
uint64_t res = 0;
13+
while(len--) {
14+
res = (res << 8) | (*src);
15+
src++;
16+
}
17+
return res;
18+
}
19+
20+
#endif // COMMON_H

base_pack/mfkey/crypto1.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#pragma GCC optimize("O3")
2+
#pragma GCC optimize("-funroll-all-loops")
3+
4+
#include <inttypes.h>
5+
#include "crypto1.h"
6+
#include "mfkey.h"
7+
8+
#define BIT(x, n) ((x) >> (n) & 1)
9+
10+
void crypto1_get_lfsr(struct Crypto1State* state, MfClassicKey* lfsr) {
11+
int i;
12+
uint64_t lfsr_value = 0;
13+
for(i = 23; i >= 0; --i) {
14+
lfsr_value = lfsr_value << 1 | BIT(state->odd, i ^ 3);
15+
lfsr_value = lfsr_value << 1 | BIT(state->even, i ^ 3);
16+
}
17+
18+
// Assign the key value to the MfClassicKey struct
19+
for(i = 0; i < 6; ++i) {
20+
lfsr->data[i] = (lfsr_value >> ((5 - i) * 8)) & 0xFF;
21+
}
22+
}

base_pack/mfkey/crypto1.h

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
#ifndef CRYPTO1_H
2+
#define CRYPTO1_H
3+
4+
#include <inttypes.h>
5+
#include "mfkey.h"
6+
#include <nfc/protocols/mf_classic/mf_classic.h>
7+
8+
#define LF_POLY_ODD (0x29CE5C)
9+
#define LF_POLY_EVEN (0x870804)
10+
#define BIT(x, n) ((x) >> (n) & 1)
11+
#define BEBIT(x, n) BIT(x, (n) ^ 24)
12+
#define SWAPENDIAN(x) \
13+
((x) = ((x) >> 8 & 0xff00ff) | ((x) & 0xff00ff) << 8, (x) = (x) >> 16 | (x) << 16)
14+
15+
static inline uint32_t prng_successor(uint32_t x, uint32_t n);
16+
static inline int filter(uint32_t const x);
17+
static inline uint8_t evenparity32(uint32_t x);
18+
static inline void update_contribution(unsigned int data[], int item, int mask1, int mask2);
19+
void crypto1_get_lfsr(struct Crypto1State* state, MfClassicKey* lfsr);
20+
static inline uint32_t crypt_word(struct Crypto1State* s);
21+
static inline void crypt_word_noret(struct Crypto1State* s, uint32_t in, int x);
22+
static inline uint32_t crypt_word_ret(struct Crypto1State* s, uint32_t in, int x);
23+
static inline void rollback_word_noret(struct Crypto1State* s, uint32_t in, int x);
24+
25+
static const uint8_t lookup1[256] = {
26+
0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0,
27+
0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16,
28+
8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, 8, 8, 24, 24, 8, 24, 8, 8,
29+
8, 24, 8, 8, 24, 24, 24, 24, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24,
30+
0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0,
31+
0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24,
32+
0, 0, 16, 16, 0, 16, 0, 0, 0, 16, 0, 0, 16, 16, 16, 16, 0, 0, 16, 16, 0, 16, 0, 0,
33+
0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24,
34+
8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24, 0, 0, 16, 16, 0, 16, 0, 0,
35+
0, 16, 0, 0, 16, 16, 16, 16, 8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24,
36+
8, 8, 24, 24, 8, 24, 8, 8, 8, 24, 8, 8, 24, 24, 24, 24};
37+
static const uint8_t lookup2[256] = {
38+
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,
39+
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,
40+
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,
41+
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,
42+
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,
43+
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,
44+
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,
45+
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,
46+
2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6};
47+
48+
static inline int filter(uint32_t const x) {
49+
uint32_t f;
50+
f = lookup1[x & 0xff] | lookup2[(x >> 8) & 0xff];
51+
f |= 0x0d938 >> (x >> 16 & 0xf) & 1;
52+
return BIT(0xEC57E80A, f);
53+
}
54+
55+
#ifndef __ARM_ARCH_7EM__
56+
static inline uint8_t evenparity32(uint32_t x) {
57+
return __builtin_parity(x);
58+
}
59+
#endif
60+
61+
#ifdef __ARM_ARCH_7EM__
62+
static inline uint8_t evenparity32(uint32_t x) {
63+
uint32_t result;
64+
__asm__ volatile("eor r1, %[x], %[x], lsr #16 \n\t" // r1 = x ^ (x >> 16)
65+
"eor r1, r1, r1, lsr #8 \n\t" // r1 = r1 ^ (r1 >> 8)
66+
"eor r1, r1, r1, lsr #4 \n\t" // r1 = r1 ^ (r1 >> 4)
67+
"eor r1, r1, r1, lsr #2 \n\t" // r1 = r1 ^ (r1 >> 2)
68+
"eor r1, r1, r1, lsr #1 \n\t" // r1 = r1 ^ (r1 >> 1)
69+
"and %[result], r1, #1 \n\t" // result = r1 & 1
70+
: [result] "=r"(result)
71+
: [x] "r"(x)
72+
: "r1");
73+
return result;
74+
}
75+
#endif
76+
77+
static inline void update_contribution(unsigned int data[], int item, int mask1, int mask2) {
78+
int p = data[item] >> 25;
79+
p = p << 1 | evenparity32(data[item] & mask1);
80+
p = p << 1 | evenparity32(data[item] & mask2);
81+
data[item] = p << 24 | (data[item] & 0xffffff);
82+
}
83+
84+
static inline uint32_t crypt_word(struct Crypto1State* s) {
85+
// "in" and "x" are always 0 (last iteration)
86+
uint32_t res_ret = 0;
87+
uint32_t feedin, t;
88+
for(int i = 0; i <= 31; i++) {
89+
res_ret |= (filter(s->odd) << (24 ^ i)); //-V629
90+
feedin = LF_POLY_EVEN & s->even;
91+
feedin ^= LF_POLY_ODD & s->odd;
92+
s->even = s->even << 1 | (evenparity32(feedin));
93+
t = s->odd, s->odd = s->even, s->even = t;
94+
}
95+
return res_ret;
96+
}
97+
98+
static inline void crypt_word_noret(struct Crypto1State* s, uint32_t in, int x) {
99+
uint8_t ret;
100+
uint32_t feedin, t, next_in;
101+
for(int i = 0; i <= 31; i++) {
102+
next_in = BEBIT(in, i);
103+
ret = filter(s->odd);
104+
feedin = ret & (!!x);
105+
feedin ^= LF_POLY_EVEN & s->even;
106+
feedin ^= LF_POLY_ODD & s->odd;
107+
feedin ^= !!next_in;
108+
s->even = s->even << 1 | (evenparity32(feedin));
109+
t = s->odd, s->odd = s->even, s->even = t;
110+
}
111+
return;
112+
}
113+
114+
static inline uint32_t crypt_word_ret(struct Crypto1State* s, uint32_t in, int x) {
115+
uint32_t ret = 0;
116+
uint32_t feedin, t, next_in;
117+
uint8_t next_ret;
118+
for(int i = 0; i <= 31; i++) {
119+
next_in = BEBIT(in, i);
120+
next_ret = filter(s->odd);
121+
feedin = next_ret & (!!x);
122+
feedin ^= LF_POLY_EVEN & s->even;
123+
feedin ^= LF_POLY_ODD & s->odd;
124+
feedin ^= !!next_in;
125+
s->even = s->even << 1 | (evenparity32(feedin));
126+
t = s->odd, s->odd = s->even, s->even = t;
127+
ret |= next_ret << (24 ^ i);
128+
}
129+
return ret;
130+
}
131+
132+
static inline void rollback_word_noret(struct Crypto1State* s, uint32_t in, int x) {
133+
uint8_t ret;
134+
uint32_t feedin, t, next_in;
135+
for(int i = 31; i >= 0; i--) {
136+
next_in = BEBIT(in, i);
137+
s->odd &= 0xffffff;
138+
t = s->odd, s->odd = s->even, s->even = t;
139+
ret = filter(s->odd);
140+
feedin = ret & (!!x);
141+
feedin ^= s->even & 1;
142+
feedin ^= LF_POLY_EVEN & (s->even >>= 1);
143+
feedin ^= LF_POLY_ODD & s->odd;
144+
feedin ^= !!next_in;
145+
s->even |= (evenparity32(feedin)) << 23;
146+
}
147+
return;
148+
}
149+
150+
static inline uint32_t prng_successor(uint32_t x, uint32_t n) {
151+
SWAPENDIAN(x);
152+
while(n--) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31;
153+
return SWAPENDIAN(x);
154+
}
155+
156+
#endif // CRYPTO1_H

base_pack/mfkey/images/mfkey.png

107 Bytes
Loading

0 commit comments

Comments
 (0)