picopass_scene_read_card_success.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. #include "../picopass_i.h"
  2. #include <dolphin/dolphin.h>
  3. #include <picopass_keys.h>
  4. void picopass_scene_read_card_success_widget_callback(
  5. GuiButtonType result,
  6. InputType type,
  7. void* context) {
  8. furi_assert(context);
  9. Picopass* picopass = context;
  10. if(type == InputTypeShort) {
  11. view_dispatcher_send_custom_event(picopass->view_dispatcher, result);
  12. }
  13. }
  14. void picopass_scene_read_card_success_on_enter(void* context) {
  15. Picopass* picopass = context;
  16. FuriString* csn_str = furi_string_alloc_set("CSN:");
  17. FuriString* credential_str = furi_string_alloc();
  18. FuriString* wiegand_str = furi_string_alloc();
  19. FuriString* key_str = furi_string_alloc();
  20. dolphin_deed(DolphinDeedNfcReadSuccess);
  21. // Send notification
  22. notification_message(picopass->notifications, &sequence_success);
  23. // Setup view
  24. PicopassBlock* AA1 = picopass->dev->dev_data.AA1;
  25. PicopassPacs* pacs = &picopass->dev->dev_data.pacs;
  26. Widget* widget = picopass->widget;
  27. uint8_t csn[PICOPASS_BLOCK_LEN] = {0};
  28. memcpy(csn, AA1[PICOPASS_CSN_BLOCK_INDEX].data, PICOPASS_BLOCK_LEN);
  29. for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
  30. furi_string_cat_printf(csn_str, "%02X", csn[i]);
  31. }
  32. // We can't test the pacs->key in case it is intentionally all 0's and we can't test the key block since it is populated with the diversified key before each key test, so we approximate with the PACS config block being blank.
  33. bool no_key = picopass_is_memset(
  34. AA1[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data, 0x00, PICOPASS_BLOCK_LEN);
  35. bool empty = picopass_is_memset(
  36. AA1[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data, 0xFF, PICOPASS_BLOCK_LEN);
  37. bool SE = 0x30 == AA1[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data[0];
  38. bool configCard = (AA1[PICOPASS_ICLASS_PACS_CFG_BLOCK_INDEX].data[7] >> 2 & 3) == 2;
  39. if(no_key) {
  40. furi_string_cat_printf(wiegand_str, "Read Failed");
  41. bool hid_csn = picopass_device_hid_csn(picopass->dev);
  42. if(pacs->se_enabled) {
  43. furi_string_cat_printf(credential_str, "SE enabled");
  44. } else if(!hid_csn) {
  45. furi_string_cat_printf(credential_str, "Non-HID CSN");
  46. }
  47. widget_add_button_element(
  48. widget,
  49. GuiButtonTypeCenter,
  50. "Menu",
  51. picopass_scene_read_card_success_widget_callback,
  52. picopass);
  53. widget_add_button_element(
  54. widget,
  55. GuiButtonTypeRight,
  56. "More",
  57. picopass_scene_read_card_success_widget_callback,
  58. picopass);
  59. } else if(pacs->se_enabled) {
  60. furi_string_cat_printf(credential_str, "SE enabled");
  61. furi_string_cat_printf(wiegand_str, "SIO");
  62. widget_add_button_element(
  63. widget,
  64. GuiButtonTypeRight,
  65. "More",
  66. picopass_scene_read_card_success_widget_callback,
  67. picopass);
  68. } else if(configCard) {
  69. furi_string_cat_printf(wiegand_str, "Config Card");
  70. } else if(empty) {
  71. furi_string_cat_printf(wiegand_str, "Empty");
  72. widget_add_button_element(
  73. widget,
  74. GuiButtonTypeCenter,
  75. "Menu",
  76. picopass_scene_read_card_success_widget_callback,
  77. picopass);
  78. } else if(pacs->bitLength == 0 || pacs->bitLength == 255) {
  79. // Neither of these are valid. Indicates the block was all 0x00 or all 0xff
  80. if(SE) {
  81. furi_string_cat_printf(wiegand_str, "SIO");
  82. } else {
  83. furi_string_cat_printf(wiegand_str, "Invalid PACS");
  84. }
  85. widget_add_button_element(
  86. widget,
  87. GuiButtonTypeCenter,
  88. "Menu",
  89. picopass_scene_read_card_success_widget_callback,
  90. picopass);
  91. widget_add_button_element(
  92. widget,
  93. GuiButtonTypeRight,
  94. "More",
  95. picopass_scene_read_card_success_widget_callback,
  96. picopass);
  97. } else {
  98. size_t bytesLength = 1 + pacs->bitLength / 8;
  99. furi_string_set(credential_str, "");
  100. for(uint8_t i = PICOPASS_BLOCK_LEN - bytesLength; i < PICOPASS_BLOCK_LEN; i++) {
  101. furi_string_cat_printf(credential_str, "%02X", pacs->credential[i]);
  102. }
  103. furi_string_cat_printf(wiegand_str, "%d bits", pacs->bitLength);
  104. if(pacs->sio) {
  105. furi_string_cat_printf(credential_str, " +SIO");
  106. }
  107. if(pacs->key) {
  108. furi_string_cat_printf(key_str, "Key: ");
  109. uint8_t key[PICOPASS_BLOCK_LEN];
  110. memcpy(key, &pacs->key, PICOPASS_BLOCK_LEN);
  111. bool standard_key = true;
  112. // Handle DES key being 56bits with parity in LSB
  113. for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
  114. if((key[i] & 0xFE) != (picopass_iclass_key[i] & 0xFE)) {
  115. standard_key = false;
  116. break;
  117. }
  118. }
  119. if(standard_key) {
  120. furi_string_cat_printf(key_str, "Standard");
  121. } else {
  122. for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) {
  123. furi_string_cat_printf(key_str, "%02X", key[i]);
  124. }
  125. }
  126. }
  127. widget_add_button_element(
  128. widget,
  129. GuiButtonTypeRight,
  130. "More",
  131. picopass_scene_read_card_success_widget_callback,
  132. picopass);
  133. }
  134. widget_add_button_element(
  135. widget,
  136. GuiButtonTypeLeft,
  137. "Retry",
  138. picopass_scene_read_card_success_widget_callback,
  139. picopass);
  140. widget_add_string_element(
  141. widget, 64, 5, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(csn_str));
  142. widget_add_string_element(
  143. widget, 64, 20, AlignCenter, AlignCenter, FontPrimary, furi_string_get_cstr(wiegand_str));
  144. widget_add_string_element(
  145. widget,
  146. 64,
  147. 36,
  148. AlignCenter,
  149. AlignCenter,
  150. FontSecondary,
  151. furi_string_get_cstr(credential_str));
  152. widget_add_string_element(
  153. widget, 64, 46, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(key_str));
  154. furi_string_free(csn_str);
  155. furi_string_free(credential_str);
  156. furi_string_free(wiegand_str);
  157. furi_string_free(key_str);
  158. view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget);
  159. }
  160. bool picopass_scene_read_card_success_on_event(void* context, SceneManagerEvent event) {
  161. Picopass* picopass = context;
  162. bool consumed = false;
  163. if(event.type == SceneManagerEventTypeCustom) {
  164. if(event.event == GuiButtonTypeLeft) {
  165. consumed = scene_manager_previous_scene(picopass->scene_manager);
  166. } else if(event.event == GuiButtonTypeRight) {
  167. // Clear device name
  168. picopass_device_set_name(picopass->dev, "");
  169. scene_manager_next_scene(picopass->scene_manager, PicopassSceneCardMenu);
  170. consumed = true;
  171. } else if(event.event == GuiButtonTypeCenter) {
  172. consumed = scene_manager_search_and_switch_to_another_scene(
  173. picopass->scene_manager, PicopassSceneStart);
  174. }
  175. } else if(event.type == SceneManagerEventTypeBack) {
  176. scene_manager_search_and_switch_to_previous_scene(
  177. picopass->scene_manager, PicopassSceneStart);
  178. consumed = true;
  179. }
  180. return consumed;
  181. }
  182. void picopass_scene_read_card_success_on_exit(void* context) {
  183. Picopass* picopass = context;
  184. // Clear view
  185. widget_reset(picopass->widget);
  186. }