nfc_device.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842
  1. #include "nfc_device.h"
  2. #include "nfc_types.h"
  3. #include <toolbox/path.h>
  4. #include <flipper_format/flipper_format.h>
  5. static const char* nfc_file_header = "Flipper NFC device";
  6. static const uint32_t nfc_file_version = 2;
  7. NfcDevice* nfc_device_alloc() {
  8. NfcDevice* nfc_dev = malloc(sizeof(NfcDevice));
  9. nfc_dev->storage = furi_record_open("storage");
  10. nfc_dev->dialogs = furi_record_open("dialogs");
  11. return nfc_dev;
  12. }
  13. void nfc_device_free(NfcDevice* nfc_dev) {
  14. furi_assert(nfc_dev);
  15. nfc_device_clear(nfc_dev);
  16. furi_record_close("storage");
  17. furi_record_close("dialogs");
  18. free(nfc_dev);
  19. }
  20. void nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string) {
  21. if(dev->format == NfcDeviceSaveFormatUid) {
  22. string_set_str(format_string, "UID");
  23. } else if(dev->format == NfcDeviceSaveFormatBankCard) {
  24. string_set_str(format_string, "Bank card");
  25. } else if(dev->format == NfcDeviceSaveFormatMifareUl) {
  26. string_set_str(format_string, nfc_mf_ul_type(dev->dev_data.mf_ul_data.type, true));
  27. } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
  28. string_set_str(format_string, "Mifare DESFire");
  29. } else {
  30. string_set_str(format_string, "Unknown");
  31. }
  32. }
  33. bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) {
  34. if(string_start_with_str_p(format_string, "UID")) {
  35. dev->format = NfcDeviceSaveFormatUid;
  36. dev->dev_data.nfc_data.protocol = NfcDeviceProtocolUnknown;
  37. return true;
  38. }
  39. if(string_start_with_str_p(format_string, "Bank card")) {
  40. dev->format = NfcDeviceSaveFormatBankCard;
  41. dev->dev_data.nfc_data.protocol = NfcDeviceProtocolEMV;
  42. return true;
  43. }
  44. // Check Mifare Ultralight types
  45. for(MfUltralightType type = MfUltralightTypeUnknown; type < MfUltralightTypeNum; type++) {
  46. if(string_start_with_str_p(format_string, nfc_mf_ul_type(type, true))) {
  47. dev->format = NfcDeviceSaveFormatMifareUl;
  48. dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareUl;
  49. dev->dev_data.mf_ul_data.type = type;
  50. return true;
  51. }
  52. }
  53. if(string_start_with_str_p(format_string, "Mifare DESFire")) {
  54. dev->format = NfcDeviceSaveFormatMifareDesfire;
  55. dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareDesfire;
  56. return true;
  57. }
  58. return false;
  59. }
  60. static bool nfc_device_save_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) {
  61. bool saved = false;
  62. MifareUlData* data = &dev->dev_data.mf_ul_data;
  63. string_t temp_str;
  64. string_init(temp_str);
  65. // Save Mifare Ultralight specific data
  66. do {
  67. if(!flipper_format_write_comment_cstr(file, "Mifare Ultralight specific data")) break;
  68. if(!flipper_format_write_hex(file, "Signature", data->signature, sizeof(data->signature)))
  69. break;
  70. if(!flipper_format_write_hex(
  71. file, "Mifare version", (uint8_t*)&data->version, sizeof(data->version)))
  72. break;
  73. // Write conters and tearing flags data
  74. bool counters_saved = true;
  75. for(uint8_t i = 0; i < 3; i++) {
  76. string_printf(temp_str, "Counter %d", i);
  77. if(!flipper_format_write_uint32(
  78. file, string_get_cstr(temp_str), &data->counter[i], 1)) {
  79. counters_saved = false;
  80. break;
  81. }
  82. string_printf(temp_str, "Tearing %d", i);
  83. if(!flipper_format_write_hex(file, string_get_cstr(temp_str), &data->tearing[i], 1)) {
  84. counters_saved = false;
  85. break;
  86. }
  87. }
  88. if(!counters_saved) break;
  89. // Write pages data
  90. uint32_t pages_total = data->data_size / 4;
  91. if(!flipper_format_write_uint32(file, "Pages total", &pages_total, 1)) break;
  92. bool pages_saved = true;
  93. for(uint16_t i = 0; i < data->data_size; i += 4) {
  94. string_printf(temp_str, "Page %d", i / 4);
  95. if(!flipper_format_write_hex(file, string_get_cstr(temp_str), &data->data[i], 4)) {
  96. pages_saved = false;
  97. break;
  98. }
  99. }
  100. if(!pages_saved) break;
  101. saved = true;
  102. } while(false);
  103. string_clear(temp_str);
  104. return saved;
  105. }
  106. bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) {
  107. bool parsed = false;
  108. MifareUlData* data = &dev->dev_data.mf_ul_data;
  109. string_t temp_str;
  110. string_init(temp_str);
  111. do {
  112. // Read signature
  113. if(!flipper_format_read_hex(file, "Signature", data->signature, sizeof(data->signature)))
  114. break;
  115. // Read Mifare version
  116. if(!flipper_format_read_hex(
  117. file, "Mifare version", (uint8_t*)&data->version, sizeof(data->version)))
  118. break;
  119. // Read counters and tearing flags
  120. bool counters_parsed = true;
  121. for(uint8_t i = 0; i < 3; i++) {
  122. string_printf(temp_str, "Counter %d", i);
  123. if(!flipper_format_read_uint32(file, string_get_cstr(temp_str), &data->counter[i], 1)) {
  124. counters_parsed = false;
  125. break;
  126. }
  127. string_printf(temp_str, "Tearing %d", i);
  128. if(!flipper_format_read_hex(file, string_get_cstr(temp_str), &data->tearing[i], 1)) {
  129. counters_parsed = false;
  130. break;
  131. }
  132. }
  133. if(!counters_parsed) break;
  134. // Read pages
  135. uint32_t pages = 0;
  136. if(!flipper_format_read_uint32(file, "Pages total", &pages, 1)) break;
  137. data->data_size = pages * 4;
  138. bool pages_parsed = true;
  139. for(uint16_t i = 0; i < pages; i++) {
  140. string_printf(temp_str, "Page %d", i);
  141. if(!flipper_format_read_hex(file, string_get_cstr(temp_str), &data->data[i * 4], 4)) {
  142. pages_parsed = false;
  143. break;
  144. }
  145. }
  146. if(!pages_parsed) break;
  147. parsed = true;
  148. } while(false);
  149. string_clear(temp_str);
  150. return parsed;
  151. }
  152. static bool nfc_device_save_mifare_df_key_settings(
  153. FlipperFormat* file,
  154. MifareDesfireKeySettings* ks,
  155. const char* prefix) {
  156. bool saved = false;
  157. string_t key;
  158. string_init(key);
  159. do {
  160. string_printf(key, "%s Change Key ID", prefix);
  161. if(!flipper_format_write_hex(file, string_get_cstr(key), &ks->change_key_id, 1)) break;
  162. string_printf(key, "%s Config Changeable", prefix);
  163. if(!flipper_format_write_bool(file, string_get_cstr(key), &ks->config_changeable, 1))
  164. break;
  165. string_printf(key, "%s Free Create Delete", prefix);
  166. if(!flipper_format_write_bool(file, string_get_cstr(key), &ks->free_create_delete, 1))
  167. break;
  168. string_printf(key, "%s Free Directory List", prefix);
  169. if(!flipper_format_write_bool(file, string_get_cstr(key), &ks->free_directory_list, 1))
  170. break;
  171. string_printf(key, "%s Key Changeable", prefix);
  172. if(!flipper_format_write_bool(file, string_get_cstr(key), &ks->master_key_changeable, 1))
  173. break;
  174. string_printf(key, "%s Max Keys", prefix);
  175. if(!flipper_format_write_hex(file, string_get_cstr(key), &ks->max_keys, 1)) break;
  176. for(MifareDesfireKeyVersion* kv = ks->key_version_head; kv; kv = kv->next) {
  177. string_printf(key, "%s Key %d Version", prefix, kv->id);
  178. if(!flipper_format_write_hex(file, string_get_cstr(key), &kv->version, 1)) break;
  179. }
  180. saved = true;
  181. } while(false);
  182. string_clear(key);
  183. return saved;
  184. }
  185. bool nfc_device_load_mifare_df_key_settings(
  186. FlipperFormat* file,
  187. MifareDesfireKeySettings* ks,
  188. const char* prefix) {
  189. bool parsed = false;
  190. string_t key;
  191. string_init(key);
  192. do {
  193. string_printf(key, "%s Change Key ID", prefix);
  194. if(!flipper_format_read_hex(file, string_get_cstr(key), &ks->change_key_id, 1)) break;
  195. string_printf(key, "%s Config Changeable", prefix);
  196. if(!flipper_format_read_bool(file, string_get_cstr(key), &ks->config_changeable, 1)) break;
  197. string_printf(key, "%s Free Create Delete", prefix);
  198. if(!flipper_format_read_bool(file, string_get_cstr(key), &ks->free_create_delete, 1))
  199. break;
  200. string_printf(key, "%s Free Directory List", prefix);
  201. if(!flipper_format_read_bool(file, string_get_cstr(key), &ks->free_directory_list, 1))
  202. break;
  203. string_printf(key, "%s Key Changeable", prefix);
  204. if(!flipper_format_read_bool(file, string_get_cstr(key), &ks->master_key_changeable, 1))
  205. break;
  206. string_printf(key, "%s Max Keys", prefix);
  207. if(!flipper_format_read_hex(file, string_get_cstr(key), &ks->max_keys, 1)) break;
  208. MifareDesfireKeyVersion** kv_head = &ks->key_version_head;
  209. for(int key_id = 0; key_id < ks->max_keys; key_id++) {
  210. string_printf(key, "%s Key %d Version", prefix, key_id);
  211. uint8_t version;
  212. if(flipper_format_read_hex(file, string_get_cstr(key), &version, 1)) {
  213. MifareDesfireKeyVersion* kv = malloc(sizeof(MifareDesfireKeyVersion));
  214. memset(kv, 0, sizeof(MifareDesfireKeyVersion));
  215. kv->id = key_id;
  216. kv->version = version;
  217. *kv_head = kv;
  218. kv_head = &kv->next;
  219. }
  220. }
  221. parsed = true;
  222. } while(false);
  223. string_clear(key);
  224. return parsed;
  225. }
  226. static bool nfc_device_save_mifare_df_app(FlipperFormat* file, MifareDesfireApplication* app) {
  227. bool saved = false;
  228. string_t prefix, key;
  229. string_init_printf(prefix, "Application %02x%02x%02x", app->id[0], app->id[1], app->id[2]);
  230. string_init(key);
  231. uint8_t* tmp = NULL;
  232. do {
  233. if(app->key_settings) {
  234. if(!nfc_device_save_mifare_df_key_settings(
  235. file, app->key_settings, string_get_cstr(prefix)))
  236. break;
  237. }
  238. uint32_t n_files = 0;
  239. for(MifareDesfireFile* f = app->file_head; f; f = f->next) {
  240. n_files++;
  241. }
  242. tmp = malloc(n_files);
  243. int i = 0;
  244. for(MifareDesfireFile* f = app->file_head; f; f = f->next) {
  245. tmp[i++] = f->id;
  246. }
  247. string_printf(key, "%s File IDs", string_get_cstr(prefix));
  248. if(!flipper_format_write_hex(file, string_get_cstr(key), tmp, n_files)) break;
  249. bool saved_files = true;
  250. for(MifareDesfireFile* f = app->file_head; f; f = f->next) {
  251. saved_files = false;
  252. string_printf(key, "%s File %d Type", string_get_cstr(prefix), f->id);
  253. if(!flipper_format_write_hex(file, string_get_cstr(key), &f->type, 1)) break;
  254. string_printf(
  255. key, "%s File %d Communication Settings", string_get_cstr(prefix), f->id);
  256. if(!flipper_format_write_hex(file, string_get_cstr(key), &f->comm, 1)) break;
  257. string_printf(key, "%s File %d Access Rights", string_get_cstr(prefix), f->id);
  258. if(!flipper_format_write_hex(
  259. file, string_get_cstr(key), (uint8_t*)&f->access_rights, 2))
  260. break;
  261. uint16_t size = 0;
  262. if(f->type == MifareDesfireFileTypeStandard ||
  263. f->type == MifareDesfireFileTypeBackup) {
  264. size = f->settings.data.size;
  265. string_printf(key, "%s File %d Size", string_get_cstr(prefix), f->id);
  266. if(!flipper_format_write_uint32(
  267. file, string_get_cstr(key), &f->settings.data.size, 1))
  268. break;
  269. } else if(f->type == MifareDesfireFileTypeValue) {
  270. string_printf(key, "%s File %d Hi Limit", string_get_cstr(prefix), f->id);
  271. if(!flipper_format_write_uint32(
  272. file, string_get_cstr(key), &f->settings.value.hi_limit, 1))
  273. break;
  274. string_printf(key, "%s File %d Lo Limit", string_get_cstr(prefix), f->id);
  275. if(!flipper_format_write_uint32(
  276. file, string_get_cstr(key), &f->settings.value.lo_limit, 1))
  277. break;
  278. string_printf(
  279. key, "%s File %d Limited Credit Value", string_get_cstr(prefix), f->id);
  280. if(!flipper_format_write_uint32(
  281. file, string_get_cstr(key), &f->settings.value.limited_credit_value, 1))
  282. break;
  283. string_printf(
  284. key, "%s File %d Limited Credit Enabled", string_get_cstr(prefix), f->id);
  285. if(!flipper_format_write_bool(
  286. file, string_get_cstr(key), &f->settings.value.limited_credit_enabled, 1))
  287. break;
  288. size = 4;
  289. } else if(
  290. f->type == MifareDesfireFileTypeLinearRecord ||
  291. f->type == MifareDesfireFileTypeCyclicRecord) {
  292. string_printf(key, "%s File %d Size", string_get_cstr(prefix), f->id);
  293. if(!flipper_format_write_uint32(
  294. file, string_get_cstr(key), &f->settings.record.size, 1))
  295. break;
  296. string_printf(key, "%s File %d Max", string_get_cstr(prefix), f->id);
  297. if(!flipper_format_write_uint32(
  298. file, string_get_cstr(key), &f->settings.record.max, 1))
  299. break;
  300. string_printf(key, "%s File %d Cur", string_get_cstr(prefix), f->id);
  301. if(!flipper_format_write_uint32(
  302. file, string_get_cstr(key), &f->settings.record.cur, 1))
  303. break;
  304. size = f->settings.record.size * f->settings.record.cur;
  305. }
  306. if(f->contents) {
  307. string_printf(key, "%s File %d", string_get_cstr(prefix), f->id);
  308. if(!flipper_format_write_hex(file, string_get_cstr(key), f->contents, size)) break;
  309. }
  310. saved_files = true;
  311. }
  312. if(!saved_files) {
  313. break;
  314. }
  315. saved = true;
  316. } while(false);
  317. free(tmp);
  318. string_clear(prefix);
  319. string_clear(key);
  320. return saved;
  321. }
  322. bool nfc_device_load_mifare_df_app(FlipperFormat* file, MifareDesfireApplication* app) {
  323. bool parsed = false;
  324. string_t prefix, key;
  325. string_init_printf(prefix, "Application %02x%02x%02x", app->id[0], app->id[1], app->id[2]);
  326. string_init(key);
  327. uint8_t* tmp = NULL;
  328. MifareDesfireFile* f = NULL;
  329. do {
  330. app->key_settings = malloc(sizeof(MifareDesfireKeySettings));
  331. memset(app->key_settings, 0, sizeof(MifareDesfireKeySettings));
  332. if(!nfc_device_load_mifare_df_key_settings(
  333. file, app->key_settings, string_get_cstr(prefix))) {
  334. free(app->key_settings);
  335. app->key_settings = NULL;
  336. break;
  337. }
  338. string_printf(key, "%s File IDs", string_get_cstr(prefix));
  339. uint32_t n_files;
  340. if(!flipper_format_get_value_count(file, string_get_cstr(key), &n_files)) break;
  341. tmp = malloc(n_files);
  342. if(!flipper_format_read_hex(file, string_get_cstr(key), tmp, n_files)) break;
  343. MifareDesfireFile** file_head = &app->file_head;
  344. bool parsed_files = true;
  345. for(int i = 0; i < n_files; i++) {
  346. parsed_files = false;
  347. f = malloc(sizeof(MifareDesfireFile));
  348. memset(f, 0, sizeof(MifareDesfireFile));
  349. f->id = tmp[i];
  350. string_printf(key, "%s File %d Type", string_get_cstr(prefix), f->id);
  351. if(!flipper_format_read_hex(file, string_get_cstr(key), &f->type, 1)) break;
  352. string_printf(
  353. key, "%s File %d Communication Settings", string_get_cstr(prefix), f->id);
  354. if(!flipper_format_read_hex(file, string_get_cstr(key), &f->comm, 1)) break;
  355. string_printf(key, "%s File %d Access Rights", string_get_cstr(prefix), f->id);
  356. if(!flipper_format_read_hex(file, string_get_cstr(key), (uint8_t*)&f->access_rights, 2))
  357. break;
  358. if(f->type == MifareDesfireFileTypeStandard ||
  359. f->type == MifareDesfireFileTypeBackup) {
  360. string_printf(key, "%s File %d Size", string_get_cstr(prefix), f->id);
  361. if(!flipper_format_read_uint32(
  362. file, string_get_cstr(key), &f->settings.data.size, 1))
  363. break;
  364. } else if(f->type == MifareDesfireFileTypeValue) {
  365. string_printf(key, "%s File %d Hi Limit", string_get_cstr(prefix), f->id);
  366. if(!flipper_format_read_uint32(
  367. file, string_get_cstr(key), &f->settings.value.hi_limit, 1))
  368. break;
  369. string_printf(key, "%s File %d Lo Limit", string_get_cstr(prefix), f->id);
  370. if(!flipper_format_read_uint32(
  371. file, string_get_cstr(key), &f->settings.value.lo_limit, 1))
  372. break;
  373. string_printf(
  374. key, "%s File %d Limited Credit Value", string_get_cstr(prefix), f->id);
  375. if(!flipper_format_read_uint32(
  376. file, string_get_cstr(key), &f->settings.value.limited_credit_value, 1))
  377. break;
  378. string_printf(
  379. key, "%s File %d Limited Credit Enabled", string_get_cstr(prefix), f->id);
  380. if(!flipper_format_read_bool(
  381. file, string_get_cstr(key), &f->settings.value.limited_credit_enabled, 1))
  382. break;
  383. } else if(
  384. f->type == MifareDesfireFileTypeLinearRecord ||
  385. f->type == MifareDesfireFileTypeCyclicRecord) {
  386. string_printf(key, "%s File %d Size", string_get_cstr(prefix), f->id);
  387. if(!flipper_format_read_uint32(
  388. file, string_get_cstr(key), &f->settings.record.size, 1))
  389. break;
  390. string_printf(key, "%s File %d Max", string_get_cstr(prefix), f->id);
  391. if(!flipper_format_read_uint32(
  392. file, string_get_cstr(key), &f->settings.record.max, 1))
  393. break;
  394. string_printf(key, "%s File %d Cur", string_get_cstr(prefix), f->id);
  395. if(!flipper_format_read_uint32(
  396. file, string_get_cstr(key), &f->settings.record.cur, 1))
  397. break;
  398. }
  399. string_printf(key, "%s File %d", string_get_cstr(prefix), f->id);
  400. if(flipper_format_key_exist(file, string_get_cstr(key))) {
  401. uint32_t size;
  402. if(!flipper_format_get_value_count(file, string_get_cstr(key), &size)) break;
  403. f->contents = malloc(size);
  404. if(!flipper_format_read_hex(file, string_get_cstr(key), f->contents, size)) break;
  405. }
  406. *file_head = f;
  407. file_head = &f->next;
  408. f = NULL;
  409. parsed_files = true;
  410. }
  411. if(!parsed_files) {
  412. break;
  413. }
  414. parsed = true;
  415. } while(false);
  416. if(f) {
  417. free(f->contents);
  418. free(f);
  419. }
  420. free(tmp);
  421. string_clear(prefix);
  422. string_clear(key);
  423. return parsed;
  424. }
  425. static bool nfc_device_save_mifare_df_data(FlipperFormat* file, NfcDevice* dev) {
  426. bool saved = false;
  427. MifareDesfireData* data = &dev->dev_data.mf_df_data;
  428. uint8_t* tmp = NULL;
  429. do {
  430. if(!flipper_format_write_comment_cstr(file, "Mifare DESFire specific data")) break;
  431. if(!flipper_format_write_hex(
  432. file, "PICC Version", (uint8_t*)&data->version, sizeof(data->version)))
  433. break;
  434. if(data->free_memory) {
  435. if(!flipper_format_write_uint32(file, "PICC Free Memory", &data->free_memory->bytes, 1))
  436. break;
  437. }
  438. if(data->master_key_settings) {
  439. if(!nfc_device_save_mifare_df_key_settings(file, data->master_key_settings, "PICC"))
  440. break;
  441. }
  442. uint32_t n_apps = 0;
  443. for(MifareDesfireApplication* app = data->app_head; app; app = app->next) {
  444. n_apps++;
  445. }
  446. if(!flipper_format_write_uint32(file, "Application Count", &n_apps, 1)) break;
  447. tmp = malloc(n_apps * 3);
  448. int i = 0;
  449. for(MifareDesfireApplication* app = data->app_head; app; app = app->next) {
  450. memcpy(tmp + i, app->id, 3);
  451. i += 3;
  452. }
  453. if(!flipper_format_write_hex(file, "Application IDs", tmp, n_apps * 3)) break;
  454. for(MifareDesfireApplication* app = data->app_head; app; app = app->next) {
  455. if(!nfc_device_save_mifare_df_app(file, app)) break;
  456. }
  457. saved = true;
  458. } while(false);
  459. free(tmp);
  460. return saved;
  461. }
  462. bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) {
  463. bool parsed = false;
  464. MifareDesfireData* data = &dev->dev_data.mf_df_data;
  465. memset(data, 0, sizeof(MifareDesfireData));
  466. uint8_t* tmp = NULL;
  467. do {
  468. if(!flipper_format_read_hex(
  469. file, "PICC Version", (uint8_t*)&data->version, sizeof(data->version)))
  470. break;
  471. if(flipper_format_key_exist(file, "PICC Free Memory")) {
  472. data->free_memory = malloc(sizeof(MifareDesfireFreeMemory));
  473. memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory));
  474. if(!flipper_format_read_uint32(
  475. file, "PICC Free Memory", &data->free_memory->bytes, 1)) {
  476. free(data->free_memory);
  477. break;
  478. }
  479. }
  480. data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings));
  481. memset(data->master_key_settings, 0, sizeof(MifareDesfireKeySettings));
  482. if(!nfc_device_load_mifare_df_key_settings(file, data->master_key_settings, "PICC")) {
  483. free(data->master_key_settings);
  484. data->master_key_settings = NULL;
  485. break;
  486. }
  487. uint32_t n_apps;
  488. if(!flipper_format_read_uint32(file, "Application Count", &n_apps, 1)) break;
  489. tmp = malloc(n_apps * 3);
  490. if(!flipper_format_read_hex(file, "Application IDs", tmp, n_apps * 3)) break;
  491. bool parsed_apps = true;
  492. MifareDesfireApplication** app_head = &data->app_head;
  493. for(int i = 0; i < n_apps; i++) {
  494. MifareDesfireApplication* app = malloc(sizeof(MifareDesfireApplication));
  495. memset(app, 0, sizeof(MifareDesfireApplication));
  496. memcpy(app->id, &tmp[i * 3], 3);
  497. if(!nfc_device_load_mifare_df_app(file, app)) {
  498. free(app);
  499. parsed_apps = false;
  500. break;
  501. }
  502. *app_head = app;
  503. app_head = &app->next;
  504. }
  505. if(!parsed_apps) break;
  506. parsed = true;
  507. } while(false);
  508. free(tmp);
  509. return parsed;
  510. }
  511. static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
  512. bool saved = false;
  513. NfcEmvData* data = &dev->dev_data.emv_data;
  514. uint32_t data_temp = 0;
  515. do {
  516. // Write Bank card specific data
  517. if(!flipper_format_write_comment_cstr(file, "Bank card specific data")) break;
  518. if(!flipper_format_write_hex(file, "AID", data->aid, data->aid_len)) break;
  519. if(!flipper_format_write_string_cstr(file, "Name", data->name)) break;
  520. if(!flipper_format_write_hex(file, "Number", data->number, data->number_len)) break;
  521. if(data->exp_mon) {
  522. uint8_t exp_data[2] = {data->exp_mon, data->exp_year};
  523. if(!flipper_format_write_hex(file, "Exp data", exp_data, sizeof(exp_data))) break;
  524. }
  525. if(data->country_code) {
  526. data_temp = data->country_code;
  527. if(!flipper_format_write_uint32(file, "Country code", &data_temp, 1)) break;
  528. }
  529. if(data->currency_code) {
  530. data_temp = data->currency_code;
  531. if(!flipper_format_write_uint32(file, "Currency code", &data_temp, 1)) break;
  532. }
  533. saved = true;
  534. } while(false);
  535. return saved;
  536. }
  537. bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) {
  538. bool parsed = false;
  539. NfcEmvData* data = &dev->dev_data.emv_data;
  540. memset(data, 0, sizeof(NfcEmvData));
  541. uint32_t data_cnt = 0;
  542. string_t temp_str;
  543. string_init(temp_str);
  544. do {
  545. // Load essential data
  546. if(!flipper_format_get_value_count(file, "AID", &data_cnt)) break;
  547. data->aid_len = data_cnt;
  548. if(!flipper_format_read_hex(file, "AID", data->aid, data->aid_len)) break;
  549. if(!flipper_format_read_string(file, "Name", temp_str)) break;
  550. strlcpy(data->name, string_get_cstr(temp_str), sizeof(data->name));
  551. if(!flipper_format_get_value_count(file, "Number", &data_cnt)) break;
  552. data->number_len = data_cnt;
  553. if(!flipper_format_read_hex(file, "Number", data->number, data->number_len)) break;
  554. parsed = true;
  555. // Load optional data
  556. uint8_t exp_data[2] = {};
  557. if(flipper_format_read_hex(file, "Exp data", exp_data, 2)) {
  558. data->exp_mon = exp_data[0];
  559. data->exp_year = exp_data[1];
  560. }
  561. if(flipper_format_read_uint32(file, "Country code", &data_cnt, 1)) {
  562. data->country_code = data_cnt;
  563. }
  564. if(flipper_format_read_uint32(file, "Currency code", &data_cnt, 1)) {
  565. data->currency_code = data_cnt;
  566. }
  567. } while(false);
  568. string_clear(temp_str);
  569. return parsed;
  570. }
  571. void nfc_device_set_name(NfcDevice* dev, const char* name) {
  572. furi_assert(dev);
  573. strlcpy(dev->dev_name, name, NFC_DEV_NAME_MAX_LEN);
  574. }
  575. static bool nfc_device_save_file(
  576. NfcDevice* dev,
  577. const char* dev_name,
  578. const char* folder,
  579. const char* extension) {
  580. furi_assert(dev);
  581. bool saved = false;
  582. FlipperFormat* file = flipper_format_file_alloc(dev->storage);
  583. NfcDeviceCommonData* data = &dev->dev_data.nfc_data;
  584. string_t temp_str;
  585. string_init(temp_str);
  586. do {
  587. // Create nfc directory if necessary
  588. if(!storage_simply_mkdir(dev->storage, NFC_APP_FOLDER)) break;
  589. // First remove nfc device file if it was saved
  590. string_printf(temp_str, "%s/%s%s", folder, dev_name, extension);
  591. // Open file
  592. if(!flipper_format_file_open_always(file, string_get_cstr(temp_str))) break;
  593. // Write header
  594. if(!flipper_format_write_header_cstr(file, nfc_file_header, nfc_file_version)) break;
  595. // Write nfc device type
  596. if(!flipper_format_write_comment_cstr(
  597. file, "Nfc device type can be UID, Mifare Ultralight, Bank card"))
  598. break;
  599. nfc_device_prepare_format_string(dev, temp_str);
  600. if(!flipper_format_write_string(file, "Device type", temp_str)) break;
  601. // Write UID, ATQA, SAK
  602. if(!flipper_format_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats"))
  603. break;
  604. if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break;
  605. if(!flipper_format_write_hex(file, "ATQA", data->atqa, 2)) break;
  606. if(!flipper_format_write_hex(file, "SAK", &data->sak, 1)) break;
  607. // Save more data if necessary
  608. if(dev->format == NfcDeviceSaveFormatMifareUl) {
  609. if(!nfc_device_save_mifare_ul_data(file, dev)) break;
  610. } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
  611. if(!nfc_device_save_mifare_df_data(file, dev)) break;
  612. } else if(dev->format == NfcDeviceSaveFormatBankCard) {
  613. if(!nfc_device_save_bank_card_data(file, dev)) break;
  614. }
  615. saved = true;
  616. } while(0);
  617. if(!saved) {
  618. dialog_message_show_storage_error(dev->dialogs, "Can not save\nkey file");
  619. }
  620. string_clear(temp_str);
  621. flipper_format_free(file);
  622. return saved;
  623. }
  624. bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
  625. return nfc_device_save_file(dev, dev_name, NFC_APP_FOLDER, NFC_APP_EXTENSION);
  626. }
  627. bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) {
  628. dev->shadow_file_exist = true;
  629. return nfc_device_save_file(dev, dev_name, NFC_APP_FOLDER, NFC_APP_SHADOW_EXTENSION);
  630. }
  631. static bool nfc_device_load_data(NfcDevice* dev, string_t path) {
  632. bool parsed = false;
  633. FlipperFormat* file = flipper_format_file_alloc(dev->storage);
  634. NfcDeviceCommonData* data = &dev->dev_data.nfc_data;
  635. uint32_t data_cnt = 0;
  636. string_t temp_str;
  637. string_init(temp_str);
  638. bool depricated_version = false;
  639. do {
  640. // Check existance of shadow file
  641. size_t ext_start = string_search_str(path, NFC_APP_EXTENSION);
  642. string_set_n(temp_str, path, 0, ext_start);
  643. string_cat_printf(temp_str, "%s", NFC_APP_SHADOW_EXTENSION);
  644. dev->shadow_file_exist =
  645. storage_common_stat(dev->storage, string_get_cstr(temp_str), NULL) == FSE_OK;
  646. // Open shadow file if it exists. If not - open original
  647. if(dev->shadow_file_exist) {
  648. if(!flipper_format_file_open_existing(file, string_get_cstr(temp_str))) break;
  649. } else {
  650. if(!flipper_format_file_open_existing(file, string_get_cstr(path))) break;
  651. }
  652. // Read and verify file header
  653. uint32_t version = 0;
  654. if(!flipper_format_read_header(file, temp_str, &version)) break;
  655. if(string_cmp_str(temp_str, nfc_file_header) || (version != nfc_file_version)) {
  656. depricated_version = true;
  657. break;
  658. }
  659. // Read Nfc device type
  660. if(!flipper_format_read_string(file, "Device type", temp_str)) break;
  661. if(!nfc_device_parse_format_string(dev, temp_str)) break;
  662. // Read and parse UID, ATQA and SAK
  663. if(!flipper_format_get_value_count(file, "UID", &data_cnt)) break;
  664. data->uid_len = data_cnt;
  665. if(!flipper_format_read_hex(file, "UID", data->uid, data->uid_len)) break;
  666. if(!flipper_format_read_hex(file, "ATQA", data->atqa, 2)) break;
  667. if(!flipper_format_read_hex(file, "SAK", &data->sak, 1)) break;
  668. // Parse other data
  669. if(dev->format == NfcDeviceSaveFormatMifareUl) {
  670. if(!nfc_device_load_mifare_ul_data(file, dev)) break;
  671. } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) {
  672. if(!nfc_device_load_mifare_df_data(file, dev)) break;
  673. } else if(dev->format == NfcDeviceSaveFormatBankCard) {
  674. if(!nfc_device_load_bank_card_data(file, dev)) break;
  675. }
  676. parsed = true;
  677. } while(false);
  678. if(!parsed) {
  679. if(depricated_version) {
  680. dialog_message_show_storage_error(dev->dialogs, "File format depricated");
  681. } else {
  682. dialog_message_show_storage_error(dev->dialogs, "Can not parse\nfile");
  683. }
  684. }
  685. string_clear(temp_str);
  686. flipper_format_free(file);
  687. return parsed;
  688. }
  689. bool nfc_device_load(NfcDevice* dev, const char* file_path) {
  690. furi_assert(dev);
  691. furi_assert(file_path);
  692. // Load device data
  693. string_t path;
  694. string_init_set_str(path, file_path);
  695. bool dev_load = nfc_device_load_data(dev, path);
  696. if(dev_load) {
  697. // Set device name
  698. path_extract_filename_no_ext(file_path, path);
  699. nfc_device_set_name(dev, string_get_cstr(path));
  700. }
  701. string_clear(path);
  702. return dev_load;
  703. }
  704. bool nfc_file_select(NfcDevice* dev) {
  705. furi_assert(dev);
  706. // Input events and views are managed by file_select
  707. bool res = dialog_file_select_show(
  708. dev->dialogs,
  709. NFC_APP_FOLDER,
  710. NFC_APP_EXTENSION,
  711. dev->file_name,
  712. sizeof(dev->file_name),
  713. dev->dev_name);
  714. if(res) {
  715. string_t dev_str;
  716. // Get key file path
  717. string_init_printf(dev_str, "%s/%s%s", NFC_APP_FOLDER, dev->file_name, NFC_APP_EXTENSION);
  718. res = nfc_device_load_data(dev, dev_str);
  719. if(res) {
  720. nfc_device_set_name(dev, dev->file_name);
  721. }
  722. string_clear(dev_str);
  723. }
  724. return res;
  725. }
  726. void nfc_device_data_clear(NfcDeviceData* dev_data) {
  727. if(dev_data->nfc_data.protocol == NfcDeviceProtocolMifareDesfire) {
  728. mf_df_clear(&dev_data->mf_df_data);
  729. }
  730. }
  731. void nfc_device_clear(NfcDevice* dev) {
  732. furi_assert(dev);
  733. nfc_device_data_clear(&dev->dev_data);
  734. memset(&dev->dev_data, 0, sizeof(dev->dev_data));
  735. dev->format = NfcDeviceSaveFormatUid;
  736. }
  737. bool nfc_device_delete(NfcDevice* dev) {
  738. furi_assert(dev);
  739. bool deleted = false;
  740. string_t file_path;
  741. string_init(file_path);
  742. do {
  743. // Delete original file
  744. string_init_printf(file_path, "%s/%s%s", NFC_APP_FOLDER, dev->dev_name, NFC_APP_EXTENSION);
  745. if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break;
  746. // Delete shadow file if it exists
  747. if(dev->shadow_file_exist) {
  748. string_printf(
  749. file_path, "%s/%s%s", NFC_APP_FOLDER, dev->dev_name, NFC_APP_SHADOW_EXTENSION);
  750. if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break;
  751. }
  752. deleted = true;
  753. } while(0);
  754. if(!deleted) {
  755. dialog_message_show_storage_error(dev->dialogs, "Can not remove file");
  756. }
  757. string_clear(file_path);
  758. return deleted;
  759. }
  760. bool nfc_device_restore(NfcDevice* dev) {
  761. furi_assert(dev);
  762. furi_assert(dev->shadow_file_exist);
  763. bool restored = false;
  764. string_t path;
  765. do {
  766. string_init_printf(
  767. path, "%s/%s%s", NFC_APP_FOLDER, dev->dev_name, NFC_APP_SHADOW_EXTENSION);
  768. if(!storage_simply_remove(dev->storage, string_get_cstr(path))) break;
  769. dev->shadow_file_exist = false;
  770. string_printf(path, "%s/%s%s", NFC_APP_FOLDER, dev->dev_name, NFC_APP_EXTENSION);
  771. if(!nfc_device_load_data(dev, path)) break;
  772. restored = true;
  773. } while(0);
  774. string_clear(path);
  775. return restored;
  776. }