Skip to content

Commit

Permalink
Merge branch 'ofw_dev' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
MX committed Dec 3, 2023
2 parents 9bf8f10 + c477d13 commit d6fcb04
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 0 deletions.
9 changes: 9 additions & 0 deletions applications/main/nfc/application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,15 @@ App(
sources=["plugins/supported_cards/kazan.c"],
)

App(
appid="aime_parser",
apptype=FlipperAppType.PLUGIN,
entry_point="aime_plugin_ep",
targets=["f7"],
requires=["nfc"],
sources=["plugins/supported_cards/aime.c"],
)

App(
appid="nfc_start",
targets=["f7"],
Expand Down
164 changes: 164 additions & 0 deletions applications/main/nfc/plugins/supported_cards/aime.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#include "nfc_supported_card_plugin.h"

#include <flipper_application/flipper_application.h>

#include <nfc/nfc_device.h>
#include <nfc/helpers/nfc_util.h>
#include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>

#define TAG "Aime"

static const uint64_t aime_key = 0x574343467632;

bool aime_verify(Nfc* nfc) {
bool verified = false;

do {
const uint8_t verify_sector = 0;
uint8_t block_num = mf_classic_get_first_block_num_of_sector(verify_sector);
FURI_LOG_D(TAG, "Verifying sector %u", verify_sector);

MfClassicKey key = {};
nfc_util_num2bytes(aime_key, COUNT_OF(key.data), key.data);

MfClassicAuthContext auth_ctx = {};
MfClassicError error =
mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_ctx);

if(error != MfClassicErrorNone) {
FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error);
break;
}

verified = true;
} while(false);

return verified;
}

static bool aime_read(Nfc* nfc, NfcDevice* device) {
furi_assert(nfc);
furi_assert(device);

bool is_read = false;

MfClassicData* data = mf_classic_alloc();
nfc_device_copy_data(device, NfcProtocolMfClassic, data);

do {
MfClassicType type = MfClassicType1k;
MfClassicError error = mf_classic_poller_sync_detect_type(nfc, &type);
if(error != MfClassicErrorNone) break;

data->type = type;
MfClassicDeviceKeys keys = {};
for(size_t i = 0; i < mf_classic_get_total_sectors_num(data->type); i++) {
nfc_util_num2bytes(aime_key, sizeof(MfClassicKey), keys.key_a[i].data);
FURI_BIT_SET(keys.key_a_mask, i);
nfc_util_num2bytes(aime_key, sizeof(MfClassicKey), keys.key_b[i].data);
FURI_BIT_SET(keys.key_b_mask, i);
}

error = mf_classic_poller_sync_read(nfc, &keys, data);
if(error != MfClassicErrorNone) {
FURI_LOG_W(TAG, "Failed to read data");
break;
}

nfc_device_set_data(device, NfcProtocolMfClassic, data);

is_read = true;
} while(false);

mf_classic_free(data);

return is_read;
}

static bool aime_parse(const NfcDevice* device, FuriString* parsed_data) {
furi_assert(device);

const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic);

bool parsed = false;

do {
// verify key
MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 0);
uint64_t key = nfc_util_bytes2num(sec_tr->key_a.data, 6);
if(key != aime_key) break;

// Aime Magic is stored at block 1, starts from byte 0, len 4 bytes
const uint8_t* aime_magic = &data->block[1].data[0];

// verify aime magic
if(aime_magic[0] != 'S' || aime_magic[1] != 'B' || aime_magic[2] != 'S' ||
aime_magic[3] != 'D')
break;

// Aime checksum is stored at block 1, starts from byte 13, len 3 bytes
// seems like only old games checks this? e.g., old versions of Chunithm
const uint8_t* aime_checksum = &data->block[1].data[13];

// Aime access code is stored as decimal hex representation in block 2, starts from byte 6, len 10 bytes
const uint8_t* aime_accesscode = &data->block[2].data[6];

char aime_accesscode_str[24 + 1];
snprintf(
aime_accesscode_str,
sizeof(aime_accesscode_str),
"%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x",
aime_accesscode[0],
aime_accesscode[1],
aime_accesscode[2],
aime_accesscode[3],
aime_accesscode[4],
aime_accesscode[5],
aime_accesscode[6],
aime_accesscode[7],
aime_accesscode[8],
aime_accesscode[9]);

// validate decimal hex representation
for(int i = 0; i < 24; i++) {
if(aime_accesscode_str[i] == ' ') continue;
if(aime_accesscode_str[i] < '0' || aime_accesscode_str[i] > '9') return false;
}

// Note: Aime access code has some other self-check algorithms that are not public.
// This parser does not try to verify the number.

furi_string_printf(
parsed_data,
"\e#Aime Card\nAccess Code: \n%s\nChecksum: %02X%02X%02X\n",
aime_accesscode_str,
aime_checksum[0],
aime_checksum[1],
aime_checksum[2]);

parsed = true;

} while(false);

return parsed;
}

/* Actual implementation of app<>plugin interface */
static const NfcSupportedCardsPlugin aime_plugin = {
.protocol = NfcProtocolMfClassic,
.verify = aime_verify,
.read = aime_read,
.parse = aime_parse,
};

/* Plugin descriptor to comply with basic plugin specification */
static const FlipperAppPluginDescriptor aime_plugin_descriptor = {
.appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID,
.ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION,
.entry_point = &aime_plugin,
};

/* Plugin entry point - must return a pointer to const descriptor */
const FlipperAppPluginDescriptor* aime_plugin_ep() {
return &aime_plugin_descriptor;
}

0 comments on commit d6fcb04

Please sign in to comment.