Skip to content

Commit

Permalink
Merge branch 'dev' into astra/3745-gen4-ultralight-password-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
Astrrra committed Apr 8, 2024
2 parents c112992 + 67ed98c commit 53adfb1
Show file tree
Hide file tree
Showing 85 changed files with 5,278 additions and 1,477 deletions.
18 changes: 13 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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"
Expand All @@ -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
12 changes: 12 additions & 0 deletions mfkey/.catalog/README.md
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
6 changes: 6 additions & 0 deletions mfkey/.catalog/changelog.md
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
Binary file added mfkey/.catalog/screenshots/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added mfkey/.catalog/screenshots/2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added mfkey/.catalog/screenshots/3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 13 additions & 5 deletions mfkey32/application.fam → mfkey/application.fam
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"],
)
22 changes: 22 additions & 0 deletions mfkey/crypto1.c
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;
}
}
156 changes: 156 additions & 0 deletions mfkey/crypto1.h
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
Binary file added mfkey/images/mfkey.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 53adfb1

Please sign in to comment.