mfc_editor_scene_data_view.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. #include "../mfc_editor_app_i.h"
  2. void mfc_editor_scene_data_view_dialog_ex_callback(DialogExResult result, void* context) {
  3. MfcEditorApp* instance = context;
  4. view_dispatcher_send_custom_event(instance->view_dispatcher, result);
  5. }
  6. void mfc_editor_scene_data_view_update_display(MfcEditorApp* instance) {
  7. DialogEx* dialog_ex = instance->dialog_ex;
  8. dialog_ex_reset(instance->dialog_ex);
  9. dialog_ex_set_context(instance->dialog_ex, instance);
  10. dialog_ex_set_result_callback(
  11. instance->dialog_ex, mfc_editor_scene_data_view_dialog_ex_callback);
  12. MfcEditorBlockView block_view =
  13. scene_manager_get_scene_state(instance->scene_manager, MfcEditorSceneDataView);
  14. MfClassicData* mf_classic_data = instance->mf_classic_data;
  15. Iso14443_3aData* iso14443_3a_data = mf_classic_data->iso14443_3a_data;
  16. furi_string_reset(instance->data_view_text);
  17. if(block_view == MfcEditorBlockViewUID) {
  18. dialog_ex_set_header(dialog_ex, "UID", 63, 3, AlignCenter, AlignTop);
  19. mfc_editor_furi_string_render_bytes(
  20. instance->data_view_text, iso14443_3a_data->uid, iso14443_3a_data->uid_len);
  21. if(memcmp(
  22. iso14443_3a_data->uid, mf_classic_data->block[0].data, iso14443_3a_data->uid_len)) {
  23. // ISO-14443 UID does not match first bytes of block 0
  24. furi_string_cat_printf(instance->data_view_text, "\nBlock 0 does not match UID!\n(");
  25. mfc_editor_furi_string_render_bytes(
  26. instance->data_view_text,
  27. mf_classic_data->block[0].data,
  28. iso14443_3a_data->uid_len);
  29. furi_string_push_back(instance->data_view_text, ')');
  30. dialog_ex_set_center_button_text(dialog_ex, "Fix");
  31. }
  32. if(mf_classic_is_block_read(mf_classic_data, 0)) {
  33. dialog_ex_set_right_button_text(dialog_ex, "Edit");
  34. }
  35. } else if(block_view == MfcEditorBlockViewBCC) {
  36. dialog_ex_set_header(dialog_ex, "Block Check Character", 63, 3, AlignCenter, AlignTop);
  37. uint8_t stored_bcc = mf_classic_data->block[0].data[4];
  38. uint8_t calculated_bcc =
  39. mfc_editor_calculate_uid_bcc(iso14443_3a_data->uid, iso14443_3a_data->uid_len);
  40. if(mf_classic_is_block_read(mf_classic_data, 0)) {
  41. furi_string_printf(
  42. instance->data_view_text,
  43. "Stored BCC: %02X\nActual BCC: %02X",
  44. stored_bcc,
  45. calculated_bcc);
  46. if(stored_bcc != calculated_bcc) {
  47. furi_string_cat(instance->data_view_text, "\n(Mismatch!)");
  48. dialog_ex_set_center_button_text(dialog_ex, "Fix");
  49. }
  50. } else {
  51. furi_string_printf(
  52. instance->data_view_text,
  53. "Actual BCC: %02X\nStored BCC is unavailable\nas Block 0 has not been read.",
  54. calculated_bcc);
  55. }
  56. } else if(block_view == MfcEditorBlockViewManufacturerBytes) {
  57. dialog_ex_set_header(dialog_ex, "Manufacturer Bytes", 63, 3, AlignCenter, AlignTop);
  58. if(mf_classic_is_block_read(mf_classic_data, 0)) {
  59. // Skip BCC byte (not present on 7B UID cards)
  60. bool skip_byte = iso14443_3a_data->uid_len == 4;
  61. uint8_t start_index = iso14443_3a_data->uid_len + skip_byte;
  62. uint8_t byte_num = MF_CLASSIC_BLOCK_SIZE - iso14443_3a_data->uid_len - skip_byte;
  63. uint8_t line_len = byte_num / 2;
  64. mfc_editor_furi_string_render_bytes(
  65. instance->data_view_text, mf_classic_data->block[0].data + start_index, line_len);
  66. furi_string_push_back(instance->data_view_text, '\n');
  67. mfc_editor_furi_string_render_bytes(
  68. instance->data_view_text,
  69. mf_classic_data->block[0].data + start_index + line_len,
  70. byte_num - line_len);
  71. dialog_ex_set_right_button_text(dialog_ex, "Edit");
  72. } else {
  73. furi_string_set(
  74. instance->data_view_text, "Data unavailable.\nBlock 0 has not been read.");
  75. }
  76. } else if(block_view == MfcEditorBlockViewKeyA) {
  77. dialog_ex_set_header(dialog_ex, "Key A", 63, 3, AlignCenter, AlignTop);
  78. if(mf_classic_is_key_found(mf_classic_data, instance->current_sector, MfClassicKeyTypeA)) {
  79. MfClassicSectorTrailer* sector_trailer =
  80. mf_classic_get_sector_trailer_by_sector(mf_classic_data, instance->current_sector);
  81. mfc_editor_furi_string_render_bytes(
  82. instance->data_view_text, sector_trailer->key_a.data, MF_CLASSIC_KEY_SIZE);
  83. dialog_ex_set_right_button_text(dialog_ex, "Edit");
  84. } else {
  85. furi_string_set(
  86. instance->data_view_text, "Key A has not been found\nfor this sector.");
  87. }
  88. } else if(block_view == MfcEditorBlockViewKeyB) {
  89. dialog_ex_set_header(dialog_ex, "Key B", 63, 3, AlignCenter, AlignTop);
  90. if(mf_classic_is_key_found(mf_classic_data, instance->current_sector, MfClassicKeyTypeB)) {
  91. MfClassicSectorTrailer* sector_trailer =
  92. mf_classic_get_sector_trailer_by_sector(mf_classic_data, instance->current_sector);
  93. mfc_editor_furi_string_render_bytes(
  94. instance->data_view_text, sector_trailer->key_b.data, MF_CLASSIC_KEY_SIZE);
  95. dialog_ex_set_right_button_text(dialog_ex, "Edit");
  96. } else {
  97. furi_string_set(
  98. instance->data_view_text, "Key B has not been found\nfor this sector.");
  99. }
  100. } else if(block_view == MfcEditorBlockViewAccessBits) {
  101. uint8_t sector_trailer_num =
  102. mf_classic_get_sector_trailer_num_by_sector(instance->current_sector);
  103. if(mf_classic_is_block_read(mf_classic_data, sector_trailer_num)) {
  104. furi_string_printf(
  105. instance->data_view_header, "Access Bits (Block %u)", instance->current_block);
  106. dialog_ex_set_header(
  107. dialog_ex,
  108. furi_string_get_cstr(instance->data_view_header),
  109. 63,
  110. 3,
  111. AlignCenter,
  112. AlignTop);
  113. MfcEditorAccessBits access_bits =
  114. mfc_editor_get_block_access_bits(mf_classic_data, instance->current_block);
  115. furi_string_printf(
  116. instance->data_view_text,
  117. "C1: %i(%i), C2: %i(%i), C3: %i(%i)\n",
  118. FURI_BIT(access_bits.bits, 0),
  119. FURI_BIT(access_bits.check_bits, 0),
  120. FURI_BIT(access_bits.bits, 1),
  121. FURI_BIT(access_bits.check_bits, 1),
  122. FURI_BIT(access_bits.bits, 2),
  123. FURI_BIT(access_bits.check_bits, 2));
  124. if(access_bits.bits != access_bits.check_bits) {
  125. furi_string_cat(
  126. instance->data_view_text,
  127. "Access Bits are invalid.\nEntire sector inaccessible.");
  128. } else if(instance->current_block == sector_trailer_num) {
  129. furi_string_cat(
  130. instance->data_view_text, access_sector_trailer_labels[access_bits.bits]);
  131. } else {
  132. furi_string_cat(
  133. instance->data_view_text, access_data_block_labels[access_bits.bits]);
  134. }
  135. dialog_ex_set_center_button_text(dialog_ex, "Next");
  136. dialog_ex_set_left_button_text(dialog_ex, "Prev");
  137. dialog_ex_set_right_button_text(dialog_ex, "Edit");
  138. } else {
  139. dialog_ex_set_header(dialog_ex, "Access Bits", 63, 3, AlignCenter, AlignTop);
  140. furi_string_printf(
  141. instance->data_view_text,
  142. "Access Bits unavailable.\nBlock %u has not been read.",
  143. sector_trailer_num);
  144. }
  145. } else if(block_view == MfcEditorBlockViewUserByte) {
  146. dialog_ex_set_header(dialog_ex, "User Byte", 63, 3, AlignCenter, AlignTop);
  147. uint8_t sector_trailer_num =
  148. mf_classic_get_sector_trailer_num_by_sector(instance->current_sector);
  149. if(mf_classic_is_block_read(mf_classic_data, sector_trailer_num)) {
  150. furi_string_printf(
  151. instance->data_view_text,
  152. "Free byte between\nAccess Bits and Key B:\n%02X",
  153. mf_classic_data->block[sector_trailer_num].data[9]);
  154. dialog_ex_set_right_button_text(dialog_ex, "Edit");
  155. } else {
  156. furi_string_printf(
  157. instance->data_view_text,
  158. "Data unavailable.\nBlock %u has not been read.",
  159. sector_trailer_num);
  160. }
  161. } else {
  162. uint8_t current_block = instance->current_block;
  163. furi_string_printf(instance->data_view_header, "Block %u Data", current_block);
  164. dialog_ex_set_header(
  165. dialog_ex,
  166. furi_string_get_cstr(instance->data_view_header),
  167. 63,
  168. 3,
  169. AlignCenter,
  170. AlignTop);
  171. // Only display a block if it is fully read, and, if it is a sector trailer, both keys are found
  172. if(mf_classic_is_block_read(mf_classic_data, current_block) &&
  173. (!mf_classic_is_sector_trailer(current_block) ||
  174. (mf_classic_is_key_found(
  175. mf_classic_data, instance->current_sector, MfClassicKeyTypeA) &&
  176. mf_classic_is_key_found(
  177. mf_classic_data, instance->current_sector, MfClassicKeyTypeB)))) {
  178. // Split block data across 2 even lines
  179. const uint8_t* block_data = mf_classic_data->block[current_block].data;
  180. mfc_editor_furi_string_render_bytes(
  181. instance->data_view_text, block_data, MF_CLASSIC_BLOCK_SIZE / 2);
  182. furi_string_push_back(instance->data_view_text, '\n');
  183. mfc_editor_furi_string_render_bytes(
  184. instance->data_view_text,
  185. block_data + MF_CLASSIC_BLOCK_SIZE / 2,
  186. MF_CLASSIC_BLOCK_SIZE / 2);
  187. dialog_ex_set_right_button_text(dialog_ex, "Edit");
  188. } else {
  189. furi_string_set(
  190. instance->data_view_text, "Data unavailable.\nBlock has not been fully read.");
  191. }
  192. }
  193. dialog_ex_set_text(
  194. dialog_ex,
  195. furi_string_get_cstr(instance->data_view_text),
  196. 63,
  197. 31,
  198. AlignCenter,
  199. AlignCenter);
  200. }
  201. void mfc_editor_scene_data_view_on_enter(void* context) {
  202. MfcEditorApp* instance = context;
  203. mfc_editor_scene_data_view_update_display(instance);
  204. view_dispatcher_switch_to_view(instance->view_dispatcher, MfcEditorAppViewDialogEx);
  205. }
  206. bool mfc_editor_scene_data_view_on_event(void* context, SceneManagerEvent event) {
  207. MfcEditorApp* instance = context;
  208. bool consumed = false;
  209. if(event.type == SceneManagerEventTypeCustom) {
  210. MfcEditorBlockView block_view =
  211. scene_manager_get_scene_state(instance->scene_manager, MfcEditorSceneDataView);
  212. if(block_view == MfcEditorBlockViewNormal) {
  213. if(event.event == DialogExResultRight) {
  214. // Block 0 and sector trailer blocks are risky edits
  215. bool risky_block =
  216. instance->current_block == 0 ||
  217. instance->current_block ==
  218. mf_classic_get_sector_trailer_num_by_block(instance->current_block);
  219. if(!risky_block || mfc_editor_warn_risky_operation(instance)) {
  220. scene_manager_set_scene_state(
  221. instance->scene_manager, MfcEditorSceneDataEdit, block_view);
  222. scene_manager_next_scene(instance->scene_manager, MfcEditorSceneDataEdit);
  223. }
  224. consumed = true;
  225. }
  226. } else if(block_view == MfcEditorBlockViewUID) {
  227. if(event.event == DialogExResultRight) {
  228. if(mfc_editor_warn_risky_operation(instance)) {
  229. scene_manager_set_scene_state(
  230. instance->scene_manager, MfcEditorSceneDataEdit, block_view);
  231. scene_manager_next_scene(instance->scene_manager, MfcEditorSceneDataEdit);
  232. }
  233. consumed = true;
  234. } else if(event.event == DialogExResultCenter) {
  235. if(mfc_editor_warn_risky_operation(instance)) {
  236. memcpy(
  237. instance->mf_classic_data->block[0].data,
  238. instance->mf_classic_data->iso14443_3a_data->uid,
  239. instance->mf_classic_data->iso14443_3a_data->uid_len);
  240. instance->is_unsaved_changes = true;
  241. mfc_editor_scene_data_view_update_display(instance);
  242. }
  243. consumed = true;
  244. }
  245. } else if(
  246. block_view == MfcEditorBlockViewManufacturerBytes ||
  247. block_view == MfcEditorBlockViewKeyA || block_view == MfcEditorBlockViewKeyB) {
  248. if(event.event == DialogExResultRight) {
  249. if(mfc_editor_warn_risky_operation(instance)) {
  250. scene_manager_set_scene_state(
  251. instance->scene_manager, MfcEditorSceneDataEdit, block_view);
  252. scene_manager_next_scene(instance->scene_manager, MfcEditorSceneDataEdit);
  253. }
  254. consumed = true;
  255. }
  256. } else if(block_view == MfcEditorBlockViewBCC) {
  257. if(event.event == DialogExResultCenter) {
  258. if(mfc_editor_warn_risky_operation(instance)) {
  259. // Fix BCC byte by setting it to calculated one
  260. instance->mf_classic_data->block[0].data[4] = mfc_editor_calculate_uid_bcc(
  261. instance->mf_classic_data->iso14443_3a_data->uid,
  262. instance->mf_classic_data->iso14443_3a_data->uid_len);
  263. instance->is_unsaved_changes = true;
  264. mfc_editor_scene_data_view_update_display(instance);
  265. }
  266. consumed = true;
  267. }
  268. } else if(block_view == MfcEditorBlockViewAccessBits) {
  269. if(event.event == DialogExResultLeft) {
  270. uint8_t new_sector = mf_classic_get_sector_by_block(--instance->current_block);
  271. if(new_sector != instance->current_sector) {
  272. instance->current_block =
  273. mf_classic_get_sector_trailer_num_by_sector(instance->current_sector);
  274. }
  275. mfc_editor_scene_data_view_update_display(instance);
  276. consumed = true;
  277. } else if(event.event == DialogExResultCenter) {
  278. uint8_t new_sector = mf_classic_get_sector_by_block(++instance->current_block);
  279. if(new_sector != instance->current_sector) {
  280. instance->current_block =
  281. mf_classic_get_first_block_num_of_sector(instance->current_sector);
  282. }
  283. mfc_editor_scene_data_view_update_display(instance);
  284. consumed = true;
  285. } else if(event.event == DialogExResultRight) {
  286. if(mfc_editor_warn_risky_operation(instance)) {
  287. scene_manager_next_scene(
  288. instance->scene_manager, MfcEditorSceneDataEditAccessBits);
  289. }
  290. consumed = true;
  291. }
  292. } else if(block_view == MfcEditorBlockViewUserByte) {
  293. scene_manager_set_scene_state(
  294. instance->scene_manager, MfcEditorSceneDataEdit, block_view);
  295. scene_manager_next_scene(instance->scene_manager, MfcEditorSceneDataEdit);
  296. consumed = true;
  297. }
  298. }
  299. return consumed;
  300. }
  301. void mfc_editor_scene_data_view_on_exit(void* context) {
  302. MfcEditorApp* instance = context;
  303. dialog_ex_reset(instance->dialog_ex);
  304. }