mfc_editor_scene_data_view.c 15 KB

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