combo_cracker.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. #include <furi.h>
  2. #include <gui/gui.h>
  3. #include <input/input.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <stdio.h>
  7. #define SCREEN_HEIGHT 64
  8. #define MAX_VALUES 10
  9. typedef enum {
  10. SCREEN_COMBO_ENTRY,
  11. SCREEN_RESULTS,
  12. SCREEN_ABOUT
  13. } ScreenState;
  14. typedef struct {
  15. int first_lock;
  16. int second_lock;
  17. float resistance;
  18. bool exit;
  19. int selected;
  20. char result[256];
  21. ViewPort* view_port;
  22. Gui* gui;
  23. ScreenState screen_state;
  24. } ComboCrackerState;
  25. char* float_to_char(float num) {
  26. static char buffer[8];
  27. snprintf(buffer, sizeof(buffer), "%.1f", (double)num);
  28. return buffer;
  29. }
  30. // calculate the value for the combo lock
  31. // Samy is my hero ;) -> https://www.youtube.com/watch?v=qkolWO6pAL8
  32. void calculate_combo(ComboCrackerState* app) {
  33. float sticky_number = app->resistance;
  34. int sticky_as_int = (int)sticky_number;
  35. int first_digit;
  36. if((sticky_number - sticky_as_int) == 0.0f) {
  37. // first digit easy, resistance + 5... crazy world we live in
  38. first_digit = sticky_as_int + 5;
  39. } else {
  40. first_digit = (int)(sticky_number + 5) + 1; // ceiling that biih... prob. a better way
  41. }
  42. first_digit = first_digit % 40;
  43. int remainder = first_digit % 4;
  44. int a = app->first_lock;
  45. int b = app->second_lock;
  46. // third digit isn't too bad
  47. int third_position_values[MAX_VALUES];
  48. int third_count = 0;
  49. for(int i = 0; i < 3; i++) {
  50. if(a % 4 == remainder) third_position_values[third_count++] = a;
  51. if(b % 4 == remainder) third_position_values[third_count++] = b;
  52. a = (a + 10) % 40;
  53. b = (b + 10) % 40;
  54. }
  55. int row_1 = (remainder + 2) % 40;
  56. int row_2 = (row_1 + 4) % 40;
  57. int second_position_values[MAX_VALUES];
  58. int second_count = 0;
  59. second_position_values[second_count++] = row_1;
  60. second_position_values[second_count++] = row_2;
  61. for(int i = 0; i < 4; i++) {
  62. row_1 = (row_1 + 8) % 40;
  63. row_2 = (row_2 + 8) % 40;
  64. second_position_values[second_count++] = row_1;
  65. second_position_values[second_count++] = row_2;
  66. }
  67. // sort that biih
  68. for(int i = 0; i < second_count - 1; i++) {
  69. for(int j = i + 1; j < second_count; j++) {
  70. if(second_position_values[i] > second_position_values[j]) {
  71. int temp = second_position_values[i];
  72. second_position_values[i] = second_position_values[j];
  73. second_position_values[j] = temp;
  74. }
  75. }
  76. }
  77. // result to push to result_callback
  78. snprintf(app->result, sizeof(app->result), "First Pin: %d\nSecond Pin(s): ", first_digit);
  79. for(int i = 0; i < second_count; i++) {
  80. char buf[6];
  81. snprintf(buf, sizeof(buf), "%d", second_position_values[i]);
  82. strcat(app->result, buf);
  83. if(i < second_count - 1) strcat(app->result, ", ");
  84. if(i == 3) strcat(app->result, "\n -> ");
  85. }
  86. strcat(app->result, "\nThird Pin(s): ");
  87. for(int i = 0; i < third_count; i++) {
  88. char buf[5];
  89. snprintf(buf, sizeof(buf), "%d", third_position_values[i]);
  90. strcat(app->result, buf);
  91. if(i < third_count - 1) strcat(app->result, ", "); // may be more than one sometimes
  92. // deduce to 8 attempts by popping -> (third_digit +/- 2)
  93. }
  94. }
  95. // main screen to push the first, second, and resistance positions
  96. void draw_callback(Canvas* canvas, void* ctx) {
  97. ComboCrackerState* app = ctx;
  98. canvas_clear(canvas);
  99. canvas_set_font(canvas, FontPrimary);
  100. char buf[16];
  101. canvas_draw_str(canvas, 2, 12, "First Lock:");
  102. snprintf(buf, sizeof(buf), "%s%d", app->selected == 0 ? ">" : " ", app->first_lock);
  103. canvas_draw_str(canvas, 100, 12, buf);
  104. canvas_draw_str(canvas, 2, 24, "Second Lock:");
  105. snprintf(buf, sizeof(buf), "%s%d", app->selected == 1 ? ">" : " ", app->second_lock);
  106. canvas_draw_str(canvas, 100, 24, buf);
  107. canvas_draw_str(canvas, 2, 36, "Resistance:");
  108. snprintf(
  109. buf, sizeof(buf), "%s%s", app->selected == 2 ? ">" : " ", float_to_char(app->resistance));
  110. canvas_draw_str(canvas, 100, 36, buf);
  111. snprintf(
  112. buf, sizeof(buf), "%sAbout", app->selected == 3 ? ">" : " "); // ugly but we rollin wit it
  113. canvas_draw_str(canvas, 2, 48, buf);
  114. canvas_draw_str(canvas, 2, 62, "OK to calculate"); // is there an OK icon??
  115. }
  116. // push the calc to screen
  117. void result_draw_callback(Canvas* canvas, void* ctx) {
  118. ComboCrackerState* app = ctx;
  119. canvas_clear(canvas);
  120. canvas_set_font(canvas, FontSecondary);
  121. int y = 12;
  122. char result_copy[256];
  123. strncpy(result_copy, app->result, sizeof(result_copy));
  124. char* line = strtok(result_copy, "\n");
  125. while(line && y < SCREEN_HEIGHT - 10) {
  126. canvas_draw_str(canvas, 2, y, line);
  127. y += 10;
  128. line = strtok(NULL, "\n");
  129. }
  130. canvas_draw_str(canvas, 2, SCREEN_HEIGHT - 2, "Back to edit");
  131. }
  132. void about_draw_callback(Canvas* canvas, void* ctx) {
  133. UNUSED(ctx);
  134. canvas_clear(canvas);
  135. canvas_set_font(canvas, FontSecondary);
  136. int y = 12;
  137. canvas_draw_str(canvas, 2, y, "Combo Lock Cracker");
  138. y += 10;
  139. canvas_draw_str(canvas, 2, y, "Based on Samy Kamkar's");
  140. y += 10;
  141. canvas_draw_str(canvas, 2, y, "Master Lock research.");
  142. y += 10;
  143. canvas_draw_str(canvas, 2, y, "Crack Combo Locks in 8 tries");
  144. y += 10;
  145. canvas_draw_str(canvas, 2, y, "https://samy.pl/master/");
  146. y += 18;
  147. canvas_draw_str(canvas, 2, SCREEN_HEIGHT - 2, "Back to main menu");
  148. }
  149. void input_callback(InputEvent* event, void* ctx);
  150. void result_input_callback(InputEvent* event, void* ctx) {
  151. ComboCrackerState* app = ctx;
  152. if(event->type == InputTypeShort && event->key == InputKeyBack) {
  153. app->screen_state = SCREEN_COMBO_ENTRY;
  154. view_port_draw_callback_set(app->view_port, draw_callback, app);
  155. view_port_input_callback_set(app->view_port, input_callback, app);
  156. }
  157. view_port_update(app->view_port);
  158. }
  159. void input_callback(InputEvent* event, void* ctx) {
  160. ComboCrackerState* app = ctx;
  161. if(event->type == InputTypeShort) {
  162. switch(event->key) {
  163. case InputKeyUp:
  164. app->selected = (app->selected + 3) % 4;
  165. break;
  166. case InputKeyDown:
  167. app->selected = (app->selected + 1) % 4;
  168. break;
  169. case InputKeyLeft:
  170. if(app->selected == 0 && app->first_lock > 0) app->first_lock--;
  171. if(app->selected == 1 && app->second_lock > 0) app->second_lock--;
  172. if(app->selected == 2 && app->resistance > 0) app->resistance -= 0.5;
  173. break;
  174. case InputKeyRight: // can't figure out how to accomodate for long presses for fast incrementation??
  175. if(app->selected == 0 && app->first_lock < 10) app->first_lock++;
  176. if(app->selected == 1 && app->second_lock < 10) app->second_lock++;
  177. if(app->selected == 2 && app->resistance < 39.5) app->resistance += 0.5;
  178. if(app->selected == 3) { // about description
  179. app->screen_state = SCREEN_ABOUT;
  180. view_port_draw_callback_set(app->view_port, about_draw_callback, app);
  181. view_port_input_callback_set(app->view_port, result_input_callback, app);
  182. }
  183. break;
  184. case InputKeyOk:
  185. calculate_combo(app);
  186. app->screen_state = SCREEN_RESULTS;
  187. view_port_draw_callback_set(app->view_port, result_draw_callback, app);
  188. view_port_input_callback_set(app->view_port, result_input_callback, app);
  189. break;
  190. case InputKeyBack:
  191. app->exit = true;
  192. break;
  193. default:
  194. break;
  195. }
  196. }
  197. view_port_update(app->view_port);
  198. }
  199. int32_t combo_cracker_app(void* p) {
  200. UNUSED(p);
  201. ComboCrackerState* app = malloc(sizeof(ComboCrackerState));
  202. app->first_lock = 0;
  203. app->second_lock = 0;
  204. app->resistance = 0.0f;
  205. app->selected = 0;
  206. app->exit = false;
  207. app->screen_state = SCREEN_COMBO_ENTRY;
  208. app->result[0] = '\0';
  209. app->view_port = view_port_alloc();
  210. view_port_draw_callback_set(app->view_port, draw_callback, app);
  211. view_port_input_callback_set(app->view_port, input_callback, app);
  212. app->gui = furi_record_open(RECORD_GUI);
  213. gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen);
  214. while(!app->exit) {
  215. furi_delay_ms(50);
  216. }
  217. view_port_enabled_set(app->view_port, false);
  218. gui_remove_view_port(app->gui, app->view_port);
  219. view_port_free(app->view_port);
  220. furi_record_close(RECORD_GUI);
  221. free(app);
  222. return 0;
  223. }