nfc_device.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. #include "nfc_device.h"
  2. #include "nfc_types.h"
  3. #include <lib/toolbox/path.h>
  4. #include <lib/flipper_file/flipper_file.h>
  5. static const char* nfc_app_folder = "/any/nfc";
  6. static const char* nfc_app_extension = ".nfc";
  7. static const char* nfc_app_shadow_extension = ".shd";
  8. static const char* nfc_file_header = "Flipper NFC device";
  9. static const uint32_t nfc_file_version = 2;
  10. NfcDevice* nfc_device_alloc() {
  11. NfcDevice* nfc_dev = furi_alloc(sizeof(NfcDevice));
  12. nfc_dev->storage = furi_record_open("storage");
  13. nfc_dev->dialogs = furi_record_open("dialogs");
  14. return nfc_dev;
  15. }
  16. void nfc_device_free(NfcDevice* nfc_dev) {
  17. furi_assert(nfc_dev);
  18. furi_record_close("storage");
  19. furi_record_close("dialogs");
  20. free(nfc_dev);
  21. }
  22. void nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string) {
  23. if(dev->format == NfcDeviceSaveFormatUid) {
  24. string_set_str(format_string, "UID");
  25. } else if(dev->format == NfcDeviceSaveFormatBankCard) {
  26. string_set_str(format_string, "Bank card");
  27. } else if(dev->format == NfcDeviceSaveFormatMifareUl) {
  28. string_set_str(format_string, nfc_mf_ul_type(dev->dev_data.mf_ul_data.type, true));
  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. return false;
  54. }
  55. static bool nfc_device_save_mifare_ul_data(FlipperFile* file, NfcDevice* dev) {
  56. bool saved = false;
  57. MifareUlData* data = &dev->dev_data.mf_ul_data;
  58. string_t temp_str;
  59. string_init(temp_str);
  60. // Save Mifare Ultralight specific data
  61. do {
  62. if(!flipper_file_write_comment_cstr(file, "Mifare Ultralight specific data")) break;
  63. if(!flipper_file_write_hex(file, "Signature", data->signature, sizeof(data->signature)))
  64. break;
  65. if(!flipper_file_write_hex(
  66. file, "Mifare version", (uint8_t*)&data->version, sizeof(data->version)))
  67. break;
  68. // Write conters and tearing flags data
  69. bool counters_saved = true;
  70. for(uint8_t i = 0; i < 3; i++) {
  71. string_printf(temp_str, "Counter %d", i);
  72. if(!flipper_file_write_uint32(file, string_get_cstr(temp_str), &data->counter[i], 1)) {
  73. counters_saved = false;
  74. break;
  75. }
  76. string_printf(temp_str, "Tearing %d", i);
  77. if(!flipper_file_write_hex(file, string_get_cstr(temp_str), &data->tearing[i], 1)) {
  78. counters_saved = false;
  79. break;
  80. }
  81. }
  82. if(!counters_saved) break;
  83. // Write pages data
  84. uint32_t pages_total = data->data_size / 4;
  85. if(!flipper_file_write_uint32(file, "Pages total", &pages_total, 1)) break;
  86. bool pages_saved = true;
  87. for(uint16_t i = 0; i < data->data_size; i += 4) {
  88. string_printf(temp_str, "Page %d", i / 4);
  89. if(!flipper_file_write_hex(file, string_get_cstr(temp_str), &data->data[i], 4)) {
  90. pages_saved = false;
  91. break;
  92. }
  93. }
  94. if(!pages_saved) break;
  95. saved = true;
  96. } while(false);
  97. string_clear(temp_str);
  98. return saved;
  99. }
  100. bool nfc_device_load_mifare_ul_data(FlipperFile* file, NfcDevice* dev) {
  101. bool parsed = false;
  102. MifareUlData* data = &dev->dev_data.mf_ul_data;
  103. string_t temp_str;
  104. string_init(temp_str);
  105. do {
  106. // Read signature
  107. if(!flipper_file_read_hex(file, "Signature", data->signature, sizeof(data->signature)))
  108. break;
  109. // Read Mifare version
  110. if(!flipper_file_read_hex(
  111. file, "Mifare version", (uint8_t*)&data->version, sizeof(data->version)))
  112. break;
  113. // Read counters and tearing flags
  114. bool counters_parsed = true;
  115. for(uint8_t i = 0; i < 3; i++) {
  116. string_printf(temp_str, "Counter %d", i);
  117. if(!flipper_file_read_uint32(file, string_get_cstr(temp_str), &data->counter[i], 1)) {
  118. counters_parsed = false;
  119. break;
  120. }
  121. string_printf(temp_str, "Tearing %d", i);
  122. if(!flipper_file_read_hex(file, string_get_cstr(temp_str), &data->tearing[i], 1)) {
  123. counters_parsed = false;
  124. break;
  125. }
  126. }
  127. if(!counters_parsed) break;
  128. // Read pages
  129. uint32_t pages = 0;
  130. if(!flipper_file_read_uint32(file, "Pages total", &pages, 1)) break;
  131. data->data_size = pages * 4;
  132. bool pages_parsed = true;
  133. for(uint16_t i = 0; i < pages; i++) {
  134. string_printf(temp_str, "Page %d", i);
  135. if(!flipper_file_read_hex(file, string_get_cstr(temp_str), &data->data[i * 4], 4)) {
  136. pages_parsed = false;
  137. break;
  138. }
  139. }
  140. if(!pages_parsed) break;
  141. parsed = true;
  142. } while(false);
  143. string_clear(temp_str);
  144. return parsed;
  145. }
  146. static bool nfc_device_save_bank_card_data(FlipperFile* file, NfcDevice* dev) {
  147. bool saved = false;
  148. NfcEmvData* data = &dev->dev_data.emv_data;
  149. uint32_t data_temp = 0;
  150. do {
  151. // Write Bank card specific data
  152. if(!flipper_file_write_comment_cstr(file, "Bank card specific data")) break;
  153. if(!flipper_file_write_hex(file, "AID", data->aid, data->aid_len)) break;
  154. if(!flipper_file_write_string_cstr(file, "Name", data->name)) break;
  155. if(!flipper_file_write_hex(file, "Number", data->number, data->number_len)) break;
  156. if(data->exp_mon) {
  157. uint8_t exp_data[2] = {data->exp_mon, data->exp_year};
  158. if(!flipper_file_write_hex(file, "Exp data", exp_data, sizeof(exp_data))) break;
  159. }
  160. if(data->country_code) {
  161. data_temp = data->country_code;
  162. if(!flipper_file_write_uint32(file, "Country code", &data_temp, 1)) break;
  163. }
  164. if(data->currency_code) {
  165. data_temp = data->currency_code;
  166. if(!flipper_file_write_uint32(file, "Currency code", &data_temp, 1)) break;
  167. }
  168. saved = true;
  169. } while(false);
  170. return saved;
  171. }
  172. bool nfc_device_load_bank_card_data(FlipperFile* file, NfcDevice* dev) {
  173. bool parsed = false;
  174. NfcEmvData* data = &dev->dev_data.emv_data;
  175. memset(data, 0, sizeof(NfcEmvData));
  176. uint32_t data_cnt = 0;
  177. string_t temp_str;
  178. string_init(temp_str);
  179. do {
  180. // Load essential data
  181. if(!flipper_file_get_value_count(file, "AID", &data_cnt)) break;
  182. data->aid_len = data_cnt;
  183. if(!flipper_file_read_hex(file, "AID", data->aid, data->aid_len)) break;
  184. if(!flipper_file_read_string(file, "Name", temp_str)) break;
  185. strlcpy(data->name, string_get_cstr(temp_str), sizeof(data->name));
  186. if(!flipper_file_get_value_count(file, "Number", &data_cnt)) break;
  187. data->number_len = data_cnt;
  188. if(!flipper_file_read_hex(file, "Number", data->number, data->number_len)) break;
  189. parsed = true;
  190. // Load optional data
  191. uint8_t exp_data[2] = {};
  192. if(flipper_file_read_hex(file, "Exp data", exp_data, 2)) {
  193. data->exp_mon = exp_data[0];
  194. data->exp_year = exp_data[1];
  195. }
  196. if(flipper_file_read_uint32(file, "Country code", &data_cnt, 1)) {
  197. data->country_code = data_cnt;
  198. }
  199. if(flipper_file_read_uint32(file, "Currency code", &data_cnt, 1)) {
  200. data->currency_code = data_cnt;
  201. }
  202. } while(false);
  203. string_clear(temp_str);
  204. return parsed;
  205. }
  206. void nfc_device_set_name(NfcDevice* dev, const char* name) {
  207. furi_assert(dev);
  208. strlcpy(dev->dev_name, name, NFC_DEV_NAME_MAX_LEN);
  209. }
  210. static bool nfc_device_save_file(
  211. NfcDevice* dev,
  212. const char* dev_name,
  213. const char* folder,
  214. const char* extension) {
  215. furi_assert(dev);
  216. bool saved = false;
  217. FlipperFile* file = flipper_file_alloc(dev->storage);
  218. NfcDeviceCommonData* data = &dev->dev_data.nfc_data;
  219. string_t temp_str;
  220. string_init(temp_str);
  221. do {
  222. // Create nfc directory if necessary
  223. if(!storage_simply_mkdir(dev->storage, nfc_app_folder)) break;
  224. // First remove nfc device file if it was saved
  225. string_printf(temp_str, "%s/%s%s", folder, dev_name, extension);
  226. // Open file
  227. if(!flipper_file_open_always(file, string_get_cstr(temp_str))) break;
  228. // Write header
  229. if(!flipper_file_write_header_cstr(file, nfc_file_header, nfc_file_version)) break;
  230. // Write nfc device type
  231. if(!flipper_file_write_comment_cstr(
  232. file, "Nfc device type can be UID, Mifare Ultralight, Bank card"))
  233. break;
  234. nfc_device_prepare_format_string(dev, temp_str);
  235. if(!flipper_file_write_string(file, "Device type", temp_str)) break;
  236. // Write UID, ATQA, SAK
  237. if(!flipper_file_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats"))
  238. break;
  239. if(!flipper_file_write_hex(file, "UID", data->uid, data->uid_len)) break;
  240. if(!flipper_file_write_hex(file, "ATQA", data->atqa, 2)) break;
  241. if(!flipper_file_write_hex(file, "SAK", &data->sak, 1)) break;
  242. // Save more data if necessary
  243. if(dev->format == NfcDeviceSaveFormatMifareUl) {
  244. if(!nfc_device_save_mifare_ul_data(file, dev)) break;
  245. } else if(dev->format == NfcDeviceSaveFormatBankCard) {
  246. if(!nfc_device_save_bank_card_data(file, dev)) break;
  247. }
  248. saved = true;
  249. } while(0);
  250. if(!saved) {
  251. dialog_message_show_storage_error(dev->dialogs, "Can not save\nkey file");
  252. }
  253. string_clear(temp_str);
  254. flipper_file_close(file);
  255. flipper_file_free(file);
  256. return saved;
  257. }
  258. bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
  259. return nfc_device_save_file(dev, dev_name, nfc_app_folder, nfc_app_extension);
  260. }
  261. bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) {
  262. dev->shadow_file_exist = true;
  263. return nfc_device_save_file(dev, dev_name, nfc_app_folder, nfc_app_shadow_extension);
  264. }
  265. static bool nfc_device_load_data(NfcDevice* dev, string_t path) {
  266. bool parsed = false;
  267. FlipperFile* file = flipper_file_alloc(dev->storage);
  268. NfcDeviceCommonData* data = &dev->dev_data.nfc_data;
  269. uint32_t data_cnt = 0;
  270. string_t temp_str;
  271. string_init(temp_str);
  272. bool depricated_version = false;
  273. do {
  274. // Check existance of shadow file
  275. size_t ext_start = string_search_str(path, nfc_app_extension);
  276. string_set_n(temp_str, path, 0, ext_start);
  277. string_cat_printf(temp_str, "%s", nfc_app_shadow_extension);
  278. dev->shadow_file_exist =
  279. storage_common_stat(dev->storage, string_get_cstr(temp_str), NULL) == FSE_OK;
  280. // Open shadow file if it exists. If not - open original
  281. if(dev->shadow_file_exist) {
  282. if(!flipper_file_open_existing(file, string_get_cstr(temp_str))) break;
  283. } else {
  284. if(!flipper_file_open_existing(file, string_get_cstr(path))) break;
  285. }
  286. // Read and verify file header
  287. uint32_t version = 0;
  288. if(!flipper_file_read_header(file, temp_str, &version)) break;
  289. if(string_cmp_str(temp_str, nfc_file_header) || (version != nfc_file_version)) {
  290. depricated_version = true;
  291. break;
  292. }
  293. // Read Nfc device type
  294. if(!flipper_file_read_string(file, "Device type", temp_str)) break;
  295. if(!nfc_device_parse_format_string(dev, temp_str)) break;
  296. // Read and parse UID, ATQA and SAK
  297. if(!flipper_file_get_value_count(file, "UID", &data_cnt)) break;
  298. data->uid_len = data_cnt;
  299. if(!flipper_file_read_hex(file, "UID", data->uid, data->uid_len)) break;
  300. if(!flipper_file_read_hex(file, "ATQA", data->atqa, 2)) break;
  301. if(!flipper_file_read_hex(file, "SAK", &data->sak, 1)) break;
  302. // Parse other data
  303. if(dev->format == NfcDeviceSaveFormatMifareUl) {
  304. if(!nfc_device_load_mifare_ul_data(file, dev)) break;
  305. } else if(dev->format == NfcDeviceSaveFormatBankCard) {
  306. if(!nfc_device_load_bank_card_data(file, dev)) break;
  307. }
  308. parsed = true;
  309. } while(false);
  310. if(!parsed) {
  311. if(depricated_version) {
  312. dialog_message_show_storage_error(dev->dialogs, "File format depricated");
  313. } else {
  314. dialog_message_show_storage_error(dev->dialogs, "Can not parse\nfile");
  315. }
  316. }
  317. string_clear(temp_str);
  318. flipper_file_close(file);
  319. flipper_file_free(file);
  320. return parsed;
  321. }
  322. bool nfc_device_load(NfcDevice* dev, const char* file_path) {
  323. furi_assert(dev);
  324. furi_assert(file_path);
  325. // Load device data
  326. string_t path;
  327. string_init_set_str(path, file_path);
  328. bool dev_load = nfc_device_load_data(dev, path);
  329. if(dev_load) {
  330. // Set device name
  331. path_extract_filename_no_ext(file_path, path);
  332. nfc_device_set_name(dev, string_get_cstr(path));
  333. }
  334. string_clear(path);
  335. return dev_load;
  336. }
  337. bool nfc_file_select(NfcDevice* dev) {
  338. furi_assert(dev);
  339. // Input events and views are managed by file_select
  340. bool res = dialog_file_select_show(
  341. dev->dialogs,
  342. nfc_app_folder,
  343. nfc_app_extension,
  344. dev->file_name,
  345. sizeof(dev->file_name),
  346. dev->dev_name);
  347. if(res) {
  348. string_t dev_str;
  349. // Get key file path
  350. string_init_printf(dev_str, "%s/%s%s", nfc_app_folder, dev->file_name, nfc_app_extension);
  351. res = nfc_device_load_data(dev, dev_str);
  352. if(res) {
  353. nfc_device_set_name(dev, dev->file_name);
  354. }
  355. string_clear(dev_str);
  356. }
  357. return res;
  358. }
  359. void nfc_device_clear(NfcDevice* dev) {
  360. furi_assert(dev);
  361. memset(&dev->dev_data, 0, sizeof(dev->dev_data));
  362. dev->format = NfcDeviceSaveFormatUid;
  363. }
  364. bool nfc_device_delete(NfcDevice* dev) {
  365. furi_assert(dev);
  366. bool deleted = false;
  367. string_t file_path;
  368. string_init(file_path);
  369. do {
  370. // Delete original file
  371. string_init_printf(file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension);
  372. if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break;
  373. // Delete shadow file if it exists
  374. if(dev->shadow_file_exist) {
  375. string_printf(
  376. file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension);
  377. if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break;
  378. }
  379. deleted = true;
  380. } while(0);
  381. if(!deleted) {
  382. dialog_message_show_storage_error(dev->dialogs, "Can not remove file");
  383. }
  384. string_clear(file_path);
  385. return deleted;
  386. }
  387. bool nfc_device_restore(NfcDevice* dev) {
  388. furi_assert(dev);
  389. furi_assert(dev->shadow_file_exist);
  390. bool restored = false;
  391. string_t path;
  392. do {
  393. string_init_printf(
  394. path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension);
  395. if(!storage_simply_remove(dev->storage, string_get_cstr(path))) break;
  396. dev->shadow_file_exist = false;
  397. string_printf(path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension);
  398. if(!nfc_device_load_data(dev, path)) break;
  399. restored = true;
  400. } while(0);
  401. string_clear(path);
  402. return restored;
  403. }