totp_scene_authenticate.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #include "totp_scene_authenticate.h"
  2. #include <dialogs/dialogs.h>
  3. #include "../../types/common.h"
  4. #include "../../services/ui/icons.h"
  5. #include "../../services/ui/constants.h"
  6. #include "../../services/config/config.h"
  7. #include "../scene_director.h"
  8. #include "../totp_scenes_enum.h"
  9. #define MAX_CODE_LENGTH TOTP_IV_SIZE
  10. #define CRYPTO_VERIFY_KEY "FFF_Crypto_pass"
  11. #define CRYPTO_VERIFY_KEY_LENGTH 16
  12. typedef struct {
  13. uint8_t code_input[MAX_CODE_LENGTH];
  14. uint8_t code_length;
  15. } SceneState;
  16. void totp_scene_authenticate_init(PluginState* plugin_state) {
  17. memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
  18. }
  19. void totp_scene_authenticate_activate(PluginState* plugin_state) {
  20. SceneState* scene_state = malloc(sizeof(SceneState));
  21. scene_state->code_length = 0;
  22. memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH);
  23. plugin_state->current_scene_state = scene_state;
  24. }
  25. void totp_scene_authenticate_render(Canvas* const canvas, PluginState* plugin_state) {
  26. SceneState* scene_state = (SceneState *)plugin_state->current_scene_state;
  27. int v_shift = 0;
  28. if (scene_state->code_length > 0) {
  29. v_shift = -10;
  30. }
  31. if (plugin_state->crypto_verify_data == NULL) {
  32. canvas_draw_str_aligned(canvas, SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER - 10 + v_shift, AlignCenter, AlignCenter, "Use arrow keys");
  33. canvas_draw_str_aligned(canvas, SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER + 5 + v_shift, AlignCenter, AlignCenter, "to setup new PIN");
  34. } else {
  35. canvas_draw_str_aligned(canvas, SCREEN_WIDTH_CENTER, SCREEN_HEIGHT_CENTER + v_shift, AlignCenter, AlignCenter, "Use arrow keys to enter PIN");
  36. }
  37. const uint8_t PIN_ASTERISK_RADIUS = 3;
  38. const uint8_t PIN_ASTERISK_STEP = (PIN_ASTERISK_RADIUS << 1) + 2;
  39. if (scene_state->code_length > 0) {
  40. uint8_t left_start_x = (scene_state->code_length - 1) * PIN_ASTERISK_STEP >> 1;
  41. for (uint8_t i = 0; i < scene_state->code_length; i++) {
  42. canvas_draw_disc(
  43. canvas,
  44. SCREEN_WIDTH_CENTER - left_start_x + i * PIN_ASTERISK_STEP,
  45. SCREEN_HEIGHT_CENTER + 10,
  46. PIN_ASTERISK_RADIUS);
  47. }
  48. }
  49. }
  50. bool totp_scene_authenticate_handle_event(PluginEvent* const event, PluginState* plugin_state) {
  51. if(event->type == EventTypeKey) {
  52. if (event->input.type == InputTypeLong && event->input.key == InputKeyBack) {
  53. return false;
  54. } else if(event->input.type == InputTypePress) {
  55. SceneState* scene_state = (SceneState *)plugin_state->current_scene_state;
  56. const uint8_t ARROW_UP_CODE = 2;
  57. const uint8_t ARROW_RIGHT_CODE = 8;
  58. const uint8_t ARROW_DOWN_CODE = 11;
  59. const uint8_t ARROW_LEFT_CODE = 5;
  60. switch(event->input.key) {
  61. case InputKeyUp:
  62. if (scene_state->code_length < MAX_CODE_LENGTH) {
  63. scene_state->code_input[scene_state->code_length] = ARROW_UP_CODE;
  64. scene_state->code_length++;
  65. }
  66. break;
  67. case InputKeyDown:
  68. if (scene_state->code_length < MAX_CODE_LENGTH) {
  69. scene_state->code_input[scene_state->code_length] = ARROW_DOWN_CODE;
  70. scene_state->code_length++;
  71. }
  72. break;
  73. case InputKeyRight:
  74. if (scene_state->code_length < MAX_CODE_LENGTH) {
  75. scene_state->code_input[scene_state->code_length] = ARROW_RIGHT_CODE;
  76. scene_state->code_length++;
  77. }
  78. break;
  79. case InputKeyLeft:
  80. if (scene_state->code_length < MAX_CODE_LENGTH) {
  81. scene_state->code_input[scene_state->code_length] = ARROW_LEFT_CODE;
  82. scene_state->code_length++;
  83. }
  84. break;
  85. case InputKeyOk:
  86. if (plugin_state->crypto_verify_data == NULL) {
  87. FURI_LOG_D(LOGGING_TAG, "Generating new IV");
  88. furi_hal_random_fill_buf(&plugin_state->base_iv[0], TOTP_IV_SIZE);
  89. }
  90. memcpy(&plugin_state->iv[0], &plugin_state->base_iv[0], TOTP_IV_SIZE);
  91. for (uint8_t i = 0; i < scene_state->code_length; i++) {
  92. plugin_state->iv[i] = plugin_state->iv[i] ^ (uint8_t)(scene_state->code_input[i] * (i + 1));
  93. }
  94. if (plugin_state->crypto_verify_data == NULL) {
  95. FURI_LOG_D(LOGGING_TAG, "Generating crypto verify data");
  96. plugin_state->crypto_verify_data = malloc(CRYPTO_VERIFY_KEY_LENGTH);
  97. plugin_state->crypto_verify_data_length = CRYPTO_VERIFY_KEY_LENGTH;
  98. Storage* storage = totp_open_storage();
  99. FlipperFormat* config_file = totp_open_config_file(storage);
  100. furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, &plugin_state->iv[0]);
  101. furi_hal_crypto_encrypt((uint8_t* )CRYPTO_VERIFY_KEY, plugin_state->crypto_verify_data, CRYPTO_VERIFY_KEY_LENGTH);
  102. furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
  103. flipper_format_insert_or_update_hex(config_file, TOTP_CONFIG_KEY_BASE_IV, plugin_state->base_iv, TOTP_IV_SIZE);
  104. flipper_format_insert_or_update_hex(config_file, TOTP_CONFIG_KEY_CRYPTO_VERIFY, plugin_state->crypto_verify_data, CRYPTO_VERIFY_KEY_LENGTH);
  105. totp_close_config_file(config_file);
  106. totp_close_storage();
  107. }
  108. uint8_t decrypted_key[CRYPTO_VERIFY_KEY_LENGTH];
  109. furi_hal_crypto_store_load_key(CRYPTO_KEY_SLOT, &plugin_state->iv[0]);
  110. furi_hal_crypto_decrypt(plugin_state->crypto_verify_data, &decrypted_key[0], CRYPTO_VERIFY_KEY_LENGTH);
  111. furi_hal_crypto_store_unload_key(CRYPTO_KEY_SLOT);
  112. bool key_valid = true;
  113. for (uint8_t i = 0; i < CRYPTO_VERIFY_KEY_LENGTH && key_valid; i++) {
  114. if (decrypted_key[i] != CRYPTO_VERIFY_KEY[i]) key_valid = false;
  115. }
  116. if (key_valid) {
  117. FURI_LOG_D(LOGGING_TAG, "PIN is valid");
  118. totp_scene_director_activate_scene(plugin_state, TotpSceneGenerateToken, NULL);
  119. } else {
  120. FURI_LOG_D(LOGGING_TAG, "PIN is NOT valid");
  121. memset(&scene_state->code_input[0], 0, MAX_CODE_LENGTH);
  122. memset(&plugin_state->iv[0], 0, TOTP_IV_SIZE);
  123. scene_state->code_length = 0;
  124. DialogMessage* message = dialog_message_alloc();
  125. dialog_message_set_buttons(message, "Try again", NULL, NULL);
  126. dialog_message_set_header(message, "You entered\ninvalid PIN", SCREEN_WIDTH_CENTER - 25, SCREEN_HEIGHT_CENTER - 5, AlignCenter, AlignCenter);
  127. dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17);
  128. dialog_message_show(plugin_state->dialogs, message);
  129. dialog_message_free(message);
  130. }
  131. break;
  132. case InputKeyBack:
  133. if (scene_state->code_length > 0) {
  134. scene_state->code_input[scene_state->code_length - 1] = 0;
  135. scene_state->code_length--;
  136. }
  137. break;
  138. }
  139. }
  140. }
  141. return true;
  142. }
  143. void totp_scene_authenticate_deactivate(PluginState* plugin_state) {
  144. if (plugin_state->current_scene_state == NULL) return;
  145. free(plugin_state->current_scene_state);
  146. plugin_state->current_scene_state = NULL;
  147. }
  148. void totp_scene_authenticate_free(PluginState* plugin_state) {
  149. UNUSED(plugin_state);
  150. }