-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'dev' into astra/3745-gen4-ultralight-password-fix
- Loading branch information
Showing
85 changed files
with
5,278 additions
and
1,477 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,14 +21,14 @@ jobs: | |
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 2 | ||
submodules: recursive | ||
|
||
|
||
- name: Set up ufbt | ||
uses: flipperdevices/[email protected].2 | ||
uses: flipperdevices/[email protected] | ||
with: | ||
sdk-channel: ${{ github.event.inputs.sdk-channel || 'rc'}} | ||
task: setup | ||
|
@@ -48,8 +48,12 @@ jobs: | |
run: | | ||
BUILD_FAILED=0 | ||
for appdir in ${{ steps.changed-files.outputs.all_changed_and_modified_files }} ; do | ||
if [ ! -f "$appdir/application.fam" ] ; then | ||
echo "Skipping $appdir, no application.fam. File may have been deleted." | ||
continue | ||
fi | ||
echo "Building in $appdir" | ||
pushd $appdir | ||
pushd "$appdir" | ||
if ! ufbt build faps ; then | ||
echo "::error::Failed to build $appdir" | ||
BUILD_FAILED=1 | ||
|
@@ -66,8 +70,12 @@ jobs: | |
run: | | ||
BUILD_FAILED=0 | ||
for appdir in $( dirname $( find . -name application.fam ) ) ; do | ||
if [ ! -f "$appdir/application.fam" ] ; then | ||
echo "Skipping $appdir, no application.fam. File may have been deleted." | ||
continue | ||
fi | ||
echo "Building in $appdir" | ||
pushd $appdir | ||
pushd "$appdir" | ||
if ! ufbt build faps ; then | ||
BUILD_FAILED=1 | ||
echo "::error::Failed to build $appdir" | ||
|
@@ -85,7 +93,7 @@ jobs: | |
cp -v $( find . -name '*.fap' ) dist/ | ||
- name: Upload all .fap files | ||
uses: actions/upload-artifact@v3 | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: faps | ||
path: dist/*.fap |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Flipper Zero MFKey | ||
|
||
This application allows you to calculate the keys of MIFARE Classic cards using the Mfkey32 and Nested algorithms directly on your Flipper Zero. After collecting the nonces using the Detect Reader feature of the NFC app, they can be used to calculate the keys to the card in the MFKey app. | ||
|
||
## Usage | ||
|
||
After collecting nonces using the Detect Reader option, press the Start button in the MFKey app and wait for it to finish. The calculation can take more than 10 minutes, so you'll have to be patient. After the calculation is complete, the keys will be saved to the user key dictionary. | ||
|
||
## Credits | ||
|
||
Developers: noproto, AG | ||
Thanks: bettse |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
## 2.0 | ||
- Added Nested key recovery, use new KeysDict API, fix crashes, more efficient RAM utilization, faster | ||
## 1.1 | ||
- Rework application with new NFC API | ||
## 1.0 | ||
- Initial release |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,27 @@ | ||
App( | ||
appid="mfkey32", | ||
name="Mfkey32", | ||
appid="mfkey", | ||
name="MFKey", | ||
apptype=FlipperAppType.EXTERNAL, | ||
targets=["f7"], | ||
entry_point="mfkey32_main", | ||
entry_point="mfkey_main", | ||
requires=[ | ||
"gui", | ||
"storage", | ||
], | ||
stack_size=1 * 1024, | ||
fap_description="Mf Classic key finder", | ||
fap_version="1.1", | ||
fap_icon="mfkey.png", | ||
fap_category="NFC", | ||
fap_author="@noproto", | ||
fap_icon_assets="images", | ||
fap_weburl="https://github.com/noproto/FlipperMfkey", | ||
fap_description="MIFARE Classic key recovery tool", | ||
fap_version="2.2", | ||
) | ||
|
||
App( | ||
appid="mfkey_init_plugin", | ||
apptype=FlipperAppType.PLUGIN, | ||
entry_point="init_plugin_ep", | ||
requires=["mfkey"], | ||
sources=["init_plugin.c"], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#pragma GCC optimize("O3") | ||
#pragma GCC optimize("-funroll-all-loops") | ||
|
||
#include <inttypes.h> | ||
#include "crypto1.h" | ||
#include "mfkey.h" | ||
|
||
#define BIT(x, n) ((x) >> (n) & 1) | ||
|
||
void crypto1_get_lfsr(struct Crypto1State* state, MfClassicKey* lfsr) { | ||
int i; | ||
uint64_t lfsr_value = 0; | ||
for(i = 23; i >= 0; --i) { | ||
lfsr_value = lfsr_value << 1 | BIT(state->odd, i ^ 3); | ||
lfsr_value = lfsr_value << 1 | BIT(state->even, i ^ 3); | ||
} | ||
|
||
// Assign the key value to the MfClassicKey struct | ||
for(i = 0; i < 6; ++i) { | ||
lfsr->data[i] = (lfsr_value >> ((5 - i) * 8)) & 0xFF; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
#ifndef CRYPTO1_H | ||
#define CRYPTO1_H | ||
|
||
#include <inttypes.h> | ||
#include "mfkey.h" | ||
#include <nfc/protocols/mf_classic/mf_classic.h> | ||
|
||
#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 SWAPENDIAN(x) \ | ||
((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); | ||
static inline void rollback_word_noret(struct Crypto1State* s, uint32_t in, int x); | ||
|
||
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}; | ||
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}; | ||
|
||
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); | ||
} | ||
|
||
#ifndef __ARM_ARCH_7EM__ | ||
static inline uint8_t evenparity32(uint32_t x) { | ||
return __builtin_parity(x); | ||
} | ||
#endif | ||
|
||
#ifdef __ARM_ARCH_7EM__ | ||
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) | ||
"eor r1, r1, r1, lsr #8 \n\t" // r1 = r1 ^ (r1 >> 8) | ||
"eor r1, r1, r1, lsr #4 \n\t" // r1 = r1 ^ (r1 >> 4) | ||
"eor r1, r1, r1, lsr #2 \n\t" // r1 = r1 ^ (r1 >> 2) | ||
"eor r1, r1, r1, lsr #1 \n\t" // r1 = r1 ^ (r1 >> 1) | ||
"and %[result], r1, #1 \n\t" // result = r1 & 1 | ||
: [result] "=r"(result) | ||
: [x] "r"(x) | ||
: "r1"); | ||
return result; | ||
} | ||
#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 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 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 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 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 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.