dict_attack.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. #include "dict_attack.h"
  2. #include <gui/elements.h>
  3. #define NFC_CLASSIC_KEYS_PER_SECTOR 2
  4. struct DictAttack {
  5. View* view;
  6. DictAttackCallback callback;
  7. void* context;
  8. };
  9. typedef struct {
  10. FuriString* header;
  11. bool card_detected;
  12. uint8_t sectors_total;
  13. uint8_t sectors_read;
  14. uint8_t current_sector;
  15. uint8_t keys_found;
  16. size_t dict_keys_total;
  17. size_t dict_keys_current;
  18. bool is_key_attack;
  19. uint8_t key_attack_current_sector;
  20. } DictAttackViewModel;
  21. static void dict_attack_draw_callback(Canvas* canvas, void* model) {
  22. DictAttackViewModel* m = model;
  23. if(!m->card_detected) {
  24. canvas_set_font(canvas, FontPrimary);
  25. canvas_draw_str_aligned(
  26. canvas, 64, 4, AlignCenter, AlignTop, "Hold the tag to the Flipper!");
  27. canvas_set_font(canvas, FontSecondary);
  28. elements_multiline_text_aligned(
  29. canvas, 64, 23, AlignCenter, AlignTop, "Make sure the tag is\npositioned correctly.");
  30. } else {
  31. char draw_str[32] = {};
  32. canvas_set_font(canvas, FontSecondary);
  33. canvas_draw_str_aligned(
  34. canvas, 64, 0, AlignCenter, AlignTop, furi_string_get_cstr(m->header));
  35. if(m->is_key_attack) {
  36. snprintf(
  37. draw_str,
  38. sizeof(draw_str),
  39. "Reuse key check for sector: %d",
  40. m->key_attack_current_sector);
  41. } else {
  42. snprintf(draw_str, sizeof(draw_str), "Unlocking sector: %d", m->current_sector);
  43. }
  44. canvas_draw_str_aligned(canvas, 0, 10, AlignLeft, AlignTop, draw_str);
  45. float dict_progress = m->dict_keys_total == 0 ?
  46. 0 :
  47. (float)(m->dict_keys_current) / (float)(m->dict_keys_total);
  48. float progress = m->sectors_total == 0 ? 0 :
  49. ((float)(m->current_sector) + dict_progress) /
  50. (float)(m->sectors_total);
  51. if(progress > 1.0f) {
  52. progress = 1.0f;
  53. }
  54. if(m->dict_keys_current == 0) {
  55. // Cause when people see 0 they think it's broken
  56. snprintf(draw_str, sizeof(draw_str), "%d/%zu", 1, m->dict_keys_total);
  57. } else {
  58. snprintf(
  59. draw_str, sizeof(draw_str), "%zu/%zu", m->dict_keys_current, m->dict_keys_total);
  60. }
  61. elements_progress_bar_with_text(canvas, 0, 20, 128, dict_progress, draw_str);
  62. canvas_set_font(canvas, FontSecondary);
  63. snprintf(
  64. draw_str,
  65. sizeof(draw_str),
  66. "Keys found: %d/%d",
  67. m->keys_found,
  68. m->sectors_total * NFC_CLASSIC_KEYS_PER_SECTOR);
  69. canvas_draw_str_aligned(canvas, 0, 33, AlignLeft, AlignTop, draw_str);
  70. snprintf(
  71. draw_str, sizeof(draw_str), "Sectors Read: %d/%d", m->sectors_read, m->sectors_total);
  72. canvas_draw_str_aligned(canvas, 0, 43, AlignLeft, AlignTop, draw_str);
  73. }
  74. elements_button_center(canvas, "Skip");
  75. }
  76. static bool dict_attack_input_callback(InputEvent* event, void* context) {
  77. DictAttack* instance = context;
  78. bool consumed = false;
  79. if(event->type == InputTypeShort && event->key == InputKeyOk) {
  80. if(instance->callback) {
  81. instance->callback(DictAttackEventSkipPressed, instance->context);
  82. }
  83. consumed = true;
  84. }
  85. return consumed;
  86. }
  87. DictAttack* dict_attack_alloc() {
  88. DictAttack* instance = malloc(sizeof(DictAttack));
  89. instance->view = view_alloc();
  90. view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(DictAttackViewModel));
  91. view_set_draw_callback(instance->view, dict_attack_draw_callback);
  92. view_set_input_callback(instance->view, dict_attack_input_callback);
  93. view_set_context(instance->view, instance);
  94. with_view_model(
  95. instance->view,
  96. DictAttackViewModel * model,
  97. { model->header = furi_string_alloc(); },
  98. false);
  99. return instance;
  100. }
  101. void dict_attack_free(DictAttack* instance) {
  102. furi_assert(instance);
  103. with_view_model(
  104. instance->view, DictAttackViewModel * model, { furi_string_free(model->header); }, false);
  105. view_free(instance->view);
  106. free(instance);
  107. }
  108. void dict_attack_reset(DictAttack* instance) {
  109. furi_assert(instance);
  110. with_view_model(
  111. instance->view,
  112. DictAttackViewModel * model,
  113. {
  114. model->sectors_total = 0;
  115. model->sectors_read = 0;
  116. model->current_sector = 0;
  117. model->keys_found = 0;
  118. model->dict_keys_total = 0;
  119. model->dict_keys_current = 0;
  120. model->is_key_attack = false;
  121. furi_string_reset(model->header);
  122. },
  123. false);
  124. }
  125. View* dict_attack_get_view(DictAttack* instance) {
  126. furi_assert(instance);
  127. return instance->view;
  128. }
  129. void dict_attack_set_callback(DictAttack* instance, DictAttackCallback callback, void* context) {
  130. furi_assert(instance);
  131. furi_assert(callback);
  132. instance->callback = callback;
  133. instance->context = context;
  134. }
  135. void dict_attack_set_header(DictAttack* instance, const char* header) {
  136. furi_assert(instance);
  137. furi_assert(header);
  138. with_view_model(
  139. instance->view,
  140. DictAttackViewModel * model,
  141. { furi_string_set(model->header, header); },
  142. true);
  143. }
  144. void dict_attack_set_card_state(DictAttack* instance, bool detected) {
  145. furi_assert(instance);
  146. with_view_model(
  147. instance->view, DictAttackViewModel * model, { model->card_detected = detected; }, true);
  148. }
  149. void dict_attack_set_sectors_total(DictAttack* instance, uint8_t sectors_total) {
  150. furi_assert(instance);
  151. with_view_model(
  152. instance->view,
  153. DictAttackViewModel * model,
  154. { model->sectors_total = sectors_total; },
  155. true);
  156. }
  157. void dict_attack_set_sectors_read(DictAttack* instance, uint8_t sectors_read) {
  158. furi_assert(instance);
  159. with_view_model(
  160. instance->view, DictAttackViewModel * model, { model->sectors_read = sectors_read; }, true);
  161. }
  162. void dict_attack_set_keys_found(DictAttack* instance, uint8_t keys_found) {
  163. furi_assert(instance);
  164. with_view_model(
  165. instance->view, DictAttackViewModel * model, { model->keys_found = keys_found; }, true);
  166. }
  167. void dict_attack_set_current_sector(DictAttack* instance, uint8_t current_sector) {
  168. furi_assert(instance);
  169. with_view_model(
  170. instance->view,
  171. DictAttackViewModel * model,
  172. { model->current_sector = current_sector; },
  173. true);
  174. }
  175. void dict_attack_set_total_dict_keys(DictAttack* instance, size_t dict_keys_total) {
  176. furi_assert(instance);
  177. with_view_model(
  178. instance->view,
  179. DictAttackViewModel * model,
  180. { model->dict_keys_total = dict_keys_total; },
  181. true);
  182. }
  183. void dict_attack_set_current_dict_key(DictAttack* instance, size_t cur_key_num) {
  184. furi_assert(instance);
  185. with_view_model(
  186. instance->view,
  187. DictAttackViewModel * model,
  188. { model->dict_keys_current = cur_key_num; },
  189. true);
  190. }
  191. void dict_attack_set_key_attack(DictAttack* instance, uint8_t sector) {
  192. furi_assert(instance);
  193. with_view_model(
  194. instance->view,
  195. DictAttackViewModel * model,
  196. {
  197. model->is_key_attack = true;
  198. model->key_attack_current_sector = sector;
  199. },
  200. true);
  201. }
  202. void dict_attack_reset_key_attack(DictAttack* instance) {
  203. furi_assert(instance);
  204. with_view_model(
  205. instance->view, DictAttackViewModel * model, { model->is_key_attack = false; }, true);
  206. }