Merge remote-tracking branch 'origin/release-candidate' into release

This commit is contained in:
Aleksandr Kutuzov 2023-12-08 16:08:51 +09:00
commit 5dbe1cf0bc
195 changed files with 2734 additions and 10584 deletions

View File

@ -1 +1 @@
--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/*
--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/microtar -e lib/mlib -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/*

View File

@ -288,13 +288,17 @@ distenv.PhonyTarget(
LINT_SOURCES=[n.srcnode() for n in firmware_env["LINT_SOURCES"]],
)
# PY_LINT_SOURCES contains recursively-built modules' SConscript files + application manifests
# PY_LINT_SOURCES contains recursively-built modules' SConscript files
# Here we add additional Python files residing in repo root
firmware_env.Append(
PY_LINT_SOURCES=[
# Py code folders
"site_scons",
"scripts",
"applications",
"applications_user",
"assets",
"targets",
# Extra files
"SConstruct",
"firmware.scons",
@ -304,7 +308,10 @@ firmware_env.Append(
black_commandline = "@${PYTHON3} -m black ${PY_BLACK_ARGS} ${PY_LINT_SOURCES}"
black_base_args = ["--include", '"\\.scons|\\.py|SConscript|SConstruct"']
black_base_args = [
"--include",
'"(\\.scons|\\.py|SConscript|SConstruct|\\.fam)$"',
]
distenv.PhonyTarget(
"lint_py",

View File

@ -13,12 +13,12 @@ struct ISO7816_Command_APDU {
//body
uint8_t Lc;
uint8_t Le;
} __attribute__((packed));
} FURI_PACKED;
struct ISO7816_Response_APDU {
uint8_t SW1;
uint8_t SW2;
} __attribute__((packed));
} FURI_PACKED;
void iso7816_answer_to_reset(uint8_t* atrBuffer, uint32_t* atrlen);
void iso7816_read_command_apdu(

View File

@ -4,7 +4,7 @@ App(
apptype=FlipperAppType.DEBUG,
entry_point="display_test_app",
requires=["gui"],
fap_libs=["misc"],
fap_libs=["u8g2"],
stack_size=1 * 1024,
order=120,
fap_category="Debug",

View File

@ -455,4 +455,19 @@ NfcError nfc_iso15693_listener_tx_sof(Nfc* instance) {
return NfcErrorNone;
}
NfcError nfc_felica_listener_set_sensf_res_data(
Nfc* instance,
const uint8_t* idm,
const uint8_t idm_len,
const uint8_t* pmm,
const uint8_t pmm_len) {
furi_assert(instance);
furi_assert(idm);
furi_assert(pmm);
furi_assert(idm_len == 8);
furi_assert(pmm_len == 8);
return NfcErrorNone;
}
#endif

View File

@ -1,27 +1,31 @@
#include "flipper.pb.h"
#include <core/check.h>
#include <core/record.h>
#include "pb_decode.h"
#include <rpc/rpc.h>
#include "rpc/rpc_i.h"
#include "storage.pb.h"
#include "storage/filesystem_api_defines.h"
#include "storage/storage.h"
#include <furi.h>
#include "../minunit.h"
#include <stdint.h>
#include <pb.h>
#include <pb_encode.h>
#include <m-list.h>
#include <lib/toolbox/md5_calc.h>
#include <lib/toolbox/path.h>
#include <cli/cli.h>
#include <loader/loader.h>
#include <protobuf_version.h>
#include <FreeRTOS.h>
#include <semphr.h>
#include <rpc/rpc.h>
#include <rpc/rpc_i.h>
#include <cli/cli.h>
#include <storage/storage.h>
#include <loader/loader.h>
#include <storage/filesystem_api_defines.h>
#include <lib/toolbox/md5_calc.h>
#include <lib/toolbox/path.h>
#include <m-list.h>
#include "../minunit.h"
#include <protobuf_version.h>
#include <pb.h>
#include <pb_encode.h>
#include <pb_decode.h>
#include <storage.pb.h>
#include <flipper.pb.h>
LIST_DEF(MsgList, PB_Main, M_POD_OPLIST)
#define M_OPL_MsgList_t() LIST_OPLIST(MsgList)

View File

@ -14,6 +14,7 @@ App(
entry_point="advanced_plugin1_ep",
requires=["example_advanced_plugins"],
sources=["plugin1.c"],
fal_embedded=True,
)
App(
@ -22,4 +23,5 @@ App(
entry_point="advanced_plugin2_ep",
requires=["example_advanced_plugins"],
sources=["plugin2.c"],
fal_embedded=True,
)

View File

@ -23,7 +23,10 @@ int32_t example_advanced_plugins_app(void* p) {
PLUGIN_APP_ID, PLUGIN_API_VERSION, composite_api_resolver_get(resolver));
do {
if(plugin_manager_load_all(manager, APP_DATA_PATH("plugins")) != PluginManagerErrorNone) {
// For built-in .fals (fal_embedded==True), use APP_ASSETS_PATH
// Otherwise, use APP_DATA_PATH
if(plugin_manager_load_all(manager, APP_ASSETS_PATH("plugins")) !=
PluginManagerErrorNone) {
FURI_LOG_E(TAG, "Failed to load all libs");
break;
}

View File

@ -13,7 +13,7 @@ App(
"!plugins",
"!nfc_cli.c",
],
fap_libs=["assets"],
fap_libs=["assets", "mbedtls"],
fap_icon="icon.png",
fap_category="NFC",
)
@ -74,6 +74,15 @@ App(
sources=["plugins/supported_cards/two_cities.c"],
)
App(
appid="aime_parser",
apptype=FlipperAppType.PLUGIN,
entry_point="aime_plugin_ep",
targets=["f7"],
requires=["nfc"],
sources=["plugins/supported_cards/aime.c"],
)
App(
appid="nfc_start",
targets=["f7"],

View File

@ -67,8 +67,14 @@ static bool nfc_scene_saved_menu_on_event_felica(NfcApp* instance, uint32_t even
return false;
}
static void nfc_scene_emulate_on_enter_felica(NfcApp* instance) {
const FelicaData* data = nfc_device_get_data(instance->nfc_device, NfcProtocolFelica);
instance->listener = nfc_listener_alloc(instance->nfc, NfcProtocolFelica, data);
nfc_listener_start(instance->listener, NULL, NULL);
}
const NfcProtocolSupportBase nfc_protocol_support_felica = {
.features = NfcProtocolFeatureNone,
.features = NfcProtocolFeatureEmulateUid,
.scene_info =
{
@ -102,7 +108,7 @@ const NfcProtocolSupportBase nfc_protocol_support_felica = {
},
.scene_emulate =
{
.on_enter = nfc_protocol_support_common_on_enter_empty,
.on_enter = nfc_scene_emulate_on_enter_felica,
.on_event = nfc_protocol_support_common_on_event_empty,
},
};

View File

@ -12,6 +12,7 @@ enum {
SubmenuIndexUnlock = SubmenuIndexCommonMax,
SubmenuIndexUnlockByReader,
SubmenuIndexUnlockByPassword,
SubmenuIndexWrite,
};
static void nfc_scene_info_on_enter_mf_ultralight(NfcApp* instance) {
@ -106,6 +107,15 @@ static void nfc_scene_read_and_saved_menu_on_enter_mf_ultralight(NfcApp* instanc
SubmenuIndexUnlock,
nfc_protocol_support_common_submenu_callback,
instance);
} else if(
data->type == MfUltralightTypeNTAG213 || data->type == MfUltralightTypeNTAG215 ||
data->type == MfUltralightTypeNTAG216) {
submenu_add_item(
submenu,
"Write",
SubmenuIndexWrite,
nfc_protocol_support_common_submenu_callback,
instance);
}
}
@ -146,6 +156,9 @@ static bool
if(event == SubmenuIndexUnlock) {
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightUnlockMenu);
return true;
} else if(event == SubmenuIndexWrite) {
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWrite);
return true;
}
return false;
}

View File

@ -29,7 +29,9 @@ static NfcCommand nfc_scene_read_poller_callback_st25tb(NfcGenericEvent event, v
NfcApp* instance = context;
const St25tbPollerEvent* st25tb_event = event.event_data;
if(st25tb_event->type == St25tbPollerEventTypeReady) {
if(st25tb_event->type == St25tbPollerEventTypeRequestMode) {
st25tb_event->data->mode_request.mode = St25tbPollerModeRead;
} else if(st25tb_event->type == St25tbPollerEventTypeSuccess) {
nfc_device_set_data(
instance->nfc_device, NfcProtocolSt25tb, nfc_poller_get_data(instance->poller));
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess);

View File

@ -400,15 +400,16 @@ bool nfc_load_from_file_select(NfcApp* instance) {
browser_options.base_path = NFC_APP_FOLDER;
browser_options.hide_dot_files = true;
// Input events and views are managed by file_browser
bool result = dialog_file_browser_show(
instance->dialogs, instance->file_path, instance->file_path, &browser_options);
bool success = false;
do {
// Input events and views are managed by file_browser
if(!dialog_file_browser_show(
instance->dialogs, instance->file_path, instance->file_path, &browser_options))
break;
success = nfc_load_file(instance, instance->file_path, true);
} while(!success);
if(result) {
result = nfc_load_file(instance, instance->file_path, true);
}
return result;
return success;
}
void nfc_show_loading_popup(void* context, bool show) {

View File

@ -0,0 +1,169 @@
#include "nfc_supported_card_plugin.h"
#include <flipper_application/flipper_application.h>
#include <nfc/nfc_device.h>
#include <nfc/helpers/nfc_util.h>
#include <nfc/protocols/mf_classic/mf_classic_poller_sync.h>
#define TAG "Aime"
static const uint64_t aime_key = 0x574343467632;
bool aime_verify(Nfc* nfc) {
bool verified = false;
do {
const uint8_t verify_sector = 0;
uint8_t block_num = mf_classic_get_first_block_num_of_sector(verify_sector);
FURI_LOG_D(TAG, "Verifying sector %u", verify_sector);
MfClassicKey key = {};
nfc_util_num2bytes(aime_key, COUNT_OF(key.data), key.data);
MfClassicAuthContext auth_ctx = {};
MfClassicError error =
mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_ctx);
if(error != MfClassicErrorNone) {
FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error);
break;
}
verified = true;
} while(false);
return verified;
}
static bool aime_read(Nfc* nfc, NfcDevice* device) {
furi_assert(nfc);
furi_assert(device);
bool is_read = false;
MfClassicData* data = mf_classic_alloc();
nfc_device_copy_data(device, NfcProtocolMfClassic, data);
do {
MfClassicType type = MfClassicType1k;
MfClassicError error = mf_classic_poller_sync_detect_type(nfc, &type);
if(error != MfClassicErrorNone) break;
data->type = type;
MfClassicDeviceKeys keys = {};
for(size_t i = 0; i < mf_classic_get_total_sectors_num(data->type); i++) {
nfc_util_num2bytes(aime_key, sizeof(MfClassicKey), keys.key_a[i].data);
FURI_BIT_SET(keys.key_a_mask, i);
nfc_util_num2bytes(aime_key, sizeof(MfClassicKey), keys.key_b[i].data);
FURI_BIT_SET(keys.key_b_mask, i);
}
error = mf_classic_poller_sync_read(nfc, &keys, data);
if(error != MfClassicErrorNone) {
FURI_LOG_W(TAG, "Failed to read data");
break;
}
nfc_device_set_data(device, NfcProtocolMfClassic, data);
is_read = true;
} while(false);
mf_classic_free(data);
return is_read;
}
static bool aime_parse(const NfcDevice* device, FuriString* parsed_data) {
furi_assert(device);
const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic);
bool parsed = false;
do {
// verify key
MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 0);
uint64_t key = nfc_util_bytes2num(sec_tr->key_a.data, 6);
if(key != aime_key) break;
// Aime Magic is stored at block 1, starts from byte 0, len 4 bytes
const uint8_t* aime_magic = &data->block[1].data[0];
// verify aime magic
if(aime_magic[0] != 'S' || aime_magic[1] != 'B' || aime_magic[2] != 'S' ||
aime_magic[3] != 'D')
break;
// Aime checksum is stored at block 1, starts from byte 13, len 3 bytes
// seems like only old games checks this? e.g., old versions of Chunithm
const uint8_t* aime_checksum = &data->block[1].data[13];
// Aime access code is stored as decimal hex representation in block 2, starts from byte 6, len 10 bytes
const uint8_t* aime_accesscode = &data->block[2].data[6];
char aime_accesscode_str[24 + 1];
snprintf(
aime_accesscode_str,
sizeof(aime_accesscode_str),
"%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x",
aime_accesscode[0],
aime_accesscode[1],
aime_accesscode[2],
aime_accesscode[3],
aime_accesscode[4],
aime_accesscode[5],
aime_accesscode[6],
aime_accesscode[7],
aime_accesscode[8],
aime_accesscode[9]);
// validate decimal hex representation
bool code_is_hex = true;
for(int i = 0; i < 24; i++) {
if(aime_accesscode_str[i] == ' ') continue;
if(aime_accesscode_str[i] < '0' || aime_accesscode_str[i] > '9') {
code_is_hex = false;
break;
}
}
if(!code_is_hex) break;
// Note: Aime access code has some other self-check algorithms that are not public.
// This parser does not try to verify the number.
furi_string_printf(
parsed_data,
"\e#Aime Card\nAccess Code: \n%s\nChecksum: %02X%02X%02X\n",
aime_accesscode_str,
aime_checksum[0],
aime_checksum[1],
aime_checksum[2]);
parsed = true;
} while(false);
return parsed;
}
/* Actual implementation of app<>plugin interface */
static const NfcSupportedCardsPlugin aime_plugin = {
.protocol = NfcProtocolMfClassic,
.verify = aime_verify,
.read = aime_read,
.parse = aime_parse,
};
/* Plugin descriptor to comply with basic plugin specification */
static const FlipperAppPluginDescriptor aime_plugin_descriptor = {
.appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID,
.ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION,
.entry_point = &aime_plugin,
};
/* Plugin entry point - must return a pointer to const descriptor */
const FlipperAppPluginDescriptor* aime_plugin_ep() {
return &aime_plugin_descriptor;
}

View File

@ -24,6 +24,10 @@ ADD_SCENE(nfc, field, Field)
ADD_SCENE(nfc, retry_confirm, RetryConfirm)
ADD_SCENE(nfc, exit_confirm, ExitConfirm)
ADD_SCENE(nfc, mf_ultralight_write, MfUltralightWrite)
ADD_SCENE(nfc, mf_ultralight_write_success, MfUltralightWriteSuccess)
ADD_SCENE(nfc, mf_ultralight_write_fail, MfUltralightWriteFail)
ADD_SCENE(nfc, mf_ultralight_wrong_card, MfUltralightWrongCard)
ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu)
ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn)
ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput)

View File

@ -37,6 +37,7 @@ bool nfc_scene_detect_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventWorkerExit) {
if(instance->protocols_detected_num > 1) {
notification_message(instance->notifications, &sequence_single_vibro);
scene_manager_next_scene(instance->scene_manager, NfcSceneSelectProtocol);
} else {
scene_manager_next_scene(instance->scene_manager, NfcSceneRead);

View File

@ -45,11 +45,7 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexMfClassicKeys) {
if(nfc_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_USER_PATH)) {
scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicKeys);
} else {
scene_manager_previous_scene(instance->scene_manager);
}
scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicKeys);
consumed = true;
} else if(event.event == SubmenuIndexMfUltralightUnlock) {
mf_ultralight_auth_reset(instance->mf_ul_auth);

View File

@ -52,11 +52,12 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve
bool consumed = false;
nfc->protocols_detected[0] = nfc_device_get_protocol(nfc->nfc_device);
MfUltralightAuthType type = nfc->mf_ul_auth->type;
if((type == MfUltralightAuthTypeReader) || (type == MfUltralightAuthTypeManual)) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == DialogExResultRight) {
const NfcProtocol mfu_protocol[] = {NfcProtocolMfUltralight};
nfc_app_set_detected_protocols(nfc, mfu_protocol, COUNT_OF(mfu_protocol));
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
dolphin_deed(DolphinDeedNfcRead);
consumed = true;

View File

@ -0,0 +1,119 @@
#include "../nfc_app_i.h"
#include <nfc/protocols/mf_ultralight/mf_ultralight_poller.h>
enum {
NfcSceneMfUltralightWriteStateCardSearch,
NfcSceneMfUltralightWriteStateCardFound,
};
NfcCommand nfc_scene_mf_ultralight_write_worker_callback(NfcGenericEvent event, void* context) {
furi_assert(context);
furi_assert(event.event_data);
furi_assert(event.protocol == NfcProtocolMfUltralight);
NfcCommand command = NfcCommandContinue;
NfcApp* instance = context;
MfUltralightPollerEvent* mfu_event = event.event_data;
if(mfu_event->type == MfUltralightPollerEventTypeRequestMode) {
mfu_event->data->poller_mode = MfUltralightPollerModeWrite;
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventCardDetected);
} else if(mfu_event->type == MfUltralightPollerEventTypeAuthRequest) {
mfu_event->data->auth_context.skip_auth = true;
} else if(mfu_event->type == MfUltralightPollerEventTypeRequestWriteData) {
mfu_event->data->write_data =
nfc_device_get_data(instance->nfc_device, NfcProtocolMfUltralight);
} else if(mfu_event->type == MfUltralightPollerEventTypeCardMismatch) {
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventWrongCard);
command = NfcCommandStop;
} else if(mfu_event->type == MfUltralightPollerEventTypeCardLocked) {
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerFailure);
command = NfcCommandStop;
} else if(mfu_event->type == MfUltralightPollerEventTypeWriteFail) {
command = NfcCommandStop;
} else if(mfu_event->type == MfUltralightPollerEventTypeWriteSuccess) {
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess);
command = NfcCommandStop;
}
return command;
}
static void nfc_scene_mf_ultralight_write_setup_view(NfcApp* instance) {
Popup* popup = instance->popup;
popup_reset(popup);
uint32_t state =
scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfUltralightWrite);
if(state == NfcSceneMfUltralightWriteStateCardSearch) {
popup_set_text(
instance->popup, "Apply the initial\ncard only", 128, 32, AlignRight, AlignCenter);
popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50);
} else {
popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter);
popup_set_icon(popup, 12, 23, &A_Loading_24);
}
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup);
}
void nfc_scene_mf_ultralight_write_on_enter(void* context) {
NfcApp* instance = context;
dolphin_deed(DolphinDeedNfcEmulate);
scene_manager_set_scene_state(
instance->scene_manager,
NfcSceneMfUltralightWrite,
NfcSceneMfUltralightWriteStateCardSearch);
nfc_scene_mf_ultralight_write_setup_view(instance);
// Setup and start worker
FURI_LOG_D("WMFU", "Card searching...");
instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfUltralight);
nfc_poller_start(instance->poller, nfc_scene_mf_ultralight_write_worker_callback, instance);
nfc_blink_emulate_start(instance);
}
bool nfc_scene_mf_ultralight_write_on_event(void* context, SceneManagerEvent event) {
NfcApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventCardDetected) {
scene_manager_set_scene_state(
instance->scene_manager,
NfcSceneMfUltralightWrite,
NfcSceneMfUltralightWriteStateCardFound);
nfc_scene_mf_ultralight_write_setup_view(instance);
consumed = true;
} else if(event.event == NfcCustomEventWrongCard) {
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWrongCard);
consumed = true;
} else if(event.event == NfcCustomEventPollerSuccess) {
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWriteSuccess);
consumed = true;
} else if(event.event == NfcCustomEventPollerFailure) {
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWriteFail);
consumed = true;
}
}
return consumed;
}
void nfc_scene_mf_ultralight_write_on_exit(void* context) {
NfcApp* instance = context;
nfc_poller_stop(instance->poller);
nfc_poller_free(instance->poller);
scene_manager_set_scene_state(
instance->scene_manager,
NfcSceneMfUltralightWrite,
NfcSceneMfUltralightWriteStateCardSearch);
// Clear view
popup_reset(instance->popup);
nfc_blink_stop(instance);
}

View File

@ -0,0 +1,67 @@
#include "../nfc_app_i.h"
void nfc_scene_mf_ultralight_write_fail_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
NfcApp* instance = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(instance->view_dispatcher, result);
}
}
void nfc_scene_mf_ultralight_write_fail_on_enter(void* context) {
NfcApp* instance = context;
Widget* widget = instance->widget;
notification_message(instance->notifications, &sequence_error);
widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48);
widget_add_string_element(
widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Writing gone wrong!");
widget_add_string_multiline_element(
widget,
7,
17,
AlignLeft,
AlignTop,
FontSecondary,
"Card protected by\npassword, AUTH0\nor lock bits");
widget_add_button_element(
widget,
GuiButtonTypeLeft,
"Finish",
nfc_scene_mf_ultralight_write_fail_widget_callback,
instance);
// Setup and start worker
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget);
}
static bool nfc_scene_mf_ultralight_write_fail_move_to_back_scene(const NfcApp* const instance) {
bool was_saved = scene_manager_has_previous_scene(instance->scene_manager, NfcSceneSavedMenu);
uint32_t scene_id = was_saved ? NfcSceneSavedMenu : NfcSceneReadMenu;
return scene_manager_search_and_switch_to_previous_scene(instance->scene_manager, scene_id);
}
bool nfc_scene_mf_ultralight_write_fail_on_event(void* context, SceneManagerEvent event) {
NfcApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) {
consumed = nfc_scene_mf_ultralight_write_fail_move_to_back_scene(instance);
}
} else if(event.type == SceneManagerEventTypeBack) {
consumed = nfc_scene_mf_ultralight_write_fail_move_to_back_scene(instance);
}
return consumed;
}
void nfc_scene_mf_ultralight_write_fail_on_exit(void* context) {
NfcApp* instance = context;
widget_reset(instance->widget);
}

View File

@ -0,0 +1,43 @@
#include "../nfc_app_i.h"
void nfc_scene_mf_ultralight_write_success_popup_callback(void* context) {
NfcApp* instance = context;
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventViewExit);
}
void nfc_scene_mf_ultralight_write_success_on_enter(void* context) {
NfcApp* instance = context;
dolphin_deed(DolphinDeedNfcSave);
notification_message(instance->notifications, &sequence_success);
Popup* popup = instance->popup;
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
popup_set_header(popup, "Successfully\nwritten", 13, 22, AlignLeft, AlignBottom);
popup_set_timeout(popup, 1500);
popup_set_context(popup, instance);
popup_set_callback(popup, nfc_scene_mf_ultralight_write_success_popup_callback);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup);
}
bool nfc_scene_mf_ultralight_write_success_on_event(void* context, SceneManagerEvent event) {
NfcApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventViewExit) {
consumed = scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, NfcSceneSavedMenu);
}
}
return consumed;
}
void nfc_scene_mf_ultralight_write_success_on_exit(void* context) {
NfcApp* instance = context;
// Clear view
popup_reset(instance->popup);
}

View File

@ -0,0 +1,58 @@
#include "../nfc_app_i.h"
void nfc_scene_mf_ultralight_wrong_card_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
NfcApp* instance = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(instance->view_dispatcher, result);
}
}
void nfc_scene_mf_ultralight_wrong_card_on_enter(void* context) {
NfcApp* instance = context;
Widget* widget = instance->widget;
notification_message(instance->notifications, &sequence_error);
widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48);
widget_add_string_element(
widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "This is wrong card");
widget_add_string_multiline_element(
widget,
4,
17,
AlignLeft,
AlignTop,
FontSecondary,
"Card of the same\ntype should be\n presented");
//"Data management\nis only possible\nwith card of same type");
widget_add_button_element(
widget,
GuiButtonTypeLeft,
"Retry",
nfc_scene_mf_ultralight_wrong_card_widget_callback,
instance);
// Setup and start worker
view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget);
}
bool nfc_scene_mf_ultralight_wrong_card_on_event(void* context, SceneManagerEvent event) {
NfcApp* instance = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeLeft) {
consumed = scene_manager_previous_scene(instance->scene_manager);
}
}
return consumed;
}
void nfc_scene_mf_ultralight_wrong_card_on_exit(void* context) {
NfcApp* instance = context;
widget_reset(instance->widget);
}

View File

@ -21,7 +21,6 @@ void nfc_scene_select_protocol_on_enter(void* context) {
} else {
prefix = "Read as";
submenu_set_header(submenu, "Multi-protocol card");
notification_message(instance->notifications, &sequence_single_vibro);
}
for(uint32_t i = 0; i < instance->protocols_detected_num; i++) {

View File

@ -125,7 +125,6 @@ void dict_attack_reset(DictAttack* instance) {
instance->view,
DictAttackViewModel * model,
{
model->card_detected = false;
model->sectors_total = 0;
model->sectors_read = 0;
model->current_sector = 0;

View File

@ -7,7 +7,7 @@ App(
icon="A_U2F_14",
order=80,
resources="resources",
fap_libs=["assets"],
fap_libs=["assets", "mbedtls"],
fap_category="USB",
fap_icon="icon.png",
)

View File

@ -1,98 +0,0 @@
/*
* hmac.c - HMAC
*
* Copyright (C) 2017 Sergei Glushchenko
* Author: Sergei Glushchenko <gl.sergei@gmail.com>
*
* This file is a part of U2F firmware for STM32
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As additional permission under GNU GPL version 3 section 7, you may
* distribute non-source form of the Program without the copy of the
* GNU GPL normally required by section 4, provided you inform the
* recipients of GNU GPL by a written offer.
*
*/
#include <stdint.h>
#include "sha256.h"
#include "hmac_sha256.h"
static void _hmac_sha256_init(const hmac_context* ctx) {
hmac_sha256_context* context = (hmac_sha256_context*)ctx;
sha256_start(&context->sha_ctx);
}
static void
_hmac_sha256_update(const hmac_context* ctx, const uint8_t* message, unsigned message_size) {
hmac_sha256_context* context = (hmac_sha256_context*)ctx;
sha256_update(&context->sha_ctx, message, message_size);
}
static void _hmac_sha256_finish(const hmac_context* ctx, uint8_t* hash_result) {
hmac_sha256_context* context = (hmac_sha256_context*)ctx;
sha256_finish(&context->sha_ctx, hash_result);
}
/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always
the same size as the hash result size. */
static void hmac_init(const hmac_context* ctx, const uint8_t* K) {
uint8_t* pad = ctx->tmp + 2 * ctx->result_size;
unsigned i;
for(i = 0; i < ctx->result_size; ++i) pad[i] = K[i] ^ 0x36;
for(; i < ctx->block_size; ++i) pad[i] = 0x36;
ctx->init_hash(ctx);
ctx->update_hash(ctx, pad, ctx->block_size);
}
static void hmac_update(const hmac_context* ctx, const uint8_t* message, unsigned message_size) {
ctx->update_hash(ctx, message, message_size);
}
static void hmac_finish(const hmac_context* ctx, const uint8_t* K, uint8_t* result) {
uint8_t* pad = ctx->tmp + 2 * ctx->result_size;
unsigned i;
for(i = 0; i < ctx->result_size; ++i) pad[i] = K[i] ^ 0x5c;
for(; i < ctx->block_size; ++i) pad[i] = 0x5c;
ctx->finish_hash(ctx, result);
ctx->init_hash(ctx);
ctx->update_hash(ctx, pad, ctx->block_size);
ctx->update_hash(ctx, result, ctx->result_size);
ctx->finish_hash(ctx, result);
}
void hmac_sha256_init(hmac_sha256_context* ctx, const uint8_t* K) {
ctx->hmac_ctx.init_hash = _hmac_sha256_init;
ctx->hmac_ctx.update_hash = _hmac_sha256_update;
ctx->hmac_ctx.finish_hash = _hmac_sha256_finish;
ctx->hmac_ctx.block_size = 64;
ctx->hmac_ctx.result_size = 32;
ctx->hmac_ctx.tmp = ctx->tmp;
hmac_init(&ctx->hmac_ctx, K);
}
void hmac_sha256_update(
const hmac_sha256_context* ctx,
const uint8_t* message,
unsigned message_size) {
hmac_update(&ctx->hmac_ctx, message, message_size);
}
void hmac_sha256_finish(const hmac_sha256_context* ctx, const uint8_t* K, uint8_t* hash_result) {
hmac_finish(&ctx->hmac_ctx, K, hash_result);
}

View File

@ -1,38 +0,0 @@
#pragma once
#include "sha256.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct hmac_context {
void (*init_hash)(const struct hmac_context* context);
void (*update_hash)(
const struct hmac_context* context,
const uint8_t* message,
unsigned message_size);
void (*finish_hash)(const struct hmac_context* context, uint8_t* hash_result);
unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */
unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */
uint8_t* tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */
} hmac_context;
typedef struct hmac_sha256_context {
hmac_context hmac_ctx;
sha256_context sha_ctx;
uint8_t tmp[32 * 2 + 64];
} hmac_sha256_context;
void hmac_sha256_init(hmac_sha256_context* ctx, const uint8_t* K);
void hmac_sha256_update(
const hmac_sha256_context* ctx,
const uint8_t* message,
unsigned message_size);
void hmac_sha256_finish(const hmac_sha256_context* ctx, const uint8_t* K, uint8_t* hash_result);
#ifdef __cplusplus
}
#endif

View File

@ -1,18 +1,22 @@
#include <furi.h>
#include "u2f.h"
#include "u2f_hid.h"
#include "u2f_data.h"
#include <furi.h>
#include <furi_hal.h>
#include <furi_hal_random.h>
#include <littlefs/lfs_util.h> // for lfs_tobe32
#include "toolbox/sha256.h"
#include "hmac_sha256.h"
#include "micro-ecc/uECC.h"
#include <mbedtls/sha256.h>
#include <mbedtls/md.h>
#include <mbedtls/ecdsa.h>
#include <mbedtls/error.h>
#define TAG "U2f"
#define WORKER_TAG TAG "Worker"
#define MCHECK(expr) furi_check((expr) == 0)
#define U2F_CMD_REGISTER 0x01
#define U2F_CMD_AUTHENTICATE 0x02
#define U2F_CMD_VERSION 0x03
@ -25,16 +29,26 @@ typedef enum {
0x08, // "dont-enforce-user-presence-and-sign" - send auth response even if user is missing
} U2fAuthMode;
#define U2F_HASH_SIZE 32
#define U2F_NONCE_SIZE 32
#define U2F_CHALLENGE_SIZE 32
#define U2F_APP_ID_SIZE 32
#define U2F_EC_KEY_SIZE 32
#define U2F_EC_BIGNUM_SIZE 32
#define U2F_EC_POINT_SIZE 65
typedef struct {
uint8_t format;
uint8_t xy[64];
} __attribute__((packed)) U2fPubKey;
} FURI_PACKED U2fPubKey;
_Static_assert(sizeof(U2fPubKey) == U2F_EC_POINT_SIZE, "U2fPubKey size mismatch");
typedef struct {
uint8_t len;
uint8_t hash[32];
uint8_t nonce[32];
} __attribute__((packed)) U2fKeyHandle;
uint8_t hash[U2F_HASH_SIZE];
uint8_t nonce[U2F_NONCE_SIZE];
} FURI_PACKED U2fKeyHandle;
typedef struct {
uint8_t cla;
@ -42,16 +56,16 @@ typedef struct {
uint8_t p1;
uint8_t p2;
uint8_t len[3];
uint8_t challenge[32];
uint8_t app_id[32];
} __attribute__((packed)) U2fRegisterReq;
uint8_t challenge[U2F_CHALLENGE_SIZE];
uint8_t app_id[U2F_APP_ID_SIZE];
} FURI_PACKED U2fRegisterReq;
typedef struct {
uint8_t reserved;
U2fPubKey pub_key;
U2fKeyHandle key_handle;
uint8_t cert[];
} __attribute__((packed)) U2fRegisterResp;
} FURI_PACKED U2fRegisterResp;
typedef struct {
uint8_t cla;
@ -59,16 +73,16 @@ typedef struct {
uint8_t p1;
uint8_t p2;
uint8_t len[3];
uint8_t challenge[32];
uint8_t app_id[32];
uint8_t challenge[U2F_CHALLENGE_SIZE];
uint8_t app_id[U2F_APP_ID_SIZE];
U2fKeyHandle key_handle;
} __attribute__((packed)) U2fAuthReq;
} FURI_PACKED U2fAuthReq;
typedef struct {
uint8_t user_present;
uint32_t counter;
uint8_t signature[];
} __attribute__((packed)) U2fAuthResp;
} FURI_PACKED U2fAuthResp;
static const uint8_t ver_str[] = {"U2F_V2"};
@ -78,19 +92,20 @@ static const uint8_t state_user_missing[] = {0x69, 0x85};
static const uint8_t state_wrong_data[] = {0x6A, 0x80};
struct U2fData {
uint8_t device_key[32];
uint8_t cert_key[32];
uint8_t device_key[U2F_EC_KEY_SIZE];
uint8_t cert_key[U2F_EC_KEY_SIZE];
uint32_t counter;
const struct uECC_Curve_t* p_curve;
bool ready;
bool user_present;
U2fEvtCallback callback;
void* context;
mbedtls_ecp_group group;
};
static int u2f_uecc_random(uint8_t* dest, unsigned size) {
static int u2f_uecc_random_cb(void* context, uint8_t* dest, unsigned size) {
UNUSED(context);
furi_hal_random_fill_buf(dest, size);
return 1;
return 0;
}
U2fData* u2f_alloc() {
@ -99,6 +114,7 @@ U2fData* u2f_alloc() {
void u2f_free(U2fData* U2F) {
furi_assert(U2F);
mbedtls_ecp_group_free(&U2F->group);
free(U2F);
}
@ -129,8 +145,8 @@ bool u2f_init(U2fData* U2F) {
}
}
U2F->p_curve = uECC_secp256r1();
uECC_set_rng(u2f_uecc_random);
mbedtls_ecp_group_init(&U2F->group);
mbedtls_ecp_group_load(&U2F->group, MBEDTLS_ECP_DP_SECP256R1);
U2F->ready = true;
return true;
@ -171,21 +187,63 @@ static uint8_t u2f_der_encode_signature(uint8_t* der, uint8_t* sig) {
der[0] = 0x30;
uint8_t len = 2;
len += u2f_der_encode_int(der + len, sig, 32);
len += u2f_der_encode_int(der + len, sig + 32, 32);
len += u2f_der_encode_int(der + len, sig, U2F_HASH_SIZE);
len += u2f_der_encode_int(der + len, sig + U2F_HASH_SIZE, U2F_HASH_SIZE);
der[1] = len - 2;
return len;
}
static void
u2f_ecc_sign(mbedtls_ecp_group* grp, const uint8_t* key, uint8_t* hash, uint8_t* signature) {
mbedtls_mpi r, s, d;
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
mbedtls_mpi_init(&d);
MCHECK(mbedtls_mpi_read_binary(&d, key, U2F_EC_KEY_SIZE));
MCHECK(mbedtls_ecdsa_sign(grp, &r, &s, &d, hash, U2F_HASH_SIZE, u2f_uecc_random_cb, NULL));
MCHECK(mbedtls_mpi_write_binary(&r, signature, U2F_EC_BIGNUM_SIZE));
MCHECK(mbedtls_mpi_write_binary(&s, signature + U2F_EC_BIGNUM_SIZE, U2F_EC_BIGNUM_SIZE));
mbedtls_mpi_free(&r);
mbedtls_mpi_free(&s);
mbedtls_mpi_free(&d);
}
static void u2f_ecc_compute_public_key(
mbedtls_ecp_group* grp,
const uint8_t* private_key,
U2fPubKey* public_key) {
mbedtls_ecp_point Q;
mbedtls_mpi d;
size_t olen;
mbedtls_ecp_point_init(&Q);
mbedtls_mpi_init(&d);
MCHECK(mbedtls_mpi_read_binary(&d, private_key, U2F_EC_KEY_SIZE));
MCHECK(mbedtls_ecp_mul(grp, &Q, &d, &grp->G, u2f_uecc_random_cb, NULL));
MCHECK(mbedtls_ecp_check_privkey(grp, &d));
MCHECK(mbedtls_ecp_point_write_binary(
grp, &Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, (unsigned char*)public_key, sizeof(U2fPubKey)));
mbedtls_ecp_point_free(&Q);
mbedtls_mpi_free(&d);
}
///////////////////////////////////////////
static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) {
U2fRegisterReq* req = (U2fRegisterReq*)buf;
U2fRegisterResp* resp = (U2fRegisterResp*)buf;
U2fKeyHandle handle;
uint8_t private[32];
uint8_t private[U2F_EC_KEY_SIZE];
U2fPubKey pub_key;
uint8_t hash[32];
uint8_t signature[64];
uint8_t hash[U2F_HASH_SIZE];
uint8_t signature[U2F_EC_BIGNUM_SIZE * 2];
if(u2f_data_check(false) == false) {
U2F->ready = false;
@ -201,40 +259,54 @@ static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) {
}
U2F->user_present = false;
hmac_sha256_context hmac_ctx;
sha256_context sha_ctx;
handle.len = U2F_HASH_SIZE * 2;
handle.len = 32 * 2;
// Generate random nonce
furi_hal_random_fill_buf(handle.nonce, 32);
// Generate private key
hmac_sha256_init(&hmac_ctx, U2F->device_key);
hmac_sha256_update(&hmac_ctx, req->app_id, 32);
hmac_sha256_update(&hmac_ctx, handle.nonce, 32);
hmac_sha256_finish(&hmac_ctx, U2F->device_key, private);
{
mbedtls_md_context_t hmac_ctx;
mbedtls_md_init(&hmac_ctx);
MCHECK(mbedtls_md_setup(&hmac_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1));
MCHECK(mbedtls_md_hmac_starts(&hmac_ctx, U2F->device_key, sizeof(U2F->device_key)));
// Generate private key handle
hmac_sha256_init(&hmac_ctx, U2F->device_key);
hmac_sha256_update(&hmac_ctx, private, 32);
hmac_sha256_update(&hmac_ctx, req->app_id, 32);
hmac_sha256_finish(&hmac_ctx, U2F->device_key, handle.hash);
// Generate private key
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id)));
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, handle.nonce, sizeof(handle.nonce)));
MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, private));
MCHECK(mbedtls_md_hmac_reset(&hmac_ctx));
// Generate private key handle
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, private, sizeof(private)));
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id)));
MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, handle.hash));
}
// Generate public key
pub_key.format = 0x04; // Uncompressed point
uECC_compute_public_key(private, pub_key.xy, U2F->p_curve);
u2f_ecc_compute_public_key(&U2F->group, private, &pub_key);
// Generate signature
uint8_t reserved_byte = 0;
sha256_start(&sha_ctx);
sha256_update(&sha_ctx, &reserved_byte, 1);
sha256_update(&sha_ctx, req->app_id, 32);
sha256_update(&sha_ctx, req->challenge, 32);
sha256_update(&sha_ctx, handle.hash, handle.len);
sha256_update(&sha_ctx, (uint8_t*)&pub_key, 65);
sha256_finish(&sha_ctx, hash);
{
uint8_t reserved_byte = 0;
uECC_sign(U2F->cert_key, hash, 32, signature, U2F->p_curve);
mbedtls_sha256_context sha_ctx;
mbedtls_sha256_init(&sha_ctx);
mbedtls_sha256_starts(&sha_ctx, 0);
mbedtls_sha256_update(&sha_ctx, &reserved_byte, 1);
mbedtls_sha256_update(&sha_ctx, req->app_id, sizeof(req->app_id));
mbedtls_sha256_update(&sha_ctx, req->challenge, sizeof(req->challenge));
mbedtls_sha256_update(&sha_ctx, handle.hash, handle.len);
mbedtls_sha256_update(&sha_ctx, (uint8_t*)&pub_key, sizeof(U2fPubKey));
mbedtls_sha256_finish(&sha_ctx, hash);
mbedtls_sha256_free(&sha_ctx);
}
// Sign hash
u2f_ecc_sign(&U2F->group, U2F->cert_key, hash, signature);
// Encode response message
resp->reserved = 0x05;
@ -250,13 +322,11 @@ static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) {
static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) {
U2fAuthReq* req = (U2fAuthReq*)buf;
U2fAuthResp* resp = (U2fAuthResp*)buf;
uint8_t priv_key[32];
uint8_t priv_key[U2F_EC_KEY_SIZE];
uint8_t mac_control[32];
hmac_sha256_context hmac_ctx;
sha256_context sha_ctx;
uint8_t flags = 0;
uint8_t hash[32];
uint8_t signature[64];
uint8_t hash[U2F_HASH_SIZE];
uint8_t signature[U2F_HASH_SIZE * 2];
uint32_t be_u2f_counter;
if(u2f_data_check(false) == false) {
@ -281,26 +351,42 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) {
be_u2f_counter = lfs_tobe32(U2F->counter + 1);
// Generate hash
sha256_start(&sha_ctx);
sha256_update(&sha_ctx, req->app_id, 32);
sha256_update(&sha_ctx, &flags, 1);
sha256_update(&sha_ctx, (uint8_t*)&(be_u2f_counter), 4);
sha256_update(&sha_ctx, req->challenge, 32);
sha256_finish(&sha_ctx, hash);
{
mbedtls_sha256_context sha_ctx;
// Recover private key
hmac_sha256_init(&hmac_ctx, U2F->device_key);
hmac_sha256_update(&hmac_ctx, req->app_id, 32);
hmac_sha256_update(&hmac_ctx, req->key_handle.nonce, 32);
hmac_sha256_finish(&hmac_ctx, U2F->device_key, priv_key);
mbedtls_sha256_init(&sha_ctx);
mbedtls_sha256_starts(&sha_ctx, 0);
// Generate and verify private key handle
hmac_sha256_init(&hmac_ctx, U2F->device_key);
hmac_sha256_update(&hmac_ctx, priv_key, 32);
hmac_sha256_update(&hmac_ctx, req->app_id, 32);
hmac_sha256_finish(&hmac_ctx, U2F->device_key, mac_control);
mbedtls_sha256_update(&sha_ctx, req->app_id, sizeof(req->app_id));
mbedtls_sha256_update(&sha_ctx, &flags, 1);
mbedtls_sha256_update(&sha_ctx, (uint8_t*)&(be_u2f_counter), sizeof(be_u2f_counter));
mbedtls_sha256_update(&sha_ctx, req->challenge, sizeof(req->challenge));
if(memcmp(req->key_handle.hash, mac_control, 32) != 0) {
mbedtls_sha256_finish(&sha_ctx, hash);
mbedtls_sha256_free(&sha_ctx);
}
{
mbedtls_md_context_t hmac_ctx;
mbedtls_md_init(&hmac_ctx);
MCHECK(mbedtls_md_setup(&hmac_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1));
MCHECK(mbedtls_md_hmac_starts(&hmac_ctx, U2F->device_key, sizeof(U2F->device_key)));
// Recover private key
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id)));
MCHECK(mbedtls_md_hmac_update(
&hmac_ctx, req->key_handle.nonce, sizeof(req->key_handle.nonce)));
MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, priv_key));
MCHECK(mbedtls_md_hmac_reset(&hmac_ctx));
// Generate and verify private key handle
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, priv_key, sizeof(priv_key)));
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id)));
MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, mac_control));
}
if(memcmp(req->key_handle.hash, mac_control, sizeof(mac_control)) != 0) {
FURI_LOG_W(TAG, "Wrong handle!");
memcpy(&buf[0], state_wrong_data, 2);
return 2;
@ -311,7 +397,8 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) {
return 2;
}
uECC_sign(priv_key, hash, 32, signature, U2F->p_curve);
// Sign hash
u2f_ecc_sign(&U2F->group, priv_key, hash, signature);
resp->user_present = flags;
resp->counter = be_u2f_counter;

View File

@ -37,7 +37,7 @@ typedef struct {
uint32_t counter;
uint8_t random_salt[24];
uint32_t control;
} __attribute__((packed)) U2fCounterData;
} FURI_PACKED U2fCounterData;
bool u2f_data_check(bool cert_only) {
bool state = false;

View File

@ -202,7 +202,7 @@ uint16_t canvas_string_width(Canvas* canvas, const char* str) {
return u8g2_GetStrWidth(&canvas->fb, str);
}
uint8_t canvas_glyph_width(Canvas* canvas, char symbol) {
uint8_t canvas_glyph_width(Canvas* canvas, uint16_t symbol) {
furi_assert(canvas);
return u8g2_GetGlyphWidth(&canvas->fb, symbol);
}

View File

@ -214,7 +214,7 @@ uint16_t canvas_string_width(Canvas* canvas, const char* str);
*
* @return width in pixels
*/
uint8_t canvas_glyph_width(Canvas* canvas, char symbol);
uint8_t canvas_glyph_width(Canvas* canvas, uint16_t symbol);
/** Draw bitmap picture at position defined by x,y.
*

View File

@ -1,9 +1,10 @@
#include "flipper.pb.h"
#include "rpc_i.h"
#include "gui.pb.h"
#include <gui/gui_i.h>
#include <assets_icons.h>
#include <flipper.pb.h>
#include <gui.pb.h>
#define TAG "RpcGui"
typedef enum {

View File

@ -1,6 +1,6 @@
#pragma once
#include "rpc.h"
#include "storage/filesystem_api_defines.h"
#include <storage/filesystem_api_defines.h>
#include <pb.h>
#include <pb_decode.h>
#include <pb_encode.h>

View File

@ -1,18 +1,18 @@
#include "flipper.pb.h"
#include <core/common_defines.h>
#include <core/memmgr.h>
#include <core/record.h>
#include "pb_decode.h"
#include "rpc/rpc.h"
#include "rpc_i.h"
#include "storage.pb.h"
#include "storage/filesystem_api_defines.h"
#include "storage/storage.h"
#include <stdint.h>
#include <rpc/rpc.h>
#include <rpc/rpc_i.h>
#include <storage/filesystem_api_defines.h>
#include <storage/storage.h>
#include <lib/toolbox/md5_calc.h>
#include <lib/toolbox/path.h>
#include <update_util/lfs_backup.h>
#include <pb_decode.h>
#include <storage.pb.h>
#include <flipper.pb.h>
#define TAG "RpcStorage"
#define MAX_NAME_LENGTH 255

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 552 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

View File

@ -14,8 +14,22 @@ enum HidDebugSubmenuIndex {
HidSubmenuIndexMouse,
HidSubmenuIndexMouseClicker,
HidSubmenuIndexMouseJiggler,
HidSubmenuIndexRemovePairing,
};
static void bt_hid_remove_pairing(Bt* bt) {
bt_disconnect(bt);
// Wait 2nd core to update nvm storage
furi_delay_ms(200);
furi_hal_bt_stop_advertising();
bt_forget_bonded_devices(bt);
furi_hal_bt_start_advertising();
}
static void hid_submenu_callback(void* context, uint32_t index) {
furi_assert(context);
Hid* app = context;
@ -45,6 +59,8 @@ static void hid_submenu_callback(void* context, uint32_t index) {
} else if(index == HidSubmenuIndexMouseJiggler) {
app->view_id = HidViewMouseJiggler;
view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseJiggler);
} else if(index == HidSubmenuIndexRemovePairing) {
bt_hid_remove_pairing(app->bt);
}
}
@ -143,6 +159,14 @@ Hid* hid_alloc(HidTransport transport) {
HidSubmenuIndexMouseJiggler,
hid_submenu_callback,
app);
if(transport == HidTransportBle) {
submenu_add_item(
app->device_type_submenu,
"Remove Pairing",
HidSubmenuIndexRemovePairing,
hid_submenu_callback,
app);
}
view_set_previous_callback(submenu_get_view(app->device_type_submenu), hid_exit);
view_dispatcher_add_view(
app->view_dispatcher, HidViewSubmenu, submenu_get_view(app->device_type_submenu));

View File

@ -49,7 +49,7 @@ typedef struct {
#define ROW_COUNT 7
#define COLUMN_COUNT 12
// 0 width items are not drawn, but there value is used
// 0 width items are not drawn, but their value is used
const HidKeyboardKey hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = {
{
{.width = 1, .icon = &I_ButtonF1_5x8, .value = HID_KEYBOARD_F1},
@ -140,17 +140,17 @@ const HidKeyboardKey hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = {
{.width = 1, .icon = &I_ButtonRight_4x7, .value = HID_KEYBOARD_RIGHT_ARROW},
},
{
{.width = 2, .icon = &I_Ctrl_15x7, .value = HID_KEYBOARD_L_CTRL},
{.width = 2, .icon = &I_Ctrl_17x10, .value = HID_KEYBOARD_L_CTRL},
{.width = 0, .value = HID_KEYBOARD_L_CTRL},
{.width = 2, .icon = &I_Alt_11x7, .value = HID_KEYBOARD_L_ALT},
{.width = 2, .icon = &I_Alt_17x10, .value = HID_KEYBOARD_L_ALT},
{.width = 0, .value = HID_KEYBOARD_L_ALT},
{.width = 2, .icon = &I_Cmd_15x7, .value = HID_KEYBOARD_L_GUI},
{.width = 2, .icon = &I_Cmd_17x10, .value = HID_KEYBOARD_L_GUI},
{.width = 0, .value = HID_KEYBOARD_L_GUI},
{.width = 2, .icon = &I_Tab_15x7, .value = HID_KEYBOARD_TAB},
{.width = 2, .icon = &I_Tab_17x10, .value = HID_KEYBOARD_TAB},
{.width = 0, .value = HID_KEYBOARD_TAB},
{.width = 2, .icon = &I_Esc_14x7, .value = HID_KEYBOARD_ESCAPE},
{.width = 2, .icon = &I_Esc_17x10, .value = HID_KEYBOARD_ESCAPE},
{.width = 0, .value = HID_KEYBOARD_ESCAPE},
{.width = 2, .icon = &I_Del_12x7, .value = HID_KEYBOARD_DELETE_FORWARD},
{.width = 2, .icon = &I_Del_17x10, .value = HID_KEYBOARD_DELETE_FORWARD},
{.width = 0, .value = HID_KEYBOARD_DELETE_FORWARD},
},
};

View File

@ -1,8 +1,8 @@
#include "storage_move_to_sd.h"
#include <core/common_defines.h>
#include <core/log.h>
#include "loader/loader.h"
#include <stdint.h>
#include <loader/loader.h>
#include <toolbox/dir_walk.h>
#include <toolbox/path.h>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Some files were not shown because too many files have changed in this diff Show More