mfc_editor_scene_data_view.c 12 KB

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