Mifare Ultralight authentication (#1365)
* mifare ultralight auth prototype * it works! * Reference source * use countof * rework everything * oops forgot scenes * build: revert changes in manifest, stack size * build: fix buid, format sources * nfc: update unlock ultralight GUI * nfc: fix byte input header * nfc: add new scenes for locked ultralight * nfc: add data read to ultralights * nfc: add unlock option in mf ultralight menu * nfc: add data read init in ultralight generation * nfc: lin sources, fix unlocked save * nfc: format python sources * nfc: clean up Co-authored-by: gornekich <n.gorbadey@gmail.com>
This commit is contained in:
committed by
GitHub
parent
d147190d61
commit
9ffcc52ada
@@ -1,10 +1,39 @@
|
||||
#include <limits.h>
|
||||
#include <mbedtls/sha1.h>
|
||||
#include "mifare_ultralight.h"
|
||||
#include "nfc_util.h"
|
||||
#include <furi.h>
|
||||
#include "furi_hal_nfc.h"
|
||||
#include <m-string.h>
|
||||
|
||||
#define TAG "MfUltralight"
|
||||
|
||||
// Algorithms from: https://github.com/RfidResearchGroup/proxmark3/blob/0f6061c16f072372b7d4d381911f1542afbc3a69/common/generator.c#L110
|
||||
uint32_t mf_ul_pwdgen_xiaomi(FuriHalNfcDevData* data) {
|
||||
uint8_t hash[20];
|
||||
mbedtls_sha1(data->uid, data->uid_len, hash);
|
||||
|
||||
uint32_t pwd = 0;
|
||||
pwd |= (hash[hash[0] % 20]) << 24;
|
||||
pwd |= (hash[(hash[0] + 5) % 20]) << 16;
|
||||
pwd |= (hash[(hash[0] + 13) % 20]) << 8;
|
||||
pwd |= (hash[(hash[0] + 17) % 20]);
|
||||
|
||||
return pwd;
|
||||
}
|
||||
|
||||
uint32_t mf_ul_pwdgen_amiibo(FuriHalNfcDevData* data) {
|
||||
uint8_t* uid = data->uid;
|
||||
|
||||
uint32_t pwd = 0;
|
||||
pwd |= (uid[1] ^ uid[3] ^ 0xAA) << 24;
|
||||
pwd |= (uid[2] ^ uid[4] ^ 0x55) << 16;
|
||||
pwd |= (uid[3] ^ uid[5] ^ 0xAA) << 8;
|
||||
pwd |= uid[4] ^ uid[6] ^ 0x55;
|
||||
|
||||
return pwd;
|
||||
}
|
||||
|
||||
bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
|
||||
if((ATQA0 == 0x44) && (ATQA1 == 0x00) && (SAK == 0x00)) {
|
||||
return true;
|
||||
@@ -12,6 +41,20 @@ bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void mf_ul_reset(MfUltralightData* data) {
|
||||
furi_assert(data);
|
||||
data->type = MfUltralightTypeUnknown;
|
||||
memset(&data->version, 0, sizeof(MfUltralightVersion));
|
||||
memset(data->signature, 0, sizeof(data->signature));
|
||||
memset(data->counter, 0, sizeof(data->counter));
|
||||
memset(data->tearing, 0, sizeof(data->tearing));
|
||||
memset(data->data, 0, sizeof(data->data));
|
||||
data->data_size = 0;
|
||||
data->data_read = 0;
|
||||
data->curr_authlim = 0;
|
||||
data->has_auth = false;
|
||||
}
|
||||
|
||||
static MfUltralightFeatures mf_ul_get_features(MfUltralightType type) {
|
||||
switch(type) {
|
||||
case MfUltralightTypeUL11:
|
||||
@@ -127,6 +170,37 @@ bool mf_ultralight_read_version(
|
||||
return version_read;
|
||||
}
|
||||
|
||||
bool mf_ultralight_authenticate(FuriHalNfcTxRxContext* tx_rx, uint32_t key, uint16_t* pack) {
|
||||
bool authenticated = false;
|
||||
|
||||
do {
|
||||
FURI_LOG_D(TAG, "Authenticating");
|
||||
tx_rx->tx_data[0] = MF_UL_AUTH;
|
||||
nfc_util_num2bytes(key, 4, &tx_rx->tx_data[1]);
|
||||
tx_rx->tx_bits = 40;
|
||||
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||
if(!furi_hal_nfc_tx_rx(tx_rx, 50)) {
|
||||
FURI_LOG_D(TAG, "Tag did not respond to authentication");
|
||||
break;
|
||||
}
|
||||
|
||||
// PACK
|
||||
if(tx_rx->rx_bits < 2 * 8) {
|
||||
FURI_LOG_D(TAG, "Authentication failed");
|
||||
break;
|
||||
}
|
||||
|
||||
if(pack != NULL) {
|
||||
*pack = (tx_rx->rx_data[0] << 8) | tx_rx->rx_data[1];
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Auth success. Password: %08X. PACK: %04X", key, *pack);
|
||||
authenticated = true;
|
||||
} while(false);
|
||||
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
static int16_t mf_ultralight_page_addr_to_tag_addr(uint8_t sector, uint8_t page) {
|
||||
return sector * 256 + page;
|
||||
}
|
||||
@@ -413,7 +487,7 @@ static int16_t mf_ultralight_ntag_i2c_addr_tag_to_lin(
|
||||
}
|
||||
}
|
||||
|
||||
static MfUltralightConfigPages* mf_ultralight_get_config_pages(MfUltralightData* data) {
|
||||
MfUltralightConfigPages* mf_ultralight_get_config_pages(MfUltralightData* data) {
|
||||
if(data->type >= MfUltralightTypeUL11 && data->type <= MfUltralightTypeNTAG216) {
|
||||
return (MfUltralightConfigPages*)&data->data[data->data_size - 4 * 4];
|
||||
} else if(
|
||||
@@ -516,6 +590,7 @@ bool mf_ultralight_read_pages(
|
||||
tx_rx->tx_data[1] = tag_page;
|
||||
tx_rx->tx_bits = 16;
|
||||
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||
|
||||
if(!furi_hal_nfc_tx_rx(tx_rx, 50) || tx_rx->rx_bits < 16 * 8) {
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
@@ -524,17 +599,19 @@ bool mf_ultralight_read_pages(
|
||||
i + (valid_pages > 4 ? 4 : valid_pages) - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
if(valid_pages > 4) {
|
||||
pages_read_cnt = 4;
|
||||
} else {
|
||||
pages_read_cnt = valid_pages;
|
||||
}
|
||||
reader->pages_read += pages_read_cnt;
|
||||
data->data_size = reader->pages_read * 4;
|
||||
memcpy(&data->data[i * 4], tx_rx->rx_data, pages_read_cnt * 4);
|
||||
}
|
||||
data->data_size = reader->pages_to_read * 4;
|
||||
data->data_read = reader->pages_read * 4;
|
||||
|
||||
return reader->pages_read == reader->pages_to_read;
|
||||
return reader->pages_read > 0;
|
||||
}
|
||||
|
||||
bool mf_ultralight_fast_read_pages(
|
||||
@@ -620,6 +697,48 @@ bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData*
|
||||
return counter_read == (is_single_counter ? 1 : 3);
|
||||
}
|
||||
|
||||
int16_t mf_ultralight_get_authlim(
|
||||
FuriHalNfcTxRxContext* tx_rx,
|
||||
MfUltralightReader* reader,
|
||||
MfUltralightData* data) {
|
||||
mf_ultralight_read_version(tx_rx, reader, data);
|
||||
if(!(reader->supported_features & MfUltralightSupportAuth)) {
|
||||
// No authentication
|
||||
return -2;
|
||||
}
|
||||
|
||||
uint8_t config_pages_index;
|
||||
if(data->type >= MfUltralightTypeUL11 && data->type <= MfUltralightTypeNTAG216) {
|
||||
config_pages_index = reader->pages_to_read - 4;
|
||||
} else if(
|
||||
data->type >= MfUltralightTypeNTAGI2CPlus1K &&
|
||||
data->type <= MfUltralightTypeNTAGI2CPlus1K) {
|
||||
config_pages_index = 0xe3;
|
||||
} else {
|
||||
// No config pages
|
||||
return -2;
|
||||
}
|
||||
|
||||
if(!mf_ultralight_read_pages_direct(tx_rx, config_pages_index, data->data)) {
|
||||
// Config pages are not readable due to protection
|
||||
return -1;
|
||||
}
|
||||
|
||||
MfUltralightConfigPages* config_pages = (MfUltralightConfigPages*)&data->data;
|
||||
if(config_pages->auth0 >= reader->pages_to_read) {
|
||||
// Authentication is not configured
|
||||
return -2;
|
||||
}
|
||||
|
||||
int16_t authlim = config_pages->access.authlim;
|
||||
if(authlim > 0 && data->type >= MfUltralightTypeNTAGI2CPlus1K &&
|
||||
data->type <= MfUltralightTypeNTAGI2CPlus2K) {
|
||||
authlim = 1 << authlim;
|
||||
}
|
||||
|
||||
return authlim;
|
||||
}
|
||||
|
||||
bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data) {
|
||||
uint8_t flag_read = 0;
|
||||
|
||||
|
@@ -28,6 +28,12 @@
|
||||
|
||||
#define MF_UL_NTAG203_COUNTER_PAGE (41)
|
||||
|
||||
typedef enum {
|
||||
MfUltralightAuthMethodManual,
|
||||
MfUltralightAuthMethodAmeebo,
|
||||
MfUltralightAuthMethodXiaomi,
|
||||
} MfUltralightAuthMethod;
|
||||
|
||||
// Important: order matters; some features are based on positioning in this enum
|
||||
typedef enum {
|
||||
MfUltralightTypeUnknown,
|
||||
@@ -50,6 +56,13 @@ typedef enum {
|
||||
MfUltralightTypeNum,
|
||||
} MfUltralightType;
|
||||
|
||||
typedef enum {
|
||||
MfUltralightAuthLimitUnknown,
|
||||
MfUltralightAuthLimitNotSupported,
|
||||
MfUltralightAuthLimitConfigured,
|
||||
MfUltralightAuthLimitNotConfigured,
|
||||
} MfUltralightAuthLimit;
|
||||
|
||||
typedef enum {
|
||||
MfUltralightSupportNone = 0,
|
||||
MfUltralightSupportFastRead = 1 << 0,
|
||||
@@ -104,9 +117,14 @@ typedef struct {
|
||||
uint8_t signature[32];
|
||||
uint32_t counter[3];
|
||||
uint8_t tearing[3];
|
||||
bool has_auth;
|
||||
MfUltralightAuthMethod auth_method;
|
||||
uint8_t auth_key[4];
|
||||
bool auth_success;
|
||||
uint16_t curr_authlim;
|
||||
uint16_t data_size;
|
||||
uint8_t data[MF_UL_MAX_DUMP_SIZE];
|
||||
uint16_t data_read;
|
||||
} MfUltralightData;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
@@ -176,6 +194,8 @@ typedef struct {
|
||||
bool read_counter_incremented;
|
||||
} MfUltralightEmulator;
|
||||
|
||||
void mf_ul_reset(MfUltralightData* data);
|
||||
|
||||
bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK);
|
||||
|
||||
bool mf_ultralight_read_version(
|
||||
@@ -204,6 +224,10 @@ bool mf_ultralight_read_counters(FuriHalNfcTxRxContext* tx_rx, MfUltralightData*
|
||||
|
||||
bool mf_ultralight_read_tearing_flags(FuriHalNfcTxRxContext* tx_rx, MfUltralightData* data);
|
||||
|
||||
bool mf_ultralight_authenticate(FuriHalNfcTxRxContext* tx_rx, uint32_t key, uint16_t* pack);
|
||||
|
||||
MfUltralightConfigPages* mf_ultralight_get_config_pages(MfUltralightData* data);
|
||||
|
||||
bool mf_ul_read_card(
|
||||
FuriHalNfcTxRxContext* tx_rx,
|
||||
MfUltralightReader* reader,
|
||||
@@ -220,3 +244,12 @@ bool mf_ul_prepare_emulation_response(
|
||||
uint16_t* buff_tx_len,
|
||||
uint32_t* data_type,
|
||||
void* context);
|
||||
|
||||
int16_t mf_ultralight_get_authlim(
|
||||
FuriHalNfcTxRxContext* tx_rx,
|
||||
MfUltralightReader* reader,
|
||||
MfUltralightData* data);
|
||||
|
||||
uint32_t mf_ul_pwdgen_amiibo(FuriHalNfcDevData* data);
|
||||
|
||||
uint32_t mf_ul_pwdgen_xiaomi(FuriHalNfcDevData* data);
|
||||
|
Reference in New Issue
Block a user