mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2024-12-29 16:25:47 +03:00
d92b0a82cc
"A long time ago in a galaxy far, far away...." we started NFC subsystem refactoring. Starring: - @gornekich - NFC refactoring project lead, architect, senior developer - @gsurkov - architect, senior developer - @RebornedBrain - senior developer Supporting roles: - @skotopes, @DrZlo13, @hedger - general architecture advisors, code review - @Astrrra, @doomwastaken, @Hellitron, @ImagineVagon333 - quality assurance Special thanks: @bettse, @pcunning, @nxv, @noproto, @AloneLiberty and everyone else who has been helping us all this time and contributing valuable knowledges, ideas and source code.
187 lines
5.0 KiB
C
187 lines
5.0 KiB
C
#include "iso14443_3a.h"
|
|
|
|
#include <furi.h>
|
|
#include <nfc/nfc_common.h>
|
|
|
|
#define ISO14443A_ATS_BIT (1U << 5)
|
|
|
|
#define ISO14443_3A_PROTOCOL_NAME_LEGACY "UID"
|
|
#define ISO14443_3A_PROTOCOL_NAME "ISO14443-3A"
|
|
#define ISO14443_3A_DEVICE_NAME "ISO14443-3A (Unknown)"
|
|
|
|
#define ISO14443_3A_ATQA_KEY "ATQA"
|
|
#define ISO14443_3A_SAK_KEY "SAK"
|
|
|
|
const NfcDeviceBase nfc_device_iso14443_3a = {
|
|
.protocol_name = ISO14443_3A_PROTOCOL_NAME,
|
|
.alloc = (NfcDeviceAlloc)iso14443_3a_alloc,
|
|
.free = (NfcDeviceFree)iso14443_3a_free,
|
|
.reset = (NfcDeviceReset)iso14443_3a_reset,
|
|
.copy = (NfcDeviceCopy)iso14443_3a_copy,
|
|
.verify = (NfcDeviceVerify)iso14443_3a_verify,
|
|
.load = (NfcDeviceLoad)iso14443_3a_load,
|
|
.save = (NfcDeviceSave)iso14443_3a_save,
|
|
.is_equal = (NfcDeviceEqual)iso14443_3a_is_equal,
|
|
.get_name = (NfcDeviceGetName)iso14443_3a_get_device_name,
|
|
.get_uid = (NfcDeviceGetUid)iso14443_3a_get_uid,
|
|
.set_uid = (NfcDeviceSetUid)iso14443_3a_set_uid,
|
|
.get_base_data = (NfcDeviceGetBaseData)iso14443_3a_get_base_data,
|
|
};
|
|
|
|
Iso14443_3aData* iso14443_3a_alloc() {
|
|
Iso14443_3aData* data = malloc(sizeof(Iso14443_3aData));
|
|
return data;
|
|
}
|
|
|
|
void iso14443_3a_free(Iso14443_3aData* data) {
|
|
furi_assert(data);
|
|
|
|
free(data);
|
|
}
|
|
|
|
void iso14443_3a_reset(Iso14443_3aData* data) {
|
|
furi_assert(data);
|
|
memset(data, 0, sizeof(Iso14443_3aData));
|
|
}
|
|
|
|
void iso14443_3a_copy(Iso14443_3aData* data, const Iso14443_3aData* other) {
|
|
furi_assert(data);
|
|
furi_assert(other);
|
|
|
|
*data = *other;
|
|
}
|
|
|
|
bool iso14443_3a_verify(Iso14443_3aData* data, const FuriString* device_type) {
|
|
UNUSED(data);
|
|
return furi_string_equal(device_type, ISO14443_3A_PROTOCOL_NAME_LEGACY);
|
|
}
|
|
|
|
bool iso14443_3a_load(Iso14443_3aData* data, FlipperFormat* ff, uint32_t version) {
|
|
furi_assert(data);
|
|
|
|
bool parsed = false;
|
|
|
|
do {
|
|
// Common to all format versions
|
|
if(!flipper_format_read_hex(ff, ISO14443_3A_ATQA_KEY, data->atqa, 2)) break;
|
|
if(!flipper_format_read_hex(ff, ISO14443_3A_SAK_KEY, &data->sak, 1)) break;
|
|
|
|
if(version > NFC_LSB_ATQA_FORMAT_VERSION) {
|
|
// Swap ATQA bytes for newer versions
|
|
FURI_SWAP(data->atqa[0], data->atqa[1]);
|
|
}
|
|
|
|
parsed = true;
|
|
} while(false);
|
|
|
|
return parsed;
|
|
}
|
|
|
|
bool iso14443_3a_save(const Iso14443_3aData* data, FlipperFormat* ff) {
|
|
furi_assert(data);
|
|
|
|
bool saved = false;
|
|
|
|
do {
|
|
// Save ATQA in MSB order for correct companion apps display
|
|
const uint8_t atqa[2] = {data->atqa[1], data->atqa[0]};
|
|
if(!flipper_format_write_comment_cstr(ff, ISO14443_3A_PROTOCOL_NAME " specific data"))
|
|
break;
|
|
|
|
// Write ATQA and SAK
|
|
if(!flipper_format_write_hex(ff, ISO14443_3A_ATQA_KEY, atqa, 2)) break;
|
|
if(!flipper_format_write_hex(ff, ISO14443_3A_SAK_KEY, &data->sak, 1)) break;
|
|
saved = true;
|
|
} while(false);
|
|
|
|
return saved;
|
|
}
|
|
|
|
bool iso14443_3a_is_equal(const Iso14443_3aData* data, const Iso14443_3aData* other) {
|
|
furi_assert(data);
|
|
furi_assert(other);
|
|
|
|
return memcmp(data, other, sizeof(Iso14443_3aData)) == 0;
|
|
}
|
|
|
|
const char* iso14443_3a_get_device_name(const Iso14443_3aData* data, NfcDeviceNameType name_type) {
|
|
UNUSED(data);
|
|
UNUSED(name_type);
|
|
return ISO14443_3A_DEVICE_NAME;
|
|
}
|
|
|
|
const uint8_t* iso14443_3a_get_uid(const Iso14443_3aData* data, size_t* uid_len) {
|
|
furi_assert(data);
|
|
|
|
if(uid_len) {
|
|
*uid_len = data->uid_len;
|
|
}
|
|
|
|
return data->uid;
|
|
}
|
|
|
|
bool iso14443_3a_set_uid(Iso14443_3aData* data, const uint8_t* uid, size_t uid_len) {
|
|
furi_assert(data);
|
|
|
|
const bool uid_valid = uid_len == ISO14443_3A_UID_4_BYTES ||
|
|
uid_len == ISO14443_3A_UID_7_BYTES ||
|
|
uid_len == ISO14443_3A_UID_10_BYTES;
|
|
|
|
if(uid_valid) {
|
|
memcpy(data->uid, uid, uid_len);
|
|
data->uid_len = uid_len;
|
|
}
|
|
|
|
return uid_valid;
|
|
}
|
|
|
|
Iso14443_3aData* iso14443_3a_get_base_data(const Iso14443_3aData* data) {
|
|
UNUSED(data);
|
|
furi_crash("No base data");
|
|
}
|
|
|
|
uint32_t iso14443_3a_get_cuid(const Iso14443_3aData* data) {
|
|
furi_assert(data);
|
|
|
|
uint32_t cuid = 0;
|
|
const uint8_t* cuid_start = data->uid;
|
|
if(data->uid_len == ISO14443_3A_UID_7_BYTES) {
|
|
cuid_start = &data->uid[3];
|
|
}
|
|
cuid = (cuid_start[0] << 24) | (cuid_start[1] << 16) | (cuid_start[2] << 8) | (cuid_start[3]);
|
|
|
|
return cuid;
|
|
}
|
|
|
|
bool iso14443_3a_supports_iso14443_4(const Iso14443_3aData* data) {
|
|
furi_assert(data);
|
|
|
|
return data->sak & ISO14443A_ATS_BIT;
|
|
}
|
|
|
|
uint8_t iso14443_3a_get_sak(const Iso14443_3aData* data) {
|
|
furi_assert(data);
|
|
|
|
return data->sak;
|
|
}
|
|
|
|
void iso14443_3a_get_atqa(const Iso14443_3aData* data, uint8_t atqa[2]) {
|
|
furi_assert(data);
|
|
furi_assert(atqa);
|
|
|
|
memcpy(atqa, data->atqa, sizeof(data->atqa));
|
|
}
|
|
|
|
void iso14443_3a_set_sak(Iso14443_3aData* data, uint8_t sak) {
|
|
furi_assert(data);
|
|
|
|
data->sak = sak;
|
|
}
|
|
|
|
void iso14443_3a_set_atqa(Iso14443_3aData* data, const uint8_t atqa[2]) {
|
|
furi_assert(data);
|
|
furi_assert(atqa);
|
|
|
|
memcpy(data->atqa, atqa, sizeof(data->atqa));
|
|
}
|