| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451 |
- #include "mifare_desfire.h"
- #include <furi.h>
- #include <furi_hal_nfc.h>
- void mf_df_clear(MifareDesfireData* data) {
- free(data->free_memory);
- if(data->master_key_settings) {
- MifareDesfireKeyVersion* key_version = data->master_key_settings->key_version_head;
- while(key_version) {
- MifareDesfireKeyVersion* next_key_version = key_version->next;
- free(key_version);
- key_version = next_key_version;
- }
- }
- free(data->master_key_settings);
- MifareDesfireApplication* app = data->app_head;
- while(app) {
- MifareDesfireApplication* next_app = app->next;
- if(app->key_settings) {
- MifareDesfireKeyVersion* key_version = app->key_settings->key_version_head;
- while(key_version) {
- MifareDesfireKeyVersion* next_key_version = key_version->next;
- free(key_version);
- key_version = next_key_version;
- }
- }
- free(app->key_settings);
- MifareDesfireFile* file = app->file_head;
- while(file) {
- MifareDesfireFile* next_file = file->next;
- free(file->contents);
- free(file);
- file = next_file;
- }
- free(app);
- app = next_app;
- }
- data->free_memory = NULL;
- data->master_key_settings = NULL;
- data->app_head = NULL;
- }
- void mf_df_cat_data(MifareDesfireData* data, string_t out) {
- mf_df_cat_card_info(data, out);
- for(MifareDesfireApplication* app = data->app_head; app; app = app->next) {
- mf_df_cat_application(app, out);
- }
- }
- void mf_df_cat_card_info(MifareDesfireData* data, string_t out) {
- mf_df_cat_version(&data->version, out);
- if(data->free_memory) {
- mf_df_cat_free_mem(data->free_memory, out);
- }
- if(data->master_key_settings) {
- mf_df_cat_key_settings(data->master_key_settings, out);
- }
- }
- void mf_df_cat_version(MifareDesfireVersion* version, string_t out) {
- string_cat_printf(
- out,
- "%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
- version->uid[0],
- version->uid[1],
- version->uid[2],
- version->uid[3],
- version->uid[4],
- version->uid[5],
- version->uid[6]);
- string_cat_printf(
- out,
- "hw %02x type %02x sub %02x\n"
- " maj %02x min %02x\n"
- " size %02x proto %02x\n",
- version->hw_vendor,
- version->hw_type,
- version->hw_subtype,
- version->hw_major,
- version->hw_minor,
- version->hw_storage,
- version->hw_proto);
- string_cat_printf(
- out,
- "sw %02x type %02x sub %02x\n"
- " maj %02x min %02x\n"
- " size %02x proto %02x\n",
- version->sw_vendor,
- version->sw_type,
- version->sw_subtype,
- version->sw_major,
- version->sw_minor,
- version->sw_storage,
- version->sw_proto);
- string_cat_printf(
- out,
- "batch %02x:%02x:%02x:%02x:%02x\n"
- "week %d year %d\n",
- version->batch[0],
- version->batch[1],
- version->batch[2],
- version->batch[3],
- version->batch[4],
- version->prod_week,
- version->prod_year);
- }
- void mf_df_cat_free_mem(MifareDesfireFreeMemory* free_mem, string_t out) {
- string_cat_printf(out, "freeMem %d\n", free_mem->bytes);
- }
- void mf_df_cat_key_settings(MifareDesfireKeySettings* ks, string_t out) {
- string_cat_printf(out, "changeKeyID %d\n", ks->change_key_id);
- string_cat_printf(out, "configChangeable %d\n", ks->config_changeable);
- string_cat_printf(out, "freeCreateDelete %d\n", ks->free_create_delete);
- string_cat_printf(out, "freeDirectoryList %d\n", ks->free_directory_list);
- string_cat_printf(out, "masterChangeable %d\n", ks->master_key_changeable);
- if(ks->flags) {
- string_cat_printf(out, "flags %d\n", ks->flags);
- }
- string_cat_printf(out, "maxKeys %d\n", ks->max_keys);
- for(MifareDesfireKeyVersion* kv = ks->key_version_head; kv; kv = kv->next) {
- string_cat_printf(out, "key %d version %d\n", kv->id, kv->version);
- }
- }
- void mf_df_cat_application_info(MifareDesfireApplication* app, string_t out) {
- string_cat_printf(out, "Application %02x%02x%02x\n", app->id[0], app->id[1], app->id[2]);
- if(app->key_settings) {
- mf_df_cat_key_settings(app->key_settings, out);
- }
- }
- void mf_df_cat_application(MifareDesfireApplication* app, string_t out) {
- mf_df_cat_application_info(app, out);
- for(MifareDesfireFile* file = app->file_head; file; file = file->next) {
- mf_df_cat_file(file, out);
- }
- }
- void mf_df_cat_file(MifareDesfireFile* file, string_t out) {
- char* type = "unknown";
- switch(file->type) {
- case MifareDesfireFileTypeStandard:
- type = "standard";
- break;
- case MifareDesfireFileTypeBackup:
- type = "backup";
- break;
- case MifareDesfireFileTypeValue:
- type = "value";
- break;
- case MifareDesfireFileTypeLinearRecord:
- type = "linear";
- break;
- case MifareDesfireFileTypeCyclicRecord:
- type = "cyclic";
- break;
- }
- char* comm = "unknown";
- switch(file->comm) {
- case MifareDesfireFileCommunicationSettingsPlaintext:
- comm = "plain";
- break;
- case MifareDesfireFileCommunicationSettingsAuthenticated:
- comm = "auth";
- break;
- case MifareDesfireFileCommunicationSettingsEnciphered:
- comm = "enciphered";
- break;
- }
- string_cat_printf(out, "File %d\n", file->id);
- string_cat_printf(out, "%s %s\n", type, comm);
- string_cat_printf(
- out,
- "r %d w %d rw %d c %d\n",
- file->access_rights >> 12 & 0xF,
- file->access_rights >> 8 & 0xF,
- file->access_rights >> 4 & 0xF,
- file->access_rights & 0xF);
- uint16_t size = 0;
- uint16_t num = 1;
- switch(file->type) {
- case MifareDesfireFileTypeStandard:
- case MifareDesfireFileTypeBackup:
- size = file->settings.data.size;
- string_cat_printf(out, "size %d\n", size);
- break;
- case MifareDesfireFileTypeValue:
- size = 4;
- string_cat_printf(
- out, "lo %d hi %d\n", file->settings.value.lo_limit, file->settings.value.hi_limit);
- string_cat_printf(
- out,
- "limit %d enabled %d\n",
- file->settings.value.limited_credit_value,
- file->settings.value.limited_credit_enabled);
- break;
- case MifareDesfireFileTypeLinearRecord:
- case MifareDesfireFileTypeCyclicRecord:
- size = file->settings.record.size;
- num = file->settings.record.cur;
- string_cat_printf(out, "size %d\n", size);
- string_cat_printf(out, "num %d max %d\n", num, file->settings.record.max);
- break;
- }
- uint8_t* data = file->contents;
- if(data) {
- for(int rec = 0; rec < num; rec++) {
- for(int ch = 0; ch < size; ch++) {
- string_cat_printf(out, "%02x", data[rec * size + ch]);
- }
- string_cat_printf(out, " \n");
- }
- }
- }
- bool mf_df_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK) {
- return ATQA0 == 0x44 && ATQA1 == 0x03 && SAK == 0x20;
- }
- uint16_t mf_df_prepare_get_version(uint8_t* dest) {
- dest[0] = MF_DF_GET_VERSION;
- return 1;
- }
- bool mf_df_parse_get_version_response(uint8_t* buf, uint16_t len, MifareDesfireVersion* out) {
- if(len < 1 || *buf) {
- return false;
- }
- len--;
- buf++;
- if(len < sizeof(MifareDesfireVersion)) {
- return false;
- }
- memcpy(out, buf, sizeof(MifareDesfireVersion));
- return true;
- }
- uint16_t mf_df_prepare_get_free_memory(uint8_t* dest) {
- dest[0] = MF_DF_GET_FREE_MEMORY;
- return 1;
- }
- bool mf_df_parse_get_free_memory_response(uint8_t* buf, uint16_t len, MifareDesfireFreeMemory* out) {
- if(len < 1 || *buf) {
- return false;
- }
- len--;
- buf++;
- if(len != 3) {
- return false;
- }
- out->bytes = buf[0] | (buf[1] << 8) | (buf[2] << 16);
- return true;
- }
- uint16_t mf_df_prepare_get_key_settings(uint8_t* dest) {
- dest[0] = MF_DF_GET_KEY_SETTINGS;
- return 1;
- }
- bool mf_df_parse_get_key_settings_response(
- uint8_t* buf,
- uint16_t len,
- MifareDesfireKeySettings* out) {
- if(len < 1 || *buf) {
- return false;
- }
- len--;
- buf++;
- if(len < 2) {
- return false;
- }
- out->change_key_id = buf[0] >> 4;
- out->config_changeable = (buf[0] & 0x8) != 0;
- out->free_create_delete = (buf[0] & 0x4) != 0;
- out->free_directory_list = (buf[0] & 0x2) != 0;
- out->master_key_changeable = (buf[0] & 0x1) != 0;
- out->flags = buf[1] >> 4;
- out->max_keys = buf[1] & 0xF;
- return true;
- }
- uint16_t mf_df_prepare_get_key_version(uint8_t* dest, uint8_t key_id) {
- dest[0] = MF_DF_GET_KEY_VERSION;
- dest[1] = key_id;
- return 2;
- }
- bool mf_df_parse_get_key_version_response(uint8_t* buf, uint16_t len, MifareDesfireKeyVersion* out) {
- if(len != 2 || *buf) {
- return false;
- }
- out->version = buf[1];
- return true;
- }
- uint16_t mf_df_prepare_get_application_ids(uint8_t* dest) {
- dest[0] = MF_DF_GET_APPLICATION_IDS;
- return 1;
- }
- bool mf_df_parse_get_application_ids_response(
- uint8_t* buf,
- uint16_t len,
- MifareDesfireApplication** app_head) {
- if(len < 1 || *buf) {
- return false;
- }
- len--;
- buf++;
- if(len % 3 != 0) {
- return false;
- }
- while(len) {
- MifareDesfireApplication* app = malloc(sizeof(MifareDesfireApplication));
- memset(app, 0, sizeof(MifareDesfireApplication));
- memcpy(app->id, buf, 3);
- len -= 3;
- buf += 3;
- *app_head = app;
- app_head = &app->next;
- }
- return true;
- }
- uint16_t mf_df_prepare_select_application(uint8_t* dest, uint8_t id[3]) {
- dest[0] = MF_DF_SELECT_APPLICATION;
- dest[1] = id[0];
- dest[2] = id[1];
- dest[3] = id[2];
- return 4;
- }
- bool mf_df_parse_select_application_response(uint8_t* buf, uint16_t len) {
- return len == 1 && !*buf;
- }
- uint16_t mf_df_prepare_get_file_ids(uint8_t* dest) {
- dest[0] = MF_DF_GET_FILE_IDS;
- return 1;
- }
- bool mf_df_parse_get_file_ids_response(uint8_t* buf, uint16_t len, MifareDesfireFile** file_head) {
- if(len < 1 || *buf) {
- return false;
- }
- len--;
- buf++;
- while(len) {
- MifareDesfireFile* file = malloc(sizeof(MifareDesfireFile));
- memset(file, 0, sizeof(MifareDesfireFile));
- file->id = *buf;
- len--;
- buf++;
- *file_head = file;
- file_head = &file->next;
- }
- return true;
- }
- uint16_t mf_df_prepare_get_file_settings(uint8_t* dest, uint8_t file_id) {
- dest[0] = MF_DF_GET_FILE_SETTINGS;
- dest[1] = file_id;
- return 2;
- }
- bool mf_df_parse_get_file_settings_response(uint8_t* buf, uint16_t len, MifareDesfireFile* out) {
- if(len < 5 || *buf) {
- return false;
- }
- len--;
- buf++;
- out->type = buf[0];
- out->comm = buf[1];
- out->access_rights = buf[2] | (buf[3] << 8);
- switch(out->type) {
- case MifareDesfireFileTypeStandard:
- case MifareDesfireFileTypeBackup:
- if(len != 7) {
- return false;
- }
- out->settings.data.size = buf[4] | (buf[5] << 8) | (buf[6] << 16);
- break;
- case MifareDesfireFileTypeValue:
- if(len != 17) {
- return false;
- }
- out->settings.value.lo_limit = buf[4] | (buf[5] << 8) | (buf[6] << 16) | (buf[7] << 24);
- out->settings.value.hi_limit = buf[8] | (buf[9] << 8) | (buf[10] << 16) | (buf[11] << 24);
- out->settings.value.limited_credit_value = buf[12] | (buf[13] << 8) | (buf[14] << 16) |
- (buf[15] << 24);
- out->settings.value.limited_credit_enabled = buf[16];
- break;
- case MifareDesfireFileTypeLinearRecord:
- case MifareDesfireFileTypeCyclicRecord:
- if(len != 13) {
- return false;
- }
- out->settings.record.size = buf[4] | (buf[5] << 8) | (buf[6] << 16);
- out->settings.record.max = buf[7] | (buf[8] << 8) | (buf[9] << 16);
- out->settings.record.cur = buf[10] | (buf[11] << 8) | (buf[12] << 16);
- break;
- default:
- return false;
- }
- return true;
- }
- uint16_t mf_df_prepare_read_data(uint8_t* dest, uint8_t file_id, uint32_t offset, uint32_t len) {
- dest[0] = MF_DF_READ_DATA;
- dest[1] = file_id;
- dest[2] = offset;
- dest[3] = offset >> 8;
- dest[4] = offset >> 16;
- dest[5] = len;
- dest[6] = len >> 8;
- dest[7] = len >> 16;
- return 8;
- }
- uint16_t mf_df_prepare_get_value(uint8_t* dest, uint8_t file_id) {
- dest[0] = MF_DF_GET_VALUE;
- dest[1] = file_id;
- return 2;
- }
- uint16_t
- mf_df_prepare_read_records(uint8_t* dest, uint8_t file_id, uint32_t offset, uint32_t len) {
- dest[0] = MF_DF_READ_RECORDS;
- dest[1] = file_id;
- dest[2] = offset;
- dest[3] = offset >> 8;
- dest[4] = offset >> 16;
- dest[5] = len;
- dest[6] = len >> 8;
- dest[7] = len >> 16;
- return 8;
- }
- bool mf_df_parse_read_data_response(uint8_t* buf, uint16_t len, MifareDesfireFile* out) {
- if(len < 1 || *buf) {
- return false;
- }
- len--;
- buf++;
- out->contents = malloc(len);
- memcpy(out->contents, buf, len);
- return true;
- }
|