|
| 1 | +#include <furi.h> |
| 2 | +#include <furi_hal.h> |
| 3 | + |
| 4 | +#include <gui/gui.h> |
| 5 | +#include <input/input.h> |
| 6 | + |
| 7 | +#include <notification/notification_messages.h> |
| 8 | + |
| 9 | +#include <totp.h> |
| 10 | +#include "totp_app.h" |
| 11 | + |
| 12 | +#include <base32.h> |
| 13 | +#include <time.h> |
| 14 | + |
| 15 | +#include <toolbox/path.h> |
| 16 | +#include <flipper_format/flipper_format.h> |
| 17 | + |
| 18 | +static const char* totp_file_header = "Flipper TOTP storage"; |
| 19 | +static const uint32_t totp_file_version = 1; |
| 20 | + |
| 21 | +typedef enum { |
| 22 | + TotpEventTypeTick, |
| 23 | + TotpEventTypeInput, |
| 24 | +} TotpEventType; |
| 25 | + |
| 26 | +typedef struct { |
| 27 | + TotpEventType type; |
| 28 | + InputEvent input; |
| 29 | + uint32_t code; |
| 30 | +} TotpEvent; |
| 31 | + |
| 32 | +uint8_t keyId = 0; |
| 33 | +uint8_t keys = 3; |
| 34 | +uint8_t* base32key[] = { |
| 35 | + (unsigned char*)"JBSWY3DPEHPK3PXP", |
| 36 | + (unsigned char*)"AMOGUSYOBABOBAAA", |
| 37 | + (unsigned char*)"AMOGUSAAAAAAAAAA"}; |
| 38 | +const char* keyNames[] = {"Test Key 1", "Test Key 2", "Amogus key"}; |
| 39 | + |
| 40 | +int keyLengths[] = {10, 10, 10}; |
| 41 | + |
| 42 | +static void totp_app_draw_callback(Canvas* canvas, void* ctx) { |
| 43 | + osMessageQueueId_t event_queue = ctx; |
| 44 | + TotpEvent event; |
| 45 | + osMessageQueueGet(event_queue, &event, NULL, osWaitForever); |
| 46 | + |
| 47 | + uint8_t hmacKey[20]; |
| 48 | + |
| 49 | + int timezone = -3; |
| 50 | + |
| 51 | + canvas_clear(canvas); |
| 52 | + canvas_set_font(canvas, FontPrimary); |
| 53 | + canvas_draw_str(canvas, 2, 10, "TOTP"); |
| 54 | + canvas_draw_str(canvas, 2, 30, keyNames[keyId]); |
| 55 | + |
| 56 | + //FURI_LOG_I("TOTP", "key is %s", base32key[keyId]); |
| 57 | + |
| 58 | + base32_decode(base32key[keyId], hmacKey, keyLengths[keyId]); |
| 59 | + //FURI_LOG_I("TOTP", "len = %d", len); |
| 60 | + |
| 61 | + //uint8_t hmacKey[] = {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0xde, 0xad, 0xbe, 0xef}; // Secret key |
| 62 | + TOTP(hmacKey, keyLengths[keyId], 30); // Secret key, Secret key length, Timestep (30s) |
| 63 | + |
| 64 | + FuriHalRtcDateTime datetime = {0}; |
| 65 | + furi_hal_rtc_get_datetime(&datetime); |
| 66 | + |
| 67 | + struct tm date = {0}; |
| 68 | + date.tm_hour = datetime.hour + timezone; |
| 69 | + date.tm_min = datetime.minute; |
| 70 | + date.tm_sec = datetime.second; |
| 71 | + date.tm_mday = datetime.day; |
| 72 | + date.tm_mon = datetime.month - 1; |
| 73 | + date.tm_year = datetime.year - 1900; |
| 74 | + // god i hate these 5 lines |
| 75 | + |
| 76 | + uint32_t newCode = getCodeFromTimestamp(mktime(&date)); |
| 77 | + //FURI_LOG_I("TOTP", "%06ld", newCode); |
| 78 | + char code_string[100] = ""; |
| 79 | + sprintf(code_string, "%06ld", newCode); |
| 80 | + canvas_draw_str(canvas, 2, 20, code_string); |
| 81 | + sprintf(code_string, "%d seconds left", 29 - date.tm_sec % 30); |
| 82 | + canvas_draw_str(canvas, 2, 40, code_string); |
| 83 | + sprintf( |
| 84 | + code_string, |
| 85 | + "%02d:%02d:%02d %02d-%02d-%04d", |
| 86 | + datetime.hour + timezone, |
| 87 | + datetime.minute, |
| 88 | + datetime.second, |
| 89 | + datetime.day, |
| 90 | + datetime.month, |
| 91 | + datetime.year); |
| 92 | + canvas_draw_str(canvas, 2, 50, code_string); |
| 93 | + canvas_draw_box(canvas, 0, 52, (29 - (date.tm_sec % 30)) * 4.414, 10); |
| 94 | +} |
| 95 | + |
| 96 | +static void totp_app_input_callback(InputEvent* input_event, void* ctx) { |
| 97 | + furi_assert(ctx); |
| 98 | + osMessageQueueId_t event_queue = ctx; |
| 99 | + |
| 100 | + TotpEvent event = {.type = TotpEventTypeInput, .input = *input_event}; |
| 101 | + osMessageQueuePut(event_queue, &event, 0, osWaitForever); |
| 102 | +} |
| 103 | + |
| 104 | +void totp_app_update(void* ctx) { |
| 105 | + furi_assert(ctx); |
| 106 | + osMessageQueueId_t event_queue = ctx; |
| 107 | + TotpEvent event = {.type = TotpEventTypeTick}; |
| 108 | + osMessageQueuePut(event_queue, &event, 0, 0); |
| 109 | +} |
| 110 | + |
| 111 | +int32_t totp_app(void* p) { |
| 112 | + UNUSED(p); |
| 113 | + bool saved = false; |
| 114 | + Storage* storage = furi_record_open("storage"); |
| 115 | + FlipperFormat* file = flipper_format_file_alloc(storage); |
| 116 | + string_t temp_str; |
| 117 | + char key_name[50] = ""; |
| 118 | + string_init(temp_str); |
| 119 | + |
| 120 | + do { |
| 121 | + // Create nfc directory if necessary |
| 122 | + if(!storage_simply_mkdir(storage, TOTP_APP_FOLDER)) break; |
| 123 | + // Open file |
| 124 | + string_printf(temp_str, "%s/%s%s", "/ext/totp", "keys", ".totp"); |
| 125 | + // Open file |
| 126 | + if(!flipper_format_file_open_always(file, string_get_cstr(temp_str))) break; |
| 127 | + // Write header |
| 128 | + if(!flipper_format_write_header_cstr(file, totp_file_header, totp_file_version)) break; |
| 129 | + // Write nfc device type |
| 130 | + //nfc_device_prepare_format_string(dev, temp_str); |
| 131 | + |
| 132 | + for(int key = 0; key < keys; key++) { |
| 133 | + string_printf(temp_str, "%s", base32key[key]); |
| 134 | + sprintf(key_name, "%s", keyNames[key]); |
| 135 | + |
| 136 | + if(!flipper_format_write_string(file, key_name, temp_str)) break; |
| 137 | + } |
| 138 | + //if(!flipper_format_write_hex(file, "Totp key 1", base32key[0], sizeof(base32key[0]))) |
| 139 | + // break; |
| 140 | + // Write UID, ATQA, SAK |
| 141 | + //if(!flipper_format_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats")) |
| 142 | + // break; |
| 143 | + //if(!flipper_format_write_hex(file, "UID", data->uid, data->uid_len)) break; |
| 144 | + //if(!flipper_format_write_hex(file, "ATQA", data->atqa, 2)) break; |
| 145 | + //if(!flipper_format_write_hex(file, "SAK", &data->sak, 1)) break; |
| 146 | + // Save more data if necessary |
| 147 | + //if(dev->format == NfcDeviceSaveFormatMifareUl) { |
| 148 | + // if(!nfc_device_save_mifare_ul_data(file, dev)) break; |
| 149 | + //} else if(dev->format == NfcDeviceSaveFormatBankCard) { |
| 150 | + // if(!nfc_device_save_bank_card_data(file, dev)) break; |
| 151 | + //} |
| 152 | + saved = true; |
| 153 | + } while(0); |
| 154 | + if(saved) { |
| 155 | + flipper_format_free(file); |
| 156 | + furi_record_close("storage"); |
| 157 | + } else { |
| 158 | + flipper_format_free(file); |
| 159 | + furi_record_close("storage"); |
| 160 | + } |
| 161 | + |
| 162 | + osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(TotpEvent), NULL); |
| 163 | + // Configure view port |
| 164 | + ViewPort* view_port = view_port_alloc(); |
| 165 | + view_port_input_callback_set(view_port, totp_app_input_callback, event_queue); |
| 166 | + view_port_draw_callback_set(view_port, totp_app_draw_callback, NULL); |
| 167 | + |
| 168 | + // Register view port in GUI |
| 169 | + Gui* gui = furi_record_open("gui"); |
| 170 | + gui_add_view_port(gui, view_port, GuiLayerFullscreen); |
| 171 | + view_port_update(view_port); |
| 172 | + |
| 173 | + osTimerId_t timer = osTimerNew(totp_app_update, osTimerPeriodic, event_queue, NULL); |
| 174 | + osTimerStart(timer, osKernelGetTickFreq()); |
| 175 | + |
| 176 | + TotpEvent event; |
| 177 | + |
| 178 | + while(1) { |
| 179 | + view_port_update(view_port); |
| 180 | + furi_check(osMessageQueueGet(event_queue, &event, NULL, osWaitForever) == osOK); |
| 181 | + |
| 182 | + if((event.input.type == InputTypeShort) && (event.input.key == InputKeyBack)) { |
| 183 | + break; |
| 184 | + } else if((event.input.type == InputTypeShort) && (event.input.key == InputKeyRight)) { |
| 185 | + if(keyId < keys - 1) { |
| 186 | + keyId++; |
| 187 | + } else { |
| 188 | + keyId = 0; |
| 189 | + } |
| 190 | + } else if((event.input.type == InputTypeShort) && (event.input.key == InputKeyLeft)) { |
| 191 | + if(keyId > 0) { |
| 192 | + keyId--; |
| 193 | + } else { |
| 194 | + keyId = keys - 1; |
| 195 | + } |
| 196 | + } |
| 197 | + } |
| 198 | + |
| 199 | + osTimerDelete(timer); |
| 200 | + |
| 201 | + gui_remove_view_port(gui, view_port); |
| 202 | + view_port_free(view_port); |
| 203 | + osMessageQueueDelete(event_queue); |
| 204 | + |
| 205 | + furi_record_close("gui"); |
| 206 | + return 0; |
| 207 | +} |
0 commit comments