Merge branch 'fz-dev' into dev

This commit is contained in:
MX
2023-02-02 11:54:20 +03:00
62 changed files with 925 additions and 123 deletions

View File

@@ -1,5 +1,6 @@
#include "flipper_application.h"
#include "elf/elf_file.h"
#include <notification/notification_messages.h>
#define TAG "fapp"
@@ -95,6 +96,15 @@ static int32_t flipper_application_thread(void* context) {
elf_file_pre_run(last_loaded_app->elf);
int32_t result = elf_file_run(last_loaded_app->elf, context);
elf_file_post_run(last_loaded_app->elf);
// wait until all notifications from RAM are completed
NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION);
const NotificationSequence sequence_empty = {
NULL,
};
notification_message_block(notifications, &sequence_empty);
furi_record_close(RECORD_NOTIFICATION);
return result;
}

View File

@@ -136,17 +136,45 @@ LevelDuration protocol_paradox_encoder_yield(ProtocolParadox* protocol) {
return level_duration_make(level, duration);
};
static uint8_t protocol_paradox_calculate_checksum(uint8_t fc, uint16_t card_id) {
uint8_t card_hi = (card_id >> 8) & 0xff;
uint8_t card_lo = card_id & 0xff;
uint8_t arr[5] = {0, 0, fc, card_hi, card_lo};
uint8_t manchester[9];
bit_lib_push_bit(manchester, 9, false);
bit_lib_push_bit(manchester, 9, false);
bit_lib_push_bit(manchester, 9, false);
bit_lib_push_bit(manchester, 9, false);
for(uint8_t i = 6; i < 40; i += 1) {
if(bit_lib_get_bit(arr, i) == 0b1) {
bit_lib_push_bit(manchester, 9, true);
bit_lib_push_bit(manchester, 9, false);
} else {
bit_lib_push_bit(manchester, 9, false);
bit_lib_push_bit(manchester, 9, true);
}
}
uint8_t output = bit_lib_crc8(manchester, 9, 0x31, 0x00, true, true, 0x06);
return output;
}
void protocol_paradox_render_data(ProtocolParadox* protocol, FuriString* result) {
uint8_t* decoded_data = protocol->data;
uint8_t fc = bit_lib_get_bits(decoded_data, 10, 8);
uint16_t card_id = bit_lib_get_bits_16(decoded_data, 18, 16);
uint8_t card_crc = bit_lib_get_bits_16(decoded_data, 34, 8);
uint8_t calc_crc = protocol_paradox_calculate_checksum(fc, card_id);
furi_string_cat_printf(result, "Facility: %u\r\n", fc);
furi_string_cat_printf(result, "Card: %u\r\n", card_id);
furi_string_cat_printf(result, "Data: ");
for(size_t i = 0; i < PARADOX_DECODED_DATA_SIZE; i++) {
furi_string_cat_printf(result, "%02X", decoded_data[i]);
}
furi_string_cat_printf(result, "CRC: %u Calc CRC: %u\r\n", card_crc, calc_crc);
if(card_crc != calc_crc) furi_string_cat_printf(result, "CRC Mismatch, Invalid Card!\r\n");
};
void protocol_paradox_render_brief_data(ProtocolParadox* protocol, FuriString* result) {
@@ -154,8 +182,15 @@ void protocol_paradox_render_brief_data(ProtocolParadox* protocol, FuriString* r
uint8_t fc = bit_lib_get_bits(decoded_data, 10, 8);
uint16_t card_id = bit_lib_get_bits_16(decoded_data, 18, 16);
uint8_t card_crc = bit_lib_get_bits_16(decoded_data, 34, 8);
uint8_t calc_crc = protocol_paradox_calculate_checksum(fc, card_id);
furi_string_cat_printf(result, "FC: %03u, Card: %05u", fc, card_id);
furi_string_cat_printf(result, "FC: %03u, Card: %05u\r\n", fc, card_id);
if(calc_crc == card_crc) {
furi_string_cat_printf(result, "CRC : %03u", card_crc);
} else {
furi_string_cat_printf(result, "Card is Invalid!");
}
};
bool protocol_paradox_write_data(ProtocolParadox* protocol, void* data) {

View File

@@ -352,11 +352,27 @@ void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType
}
// Set SAK to 08
data->nfc_data.sak = 0x08;
} else if(type == MfClassicTypeMini) {
// Set every block to 0xFF
for(uint16_t i = 1; i < MF_MINI_TOTAL_SECTORS_NUM * 4; i += 1) {
if(mf_classic_is_sector_trailer(i)) {
nfc_generate_mf_classic_sector_trailer(mfc, i);
} else {
memset(&mfc->block[i].value, 0xFF, 16);
}
mf_classic_set_block_read(mfc, i, &mfc->block[i]);
}
// Set SAK to 09
data->nfc_data.sak = 0x09;
}
mfc->type = type;
}
static void nfc_generate_mf_mini(NfcDeviceData* data) {
nfc_generate_mf_classic(data, 4, MfClassicTypeMini);
}
static void nfc_generate_mf_classic_1k_4b_uid(NfcDeviceData* data) {
nfc_generate_mf_classic(data, 4, MfClassicType1k);
}
@@ -438,6 +454,11 @@ static const NfcGenerator ntag_i2c_plus_2k_generator = {
.generator_func = nfc_generate_ntag_i2c_plus_2k,
};
static const NfcGenerator mifare_mini_generator = {
.name = "Mifare Mini",
.generator_func = nfc_generate_mf_mini,
};
static const NfcGenerator mifare_classic_1k_4b_uid_generator = {
.name = "Mifare Classic 1k 4byte UID",
.generator_func = nfc_generate_mf_classic_1k_4b_uid,
@@ -472,6 +493,7 @@ const NfcGenerator* const nfc_generators[] = {
&ntag_i2c_2k_generator,
&ntag_i2c_plus_1k_generator,
&ntag_i2c_plus_2k_generator,
&mifare_mini_generator,
&mifare_classic_1k_4b_uid_generator,
&mifare_classic_1k_7b_uid_generator,
&mifare_classic_4k_4b_uid_generator,

View File

@@ -163,6 +163,7 @@ void reader_analyzer_stop(ReaderAnalyzer* instance) {
}
if(instance->pcap) {
nfc_debug_pcap_free(instance->pcap);
instance->pcap = NULL;
}
}

View File

@@ -773,7 +773,10 @@ static bool nfc_device_save_mifare_classic_data(FlipperFormat* file, NfcDevice*
do {
if(!flipper_format_write_comment_cstr(file, "Mifare Classic specific data")) break;
if(data->type == MfClassicType1k) {
if(data->type == MfClassicTypeMini) {
if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "MINI")) break;
blocks = 20;
} else if(data->type == MfClassicType1k) {
if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "1K")) break;
blocks = 64;
} else if(data->type == MfClassicType4k) {
@@ -871,7 +874,10 @@ static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice*
do {
// Read Mifare Classic type
if(!flipper_format_read_string(file, "Mifare Classic type", temp_str)) break;
if(!furi_string_cmp(temp_str, "1K")) {
if(!furi_string_cmp(temp_str, "MINI")) {
data->type = MfClassicTypeMini;
data_blocks = 20;
} else if(!furi_string_cmp(temp_str, "1K")) {
data->type = MfClassicType1k;
data_blocks = 64;
} else if(!furi_string_cmp(temp_str, "4K")) {
@@ -946,7 +952,9 @@ static bool nfc_device_save_mifare_classic_keys(NfcDevice* dev) {
if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break;
if(!flipper_format_write_header_cstr(file, nfc_keys_file_header, nfc_keys_file_version))
break;
if(data->type == MfClassicType1k) {
if(data->type == MfClassicTypeMini) {
if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "MINI")) break;
} else if(data->type == MfClassicType1k) {
if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "1K")) break;
} else if(data->type == MfClassicType4k) {
if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "4K")) break;
@@ -996,7 +1004,9 @@ bool nfc_device_load_key_cache(NfcDevice* dev) {
if(furi_string_cmp_str(temp_str, nfc_keys_file_header)) break;
if(version != nfc_keys_file_version) break;
if(!flipper_format_read_string(file, "Mifare Classic type", temp_str)) break;
if(!furi_string_cmp(temp_str, "1K")) {
if(!furi_string_cmp(temp_str, "MINI")) {
data->type = MfClassicTypeMini;
} else if(!furi_string_cmp(temp_str, "1K")) {
data->type = MfClassicType1k;
} else if(!furi_string_cmp(temp_str, "4K")) {
data->type = MfClassicType4k;

View File

@@ -55,7 +55,9 @@ const char* nfc_mf_ul_type(MfUltralightType type, bool full_name) {
}
const char* nfc_mf_classic_type(MfClassicType type) {
if(type == MfClassicType1k) {
if(type == MfClassicTypeMini) {
return "Mifare Mini 0.3K";
} else if(type == MfClassicType1k) {
return "Mifare Classic 1K";
} else if(type == MfClassicType4k) {
return "Mifare Classic 4K";

View File

@@ -142,21 +142,44 @@ static bool emv_decode_response(uint8_t* buff, uint16_t len, EmvApplication* app
success = true;
FURI_LOG_T(TAG, "found EMV_TAG_AFL %x (len=%d)", tag, tlen);
break;
case EMV_TAG_CARD_NUM: // Track 2 Equivalent Data. 0xD0 delimits PAN from expiry (YYMM)
case EMV_TAG_TRACK_1_EQUIV: {
char track_1_equiv[80];
memcpy(track_1_equiv, &buff[i], tlen);
track_1_equiv[tlen] = '\0';
success = true;
FURI_LOG_T(TAG, "found EMV_TAG_TRACK_1_EQUIV %x : %s", tag, track_1_equiv);
break;
}
case EMV_TAG_TRACK_2_EQUIV: {
// 0xD0 delimits PAN from expiry (YYMM)
for(int x = 1; x < tlen; x++) {
if(buff[i + x + 1] > 0xD0) {
memcpy(app->card_number, &buff[i], x + 1);
app->card_number_len = x + 1;
app->exp_year = (buff[i + x + 1] << 4) | (buff[i + x + 2] >> 4);
app->exp_month = (buff[i + x + 2] << 4) | (buff[i + x + 3] >> 4);
break;
}
}
// Convert 4-bit to ASCII representation
char track_2_equiv[41];
uint8_t track_2_equiv_len = 0;
for(int x = 0; x < tlen; x++) {
char top = (buff[i + x] >> 4) + '0';
char bottom = (buff[i + x] & 0x0F) + '0';
track_2_equiv[x * 2] = top;
track_2_equiv_len++;
if(top == '?') break;
track_2_equiv[x * 2 + 1] = bottom;
track_2_equiv_len++;
if(bottom == '?') break;
}
track_2_equiv[track_2_equiv_len] = '\0';
success = true;
FURI_LOG_T(
TAG,
"found EMV_TAG_CARD_NUM %x (len=%d)",
EMV_TAG_CARD_NUM,
app->card_number_len);
FURI_LOG_T(TAG, "found EMV_TAG_TRACK_2_EQUIV %x : %s", tag, track_2_equiv);
break;
}
case EMV_TAG_PAN:
memcpy(app->card_number, &buff[i], tlen);
app->card_number_len = tlen;

View File

@@ -11,7 +11,8 @@
#define EMV_TAG_CARD_NAME 0x50
#define EMV_TAG_FCI 0xBF0C
#define EMV_TAG_LOG_CTRL 0x9F4D
#define EMV_TAG_CARD_NUM 0x57
#define EMV_TAG_TRACK_1_EQUIV 0x56
#define EMV_TAG_TRACK_2_EQUIV 0x57
#define EMV_TAG_PAN 0x5A
#define EMV_TAG_AFL 0x94
#define EMV_TAG_EXP_DATE 0x5F24

View File

@@ -13,7 +13,9 @@
#define MF_CLASSIC_WRITE_BLOCK_CMD (0xA0)
const char* mf_classic_get_type_str(MfClassicType type) {
if(type == MfClassicType1k) {
if(type == MfClassicTypeMini) {
return "MIFARE Mini 0.3K";
} else if(type == MfClassicType1k) {
return "MIFARE Classic 1K";
} else if(type == MfClassicType4k) {
return "MIFARE Classic 4K";
@@ -73,7 +75,9 @@ MfClassicSectorTrailer*
}
uint8_t mf_classic_get_total_sectors_num(MfClassicType type) {
if(type == MfClassicType1k) {
if(type == MfClassicTypeMini) {
return MF_MINI_TOTAL_SECTORS_NUM;
} else if(type == MfClassicType1k) {
return MF_CLASSIC_1K_TOTAL_SECTORS_NUM;
} else if(type == MfClassicType4k) {
return MF_CLASSIC_4K_TOTAL_SECTORS_NUM;
@@ -83,7 +87,9 @@ uint8_t mf_classic_get_total_sectors_num(MfClassicType type) {
}
uint16_t mf_classic_get_total_block_num(MfClassicType type) {
if(type == MfClassicType1k) {
if(type == MfClassicTypeMini) {
return 20;
} else if(type == MfClassicType1k) {
return 64;
} else if(type == MfClassicType4k) {
return 256;
@@ -361,10 +367,14 @@ bool mf_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
}
}
MfClassicType mf_classic_get_classic_type(int8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
MfClassicType mf_classic_get_classic_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
UNUSED(ATQA1);
if((ATQA0 == 0x44 || ATQA0 == 0x04) && (SAK == 0x08 || SAK == 0x88 || SAK == 0x09)) {
return MfClassicType1k;
if((ATQA0 == 0x44 || ATQA0 == 0x04)) {
if((SAK == 0x08 || SAK == 0x88)) {
return MfClassicType1k;
} else if(SAK == 0x09) {
return MfClassicTypeMini;
}
} else if((ATQA0 == 0x01) && (ATQA1 == 0x0F) && (SAK == 0x01)) {
//skylanders support
return MfClassicType1k;
@@ -595,6 +605,14 @@ void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, u
if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) {
mf_classic_set_block_read(data, i, &block_tmp);
blocks_read++;
} else if(i > start_block) {
// Try to re-auth to read block in case prevous block was protected from read
furi_hal_nfc_sleep();
if(!mf_classic_auth(tx_rx, i, key, MfClassicKeyA, &crypto, false, 0)) break;
if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) {
mf_classic_set_block_read(data, i, &block_tmp);
blocks_read++;
}
}
} else {
blocks_read++;
@@ -607,13 +625,20 @@ void mf_classic_read_sector(FuriHalNfcTxRxContext* tx_rx, MfClassicData* data, u
if(!key_b_found) break;
FURI_LOG_D(TAG, "Try to read blocks with key B");
key = nfc_util_bytes2num(sec_tr->key_b, sizeof(sec_tr->key_b));
furi_hal_nfc_sleep();
if(!mf_classic_auth(tx_rx, start_block, key, MfClassicKeyB, &crypto, false, 0)) break;
for(size_t i = start_block; i < start_block + total_blocks; i++) {
if(!mf_classic_is_block_read(data, i)) {
if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) {
mf_classic_set_block_read(data, i, &block_tmp);
blocks_read++;
} else if(i > start_block) {
// Try to re-auth to read block in case prevous block was protected from read
furi_hal_nfc_sleep();
if(!mf_classic_auth(tx_rx, i, key, MfClassicKeyB, &crypto, false, 0)) break;
if(mf_classic_read_block(tx_rx, &crypto, i, &block_tmp)) {
mf_classic_set_block_read(data, i, &block_tmp);
blocks_read++;
}
}
} else {
blocks_read++;
@@ -665,6 +690,11 @@ static bool mf_classic_read_sector_with_reader(
// Read blocks
for(uint8_t i = 0; i < sector->total_blocks; i++) {
if(mf_classic_read_block(tx_rx, crypto, first_block + i, &sector->block[i])) continue;
if(i == 0) continue;
// Try to auth to read next block in case previous is locked
furi_hal_nfc_sleep();
if(!mf_classic_auth(tx_rx, first_block + i, key, key_type, crypto, false, 0)) continue;
mf_classic_read_block(tx_rx, crypto, first_block + i, &sector->block[i]);
}
// Save sector keys in last block

View File

@@ -6,6 +6,7 @@
#define MF_CLASSIC_BLOCK_SIZE (16)
#define MF_CLASSIC_TOTAL_BLOCKS_MAX (256)
#define MF_MINI_TOTAL_SECTORS_NUM (5)
#define MF_CLASSIC_1K_TOTAL_SECTORS_NUM (16)
#define MF_CLASSIC_4K_TOTAL_SECTORS_NUM (40)
@@ -20,6 +21,7 @@
typedef enum {
MfClassicType1k,
MfClassicType4k,
MfClassicTypeMini,
} MfClassicType;
typedef enum {
@@ -94,7 +96,7 @@ const char* mf_classic_get_type_str(MfClassicType type);
bool mf_classic_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK);
MfClassicType mf_classic_get_classic_type(int8_t ATQA0, uint8_t ATQA1, uint8_t SAK);
MfClassicType mf_classic_get_classic_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK);
uint8_t mf_classic_get_total_sectors_num(MfClassicType type);