Skip to content

Commit

Permalink
Implemented "type code in badusb mode"
Browse files Browse the repository at this point in the history
* Implemented #21
  • Loading branch information
akopachov authored Nov 10, 2022
1 parent 8064471 commit 329cf66
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 5 deletions.
7 changes: 7 additions & 0 deletions FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,15 @@ Detailed description of file format can be found [here](docs/conf-file_descripti
## Is there a CLI?

**YES!**

When Flipper Authenticator is running `totp` CLI is available for you to list, add or remove tokens. Run `totp help` to get list of available commands and arguments.

## Manually typing codes is boring, is there Bad USB mode?

**YES!**

Just pick the token you would like to auto-type then hold "arrow down" button for 1-2sec. and Flipper Authenticator will type it instead of you :)

## How to change\recover PIN?

For now there is no way to change or recover PIN once it is set without loosing all the token secrets. If you would like to completely reset app settings including PIN and all the tokens - just delete `/ext/apps/Misc/totp.conf` file. Flipper Authenticator will create new empty file and you will be able to setup everything from scratch.
Expand Down
42 changes: 37 additions & 5 deletions totp/scenes/generate_token/totp_scene_generate_token.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,21 @@
#include "../../services/roll_value/roll_value.h"
#include "../scene_director.h"
#include "../token_menu/totp_scene_token_menu.h"
#include "../../services/hid_worker/hid_worker.h"

#define TOKEN_LIFETIME 30
#define DIGIT_TO_CHAR(digit) ((digit) + '0')

typedef struct {
uint16_t current_token_index;
char last_code[9];
char last_code[TOTP_TOKEN_DIGITS_MAX_COUNT + 1];
char* last_code_name;
bool need_token_update;
uint32_t last_token_gen_time;
TotpHidWorkerTypeContext* hid_worker_context;
} SceneState;

static const NotificationSequence sequence_short_vibro_and_sound = {
static const NotificationSequence notification_sequence_new_token = {
&message_display_backlight_on,
&message_green_255,
&message_vibro_on,
Expand All @@ -36,6 +38,19 @@ static const NotificationSequence sequence_short_vibro_and_sound = {
NULL,
};

static const NotificationSequence notification_sequence_badusb = {
&message_vibro_on,
&message_note_d5,
&message_delay_50,
&message_note_e4,
&message_delay_50,
&message_note_f3,
&message_delay_50,
&message_vibro_off,
&message_sound_off,
NULL,
};

static void i_token_to_str(uint32_t i_token_code, char* str, TokenDigitsCount len) {
uint8_t str_token_length = 0;
if(len == TOTP_8_DIGITS) {
Expand Down Expand Up @@ -137,6 +152,9 @@ void totp_scene_generate_token_activate(
plugin_state->current_scene_state = scene_state;
FURI_LOG_D(LOGGING_TAG, "Timezone set to: %f", (double)plugin_state->timezone_offset);
update_totp_params(plugin_state);
scene_state->hid_worker_context = totp_hid_worker_start();
scene_state->hid_worker_context->string = &scene_state->last_code[0];
scene_state->hid_worker_context->string_length = TOTP_TOKEN_DIGITS_MAX_COUNT + 1;
}

void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_state) {
Expand Down Expand Up @@ -172,12 +190,13 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
scene_state->need_token_update = false;
scene_state->last_token_gen_time = curr_ts;

TokenInfo* tokenInfo =
const TokenInfo* tokenInfo =
(TokenInfo*)(list_element_at(
plugin_state->tokens_list, scene_state->current_token_index)
->data);

if(tokenInfo->token != NULL && tokenInfo->token_length > 0) {
furi_mutex_acquire(scene_state->hid_worker_context->string_sync, FuriWaitForever);
size_t key_length;
uint8_t* key = totp_crypto_decrypt(
tokenInfo->token, tokenInfo->token_length, &plugin_state->iv[0], &key_length);
Expand All @@ -196,11 +215,14 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
memset_s(key, key_length, 0, key_length);
free(key);
} else {
furi_mutex_acquire(scene_state->hid_worker_context->string_sync, FuriWaitForever);
i_token_to_str(0, scene_state->last_code, tokenInfo->digits);
}

furi_mutex_release(scene_state->hid_worker_context->string_sync);

if(is_new_token_time) {
notification_message(plugin_state->notification, &sequence_short_vibro_and_sound);
notification_message(plugin_state->notification, &notification_sequence_new_token);
}
}

Expand Down Expand Up @@ -263,11 +285,19 @@ bool totp_scene_generate_token_handle_event(
return false;
}

SceneState* scene_state;
if(event->input.type == InputTypeLong && event->input.key == InputKeyDown) {
scene_state = (SceneState*)plugin_state->current_scene_state;
totp_hid_worker_notify(scene_state->hid_worker_context, TotpHidWorkerEvtType);
notification_message(plugin_state->notification, &notification_sequence_badusb);
return true;
}

if(event->input.type != InputTypePress) {
return true;
}

SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
scene_state = (SceneState*)plugin_state->current_scene_state;
switch(event->input.key) {
case InputKeyUp:
break;
Expand Down Expand Up @@ -312,6 +342,8 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) {
if(plugin_state->current_scene_state == NULL) return;
SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;

totp_hid_worker_stop(scene_state->hid_worker_context);

free(scene_state);
plugin_state->current_scene_state = NULL;
}
Expand Down
100 changes: 100 additions & 0 deletions totp/services/hid_worker/hid_worker.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#include "hid_worker.h"

const uint8_t hid_number_keys[10] = {
HID_KEYBOARD_0,
HID_KEYBOARD_1,
HID_KEYBOARD_2,
HID_KEYBOARD_3,
HID_KEYBOARD_4,
HID_KEYBOARD_5,
HID_KEYBOARD_6,
HID_KEYBOARD_7,
HID_KEYBOARD_8,
HID_KEYBOARD_9};

static void totp_hid_worker_type_code(TotpHidWorkerTypeContext* context) {
FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config();
furi_hal_usb_unlock();
furi_check(furi_hal_usb_set_config(&usb_hid, NULL) == true);
uint8_t i = 0;
do {
furi_delay_ms(500);
i++;
} while(!furi_hal_hid_is_connected() && i < 100);

if(furi_hal_hid_is_connected() &&
furi_mutex_acquire(context->string_sync, 500) == FuriStatusOk) {
i = 0;
while(i < context->string_length && context->string[i] != 0) {
uint8_t digit = context->string[i] - '0';
if(digit > 9) break;
uint8_t hid_kb_key = hid_number_keys[digit];
furi_hal_hid_kb_press(hid_kb_key);
furi_delay_ms(30);
furi_hal_hid_kb_release(hid_kb_key);
i++;
}

furi_mutex_release(context->string_sync);

furi_hal_hid_kb_press(HID_KEYBOARD_RETURN);
furi_delay_ms(30);
furi_hal_hid_kb_release(HID_KEYBOARD_RETURN);

furi_delay_ms(100);
}

furi_hal_usb_set_config(usb_mode_prev, NULL);
}

static int32_t totp_hid_worker_callback(void* context) {
ValueMutex context_mutex;
if(!init_mutex(&context_mutex, context, sizeof(TotpHidWorkerTypeContext))) {
return 251;
}

while(true) {
uint32_t flags = furi_thread_flags_wait(
TotpHidWorkerEvtStop | TotpHidWorkerEvtType, FuriFlagWaitAny, FuriWaitForever);
furi_check((flags & FuriFlagError) == 0); //-V562
if(flags & TotpHidWorkerEvtStop) break;

TotpHidWorkerTypeContext* h_context = acquire_mutex_block(&context_mutex);
if(flags & TotpHidWorkerEvtType) {
totp_hid_worker_type_code(h_context);
}

release_mutex(&context_mutex, h_context);
}

delete_mutex(&context_mutex);

return 0;
}

TotpHidWorkerTypeContext* totp_hid_worker_start() {
TotpHidWorkerTypeContext* context = malloc(sizeof(TotpHidWorkerTypeContext));
furi_check(context != NULL);
context->string_sync = furi_mutex_alloc(FuriMutexTypeNormal);
context->thread = furi_thread_alloc();
furi_thread_set_name(context->thread, "TOTPHidWorker");
furi_thread_set_stack_size(context->thread, 1024);
furi_thread_set_context(context->thread, context);
furi_thread_set_callback(context->thread, totp_hid_worker_callback);
furi_thread_start(context->thread);
return context;
}

void totp_hid_worker_stop(TotpHidWorkerTypeContext* context) {
furi_assert(context);
furi_thread_flags_set(furi_thread_get_id(context->thread), TotpHidWorkerEvtStop);
furi_thread_join(context->thread);
furi_thread_free(context->thread);
furi_mutex_free(context->string_sync);
free(context);
}

void totp_hid_worker_notify(TotpHidWorkerTypeContext* context, TotpHidWorkerEvtFlags event) {
furi_assert(context);
furi_thread_flags_set(furi_thread_get_id(context->thread), event);
}
22 changes: 22 additions & 0 deletions totp/services/hid_worker/hid_worker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include <stdlib.h>
#include <furi/furi.h>
#include <furi_hal.h>

typedef struct {
char* string;
uint8_t string_length;
FuriThread* thread;
FuriMutex* string_sync;
} TotpHidWorkerTypeContext;

typedef enum {
TotpHidWorkerEvtReserved = (1 << 0),
TotpHidWorkerEvtStop = (1 << 1),
TotpHidWorkerEvtType = (1 << 2)
} TotpHidWorkerEvtFlags;

TotpHidWorkerTypeContext* totp_hid_worker_start();
void totp_hid_worker_stop(TotpHidWorkerTypeContext* context);
void totp_hid_worker_notify(TotpHidWorkerTypeContext* context, TotpHidWorkerEvtFlags event);
2 changes: 2 additions & 0 deletions totp/types/token_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ typedef enum { SHA1, SHA256, SHA512 } TokenHashAlgo;

typedef enum { TOTP_6_DIGITS, TOTP_8_DIGITS } TokenDigitsCount;

#define TOTP_TOKEN_DIGITS_MAX_COUNT 8

typedef struct {
uint8_t* token;
size_t token_length;
Expand Down

0 comments on commit 329cf66

Please sign in to comment.