[FL-1958] U2F prototype (#879)
* U2F implementation prototype * U2F data encryption and store, user confirmation request * remove debug prints * fix notification bug in chrome * split u2f_alloc into u2f_init and u2f_alloc * typo fix, furi-hal-trng -> furi-hal-random * rand/srand redefinition * SubGhz: a little bit of Dante. * u2f_data naming fix Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									9b62b557b4
								
							
						
					
					
						commit
						9e62f08e4d
					
				| @ -20,6 +20,7 @@ extern int32_t desktop_srv(void* p); | |||||||
| extern int32_t accessor_app(void* p); | extern int32_t accessor_app(void* p); | ||||||
| extern int32_t archive_app(void* p); | extern int32_t archive_app(void* p); | ||||||
| extern int32_t bad_usb_app(void* p); | extern int32_t bad_usb_app(void* p); | ||||||
|  | extern int32_t u2f_app(void* p); | ||||||
| extern int32_t uart_echo_app(void* p); | extern int32_t uart_echo_app(void* p); | ||||||
| extern int32_t blink_test_app(void* p); | extern int32_t blink_test_app(void* p); | ||||||
| extern int32_t bt_debug_app(void* p); | extern int32_t bt_debug_app(void* p); | ||||||
| @ -154,6 +155,11 @@ const FlipperApplication FLIPPER_APPS[] = { | |||||||
| #ifdef APP_BAD_USB | #ifdef APP_BAD_USB | ||||||
|     {.app = bad_usb_app, .name = "Bad USB", .stack_size = 2048, .icon = &A_BadUsb_14}, |     {.app = bad_usb_app, .name = "Bad USB", .stack_size = 2048, .icon = &A_BadUsb_14}, | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef APP_U2F | ||||||
|  |     {.app = u2f_app, .name = "U2F", .stack_size = 2048, .icon = &A_U2F_14}, | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const size_t FLIPPER_APPS_COUNT = sizeof(FLIPPER_APPS) / sizeof(FlipperApplication); | const size_t FLIPPER_APPS_COUNT = sizeof(FLIPPER_APPS) / sizeof(FlipperApplication); | ||||||
|  | |||||||
| @ -50,6 +50,7 @@ APP_DISPLAY_TEST = 1 | |||||||
| APP_BLE_HID = 1 | APP_BLE_HID = 1 | ||||||
| APP_USB_MOUSE = 1 | APP_USB_MOUSE = 1 | ||||||
| APP_BAD_USB = 1 | APP_BAD_USB = 1 | ||||||
|  | APP_U2F = 1 | ||||||
| APP_UART_ECHO = 1 | APP_UART_ECHO = 1 | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| @ -165,7 +166,13 @@ APP_BAD_USB ?= 0 | |||||||
| ifeq ($(APP_BAD_USB), 1) | ifeq ($(APP_BAD_USB), 1) | ||||||
| CFLAGS		+= -DAPP_BAD_USB | CFLAGS		+= -DAPP_BAD_USB | ||||||
| SRV_GUI = 1 | SRV_GUI = 1 | ||||||
| endif  | endif | ||||||
|  | 
 | ||||||
|  | APP_U2F ?= 0 | ||||||
|  | ifeq ($(APP_U2F), 1) | ||||||
|  | CFLAGS		+= -DAPP_U2F | ||||||
|  | SRV_GUI = 1 | ||||||
|  | endif | ||||||
| 
 | 
 | ||||||
| APP_BLE_HID ?=0 | APP_BLE_HID ?=0 | ||||||
| ifeq ($(APP_BLE_HID), 1) | ifeq ($(APP_BLE_HID), 1) | ||||||
|  | |||||||
| @ -35,7 +35,7 @@ void usb_test_submenu_callback(void* context, uint32_t index) { | |||||||
|     } else if(index == UsbTestSubmenuIndexHid) { |     } else if(index == UsbTestSubmenuIndexHid) { | ||||||
|         furi_hal_usb_set_config(&usb_hid); |         furi_hal_usb_set_config(&usb_hid); | ||||||
|     } else if(index == UsbTestSubmenuIndexHidU2F) { |     } else if(index == UsbTestSubmenuIndexHidU2F) { | ||||||
|         //furi_hal_usb_set_config(UsbModeU2F);
 |         furi_hal_usb_set_config(&usb_hid_u2f); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -67,7 +67,7 @@ UsbTestApp* usb_test_app_alloc() { | |||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         app->submenu, "HID KB+Mouse", UsbTestSubmenuIndexHid, usb_test_submenu_callback, app); |         app->submenu, "HID KB+Mouse", UsbTestSubmenuIndexHid, usb_test_submenu_callback, app); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         app->submenu, "TODO: HID U2F", UsbTestSubmenuIndexHidU2F, usb_test_submenu_callback, app); |         app->submenu, "HID U2F", UsbTestSubmenuIndexHidU2F, usb_test_submenu_callback, app); | ||||||
|     view_set_previous_callback(submenu_get_view(app->submenu), usb_test_exit); |     view_set_previous_callback(submenu_get_view(app->submenu), usb_test_exit); | ||||||
|     view_dispatcher_add_view(app->view_dispatcher, 0, submenu_get_view(app->submenu)); |     view_dispatcher_add_view(app->view_dispatcher, 0, submenu_get_view(app->submenu)); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,7 +1,4 @@ | |||||||
| /*
 | /* Abandon hope, all ye who enter here. */ | ||||||
| *    Give up hope, everyone who enters here!!! |  | ||||||
| *      Оставь надежду, всяк сюда входящий!!! |  | ||||||
| */ |  | ||||||
| 
 | 
 | ||||||
| #include "subghz_i.h" | #include "subghz_i.h" | ||||||
| #include <lib/toolbox/path.h> | #include <lib/toolbox/path.h> | ||||||
| @ -329,4 +326,4 @@ int32_t subghz_app(void* p) { | |||||||
|     subghz_free(subghz); |     subghz_free(subghz); | ||||||
| 
 | 
 | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										30
									
								
								applications/u2f/scenes/u2f_scene.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								applications/u2f/scenes/u2f_scene.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | #include "u2f_scene.h" | ||||||
|  | 
 | ||||||
|  | // Generate scene on_enter handlers array
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, | ||||||
|  | void (*const u2f_scene_on_enter_handlers[])(void*) = { | ||||||
|  | #include "u2f_scene_config.h" | ||||||
|  | }; | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Generate scene on_event handlers array
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, | ||||||
|  | bool (*const u2f_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = { | ||||||
|  | #include "u2f_scene_config.h" | ||||||
|  | }; | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Generate scene on_exit handlers array
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, | ||||||
|  | void (*const u2f_scene_on_exit_handlers[])(void* context) = { | ||||||
|  | #include "u2f_scene_config.h" | ||||||
|  | }; | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Initialize scene handlers configuration structure
 | ||||||
|  | const SceneManagerHandlers u2f_scene_handlers = { | ||||||
|  |     .on_enter_handlers = u2f_scene_on_enter_handlers, | ||||||
|  |     .on_event_handlers = u2f_scene_on_event_handlers, | ||||||
|  |     .on_exit_handlers = u2f_scene_on_exit_handlers, | ||||||
|  |     .scene_num = U2fSceneNum, | ||||||
|  | }; | ||||||
							
								
								
									
										29
									
								
								applications/u2f/scenes/u2f_scene.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								applications/u2f/scenes/u2f_scene.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <gui/scene_manager.h> | ||||||
|  | 
 | ||||||
|  | // Generate scene id and total number
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) U2fScene##id, | ||||||
|  | typedef enum { | ||||||
|  | #include "u2f_scene_config.h" | ||||||
|  |     U2fSceneNum, | ||||||
|  | } U2fScene; | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | extern const SceneManagerHandlers u2f_scene_handlers; | ||||||
|  | 
 | ||||||
|  | // Generate scene on_enter handlers declaration
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); | ||||||
|  | #include "u2f_scene_config.h" | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Generate scene on_event handlers declaration
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) \ | ||||||
|  |     bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); | ||||||
|  | #include "u2f_scene_config.h" | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Generate scene on_exit handlers declaration
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); | ||||||
|  | #include "u2f_scene_config.h" | ||||||
|  | #undef ADD_SCENE | ||||||
							
								
								
									
										1
									
								
								applications/u2f/scenes/u2f_scene_config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								applications/u2f/scenes/u2f_scene_config.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | ADD_SCENE(u2f, main, Main) | ||||||
							
								
								
									
										92
									
								
								applications/u2f/scenes/u2f_scene_main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								applications/u2f/scenes/u2f_scene_main.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | |||||||
|  | #include "../u2f_app_i.h" | ||||||
|  | #include "../views/u2f_view.h" | ||||||
|  | #include "furi-hal.h" | ||||||
|  | #include "../u2f.h" | ||||||
|  | 
 | ||||||
|  | #define U2F_EVENT_TIMEOUT 500 | ||||||
|  | 
 | ||||||
|  | static void u2f_scene_main_ok_callback(InputType type, void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     U2fApp* app = context; | ||||||
|  |     view_dispatcher_send_custom_event(app->view_dispatcher, U2fCustomEventConfirm); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void u2f_scene_main_event_callback(U2fNotifyEvent evt, void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     U2fApp* app = context; | ||||||
|  |     if(evt == U2fNotifyRegister) | ||||||
|  |         view_dispatcher_send_custom_event(app->view_dispatcher, U2fCustomEventRegister); | ||||||
|  |     else if(evt == U2fNotifyAuth) | ||||||
|  |         view_dispatcher_send_custom_event(app->view_dispatcher, U2fCustomEventAuth); | ||||||
|  |     else if(evt == U2fNotifyWink) | ||||||
|  |         view_dispatcher_send_custom_event(app->view_dispatcher, U2fCustomEventWink); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void u2f_scene_main_timer_callback(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     U2fApp* app = context; | ||||||
|  |     view_dispatcher_send_custom_event(app->view_dispatcher, U2fCustomEventTimeout); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool u2f_scene_main_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     U2fApp* app = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if((event.event == U2fCustomEventRegister) || (event.event == U2fCustomEventAuth)) { | ||||||
|  |             osTimerStart(app->timer, U2F_EVENT_TIMEOUT); | ||||||
|  |             if(app->event_cur == U2fCustomEventNone) { | ||||||
|  |                 app->event_cur = event.event; | ||||||
|  |                 if(event.event == U2fCustomEventRegister) | ||||||
|  |                     u2f_view_set_state(app->u2f_view, U2fMsgRegister); | ||||||
|  |                 else if(event.event == U2fCustomEventAuth) | ||||||
|  |                     u2f_view_set_state(app->u2f_view, U2fMsgAuth); | ||||||
|  |                 notification_message(app->notifications, &sequence_success); | ||||||
|  |             } | ||||||
|  |             notification_message(app->notifications, &sequence_blink_blue_10); | ||||||
|  |         } else if(event.event == U2fCustomEventWink) { | ||||||
|  |             notification_message(app->notifications, &sequence_blink_green_10); | ||||||
|  |         } else if(event.event == U2fCustomEventTimeout) { | ||||||
|  |             app->event_cur = U2fCustomEventNone; | ||||||
|  |             u2f_view_set_state(app->u2f_view, U2fMsgNone); | ||||||
|  |         } else if(event.event == U2fCustomEventConfirm) { | ||||||
|  |             if(app->event_cur != U2fCustomEventNone) { | ||||||
|  |                 u2f_confirm_user_present(app->u2f_instance); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         consumed = true; | ||||||
|  |     } else if(event.type == SceneManagerEventTypeTick) { | ||||||
|  |     } | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void u2f_scene_main_on_enter(void* context) { | ||||||
|  |     U2fApp* app = context; | ||||||
|  | 
 | ||||||
|  |     app->timer = osTimerNew(u2f_scene_main_timer_callback, osTimerOnce, app, NULL); | ||||||
|  | 
 | ||||||
|  |     app->u2f_instance = u2f_alloc(); | ||||||
|  |     app->u2f_ready = u2f_init(app->u2f_instance); | ||||||
|  |     if(app->u2f_ready == true) { | ||||||
|  |         u2f_set_event_callback(app->u2f_instance, u2f_scene_main_event_callback, app); | ||||||
|  |         app->u2f_hid = u2f_hid_start(app->u2f_instance); | ||||||
|  |         u2f_view_set_ok_callback(app->u2f_view, u2f_scene_main_ok_callback, app); | ||||||
|  |     } else { | ||||||
|  |         u2f_free(app->u2f_instance); | ||||||
|  |         u2f_view_set_state(app->u2f_view, U2fMsgError); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(app->view_dispatcher, U2fAppViewMain); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void u2f_scene_main_on_exit(void* context) { | ||||||
|  |     U2fApp* app = context; | ||||||
|  |     osTimerStop(app->timer); | ||||||
|  |     osTimerDelete(app->timer); | ||||||
|  |     if(app->u2f_ready == true) { | ||||||
|  |         u2f_hid_stop(app->u2f_hid); | ||||||
|  |         u2f_free(app->u2f_instance); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										332
									
								
								applications/u2f/u2f.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										332
									
								
								applications/u2f/u2f.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,332 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include "u2f.h" | ||||||
|  | #include "u2f_hid.h" | ||||||
|  | #include "u2f_data.h" | ||||||
|  | #include <furi-hal.h> | ||||||
|  | #include <furi-hal-random.h> | ||||||
|  | 
 | ||||||
|  | #include "toolbox/sha256.h" | ||||||
|  | #include "toolbox/hmac_sha256.h" | ||||||
|  | #include "micro-ecc/uECC.h" | ||||||
|  | 
 | ||||||
|  | #define TAG "U2F" | ||||||
|  | #define WORKER_TAG TAG "Worker" | ||||||
|  | 
 | ||||||
|  | #define U2F_CMD_REGISTER 0x01 | ||||||
|  | #define U2F_CMD_AUTHENTICATE 0x02 | ||||||
|  | #define U2F_CMD_VERSION 0x03 | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     U2fCheckOnly = 0x07, // "check-only" - only check key handle, don't send auth response
 | ||||||
|  |     U2fEnforce = | ||||||
|  |         0x03, // "enforce-user-presence-and-sign" - send auth response only if user is present
 | ||||||
|  |     U2fDontEnforce = | ||||||
|  |         0x08, // "dont-enforce-user-presence-and-sign" - send auth response even if user is missing
 | ||||||
|  | } U2fAuthMode; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t format; | ||||||
|  |     uint8_t xy[64]; | ||||||
|  | } __attribute__((packed)) U2fPubKey; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t len; | ||||||
|  |     uint8_t hash[32]; | ||||||
|  |     uint8_t nonce[32]; | ||||||
|  | } __attribute__((packed)) U2fKeyHandle; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t cla; | ||||||
|  |     uint8_t ins; | ||||||
|  |     uint8_t p1; | ||||||
|  |     uint8_t p2; | ||||||
|  |     uint8_t len[3]; | ||||||
|  |     uint8_t challenge[32]; | ||||||
|  |     uint8_t app_id[32]; | ||||||
|  | } __attribute__((packed)) U2fRegisterReq; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t reserved; | ||||||
|  |     U2fPubKey pub_key; | ||||||
|  |     U2fKeyHandle key_handle; | ||||||
|  |     uint8_t cert[]; | ||||||
|  | } __attribute__((packed)) U2fRegisterResp; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t cla; | ||||||
|  |     uint8_t ins; | ||||||
|  |     uint8_t p1; | ||||||
|  |     uint8_t p2; | ||||||
|  |     uint8_t len[3]; | ||||||
|  |     uint8_t challenge[32]; | ||||||
|  |     uint8_t app_id[32]; | ||||||
|  |     U2fKeyHandle key_handle; | ||||||
|  | } __attribute__((packed)) U2fAuthReq; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t user_present; | ||||||
|  |     uint32_t counter; | ||||||
|  |     uint8_t signature[]; | ||||||
|  | } __attribute__((packed)) U2fAuthResp; | ||||||
|  | 
 | ||||||
|  | static const uint8_t ver_str[] = {"U2F_V2"}; | ||||||
|  | 
 | ||||||
|  | static const uint8_t state_no_error[] = {0x90, 0x00}; | ||||||
|  | static const uint8_t state_not_supported[] = {0x6D, 0x00}; | ||||||
|  | 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]; | ||||||
|  |     uint32_t counter; | ||||||
|  |     const struct uECC_Curve_t* p_curve; | ||||||
|  |     bool ready; | ||||||
|  |     bool user_present; | ||||||
|  |     U2fEvtCallback callback; | ||||||
|  |     void* context; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static int u2f_uecc_random(uint8_t* dest, unsigned size) { | ||||||
|  |     furi_hal_random_fill_buf(dest, size); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | U2fData* u2f_alloc() { | ||||||
|  |     return furi_alloc(sizeof(U2fData)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void u2f_free(U2fData* U2F) { | ||||||
|  |     furi_assert(U2F); | ||||||
|  |     free(U2F); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool u2f_init(U2fData* U2F) { | ||||||
|  |     furi_assert(U2F); | ||||||
|  | 
 | ||||||
|  |     if(u2f_data_cert_check() == false) { | ||||||
|  |         FURI_LOG_E(TAG, "Certificate load error"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     if(u2f_data_cert_key_load(U2F->cert_key) == false) { | ||||||
|  |         FURI_LOG_E(TAG, "Certificate key load error"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     if(u2f_data_key_load(U2F->device_key) == false) { | ||||||
|  |         FURI_LOG_W(TAG, "Key loading error, generating new"); | ||||||
|  |         if(u2f_data_key_generate(U2F->device_key) == false) { | ||||||
|  |             FURI_LOG_E(TAG, "Key write failed"); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if(u2f_data_cnt_read(&U2F->counter) == false) { | ||||||
|  |         FURI_LOG_W(TAG, "Counter loading error, resetting counter"); | ||||||
|  |         U2F->counter = 0; | ||||||
|  |         if(u2f_data_cnt_write(0) == false) { | ||||||
|  |             FURI_LOG_E(TAG, "Counter write failed"); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     U2F->p_curve = uECC_secp256r1(); | ||||||
|  |     uECC_set_rng(u2f_uecc_random); | ||||||
|  | 
 | ||||||
|  |     U2F->ready = true; | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void u2f_set_event_callback(U2fData* U2F, U2fEvtCallback callback, void* context) { | ||||||
|  |     furi_assert(U2F); | ||||||
|  |     furi_assert(callback); | ||||||
|  |     U2F->callback = callback; | ||||||
|  |     U2F->context = context; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void u2f_confirm_user_present(U2fData* U2F) { | ||||||
|  |     U2F->user_present = true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static uint8_t u2f_der_encode_int(uint8_t* der, uint8_t* val, uint8_t val_len) { | ||||||
|  |     der[0] = 0x02; // Integer
 | ||||||
|  | 
 | ||||||
|  |     uint8_t len = 2; | ||||||
|  |     // Omit leading zeros
 | ||||||
|  |     while(val[0] == 0 && val_len > 0) { | ||||||
|  |         ++val; | ||||||
|  |         --val_len; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Check if integer is negative
 | ||||||
|  |     if(val[0] > 0x7f) der[len++] = 0; | ||||||
|  | 
 | ||||||
|  |     memcpy(der + len, val, val_len); | ||||||
|  |     len += val_len; | ||||||
|  | 
 | ||||||
|  |     der[1] = len - 2; | ||||||
|  |     return len; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 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); | ||||||
|  | 
 | ||||||
|  |     der[1] = len - 2; | ||||||
|  |     return len; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) { | ||||||
|  |     U2fRegisterReq* req = (U2fRegisterReq*)buf; | ||||||
|  |     U2fRegisterResp* resp = (U2fRegisterResp*)buf; | ||||||
|  |     U2fKeyHandle handle; | ||||||
|  |     uint8_t private[32]; | ||||||
|  |     U2fPubKey pub_key; | ||||||
|  |     uint8_t hash[32]; | ||||||
|  |     uint8_t signature[64]; | ||||||
|  | 
 | ||||||
|  |     if(U2F->callback != NULL) U2F->callback(U2fNotifyRegister, U2F->context); | ||||||
|  |     if(U2F->user_present == false) { | ||||||
|  |         memcpy(&buf[0], state_user_missing, 2); | ||||||
|  |         return 2; | ||||||
|  |     } | ||||||
|  |     U2F->user_present = false; | ||||||
|  | 
 | ||||||
|  |     hmac_sha256_context hmac_ctx; | ||||||
|  |     sha256_context sha_ctx; | ||||||
|  | 
 | ||||||
|  |     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); | ||||||
|  | 
 | ||||||
|  |     // 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 public key
 | ||||||
|  |     pub_key.format = 0x04; // Uncompressed point
 | ||||||
|  |     uECC_compute_public_key(private, pub_key.xy, U2F->p_curve); | ||||||
|  | 
 | ||||||
|  |     // 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); | ||||||
|  | 
 | ||||||
|  |     uECC_sign(U2F->cert_key, hash, 32, signature, U2F->p_curve); | ||||||
|  | 
 | ||||||
|  |     // Encode response message
 | ||||||
|  |     resp->reserved = 0x05; | ||||||
|  |     memcpy(&(resp->pub_key), &pub_key, sizeof(U2fPubKey)); | ||||||
|  |     memcpy(&(resp->key_handle), &handle, sizeof(U2fKeyHandle)); | ||||||
|  |     uint32_t cert_len = u2f_data_cert_load(resp->cert); | ||||||
|  |     uint8_t signature_len = u2f_der_encode_signature(resp->cert + cert_len, signature); | ||||||
|  |     memcpy(resp->cert + cert_len + signature_len, state_no_error, 2); | ||||||
|  | 
 | ||||||
|  |     return (sizeof(U2fRegisterResp) + cert_len + signature_len + 2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 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 mac_control[32]; | ||||||
|  |     hmac_sha256_context hmac_ctx; | ||||||
|  |     sha256_context sha_ctx; | ||||||
|  |     uint8_t flags = 0; | ||||||
|  |     uint8_t hash[32]; | ||||||
|  |     uint8_t signature[64]; | ||||||
|  | 
 | ||||||
|  |     if(U2F->callback != NULL) U2F->callback(U2fNotifyAuth, U2F->context); | ||||||
|  |     if(U2F->user_present == true) { | ||||||
|  |         flags |= 1; | ||||||
|  |     } else { | ||||||
|  |         if(req->p1 == U2fEnforce) { | ||||||
|  |             memcpy(&buf[0], state_user_missing, 2); | ||||||
|  |             return 2; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     U2F->user_present = false; | ||||||
|  | 
 | ||||||
|  |     // 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*)&(U2F->counter), 4); | ||||||
|  |     sha256_update(&sha_ctx, req->challenge, 32); | ||||||
|  |     sha256_finish(&sha_ctx, hash); | ||||||
|  | 
 | ||||||
|  |     // 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); | ||||||
|  | 
 | ||||||
|  |     // 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); | ||||||
|  | 
 | ||||||
|  |     if(memcmp(req->key_handle.hash, mac_control, 32) != 0) { | ||||||
|  |         FURI_LOG_W(TAG, "Wrong handle!"); | ||||||
|  |         memcpy(&buf[0], state_wrong_data, 2); | ||||||
|  |         return 2; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(req->p1 == U2fCheckOnly) { // Check-only: don't need to send full response
 | ||||||
|  |         memcpy(&buf[0], state_user_missing, 2); | ||||||
|  |         return 2; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     uECC_sign(priv_key, hash, 32, signature, U2F->p_curve); | ||||||
|  | 
 | ||||||
|  |     resp->user_present = flags; | ||||||
|  |     resp->counter = U2F->counter; | ||||||
|  |     uint8_t signature_len = u2f_der_encode_signature(resp->signature, signature); | ||||||
|  |     memcpy(resp->signature + signature_len, state_no_error, 2); | ||||||
|  | 
 | ||||||
|  |     FURI_LOG_I(TAG, "Counter: %lu", U2F->counter); | ||||||
|  |     U2F->counter++; | ||||||
|  |     u2f_data_cnt_write(U2F->counter); | ||||||
|  | 
 | ||||||
|  |     return (sizeof(U2fAuthResp) + signature_len + 2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint16_t u2f_msg_parse(U2fData* U2F, uint8_t* buf, uint16_t len) { | ||||||
|  |     furi_assert(U2F); | ||||||
|  |     if(!U2F->ready) return 0; | ||||||
|  |     if((buf[0] != 0x00) && (len < 5)) return 0; | ||||||
|  |     if(buf[1] == U2F_CMD_REGISTER) { // Register request
 | ||||||
|  |         return u2f_register(U2F, buf); | ||||||
|  | 
 | ||||||
|  |     } else if(buf[1] == U2F_CMD_AUTHENTICATE) { // Authenticate request
 | ||||||
|  |         return u2f_authenticate(U2F, buf); | ||||||
|  | 
 | ||||||
|  |     } else if(buf[1] == U2F_CMD_VERSION) { // Get U2F version string
 | ||||||
|  |         memcpy(&buf[0], ver_str, 6); | ||||||
|  |         memcpy(&buf[6], state_no_error, 2); | ||||||
|  |         return 8; | ||||||
|  |     } else { | ||||||
|  |         memcpy(&buf[0], state_not_supported, 2); | ||||||
|  |         return 2; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void u2f_wink(U2fData* U2F) { | ||||||
|  |     if(U2F->callback != NULL) U2F->callback(U2fNotifyWink, U2F->context); | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								applications/u2f/u2f.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								applications/u2f/u2f.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     U2fNotifyRegister, | ||||||
|  |     U2fNotifyAuth, | ||||||
|  |     U2fNotifyWink, | ||||||
|  | } U2fNotifyEvent; | ||||||
|  | 
 | ||||||
|  | typedef struct U2fData U2fData; | ||||||
|  | 
 | ||||||
|  | typedef void (*U2fEvtCallback)(U2fNotifyEvent evt, void* context); | ||||||
|  | 
 | ||||||
|  | U2fData* u2f_alloc(); | ||||||
|  | 
 | ||||||
|  | bool u2f_init(U2fData* instance); | ||||||
|  | 
 | ||||||
|  | void u2f_free(U2fData* instance); | ||||||
|  | 
 | ||||||
|  | void u2f_set_event_callback(U2fData* instance, U2fEvtCallback callback, void* context); | ||||||
|  | 
 | ||||||
|  | void u2f_confirm_user_present(U2fData* instance); | ||||||
|  | 
 | ||||||
|  | uint16_t u2f_msg_parse(U2fData* instance, uint8_t* buf, uint16_t len); | ||||||
|  | 
 | ||||||
|  | void u2f_wink(U2fData* instance); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
							
								
								
									
										77
									
								
								applications/u2f/u2f_app.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								applications/u2f/u2f_app.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,77 @@ | |||||||
|  | #include "u2f_app_i.h" | ||||||
|  | #include <furi.h> | ||||||
|  | #include <furi-hal.h> | ||||||
|  | 
 | ||||||
|  | static bool u2f_app_custom_event_callback(void* context, uint32_t event) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     U2fApp* app = context; | ||||||
|  |     return scene_manager_handle_custom_event(app->scene_manager, event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool u2f_app_back_event_callback(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     U2fApp* app = context; | ||||||
|  |     return scene_manager_handle_back_event(app->scene_manager); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void u2f_app_tick_event_callback(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     U2fApp* app = context; | ||||||
|  |     scene_manager_handle_tick_event(app->scene_manager); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | U2fApp* u2f_app_alloc() { | ||||||
|  |     U2fApp* app = furi_alloc(sizeof(U2fApp)); | ||||||
|  | 
 | ||||||
|  |     app->gui = furi_record_open("gui"); | ||||||
|  |     app->notifications = furi_record_open("notification"); | ||||||
|  | 
 | ||||||
|  |     app->view_dispatcher = view_dispatcher_alloc(); | ||||||
|  |     app->scene_manager = scene_manager_alloc(&u2f_scene_handlers, app); | ||||||
|  |     view_dispatcher_enable_queue(app->view_dispatcher); | ||||||
|  |     view_dispatcher_set_event_callback_context(app->view_dispatcher, app); | ||||||
|  |     view_dispatcher_set_tick_event_callback( | ||||||
|  |         app->view_dispatcher, u2f_app_tick_event_callback, 500); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_set_custom_event_callback(app->view_dispatcher, u2f_app_custom_event_callback); | ||||||
|  |     view_dispatcher_set_navigation_event_callback( | ||||||
|  |         app->view_dispatcher, u2f_app_back_event_callback); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); | ||||||
|  | 
 | ||||||
|  |     app->u2f_view = u2f_view_alloc(); | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         app->view_dispatcher, U2fAppViewMain, u2f_view_get_view(app->u2f_view)); | ||||||
|  | 
 | ||||||
|  |     scene_manager_next_scene(app->scene_manager, U2fAppViewMain); | ||||||
|  | 
 | ||||||
|  |     return app; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void u2f_app_free(U2fApp* app) { | ||||||
|  |     furi_assert(app); | ||||||
|  | 
 | ||||||
|  |     // Views
 | ||||||
|  |     view_dispatcher_remove_view(app->view_dispatcher, U2fAppViewMain); | ||||||
|  |     u2f_view_free(app->u2f_view); | ||||||
|  | 
 | ||||||
|  |     // View dispatcher
 | ||||||
|  |     view_dispatcher_free(app->view_dispatcher); | ||||||
|  |     scene_manager_free(app->scene_manager); | ||||||
|  | 
 | ||||||
|  |     // Close records
 | ||||||
|  |     furi_record_close("gui"); | ||||||
|  |     furi_record_close("notification"); | ||||||
|  | 
 | ||||||
|  |     free(app); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int32_t u2f_app(void* p) { | ||||||
|  |     U2fApp* u2f_app = u2f_app_alloc(); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_run(u2f_app->view_dispatcher); | ||||||
|  | 
 | ||||||
|  |     u2f_app_free(u2f_app); | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								applications/u2f/u2f_app.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								applications/u2f/u2f_app.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | typedef struct U2fApp U2fApp; | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
							
								
								
									
										45
									
								
								applications/u2f/u2f_app_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								applications/u2f/u2f_app_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include "u2f_app.h" | ||||||
|  | #include "scenes/u2f_scene.h" | ||||||
|  | 
 | ||||||
|  | #include <gui/gui.h> | ||||||
|  | #include <gui/view_dispatcher.h> | ||||||
|  | #include <gui/scene_manager.h> | ||||||
|  | #include <gui/modules/submenu.h> | ||||||
|  | #include <dialogs/dialogs.h> | ||||||
|  | #include <notification/notification-messages.h> | ||||||
|  | #include <gui/modules/variable-item-list.h> | ||||||
|  | #include "views/u2f_view.h" | ||||||
|  | #include "u2f_hid.h" | ||||||
|  | #include "u2f.h" | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     U2fCustomEventNone, | ||||||
|  | 
 | ||||||
|  |     U2fCustomEventRegister, | ||||||
|  |     U2fCustomEventAuth, | ||||||
|  |     U2fCustomEventWink, | ||||||
|  | 
 | ||||||
|  |     U2fCustomEventTimeout, | ||||||
|  | 
 | ||||||
|  |     U2fCustomEventConfirm, | ||||||
|  | 
 | ||||||
|  | } GpioCustomEvent; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     U2fAppViewMain, | ||||||
|  | } U2fAppView; | ||||||
|  | 
 | ||||||
|  | struct U2fApp { | ||||||
|  |     Gui* gui; | ||||||
|  |     ViewDispatcher* view_dispatcher; | ||||||
|  |     SceneManager* scene_manager; | ||||||
|  |     NotificationApp* notifications; | ||||||
|  |     osTimerId_t timer; | ||||||
|  |     U2fHid* u2f_hid; | ||||||
|  |     U2fView* u2f_view; | ||||||
|  |     U2fData* u2f_instance; | ||||||
|  |     GpioCustomEvent event_cur; | ||||||
|  |     bool u2f_ready; | ||||||
|  | }; | ||||||
							
								
								
									
										382
									
								
								applications/u2f/u2f_data.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										382
									
								
								applications/u2f/u2f_data.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,382 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include "u2f_hid.h" | ||||||
|  | #include <furi-hal.h> | ||||||
|  | #include <storage/storage.h> | ||||||
|  | #include <furi-hal-random.h> | ||||||
|  | #include <flipper_file.h> | ||||||
|  | 
 | ||||||
|  | #define TAG "U2F" | ||||||
|  | 
 | ||||||
|  | #define U2F_DATA_FOLDER "/any/u2f/" | ||||||
|  | #define U2F_CERT_FILE U2F_DATA_FOLDER "cert.der" | ||||||
|  | #define U2F_CERT_KEY_FILE U2F_DATA_FOLDER "cert_key.u2f" | ||||||
|  | #define U2F_KEY_FILE U2F_DATA_FOLDER "key.u2f" | ||||||
|  | #define U2F_CNT_FILE U2F_DATA_FOLDER "cnt.u2f" | ||||||
|  | 
 | ||||||
|  | #define U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_FACTORY 2 | ||||||
|  | #define U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE 11 | ||||||
|  | 
 | ||||||
|  | #define U2F_CERT_STOCK 0 // Stock certificate, private key is encrypted with factory key
 | ||||||
|  | #define U2F_CERT_USER 1 // User certificate, private key is encrypted with unique key
 | ||||||
|  | 
 | ||||||
|  | #define U2F_CERT_KEY_FILE_TYPE "Flipper U2F Certificate Key File" | ||||||
|  | #define U2F_CERT_KEY_VERSION 1 | ||||||
|  | 
 | ||||||
|  | #define U2F_DEVICE_KEY_FILE_TYPE "Flipper U2F Device Key File" | ||||||
|  | #define U2F_DEVICE_KEY_VERSION 1 | ||||||
|  | 
 | ||||||
|  | #define U2F_COUNTER_FILE_TYPE "Flipper U2F Counter File" | ||||||
|  | #define U2F_COUNTER_VERSION 1 | ||||||
|  | 
 | ||||||
|  | #define U2F_COUNTER_CONTROL_VAL 0xAA5500FF | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint32_t counter; | ||||||
|  |     uint8_t random_salt[24]; | ||||||
|  |     uint32_t control; | ||||||
|  | } __attribute__((packed)) U2fCounterData; | ||||||
|  | 
 | ||||||
|  | bool u2f_data_cert_check() { | ||||||
|  |     bool state = false; | ||||||
|  |     Storage* fs_api = furi_record_open("storage"); | ||||||
|  |     File* file = storage_file_alloc(fs_api); | ||||||
|  |     uint8_t file_buf[8]; | ||||||
|  | 
 | ||||||
|  |     if(storage_file_open(file, U2F_CERT_FILE, FSAM_READ, FSOM_OPEN_EXISTING)) { | ||||||
|  |         do { | ||||||
|  |             // Read header to check certificate size
 | ||||||
|  |             size_t file_size = storage_file_size(file); | ||||||
|  |             size_t len_cur = storage_file_read(file, file_buf, 4); | ||||||
|  |             if(len_cur != 4) break; | ||||||
|  | 
 | ||||||
|  |             if(file_buf[0] != 0x30) { | ||||||
|  |                 FURI_LOG_E(TAG, "Wrong certificate header"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             size_t temp_len = ((file_buf[2] << 8) | (file_buf[3])) + 4; | ||||||
|  |             if(temp_len != file_size) { | ||||||
|  |                 FURI_LOG_E(TAG, "Wrong certificate length"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             state = true; | ||||||
|  |         } while(0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     storage_file_close(file); | ||||||
|  |     storage_file_free(file); | ||||||
|  | 
 | ||||||
|  |     furi_record_close("storage"); | ||||||
|  | 
 | ||||||
|  |     return state; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint32_t u2f_data_cert_load(uint8_t* cert) { | ||||||
|  |     furi_assert(cert); | ||||||
|  | 
 | ||||||
|  |     Storage* fs_api = furi_record_open("storage"); | ||||||
|  |     File* file = storage_file_alloc(fs_api); | ||||||
|  |     uint32_t file_size = 0; | ||||||
|  |     uint32_t len_cur = 0; | ||||||
|  | 
 | ||||||
|  |     if(storage_file_open(file, U2F_CERT_FILE, FSAM_READ, FSOM_OPEN_EXISTING)) { | ||||||
|  |         file_size = storage_file_size(file); | ||||||
|  |         len_cur = storage_file_read(file, cert, file_size); | ||||||
|  |         if(len_cur != file_size) len_cur = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     storage_file_close(file); | ||||||
|  |     storage_file_free(file); | ||||||
|  |     furi_record_close("storage"); | ||||||
|  | 
 | ||||||
|  |     return len_cur; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool u2f_data_cert_key_load(uint8_t* cert_key) { | ||||||
|  |     furi_assert(cert_key); | ||||||
|  | 
 | ||||||
|  |     bool state = false; | ||||||
|  |     uint8_t iv[16]; | ||||||
|  |     uint8_t key[48]; | ||||||
|  |     uint32_t cert_type = 0; | ||||||
|  |     uint8_t key_slot = 0; | ||||||
|  |     uint32_t version = 0; | ||||||
|  | 
 | ||||||
|  |     // Check if unique key exists in secure eclave and generate it if missing
 | ||||||
|  |     if(!furi_hal_crypto_verify_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE)) return false; | ||||||
|  | 
 | ||||||
|  |     string_t filetype; | ||||||
|  |     string_init(filetype); | ||||||
|  | 
 | ||||||
|  |     Storage* storage = furi_record_open("storage"); | ||||||
|  |     FlipperFile* flipper_file = flipper_file_alloc(storage); | ||||||
|  | 
 | ||||||
|  |     if(flipper_file_open_existing(flipper_file, U2F_CERT_KEY_FILE)) { | ||||||
|  |         do { | ||||||
|  |             if(!flipper_file_read_header(flipper_file, filetype, &version)) { | ||||||
|  |                 FURI_LOG_E(TAG, "Missing or incorrect header"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(strcmp(string_get_cstr(filetype), U2F_CERT_KEY_FILE_TYPE) != 0 || | ||||||
|  |                version != U2F_CERT_KEY_VERSION) { | ||||||
|  |                 FURI_LOG_E(TAG, "Type or version mismatch"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(!flipper_file_read_uint32(flipper_file, "Type", &cert_type, 1)) { | ||||||
|  |                 FURI_LOG_E(TAG, "Missing cert type"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(cert_type == U2F_CERT_STOCK) { | ||||||
|  |                 key_slot = U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_FACTORY; | ||||||
|  |             } else if(cert_type == U2F_CERT_USER) { | ||||||
|  |                 key_slot = U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE; | ||||||
|  |             } else { | ||||||
|  |                 FURI_LOG_E(TAG, "Unknown cert type"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(!flipper_file_read_hex(flipper_file, "IV", iv, 16)) { | ||||||
|  |                 FURI_LOG_E(TAG, "Missing IV"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(!flipper_file_read_hex(flipper_file, "Data", key, 48)) { | ||||||
|  |                 FURI_LOG_E(TAG, "Missing data"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(!furi_hal_crypto_store_load_key(key_slot, iv)) { | ||||||
|  |                 FURI_LOG_E(TAG, "Unable to load encryption key"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             memset(cert_key, 0, 32); | ||||||
|  | 
 | ||||||
|  |             if(!furi_hal_crypto_decrypt(key, cert_key, 32)) { | ||||||
|  |                 memset(cert_key, 0, 32); | ||||||
|  |                 FURI_LOG_E(TAG, "Decryption failed"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             furi_hal_crypto_store_unload_key(key_slot); | ||||||
|  |             state = true; | ||||||
|  |         } while(0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     flipper_file_close(flipper_file); | ||||||
|  |     flipper_file_free(flipper_file); | ||||||
|  |     furi_record_close("storage"); | ||||||
|  |     string_clear(filetype); | ||||||
|  | 
 | ||||||
|  |     return state; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool u2f_data_key_load(uint8_t* device_key) { | ||||||
|  |     furi_assert(device_key); | ||||||
|  | 
 | ||||||
|  |     bool state = false; | ||||||
|  |     uint8_t iv[16]; | ||||||
|  |     uint8_t key[48]; | ||||||
|  |     uint32_t version = 0; | ||||||
|  | 
 | ||||||
|  |     string_t filetype; | ||||||
|  |     string_init(filetype); | ||||||
|  | 
 | ||||||
|  |     Storage* storage = furi_record_open("storage"); | ||||||
|  |     FlipperFile* flipper_file = flipper_file_alloc(storage); | ||||||
|  | 
 | ||||||
|  |     if(flipper_file_open_existing(flipper_file, U2F_KEY_FILE)) { | ||||||
|  |         do { | ||||||
|  |             if(!flipper_file_read_header(flipper_file, filetype, &version)) { | ||||||
|  |                 FURI_LOG_E(TAG, "Missing or incorrect header"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             if(strcmp(string_get_cstr(filetype), U2F_DEVICE_KEY_FILE_TYPE) != 0 || | ||||||
|  |                version != U2F_DEVICE_KEY_VERSION) { | ||||||
|  |                 FURI_LOG_E(TAG, "Type or version mismatch"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             if(!flipper_file_read_hex(flipper_file, "IV", iv, 16)) { | ||||||
|  |                 FURI_LOG_E(TAG, "Missing IV"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             if(!flipper_file_read_hex(flipper_file, "Data", key, 48)) { | ||||||
|  |                 FURI_LOG_E(TAG, "Missing data"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             if(!furi_hal_crypto_store_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) { | ||||||
|  |                 FURI_LOG_E(TAG, "Unable to load encryption key"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             memset(device_key, 0, 32); | ||||||
|  |             if(!furi_hal_crypto_decrypt(key, device_key, 32)) { | ||||||
|  |                 memset(device_key, 0, 32); | ||||||
|  |                 FURI_LOG_E(TAG, "Decryption failed"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             furi_hal_crypto_store_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE); | ||||||
|  |             state = true; | ||||||
|  |         } while(0); | ||||||
|  |     } | ||||||
|  |     flipper_file_close(flipper_file); | ||||||
|  |     flipper_file_free(flipper_file); | ||||||
|  |     furi_record_close("storage"); | ||||||
|  |     string_clear(filetype); | ||||||
|  |     return state; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool u2f_data_key_generate(uint8_t* device_key) { | ||||||
|  |     furi_assert(device_key); | ||||||
|  | 
 | ||||||
|  |     bool state = false; | ||||||
|  |     uint8_t iv[16]; | ||||||
|  |     uint8_t key[32]; | ||||||
|  |     uint8_t key_encrypted[48]; | ||||||
|  | 
 | ||||||
|  |     // Generate random IV and key
 | ||||||
|  |     furi_hal_random_fill_buf(iv, 16); | ||||||
|  |     furi_hal_random_fill_buf(key, 32); | ||||||
|  | 
 | ||||||
|  |     if(!furi_hal_crypto_store_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) { | ||||||
|  |         FURI_LOG_E(TAG, "Unable to load encryption key"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(!furi_hal_crypto_encrypt(key, key_encrypted, 32)) { | ||||||
|  |         FURI_LOG_E(TAG, "Encryption failed"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     furi_hal_crypto_store_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE); | ||||||
|  | 
 | ||||||
|  |     string_t filetype; | ||||||
|  |     string_init(filetype); | ||||||
|  | 
 | ||||||
|  |     Storage* storage = furi_record_open("storage"); | ||||||
|  |     FlipperFile* flipper_file = flipper_file_alloc(storage); | ||||||
|  | 
 | ||||||
|  |     if(flipper_file_open_always(flipper_file, U2F_KEY_FILE)) { | ||||||
|  |         do { | ||||||
|  |             if(!flipper_file_write_header_cstr( | ||||||
|  |                    flipper_file, U2F_DEVICE_KEY_FILE_TYPE, U2F_DEVICE_KEY_VERSION)) | ||||||
|  |                 break; | ||||||
|  |             if(!flipper_file_write_hex(flipper_file, "IV", iv, 16)) break; | ||||||
|  |             if(!flipper_file_write_hex(flipper_file, "Data", key_encrypted, 48)) break; | ||||||
|  |             state = true; | ||||||
|  |             memcpy(device_key, key, 32); | ||||||
|  |         } while(0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     flipper_file_close(flipper_file); | ||||||
|  |     flipper_file_free(flipper_file); | ||||||
|  |     furi_record_close("storage"); | ||||||
|  |     string_clear(filetype); | ||||||
|  | 
 | ||||||
|  |     return state; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool u2f_data_cnt_read(uint32_t* cnt_val) { | ||||||
|  |     furi_assert(cnt_val); | ||||||
|  | 
 | ||||||
|  |     bool state = false; | ||||||
|  |     uint8_t iv[16]; | ||||||
|  |     U2fCounterData cnt; | ||||||
|  |     uint8_t cnt_encr[48]; | ||||||
|  |     uint32_t version = 0; | ||||||
|  | 
 | ||||||
|  |     string_t filetype; | ||||||
|  |     string_init(filetype); | ||||||
|  | 
 | ||||||
|  |     Storage* storage = furi_record_open("storage"); | ||||||
|  |     FlipperFile* flipper_file = flipper_file_alloc(storage); | ||||||
|  | 
 | ||||||
|  |     if(flipper_file_open_existing(flipper_file, U2F_CNT_FILE)) { | ||||||
|  |         do { | ||||||
|  |             if(!flipper_file_read_header(flipper_file, filetype, &version)) { | ||||||
|  |                 FURI_LOG_E(TAG, "Missing or incorrect header"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             if(strcmp(string_get_cstr(filetype), U2F_COUNTER_FILE_TYPE) != 0 || | ||||||
|  |                version != U2F_COUNTER_VERSION) { | ||||||
|  |                 FURI_LOG_E(TAG, "Type or version mismatch"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             if(!flipper_file_read_hex(flipper_file, "IV", iv, 16)) { | ||||||
|  |                 FURI_LOG_E(TAG, "Missing IV"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             if(!flipper_file_read_hex(flipper_file, "Data", cnt_encr, 48)) { | ||||||
|  |                 FURI_LOG_E(TAG, "Missing data"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             if(!furi_hal_crypto_store_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) { | ||||||
|  |                 FURI_LOG_E(TAG, "Unable to load encryption key"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             memset(&cnt, 0, 32); | ||||||
|  |             if(!furi_hal_crypto_decrypt(cnt_encr, (uint8_t*)&cnt, 32)) { | ||||||
|  |                 memset(&cnt, 0, 32); | ||||||
|  |                 FURI_LOG_E(TAG, "Decryption failed"); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             furi_hal_crypto_store_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE); | ||||||
|  |             if(cnt.control == U2F_COUNTER_CONTROL_VAL) { | ||||||
|  |                 *cnt_val = cnt.counter; | ||||||
|  |                 state = true; | ||||||
|  |             } | ||||||
|  |         } while(0); | ||||||
|  |     } | ||||||
|  |     flipper_file_close(flipper_file); | ||||||
|  |     flipper_file_free(flipper_file); | ||||||
|  |     furi_record_close("storage"); | ||||||
|  |     string_clear(filetype); | ||||||
|  |     return state; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool u2f_data_cnt_write(uint32_t cnt_val) { | ||||||
|  |     bool state = false; | ||||||
|  |     uint8_t iv[16]; | ||||||
|  |     U2fCounterData cnt; | ||||||
|  |     uint8_t cnt_encr[48]; | ||||||
|  | 
 | ||||||
|  |     // Generate random IV and key
 | ||||||
|  |     furi_hal_random_fill_buf(iv, 16); | ||||||
|  |     furi_hal_random_fill_buf(cnt.random_salt, 24); | ||||||
|  |     cnt.control = U2F_COUNTER_CONTROL_VAL; | ||||||
|  |     cnt.counter = cnt_val; | ||||||
|  | 
 | ||||||
|  |     if(!furi_hal_crypto_store_load_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE, iv)) { | ||||||
|  |         FURI_LOG_E(TAG, "Unable to load encryption key"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(!furi_hal_crypto_encrypt((uint8_t*)&cnt, cnt_encr, 32)) { | ||||||
|  |         FURI_LOG_E(TAG, "Encryption failed"); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     furi_hal_crypto_store_unload_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE); | ||||||
|  | 
 | ||||||
|  |     string_t filetype; | ||||||
|  |     string_init(filetype); | ||||||
|  | 
 | ||||||
|  |     Storage* storage = furi_record_open("storage"); | ||||||
|  |     FlipperFile* flipper_file = flipper_file_alloc(storage); | ||||||
|  | 
 | ||||||
|  |     if(flipper_file_open_always(flipper_file, U2F_CNT_FILE)) { | ||||||
|  |         do { | ||||||
|  |             if(!flipper_file_write_header_cstr( | ||||||
|  |                    flipper_file, U2F_COUNTER_FILE_TYPE, U2F_COUNTER_VERSION)) | ||||||
|  |                 break; | ||||||
|  |             if(!flipper_file_write_hex(flipper_file, "IV", iv, 16)) break; | ||||||
|  |             if(!flipper_file_write_hex(flipper_file, "Data", cnt_encr, 48)) break; | ||||||
|  |             state = true; | ||||||
|  |         } while(0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     flipper_file_close(flipper_file); | ||||||
|  |     flipper_file_free(flipper_file); | ||||||
|  |     furi_record_close("storage"); | ||||||
|  |     string_clear(filetype); | ||||||
|  | 
 | ||||||
|  |     return state; | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								applications/u2f/u2f_data.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								applications/u2f/u2f_data.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | bool u2f_data_cert_check(); | ||||||
|  | 
 | ||||||
|  | uint32_t u2f_data_cert_load(uint8_t* cert); | ||||||
|  | 
 | ||||||
|  | bool u2f_data_cert_key_load(uint8_t* cert_key); | ||||||
|  | 
 | ||||||
|  | bool u2f_data_key_load(uint8_t* device_key); | ||||||
|  | 
 | ||||||
|  | bool u2f_data_key_generate(uint8_t* device_key); | ||||||
|  | 
 | ||||||
|  | bool u2f_data_cnt_read(uint32_t* cnt); | ||||||
|  | 
 | ||||||
|  | bool u2f_data_cnt_write(uint32_t cnt); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
							
								
								
									
										293
									
								
								applications/u2f/u2f_hid.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										293
									
								
								applications/u2f/u2f_hid.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,293 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include "u2f_hid.h" | ||||||
|  | #include "u2f.h" | ||||||
|  | #include <furi-hal.h> | ||||||
|  | #include <gui/gui.h> | ||||||
|  | #include <input/input.h> | ||||||
|  | #include <lib/toolbox/args.h> | ||||||
|  | #include <furi-hal-usb-hid-u2f.h> | ||||||
|  | #include <storage/storage.h> | ||||||
|  | 
 | ||||||
|  | #include <furi-hal-console.h> | ||||||
|  | 
 | ||||||
|  | #define TAG "U2FHID" | ||||||
|  | #define WORKER_TAG TAG "Worker" | ||||||
|  | 
 | ||||||
|  | #define U2F_HID_MAX_PAYLOAD_LEN ((HID_U2F_PACKET_LEN - 7) + 128 * (HID_U2F_PACKET_LEN - 5)) | ||||||
|  | 
 | ||||||
|  | #define U2F_HID_TYPE_MASK 0x80 // Frame type mask
 | ||||||
|  | #define U2F_HID_TYPE_INIT 0x80 // Initial frame identifier
 | ||||||
|  | #define U2F_HID_TYPE_CONT 0x00 // Continuation frame identifier
 | ||||||
|  | 
 | ||||||
|  | #define U2F_HID_PING (U2F_HID_TYPE_INIT | 0x01) // Echo data through local processor only
 | ||||||
|  | #define U2F_HID_MSG (U2F_HID_TYPE_INIT | 0x03) // Send U2F message frame
 | ||||||
|  | #define U2F_HID_LOCK (U2F_HID_TYPE_INIT | 0x04) // Send lock channel command
 | ||||||
|  | #define U2F_HID_INIT (U2F_HID_TYPE_INIT | 0x06) // Channel initialization
 | ||||||
|  | #define U2F_HID_WINK (U2F_HID_TYPE_INIT | 0x08) // Send device identification wink
 | ||||||
|  | #define U2F_HID_ERROR (U2F_HID_TYPE_INIT | 0x3f) // Error response
 | ||||||
|  | 
 | ||||||
|  | #define U2F_HID_ERR_NONE 0x00 // No error
 | ||||||
|  | #define U2F_HID_ERR_INVALID_CMD 0x01 // Invalid command
 | ||||||
|  | #define U2F_HID_ERR_INVALID_PAR 0x02 // Invalid parameter
 | ||||||
|  | #define U2F_HID_ERR_INVALID_LEN 0x03 // Invalid message length
 | ||||||
|  | #define U2F_HID_ERR_INVALID_SEQ 0x04 // Invalid message sequencing
 | ||||||
|  | #define U2F_HID_ERR_MSG_TIMEOUT 0x05 // Message has timed out
 | ||||||
|  | #define U2F_HID_ERR_CHANNEL_BUSY 0x06 // Channel busy
 | ||||||
|  | #define U2F_HID_ERR_LOCK_REQUIRED 0x0a // Command requires channel lock
 | ||||||
|  | #define U2F_HID_ERR_SYNC_FAIL 0x0b // SYNC command failed
 | ||||||
|  | #define U2F_HID_ERR_OTHER 0x7f // Other unspecified error
 | ||||||
|  | 
 | ||||||
|  | #define U2F_HID_BROADCAST_CID 0xFFFFFFFF | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     WorkerEvtReserved = (1 << 0), | ||||||
|  |     WorkerEvtStop = (1 << 1), | ||||||
|  |     WorkerEvtConnect = (1 << 2), | ||||||
|  |     WorkerEvtDisconnect = (1 << 3), | ||||||
|  |     WorkerEvtRequest = (1 << 4), | ||||||
|  |     WorkerEvtUnlock = (1 << 5), | ||||||
|  | } WorkerEvtFlags; | ||||||
|  | 
 | ||||||
|  | struct U2fHid_packet { | ||||||
|  |     uint32_t cid; | ||||||
|  |     uint16_t len; | ||||||
|  |     uint8_t cmd; | ||||||
|  |     uint8_t payload[U2F_HID_MAX_PAYLOAD_LEN]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct U2fHid { | ||||||
|  |     FuriThread* thread; | ||||||
|  |     osTimerId_t lock_timer; | ||||||
|  |     struct U2fHid_packet packet; | ||||||
|  |     uint8_t seq_id_last; | ||||||
|  |     uint16_t req_buf_ptr; | ||||||
|  |     uint32_t req_len_left; | ||||||
|  |     uint32_t lock_cid; | ||||||
|  |     bool lock; | ||||||
|  |     U2fData* u2f_instance; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void u2f_hid_event_callback(HidU2fEvent ev, void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     U2fHid* u2f_hid = context; | ||||||
|  | 
 | ||||||
|  |     if(ev == HidU2fDisconnected) | ||||||
|  |         osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtDisconnect); | ||||||
|  |     else if(ev == HidU2fConnected) | ||||||
|  |         osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtConnect); | ||||||
|  |     else if(ev == HidU2fRequest) | ||||||
|  |         osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtRequest); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void u2f_hid_lock_timeout_callback(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     U2fHid* u2f_hid = context; | ||||||
|  | 
 | ||||||
|  |     osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtUnlock); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void u2f_hid_send_response(U2fHid* u2f_hid) { | ||||||
|  |     uint8_t packet_buf[HID_U2F_PACKET_LEN]; | ||||||
|  |     uint16_t len_remain = u2f_hid->packet.len; | ||||||
|  |     uint8_t len_cur = 0; | ||||||
|  |     uint8_t seq_cnt = 0; | ||||||
|  |     uint16_t data_ptr = 0; | ||||||
|  | 
 | ||||||
|  |     memset(packet_buf, 0, HID_U2F_PACKET_LEN); | ||||||
|  |     memcpy(packet_buf, &(u2f_hid->packet.cid), 4); | ||||||
|  | 
 | ||||||
|  |     // Init packet
 | ||||||
|  |     packet_buf[4] = u2f_hid->packet.cmd; | ||||||
|  |     packet_buf[5] = u2f_hid->packet.len >> 8; | ||||||
|  |     packet_buf[6] = (u2f_hid->packet.len & 0xFF); | ||||||
|  |     len_cur = (len_remain < (HID_U2F_PACKET_LEN - 7)) ? (len_remain) : (HID_U2F_PACKET_LEN - 7); | ||||||
|  |     if(len_cur > 0) memcpy(&packet_buf[7], u2f_hid->packet.payload, len_cur); | ||||||
|  |     furi_hal_hid_u2f_send_response(packet_buf, HID_U2F_PACKET_LEN); | ||||||
|  |     data_ptr = len_cur; | ||||||
|  |     len_remain -= len_cur; | ||||||
|  | 
 | ||||||
|  |     // Continuation packets
 | ||||||
|  |     while(len_remain > 0) { | ||||||
|  |         memset(&packet_buf[4], 0, HID_U2F_PACKET_LEN - 4); | ||||||
|  |         packet_buf[4] = seq_cnt; | ||||||
|  |         len_cur = (len_remain < (HID_U2F_PACKET_LEN - 5)) ? (len_remain) : | ||||||
|  |                                                             (HID_U2F_PACKET_LEN - 5); | ||||||
|  |         memcpy(&packet_buf[5], &(u2f_hid->packet.payload[data_ptr]), len_cur); | ||||||
|  |         furi_hal_hid_u2f_send_response(packet_buf, HID_U2F_PACKET_LEN); | ||||||
|  |         seq_cnt++; | ||||||
|  |         len_remain -= len_cur; | ||||||
|  |         data_ptr += len_cur; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void u2f_hid_send_error(U2fHid* u2f_hid, uint8_t error) { | ||||||
|  |     u2f_hid->packet.len = 1; | ||||||
|  |     u2f_hid->packet.cmd = U2F_HID_ERROR; | ||||||
|  |     u2f_hid->packet.payload[0] = error; | ||||||
|  |     u2f_hid_send_response(u2f_hid); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool u2f_hid_parse_request(U2fHid* u2f_hid) { | ||||||
|  |     FURI_LOG_I( | ||||||
|  |         WORKER_TAG, | ||||||
|  |         "Req cid=%lX cmd=%x len=%u", | ||||||
|  |         u2f_hid->packet.cid, | ||||||
|  |         u2f_hid->packet.cmd, | ||||||
|  |         u2f_hid->packet.len); | ||||||
|  | 
 | ||||||
|  |     if(u2f_hid->packet.cmd == U2F_HID_PING) { // PING - echo request back
 | ||||||
|  |         u2f_hid_send_response(u2f_hid); | ||||||
|  | 
 | ||||||
|  |     } else if(u2f_hid->packet.cmd == U2F_HID_MSG) { // MSG - U2F message
 | ||||||
|  |         if((u2f_hid->lock == true) && (u2f_hid->packet.cid != u2f_hid->lock_cid)) return false; | ||||||
|  |         uint16_t resp_len = | ||||||
|  |             u2f_msg_parse(u2f_hid->u2f_instance, u2f_hid->packet.payload, u2f_hid->packet.len); | ||||||
|  |         if(resp_len > 0) { | ||||||
|  |             u2f_hid->packet.len = resp_len; | ||||||
|  |             u2f_hid_send_response(u2f_hid); | ||||||
|  |         } else | ||||||
|  |             return false; | ||||||
|  | 
 | ||||||
|  |     } else if(u2f_hid->packet.cmd == U2F_HID_LOCK) { // LOCK - lock all channels except current
 | ||||||
|  |         if(u2f_hid->packet.len != 1) return false; | ||||||
|  |         uint8_t lock_timeout = u2f_hid->packet.payload[0]; | ||||||
|  |         if(lock_timeout == 0) { // Lock off
 | ||||||
|  |             u2f_hid->lock = false; | ||||||
|  |             u2f_hid->lock_cid = 0; | ||||||
|  |         } else { // Lock on
 | ||||||
|  |             u2f_hid->lock = true; | ||||||
|  |             u2f_hid->lock_cid = u2f_hid->packet.cid; | ||||||
|  |             osTimerStart(u2f_hid->lock_timer, lock_timeout * 1000); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } else if(u2f_hid->packet.cmd == U2F_HID_INIT) { // INIT - channel initialization request
 | ||||||
|  |         if((u2f_hid->packet.len != 8) || (u2f_hid->packet.cid != U2F_HID_BROADCAST_CID) || | ||||||
|  |            (u2f_hid->lock == true)) | ||||||
|  |             return false; | ||||||
|  |         u2f_hid->packet.len = 17; | ||||||
|  |         uint32_t random_cid = furi_hal_random_get(); | ||||||
|  |         memcpy(&(u2f_hid->packet.payload[8]), &random_cid, 4); | ||||||
|  |         u2f_hid->packet.payload[12] = 2; // Protocol version
 | ||||||
|  |         u2f_hid->packet.payload[13] = 1; // Device version major
 | ||||||
|  |         u2f_hid->packet.payload[14] = 0; // Device version minor
 | ||||||
|  |         u2f_hid->packet.payload[15] = 1; // Device build version
 | ||||||
|  |         u2f_hid->packet.payload[16] = 1; // Capabilities: wink
 | ||||||
|  |         u2f_hid_send_response(u2f_hid); | ||||||
|  | 
 | ||||||
|  |     } else if(u2f_hid->packet.cmd == U2F_HID_WINK) { // WINK - notify user
 | ||||||
|  |         if(u2f_hid->packet.len != 0) return false; | ||||||
|  |         u2f_wink(u2f_hid->u2f_instance); | ||||||
|  |         u2f_hid->packet.len = 0; | ||||||
|  |         u2f_hid_send_response(u2f_hid); | ||||||
|  |     } else | ||||||
|  |         return false; | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int32_t u2f_hid_worker(void* context) { | ||||||
|  |     U2fHid* u2f_hid = context; | ||||||
|  |     uint8_t packet_buf[HID_U2F_PACKET_LEN]; | ||||||
|  | 
 | ||||||
|  |     FURI_LOG_I(WORKER_TAG, "Init"); | ||||||
|  | 
 | ||||||
|  |     UsbInterface* usb_mode_prev = furi_hal_usb_get_config(); | ||||||
|  |     furi_hal_usb_set_config(&usb_hid_u2f); | ||||||
|  | 
 | ||||||
|  |     u2f_hid->lock_timer = osTimerNew(u2f_hid_lock_timeout_callback, osTimerOnce, u2f_hid, NULL); | ||||||
|  | 
 | ||||||
|  |     furi_hal_hid_u2f_set_callback(u2f_hid_event_callback, u2f_hid); | ||||||
|  | 
 | ||||||
|  |     while(1) { | ||||||
|  |         uint32_t flags = osThreadFlagsWait( | ||||||
|  |             WorkerEvtStop | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtRequest, | ||||||
|  |             osFlagsWaitAny, | ||||||
|  |             osWaitForever); | ||||||
|  |         furi_check((flags & osFlagsError) == 0); | ||||||
|  |         if(flags & WorkerEvtStop) break; | ||||||
|  |         if(flags & WorkerEvtConnect) FURI_LOG_I(WORKER_TAG, "Connect"); | ||||||
|  |         if(flags & WorkerEvtDisconnect) FURI_LOG_I(WORKER_TAG, "Disconnect"); | ||||||
|  |         if(flags & WorkerEvtRequest) { | ||||||
|  |             uint32_t len_cur = furi_hal_hid_u2f_get_request(packet_buf); | ||||||
|  |             if(len_cur > 0) { | ||||||
|  |                 if((packet_buf[4] & U2F_HID_TYPE_MASK) == U2F_HID_TYPE_INIT) { | ||||||
|  |                     // Init packet
 | ||||||
|  |                     u2f_hid->packet.len = (packet_buf[5] << 8) | (packet_buf[6]); | ||||||
|  |                     if(u2f_hid->packet.len > (len_cur - 7)) { | ||||||
|  |                         u2f_hid->req_len_left = u2f_hid->packet.len - (len_cur - 7); | ||||||
|  |                         len_cur = len_cur - 7; | ||||||
|  |                     } else { | ||||||
|  |                         u2f_hid->req_len_left = 0; | ||||||
|  |                         len_cur = u2f_hid->packet.len; | ||||||
|  |                     } | ||||||
|  |                     memcpy(&(u2f_hid->packet.cid), packet_buf, 4); | ||||||
|  |                     u2f_hid->packet.cmd = packet_buf[4]; | ||||||
|  |                     u2f_hid->seq_id_last = 0; | ||||||
|  |                     u2f_hid->req_buf_ptr = len_cur; | ||||||
|  |                     if(len_cur > 0) memcpy(u2f_hid->packet.payload, &packet_buf[7], len_cur); | ||||||
|  |                 } else { | ||||||
|  |                     // Continuation packet
 | ||||||
|  |                     if(u2f_hid->req_len_left > 0) { | ||||||
|  |                         uint32_t cid_temp = 0; | ||||||
|  |                         memcpy(&cid_temp, packet_buf, 4); | ||||||
|  |                         uint8_t seq_temp = packet_buf[4]; | ||||||
|  |                         if((cid_temp == u2f_hid->packet.cid) && | ||||||
|  |                            (seq_temp == u2f_hid->seq_id_last)) { | ||||||
|  |                             if(u2f_hid->req_len_left > (len_cur - 5)) { | ||||||
|  |                                 len_cur = len_cur - 5; | ||||||
|  |                                 u2f_hid->req_len_left -= len_cur; | ||||||
|  |                             } else { | ||||||
|  |                                 len_cur = u2f_hid->req_len_left; | ||||||
|  |                                 u2f_hid->req_len_left = 0; | ||||||
|  |                             } | ||||||
|  |                             memcpy( | ||||||
|  |                                 &(u2f_hid->packet.payload[u2f_hid->req_buf_ptr]), | ||||||
|  |                                 &packet_buf[5], | ||||||
|  |                                 len_cur); | ||||||
|  |                             u2f_hid->req_buf_ptr += len_cur; | ||||||
|  |                             u2f_hid->seq_id_last++; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if(u2f_hid->req_len_left == 0) { | ||||||
|  |                     if(u2f_hid_parse_request(u2f_hid) == false) { | ||||||
|  |                         u2f_hid_send_error(u2f_hid, U2F_HID_ERR_INVALID_CMD); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if(flags & WorkerEvtUnlock) { | ||||||
|  |             u2f_hid->lock = false; | ||||||
|  |             u2f_hid->lock_cid = 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     osTimerStop(u2f_hid->lock_timer); | ||||||
|  |     osTimerDelete(u2f_hid->lock_timer); | ||||||
|  | 
 | ||||||
|  |     furi_hal_hid_u2f_set_callback(NULL, NULL); | ||||||
|  |     furi_hal_usb_set_config(usb_mode_prev); | ||||||
|  |     FURI_LOG_I(WORKER_TAG, "End"); | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | U2fHid* u2f_hid_start(U2fData* u2f_inst) { | ||||||
|  |     U2fHid* u2f_hid = furi_alloc(sizeof(U2fHid)); | ||||||
|  | 
 | ||||||
|  |     u2f_hid->u2f_instance = u2f_inst; | ||||||
|  | 
 | ||||||
|  |     u2f_hid->thread = furi_thread_alloc(); | ||||||
|  |     furi_thread_set_name(u2f_hid->thread, "U2fHidWorker"); | ||||||
|  |     furi_thread_set_stack_size(u2f_hid->thread, 2048); | ||||||
|  |     furi_thread_set_context(u2f_hid->thread, u2f_hid); | ||||||
|  |     furi_thread_set_callback(u2f_hid->thread, u2f_hid_worker); | ||||||
|  |     furi_thread_start(u2f_hid->thread); | ||||||
|  |     return u2f_hid; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void u2f_hid_stop(U2fHid* u2f_hid) { | ||||||
|  |     furi_assert(u2f_hid); | ||||||
|  |     osThreadFlagsSet(furi_thread_get_thread_id(u2f_hid->thread), WorkerEvtStop); | ||||||
|  |     furi_thread_join(u2f_hid->thread); | ||||||
|  |     furi_thread_free(u2f_hid->thread); | ||||||
|  |     free(u2f_hid); | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								applications/u2f/u2f_hid.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								applications/u2f/u2f_hid.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #include <furi.h> | ||||||
|  | #include "u2f.h" | ||||||
|  | 
 | ||||||
|  | typedef struct U2fHid U2fHid; | ||||||
|  | 
 | ||||||
|  | U2fHid* u2f_hid_start(U2fData* u2f_inst); | ||||||
|  | 
 | ||||||
|  | void u2f_hid_stop(U2fHid* u2f_hid); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
							
								
								
									
										91
									
								
								applications/u2f/views/u2f_view.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								applications/u2f/views/u2f_view.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,91 @@ | |||||||
|  | #include "u2f_view.h" | ||||||
|  | #include <gui/elements.h> | ||||||
|  | 
 | ||||||
|  | struct U2fView { | ||||||
|  |     View* view; | ||||||
|  |     U2fOkCallback callback; | ||||||
|  |     void* context; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     U2fViewMsg display_msg; | ||||||
|  | } U2fModel; | ||||||
|  | 
 | ||||||
|  | static void u2f_view_draw_callback(Canvas* canvas, void* _model) { | ||||||
|  |     U2fModel* model = _model; | ||||||
|  | 
 | ||||||
|  |     canvas_set_font(canvas, FontPrimary); | ||||||
|  |     canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, "U2F Demo"); | ||||||
|  | 
 | ||||||
|  |     if(model->display_msg == U2fMsgRegister) { | ||||||
|  |         canvas_set_font(canvas, FontPrimary); | ||||||
|  |         canvas_draw_str_aligned(canvas, 0, 45, AlignLeft, AlignBottom, "Registration"); | ||||||
|  |         canvas_set_font(canvas, FontSecondary); | ||||||
|  |         canvas_draw_str_aligned(canvas, 0, 63, AlignLeft, AlignBottom, "Press [OK] to confirm"); | ||||||
|  |     } else if(model->display_msg == U2fMsgAuth) { | ||||||
|  |         canvas_set_font(canvas, FontPrimary); | ||||||
|  |         canvas_draw_str_aligned(canvas, 0, 45, AlignLeft, AlignBottom, "Authentication"); | ||||||
|  |         canvas_set_font(canvas, FontSecondary); | ||||||
|  |         canvas_draw_str_aligned(canvas, 0, 63, AlignLeft, AlignBottom, "Press [OK] to confirm"); | ||||||
|  |     } else if(model->display_msg == U2fMsgError) { | ||||||
|  |         canvas_set_font(canvas, FontPrimary); | ||||||
|  |         canvas_draw_str_aligned(canvas, 64, 40, AlignCenter, AlignCenter, "U2F data missing"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool u2f_view_input_callback(InputEvent* event, void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     U2fView* u2f = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event->type == InputTypeShort) { | ||||||
|  |         if(event->key == InputKeyOk) { | ||||||
|  |             consumed = true; | ||||||
|  |             if(u2f->callback != NULL) u2f->callback(InputTypeShort, u2f->context); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | U2fView* u2f_view_alloc() { | ||||||
|  |     U2fView* u2f = furi_alloc(sizeof(U2fView)); | ||||||
|  | 
 | ||||||
|  |     u2f->view = view_alloc(); | ||||||
|  |     view_allocate_model(u2f->view, ViewModelTypeLocking, sizeof(U2fModel)); | ||||||
|  |     view_set_context(u2f->view, u2f); | ||||||
|  |     view_set_draw_callback(u2f->view, u2f_view_draw_callback); | ||||||
|  |     view_set_input_callback(u2f->view, u2f_view_input_callback); | ||||||
|  | 
 | ||||||
|  |     return u2f; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void u2f_view_free(U2fView* u2f) { | ||||||
|  |     furi_assert(u2f); | ||||||
|  |     view_free(u2f->view); | ||||||
|  |     free(u2f); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | View* u2f_view_get_view(U2fView* u2f) { | ||||||
|  |     furi_assert(u2f); | ||||||
|  |     return u2f->view; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void u2f_view_set_ok_callback(U2fView* u2f, U2fOkCallback callback, void* context) { | ||||||
|  |     furi_assert(u2f); | ||||||
|  |     furi_assert(callback); | ||||||
|  |     with_view_model( | ||||||
|  |         u2f->view, (U2fModel * model) { | ||||||
|  |             u2f->callback = callback; | ||||||
|  |             u2f->context = context; | ||||||
|  |             return false; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void u2f_view_set_state(U2fView* u2f, U2fViewMsg msg) { | ||||||
|  |     with_view_model( | ||||||
|  |         u2f->view, (U2fModel * model) { | ||||||
|  |             model->display_msg = msg; | ||||||
|  |             return false; | ||||||
|  |         }); | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								applications/u2f/views/u2f_view.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								applications/u2f/views/u2f_view.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <gui/view.h> | ||||||
|  | 
 | ||||||
|  | typedef struct U2fView U2fView; | ||||||
|  | typedef void (*U2fOkCallback)(InputType type, void* context); | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     U2fMsgNone, | ||||||
|  |     U2fMsgRegister, | ||||||
|  |     U2fMsgAuth, | ||||||
|  |     U2fMsgError, | ||||||
|  | } U2fViewMsg; | ||||||
|  | 
 | ||||||
|  | U2fView* u2f_view_alloc(); | ||||||
|  | 
 | ||||||
|  | void u2f_view_free(U2fView* u2f); | ||||||
|  | 
 | ||||||
|  | View* u2f_view_get_view(U2fView* u2f); | ||||||
|  | 
 | ||||||
|  | void u2f_view_set_ok_callback(U2fView* u2f, U2fOkCallback callback, void* context); | ||||||
|  | 
 | ||||||
|  | void u2f_view_set_state(U2fView* u2f, U2fViewMsg msg); | ||||||
							
								
								
									
										
											BIN
										
									
								
								assets/resources/u2f/cert.der
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/resources/u2f/cert.der
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										5
									
								
								assets/resources/u2f/cert_key.u2f
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								assets/resources/u2f/cert_key.u2f
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | Filetype: Flipper U2F Certificate Key File | ||||||
|  | Version: 1 | ||||||
|  | Type: 0 | ||||||
|  | IV: E1 56 CE 83 98 FA 59 0D 45 EC 1C EB 34 FC 08 C9 | ||||||
|  | Data: E1 8C C9 9A 98 F7 B9 50 1E 85 71 8F A4 CE 76 95 87 4F AC 8B 5E D0 1F 13 BA 3B 2E E7 98 73 54 64 58 0A 00 20 55 B8 00 08 58 0A 00 20 50 4E 01 20 | ||||||
| @ -1,5 +1,6 @@ | |||||||
| #include <furi-hal-crypto.h> | #include <furi-hal-crypto.h> | ||||||
| #include <furi-hal-bt.h> | #include <furi-hal-bt.h> | ||||||
|  | #include <furi-hal-random.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <shci.h> | #include <shci.h> | ||||||
| 
 | 
 | ||||||
| @ -7,10 +8,119 @@ | |||||||
| 
 | 
 | ||||||
| CRYP_HandleTypeDef crypt; | CRYP_HandleTypeDef crypt; | ||||||
| 
 | 
 | ||||||
|  | #define ENCLAVE_FACTORY_KEY_SLOTS 10 | ||||||
|  | #define ENCLAVE_SIGNATURE_SIZE 16 | ||||||
|  | 
 | ||||||
|  | static const uint8_t enclave_signature_iv[ENCLAVE_FACTORY_KEY_SLOTS][16] = { | ||||||
|  |     {0xac, 0x5d, 0x68, 0xb8, 0x79, 0x74, 0xfc, 0x7f, 0x45, 0x02, 0x82, 0xf1, 0x48, 0x7e, 0x75, 0x8a}, | ||||||
|  |     {0x38, 0xe6, 0x6a, 0x90, 0x5e, 0x5b, 0x8a, 0xa6, 0x70, 0x30, 0x04, 0x72, 0xc2, 0x42, 0xea, 0xaf}, | ||||||
|  |     {0x73, 0xd5, 0x8e, 0xfb, 0x0f, 0x4b, 0xa9, 0x79, 0x0f, 0xde, 0x0e, 0x53, 0x44, 0x7d, 0xaa, 0xfd}, | ||||||
|  |     {0x3c, 0x9a, 0xf4, 0x43, 0x2b, 0xfe, 0xea, 0xae, 0x8c, 0xc6, 0xd1, 0x60, 0xd2, 0x96, 0x64, 0xa9}, | ||||||
|  |     {0x10, 0xac, 0x7b, 0x63, 0x03, 0x7f, 0x43, 0x18, 0xec, 0x9d, 0x9c, 0xc4, 0x01, 0xdc, 0x35, 0xa7}, | ||||||
|  |     {0x26, 0x21, 0x64, 0xe6, 0xd0, 0xf2, 0x47, 0x49, 0xdc, 0x36, 0xcd, 0x68, 0x0c, 0x91, 0x03, 0x44}, | ||||||
|  |     {0x7a, 0xbd, 0xce, 0x9c, 0x24, 0x7a, 0x2a, 0xb1, 0x3c, 0x4f, 0x5a, 0x7d, 0x80, 0x3e, 0xfc, 0x0d}, | ||||||
|  |     {0xcd, 0xdd, 0xd3, 0x02, 0x85, 0x65, 0x43, 0x83, 0xf9, 0xac, 0x75, 0x2f, 0x21, 0xef, 0x28, 0x6b}, | ||||||
|  |     {0xab, 0x73, 0x70, 0xe8, 0xe2, 0x56, 0x0f, 0x58, 0xab, 0x29, 0xa5, 0xb1, 0x13, 0x47, 0x5e, 0xe8}, | ||||||
|  |     {0x4f, 0x3c, 0x43, 0x77, 0xde, 0xed, 0x79, 0xa1, 0x8d, 0x4c, 0x1f, 0xfd, 0xdb, 0x96, 0x87, 0x2e}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const uint8_t enclave_signature_input[ENCLAVE_FACTORY_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = { | ||||||
|  |     {0x9f, 0x5c, 0xb1, 0x43, 0x17, 0x53, 0x18, 0x8c, 0x66, 0x3d, 0x39, 0x45, 0x90, 0x13, 0xa9, 0xde}, | ||||||
|  |     {0xc5, 0x98, 0xe9, 0x17, 0xb8, 0x97, 0x9e, 0x03, 0x33, 0x14, 0x13, 0x8f, 0xce, 0x74, 0x0d, 0x54}, | ||||||
|  |     {0x34, 0xba, 0x99, 0x59, 0x9f, 0x70, 0x67, 0xe9, 0x09, 0xee, 0x64, 0x0e, 0xb3, 0xba, 0xfb, 0x75}, | ||||||
|  |     {0xdc, 0xfa, 0x6c, 0x9a, 0x6f, 0x0a, 0x3e, 0xdc, 0x42, 0xf6, 0xae, 0x0d, 0x3c, 0xf7, 0x83, 0xaf}, | ||||||
|  |     {0xea, 0x2d, 0xe3, 0x1f, 0x02, 0x99, 0x1a, 0x7e, 0x6d, 0x93, 0x4c, 0xb5, 0x42, 0xf0, 0x7a, 0x9b}, | ||||||
|  |     {0x53, 0x5e, 0x04, 0xa2, 0x49, 0xa0, 0x73, 0x49, 0x56, 0xb0, 0x88, 0x8c, 0x12, 0xa0, 0xe4, 0x18}, | ||||||
|  |     {0x7d, 0xa7, 0xc5, 0x21, 0x7f, 0x12, 0x95, 0xdd, 0x4d, 0x77, 0x01, 0xfa, 0x71, 0x88, 0x2b, 0x7f}, | ||||||
|  |     {0xdc, 0x9b, 0xc5, 0xa7, 0x6b, 0x84, 0x5c, 0x37, 0x7c, 0xec, 0x05, 0xa1, 0x9f, 0x91, 0x17, 0x3b}, | ||||||
|  |     {0xea, 0xcf, 0xd9, 0x9b, 0x86, 0xcd, 0x2b, 0x43, 0x54, 0x45, 0x82, 0xc6, 0xfe, 0x73, 0x1a, 0x1a}, | ||||||
|  |     {0x77, 0xb8, 0x1b, 0x90, 0xb4, 0xb7, 0x32, 0x76, 0x8f, 0x8a, 0x57, 0x06, 0xc7, 0xdd, 0x08, 0x90}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const uint8_t enclave_signature_expected[ENCLAVE_FACTORY_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = { | ||||||
|  |     {0xe9, 0x9a, 0xce, 0xe9, 0x4d, 0xe1, 0x7f, 0x55, 0xcb, 0x8a, 0xbf, 0xf2, 0x4d, 0x98, 0x27, 0x67}, | ||||||
|  |     {0x34, 0x27, 0xa7, 0xea, 0xa8, 0x98, 0x66, 0x9b, 0xed, 0x43, 0xd3, 0x93, 0xb5, 0xa2, 0x87, 0x8e}, | ||||||
|  |     {0x6c, 0xf3, 0x01, 0x78, 0x53, 0x1b, 0x11, 0x32, 0xf0, 0x27, 0x2f, 0xe3, 0x7d, 0xa6, 0xe2, 0xfd}, | ||||||
|  |     {0xdf, 0x7f, 0x37, 0x65, 0x2f, 0xdb, 0x7c, 0xcf, 0x5b, 0xb6, 0xe4, 0x9c, 0x63, 0xc5, 0x0f, 0xe0}, | ||||||
|  |     {0x9b, 0x5c, 0xee, 0x44, 0x0e, 0xd1, 0xcb, 0x5f, 0x28, 0x9f, 0x12, 0x17, 0x59, 0x64, 0x40, 0xbb}, | ||||||
|  |     {0x94, 0xc2, 0x09, 0x98, 0x62, 0xa7, 0x2b, 0x93, 0xed, 0x36, 0x1f, 0x10, 0xbc, 0x26, 0xbd, 0x41}, | ||||||
|  |     {0x4d, 0xb2, 0x2b, 0xc5, 0x96, 0x47, 0x61, 0xf4, 0x16, 0xe0, 0x81, 0xc3, 0x8e, 0xb9, 0x9c, 0x9b}, | ||||||
|  |     {0xc3, 0x6b, 0x83, 0x55, 0x90, 0x38, 0x0f, 0xea, 0xd1, 0x65, 0xbf, 0x32, 0x4f, 0x8e, 0x62, 0x5b}, | ||||||
|  |     {0x8d, 0x5e, 0x27, 0xbc, 0x14, 0x4f, 0x08, 0xa8, 0x2b, 0x14, 0x89, 0x5e, 0xdf, 0x77, 0x04, 0x31}, | ||||||
|  |     {0xc9, 0xf7, 0x03, 0xf1, 0x6c, 0x65, 0xad, 0x49, 0x74, 0xbe, 0x00, 0x54, 0xfd, 0xa6, 0x9c, 0x32}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| void furi_hal_crypto_init() { | void furi_hal_crypto_init() { | ||||||
|     FURI_LOG_I(TAG, "Init OK"); |     FURI_LOG_I(TAG, "Init OK"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool furi_hal_crypto_generate_unique_keys(uint8_t start_slot, uint8_t end_slot) { | ||||||
|  |     FuriHalCryptoKey key; | ||||||
|  |     uint8_t key_data[32]; | ||||||
|  |     FURI_LOG_I(TAG, "Generating keys %u..%u", start_slot, end_slot); | ||||||
|  |     for (uint8_t slot = start_slot; slot <= end_slot; slot++) { | ||||||
|  |         key.type = FuriHalCryptoKeyTypeSimple; | ||||||
|  |         key.size = FuriHalCryptoKeySize256; | ||||||
|  |         key.data = key_data; | ||||||
|  |         furi_hal_random_fill_buf(key_data, 32); | ||||||
|  |         if (!furi_hal_crypto_store_add_key(&key, &slot)) { | ||||||
|  |             FURI_LOG_E(TAG, "Error writing key to slot %u", slot); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool furi_hal_crypto_verify_key(uint8_t key_slot) { | ||||||
|  |     uint8_t keys_nb = 0; | ||||||
|  |     uint8_t valid_keys_nb = 0; | ||||||
|  |     uint8_t last_valid_slot = ENCLAVE_FACTORY_KEY_SLOTS; | ||||||
|  |     uint8_t empty_iv[16]; | ||||||
|  |     furi_hal_crypto_verify_enclave(&keys_nb, &valid_keys_nb); | ||||||
|  |     if (key_slot <= ENCLAVE_FACTORY_KEY_SLOTS) { // It's a factory key
 | ||||||
|  |         if (key_slot > keys_nb) | ||||||
|  |             return false; | ||||||
|  |     } else { // Unique key
 | ||||||
|  |         if (keys_nb < ENCLAVE_FACTORY_KEY_SLOTS) // Some factory keys are missing
 | ||||||
|  |             return false; | ||||||
|  |         for (uint8_t i = key_slot; i > ENCLAVE_FACTORY_KEY_SLOTS; i--) { | ||||||
|  |             if(furi_hal_crypto_store_load_key(i, empty_iv)) { | ||||||
|  |                 last_valid_slot = i; | ||||||
|  |                 furi_hal_crypto_store_unload_key(i); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (last_valid_slot == key_slot) | ||||||
|  |             return true; | ||||||
|  |         else // Generate missing unique keys
 | ||||||
|  |             return furi_hal_crypto_generate_unique_keys(last_valid_slot+1, key_slot); | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool furi_hal_crypto_verify_enclave(uint8_t* keys_nb, uint8_t* valid_keys_nb) { | ||||||
|  |     furi_assert(keys_nb); | ||||||
|  |     furi_assert(valid_keys_nb); | ||||||
|  |     uint8_t keys = 0; | ||||||
|  |     uint8_t keys_valid = 0; | ||||||
|  |     uint8_t buffer[ENCLAVE_SIGNATURE_SIZE]; | ||||||
|  |     for(size_t key_slot = 0; key_slot < ENCLAVE_FACTORY_KEY_SLOTS; key_slot++) { | ||||||
|  |         if(furi_hal_crypto_store_load_key(key_slot + 1, enclave_signature_iv[key_slot])) { | ||||||
|  |             keys++; | ||||||
|  |             if(furi_hal_crypto_encrypt(enclave_signature_input[key_slot], buffer, ENCLAVE_SIGNATURE_SIZE)) { | ||||||
|  |                 keys_valid += memcmp(buffer, enclave_signature_expected[key_slot], ENCLAVE_SIGNATURE_SIZE) == 0; | ||||||
|  |             } | ||||||
|  |             furi_hal_crypto_store_unload_key(key_slot + 1); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     *keys_nb = keys; | ||||||
|  |     *valid_keys_nb = keys_valid; | ||||||
|  |     if (*valid_keys_nb == ENCLAVE_FACTORY_KEY_SLOTS) | ||||||
|  |         return true; | ||||||
|  |     else | ||||||
|  |         return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) { | bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) { | ||||||
|     furi_assert(key); |     furi_assert(key); | ||||||
|     furi_assert(slot); |     furi_assert(slot); | ||||||
|  | |||||||
| @ -2,48 +2,6 @@ | |||||||
| #include <furi-hal.h> | #include <furi-hal.h> | ||||||
| #include <shci.h> | #include <shci.h> | ||||||
| 
 | 
 | ||||||
| #define ENCLAVE_SIGNATURE_KEY_SLOTS 10 |  | ||||||
| #define ENCLAVE_SIGNATURE_SIZE 16 |  | ||||||
| 
 |  | ||||||
| static const uint8_t enclave_signature_iv[ENCLAVE_SIGNATURE_KEY_SLOTS][16] = { |  | ||||||
|     {0xac, 0x5d, 0x68, 0xb8, 0x79, 0x74, 0xfc, 0x7f, 0x45, 0x02, 0x82, 0xf1, 0x48, 0x7e, 0x75, 0x8a}, |  | ||||||
|     {0x38, 0xe6, 0x6a, 0x90, 0x5e, 0x5b, 0x8a, 0xa6, 0x70, 0x30, 0x04, 0x72, 0xc2, 0x42, 0xea, 0xaf}, |  | ||||||
|     {0x73, 0xd5, 0x8e, 0xfb, 0x0f, 0x4b, 0xa9, 0x79, 0x0f, 0xde, 0x0e, 0x53, 0x44, 0x7d, 0xaa, 0xfd}, |  | ||||||
|     {0x3c, 0x9a, 0xf4, 0x43, 0x2b, 0xfe, 0xea, 0xae, 0x8c, 0xc6, 0xd1, 0x60, 0xd2, 0x96, 0x64, 0xa9}, |  | ||||||
|     {0x10, 0xac, 0x7b, 0x63, 0x03, 0x7f, 0x43, 0x18, 0xec, 0x9d, 0x9c, 0xc4, 0x01, 0xdc, 0x35, 0xa7}, |  | ||||||
|     {0x26, 0x21, 0x64, 0xe6, 0xd0, 0xf2, 0x47, 0x49, 0xdc, 0x36, 0xcd, 0x68, 0x0c, 0x91, 0x03, 0x44}, |  | ||||||
|     {0x7a, 0xbd, 0xce, 0x9c, 0x24, 0x7a, 0x2a, 0xb1, 0x3c, 0x4f, 0x5a, 0x7d, 0x80, 0x3e, 0xfc, 0x0d}, |  | ||||||
|     {0xcd, 0xdd, 0xd3, 0x02, 0x85, 0x65, 0x43, 0x83, 0xf9, 0xac, 0x75, 0x2f, 0x21, 0xef, 0x28, 0x6b}, |  | ||||||
|     {0xab, 0x73, 0x70, 0xe8, 0xe2, 0x56, 0x0f, 0x58, 0xab, 0x29, 0xa5, 0xb1, 0x13, 0x47, 0x5e, 0xe8}, |  | ||||||
|     {0x4f, 0x3c, 0x43, 0x77, 0xde, 0xed, 0x79, 0xa1, 0x8d, 0x4c, 0x1f, 0xfd, 0xdb, 0x96, 0x87, 0x2e}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const uint8_t enclave_signature_input[ENCLAVE_SIGNATURE_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = { |  | ||||||
|     {0x9f, 0x5c, 0xb1, 0x43, 0x17, 0x53, 0x18, 0x8c, 0x66, 0x3d, 0x39, 0x45, 0x90, 0x13, 0xa9, 0xde}, |  | ||||||
|     {0xc5, 0x98, 0xe9, 0x17, 0xb8, 0x97, 0x9e, 0x03, 0x33, 0x14, 0x13, 0x8f, 0xce, 0x74, 0x0d, 0x54}, |  | ||||||
|     {0x34, 0xba, 0x99, 0x59, 0x9f, 0x70, 0x67, 0xe9, 0x09, 0xee, 0x64, 0x0e, 0xb3, 0xba, 0xfb, 0x75}, |  | ||||||
|     {0xdc, 0xfa, 0x6c, 0x9a, 0x6f, 0x0a, 0x3e, 0xdc, 0x42, 0xf6, 0xae, 0x0d, 0x3c, 0xf7, 0x83, 0xaf}, |  | ||||||
|     {0xea, 0x2d, 0xe3, 0x1f, 0x02, 0x99, 0x1a, 0x7e, 0x6d, 0x93, 0x4c, 0xb5, 0x42, 0xf0, 0x7a, 0x9b}, |  | ||||||
|     {0x53, 0x5e, 0x04, 0xa2, 0x49, 0xa0, 0x73, 0x49, 0x56, 0xb0, 0x88, 0x8c, 0x12, 0xa0, 0xe4, 0x18}, |  | ||||||
|     {0x7d, 0xa7, 0xc5, 0x21, 0x7f, 0x12, 0x95, 0xdd, 0x4d, 0x77, 0x01, 0xfa, 0x71, 0x88, 0x2b, 0x7f}, |  | ||||||
|     {0xdc, 0x9b, 0xc5, 0xa7, 0x6b, 0x84, 0x5c, 0x37, 0x7c, 0xec, 0x05, 0xa1, 0x9f, 0x91, 0x17, 0x3b}, |  | ||||||
|     {0xea, 0xcf, 0xd9, 0x9b, 0x86, 0xcd, 0x2b, 0x43, 0x54, 0x45, 0x82, 0xc6, 0xfe, 0x73, 0x1a, 0x1a}, |  | ||||||
|     {0x77, 0xb8, 0x1b, 0x90, 0xb4, 0xb7, 0x32, 0x76, 0x8f, 0x8a, 0x57, 0x06, 0xc7, 0xdd, 0x08, 0x90}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const uint8_t enclave_signature_expected[ENCLAVE_SIGNATURE_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = { |  | ||||||
|     {0xe9, 0x9a, 0xce, 0xe9, 0x4d, 0xe1, 0x7f, 0x55, 0xcb, 0x8a, 0xbf, 0xf2, 0x4d, 0x98, 0x27, 0x67}, |  | ||||||
|     {0x34, 0x27, 0xa7, 0xea, 0xa8, 0x98, 0x66, 0x9b, 0xed, 0x43, 0xd3, 0x93, 0xb5, 0xa2, 0x87, 0x8e}, |  | ||||||
|     {0x6c, 0xf3, 0x01, 0x78, 0x53, 0x1b, 0x11, 0x32, 0xf0, 0x27, 0x2f, 0xe3, 0x7d, 0xa6, 0xe2, 0xfd}, |  | ||||||
|     {0xdf, 0x7f, 0x37, 0x65, 0x2f, 0xdb, 0x7c, 0xcf, 0x5b, 0xb6, 0xe4, 0x9c, 0x63, 0xc5, 0x0f, 0xe0}, |  | ||||||
|     {0x9b, 0x5c, 0xee, 0x44, 0x0e, 0xd1, 0xcb, 0x5f, 0x28, 0x9f, 0x12, 0x17, 0x59, 0x64, 0x40, 0xbb}, |  | ||||||
|     {0x94, 0xc2, 0x09, 0x98, 0x62, 0xa7, 0x2b, 0x93, 0xed, 0x36, 0x1f, 0x10, 0xbc, 0x26, 0xbd, 0x41}, |  | ||||||
|     {0x4d, 0xb2, 0x2b, 0xc5, 0x96, 0x47, 0x61, 0xf4, 0x16, 0xe0, 0x81, 0xc3, 0x8e, 0xb9, 0x9c, 0x9b}, |  | ||||||
|     {0xc3, 0x6b, 0x83, 0x55, 0x90, 0x38, 0x0f, 0xea, 0xd1, 0x65, 0xbf, 0x32, 0x4f, 0x8e, 0x62, 0x5b}, |  | ||||||
|     {0x8d, 0x5e, 0x27, 0xbc, 0x14, 0x4f, 0x08, 0xa8, 0x2b, 0x14, 0x89, 0x5e, 0xdf, 0x77, 0x04, 0x31}, |  | ||||||
|     {0xc9, 0xf7, 0x03, 0xf1, 0x6c, 0x65, 0xad, 0x49, 0x74, 0xbe, 0x00, 0x54, 0xfd, 0xa6, 0x9c, 0x32}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) { | void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) { | ||||||
|     string_t value; |     string_t value; | ||||||
|     string_init(value); |     string_init(value); | ||||||
| @ -164,23 +122,12 @@ void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) { | |||||||
|         out("radio_ble_mac", string_get_cstr(value), false, context); |         out("radio_ble_mac", string_get_cstr(value), false, context); | ||||||
| 
 | 
 | ||||||
|         // Signature verification
 |         // Signature verification
 | ||||||
|         uint8_t buffer[ENCLAVE_SIGNATURE_SIZE]; |         uint8_t enclave_keys = 0; | ||||||
|         size_t enclave_valid_keys = 0; |         uint8_t enclave_valid_keys = 0; | ||||||
|         for(size_t key_slot = 0; key_slot < ENCLAVE_SIGNATURE_KEY_SLOTS; key_slot++) { |         bool enclave_valid = furi_hal_crypto_verify_enclave(&enclave_keys, &enclave_valid_keys); | ||||||
|             if(furi_hal_crypto_store_load_key(key_slot + 1, enclave_signature_iv[key_slot])) { |  | ||||||
|                 if(furi_hal_crypto_encrypt( |  | ||||||
|                        enclave_signature_input[key_slot], buffer, ENCLAVE_SIGNATURE_SIZE)) { |  | ||||||
|                     enclave_valid_keys += memcmp( |  | ||||||
|                                               buffer, |  | ||||||
|                                               enclave_signature_expected[key_slot], |  | ||||||
|                                               ENCLAVE_SIGNATURE_SIZE) == 0; |  | ||||||
|                 } |  | ||||||
|                 furi_hal_crypto_store_unload_key(key_slot + 1); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         string_printf(value, "%d", enclave_valid_keys); |         string_printf(value, "%d", enclave_valid_keys); | ||||||
|         out("enclave_valid_keys", string_get_cstr(value), false, context); |         out("enclave_valid_keys", string_get_cstr(value), false, context); | ||||||
|         out("enclave_valid", (enclave_valid_keys == ENCLAVE_SIGNATURE_KEY_SLOTS) ? "true" : "false", true, context); |         out("enclave_valid", enclave_valid ? "true" : "false", true, context); | ||||||
|     } else { |     } else { | ||||||
|         out("radio_alive", "false", true, context); |         out("radio_alive", "false", true, context); | ||||||
|     } |     } | ||||||
|  | |||||||
							
								
								
									
										56
									
								
								firmware/targets/f6/furi-hal/furi-hal-random.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								firmware/targets/f6/furi-hal/furi-hal-random.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | |||||||
|  | #include "furi-hal-random.h" | ||||||
|  | #include <furi.h> | ||||||
|  | #include <furi-hal.h> | ||||||
|  | 
 | ||||||
|  | #include <stm32wbxx_ll_rng.h> | ||||||
|  | #include <stm32wbxx_ll_hsem.h> | ||||||
|  | 
 | ||||||
|  | #include <hw_conf.h> | ||||||
|  | 
 | ||||||
|  | uint32_t furi_hal_random_get() { | ||||||
|  | 
 | ||||||
|  |     while( LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID)); | ||||||
|  |     LL_RNG_Enable(RNG); | ||||||
|  | 
 | ||||||
|  |     while (!LL_RNG_IsActiveFlag_DRDY(RNG)); | ||||||
|  | 
 | ||||||
|  |     if ((LL_RNG_IsActiveFlag_CECS(RNG)) || (LL_RNG_IsActiveFlag_SECS(RNG))) { | ||||||
|  |         furi_crash("TRNG error"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     uint32_t random_val = LL_RNG_ReadRandData32(RNG); | ||||||
|  | 
 | ||||||
|  |     LL_RNG_Disable(RNG); | ||||||
|  |     LL_HSEM_ReleaseLock(HSEM, CFG_HW_RNG_SEMID, 0); | ||||||
|  | 
 | ||||||
|  |     return random_val; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_random_fill_buf(uint8_t* buf, uint32_t len) { | ||||||
|  | 
 | ||||||
|  |     while( LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID)); | ||||||
|  |     LL_RNG_Enable(RNG); | ||||||
|  | 
 | ||||||
|  |     for (uint32_t i = 0; i < len; i+= 4) { | ||||||
|  |         while (!LL_RNG_IsActiveFlag_DRDY(RNG)); | ||||||
|  | 
 | ||||||
|  |         if ((LL_RNG_IsActiveFlag_CECS(RNG)) || (LL_RNG_IsActiveFlag_SECS(RNG))) { | ||||||
|  |             furi_crash("TRNG error"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         uint32_t random_val = LL_RNG_ReadRandData32(RNG); | ||||||
|  | 
 | ||||||
|  |         uint8_t len_cur = ((i+4) < len) ? (4) : (len-i); | ||||||
|  |         memcpy(&buf[i], &random_val, len_cur); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LL_RNG_Disable(RNG); | ||||||
|  |     LL_HSEM_ReleaseLock(HSEM, CFG_HW_RNG_SEMID, 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void srand(unsigned seed) { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int rand() { | ||||||
|  |     return (furi_hal_random_get() & RAND_MAX); | ||||||
|  | } | ||||||
							
								
								
									
										309
									
								
								firmware/targets/f6/furi-hal/furi-hal-usb-u2f.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										309
									
								
								firmware/targets/f6/furi-hal/furi-hal-usb-u2f.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,309 @@ | |||||||
|  | #include "furi-hal-version.h" | ||||||
|  | #include "furi-hal-usb_i.h" | ||||||
|  | #include "furi-hal-usb-hid-u2f.h" | ||||||
|  | #include "furi-hal-usb.h" | ||||||
|  | #include <furi.h> | ||||||
|  | #include "usb.h" | ||||||
|  | #include "usb_hid.h" | ||||||
|  | 
 | ||||||
|  | #define HID_PAGE_FIDO 0xF1D0 | ||||||
|  | #define HID_FIDO_U2F 0x01 | ||||||
|  | #define HID_FIDO_INPUT 0x20 | ||||||
|  | #define HID_FIDO_OUTPUT 0x21 | ||||||
|  | 
 | ||||||
|  | #define HID_EP_IN 0x81 | ||||||
|  | #define HID_EP_OUT 0x01 | ||||||
|  | 
 | ||||||
|  | struct HidIadDescriptor { | ||||||
|  |     struct usb_iad_descriptor hid_iad; | ||||||
|  |     struct usb_interface_descriptor hid; | ||||||
|  |     struct usb_hid_descriptor hid_desc; | ||||||
|  |     struct usb_endpoint_descriptor hid_ep_in; | ||||||
|  |     struct usb_endpoint_descriptor hid_ep_out; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct HidConfigDescriptor { | ||||||
|  |     struct usb_config_descriptor config; | ||||||
|  |     struct HidIadDescriptor iad_0; | ||||||
|  | } __attribute__((packed)); | ||||||
|  | 
 | ||||||
|  | /* HID report: FIDO U2F */ | ||||||
|  | static const uint8_t hid_u2f_report_desc[] = { | ||||||
|  |     HID_RI_USAGE_PAGE(16, HID_PAGE_FIDO), | ||||||
|  |     HID_USAGE(HID_FIDO_U2F), | ||||||
|  |     HID_COLLECTION(HID_APPLICATION_COLLECTION), | ||||||
|  |     HID_USAGE(HID_FIDO_INPUT), | ||||||
|  |     HID_LOGICAL_MINIMUM(0x00), | ||||||
|  |     HID_LOGICAL_MAXIMUM(0xFF), | ||||||
|  |     HID_REPORT_SIZE(8), | ||||||
|  |     HID_REPORT_COUNT(HID_U2F_PACKET_LEN), | ||||||
|  |     HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), | ||||||
|  |     HID_USAGE(HID_FIDO_OUTPUT), | ||||||
|  |     HID_LOGICAL_MINIMUM(0x00), | ||||||
|  |     HID_LOGICAL_MAXIMUM(0xFF), | ||||||
|  |     HID_REPORT_SIZE(8), | ||||||
|  |     HID_REPORT_COUNT(HID_U2F_PACKET_LEN), | ||||||
|  |     HID_OUTPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), | ||||||
|  |     HID_END_COLLECTION, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Flipper Devices Inc."); | ||||||
|  | static const struct usb_string_descriptor dev_prod_desc = USB_STRING_DESC("U2F Token test"); | ||||||
|  | static const struct usb_string_descriptor dev_serial_desc = USB_STRING_DESC("TODO: serial"); | ||||||
|  | 
 | ||||||
|  | /* Device descriptor */ | ||||||
|  | static const struct usb_device_descriptor hid_u2f_device_desc = { | ||||||
|  |     .bLength = sizeof(struct usb_device_descriptor), | ||||||
|  |     .bDescriptorType = USB_DTYPE_DEVICE, | ||||||
|  |     .bcdUSB = VERSION_BCD(2, 0, 0), | ||||||
|  |     .bDeviceClass = USB_CLASS_IAD, | ||||||
|  |     .bDeviceSubClass = USB_SUBCLASS_IAD, | ||||||
|  |     .bDeviceProtocol = USB_PROTO_IAD, | ||||||
|  |     .bMaxPacketSize0 = USB_EP0_SIZE, | ||||||
|  |     .idVendor = 0x0483, | ||||||
|  |     .idProduct = 0x5741, | ||||||
|  |     .bcdDevice = VERSION_BCD(1, 0, 0), | ||||||
|  |     .iManufacturer = UsbDevManuf, | ||||||
|  |     .iProduct = UsbDevProduct, | ||||||
|  |     .iSerialNumber = UsbDevSerial, | ||||||
|  |     .bNumConfigurations = 1, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Device configuration descriptor */ | ||||||
|  | static const struct HidConfigDescriptor hid_u2f_cfg_desc = { | ||||||
|  |     .config = | ||||||
|  |         { | ||||||
|  |             .bLength = sizeof(struct usb_config_descriptor), | ||||||
|  |             .bDescriptorType = USB_DTYPE_CONFIGURATION, | ||||||
|  |             .wTotalLength = sizeof(struct HidConfigDescriptor), | ||||||
|  |             .bNumInterfaces = 1, | ||||||
|  |             .bConfigurationValue = 1, | ||||||
|  |             .iConfiguration = NO_DESCRIPTOR, | ||||||
|  |             .bmAttributes = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED, | ||||||
|  |             .bMaxPower = USB_CFG_POWER_MA(100), | ||||||
|  |         }, | ||||||
|  |     .iad_0 = | ||||||
|  |         { | ||||||
|  |             .hid_iad = | ||||||
|  |                 { | ||||||
|  |                     .bLength = sizeof(struct usb_iad_descriptor), | ||||||
|  |                     .bDescriptorType = USB_DTYPE_INTERFASEASSOC, | ||||||
|  |                     .bFirstInterface = 0, | ||||||
|  |                     .bInterfaceCount = 1, | ||||||
|  |                     .bFunctionClass = USB_CLASS_PER_INTERFACE, | ||||||
|  |                     .bFunctionSubClass = USB_SUBCLASS_NONE, | ||||||
|  |                     .bFunctionProtocol = USB_PROTO_NONE, | ||||||
|  |                     .iFunction = NO_DESCRIPTOR, | ||||||
|  |                 }, | ||||||
|  |             .hid = | ||||||
|  |                 { | ||||||
|  |                     .bLength = sizeof(struct usb_interface_descriptor), | ||||||
|  |                     .bDescriptorType = USB_DTYPE_INTERFACE, | ||||||
|  |                     .bInterfaceNumber = 0, | ||||||
|  |                     .bAlternateSetting = 0, | ||||||
|  |                     .bNumEndpoints = 2, | ||||||
|  |                     .bInterfaceClass = USB_CLASS_HID, | ||||||
|  |                     .bInterfaceSubClass = USB_HID_SUBCLASS_NONBOOT, | ||||||
|  |                     .bInterfaceProtocol = USB_HID_PROTO_NONBOOT, | ||||||
|  |                     .iInterface = NO_DESCRIPTOR, | ||||||
|  |                 }, | ||||||
|  |             .hid_desc = | ||||||
|  |                 { | ||||||
|  |                     .bLength = sizeof(struct usb_hid_descriptor), | ||||||
|  |                     .bDescriptorType = USB_DTYPE_HID, | ||||||
|  |                     .bcdHID = VERSION_BCD(1, 0, 0), | ||||||
|  |                     .bCountryCode = USB_HID_COUNTRY_NONE, | ||||||
|  |                     .bNumDescriptors = 1, | ||||||
|  |                     .bDescriptorType0 = USB_DTYPE_HID_REPORT, | ||||||
|  |                     .wDescriptorLength0 = sizeof(hid_u2f_report_desc), | ||||||
|  |                 }, | ||||||
|  |             .hid_ep_in = | ||||||
|  |                 { | ||||||
|  |                     .bLength = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |                     .bDescriptorType = USB_DTYPE_ENDPOINT, | ||||||
|  |                     .bEndpointAddress = HID_EP_IN, | ||||||
|  |                     .bmAttributes = USB_EPTYPE_INTERRUPT, | ||||||
|  |                     .wMaxPacketSize = HID_U2F_PACKET_LEN, | ||||||
|  |                     .bInterval = 5, | ||||||
|  |                 }, | ||||||
|  |             .hid_ep_out = | ||||||
|  |                 { | ||||||
|  |                     .bLength = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |                     .bDescriptorType = USB_DTYPE_ENDPOINT, | ||||||
|  |                     .bEndpointAddress = HID_EP_OUT, | ||||||
|  |                     .bmAttributes = USB_EPTYPE_INTERRUPT, | ||||||
|  |                     .wMaxPacketSize = HID_U2F_PACKET_LEN, | ||||||
|  |                     .bInterval = 5, | ||||||
|  |                 }, | ||||||
|  |         }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void hid_u2f_init(usbd_device* dev, UsbInterface* intf); | ||||||
|  | static void hid_u2f_deinit(usbd_device* dev); | ||||||
|  | static void hid_u2f_on_wakeup(usbd_device* dev); | ||||||
|  | static void hid_u2f_on_suspend(usbd_device* dev); | ||||||
|  | 
 | ||||||
|  | //static bool hid_u2f_send_report(uint8_t report_id);
 | ||||||
|  | static usbd_respond hid_u2f_ep_config(usbd_device* dev, uint8_t cfg); | ||||||
|  | static usbd_respond | ||||||
|  |     hid_u2f_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback); | ||||||
|  | static usbd_device* usb_dev; | ||||||
|  | static osSemaphoreId_t hid_u2f_semaphore = NULL; | ||||||
|  | static bool hid_u2f_connected = false; | ||||||
|  | 
 | ||||||
|  | static HidU2fCallback callback; | ||||||
|  | static void* cb_ctx; | ||||||
|  | 
 | ||||||
|  | bool furi_hal_hid_u2f_is_connected() { | ||||||
|  |     return hid_u2f_connected; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_hid_u2f_set_callback(HidU2fCallback cb, void* ctx) { | ||||||
|  |     if (callback != NULL) { | ||||||
|  |         if (hid_u2f_connected == true) | ||||||
|  |             callback(HidU2fDisconnected, cb_ctx); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     callback = cb; | ||||||
|  |     cb_ctx = ctx; | ||||||
|  | 
 | ||||||
|  |     if (callback != NULL) { | ||||||
|  |         if (hid_u2f_connected == true) | ||||||
|  |             callback(HidU2fConnected, cb_ctx); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | UsbInterface usb_hid_u2f = { | ||||||
|  |     .init = hid_u2f_init, | ||||||
|  |     .deinit = hid_u2f_deinit, | ||||||
|  |     .wakeup = hid_u2f_on_wakeup, | ||||||
|  |     .suspend = hid_u2f_on_suspend, | ||||||
|  | 
 | ||||||
|  |     .dev_descr = (struct usb_device_descriptor*)&hid_u2f_device_desc, | ||||||
|  | 
 | ||||||
|  |     .str_manuf_descr = (void*)&dev_manuf_desc, | ||||||
|  |     .str_prod_descr = (void*)&dev_prod_desc, | ||||||
|  |     .str_serial_descr = (void*)&dev_serial_desc, | ||||||
|  | 
 | ||||||
|  |     .cfg_descr = (void*)&hid_u2f_cfg_desc, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void hid_u2f_init(usbd_device* dev, UsbInterface* intf) { | ||||||
|  |     if(hid_u2f_semaphore == NULL) hid_u2f_semaphore = osSemaphoreNew(1, 1, NULL); | ||||||
|  |     usb_dev = dev; | ||||||
|  | 
 | ||||||
|  |     usbd_reg_config(dev, hid_u2f_ep_config); | ||||||
|  |     usbd_reg_control(dev, hid_u2f_control); | ||||||
|  | 
 | ||||||
|  |     usbd_connect(dev, true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_u2f_deinit(usbd_device* dev) { | ||||||
|  |     usbd_reg_config(dev, NULL); | ||||||
|  |     usbd_reg_control(dev, NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_u2f_on_wakeup(usbd_device* dev) { | ||||||
|  |     hid_u2f_connected = true; | ||||||
|  |     if (callback != NULL) | ||||||
|  |         callback(HidU2fConnected, cb_ctx); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_u2f_on_suspend(usbd_device* dev) { | ||||||
|  |     if(hid_u2f_connected == true) { | ||||||
|  |         hid_u2f_connected = false; | ||||||
|  |         osSemaphoreRelease(hid_u2f_semaphore); | ||||||
|  |         if (callback != NULL) | ||||||
|  |             callback(HidU2fDisconnected, cb_ctx); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_hid_u2f_send_response(uint8_t* data, uint8_t len) { | ||||||
|  |     if ((hid_u2f_semaphore == NULL) || (hid_u2f_connected == false)) | ||||||
|  |         return; | ||||||
|  |     furi_check(osSemaphoreAcquire(hid_u2f_semaphore, osWaitForever) == osOK); | ||||||
|  |     if (hid_u2f_connected == true) { | ||||||
|  |         usbd_ep_write(usb_dev, HID_EP_OUT, data, len); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint32_t furi_hal_hid_u2f_get_request(uint8_t* data) { | ||||||
|  |     int32_t len = usbd_ep_read(usb_dev, HID_EP_IN, data, HID_U2F_PACKET_LEN); | ||||||
|  |     return ((len < 0) ? 0 : len); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_u2f_rx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     if (callback != NULL) | ||||||
|  |         callback(HidU2fRequest, cb_ctx); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_u2f_tx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     osSemaphoreRelease(hid_u2f_semaphore); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_u2f_txrx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     if (event == usbd_evt_eptx) { | ||||||
|  |         hid_u2f_tx_ep_callback(dev, event, ep); | ||||||
|  |     } else { | ||||||
|  |         hid_u2f_rx_ep_callback(dev, event, ep); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Configure endpoints */ | ||||||
|  | static usbd_respond hid_u2f_ep_config(usbd_device* dev, uint8_t cfg) { | ||||||
|  |     switch(cfg) { | ||||||
|  |     case 0: | ||||||
|  |         /* deconfiguring device */ | ||||||
|  |         usbd_ep_deconfig(dev, HID_EP_IN); | ||||||
|  |         usbd_ep_deconfig(dev, HID_EP_OUT); | ||||||
|  |         usbd_reg_endpoint(dev, HID_EP_IN, 0); | ||||||
|  |         usbd_reg_endpoint(dev, HID_EP_OUT, 0); | ||||||
|  |         return usbd_ack; | ||||||
|  |     case 1: | ||||||
|  |         /* configuring device */ | ||||||
|  |         usbd_ep_config(dev, HID_EP_IN, USB_EPTYPE_INTERRUPT, HID_U2F_PACKET_LEN); | ||||||
|  |         usbd_ep_config(dev, HID_EP_OUT, USB_EPTYPE_INTERRUPT, HID_U2F_PACKET_LEN); | ||||||
|  |         usbd_reg_endpoint(dev, HID_EP_IN, hid_u2f_txrx_ep_callback); | ||||||
|  |         usbd_reg_endpoint(dev, HID_EP_OUT, hid_u2f_txrx_ep_callback); | ||||||
|  |         usbd_ep_write(dev, HID_U2F_PACKET_LEN, 0, 0); | ||||||
|  |         return usbd_ack; | ||||||
|  |     default: | ||||||
|  |         return usbd_fail; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Control requests handler */ | ||||||
|  | static usbd_respond hid_u2f_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback) { | ||||||
|  |     /* HID control requests */ | ||||||
|  |     if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == | ||||||
|  |            (USB_REQ_INTERFACE | USB_REQ_CLASS) && | ||||||
|  |        req->wIndex == 0) { | ||||||
|  |         switch(req->bRequest) { | ||||||
|  |         case USB_HID_SETIDLE: | ||||||
|  |             return usbd_ack; | ||||||
|  |         case USB_HID_GETREPORT: | ||||||
|  |             // dev->status.data_ptr = &hid_u2f_report;
 | ||||||
|  |             // dev->status.data_count = sizeof(hid_u2f_report);
 | ||||||
|  |             return usbd_ack; | ||||||
|  |         default: | ||||||
|  |             return usbd_fail; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == | ||||||
|  |            (USB_REQ_INTERFACE | USB_REQ_STANDARD) && | ||||||
|  |        req->wIndex == 0 && req->bRequest == USB_STD_GET_DESCRIPTOR) { | ||||||
|  |         switch(req->wValue >> 8) { | ||||||
|  |         case USB_DTYPE_HID: | ||||||
|  |             dev->status.data_ptr = (uint8_t*)&(hid_u2f_cfg_desc.iad_0.hid_desc); | ||||||
|  |             dev->status.data_count = sizeof(hid_u2f_cfg_desc.iad_0.hid_desc); | ||||||
|  |             return usbd_ack; | ||||||
|  |         case USB_DTYPE_HID_REPORT: | ||||||
|  |             dev->status.data_ptr = (uint8_t*)hid_u2f_report_desc; | ||||||
|  |             dev->status.data_count = sizeof(hid_u2f_report_desc); | ||||||
|  |             return usbd_ack; | ||||||
|  |         default: | ||||||
|  |             return usbd_fail; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return usbd_fail; | ||||||
|  | } | ||||||
| @ -71,7 +71,8 @@ C_SOURCES += \ | |||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_tim.c \
 | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_tim.c \
 | ||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usart.c \
 | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usart.c \
 | ||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_lpuart.c \
 | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_lpuart.c \
 | ||||||
| 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c \
 | ||||||
|  | 	$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_rng.c | ||||||
| 
 | 
 | ||||||
| # FreeRTOS
 | # FreeRTOS
 | ||||||
| CFLAGS += \
 | CFLAGS += \
 | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| #include <furi-hal-crypto.h> | #include <furi-hal-crypto.h> | ||||||
| #include <furi-hal-bt.h> | #include <furi-hal-bt.h> | ||||||
|  | #include <furi-hal-random.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <shci.h> | #include <shci.h> | ||||||
| 
 | 
 | ||||||
| @ -7,10 +8,119 @@ | |||||||
| 
 | 
 | ||||||
| CRYP_HandleTypeDef crypt; | CRYP_HandleTypeDef crypt; | ||||||
| 
 | 
 | ||||||
|  | #define ENCLAVE_FACTORY_KEY_SLOTS 10 | ||||||
|  | #define ENCLAVE_SIGNATURE_SIZE 16 | ||||||
|  | 
 | ||||||
|  | static const uint8_t enclave_signature_iv[ENCLAVE_FACTORY_KEY_SLOTS][16] = { | ||||||
|  |     {0xac, 0x5d, 0x68, 0xb8, 0x79, 0x74, 0xfc, 0x7f, 0x45, 0x02, 0x82, 0xf1, 0x48, 0x7e, 0x75, 0x8a}, | ||||||
|  |     {0x38, 0xe6, 0x6a, 0x90, 0x5e, 0x5b, 0x8a, 0xa6, 0x70, 0x30, 0x04, 0x72, 0xc2, 0x42, 0xea, 0xaf}, | ||||||
|  |     {0x73, 0xd5, 0x8e, 0xfb, 0x0f, 0x4b, 0xa9, 0x79, 0x0f, 0xde, 0x0e, 0x53, 0x44, 0x7d, 0xaa, 0xfd}, | ||||||
|  |     {0x3c, 0x9a, 0xf4, 0x43, 0x2b, 0xfe, 0xea, 0xae, 0x8c, 0xc6, 0xd1, 0x60, 0xd2, 0x96, 0x64, 0xa9}, | ||||||
|  |     {0x10, 0xac, 0x7b, 0x63, 0x03, 0x7f, 0x43, 0x18, 0xec, 0x9d, 0x9c, 0xc4, 0x01, 0xdc, 0x35, 0xa7}, | ||||||
|  |     {0x26, 0x21, 0x64, 0xe6, 0xd0, 0xf2, 0x47, 0x49, 0xdc, 0x36, 0xcd, 0x68, 0x0c, 0x91, 0x03, 0x44}, | ||||||
|  |     {0x7a, 0xbd, 0xce, 0x9c, 0x24, 0x7a, 0x2a, 0xb1, 0x3c, 0x4f, 0x5a, 0x7d, 0x80, 0x3e, 0xfc, 0x0d}, | ||||||
|  |     {0xcd, 0xdd, 0xd3, 0x02, 0x85, 0x65, 0x43, 0x83, 0xf9, 0xac, 0x75, 0x2f, 0x21, 0xef, 0x28, 0x6b}, | ||||||
|  |     {0xab, 0x73, 0x70, 0xe8, 0xe2, 0x56, 0x0f, 0x58, 0xab, 0x29, 0xa5, 0xb1, 0x13, 0x47, 0x5e, 0xe8}, | ||||||
|  |     {0x4f, 0x3c, 0x43, 0x77, 0xde, 0xed, 0x79, 0xa1, 0x8d, 0x4c, 0x1f, 0xfd, 0xdb, 0x96, 0x87, 0x2e}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const uint8_t enclave_signature_input[ENCLAVE_FACTORY_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = { | ||||||
|  |     {0x9f, 0x5c, 0xb1, 0x43, 0x17, 0x53, 0x18, 0x8c, 0x66, 0x3d, 0x39, 0x45, 0x90, 0x13, 0xa9, 0xde}, | ||||||
|  |     {0xc5, 0x98, 0xe9, 0x17, 0xb8, 0x97, 0x9e, 0x03, 0x33, 0x14, 0x13, 0x8f, 0xce, 0x74, 0x0d, 0x54}, | ||||||
|  |     {0x34, 0xba, 0x99, 0x59, 0x9f, 0x70, 0x67, 0xe9, 0x09, 0xee, 0x64, 0x0e, 0xb3, 0xba, 0xfb, 0x75}, | ||||||
|  |     {0xdc, 0xfa, 0x6c, 0x9a, 0x6f, 0x0a, 0x3e, 0xdc, 0x42, 0xf6, 0xae, 0x0d, 0x3c, 0xf7, 0x83, 0xaf}, | ||||||
|  |     {0xea, 0x2d, 0xe3, 0x1f, 0x02, 0x99, 0x1a, 0x7e, 0x6d, 0x93, 0x4c, 0xb5, 0x42, 0xf0, 0x7a, 0x9b}, | ||||||
|  |     {0x53, 0x5e, 0x04, 0xa2, 0x49, 0xa0, 0x73, 0x49, 0x56, 0xb0, 0x88, 0x8c, 0x12, 0xa0, 0xe4, 0x18}, | ||||||
|  |     {0x7d, 0xa7, 0xc5, 0x21, 0x7f, 0x12, 0x95, 0xdd, 0x4d, 0x77, 0x01, 0xfa, 0x71, 0x88, 0x2b, 0x7f}, | ||||||
|  |     {0xdc, 0x9b, 0xc5, 0xa7, 0x6b, 0x84, 0x5c, 0x37, 0x7c, 0xec, 0x05, 0xa1, 0x9f, 0x91, 0x17, 0x3b}, | ||||||
|  |     {0xea, 0xcf, 0xd9, 0x9b, 0x86, 0xcd, 0x2b, 0x43, 0x54, 0x45, 0x82, 0xc6, 0xfe, 0x73, 0x1a, 0x1a}, | ||||||
|  |     {0x77, 0xb8, 0x1b, 0x90, 0xb4, 0xb7, 0x32, 0x76, 0x8f, 0x8a, 0x57, 0x06, 0xc7, 0xdd, 0x08, 0x90}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const uint8_t enclave_signature_expected[ENCLAVE_FACTORY_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = { | ||||||
|  |     {0xe9, 0x9a, 0xce, 0xe9, 0x4d, 0xe1, 0x7f, 0x55, 0xcb, 0x8a, 0xbf, 0xf2, 0x4d, 0x98, 0x27, 0x67}, | ||||||
|  |     {0x34, 0x27, 0xa7, 0xea, 0xa8, 0x98, 0x66, 0x9b, 0xed, 0x43, 0xd3, 0x93, 0xb5, 0xa2, 0x87, 0x8e}, | ||||||
|  |     {0x6c, 0xf3, 0x01, 0x78, 0x53, 0x1b, 0x11, 0x32, 0xf0, 0x27, 0x2f, 0xe3, 0x7d, 0xa6, 0xe2, 0xfd}, | ||||||
|  |     {0xdf, 0x7f, 0x37, 0x65, 0x2f, 0xdb, 0x7c, 0xcf, 0x5b, 0xb6, 0xe4, 0x9c, 0x63, 0xc5, 0x0f, 0xe0}, | ||||||
|  |     {0x9b, 0x5c, 0xee, 0x44, 0x0e, 0xd1, 0xcb, 0x5f, 0x28, 0x9f, 0x12, 0x17, 0x59, 0x64, 0x40, 0xbb}, | ||||||
|  |     {0x94, 0xc2, 0x09, 0x98, 0x62, 0xa7, 0x2b, 0x93, 0xed, 0x36, 0x1f, 0x10, 0xbc, 0x26, 0xbd, 0x41}, | ||||||
|  |     {0x4d, 0xb2, 0x2b, 0xc5, 0x96, 0x47, 0x61, 0xf4, 0x16, 0xe0, 0x81, 0xc3, 0x8e, 0xb9, 0x9c, 0x9b}, | ||||||
|  |     {0xc3, 0x6b, 0x83, 0x55, 0x90, 0x38, 0x0f, 0xea, 0xd1, 0x65, 0xbf, 0x32, 0x4f, 0x8e, 0x62, 0x5b}, | ||||||
|  |     {0x8d, 0x5e, 0x27, 0xbc, 0x14, 0x4f, 0x08, 0xa8, 0x2b, 0x14, 0x89, 0x5e, 0xdf, 0x77, 0x04, 0x31}, | ||||||
|  |     {0xc9, 0xf7, 0x03, 0xf1, 0x6c, 0x65, 0xad, 0x49, 0x74, 0xbe, 0x00, 0x54, 0xfd, 0xa6, 0x9c, 0x32}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| void furi_hal_crypto_init() { | void furi_hal_crypto_init() { | ||||||
|     FURI_LOG_I(TAG, "Init OK"); |     FURI_LOG_I(TAG, "Init OK"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool furi_hal_crypto_generate_unique_keys(uint8_t start_slot, uint8_t end_slot) { | ||||||
|  |     FuriHalCryptoKey key; | ||||||
|  |     uint8_t key_data[32]; | ||||||
|  |     FURI_LOG_I(TAG, "Generating keys %u..%u", start_slot, end_slot); | ||||||
|  |     for (uint8_t slot = start_slot; slot <= end_slot; slot++) { | ||||||
|  |         key.type = FuriHalCryptoKeyTypeSimple; | ||||||
|  |         key.size = FuriHalCryptoKeySize256; | ||||||
|  |         key.data = key_data; | ||||||
|  |         furi_hal_random_fill_buf(key_data, 32); | ||||||
|  |         if (!furi_hal_crypto_store_add_key(&key, &slot)) { | ||||||
|  |             FURI_LOG_E(TAG, "Error writing key to slot %u", slot); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool furi_hal_crypto_verify_key(uint8_t key_slot) { | ||||||
|  |     uint8_t keys_nb = 0; | ||||||
|  |     uint8_t valid_keys_nb = 0; | ||||||
|  |     uint8_t last_valid_slot = ENCLAVE_FACTORY_KEY_SLOTS; | ||||||
|  |     uint8_t empty_iv[16]; | ||||||
|  |     furi_hal_crypto_verify_enclave(&keys_nb, &valid_keys_nb); | ||||||
|  |     if (key_slot <= ENCLAVE_FACTORY_KEY_SLOTS) { // It's a factory key
 | ||||||
|  |         if (key_slot > keys_nb) | ||||||
|  |             return false; | ||||||
|  |     } else { // Unique key
 | ||||||
|  |         if (keys_nb < ENCLAVE_FACTORY_KEY_SLOTS) // Some factory keys are missing
 | ||||||
|  |             return false; | ||||||
|  |         for (uint8_t i = key_slot; i > ENCLAVE_FACTORY_KEY_SLOTS; i--) { | ||||||
|  |             if(furi_hal_crypto_store_load_key(i, empty_iv)) { | ||||||
|  |                 last_valid_slot = i; | ||||||
|  |                 furi_hal_crypto_store_unload_key(i); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (last_valid_slot == key_slot) | ||||||
|  |             return true; | ||||||
|  |         else // Generate missing unique keys
 | ||||||
|  |             return furi_hal_crypto_generate_unique_keys(last_valid_slot+1, key_slot); | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool furi_hal_crypto_verify_enclave(uint8_t* keys_nb, uint8_t* valid_keys_nb) { | ||||||
|  |     furi_assert(keys_nb); | ||||||
|  |     furi_assert(valid_keys_nb); | ||||||
|  |     uint8_t keys = 0; | ||||||
|  |     uint8_t keys_valid = 0; | ||||||
|  |     uint8_t buffer[ENCLAVE_SIGNATURE_SIZE]; | ||||||
|  |     for(size_t key_slot = 0; key_slot < ENCLAVE_FACTORY_KEY_SLOTS; key_slot++) { | ||||||
|  |         if(furi_hal_crypto_store_load_key(key_slot + 1, enclave_signature_iv[key_slot])) { | ||||||
|  |             keys++; | ||||||
|  |             if(furi_hal_crypto_encrypt(enclave_signature_input[key_slot], buffer, ENCLAVE_SIGNATURE_SIZE)) { | ||||||
|  |                 keys_valid += memcmp(buffer, enclave_signature_expected[key_slot], ENCLAVE_SIGNATURE_SIZE) == 0; | ||||||
|  |             } | ||||||
|  |             furi_hal_crypto_store_unload_key(key_slot + 1); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     *keys_nb = keys; | ||||||
|  |     *valid_keys_nb = keys_valid; | ||||||
|  |     if (*valid_keys_nb == ENCLAVE_FACTORY_KEY_SLOTS) | ||||||
|  |         return true; | ||||||
|  |     else | ||||||
|  |         return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) { | bool furi_hal_crypto_store_add_key(FuriHalCryptoKey* key, uint8_t* slot) { | ||||||
|     furi_assert(key); |     furi_assert(key); | ||||||
|     furi_assert(slot); |     furi_assert(slot); | ||||||
|  | |||||||
| @ -2,48 +2,6 @@ | |||||||
| #include <furi-hal.h> | #include <furi-hal.h> | ||||||
| #include <shci.h> | #include <shci.h> | ||||||
| 
 | 
 | ||||||
| #define ENCLAVE_SIGNATURE_KEY_SLOTS 10 |  | ||||||
| #define ENCLAVE_SIGNATURE_SIZE 16 |  | ||||||
| 
 |  | ||||||
| static const uint8_t enclave_signature_iv[ENCLAVE_SIGNATURE_KEY_SLOTS][16] = { |  | ||||||
|     {0xac, 0x5d, 0x68, 0xb8, 0x79, 0x74, 0xfc, 0x7f, 0x45, 0x02, 0x82, 0xf1, 0x48, 0x7e, 0x75, 0x8a}, |  | ||||||
|     {0x38, 0xe6, 0x6a, 0x90, 0x5e, 0x5b, 0x8a, 0xa6, 0x70, 0x30, 0x04, 0x72, 0xc2, 0x42, 0xea, 0xaf}, |  | ||||||
|     {0x73, 0xd5, 0x8e, 0xfb, 0x0f, 0x4b, 0xa9, 0x79, 0x0f, 0xde, 0x0e, 0x53, 0x44, 0x7d, 0xaa, 0xfd}, |  | ||||||
|     {0x3c, 0x9a, 0xf4, 0x43, 0x2b, 0xfe, 0xea, 0xae, 0x8c, 0xc6, 0xd1, 0x60, 0xd2, 0x96, 0x64, 0xa9}, |  | ||||||
|     {0x10, 0xac, 0x7b, 0x63, 0x03, 0x7f, 0x43, 0x18, 0xec, 0x9d, 0x9c, 0xc4, 0x01, 0xdc, 0x35, 0xa7}, |  | ||||||
|     {0x26, 0x21, 0x64, 0xe6, 0xd0, 0xf2, 0x47, 0x49, 0xdc, 0x36, 0xcd, 0x68, 0x0c, 0x91, 0x03, 0x44}, |  | ||||||
|     {0x7a, 0xbd, 0xce, 0x9c, 0x24, 0x7a, 0x2a, 0xb1, 0x3c, 0x4f, 0x5a, 0x7d, 0x80, 0x3e, 0xfc, 0x0d}, |  | ||||||
|     {0xcd, 0xdd, 0xd3, 0x02, 0x85, 0x65, 0x43, 0x83, 0xf9, 0xac, 0x75, 0x2f, 0x21, 0xef, 0x28, 0x6b}, |  | ||||||
|     {0xab, 0x73, 0x70, 0xe8, 0xe2, 0x56, 0x0f, 0x58, 0xab, 0x29, 0xa5, 0xb1, 0x13, 0x47, 0x5e, 0xe8}, |  | ||||||
|     {0x4f, 0x3c, 0x43, 0x77, 0xde, 0xed, 0x79, 0xa1, 0x8d, 0x4c, 0x1f, 0xfd, 0xdb, 0x96, 0x87, 0x2e}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const uint8_t enclave_signature_input[ENCLAVE_SIGNATURE_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = { |  | ||||||
|     {0x9f, 0x5c, 0xb1, 0x43, 0x17, 0x53, 0x18, 0x8c, 0x66, 0x3d, 0x39, 0x45, 0x90, 0x13, 0xa9, 0xde}, |  | ||||||
|     {0xc5, 0x98, 0xe9, 0x17, 0xb8, 0x97, 0x9e, 0x03, 0x33, 0x14, 0x13, 0x8f, 0xce, 0x74, 0x0d, 0x54}, |  | ||||||
|     {0x34, 0xba, 0x99, 0x59, 0x9f, 0x70, 0x67, 0xe9, 0x09, 0xee, 0x64, 0x0e, 0xb3, 0xba, 0xfb, 0x75}, |  | ||||||
|     {0xdc, 0xfa, 0x6c, 0x9a, 0x6f, 0x0a, 0x3e, 0xdc, 0x42, 0xf6, 0xae, 0x0d, 0x3c, 0xf7, 0x83, 0xaf}, |  | ||||||
|     {0xea, 0x2d, 0xe3, 0x1f, 0x02, 0x99, 0x1a, 0x7e, 0x6d, 0x93, 0x4c, 0xb5, 0x42, 0xf0, 0x7a, 0x9b}, |  | ||||||
|     {0x53, 0x5e, 0x04, 0xa2, 0x49, 0xa0, 0x73, 0x49, 0x56, 0xb0, 0x88, 0x8c, 0x12, 0xa0, 0xe4, 0x18}, |  | ||||||
|     {0x7d, 0xa7, 0xc5, 0x21, 0x7f, 0x12, 0x95, 0xdd, 0x4d, 0x77, 0x01, 0xfa, 0x71, 0x88, 0x2b, 0x7f}, |  | ||||||
|     {0xdc, 0x9b, 0xc5, 0xa7, 0x6b, 0x84, 0x5c, 0x37, 0x7c, 0xec, 0x05, 0xa1, 0x9f, 0x91, 0x17, 0x3b}, |  | ||||||
|     {0xea, 0xcf, 0xd9, 0x9b, 0x86, 0xcd, 0x2b, 0x43, 0x54, 0x45, 0x82, 0xc6, 0xfe, 0x73, 0x1a, 0x1a}, |  | ||||||
|     {0x77, 0xb8, 0x1b, 0x90, 0xb4, 0xb7, 0x32, 0x76, 0x8f, 0x8a, 0x57, 0x06, 0xc7, 0xdd, 0x08, 0x90}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static const uint8_t enclave_signature_expected[ENCLAVE_SIGNATURE_KEY_SLOTS][ENCLAVE_SIGNATURE_SIZE] = { |  | ||||||
|     {0xe9, 0x9a, 0xce, 0xe9, 0x4d, 0xe1, 0x7f, 0x55, 0xcb, 0x8a, 0xbf, 0xf2, 0x4d, 0x98, 0x27, 0x67}, |  | ||||||
|     {0x34, 0x27, 0xa7, 0xea, 0xa8, 0x98, 0x66, 0x9b, 0xed, 0x43, 0xd3, 0x93, 0xb5, 0xa2, 0x87, 0x8e}, |  | ||||||
|     {0x6c, 0xf3, 0x01, 0x78, 0x53, 0x1b, 0x11, 0x32, 0xf0, 0x27, 0x2f, 0xe3, 0x7d, 0xa6, 0xe2, 0xfd}, |  | ||||||
|     {0xdf, 0x7f, 0x37, 0x65, 0x2f, 0xdb, 0x7c, 0xcf, 0x5b, 0xb6, 0xe4, 0x9c, 0x63, 0xc5, 0x0f, 0xe0}, |  | ||||||
|     {0x9b, 0x5c, 0xee, 0x44, 0x0e, 0xd1, 0xcb, 0x5f, 0x28, 0x9f, 0x12, 0x17, 0x59, 0x64, 0x40, 0xbb}, |  | ||||||
|     {0x94, 0xc2, 0x09, 0x98, 0x62, 0xa7, 0x2b, 0x93, 0xed, 0x36, 0x1f, 0x10, 0xbc, 0x26, 0xbd, 0x41}, |  | ||||||
|     {0x4d, 0xb2, 0x2b, 0xc5, 0x96, 0x47, 0x61, 0xf4, 0x16, 0xe0, 0x81, 0xc3, 0x8e, 0xb9, 0x9c, 0x9b}, |  | ||||||
|     {0xc3, 0x6b, 0x83, 0x55, 0x90, 0x38, 0x0f, 0xea, 0xd1, 0x65, 0xbf, 0x32, 0x4f, 0x8e, 0x62, 0x5b}, |  | ||||||
|     {0x8d, 0x5e, 0x27, 0xbc, 0x14, 0x4f, 0x08, 0xa8, 0x2b, 0x14, 0x89, 0x5e, 0xdf, 0x77, 0x04, 0x31}, |  | ||||||
|     {0xc9, 0xf7, 0x03, 0xf1, 0x6c, 0x65, 0xad, 0x49, 0x74, 0xbe, 0x00, 0x54, 0xfd, 0xa6, 0x9c, 0x32}, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) { | void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) { | ||||||
|     string_t value; |     string_t value; | ||||||
|     string_init(value); |     string_init(value); | ||||||
| @ -164,23 +122,12 @@ void furi_hal_info_get(FuriHalInfoValueCallback out, void* context) { | |||||||
|         out("radio_ble_mac", string_get_cstr(value), false, context); |         out("radio_ble_mac", string_get_cstr(value), false, context); | ||||||
| 
 | 
 | ||||||
|         // Signature verification
 |         // Signature verification
 | ||||||
|         uint8_t buffer[ENCLAVE_SIGNATURE_SIZE]; |         uint8_t enclave_keys = 0; | ||||||
|         size_t enclave_valid_keys = 0; |         uint8_t enclave_valid_keys = 0; | ||||||
|         for(size_t key_slot = 0; key_slot < ENCLAVE_SIGNATURE_KEY_SLOTS; key_slot++) { |         bool enclave_valid = furi_hal_crypto_verify_enclave(&enclave_keys, &enclave_valid_keys); | ||||||
|             if(furi_hal_crypto_store_load_key(key_slot + 1, enclave_signature_iv[key_slot])) { |  | ||||||
|                 if(furi_hal_crypto_encrypt( |  | ||||||
|                        enclave_signature_input[key_slot], buffer, ENCLAVE_SIGNATURE_SIZE)) { |  | ||||||
|                     enclave_valid_keys += memcmp( |  | ||||||
|                                               buffer, |  | ||||||
|                                               enclave_signature_expected[key_slot], |  | ||||||
|                                               ENCLAVE_SIGNATURE_SIZE) == 0; |  | ||||||
|                 } |  | ||||||
|                 furi_hal_crypto_store_unload_key(key_slot + 1); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         string_printf(value, "%d", enclave_valid_keys); |         string_printf(value, "%d", enclave_valid_keys); | ||||||
|         out("enclave_valid_keys", string_get_cstr(value), false, context); |         out("enclave_valid_keys", string_get_cstr(value), false, context); | ||||||
|         out("enclave_valid", (enclave_valid_keys == ENCLAVE_SIGNATURE_KEY_SLOTS) ? "true" : "false", true, context); |         out("enclave_valid", enclave_valid ? "true" : "false", true, context); | ||||||
|     } else { |     } else { | ||||||
|         out("radio_alive", "false", true, context); |         out("radio_alive", "false", true, context); | ||||||
|     } |     } | ||||||
|  | |||||||
							
								
								
									
										56
									
								
								firmware/targets/f7/furi-hal/furi-hal-random.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								firmware/targets/f7/furi-hal/furi-hal-random.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | |||||||
|  | #include "furi-hal-random.h" | ||||||
|  | #include <furi.h> | ||||||
|  | #include <furi-hal.h> | ||||||
|  | 
 | ||||||
|  | #include <stm32wbxx_ll_rng.h> | ||||||
|  | #include <stm32wbxx_ll_hsem.h> | ||||||
|  | 
 | ||||||
|  | #include <hw_conf.h> | ||||||
|  | 
 | ||||||
|  | uint32_t furi_hal_random_get() { | ||||||
|  | 
 | ||||||
|  |     while( LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID)); | ||||||
|  |     LL_RNG_Enable(RNG); | ||||||
|  | 
 | ||||||
|  |     while (!LL_RNG_IsActiveFlag_DRDY(RNG)); | ||||||
|  | 
 | ||||||
|  |     if ((LL_RNG_IsActiveFlag_CECS(RNG)) || (LL_RNG_IsActiveFlag_SECS(RNG))) { | ||||||
|  |         furi_crash("TRNG error"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     uint32_t random_val = LL_RNG_ReadRandData32(RNG); | ||||||
|  | 
 | ||||||
|  |     LL_RNG_Disable(RNG); | ||||||
|  |     LL_HSEM_ReleaseLock(HSEM, CFG_HW_RNG_SEMID, 0); | ||||||
|  | 
 | ||||||
|  |     return random_val; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_random_fill_buf(uint8_t* buf, uint32_t len) { | ||||||
|  | 
 | ||||||
|  |     while( LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID)); | ||||||
|  |     LL_RNG_Enable(RNG); | ||||||
|  | 
 | ||||||
|  |     for (uint32_t i = 0; i < len; i+= 4) { | ||||||
|  |         while (!LL_RNG_IsActiveFlag_DRDY(RNG)); | ||||||
|  | 
 | ||||||
|  |         if ((LL_RNG_IsActiveFlag_CECS(RNG)) || (LL_RNG_IsActiveFlag_SECS(RNG))) { | ||||||
|  |             furi_crash("TRNG error"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         uint32_t random_val = LL_RNG_ReadRandData32(RNG); | ||||||
|  | 
 | ||||||
|  |         uint8_t len_cur = ((i+4) < len) ? (4) : (len-i); | ||||||
|  |         memcpy(&buf[i], &random_val, len_cur); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LL_RNG_Disable(RNG); | ||||||
|  |     LL_HSEM_ReleaseLock(HSEM, CFG_HW_RNG_SEMID, 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void srand(unsigned seed) { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int rand() { | ||||||
|  |     return (furi_hal_random_get() & RAND_MAX); | ||||||
|  | } | ||||||
							
								
								
									
										309
									
								
								firmware/targets/f7/furi-hal/furi-hal-usb-u2f.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										309
									
								
								firmware/targets/f7/furi-hal/furi-hal-usb-u2f.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,309 @@ | |||||||
|  | #include "furi-hal-version.h" | ||||||
|  | #include "furi-hal-usb_i.h" | ||||||
|  | #include "furi-hal-usb-hid-u2f.h" | ||||||
|  | #include "furi-hal-usb.h" | ||||||
|  | #include <furi.h> | ||||||
|  | #include "usb.h" | ||||||
|  | #include "usb_hid.h" | ||||||
|  | 
 | ||||||
|  | #define HID_PAGE_FIDO 0xF1D0 | ||||||
|  | #define HID_FIDO_U2F 0x01 | ||||||
|  | #define HID_FIDO_INPUT 0x20 | ||||||
|  | #define HID_FIDO_OUTPUT 0x21 | ||||||
|  | 
 | ||||||
|  | #define HID_EP_IN 0x81 | ||||||
|  | #define HID_EP_OUT 0x01 | ||||||
|  | 
 | ||||||
|  | struct HidIadDescriptor { | ||||||
|  |     struct usb_iad_descriptor hid_iad; | ||||||
|  |     struct usb_interface_descriptor hid; | ||||||
|  |     struct usb_hid_descriptor hid_desc; | ||||||
|  |     struct usb_endpoint_descriptor hid_ep_in; | ||||||
|  |     struct usb_endpoint_descriptor hid_ep_out; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct HidConfigDescriptor { | ||||||
|  |     struct usb_config_descriptor config; | ||||||
|  |     struct HidIadDescriptor iad_0; | ||||||
|  | } __attribute__((packed)); | ||||||
|  | 
 | ||||||
|  | /* HID report: FIDO U2F */ | ||||||
|  | static const uint8_t hid_u2f_report_desc[] = { | ||||||
|  |     HID_RI_USAGE_PAGE(16, HID_PAGE_FIDO), | ||||||
|  |     HID_USAGE(HID_FIDO_U2F), | ||||||
|  |     HID_COLLECTION(HID_APPLICATION_COLLECTION), | ||||||
|  |     HID_USAGE(HID_FIDO_INPUT), | ||||||
|  |     HID_LOGICAL_MINIMUM(0x00), | ||||||
|  |     HID_LOGICAL_MAXIMUM(0xFF), | ||||||
|  |     HID_REPORT_SIZE(8), | ||||||
|  |     HID_REPORT_COUNT(HID_U2F_PACKET_LEN), | ||||||
|  |     HID_INPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), | ||||||
|  |     HID_USAGE(HID_FIDO_OUTPUT), | ||||||
|  |     HID_LOGICAL_MINIMUM(0x00), | ||||||
|  |     HID_LOGICAL_MAXIMUM(0xFF), | ||||||
|  |     HID_REPORT_SIZE(8), | ||||||
|  |     HID_REPORT_COUNT(HID_U2F_PACKET_LEN), | ||||||
|  |     HID_OUTPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), | ||||||
|  |     HID_END_COLLECTION, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Flipper Devices Inc."); | ||||||
|  | static const struct usb_string_descriptor dev_prod_desc = USB_STRING_DESC("U2F Token test"); | ||||||
|  | static const struct usb_string_descriptor dev_serial_desc = USB_STRING_DESC("TODO: serial"); | ||||||
|  | 
 | ||||||
|  | /* Device descriptor */ | ||||||
|  | static const struct usb_device_descriptor hid_u2f_device_desc = { | ||||||
|  |     .bLength = sizeof(struct usb_device_descriptor), | ||||||
|  |     .bDescriptorType = USB_DTYPE_DEVICE, | ||||||
|  |     .bcdUSB = VERSION_BCD(2, 0, 0), | ||||||
|  |     .bDeviceClass = USB_CLASS_IAD, | ||||||
|  |     .bDeviceSubClass = USB_SUBCLASS_IAD, | ||||||
|  |     .bDeviceProtocol = USB_PROTO_IAD, | ||||||
|  |     .bMaxPacketSize0 = USB_EP0_SIZE, | ||||||
|  |     .idVendor = 0x0483, | ||||||
|  |     .idProduct = 0x5741, | ||||||
|  |     .bcdDevice = VERSION_BCD(1, 0, 0), | ||||||
|  |     .iManufacturer = UsbDevManuf, | ||||||
|  |     .iProduct = UsbDevProduct, | ||||||
|  |     .iSerialNumber = UsbDevSerial, | ||||||
|  |     .bNumConfigurations = 1, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* Device configuration descriptor */ | ||||||
|  | static const struct HidConfigDescriptor hid_u2f_cfg_desc = { | ||||||
|  |     .config = | ||||||
|  |         { | ||||||
|  |             .bLength = sizeof(struct usb_config_descriptor), | ||||||
|  |             .bDescriptorType = USB_DTYPE_CONFIGURATION, | ||||||
|  |             .wTotalLength = sizeof(struct HidConfigDescriptor), | ||||||
|  |             .bNumInterfaces = 1, | ||||||
|  |             .bConfigurationValue = 1, | ||||||
|  |             .iConfiguration = NO_DESCRIPTOR, | ||||||
|  |             .bmAttributes = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED, | ||||||
|  |             .bMaxPower = USB_CFG_POWER_MA(100), | ||||||
|  |         }, | ||||||
|  |     .iad_0 = | ||||||
|  |         { | ||||||
|  |             .hid_iad = | ||||||
|  |                 { | ||||||
|  |                     .bLength = sizeof(struct usb_iad_descriptor), | ||||||
|  |                     .bDescriptorType = USB_DTYPE_INTERFASEASSOC, | ||||||
|  |                     .bFirstInterface = 0, | ||||||
|  |                     .bInterfaceCount = 1, | ||||||
|  |                     .bFunctionClass = USB_CLASS_PER_INTERFACE, | ||||||
|  |                     .bFunctionSubClass = USB_SUBCLASS_NONE, | ||||||
|  |                     .bFunctionProtocol = USB_PROTO_NONE, | ||||||
|  |                     .iFunction = NO_DESCRIPTOR, | ||||||
|  |                 }, | ||||||
|  |             .hid = | ||||||
|  |                 { | ||||||
|  |                     .bLength = sizeof(struct usb_interface_descriptor), | ||||||
|  |                     .bDescriptorType = USB_DTYPE_INTERFACE, | ||||||
|  |                     .bInterfaceNumber = 0, | ||||||
|  |                     .bAlternateSetting = 0, | ||||||
|  |                     .bNumEndpoints = 2, | ||||||
|  |                     .bInterfaceClass = USB_CLASS_HID, | ||||||
|  |                     .bInterfaceSubClass = USB_HID_SUBCLASS_NONBOOT, | ||||||
|  |                     .bInterfaceProtocol = USB_HID_PROTO_NONBOOT, | ||||||
|  |                     .iInterface = NO_DESCRIPTOR, | ||||||
|  |                 }, | ||||||
|  |             .hid_desc = | ||||||
|  |                 { | ||||||
|  |                     .bLength = sizeof(struct usb_hid_descriptor), | ||||||
|  |                     .bDescriptorType = USB_DTYPE_HID, | ||||||
|  |                     .bcdHID = VERSION_BCD(1, 0, 0), | ||||||
|  |                     .bCountryCode = USB_HID_COUNTRY_NONE, | ||||||
|  |                     .bNumDescriptors = 1, | ||||||
|  |                     .bDescriptorType0 = USB_DTYPE_HID_REPORT, | ||||||
|  |                     .wDescriptorLength0 = sizeof(hid_u2f_report_desc), | ||||||
|  |                 }, | ||||||
|  |             .hid_ep_in = | ||||||
|  |                 { | ||||||
|  |                     .bLength = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |                     .bDescriptorType = USB_DTYPE_ENDPOINT, | ||||||
|  |                     .bEndpointAddress = HID_EP_IN, | ||||||
|  |                     .bmAttributes = USB_EPTYPE_INTERRUPT, | ||||||
|  |                     .wMaxPacketSize = HID_U2F_PACKET_LEN, | ||||||
|  |                     .bInterval = 5, | ||||||
|  |                 }, | ||||||
|  |             .hid_ep_out = | ||||||
|  |                 { | ||||||
|  |                     .bLength = sizeof(struct usb_endpoint_descriptor), | ||||||
|  |                     .bDescriptorType = USB_DTYPE_ENDPOINT, | ||||||
|  |                     .bEndpointAddress = HID_EP_OUT, | ||||||
|  |                     .bmAttributes = USB_EPTYPE_INTERRUPT, | ||||||
|  |                     .wMaxPacketSize = HID_U2F_PACKET_LEN, | ||||||
|  |                     .bInterval = 5, | ||||||
|  |                 }, | ||||||
|  |         }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void hid_u2f_init(usbd_device* dev, UsbInterface* intf); | ||||||
|  | static void hid_u2f_deinit(usbd_device* dev); | ||||||
|  | static void hid_u2f_on_wakeup(usbd_device* dev); | ||||||
|  | static void hid_u2f_on_suspend(usbd_device* dev); | ||||||
|  | 
 | ||||||
|  | //static bool hid_u2f_send_report(uint8_t report_id);
 | ||||||
|  | static usbd_respond hid_u2f_ep_config(usbd_device* dev, uint8_t cfg); | ||||||
|  | static usbd_respond | ||||||
|  |     hid_u2f_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback); | ||||||
|  | static usbd_device* usb_dev; | ||||||
|  | static osSemaphoreId_t hid_u2f_semaphore = NULL; | ||||||
|  | static bool hid_u2f_connected = false; | ||||||
|  | 
 | ||||||
|  | static HidU2fCallback callback; | ||||||
|  | static void* cb_ctx; | ||||||
|  | 
 | ||||||
|  | bool furi_hal_hid_u2f_is_connected() { | ||||||
|  |     return hid_u2f_connected; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_hid_u2f_set_callback(HidU2fCallback cb, void* ctx) { | ||||||
|  |     if (callback != NULL) { | ||||||
|  |         if (hid_u2f_connected == true) | ||||||
|  |             callback(HidU2fDisconnected, cb_ctx); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     callback = cb; | ||||||
|  |     cb_ctx = ctx; | ||||||
|  | 
 | ||||||
|  |     if (callback != NULL) { | ||||||
|  |         if (hid_u2f_connected == true) | ||||||
|  |             callback(HidU2fConnected, cb_ctx); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | UsbInterface usb_hid_u2f = { | ||||||
|  |     .init = hid_u2f_init, | ||||||
|  |     .deinit = hid_u2f_deinit, | ||||||
|  |     .wakeup = hid_u2f_on_wakeup, | ||||||
|  |     .suspend = hid_u2f_on_suspend, | ||||||
|  | 
 | ||||||
|  |     .dev_descr = (struct usb_device_descriptor*)&hid_u2f_device_desc, | ||||||
|  | 
 | ||||||
|  |     .str_manuf_descr = (void*)&dev_manuf_desc, | ||||||
|  |     .str_prod_descr = (void*)&dev_prod_desc, | ||||||
|  |     .str_serial_descr = (void*)&dev_serial_desc, | ||||||
|  | 
 | ||||||
|  |     .cfg_descr = (void*)&hid_u2f_cfg_desc, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void hid_u2f_init(usbd_device* dev, UsbInterface* intf) { | ||||||
|  |     if(hid_u2f_semaphore == NULL) hid_u2f_semaphore = osSemaphoreNew(1, 1, NULL); | ||||||
|  |     usb_dev = dev; | ||||||
|  | 
 | ||||||
|  |     usbd_reg_config(dev, hid_u2f_ep_config); | ||||||
|  |     usbd_reg_control(dev, hid_u2f_control); | ||||||
|  | 
 | ||||||
|  |     usbd_connect(dev, true); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_u2f_deinit(usbd_device* dev) { | ||||||
|  |     usbd_reg_config(dev, NULL); | ||||||
|  |     usbd_reg_control(dev, NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_u2f_on_wakeup(usbd_device* dev) { | ||||||
|  |     hid_u2f_connected = true; | ||||||
|  |     if (callback != NULL) | ||||||
|  |         callback(HidU2fConnected, cb_ctx); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_u2f_on_suspend(usbd_device* dev) { | ||||||
|  |     if(hid_u2f_connected == true) { | ||||||
|  |         hid_u2f_connected = false; | ||||||
|  |         osSemaphoreRelease(hid_u2f_semaphore); | ||||||
|  |         if (callback != NULL) | ||||||
|  |             callback(HidU2fDisconnected, cb_ctx); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_hid_u2f_send_response(uint8_t* data, uint8_t len) { | ||||||
|  |     if ((hid_u2f_semaphore == NULL) || (hid_u2f_connected == false)) | ||||||
|  |         return; | ||||||
|  |     furi_check(osSemaphoreAcquire(hid_u2f_semaphore, osWaitForever) == osOK); | ||||||
|  |     if (hid_u2f_connected == true) { | ||||||
|  |         usbd_ep_write(usb_dev, HID_EP_OUT, data, len); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint32_t furi_hal_hid_u2f_get_request(uint8_t* data) { | ||||||
|  |     int32_t len = usbd_ep_read(usb_dev, HID_EP_IN, data, HID_U2F_PACKET_LEN); | ||||||
|  |     return ((len < 0) ? 0 : len); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_u2f_rx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     if (callback != NULL) | ||||||
|  |         callback(HidU2fRequest, cb_ctx); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_u2f_tx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     osSemaphoreRelease(hid_u2f_semaphore); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void hid_u2f_txrx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) { | ||||||
|  |     if (event == usbd_evt_eptx) { | ||||||
|  |         hid_u2f_tx_ep_callback(dev, event, ep); | ||||||
|  |     } else { | ||||||
|  |         hid_u2f_rx_ep_callback(dev, event, ep); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Configure endpoints */ | ||||||
|  | static usbd_respond hid_u2f_ep_config(usbd_device* dev, uint8_t cfg) { | ||||||
|  |     switch(cfg) { | ||||||
|  |     case 0: | ||||||
|  |         /* deconfiguring device */ | ||||||
|  |         usbd_ep_deconfig(dev, HID_EP_IN); | ||||||
|  |         usbd_ep_deconfig(dev, HID_EP_OUT); | ||||||
|  |         usbd_reg_endpoint(dev, HID_EP_IN, 0); | ||||||
|  |         usbd_reg_endpoint(dev, HID_EP_OUT, 0); | ||||||
|  |         return usbd_ack; | ||||||
|  |     case 1: | ||||||
|  |         /* configuring device */ | ||||||
|  |         usbd_ep_config(dev, HID_EP_IN, USB_EPTYPE_INTERRUPT, HID_U2F_PACKET_LEN); | ||||||
|  |         usbd_ep_config(dev, HID_EP_OUT, USB_EPTYPE_INTERRUPT, HID_U2F_PACKET_LEN); | ||||||
|  |         usbd_reg_endpoint(dev, HID_EP_IN, hid_u2f_txrx_ep_callback); | ||||||
|  |         usbd_reg_endpoint(dev, HID_EP_OUT, hid_u2f_txrx_ep_callback); | ||||||
|  |         usbd_ep_write(dev, HID_U2F_PACKET_LEN, 0, 0); | ||||||
|  |         return usbd_ack; | ||||||
|  |     default: | ||||||
|  |         return usbd_fail; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Control requests handler */ | ||||||
|  | static usbd_respond hid_u2f_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback) { | ||||||
|  |     /* HID control requests */ | ||||||
|  |     if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == | ||||||
|  |            (USB_REQ_INTERFACE | USB_REQ_CLASS) && | ||||||
|  |        req->wIndex == 0) { | ||||||
|  |         switch(req->bRequest) { | ||||||
|  |         case USB_HID_SETIDLE: | ||||||
|  |             return usbd_ack; | ||||||
|  |         case USB_HID_GETREPORT: | ||||||
|  |             // dev->status.data_ptr = &hid_u2f_report;
 | ||||||
|  |             // dev->status.data_count = sizeof(hid_u2f_report);
 | ||||||
|  |             return usbd_ack; | ||||||
|  |         default: | ||||||
|  |             return usbd_fail; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == | ||||||
|  |            (USB_REQ_INTERFACE | USB_REQ_STANDARD) && | ||||||
|  |        req->wIndex == 0 && req->bRequest == USB_STD_GET_DESCRIPTOR) { | ||||||
|  |         switch(req->wValue >> 8) { | ||||||
|  |         case USB_DTYPE_HID: | ||||||
|  |             dev->status.data_ptr = (uint8_t*)&(hid_u2f_cfg_desc.iad_0.hid_desc); | ||||||
|  |             dev->status.data_count = sizeof(hid_u2f_cfg_desc.iad_0.hid_desc); | ||||||
|  |             return usbd_ack; | ||||||
|  |         case USB_DTYPE_HID_REPORT: | ||||||
|  |             dev->status.data_ptr = (uint8_t*)hid_u2f_report_desc; | ||||||
|  |             dev->status.data_count = sizeof(hid_u2f_report_desc); | ||||||
|  |             return usbd_ack; | ||||||
|  |         default: | ||||||
|  |             return usbd_fail; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return usbd_fail; | ||||||
|  | } | ||||||
| @ -32,6 +32,10 @@ typedef struct { | |||||||
|  */ |  */ | ||||||
| void furi_hal_crypto_init(); | void furi_hal_crypto_init(); | ||||||
| 
 | 
 | ||||||
|  | bool furi_hal_crypto_verify_enclave(uint8_t* keys_nb, uint8_t* valid_keys_nb); | ||||||
|  | 
 | ||||||
|  | bool furi_hal_crypto_verify_key(uint8_t key_slot); | ||||||
|  | 
 | ||||||
| /** Store key in crypto storage
 | /** Store key in crypto storage
 | ||||||
|  * |  * | ||||||
|  * @param      key   FuriHalCryptoKey to store. Only Master, Simple or |  * @param      key   FuriHalCryptoKey to store. Only Master, Simple or | ||||||
|  | |||||||
							
								
								
									
										24
									
								
								firmware/targets/furi-hal-include/furi-hal-random.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								firmware/targets/furi-hal-include/furi-hal-random.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <stdint.h> | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /** Get random value
 | ||||||
|  |  * | ||||||
|  |  * @return     random value | ||||||
|  |  */ | ||||||
|  | uint32_t furi_hal_random_get(); | ||||||
|  | 
 | ||||||
|  | /** Fill buffer with random data
 | ||||||
|  |  * | ||||||
|  |  * @param      buf  buffer pointer | ||||||
|  |  * @param      data buffer len | ||||||
|  |  */ | ||||||
|  | void furi_hal_random_fill_buf(uint8_t* buf, uint32_t len); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
							
								
								
									
										36
									
								
								firmware/targets/furi-hal-include/furi-hal-usb-hid-u2f.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								firmware/targets/furi-hal-include/furi-hal-usb-hid-u2f.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #define HID_U2F_PACKET_LEN 64 | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     HidU2fDisconnected, | ||||||
|  |     HidU2fConnected, | ||||||
|  |     HidU2fRequest, | ||||||
|  | } HidU2fEvent; | ||||||
|  | 
 | ||||||
|  | typedef void (*HidU2fCallback)(HidU2fEvent ev, void* context); | ||||||
|  | 
 | ||||||
|  | /** Get HID U2F connection state
 | ||||||
|  |  * | ||||||
|  |  * @return      true / false | ||||||
|  |  */ | ||||||
|  | bool furi_hal_hid_u2f_is_connected(); | ||||||
|  | 
 | ||||||
|  | /** Set HID U2F event callback
 | ||||||
|  |  * | ||||||
|  |  * @param      cb  callback | ||||||
|  |  * @param      ctx  callback context | ||||||
|  |  */ | ||||||
|  | void furi_hal_hid_u2f_set_callback(HidU2fCallback cb, void* ctx); | ||||||
|  | 
 | ||||||
|  | /** Get received U2F HID packet
 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | uint32_t furi_hal_hid_u2f_get_request(uint8_t* data); | ||||||
|  | 
 | ||||||
|  | /** Send U2F HID response packet
 | ||||||
|  |  * | ||||||
|  |  * @param      data  response data | ||||||
|  |  * @param      len  packet length | ||||||
|  |  */ | ||||||
|  | void furi_hal_hid_u2f_send_response(uint8_t* data, uint8_t len); | ||||||
| @ -23,6 +23,7 @@ struct UsbInterface { | |||||||
| extern UsbInterface usb_cdc_single; | extern UsbInterface usb_cdc_single; | ||||||
| extern UsbInterface usb_cdc_dual; | extern UsbInterface usb_cdc_dual; | ||||||
| extern UsbInterface usb_hid; | extern UsbInterface usb_hid; | ||||||
|  | extern UsbInterface usb_hid_u2f; | ||||||
| 
 | 
 | ||||||
| /** USB device low-level initialization
 | /** USB device low-level initialization
 | ||||||
|  */ |  */ | ||||||
|  | |||||||
| @ -40,6 +40,7 @@ template <unsigned int N> struct STOP_EXTERNING_ME {}; | |||||||
| #include "furi-hal-compress.h" | #include "furi-hal-compress.h" | ||||||
| #include "furi-hal-uart.h" | #include "furi-hal-uart.h" | ||||||
| #include "furi-hal-info.h" | #include "furi-hal-info.h" | ||||||
|  | #include "furi-hal-random.h" | ||||||
| 
 | 
 | ||||||
| /** Init furi-hal */ | /** Init furi-hal */ | ||||||
| void furi_hal_init(); | void furi_hal_init(); | ||||||
|  | |||||||
| @ -124,3 +124,7 @@ C_SOURCES		+= $(wildcard $(LIB_DIR)/heatshrink/*.c) | |||||||
| # Toolbox
 | # Toolbox
 | ||||||
| CFLAGS			+= -I$(LIB_DIR)/flipper_file | CFLAGS			+= -I$(LIB_DIR)/flipper_file | ||||||
| C_SOURCES		+= $(wildcard $(LIB_DIR)/flipper_file/*.c) | C_SOURCES		+= $(wildcard $(LIB_DIR)/flipper_file/*.c) | ||||||
|  | 
 | ||||||
|  | # Micro-ECC
 | ||||||
|  | CFLAGS			+= -I$(LIB_DIR)/micro-ecc | ||||||
|  | C_SOURCES		+= $(wildcard $(LIB_DIR)/micro-ecc/*.c) | ||||||
|  | |||||||
							
								
								
									
										21
									
								
								lib/micro-ecc/LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								lib/micro-ecc/LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  | Copyright (c) 2014, Kenneth MacKay | ||||||
|  | All rights reserved. | ||||||
|  | 
 | ||||||
|  | Redistribution and use in source and binary forms, with or without modification, | ||||||
|  | are permitted provided that the following conditions are met: | ||||||
|  |  * Redistributions of source code must retain the above copyright notice, this | ||||||
|  |    list of conditions and the following disclaimer. | ||||||
|  |  * Redistributions in binary form must reproduce the above copyright notice, | ||||||
|  |    this list of conditions and the following disclaimer in the documentation | ||||||
|  |    and/or other materials provided with the distribution. | ||||||
|  | 
 | ||||||
|  | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||||||
|  | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||||
|  | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||||
|  | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | ||||||
|  | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||||
|  | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||||
|  | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||||||
|  | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||||
|  | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
							
								
								
									
										41
									
								
								lib/micro-ecc/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								lib/micro-ecc/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | micro-ecc | ||||||
|  | ========== | ||||||
|  | 
 | ||||||
|  | A small and fast ECDH and ECDSA implementation for 8-bit, 32-bit, and 64-bit processors. | ||||||
|  | 
 | ||||||
|  | The static version of micro-ecc (ie, where the curve was selected at compile-time) can be found in the "static" branch. | ||||||
|  | 
 | ||||||
|  | Features | ||||||
|  | -------- | ||||||
|  | 
 | ||||||
|  |  * Resistant to known side-channel attacks. | ||||||
|  |  * Written in C, with optional GCC inline assembly for AVR, ARM and Thumb platforms. | ||||||
|  |  * Supports 8, 32, and 64-bit architectures. | ||||||
|  |  * Small code size. | ||||||
|  |  * No dynamic memory allocation. | ||||||
|  |  * Support for 5 standard curves: secp160r1, secp192r1, secp224r1, secp256r1, and secp256k1. | ||||||
|  |  * BSD 2-clause license. | ||||||
|  | 
 | ||||||
|  | Usage Notes | ||||||
|  | ----------- | ||||||
|  | ### Point Representation ### | ||||||
|  | Compressed points are represented in the standard format as defined in http://www.secg.org/sec1-v2.pdf; uncompressed points are represented in standard format, but without the `0x04` prefix. All functions except `uECC_decompress()` only accept uncompressed points; use `uECC_compress()` and `uECC_decompress()` to convert between compressed and uncompressed point representations. | ||||||
|  | 
 | ||||||
|  | Private keys are represented in the standard format. | ||||||
|  | 
 | ||||||
|  | ### Using the Code ### | ||||||
|  | 
 | ||||||
|  | I recommend just copying (or symlink) the uECC files into your project. Then just `#include "uECC.h"` to use the micro-ecc functions. | ||||||
|  | 
 | ||||||
|  | For use with Arduino, you can use the Library Manager to download micro-ecc (**Sketch**=>**Include Library**=>**Manage Libraries**). You can then use uECC just like any other Arduino library (uECC should show up in the **Sketch**=>**Import Library** submenu). | ||||||
|  | 
 | ||||||
|  | See uECC.h for documentation for each function. | ||||||
|  | 
 | ||||||
|  | ### Compilation Notes ### | ||||||
|  | 
 | ||||||
|  |  * Should compile with any C/C++ compiler that supports stdint.h (this includes Visual Studio 2013). | ||||||
|  |  * If you want to change the defaults for any of the uECC compile-time options (such as `uECC_OPTIMIZATION_LEVEL`), you must change them in your Makefile or similar so that uECC.c is compiled with the desired values (ie, compile uECC.c with `-DuECC_OPTIMIZATION_LEVEL=3` or whatever). | ||||||
|  |  * When compiling for a Thumb-1 platform, you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher). | ||||||
|  |  * When compiling for an ARM/Thumb-2 platform with `uECC_OPTIMIZATION_LEVEL` >= 3, you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher). | ||||||
|  |  * When compiling for AVR, you must have optimizations enabled (compile with `-O1` or higher). | ||||||
|  |  * When building for Windows, you will need to link in the `advapi32.lib` system library. | ||||||
							
								
								
									
										820
									
								
								lib/micro-ecc/asm_arm.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										820
									
								
								lib/micro-ecc/asm_arm.inc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,820 @@ | |||||||
|  | /* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ | ||||||
|  | 
 | ||||||
|  | #ifndef _UECC_ASM_ARM_H_
 | ||||||
|  | #define _UECC_ASM_ARM_H_
 | ||||||
|  | 
 | ||||||
|  | #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)
 | ||||||
|  |     #define uECC_MIN_WORDS 8
 | ||||||
|  | #endif
 | ||||||
|  | #if uECC_SUPPORTS_secp224r1
 | ||||||
|  |     #undef uECC_MIN_WORDS
 | ||||||
|  |     #define uECC_MIN_WORDS 7
 | ||||||
|  | #endif
 | ||||||
|  | #if uECC_SUPPORTS_secp192r1
 | ||||||
|  |     #undef uECC_MIN_WORDS
 | ||||||
|  |     #define uECC_MIN_WORDS 6
 | ||||||
|  | #endif
 | ||||||
|  | #if uECC_SUPPORTS_secp160r1
 | ||||||
|  |     #undef uECC_MIN_WORDS
 | ||||||
|  |     #define uECC_MIN_WORDS 5
 | ||||||
|  | #endif
 | ||||||
|  | 
 | ||||||
|  | #if (uECC_PLATFORM == uECC_arm_thumb)
 | ||||||
|  |     #define REG_RW "+l"
 | ||||||
|  |     #define REG_WRITE "=l"
 | ||||||
|  | #else
 | ||||||
|  |     #define REG_RW "+r"
 | ||||||
|  |     #define REG_WRITE "=r"
 | ||||||
|  | #endif
 | ||||||
|  | 
 | ||||||
|  | #if (uECC_PLATFORM == uECC_arm_thumb || uECC_PLATFORM == uECC_arm_thumb2)
 | ||||||
|  |     #define REG_RW_LO "+l"
 | ||||||
|  |     #define REG_WRITE_LO "=l"
 | ||||||
|  | #else
 | ||||||
|  |     #define REG_RW_LO "+r"
 | ||||||
|  |     #define REG_WRITE_LO "=r"
 | ||||||
|  | #endif
 | ||||||
|  | 
 | ||||||
|  | #if (uECC_PLATFORM == uECC_arm_thumb2)
 | ||||||
|  |     #define RESUME_SYNTAX
 | ||||||
|  | #else
 | ||||||
|  |     #define RESUME_SYNTAX ".syntax divided \n\t"
 | ||||||
|  | #endif
 | ||||||
|  | 
 | ||||||
|  | #if (uECC_OPTIMIZATION_LEVEL >= 2)
 | ||||||
|  | 
 | ||||||
|  | uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result, | ||||||
|  |                                       const uECC_word_t *left, | ||||||
|  |                                       const uECC_word_t *right, | ||||||
|  |                                       wordcount_t num_words) { | ||||||
|  | #if (uECC_MAX_WORDS != uECC_MIN_WORDS)
 | ||||||
|  |   #if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2)
 | ||||||
|  |     uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 2 + 1; | ||||||
|  |   #else /* ARM */
 | ||||||
|  |     uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 4; | ||||||
|  |   #endif
 | ||||||
|  | #endif
 | ||||||
|  |     uint32_t carry; | ||||||
|  |     uint32_t left_word; | ||||||
|  |     uint32_t right_word; | ||||||
|  |      | ||||||
|  |     __asm__ volatile ( | ||||||
|  |         ".syntax unified \n\t" | ||||||
|  |         "movs %[carry], #0 \n\t" | ||||||
|  |     #if (uECC_MAX_WORDS != uECC_MIN_WORDS)
 | ||||||
|  |         "adr %[left], 1f \n\t" | ||||||
|  |         ".align 4 \n\t" | ||||||
|  |         "adds %[jump], %[left] \n\t" | ||||||
|  |     #endif
 | ||||||
|  |          | ||||||
|  |         "ldmia %[lptr]!, {%[left]} \n\t" | ||||||
|  |         "ldmia %[rptr]!, {%[right]} \n\t" | ||||||
|  |         "adds %[left], %[right] \n\t" | ||||||
|  |         "stmia %[dptr]!, {%[left]} \n\t" | ||||||
|  |          | ||||||
|  |     #if (uECC_MAX_WORDS != uECC_MIN_WORDS)
 | ||||||
|  |         "bx %[jump] \n\t" | ||||||
|  |     #endif
 | ||||||
|  |         "1: \n\t" | ||||||
|  |         REPEAT(DEC(uECC_MAX_WORDS), | ||||||
|  |             "ldmia %[lptr]!, {%[left]} \n\t" | ||||||
|  |             "ldmia %[rptr]!, {%[right]} \n\t" | ||||||
|  |             "adcs %[left], %[right] \n\t" | ||||||
|  |             "stmia %[dptr]!, {%[left]} \n\t") | ||||||
|  |          | ||||||
|  |         "adcs %[carry], %[carry] \n\t" | ||||||
|  |         RESUME_SYNTAX | ||||||
|  |         : [dptr] REG_RW_LO (result), [lptr] REG_RW_LO (left), [rptr] REG_RW_LO (right), | ||||||
|  |     #if (uECC_MAX_WORDS != uECC_MIN_WORDS)
 | ||||||
|  |           [jump] REG_RW_LO (jump), | ||||||
|  |     #endif
 | ||||||
|  |           [carry] REG_WRITE_LO (carry), [left] REG_WRITE_LO (left_word), | ||||||
|  |           [right] REG_WRITE_LO (right_word) | ||||||
|  |         : | ||||||
|  |         : "cc", "memory" | ||||||
|  |     ); | ||||||
|  |     return carry; | ||||||
|  | } | ||||||
|  | #define asm_add 1
 | ||||||
|  | 
 | ||||||
|  | uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result, | ||||||
|  |                                       const uECC_word_t *left, | ||||||
|  |                                       const uECC_word_t *right, | ||||||
|  |                                       wordcount_t num_words) { | ||||||
|  | #if (uECC_MAX_WORDS != uECC_MIN_WORDS)
 | ||||||
|  |   #if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2)
 | ||||||
|  |     uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 2 + 1; | ||||||
|  |   #else /* ARM */
 | ||||||
|  |     uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 4; | ||||||
|  |   #endif
 | ||||||
|  | #endif
 | ||||||
|  |     uint32_t carry; | ||||||
|  |     uint32_t left_word; | ||||||
|  |     uint32_t right_word; | ||||||
|  |      | ||||||
|  |     __asm__ volatile ( | ||||||
|  |         ".syntax unified \n\t" | ||||||
|  |         "movs %[carry], #0 \n\t" | ||||||
|  |     #if (uECC_MAX_WORDS != uECC_MIN_WORDS)
 | ||||||
|  |         "adr %[left], 1f \n\t" | ||||||
|  |         ".align 4 \n\t" | ||||||
|  |         "adds %[jump], %[left] \n\t" | ||||||
|  |     #endif
 | ||||||
|  |          | ||||||
|  |         "ldmia %[lptr]!, {%[left]} \n\t" | ||||||
|  |         "ldmia %[rptr]!, {%[right]} \n\t" | ||||||
|  |         "subs %[left], %[right] \n\t" | ||||||
|  |         "stmia %[dptr]!, {%[left]} \n\t" | ||||||
|  |          | ||||||
|  |     #if (uECC_MAX_WORDS != uECC_MIN_WORDS)
 | ||||||
|  |         "bx %[jump] \n\t" | ||||||
|  |     #endif
 | ||||||
|  |         "1: \n\t" | ||||||
|  |         REPEAT(DEC(uECC_MAX_WORDS), | ||||||
|  |             "ldmia %[lptr]!, {%[left]} \n\t" | ||||||
|  |             "ldmia %[rptr]!, {%[right]} \n\t" | ||||||
|  |             "sbcs %[left], %[right] \n\t" | ||||||
|  |             "stmia %[dptr]!, {%[left]} \n\t") | ||||||
|  |          | ||||||
|  |         "adcs %[carry], %[carry] \n\t" | ||||||
|  |         RESUME_SYNTAX | ||||||
|  |         : [dptr] REG_RW_LO (result), [lptr] REG_RW_LO (left), [rptr] REG_RW_LO (right), | ||||||
|  |     #if (uECC_MAX_WORDS != uECC_MIN_WORDS)
 | ||||||
|  |           [jump] REG_RW_LO (jump), | ||||||
|  |     #endif
 | ||||||
|  |           [carry] REG_WRITE_LO (carry), [left] REG_WRITE_LO (left_word), | ||||||
|  |           [right] REG_WRITE_LO (right_word) | ||||||
|  |         : | ||||||
|  |         : "cc", "memory" | ||||||
|  |     ); | ||||||
|  |     return !carry; /* Note that on ARM, carry flag set means "no borrow" when subtracting | ||||||
|  |                       (for some reason...) */ | ||||||
|  | } | ||||||
|  | #define asm_sub 1
 | ||||||
|  | 
 | ||||||
|  | #endif /* (uECC_OPTIMIZATION_LEVEL >= 2) */
 | ||||||
|  | 
 | ||||||
|  | #if (uECC_OPTIMIZATION_LEVEL >= 3)
 | ||||||
|  | 
 | ||||||
|  | #if (uECC_PLATFORM != uECC_arm_thumb)
 | ||||||
|  | 
 | ||||||
|  | #if uECC_ARM_USE_UMAAL
 | ||||||
|  |     #include "asm_arm_mult_square_umaal.inc"
 | ||||||
|  | #else
 | ||||||
|  |     #include "asm_arm_mult_square.inc"
 | ||||||
|  | #endif
 | ||||||
|  | 
 | ||||||
|  | #if (uECC_OPTIMIZATION_LEVEL == 3)
 | ||||||
|  | 
 | ||||||
|  | uECC_VLI_API void uECC_vli_mult(uint32_t *result, | ||||||
|  |                                 const uint32_t *left, | ||||||
|  |                                 const uint32_t *right, | ||||||
|  |                                 wordcount_t num_words) { | ||||||
|  |     register uint32_t *r0 __asm__("r0") = result; | ||||||
|  |     register const uint32_t *r1 __asm__("r1") = left; | ||||||
|  |     register const uint32_t *r2 __asm__("r2") = right; | ||||||
|  |     register uint32_t r3 __asm__("r3") = num_words; | ||||||
|  |      | ||||||
|  |     __asm__ volatile ( | ||||||
|  |         ".syntax unified \n\t" | ||||||
|  | #if (uECC_MIN_WORDS == 5)
 | ||||||
|  |         FAST_MULT_ASM_5 | ||||||
|  |     #if (uECC_MAX_WORDS > 5)
 | ||||||
|  |         FAST_MULT_ASM_5_TO_6 | ||||||
|  |     #endif
 | ||||||
|  |     #if (uECC_MAX_WORDS > 6)
 | ||||||
|  |         FAST_MULT_ASM_6_TO_7 | ||||||
|  |     #endif
 | ||||||
|  |     #if (uECC_MAX_WORDS > 7)
 | ||||||
|  |         FAST_MULT_ASM_7_TO_8 | ||||||
|  |     #endif
 | ||||||
|  | #elif (uECC_MIN_WORDS == 6)
 | ||||||
|  |         FAST_MULT_ASM_6 | ||||||
|  |     #if (uECC_MAX_WORDS > 6)
 | ||||||
|  |         FAST_MULT_ASM_6_TO_7 | ||||||
|  |     #endif
 | ||||||
|  |     #if (uECC_MAX_WORDS > 7)
 | ||||||
|  |         FAST_MULT_ASM_7_TO_8 | ||||||
|  |     #endif
 | ||||||
|  | #elif (uECC_MIN_WORDS == 7)
 | ||||||
|  |         FAST_MULT_ASM_7 | ||||||
|  |     #if (uECC_MAX_WORDS > 7)
 | ||||||
|  |         FAST_MULT_ASM_7_TO_8 | ||||||
|  |     #endif
 | ||||||
|  | #elif (uECC_MIN_WORDS == 8)
 | ||||||
|  |         FAST_MULT_ASM_8 | ||||||
|  | #endif
 | ||||||
|  |         "1: \n\t" | ||||||
|  |         RESUME_SYNTAX | ||||||
|  |         : "+r" (r0), "+r" (r1), "+r" (r2) | ||||||
|  |         : "r" (r3) | ||||||
|  |         : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | #define asm_mult 1
 | ||||||
|  | 
 | ||||||
|  | #if uECC_SQUARE_FUNC
 | ||||||
|  | uECC_VLI_API void uECC_vli_square(uECC_word_t *result, | ||||||
|  |                                   const uECC_word_t *left, | ||||||
|  |                                   wordcount_t num_words) { | ||||||
|  |     register uint32_t *r0 __asm__("r0") = result; | ||||||
|  |     register const uint32_t *r1 __asm__("r1") = left; | ||||||
|  |     register uint32_t r2 __asm__("r2") = num_words; | ||||||
|  |      | ||||||
|  |     __asm__ volatile ( | ||||||
|  |         ".syntax unified \n\t" | ||||||
|  | #if (uECC_MIN_WORDS == 5)
 | ||||||
|  |         FAST_SQUARE_ASM_5 | ||||||
|  |     #if (uECC_MAX_WORDS > 5)
 | ||||||
|  |         FAST_SQUARE_ASM_5_TO_6 | ||||||
|  |     #endif
 | ||||||
|  |     #if (uECC_MAX_WORDS > 6)
 | ||||||
|  |         FAST_SQUARE_ASM_6_TO_7 | ||||||
|  |     #endif
 | ||||||
|  |     #if (uECC_MAX_WORDS > 7)
 | ||||||
|  |         FAST_SQUARE_ASM_7_TO_8 | ||||||
|  |     #endif
 | ||||||
|  | #elif (uECC_MIN_WORDS == 6)
 | ||||||
|  |         FAST_SQUARE_ASM_6 | ||||||
|  |     #if (uECC_MAX_WORDS > 6)
 | ||||||
|  |         FAST_SQUARE_ASM_6_TO_7 | ||||||
|  |     #endif
 | ||||||
|  |     #if (uECC_MAX_WORDS > 7)
 | ||||||
|  |         FAST_SQUARE_ASM_7_TO_8 | ||||||
|  |     #endif
 | ||||||
|  | #elif (uECC_MIN_WORDS == 7)
 | ||||||
|  |         FAST_SQUARE_ASM_7 | ||||||
|  |     #if (uECC_MAX_WORDS > 7)
 | ||||||
|  |         FAST_SQUARE_ASM_7_TO_8 | ||||||
|  |     #endif
 | ||||||
|  | #elif (uECC_MIN_WORDS == 8)
 | ||||||
|  |         FAST_SQUARE_ASM_8 | ||||||
|  | #endif
 | ||||||
|  | 
 | ||||||
|  |         "1: \n\t" | ||||||
|  |         RESUME_SYNTAX | ||||||
|  |         : "+r" (r0), "+r" (r1) | ||||||
|  |         : "r" (r2) | ||||||
|  |         : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | #define asm_square 1
 | ||||||
|  | #endif /* uECC_SQUARE_FUNC */
 | ||||||
|  | 
 | ||||||
|  | #else /* (uECC_OPTIMIZATION_LEVEL > 3) */
 | ||||||
|  | 
 | ||||||
|  | uECC_VLI_API void uECC_vli_mult(uint32_t *result, | ||||||
|  |                                 const uint32_t *left, | ||||||
|  |                                 const uint32_t *right, | ||||||
|  |                                 wordcount_t num_words) { | ||||||
|  |     register uint32_t *r0 __asm__("r0") = result; | ||||||
|  |     register const uint32_t *r1 __asm__("r1") = left; | ||||||
|  |     register const uint32_t *r2 __asm__("r2") = right; | ||||||
|  |     register uint32_t r3 __asm__("r3") = num_words; | ||||||
|  |      | ||||||
|  | #if uECC_SUPPORTS_secp160r1
 | ||||||
|  |     if (num_words == 5) { | ||||||
|  |         __asm__ volatile ( | ||||||
|  |             ".syntax unified \n\t" | ||||||
|  |             FAST_MULT_ASM_5 | ||||||
|  |             RESUME_SYNTAX | ||||||
|  |             : "+r" (r0), "+r" (r1), "+r" (r2) | ||||||
|  |             : "r" (r3) | ||||||
|  |             : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" | ||||||
|  |         ); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | #endif
 | ||||||
|  | #if uECC_SUPPORTS_secp192r1
 | ||||||
|  |     if (num_words == 6) { | ||||||
|  |         __asm__ volatile ( | ||||||
|  |             ".syntax unified \n\t" | ||||||
|  |             FAST_MULT_ASM_6 | ||||||
|  |             RESUME_SYNTAX | ||||||
|  |             : "+r" (r0), "+r" (r1), "+r" (r2) | ||||||
|  |             : "r" (r3) | ||||||
|  |             : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" | ||||||
|  |         ); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | #endif
 | ||||||
|  | #if uECC_SUPPORTS_secp224r1
 | ||||||
|  |     if (num_words == 7) { | ||||||
|  |         __asm__ volatile ( | ||||||
|  |             ".syntax unified \n\t" | ||||||
|  |             FAST_MULT_ASM_7 | ||||||
|  |             RESUME_SYNTAX | ||||||
|  |             : "+r" (r0), "+r" (r1), "+r" (r2) | ||||||
|  |             : "r" (r3) | ||||||
|  |             : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" | ||||||
|  |         ); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | #endif
 | ||||||
|  | #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)
 | ||||||
|  |     if (num_words == 8) { | ||||||
|  |         __asm__ volatile ( | ||||||
|  |             ".syntax unified \n\t" | ||||||
|  |             FAST_MULT_ASM_8 | ||||||
|  |             RESUME_SYNTAX | ||||||
|  |             : "+r" (r0), "+r" (r1), "+r" (r2) | ||||||
|  |             : "r" (r3) | ||||||
|  |             : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" | ||||||
|  |         ); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | #endif
 | ||||||
|  | } | ||||||
|  | #define asm_mult 1
 | ||||||
|  | 
 | ||||||
|  | #if uECC_SQUARE_FUNC
 | ||||||
|  | uECC_VLI_API void uECC_vli_square(uECC_word_t *result, | ||||||
|  |                                   const uECC_word_t *left, | ||||||
|  |                                   wordcount_t num_words) { | ||||||
|  |     register uint32_t *r0 __asm__("r0") = result; | ||||||
|  |     register const uint32_t *r1 __asm__("r1") = left; | ||||||
|  |     register uint32_t r2 __asm__("r2") = num_words; | ||||||
|  |      | ||||||
|  | #if uECC_SUPPORTS_secp160r1
 | ||||||
|  |     if (num_words == 5) { | ||||||
|  |         __asm__ volatile ( | ||||||
|  |             ".syntax unified \n\t" | ||||||
|  |             FAST_SQUARE_ASM_5 | ||||||
|  |             RESUME_SYNTAX | ||||||
|  |             : "+r" (r0), "+r" (r1) | ||||||
|  |             : "r" (r2) | ||||||
|  |             : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" | ||||||
|  |         ); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | #endif
 | ||||||
|  | #if uECC_SUPPORTS_secp192r1
 | ||||||
|  |     if (num_words == 6) { | ||||||
|  |         __asm__ volatile ( | ||||||
|  |             ".syntax unified \n\t" | ||||||
|  |             FAST_SQUARE_ASM_6 | ||||||
|  |             RESUME_SYNTAX | ||||||
|  |             : "+r" (r0), "+r" (r1) | ||||||
|  |             : "r" (r2) | ||||||
|  |             : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" | ||||||
|  |         ); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | #endif
 | ||||||
|  | #if uECC_SUPPORTS_secp224r1
 | ||||||
|  |     if (num_words == 7) { | ||||||
|  |         __asm__ volatile ( | ||||||
|  |             ".syntax unified \n\t" | ||||||
|  |             FAST_SQUARE_ASM_7 | ||||||
|  |             RESUME_SYNTAX | ||||||
|  |             : "+r" (r0), "+r" (r1) | ||||||
|  |             : "r" (r2) | ||||||
|  |             : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" | ||||||
|  |         ); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | #endif
 | ||||||
|  | #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)
 | ||||||
|  |     if (num_words == 8) { | ||||||
|  |         __asm__ volatile ( | ||||||
|  |             ".syntax unified \n\t" | ||||||
|  |             FAST_SQUARE_ASM_8 | ||||||
|  |             RESUME_SYNTAX | ||||||
|  |             : "+r" (r0), "+r" (r1) | ||||||
|  |             : "r" (r2) | ||||||
|  |             : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" | ||||||
|  |         ); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | #endif
 | ||||||
|  | } | ||||||
|  | #define asm_square 1
 | ||||||
|  | #endif /* uECC_SQUARE_FUNC */
 | ||||||
|  | 
 | ||||||
|  | #endif /* (uECC_OPTIMIZATION_LEVEL > 3) */
 | ||||||
|  | 
 | ||||||
|  | #endif /* uECC_PLATFORM != uECC_arm_thumb */
 | ||||||
|  | 
 | ||||||
|  | #endif /* (uECC_OPTIMIZATION_LEVEL >= 3) */
 | ||||||
|  | 
 | ||||||
|  | /* ---- "Small" implementations ---- */ | ||||||
|  | 
 | ||||||
|  | #if !asm_add
 | ||||||
|  | uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result, | ||||||
|  |                                       const uECC_word_t *left, | ||||||
|  |                                       const uECC_word_t *right, | ||||||
|  |                                       wordcount_t num_words) { | ||||||
|  |     uint32_t carry = 0; | ||||||
|  |     uint32_t left_word; | ||||||
|  |     uint32_t right_word; | ||||||
|  |      | ||||||
|  |     __asm__ volatile ( | ||||||
|  |         ".syntax unified \n\t" | ||||||
|  |         "1: \n\t" | ||||||
|  |         "ldmia %[lptr]!, {%[left]} \n\t"  /* Load left word. */ | ||||||
|  |         "ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */ | ||||||
|  |         "lsrs %[carry], #1 \n\t"          /* Set up carry flag (carry = 0 after this). */ | ||||||
|  |         "adcs %[left], %[left], %[right] \n\t"   /* Add with carry. */ | ||||||
|  |         "adcs %[carry], %[carry], %[carry] \n\t" /* Store carry bit. */ | ||||||
|  |         "stmia %[dptr]!, {%[left]} \n\t"  /* Store result word. */ | ||||||
|  |         "subs %[ctr], #1 \n\t"            /* Decrement counter. */ | ||||||
|  |         "bne 1b \n\t"                     /* Loop until counter == 0. */ | ||||||
|  |         RESUME_SYNTAX | ||||||
|  |         : [dptr] REG_RW (result), [lptr] REG_RW (left), [rptr] REG_RW (right), | ||||||
|  |           [ctr] REG_RW (num_words), [carry] REG_RW (carry), | ||||||
|  |           [left] REG_WRITE (left_word), [right] REG_WRITE (right_word) | ||||||
|  |         : | ||||||
|  |         : "cc", "memory" | ||||||
|  |     ); | ||||||
|  |     return carry; | ||||||
|  | } | ||||||
|  | #define asm_add 1
 | ||||||
|  | #endif
 | ||||||
|  | 
 | ||||||
|  | #if !asm_sub
 | ||||||
|  | uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result, | ||||||
|  |                                       const uECC_word_t *left, | ||||||
|  |                                       const uECC_word_t *right, | ||||||
|  |                                       wordcount_t num_words) { | ||||||
|  |     uint32_t carry = 1; /* carry = 1 initially (means don't borrow) */ | ||||||
|  |     uint32_t left_word; | ||||||
|  |     uint32_t right_word; | ||||||
|  |      | ||||||
|  |     __asm__ volatile ( | ||||||
|  |         ".syntax unified \n\t" | ||||||
|  |         "1: \n\t" | ||||||
|  |         "ldmia %[lptr]!, {%[left]} \n\t"  /* Load left word. */ | ||||||
|  |         "ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */ | ||||||
|  |         "lsrs %[carry], #1 \n\t"          /* Set up carry flag (carry = 0 after this). */ | ||||||
|  |         "sbcs %[left], %[left], %[right] \n\t"   /* Subtract with borrow. */ | ||||||
|  |         "adcs %[carry], %[carry], %[carry] \n\t" /* Store carry bit. */ | ||||||
|  |         "stmia %[dptr]!, {%[left]} \n\t"  /* Store result word. */ | ||||||
|  |         "subs %[ctr], #1 \n\t"            /* Decrement counter. */ | ||||||
|  |         "bne 1b \n\t"                     /* Loop until counter == 0. */ | ||||||
|  |         RESUME_SYNTAX | ||||||
|  |         : [dptr] REG_RW (result), [lptr] REG_RW (left), [rptr] REG_RW (right), | ||||||
|  |           [ctr] REG_RW (num_words), [carry] REG_RW (carry), | ||||||
|  |           [left] REG_WRITE (left_word), [right] REG_WRITE (right_word) | ||||||
|  |         : | ||||||
|  |         : "cc", "memory" | ||||||
|  |     ); | ||||||
|  |     return !carry; | ||||||
|  | } | ||||||
|  | #define asm_sub 1
 | ||||||
|  | #endif
 | ||||||
|  | 
 | ||||||
|  | #if !asm_mult
 | ||||||
|  | uECC_VLI_API void uECC_vli_mult(uECC_word_t *result, | ||||||
|  |                                 const uECC_word_t *left, | ||||||
|  |                                 const uECC_word_t *right, | ||||||
|  |                                 wordcount_t num_words) { | ||||||
|  | #if (uECC_PLATFORM != uECC_arm_thumb)
 | ||||||
|  |     uint32_t c0 = 0; | ||||||
|  |     uint32_t c1 = 0; | ||||||
|  |     uint32_t c2 = 0; | ||||||
|  |     uint32_t k = 0; | ||||||
|  |     uint32_t i; | ||||||
|  |     uint32_t t0, t1; | ||||||
|  |      | ||||||
|  |     __asm__ volatile ( | ||||||
|  |         ".syntax unified \n\t" | ||||||
|  |          | ||||||
|  |         "1: \n\t" /* outer loop (k < num_words) */ | ||||||
|  |         "movs %[i], #0 \n\t" /* i = 0 */ | ||||||
|  |         "b 3f \n\t" | ||||||
|  |          | ||||||
|  |         "2: \n\t" /* outer loop (k >= num_words) */ | ||||||
|  |         "movs %[i], %[k] \n\t"         /* i = k */ | ||||||
|  |         "subs %[i], %[last_word] \n\t" /* i = k - (num_words - 1) (times 4) */ | ||||||
|  |          | ||||||
|  |         "3: \n\t" /* inner loop */ | ||||||
|  |         "subs %[t0], %[k], %[i] \n\t" /* t0 = k-i */ | ||||||
|  |          | ||||||
|  |         "ldr %[t1], [%[right], %[t0]] \n\t" /* t1 = right[k - i] */ | ||||||
|  |         "ldr %[t0], [%[left], %[i]] \n\t"   /* t0 = left[i] */ | ||||||
|  |          | ||||||
|  |         "umull %[t0], %[t1], %[t0], %[t1] \n\t" /* (t0, t1) = left[i] * right[k - i] */ | ||||||
|  |          | ||||||
|  |         "adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */ | ||||||
|  |         "adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */ | ||||||
|  |         "adcs %[c2], %[c2], #0 \n\t"    /* add carry to c2 */ | ||||||
|  | 
 | ||||||
|  |         "adds %[i], #4 \n\t"          /* i += 4 */ | ||||||
|  |         "cmp %[i], %[last_word] \n\t" /* i > (num_words - 1) (times 4)? */ | ||||||
|  |         "bgt 4f \n\t"                 /*   if so, exit the loop */ | ||||||
|  |         "cmp %[i], %[k] \n\t"         /* i <= k? */ | ||||||
|  |         "ble 3b \n\t"                 /*   if so, continue looping */ | ||||||
|  |          | ||||||
|  |         "4: \n\t" /* end inner loop */ | ||||||
|  |          | ||||||
|  |         "str %[c0], [%[result], %[k]] \n\t" /* result[k] = c0 */ | ||||||
|  |         "mov %[c0], %[c1] \n\t"       /* c0 = c1 */ | ||||||
|  |         "mov %[c1], %[c2] \n\t"       /* c1 = c2 */ | ||||||
|  |         "movs %[c2], #0 \n\t"         /* c2 = 0 */ | ||||||
|  |         "adds %[k], #4 \n\t"          /* k += 4 */ | ||||||
|  |         "cmp %[k], %[last_word] \n\t" /* k <= (num_words - 1) (times 4) ? */ | ||||||
|  |         "ble 1b \n\t"                 /*   if so, loop back, start with i = 0 */ | ||||||
|  |         "cmp %[k], %[last_word], lsl #1 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */ | ||||||
|  |         "ble 2b \n\t"                 /*   if so, loop back, start with i = (k + 1) - num_words */ | ||||||
|  |         /* end outer loop */ | ||||||
|  |          | ||||||
|  |         "str %[c0], [%[result], %[k]] \n\t" /* result[num_words * 2 - 1] = c0 */ | ||||||
|  |         RESUME_SYNTAX | ||||||
|  |         : [c0] "+r" (c0), [c1] "+r" (c1), [c2] "+r" (c2), | ||||||
|  |           [k] "+r" (k), [i] "=&r" (i), [t0] "=&r" (t0), [t1] "=&r" (t1) | ||||||
|  |         : [result] "r" (result), [left] "r" (left), [right] "r" (right), | ||||||
|  |           [last_word] "r" ((num_words - 1) * 4) | ||||||
|  |         : "cc", "memory" | ||||||
|  |     ); | ||||||
|  |      | ||||||
|  | #else /* Thumb-1 */
 | ||||||
|  |     uint32_t r4, r5, r6, r7; | ||||||
|  | 
 | ||||||
|  |     __asm__ volatile ( | ||||||
|  |         ".syntax unified \n\t" | ||||||
|  |         "subs %[r3], #1 \n\t" /* r3 = num_words - 1 */ | ||||||
|  |         "lsls %[r3], #2 \n\t" /* r3 = (num_words - 1) * 4 */ | ||||||
|  |         "mov r8, %[r3] \n\t"  /* r8 = (num_words - 1) * 4 */ | ||||||
|  |         "lsls %[r3], #1 \n\t" /* r3 = (num_words - 1) * 8 */ | ||||||
|  |         "mov r9, %[r3] \n\t"  /* r9 = (num_words - 1) * 8 */ | ||||||
|  |         "movs %[r3], #0 \n\t" /* c0 = 0 */ | ||||||
|  |         "movs %[r4], #0 \n\t" /* c1 = 0 */ | ||||||
|  |         "movs %[r5], #0 \n\t" /* c2 = 0 */ | ||||||
|  |         "movs %[r6], #0 \n\t" /* k = 0 */ | ||||||
|  |          | ||||||
|  |         "push {%[r0]} \n\t" /* keep result on the stack */ | ||||||
|  |          | ||||||
|  |         "1: \n\t" /* outer loop (k < num_words) */ | ||||||
|  |         "movs %[r7], #0 \n\t" /* r7 = i = 0 */ | ||||||
|  |         "b 3f \n\t" | ||||||
|  |          | ||||||
|  |         "2: \n\t" /* outer loop (k >= num_words) */ | ||||||
|  |         "movs %[r7], %[r6] \n\t" /* r7 = k */ | ||||||
|  |         "mov %[r0], r8 \n\t"     /* r0 = (num_words - 1) * 4 */ | ||||||
|  |         "subs %[r7], %[r0] \n\t" /* r7 = i = k - (num_words - 1) (times 4) */ | ||||||
|  |          | ||||||
|  |         "3: \n\t" /* inner loop */ | ||||||
|  |         "mov r10, %[r3] \n\t" | ||||||
|  |         "mov r11, %[r4] \n\t" | ||||||
|  |         "mov r12, %[r5] \n\t" | ||||||
|  |         "mov r14, %[r6] \n\t" | ||||||
|  |         "subs %[r0], %[r6], %[r7] \n\t"          /* r0 = k - i */ | ||||||
|  |          | ||||||
|  |         "ldr %[r4], [%[r2], %[r0]] \n\t" /* r4 = right[k - i] */ | ||||||
|  |         "ldr %[r0], [%[r1], %[r7]] \n\t" /* r0 = left[i] */ | ||||||
|  |          | ||||||
|  |         "lsrs %[r3], %[r0], #16 \n\t" /* r3 = a1 */ | ||||||
|  |         "uxth %[r0], %[r0] \n\t"      /* r0 = a0 */ | ||||||
|  |          | ||||||
|  |         "lsrs %[r5], %[r4], #16 \n\t" /* r5 = b1 */ | ||||||
|  |         "uxth %[r4], %[r4] \n\t"      /* r4 = b0 */ | ||||||
|  |          | ||||||
|  |         "movs %[r6], %[r3] \n\t"        /* r6 = a1 */ | ||||||
|  |         "muls %[r6], %[r5], %[r6] \n\t" /* r6 = a1 * b1 */ | ||||||
|  |         "muls %[r3], %[r4], %[r3] \n\t" /* r3 = b0 * a1 */ | ||||||
|  |         "muls %[r5], %[r0], %[r5] \n\t" /* r5 = a0 * b1 */ | ||||||
|  |         "muls %[r0], %[r4], %[r0] \n\t" /* r0 = a0 * b0 */ | ||||||
|  |          | ||||||
|  |         /* Add middle terms */ | ||||||
|  |         "lsls %[r4], %[r3], #16 \n\t" | ||||||
|  |         "lsrs %[r3], %[r3], #16 \n\t" | ||||||
|  |         "adds %[r0], %[r4] \n\t" | ||||||
|  |         "adcs %[r6], %[r3] \n\t" | ||||||
|  |          | ||||||
|  |         "lsls %[r4], %[r5], #16 \n\t" | ||||||
|  |         "lsrs %[r5], %[r5], #16 \n\t" | ||||||
|  |         "adds %[r0], %[r4] \n\t" | ||||||
|  |         "adcs %[r6], %[r5] \n\t" | ||||||
|  |          | ||||||
|  |         "mov %[r3], r10\n\t" | ||||||
|  |         "mov %[r4], r11\n\t" | ||||||
|  |         "mov %[r5], r12\n\t" | ||||||
|  |         "adds %[r3], %[r0] \n\t"         /* add low word to c0 */ | ||||||
|  |         "adcs %[r4], %[r6] \n\t"         /* add high word to c1, including carry */ | ||||||
|  |         "movs %[r0], #0 \n\t"            /* r0 = 0 (does not affect carry bit) */ | ||||||
|  |         "adcs %[r5], %[r0] \n\t"         /* add carry to c2 */ | ||||||
|  |          | ||||||
|  |         "mov %[r6], r14\n\t" /* r6 = k */ | ||||||
|  | 
 | ||||||
|  |         "adds %[r7], #4 \n\t"   /* i += 4 */ | ||||||
|  |         "cmp %[r7], r8 \n\t"    /* i > (num_words - 1) (times 4)? */ | ||||||
|  |         "bgt 4f \n\t"           /*   if so, exit the loop */ | ||||||
|  |         "cmp %[r7], %[r6] \n\t" /* i <= k? */ | ||||||
|  |         "ble 3b \n\t"           /*   if so, continue looping */ | ||||||
|  |          | ||||||
|  |         "4: \n\t" /* end inner loop */ | ||||||
|  |          | ||||||
|  |         "ldr %[r0], [sp, #0] \n\t" /* r0 = result */ | ||||||
|  |          | ||||||
|  |         "str %[r3], [%[r0], %[r6]] \n\t" /* result[k] = c0 */ | ||||||
|  |         "mov %[r3], %[r4] \n\t"          /* c0 = c1 */ | ||||||
|  |         "mov %[r4], %[r5] \n\t"          /* c1 = c2 */ | ||||||
|  |         "movs %[r5], #0 \n\t"            /* c2 = 0 */ | ||||||
|  |         "adds %[r6], #4 \n\t"            /* k += 4 */ | ||||||
|  |         "cmp %[r6], r8 \n\t"             /* k <= (num_words - 1) (times 4) ? */ | ||||||
|  |         "ble 1b \n\t"                    /*   if so, loop back, start with i = 0 */ | ||||||
|  |         "cmp %[r6], r9 \n\t"             /* k <= (num_words * 2 - 2) (times 4) ? */ | ||||||
|  |         "ble 2b \n\t"                    /*   if so, loop back, with i = (k + 1) - num_words */ | ||||||
|  |         /* end outer loop */ | ||||||
|  |          | ||||||
|  |         "str %[r3], [%[r0], %[r6]] \n\t" /* result[num_words * 2 - 1] = c0 */ | ||||||
|  |         "pop {%[r0]} \n\t"               /* pop result off the stack */ | ||||||
|  |          | ||||||
|  |         ".syntax divided \n\t" | ||||||
|  |         : [r3] "+l" (num_words), [r4] "=&l" (r4), | ||||||
|  |           [r5] "=&l" (r5), [r6] "=&l" (r6), [r7] "=&l" (r7) | ||||||
|  |         : [r0] "l" (result), [r1] "l" (left), [r2] "l" (right) | ||||||
|  |         : "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" | ||||||
|  |     ); | ||||||
|  | #endif
 | ||||||
|  | } | ||||||
|  | #define asm_mult 1
 | ||||||
|  | #endif
 | ||||||
|  | 
 | ||||||
|  | #if uECC_SQUARE_FUNC
 | ||||||
|  | #if !asm_square
 | ||||||
|  | uECC_VLI_API void uECC_vli_square(uECC_word_t *result, | ||||||
|  |                                   const uECC_word_t *left, | ||||||
|  |                                   wordcount_t num_words) { | ||||||
|  | #if (uECC_PLATFORM != uECC_arm_thumb)
 | ||||||
|  |     uint32_t c0 = 0; | ||||||
|  |     uint32_t c1 = 0; | ||||||
|  |     uint32_t c2 = 0; | ||||||
|  |     uint32_t k = 0; | ||||||
|  |     uint32_t i, tt; | ||||||
|  |     uint32_t t0, t1; | ||||||
|  |      | ||||||
|  |     __asm__ volatile ( | ||||||
|  |         ".syntax unified \n\t" | ||||||
|  |          | ||||||
|  |         "1: \n\t" /* outer loop (k < num_words) */ | ||||||
|  |         "movs %[i], #0 \n\t" /* i = 0 */ | ||||||
|  |         "b 3f \n\t" | ||||||
|  |          | ||||||
|  |         "2: \n\t" /* outer loop (k >= num_words) */ | ||||||
|  |         "movs %[i], %[k] \n\t"         /* i = k */ | ||||||
|  |         "subs %[i], %[last_word] \n\t" /* i = k - (num_words - 1) (times 4) */ | ||||||
|  |          | ||||||
|  |         "3: \n\t" /* inner loop */ | ||||||
|  |         "subs %[tt], %[k], %[i] \n\t" /* tt = k-i */ | ||||||
|  |          | ||||||
|  |         "ldr %[t1], [%[left], %[tt]] \n\t" /* t1 = left[k - i] */ | ||||||
|  |         "ldr %[t0], [%[left], %[i]] \n\t"  /* t0 = left[i] */ | ||||||
|  |          | ||||||
|  |         "umull %[t0], %[t1], %[t0], %[t1] \n\t" /* (t0, t1) = left[i] * right[k - i] */ | ||||||
|  |          | ||||||
|  |         "cmp %[i], %[tt] \n\t"      /* (i < k - i) ? */ | ||||||
|  |         "bge 4f \n\t"               /*   if i >= k - i, skip */ | ||||||
|  |         "adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */ | ||||||
|  |         "adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */ | ||||||
|  |         "adcs %[c2], %[c2], #0 \n\t"    /* add carry to c2 */ | ||||||
|  |          | ||||||
|  |         "4: \n\t" | ||||||
|  |         "adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */ | ||||||
|  |         "adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */ | ||||||
|  |         "adcs %[c2], %[c2], #0 \n\t"    /* add carry to c2 */ | ||||||
|  |          | ||||||
|  |         "adds %[i], #4 \n\t"          /* i += 4 */ | ||||||
|  |         "cmp %[i], %[k] \n\t"         /* i >= k? */ | ||||||
|  |         "bge 5f \n\t"                 /*   if so, exit the loop */ | ||||||
|  |         "subs %[tt], %[k], %[i] \n\t" /* tt = k - i */ | ||||||
|  |         "cmp %[i], %[tt] \n\t"        /* i <= k - i? */ | ||||||
|  |         "ble 3b \n\t"                 /*   if so, continue looping */ | ||||||
|  |          | ||||||
|  |         "5: \n\t" /* end inner loop */ | ||||||
|  |          | ||||||
|  |         "str %[c0], [%[result], %[k]] \n\t" /* result[k] = c0 */ | ||||||
|  |         "mov %[c0], %[c1] \n\t"       /* c0 = c1 */ | ||||||
|  |         "mov %[c1], %[c2] \n\t"       /* c1 = c2 */ | ||||||
|  |         "movs %[c2], #0 \n\t"         /* c2 = 0 */ | ||||||
|  |         "adds %[k], #4 \n\t"          /* k += 4 */ | ||||||
|  |         "cmp %[k], %[last_word] \n\t" /* k <= (num_words - 1) (times 4) ? */ | ||||||
|  |         "ble 1b \n\t"                 /*   if so, loop back, start with i = 0 */ | ||||||
|  |         "cmp %[k], %[last_word], lsl #1 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */ | ||||||
|  |         "ble 2b \n\t"                 /*   if so, loop back, start with i = (k + 1) - num_words */ | ||||||
|  |         /* end outer loop */ | ||||||
|  |          | ||||||
|  |         "str %[c0], [%[result], %[k]] \n\t" /* result[num_words * 2 - 1] = c0 */ | ||||||
|  |         RESUME_SYNTAX | ||||||
|  |         : [c0] "+r" (c0), [c1] "+r" (c1), [c2] "+r" (c2), | ||||||
|  |           [k] "+r" (k), [i] "=&r" (i), [tt] "=&r" (tt), [t0] "=&r" (t0), [t1] "=&r" (t1) | ||||||
|  |         : [result] "r" (result), [left] "r" (left), [last_word] "r" ((num_words - 1) * 4) | ||||||
|  |         : "cc", "memory" | ||||||
|  |     ); | ||||||
|  |      | ||||||
|  | #else
 | ||||||
|  |     uint32_t r3, r4, r5, r6, r7; | ||||||
|  | 
 | ||||||
|  |     __asm__ volatile ( | ||||||
|  |         ".syntax unified \n\t" | ||||||
|  |         "subs %[r2], #1 \n\t" /* r2 = num_words - 1 */ | ||||||
|  |         "lsls %[r2], #2 \n\t" /* r2 = (num_words - 1) * 4 */ | ||||||
|  |         "mov r8, %[r2] \n\t"  /* r8 = (num_words - 1) * 4 */ | ||||||
|  |         "lsls %[r2], #1 \n\t" /* r2 = (num_words - 1) * 8 */ | ||||||
|  |         "mov r9, %[r2] \n\t"  /* r9 = (num_words - 1) * 8 */ | ||||||
|  |         "movs %[r2], #0 \n\t" /* c0 = 0 */ | ||||||
|  |         "movs %[r3], #0 \n\t" /* c1 = 0 */ | ||||||
|  |         "movs %[r4], #0 \n\t" /* c2 = 0 */ | ||||||
|  |         "movs %[r5], #0 \n\t" /* k = 0 */ | ||||||
|  |          | ||||||
|  |         "push {%[r0]} \n\t" /* keep result on the stack */ | ||||||
|  |          | ||||||
|  |         "1: \n\t" /* outer loop (k < num_words) */ | ||||||
|  |         "movs %[r6], #0 \n\t" /* r6 = i = 0 */ | ||||||
|  |         "b 3f \n\t" | ||||||
|  |          | ||||||
|  |         "2: \n\t" /* outer loop (k >= num_words) */ | ||||||
|  |         "movs %[r6], %[r5] \n\t" /* r6 = k */ | ||||||
|  |         "mov %[r0], r8 \n\t"     /* r0 = (num_words - 1) * 4 */ | ||||||
|  |         "subs %[r6], %[r0] \n\t" /* r6 = i = k - (num_words - 1) (times 4) */ | ||||||
|  |          | ||||||
|  |         "3: \n\t" /* inner loop */ | ||||||
|  |         "mov r10, %[r2] \n\t" | ||||||
|  |         "mov r11, %[r3] \n\t" | ||||||
|  |         "mov r12, %[r4] \n\t" | ||||||
|  |         "mov r14, %[r5] \n\t" | ||||||
|  |         "subs %[r7], %[r5], %[r6] \n\t"  /* r7 = k - i */ | ||||||
|  |          | ||||||
|  |         "ldr %[r3], [%[r1], %[r7]] \n\t" /* r3 = left[k - i] */ | ||||||
|  |         "ldr %[r0], [%[r1], %[r6]] \n\t" /* r0 = left[i] */ | ||||||
|  |          | ||||||
|  |         "lsrs %[r2], %[r0], #16 \n\t" /* r2 = a1 */ | ||||||
|  |         "uxth %[r0], %[r0] \n\t"      /* r0 = a0 */ | ||||||
|  |          | ||||||
|  |         "lsrs %[r4], %[r3], #16 \n\t" /* r4 = b1 */ | ||||||
|  |         "uxth %[r3], %[r3] \n\t"      /* r3 = b0 */ | ||||||
|  |          | ||||||
|  |         "movs %[r5], %[r2] \n\t"        /* r5 = a1 */ | ||||||
|  |         "muls %[r5], %[r4], %[r5] \n\t" /* r5 = a1 * b1 */ | ||||||
|  |         "muls %[r2], %[r3], %[r2] \n\t" /* r2 = b0 * a1 */ | ||||||
|  |         "muls %[r4], %[r0], %[r4] \n\t" /* r4 = a0 * b1 */ | ||||||
|  |         "muls %[r0], %[r3], %[r0] \n\t" /* r0 = a0 * b0 */ | ||||||
|  |          | ||||||
|  |         /* Add middle terms */ | ||||||
|  |         "lsls %[r3], %[r2], #16 \n\t" | ||||||
|  |         "lsrs %[r2], %[r2], #16 \n\t" | ||||||
|  |         "adds %[r0], %[r3] \n\t" | ||||||
|  |         "adcs %[r5], %[r2] \n\t" | ||||||
|  |          | ||||||
|  |         "lsls %[r3], %[r4], #16 \n\t" | ||||||
|  |         "lsrs %[r4], %[r4], #16 \n\t" | ||||||
|  |         "adds %[r0], %[r3] \n\t" | ||||||
|  |         "adcs %[r5], %[r4] \n\t" | ||||||
|  |          | ||||||
|  |         /* Add to acc, doubling if necessary */ | ||||||
|  |         "mov %[r2], r10\n\t" | ||||||
|  |         "mov %[r3], r11\n\t" | ||||||
|  |         "mov %[r4], r12\n\t" | ||||||
|  |          | ||||||
|  |         "cmp %[r6], %[r7] \n\t"    /* (i < k - i) ? */ | ||||||
|  |         "bge 4f \n\t"            /*   if i >= k - i, skip */ | ||||||
|  |         "movs %[r7], #0 \n\t"    /* r7 = 0 */ | ||||||
|  |         "adds %[r2], %[r0] \n\t" /* add low word to c0 */ | ||||||
|  |         "adcs %[r3], %[r5] \n\t" /* add high word to c1, including carry */ | ||||||
|  |         "adcs %[r4], %[r7] \n\t" /* add carry to c2 */ | ||||||
|  |         "4: \n\t" | ||||||
|  |         "movs %[r7], #0 \n\t"    /* r7 = 0 */ | ||||||
|  |         "adds %[r2], %[r0] \n\t" /* add low word to c0 */ | ||||||
|  |         "adcs %[r3], %[r5] \n\t" /* add high word to c1, including carry */ | ||||||
|  |         "adcs %[r4], %[r7] \n\t" /* add carry to c2 */ | ||||||
|  |          | ||||||
|  |         "mov %[r5], r14\n\t" /* r5 = k */ | ||||||
|  |          | ||||||
|  |         "adds %[r6], #4 \n\t"           /* i += 4 */ | ||||||
|  |         "cmp %[r6], %[r5] \n\t"         /* i >= k? */ | ||||||
|  |         "bge 5f \n\t"                   /*   if so, exit the loop */ | ||||||
|  |         "subs %[r7], %[r5], %[r6] \n\t" /* r7 = k - i */ | ||||||
|  |         "cmp %[r6], %[r7] \n\t"         /* i <= k - i? */ | ||||||
|  |         "ble 3b \n\t"                   /*   if so, continue looping */ | ||||||
|  |          | ||||||
|  |         "5: \n\t" /* end inner loop */ | ||||||
|  |          | ||||||
|  |         "ldr %[r0], [sp, #0] \n\t" /* r0 = result */ | ||||||
|  |          | ||||||
|  |         "str %[r2], [%[r0], %[r5]] \n\t" /* result[k] = c0 */ | ||||||
|  |         "mov %[r2], %[r3] \n\t"          /* c0 = c1 */ | ||||||
|  |         "mov %[r3], %[r4] \n\t"          /* c1 = c2 */ | ||||||
|  |         "movs %[r4], #0 \n\t"            /* c2 = 0 */ | ||||||
|  |         "adds %[r5], #4 \n\t"            /* k += 4 */ | ||||||
|  |         "cmp %[r5], r8 \n\t"             /* k <= (num_words - 1) (times 4) ? */ | ||||||
|  |         "ble 1b \n\t"                    /*   if so, loop back, start with i = 0 */ | ||||||
|  |         "cmp %[r5], r9 \n\t"             /* k <= (num_words * 2 - 2) (times 4) ? */ | ||||||
|  |         "ble 2b \n\t"                    /*   if so, loop back, with i = (k + 1) - num_words */ | ||||||
|  |         /* end outer loop */ | ||||||
|  |          | ||||||
|  |         "str %[r2], [%[r0], %[r5]] \n\t" /* result[num_words * 2 - 1] = c0 */ | ||||||
|  |         "pop {%[r0]} \n\t"               /* pop result off the stack */ | ||||||
|  | 
 | ||||||
|  |         ".syntax divided \n\t" | ||||||
|  |         : [r2] "+l" (num_words), [r3] "=&l" (r3), [r4] "=&l" (r4), | ||||||
|  |           [r5] "=&l" (r5), [r6] "=&l" (r6), [r7] "=&l" (r7) | ||||||
|  |         : [r0] "l" (result), [r1] "l" (left) | ||||||
|  |         : "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" | ||||||
|  |     ); | ||||||
|  | #endif
 | ||||||
|  | } | ||||||
|  | #define asm_square 1
 | ||||||
|  | #endif
 | ||||||
|  | #endif /* uECC_SQUARE_FUNC */
 | ||||||
|  | 
 | ||||||
|  | #endif /* _UECC_ASM_ARM_H_ */
 | ||||||
							
								
								
									
										2311
									
								
								lib/micro-ecc/asm_arm_mult_square.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2311
									
								
								lib/micro-ecc/asm_arm_mult_square.inc
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1202
									
								
								lib/micro-ecc/asm_arm_mult_square_umaal.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1202
									
								
								lib/micro-ecc/asm_arm_mult_square_umaal.inc
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1248
									
								
								lib/micro-ecc/curve-specific.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1248
									
								
								lib/micro-ecc/curve-specific.inc
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										94
									
								
								lib/micro-ecc/platform-specific.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								lib/micro-ecc/platform-specific.inc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,94 @@ | |||||||
|  | /* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ | ||||||
|  | 
 | ||||||
|  | #ifndef _UECC_PLATFORM_SPECIFIC_H_
 | ||||||
|  | #define _UECC_PLATFORM_SPECIFIC_H_
 | ||||||
|  | 
 | ||||||
|  | #include "types.h"
 | ||||||
|  | 
 | ||||||
|  | #if (defined(_WIN32) || defined(_WIN64))
 | ||||||
|  | /* Windows */ | ||||||
|  | 
 | ||||||
|  | // use pragma syntax to prevent tweaking the linker script for getting CryptXYZ function
 | ||||||
|  | #pragma comment(lib, "crypt32.lib")
 | ||||||
|  | #pragma comment(lib, "advapi32.lib")
 | ||||||
|  | 
 | ||||||
|  | #define WIN32_LEAN_AND_MEAN
 | ||||||
|  | #include <windows.h>
 | ||||||
|  | #include <wincrypt.h>
 | ||||||
|  | 
 | ||||||
|  | static int default_RNG(uint8_t *dest, unsigned size) { | ||||||
|  |     HCRYPTPROV prov; | ||||||
|  |     if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     CryptGenRandom(prov, size, (BYTE *)dest); | ||||||
|  |     CryptReleaseContext(prov, 0); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | #define default_RNG_defined 1
 | ||||||
|  | 
 | ||||||
|  | #elif defined(unix) || defined(__linux__) || defined(__unix__) || defined(__unix) || \
 | ||||||
|  |     (defined(__APPLE__) && defined(__MACH__)) || defined(uECC_POSIX) | ||||||
|  | 
 | ||||||
|  | /* Some POSIX-like system with /dev/urandom or /dev/random. */ | ||||||
|  | #include <sys/types.h>
 | ||||||
|  | #include <fcntl.h>
 | ||||||
|  | #include <unistd.h>
 | ||||||
|  | 
 | ||||||
|  | #ifndef O_CLOEXEC
 | ||||||
|  |     #define O_CLOEXEC 0
 | ||||||
|  | #endif
 | ||||||
|  | 
 | ||||||
|  | static int default_RNG(uint8_t *dest, unsigned size) { | ||||||
|  |     int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); | ||||||
|  |     if (fd == -1) { | ||||||
|  |         fd = open("/dev/random", O_RDONLY | O_CLOEXEC); | ||||||
|  |         if (fd == -1) { | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     char *ptr = (char *)dest; | ||||||
|  |     size_t left = size; | ||||||
|  |     while (left > 0) { | ||||||
|  |         ssize_t bytes_read = read(fd, ptr, left); | ||||||
|  |         if (bytes_read <= 0) { // read failed
 | ||||||
|  |             close(fd); | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  |         left -= bytes_read; | ||||||
|  |         ptr += bytes_read; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     close(fd); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | #define default_RNG_defined 1
 | ||||||
|  | 
 | ||||||
|  | #elif defined(RIOT_VERSION)
 | ||||||
|  | 
 | ||||||
|  | #include <random.h>
 | ||||||
|  | 
 | ||||||
|  | static int default_RNG(uint8_t *dest, unsigned size) { | ||||||
|  |     random_bytes(dest, size); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | #define default_RNG_defined 1
 | ||||||
|  | 
 | ||||||
|  | #elif defined(NRF52_SERIES)
 | ||||||
|  | 
 | ||||||
|  | #include "app_error.h"
 | ||||||
|  | #include "nrf_crypto_rng.h"
 | ||||||
|  | 
 | ||||||
|  | static int default_RNG(uint8_t *dest, unsigned size)  | ||||||
|  | { | ||||||
|  |     // make sure to call nrf_crypto_init and nrf_crypto_rng_init first
 | ||||||
|  |     ret_code_t ret_code = nrf_crypto_rng_vector_generate(dest, size); | ||||||
|  |     return (ret_code == NRF_SUCCESS) ? 1 : 0; | ||||||
|  | } | ||||||
|  | #define default_RNG_defined 1
 | ||||||
|  | 
 | ||||||
|  | #endif /* platform */
 | ||||||
|  | 
 | ||||||
|  | #endif /* _UECC_PLATFORM_SPECIFIC_H_ */
 | ||||||
							
								
								
									
										108
									
								
								lib/micro-ecc/types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								lib/micro-ecc/types.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,108 @@ | |||||||
|  | /* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ | ||||||
|  | 
 | ||||||
|  | #ifndef _UECC_TYPES_H_ | ||||||
|  | #define _UECC_TYPES_H_ | ||||||
|  | 
 | ||||||
|  | #ifndef uECC_PLATFORM | ||||||
|  |     #if __AVR__ | ||||||
|  |         #define uECC_PLATFORM uECC_avr | ||||||
|  |     #elif defined(__thumb2__) || defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */ | ||||||
|  |         #define uECC_PLATFORM uECC_arm_thumb2 | ||||||
|  |     #elif defined(__thumb__) | ||||||
|  |         #define uECC_PLATFORM uECC_arm_thumb | ||||||
|  |     #elif defined(__arm__) || defined(_M_ARM) | ||||||
|  |         #define uECC_PLATFORM uECC_arm | ||||||
|  |     #elif defined(__aarch64__) | ||||||
|  |         #define uECC_PLATFORM uECC_arm64 | ||||||
|  |     #elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__I86__) | ||||||
|  |         #define uECC_PLATFORM uECC_x86 | ||||||
|  |     #elif defined(__amd64__) || defined(_M_X64) | ||||||
|  |         #define uECC_PLATFORM uECC_x86_64 | ||||||
|  |     #else | ||||||
|  |         #define uECC_PLATFORM uECC_arch_other | ||||||
|  |     #endif | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef uECC_ARM_USE_UMAAL | ||||||
|  |     #if (uECC_PLATFORM == uECC_arm) && (__ARM_ARCH >= 6) | ||||||
|  |         #define uECC_ARM_USE_UMAAL 1 | ||||||
|  |     #elif (uECC_PLATFORM == uECC_arm_thumb2) && (__ARM_ARCH >= 6) && !__ARM_ARCH_7M__ | ||||||
|  |         #define uECC_ARM_USE_UMAAL 1 | ||||||
|  |     #else | ||||||
|  |         #define uECC_ARM_USE_UMAAL 0 | ||||||
|  |     #endif | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef uECC_WORD_SIZE | ||||||
|  |     #if uECC_PLATFORM == uECC_avr | ||||||
|  |         #define uECC_WORD_SIZE 1 | ||||||
|  |     #elif (uECC_PLATFORM == uECC_x86_64 || uECC_PLATFORM == uECC_arm64) | ||||||
|  |         #define uECC_WORD_SIZE 8 | ||||||
|  |     #else | ||||||
|  |         #define uECC_WORD_SIZE 4 | ||||||
|  |     #endif | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if (uECC_WORD_SIZE != 1) && (uECC_WORD_SIZE != 4) && (uECC_WORD_SIZE != 8) | ||||||
|  |     #error "Unsupported value for uECC_WORD_SIZE" | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if ((uECC_PLATFORM == uECC_avr) && (uECC_WORD_SIZE != 1)) | ||||||
|  |     #pragma message ("uECC_WORD_SIZE must be 1 for AVR") | ||||||
|  |     #undef uECC_WORD_SIZE | ||||||
|  |     #define uECC_WORD_SIZE 1 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if ((uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \ | ||||||
|  |         uECC_PLATFORM ==  uECC_arm_thumb2) && \ | ||||||
|  |      (uECC_WORD_SIZE != 4)) | ||||||
|  |     #pragma message ("uECC_WORD_SIZE must be 4 for ARM") | ||||||
|  |     #undef uECC_WORD_SIZE | ||||||
|  |     #define uECC_WORD_SIZE 4 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if defined(__SIZEOF_INT128__) || ((__clang_major__ * 100 + __clang_minor__) >= 302) | ||||||
|  |     #define SUPPORTS_INT128 1 | ||||||
|  | #else | ||||||
|  |     #define SUPPORTS_INT128 0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | typedef int8_t wordcount_t; | ||||||
|  | typedef int16_t bitcount_t; | ||||||
|  | typedef int8_t cmpresult_t; | ||||||
|  | 
 | ||||||
|  | #if (uECC_WORD_SIZE == 1) | ||||||
|  | 
 | ||||||
|  | typedef uint8_t uECC_word_t; | ||||||
|  | typedef uint16_t uECC_dword_t; | ||||||
|  | 
 | ||||||
|  | #define HIGH_BIT_SET 0x80 | ||||||
|  | #define uECC_WORD_BITS 8 | ||||||
|  | #define uECC_WORD_BITS_SHIFT 3 | ||||||
|  | #define uECC_WORD_BITS_MASK 0x07 | ||||||
|  | 
 | ||||||
|  | #elif (uECC_WORD_SIZE == 4) | ||||||
|  | 
 | ||||||
|  | typedef uint32_t uECC_word_t; | ||||||
|  | typedef uint64_t uECC_dword_t; | ||||||
|  | 
 | ||||||
|  | #define HIGH_BIT_SET 0x80000000 | ||||||
|  | #define uECC_WORD_BITS 32 | ||||||
|  | #define uECC_WORD_BITS_SHIFT 5 | ||||||
|  | #define uECC_WORD_BITS_MASK 0x01F | ||||||
|  | 
 | ||||||
|  | #elif (uECC_WORD_SIZE == 8) | ||||||
|  | 
 | ||||||
|  | typedef uint64_t uECC_word_t; | ||||||
|  | #if SUPPORTS_INT128 | ||||||
|  | typedef unsigned __int128 uECC_dword_t; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #define HIGH_BIT_SET 0x8000000000000000ull | ||||||
|  | #define uECC_WORD_BITS 64 | ||||||
|  | #define uECC_WORD_BITS_SHIFT 6 | ||||||
|  | #define uECC_WORD_BITS_MASK 0x03F | ||||||
|  | 
 | ||||||
|  | #endif /* uECC_WORD_SIZE */ | ||||||
|  | 
 | ||||||
|  | #endif /* _UECC_TYPES_H_ */ | ||||||
							
								
								
									
										1669
									
								
								lib/micro-ecc/uECC.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1669
									
								
								lib/micro-ecc/uECC.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										367
									
								
								lib/micro-ecc/uECC.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										367
									
								
								lib/micro-ecc/uECC.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,367 @@ | |||||||
|  | /* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */ | ||||||
|  | 
 | ||||||
|  | #ifndef _UECC_H_ | ||||||
|  | #define _UECC_H_ | ||||||
|  | 
 | ||||||
|  | #include <stdint.h> | ||||||
|  | 
 | ||||||
|  | /* Platform selection options.
 | ||||||
|  | If uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros. | ||||||
|  | Possible values for uECC_PLATFORM are defined below: */ | ||||||
|  | #define uECC_arch_other 0 | ||||||
|  | #define uECC_x86        1 | ||||||
|  | #define uECC_x86_64     2 | ||||||
|  | #define uECC_arm        3 | ||||||
|  | #define uECC_arm_thumb  4 | ||||||
|  | #define uECC_arm_thumb2 5 | ||||||
|  | #define uECC_arm64      6 | ||||||
|  | #define uECC_avr        7 | ||||||
|  | 
 | ||||||
|  | /* If desired, you can define uECC_WORD_SIZE as appropriate for your platform (1, 4, or 8 bytes).
 | ||||||
|  | If uECC_WORD_SIZE is not explicitly defined then it will be automatically set based on your | ||||||
|  | platform. */ | ||||||
|  | 
 | ||||||
|  | /* Optimization level; trade speed for code size.
 | ||||||
|  |    Larger values produce code that is faster but larger. | ||||||
|  |    Currently supported values are 0 - 4; 0 is unusably slow for most applications. | ||||||
|  |    Optimization level 4 currently only has an effect ARM platforms where more than one | ||||||
|  |    curve is enabled. */ | ||||||
|  | #ifndef uECC_OPTIMIZATION_LEVEL | ||||||
|  |     #define uECC_OPTIMIZATION_LEVEL 2 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a specific function to be
 | ||||||
|  | used for (scalar) squaring instead of the generic multiplication function. This can make things | ||||||
|  | faster somewhat faster, but increases the code size. */ | ||||||
|  | #ifndef uECC_SQUARE_FUNC | ||||||
|  |     #define uECC_SQUARE_FUNC 0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* uECC_VLI_NATIVE_LITTLE_ENDIAN - If enabled (defined as nonzero), this will switch to native
 | ||||||
|  | little-endian format for *all* arrays passed in and out of the public API. This includes public | ||||||
|  | and private keys, shared secrets, signatures and message hashes. | ||||||
|  | Using this switch reduces the amount of call stack memory used by uECC, since less intermediate | ||||||
|  | translations are required. | ||||||
|  | Note that this will *only* work on native little-endian processors and it will treat the uint8_t | ||||||
|  | arrays passed into the public API as word arrays, therefore requiring the provided byte arrays | ||||||
|  | to be word aligned on architectures that do not support unaligned accesses. | ||||||
|  | IMPORTANT: Keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=1 are incompatible | ||||||
|  | with keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=0; all parties must use | ||||||
|  | the same endianness. */ | ||||||
|  | #ifndef uECC_VLI_NATIVE_LITTLE_ENDIAN | ||||||
|  |     #define uECC_VLI_NATIVE_LITTLE_ENDIAN 0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* Curve support selection. Set to 0 to remove that curve. */ | ||||||
|  | #ifndef uECC_SUPPORTS_secp160r1 | ||||||
|  |     #define uECC_SUPPORTS_secp160r1 1 | ||||||
|  | #endif | ||||||
|  | #ifndef uECC_SUPPORTS_secp192r1 | ||||||
|  |     #define uECC_SUPPORTS_secp192r1 1 | ||||||
|  | #endif | ||||||
|  | #ifndef uECC_SUPPORTS_secp224r1 | ||||||
|  |     #define uECC_SUPPORTS_secp224r1 1 | ||||||
|  | #endif | ||||||
|  | #ifndef uECC_SUPPORTS_secp256r1 | ||||||
|  |     #define uECC_SUPPORTS_secp256r1 1 | ||||||
|  | #endif | ||||||
|  | #ifndef uECC_SUPPORTS_secp256k1 | ||||||
|  |     #define uECC_SUPPORTS_secp256k1 1 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* Specifies whether compressed point format is supported.
 | ||||||
|  |    Set to 0 to disable point compression/decompression functions. */ | ||||||
|  | #ifndef uECC_SUPPORT_COMPRESSED_POINT | ||||||
|  |     #define uECC_SUPPORT_COMPRESSED_POINT 1 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | struct uECC_Curve_t; | ||||||
|  | typedef const struct uECC_Curve_t * uECC_Curve; | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" | ||||||
|  | { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if uECC_SUPPORTS_secp160r1 | ||||||
|  | uECC_Curve uECC_secp160r1(void); | ||||||
|  | #endif | ||||||
|  | #if uECC_SUPPORTS_secp192r1 | ||||||
|  | uECC_Curve uECC_secp192r1(void); | ||||||
|  | #endif | ||||||
|  | #if uECC_SUPPORTS_secp224r1 | ||||||
|  | uECC_Curve uECC_secp224r1(void); | ||||||
|  | #endif | ||||||
|  | #if uECC_SUPPORTS_secp256r1 | ||||||
|  | uECC_Curve uECC_secp256r1(void); | ||||||
|  | #endif | ||||||
|  | #if uECC_SUPPORTS_secp256k1 | ||||||
|  | uECC_Curve uECC_secp256k1(void); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* uECC_RNG_Function type
 | ||||||
|  | The RNG function should fill 'size' random bytes into 'dest'. It should return 1 if | ||||||
|  | 'dest' was filled with random data, or 0 if the random data could not be generated. | ||||||
|  | The filled-in values should be either truly random, or from a cryptographically-secure PRNG. | ||||||
|  | 
 | ||||||
|  | A correctly functioning RNG function must be set (using uECC_set_rng()) before calling | ||||||
|  | uECC_make_key() or uECC_sign(). | ||||||
|  | 
 | ||||||
|  | Setting a correctly functioning RNG function improves the resistance to side-channel attacks | ||||||
|  | for uECC_shared_secret() and uECC_sign_deterministic(). | ||||||
|  | 
 | ||||||
|  | A correct RNG function is set by default when building for Windows, Linux, or OS X. | ||||||
|  | If you are building on another POSIX-compliant system that supports /dev/random or /dev/urandom, | ||||||
|  | you can define uECC_POSIX to use the predefined RNG. For embedded platforms there is no predefined | ||||||
|  | RNG function; you must provide your own. | ||||||
|  | */ | ||||||
|  | typedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size); | ||||||
|  | 
 | ||||||
|  | /* uECC_set_rng() function.
 | ||||||
|  | Set the function that will be used to generate random bytes. The RNG function should | ||||||
|  | return 1 if the random data was generated, or 0 if the random data could not be generated. | ||||||
|  | 
 | ||||||
|  | On platforms where there is no predefined RNG function (eg embedded platforms), this must | ||||||
|  | be called before uECC_make_key() or uECC_sign() are used. | ||||||
|  | 
 | ||||||
|  | Inputs: | ||||||
|  |     rng_function - The function that will be used to generate random bytes. | ||||||
|  | */ | ||||||
|  | void uECC_set_rng(uECC_RNG_Function rng_function); | ||||||
|  | 
 | ||||||
|  | /* uECC_get_rng() function.
 | ||||||
|  | 
 | ||||||
|  | Returns the function that will be used to generate random bytes. | ||||||
|  | */ | ||||||
|  | uECC_RNG_Function uECC_get_rng(void); | ||||||
|  | 
 | ||||||
|  | /* uECC_curve_private_key_size() function.
 | ||||||
|  | 
 | ||||||
|  | Returns the size of a private key for the curve in bytes. | ||||||
|  | */ | ||||||
|  | int uECC_curve_private_key_size(uECC_Curve curve); | ||||||
|  | 
 | ||||||
|  | /* uECC_curve_public_key_size() function.
 | ||||||
|  | 
 | ||||||
|  | Returns the size of a public key for the curve in bytes. | ||||||
|  | */ | ||||||
|  | int uECC_curve_public_key_size(uECC_Curve curve); | ||||||
|  | 
 | ||||||
|  | /* uECC_make_key() function.
 | ||||||
|  | Create a public/private key pair. | ||||||
|  | 
 | ||||||
|  | Outputs: | ||||||
|  |     public_key  - Will be filled in with the public key. Must be at least 2 * the curve size | ||||||
|  |                   (in bytes) long. For example, if the curve is secp256r1, public_key must be 64 | ||||||
|  |                   bytes long. | ||||||
|  |     private_key - Will be filled in with the private key. Must be as long as the curve order; this | ||||||
|  |                   is typically the same as the curve size, except for secp160r1. For example, if the | ||||||
|  |                   curve is secp256r1, private_key must be 32 bytes long. | ||||||
|  | 
 | ||||||
|  |                   For secp160r1, private_key must be 21 bytes long! Note that the first byte will | ||||||
|  |                   almost always be 0 (there is about a 1 in 2^80 chance of it being non-zero). | ||||||
|  | 
 | ||||||
|  | Returns 1 if the key pair was generated successfully, 0 if an error occurred. | ||||||
|  | */ | ||||||
|  | int uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve); | ||||||
|  | 
 | ||||||
|  | /* uECC_shared_secret() function.
 | ||||||
|  | Compute a shared secret given your secret key and someone else's public key. If the public key | ||||||
|  | is not from a trusted source and has not been previously verified, you should verify it first | ||||||
|  | using uECC_valid_public_key(). | ||||||
|  | Note: It is recommended that you hash the result of uECC_shared_secret() before using it for | ||||||
|  | symmetric encryption or HMAC. | ||||||
|  | 
 | ||||||
|  | Inputs: | ||||||
|  |     public_key  - The public key of the remote party. | ||||||
|  |     private_key - Your private key. | ||||||
|  | 
 | ||||||
|  | Outputs: | ||||||
|  |     secret - Will be filled in with the shared secret value. Must be the same size as the | ||||||
|  |              curve size; for example, if the curve is secp256r1, secret must be 32 bytes long. | ||||||
|  | 
 | ||||||
|  | Returns 1 if the shared secret was generated successfully, 0 if an error occurred. | ||||||
|  | */ | ||||||
|  | int uECC_shared_secret(const uint8_t *public_key, | ||||||
|  |                        const uint8_t *private_key, | ||||||
|  |                        uint8_t *secret, | ||||||
|  |                        uECC_Curve curve); | ||||||
|  | 
 | ||||||
|  | #if uECC_SUPPORT_COMPRESSED_POINT | ||||||
|  | /* uECC_compress() function.
 | ||||||
|  | Compress a public key. | ||||||
|  | 
 | ||||||
|  | Inputs: | ||||||
|  |     public_key - The public key to compress. | ||||||
|  | 
 | ||||||
|  | Outputs: | ||||||
|  |     compressed - Will be filled in with the compressed public key. Must be at least | ||||||
|  |                  (curve size + 1) bytes long; for example, if the curve is secp256r1, | ||||||
|  |                  compressed must be 33 bytes long. | ||||||
|  | */ | ||||||
|  | void uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve); | ||||||
|  | 
 | ||||||
|  | /* uECC_decompress() function.
 | ||||||
|  | Decompress a compressed public key. | ||||||
|  | 
 | ||||||
|  | Inputs: | ||||||
|  |     compressed - The compressed public key. | ||||||
|  | 
 | ||||||
|  | Outputs: | ||||||
|  |     public_key - Will be filled in with the decompressed public key. | ||||||
|  | */ | ||||||
|  | void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve); | ||||||
|  | #endif /* uECC_SUPPORT_COMPRESSED_POINT */ | ||||||
|  | 
 | ||||||
|  | /* uECC_valid_public_key() function.
 | ||||||
|  | Check to see if a public key is valid. | ||||||
|  | 
 | ||||||
|  | Note that you are not required to check for a valid public key before using any other uECC | ||||||
|  | functions. However, you may wish to avoid spending CPU time computing a shared secret or | ||||||
|  | verifying a signature using an invalid public key. | ||||||
|  | 
 | ||||||
|  | Inputs: | ||||||
|  |     public_key - The public key to check. | ||||||
|  | 
 | ||||||
|  | Returns 1 if the public key is valid, 0 if it is invalid. | ||||||
|  | */ | ||||||
|  | int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve); | ||||||
|  | 
 | ||||||
|  | /* uECC_compute_public_key() function.
 | ||||||
|  | Compute the corresponding public key for a private key. | ||||||
|  | 
 | ||||||
|  | Inputs: | ||||||
|  |     private_key - The private key to compute the public key for | ||||||
|  | 
 | ||||||
|  | Outputs: | ||||||
|  |     public_key - Will be filled in with the corresponding public key | ||||||
|  | 
 | ||||||
|  | Returns 1 if the key was computed successfully, 0 if an error occurred. | ||||||
|  | */ | ||||||
|  | int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve); | ||||||
|  | 
 | ||||||
|  | /* uECC_sign() function.
 | ||||||
|  | Generate an ECDSA signature for a given hash value. | ||||||
|  | 
 | ||||||
|  | Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to | ||||||
|  | this function along with your private key. | ||||||
|  | 
 | ||||||
|  | Inputs: | ||||||
|  |     private_key  - Your private key. | ||||||
|  |     message_hash - The hash of the message to sign. | ||||||
|  |     hash_size    - The size of message_hash in bytes. | ||||||
|  | 
 | ||||||
|  | Outputs: | ||||||
|  |     signature - Will be filled in with the signature value. Must be at least 2 * curve size long. | ||||||
|  |                 For example, if the curve is secp256r1, signature must be 64 bytes long. | ||||||
|  | 
 | ||||||
|  | Returns 1 if the signature generated successfully, 0 if an error occurred. | ||||||
|  | */ | ||||||
|  | int uECC_sign(const uint8_t *private_key, | ||||||
|  |               const uint8_t *message_hash, | ||||||
|  |               unsigned hash_size, | ||||||
|  |               uint8_t *signature, | ||||||
|  |               uECC_Curve curve); | ||||||
|  | 
 | ||||||
|  | /* uECC_HashContext structure.
 | ||||||
|  | This is used to pass in an arbitrary hash function to uECC_sign_deterministic(). | ||||||
|  | The structure will be used for multiple hash computations; each time a new hash | ||||||
|  | is computed, init_hash() will be called, followed by one or more calls to | ||||||
|  | update_hash(), and finally a call to finish_hash() to produce the resulting hash. | ||||||
|  | 
 | ||||||
|  | The intention is that you will create a structure that includes uECC_HashContext | ||||||
|  | followed by any hash-specific data. For example: | ||||||
|  | 
 | ||||||
|  | typedef struct SHA256_HashContext { | ||||||
|  |     uECC_HashContext uECC; | ||||||
|  |     SHA256_CTX ctx; | ||||||
|  | } SHA256_HashContext; | ||||||
|  | 
 | ||||||
|  | void init_SHA256(uECC_HashContext *base) { | ||||||
|  |     SHA256_HashContext *context = (SHA256_HashContext *)base; | ||||||
|  |     SHA256_Init(&context->ctx); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void update_SHA256(uECC_HashContext *base, | ||||||
|  |                    const uint8_t *message, | ||||||
|  |                    unsigned message_size) { | ||||||
|  |     SHA256_HashContext *context = (SHA256_HashContext *)base; | ||||||
|  |     SHA256_Update(&context->ctx, message, message_size); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) { | ||||||
|  |     SHA256_HashContext *context = (SHA256_HashContext *)base; | ||||||
|  |     SHA256_Final(hash_result, &context->ctx); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ... when signing ... | ||||||
|  | { | ||||||
|  |     uint8_t tmp[32 + 32 + 64]; | ||||||
|  |     SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp}}; | ||||||
|  |     uECC_sign_deterministic(key, message_hash, &ctx.uECC, signature); | ||||||
|  | } | ||||||
|  | */ | ||||||
|  | typedef struct uECC_HashContext { | ||||||
|  |     void (*init_hash)(const struct uECC_HashContext *context); | ||||||
|  |     void (*update_hash)(const struct uECC_HashContext *context, | ||||||
|  |                         const uint8_t *message, | ||||||
|  |                         unsigned message_size); | ||||||
|  |     void (*finish_hash)(const struct uECC_HashContext *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. */ | ||||||
|  | } uECC_HashContext; | ||||||
|  | 
 | ||||||
|  | /* uECC_sign_deterministic() function.
 | ||||||
|  | Generate an ECDSA signature for a given hash value, using a deterministic algorithm | ||||||
|  | (see RFC 6979). You do not need to set the RNG using uECC_set_rng() before calling | ||||||
|  | this function; however, if the RNG is defined it will improve resistance to side-channel | ||||||
|  | attacks. | ||||||
|  | 
 | ||||||
|  | Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it to | ||||||
|  | this function along with your private key and a hash context. Note that the message_hash | ||||||
|  | does not need to be computed with the same hash function used by hash_context. | ||||||
|  | 
 | ||||||
|  | Inputs: | ||||||
|  |     private_key  - Your private key. | ||||||
|  |     message_hash - The hash of the message to sign. | ||||||
|  |     hash_size    - The size of message_hash in bytes. | ||||||
|  |     hash_context - A hash context to use. | ||||||
|  | 
 | ||||||
|  | Outputs: | ||||||
|  |     signature - Will be filled in with the signature value. | ||||||
|  | 
 | ||||||
|  | Returns 1 if the signature generated successfully, 0 if an error occurred. | ||||||
|  | */ | ||||||
|  | int uECC_sign_deterministic(const uint8_t *private_key, | ||||||
|  |                             const uint8_t *message_hash, | ||||||
|  |                             unsigned hash_size, | ||||||
|  |                             const uECC_HashContext *hash_context, | ||||||
|  |                             uint8_t *signature, | ||||||
|  |                             uECC_Curve curve); | ||||||
|  | 
 | ||||||
|  | /* uECC_verify() function.
 | ||||||
|  | Verify an ECDSA signature. | ||||||
|  | 
 | ||||||
|  | Usage: Compute the hash of the signed data using the same hash as the signer and | ||||||
|  | pass it to this function along with the signer's public key and the signature values (r and s). | ||||||
|  | 
 | ||||||
|  | Inputs: | ||||||
|  |     public_key   - The signer's public key. | ||||||
|  |     message_hash - The hash of the signed data. | ||||||
|  |     hash_size    - The size of message_hash in bytes. | ||||||
|  |     signature    - The signature value. | ||||||
|  | 
 | ||||||
|  | Returns 1 if the signature is valid, 0 if it is invalid. | ||||||
|  | */ | ||||||
|  | int uECC_verify(const uint8_t *public_key, | ||||||
|  |                 const uint8_t *message_hash, | ||||||
|  |                 unsigned hash_size, | ||||||
|  |                 const uint8_t *signature, | ||||||
|  |                 uECC_Curve curve); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } /* end of extern "C" */ | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #endif /* _UECC_H_ */ | ||||||
							
								
								
									
										172
									
								
								lib/micro-ecc/uECC_vli.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								lib/micro-ecc/uECC_vli.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,172 @@ | |||||||
|  | /* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ | ||||||
|  | 
 | ||||||
|  | #ifndef _UECC_VLI_H_ | ||||||
|  | #define _UECC_VLI_H_ | ||||||
|  | 
 | ||||||
|  | #include "uECC.h" | ||||||
|  | #include "types.h" | ||||||
|  | 
 | ||||||
|  | /* Functions for raw large-integer manipulation. These are only available
 | ||||||
|  |    if uECC.c is compiled with uECC_ENABLE_VLI_API defined to 1. */ | ||||||
|  | #ifndef uECC_ENABLE_VLI_API | ||||||
|  |     #define uECC_ENABLE_VLI_API 0 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" | ||||||
|  | { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #if uECC_ENABLE_VLI_API | ||||||
|  | 
 | ||||||
|  | void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words); | ||||||
|  | 
 | ||||||
|  | /* Constant-time comparison to zero - secure way to compare long integers */ | ||||||
|  | /* Returns 1 if vli == 0, 0 otherwise. */ | ||||||
|  | uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words); | ||||||
|  | 
 | ||||||
|  | /* Returns nonzero if bit 'bit' of vli is set. */ | ||||||
|  | uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit); | ||||||
|  | 
 | ||||||
|  | /* Counts the number of bits required to represent vli. */ | ||||||
|  | bitcount_t uECC_vli_numBits(const uECC_word_t *vli, const wordcount_t max_words); | ||||||
|  | 
 | ||||||
|  | /* Sets dest = src. */ | ||||||
|  | void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, wordcount_t num_words); | ||||||
|  | 
 | ||||||
|  | /* Constant-time comparison function - secure way to compare long integers */ | ||||||
|  | /* Returns one if left == right, zero otherwise */ | ||||||
|  | uECC_word_t uECC_vli_equal(const uECC_word_t *left, | ||||||
|  |                            const uECC_word_t *right, | ||||||
|  |                            wordcount_t num_words); | ||||||
|  | 
 | ||||||
|  | /* Constant-time comparison function - secure way to compare long integers */ | ||||||
|  | /* Returns sign of left - right, in constant time. */ | ||||||
|  | cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right, wordcount_t num_words); | ||||||
|  | 
 | ||||||
|  | /* Computes vli = vli >> 1. */ | ||||||
|  | void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words); | ||||||
|  | 
 | ||||||
|  | /* Computes result = left + right, returning carry. Can modify in place. */ | ||||||
|  | uECC_word_t uECC_vli_add(uECC_word_t *result, | ||||||
|  |                          const uECC_word_t *left, | ||||||
|  |                          const uECC_word_t *right, | ||||||
|  |                          wordcount_t num_words); | ||||||
|  | 
 | ||||||
|  | /* Computes result = left - right, returning borrow. Can modify in place. */ | ||||||
|  | uECC_word_t uECC_vli_sub(uECC_word_t *result, | ||||||
|  |                          const uECC_word_t *left, | ||||||
|  |                          const uECC_word_t *right, | ||||||
|  |                          wordcount_t num_words); | ||||||
|  | 
 | ||||||
|  | /* Computes result = left * right. Result must be 2 * num_words long. */ | ||||||
|  | void uECC_vli_mult(uECC_word_t *result, | ||||||
|  |                    const uECC_word_t *left, | ||||||
|  |                    const uECC_word_t *right, | ||||||
|  |                    wordcount_t num_words); | ||||||
|  | 
 | ||||||
|  | /* Computes result = left^2. Result must be 2 * num_words long. */ | ||||||
|  | void uECC_vli_square(uECC_word_t *result, const uECC_word_t *left, wordcount_t num_words); | ||||||
|  | 
 | ||||||
|  | /* Computes result = (left + right) % mod.
 | ||||||
|  |    Assumes that left < mod and right < mod, and that result does not overlap mod. */ | ||||||
|  | void uECC_vli_modAdd(uECC_word_t *result, | ||||||
|  |                      const uECC_word_t *left, | ||||||
|  |                      const uECC_word_t *right, | ||||||
|  |                      const uECC_word_t *mod, | ||||||
|  |                      wordcount_t num_words); | ||||||
|  | 
 | ||||||
|  | /* Computes result = (left - right) % mod.
 | ||||||
|  |    Assumes that left < mod and right < mod, and that result does not overlap mod. */ | ||||||
|  | void uECC_vli_modSub(uECC_word_t *result, | ||||||
|  |                      const uECC_word_t *left, | ||||||
|  |                      const uECC_word_t *right, | ||||||
|  |                      const uECC_word_t *mod, | ||||||
|  |                      wordcount_t num_words); | ||||||
|  | 
 | ||||||
|  | /* Computes result = product % mod, where product is 2N words long.
 | ||||||
|  |    Currently only designed to work for mod == curve->p or curve_n. */ | ||||||
|  | void uECC_vli_mmod(uECC_word_t *result, | ||||||
|  |                    uECC_word_t *product, | ||||||
|  |                    const uECC_word_t *mod, | ||||||
|  |                    wordcount_t num_words); | ||||||
|  | 
 | ||||||
|  | /* Calculates result = product (mod curve->p), where product is up to
 | ||||||
|  |    2 * curve->num_words long. */ | ||||||
|  | void uECC_vli_mmod_fast(uECC_word_t *result, uECC_word_t *product, uECC_Curve curve); | ||||||
|  | 
 | ||||||
|  | /* Computes result = (left * right) % mod.
 | ||||||
|  |    Currently only designed to work for mod == curve->p or curve_n. */ | ||||||
|  | void uECC_vli_modMult(uECC_word_t *result, | ||||||
|  |                       const uECC_word_t *left, | ||||||
|  |                       const uECC_word_t *right, | ||||||
|  |                       const uECC_word_t *mod, | ||||||
|  |                       wordcount_t num_words); | ||||||
|  | 
 | ||||||
|  | /* Computes result = (left * right) % curve->p. */ | ||||||
|  | void uECC_vli_modMult_fast(uECC_word_t *result, | ||||||
|  |                            const uECC_word_t *left, | ||||||
|  |                            const uECC_word_t *right, | ||||||
|  |                            uECC_Curve curve); | ||||||
|  | 
 | ||||||
|  | /* Computes result = left^2 % mod.
 | ||||||
|  |    Currently only designed to work for mod == curve->p or curve_n. */ | ||||||
|  | void uECC_vli_modSquare(uECC_word_t *result, | ||||||
|  |                         const uECC_word_t *left, | ||||||
|  |                         const uECC_word_t *mod, | ||||||
|  |                         wordcount_t num_words); | ||||||
|  | 
 | ||||||
|  | /* Computes result = left^2 % curve->p. */ | ||||||
|  | void uECC_vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left, uECC_Curve curve); | ||||||
|  | 
 | ||||||
|  | /* Computes result = (1 / input) % mod.*/ | ||||||
|  | void uECC_vli_modInv(uECC_word_t *result, | ||||||
|  |                      const uECC_word_t *input, | ||||||
|  |                      const uECC_word_t *mod, | ||||||
|  |                      wordcount_t num_words); | ||||||
|  | 
 | ||||||
|  | #if uECC_SUPPORT_COMPRESSED_POINT | ||||||
|  | /* Calculates a = sqrt(a) (mod curve->p) */ | ||||||
|  | void uECC_vli_mod_sqrt(uECC_word_t *a, uECC_Curve curve); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | /* Converts an integer in uECC native format to big-endian bytes. */ | ||||||
|  | void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes, const uECC_word_t *native); | ||||||
|  | /* Converts big-endian bytes to an integer in uECC native format. */ | ||||||
|  | void uECC_vli_bytesToNative(uECC_word_t *native, const uint8_t *bytes, int num_bytes); | ||||||
|  | 
 | ||||||
|  | unsigned uECC_curve_num_words(uECC_Curve curve); | ||||||
|  | unsigned uECC_curve_num_bytes(uECC_Curve curve); | ||||||
|  | unsigned uECC_curve_num_bits(uECC_Curve curve); | ||||||
|  | unsigned uECC_curve_num_n_words(uECC_Curve curve); | ||||||
|  | unsigned uECC_curve_num_n_bytes(uECC_Curve curve); | ||||||
|  | unsigned uECC_curve_num_n_bits(uECC_Curve curve); | ||||||
|  | 
 | ||||||
|  | const uECC_word_t *uECC_curve_p(uECC_Curve curve); | ||||||
|  | const uECC_word_t *uECC_curve_n(uECC_Curve curve); | ||||||
|  | const uECC_word_t *uECC_curve_G(uECC_Curve curve); | ||||||
|  | const uECC_word_t *uECC_curve_b(uECC_Curve curve); | ||||||
|  | 
 | ||||||
|  | int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve); | ||||||
|  | 
 | ||||||
|  | /* Multiplies a point by a scalar. Points are represented by the X coordinate followed by
 | ||||||
|  |    the Y coordinate in the same array, both coordinates are curve->num_words long. Note | ||||||
|  |    that scalar must be curve->num_n_words long (NOT curve->num_words). */ | ||||||
|  | void uECC_point_mult(uECC_word_t *result, | ||||||
|  |                      const uECC_word_t *point, | ||||||
|  |                      const uECC_word_t *scalar, | ||||||
|  |                      uECC_Curve curve); | ||||||
|  | 
 | ||||||
|  | /* Generates a random integer in the range 0 < random < top.
 | ||||||
|  |    Both random and top have num_words words. */ | ||||||
|  | int uECC_generate_random_int(uECC_word_t *random, | ||||||
|  |                              const uECC_word_t *top, | ||||||
|  |                              wordcount_t num_words); | ||||||
|  | 
 | ||||||
|  | #endif /* uECC_ENABLE_VLI_API */ | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } /* end of extern "C" */ | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #endif /* _UECC_VLI_H_ */ | ||||||
							
								
								
									
										123
									
								
								lib/toolbox/hmac_sha256.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								lib/toolbox/hmac_sha256.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,123 @@ | |||||||
|  | /*
 | ||||||
|  |  * 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); | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								lib/toolbox/hmac_sha256.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								lib/toolbox/hmac_sha256.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | |||||||
|  | 
 | ||||||
|  | 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); | ||||||
							
								
								
									
										226
									
								
								lib/toolbox/sha256.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								lib/toolbox/sha256.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,226 @@ | |||||||
|  | /*
 | ||||||
|  |  * sha256.c -- Compute SHA-256 hash | ||||||
|  |  * | ||||||
|  |  * Just for little endian architecture. | ||||||
|  |  * | ||||||
|  |  * Code taken from: | ||||||
|  |  *  http://gladman.plushost.co.uk/oldsite/cryptography_technology/sha/index.php
 | ||||||
|  |  * | ||||||
|  |  *  File names are sha2.c, sha2.h, brg_types.h, brg_endian.h | ||||||
|  |  *  in the archive sha2-07-01-07.zip. | ||||||
|  |  * | ||||||
|  |  * Code is modified in the style of PolarSSL API. | ||||||
|  |  * | ||||||
|  |  * See original copyright notice below. | ||||||
|  |  */ | ||||||
|  | /*
 | ||||||
|  |  --------------------------------------------------------------------------- | ||||||
|  |  Copyright (c) 2002, Dr Brian Gladman, Worcester, UK.   All rights reserved. | ||||||
|  | 
 | ||||||
|  |  LICENSE TERMS | ||||||
|  | 
 | ||||||
|  |  The free distribution and use of this software in both source and binary | ||||||
|  |  form is allowed (with or without changes) provided that: | ||||||
|  | 
 | ||||||
|  |    1. distributions of this source code include the above copyright | ||||||
|  |       notice, this list of conditions and the following disclaimer; | ||||||
|  | 
 | ||||||
|  |    2. distributions in binary form include the above copyright | ||||||
|  |       notice, this list of conditions and the following disclaimer | ||||||
|  |       in the documentation and/or other associated materials; | ||||||
|  | 
 | ||||||
|  |    3. the copyright holder's name is not used to endorse products | ||||||
|  |       built using this software without specific written permission. | ||||||
|  | 
 | ||||||
|  |  ALTERNATIVELY, provided that this notice is retained in full, this product | ||||||
|  |  may be distributed under the terms of the GNU General Public License (GPL), | ||||||
|  |  in which case the provisions of the GPL apply INSTEAD OF those given above. | ||||||
|  | 
 | ||||||
|  |  DISCLAIMER | ||||||
|  | 
 | ||||||
|  |  This software is provided 'as is' with no explicit or implied warranties | ||||||
|  |  in respect of its properties, including, but not limited to, correctness | ||||||
|  |  and/or fitness for purpose. | ||||||
|  |  --------------------------------------------------------------------------- | ||||||
|  |  Issue Date: 01/08/2005 | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #include <string.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include "sha256.h" | ||||||
|  | 
 | ||||||
|  | #define SHA256_MASK (SHA256_BLOCK_SIZE - 1) | ||||||
|  | 
 | ||||||
|  | static void memcpy_output_bswap32 (unsigned char *dst, const uint32_t *p) | ||||||
|  | { | ||||||
|  |   int i; | ||||||
|  |   uint32_t q = 0; | ||||||
|  | 
 | ||||||
|  |   for (i = 0; i < 32; i++) | ||||||
|  |     { | ||||||
|  |       if ((i & 3) == 0) | ||||||
|  | 	q = __builtin_bswap32 (p[i >> 2]); /* bswap32 is GCC extention */ | ||||||
|  |       dst[i] = q >> ((i & 3) * 8); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define rotr32(x,n)   (((x) >> n) | ((x) << (32 - n))) | ||||||
|  | 
 | ||||||
|  | #define ch(x,y,z)       ((z) ^ ((x) & ((y) ^ (z)))) | ||||||
|  | #define maj(x,y,z)      (((x) & (y)) | ((z) & ((x) ^ (y)))) | ||||||
|  | 
 | ||||||
|  | /* round transforms for SHA256 compression functions */ | ||||||
|  | #define vf(n,i) v[(n - i) & 7] | ||||||
|  | 
 | ||||||
|  | #define hf(i) (p[i & 15] += \ | ||||||
|  |     g_1(p[(i + 14) & 15]) + p[(i + 9) & 15] + g_0(p[(i + 1) & 15])) | ||||||
|  | 
 | ||||||
|  | #define v_cycle0(i)                                 \ | ||||||
|  |     p[i] = __builtin_bswap32 (p[i]);                \ | ||||||
|  |     vf(7,i) += p[i] + k_0[i]                        \ | ||||||
|  |     + s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i));   \ | ||||||
|  |     vf(3,i) += vf(7,i);                             \ | ||||||
|  |     vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i)) | ||||||
|  | 
 | ||||||
|  | #define v_cycle(i, j)                               \ | ||||||
|  |     vf(7,i) += hf(i) + k_0[i+j]                     \ | ||||||
|  |     + s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i));   \ | ||||||
|  |     vf(3,i) += vf(7,i);                             \ | ||||||
|  |     vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i)) | ||||||
|  | 
 | ||||||
|  | #define s_0(x)  (rotr32((x),  2) ^ rotr32((x), 13) ^ rotr32((x), 22)) | ||||||
|  | #define s_1(x)  (rotr32((x),  6) ^ rotr32((x), 11) ^ rotr32((x), 25)) | ||||||
|  | #define g_0(x)  (rotr32((x),  7) ^ rotr32((x), 18) ^ ((x) >>  3)) | ||||||
|  | #define g_1(x)  (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10)) | ||||||
|  | #define k_0     k256 | ||||||
|  | 
 | ||||||
|  | static const uint32_t k256[64] = { | ||||||
|  |   0X428A2F98, 0X71374491, 0XB5C0FBCF, 0XE9B5DBA5, | ||||||
|  |   0X3956C25B, 0X59F111F1, 0X923F82A4, 0XAB1C5ED5, | ||||||
|  |   0XD807AA98, 0X12835B01, 0X243185BE, 0X550C7DC3, | ||||||
|  |   0X72BE5D74, 0X80DEB1FE, 0X9BDC06A7, 0XC19BF174, | ||||||
|  |   0XE49B69C1, 0XEFBE4786, 0X0FC19DC6, 0X240CA1CC, | ||||||
|  |   0X2DE92C6F, 0X4A7484AA, 0X5CB0A9DC, 0X76F988DA, | ||||||
|  |   0X983E5152, 0XA831C66D, 0XB00327C8, 0XBF597FC7, | ||||||
|  |   0XC6E00BF3, 0XD5A79147, 0X06CA6351, 0X14292967, | ||||||
|  |   0X27B70A85, 0X2E1B2138, 0X4D2C6DFC, 0X53380D13, | ||||||
|  |   0X650A7354, 0X766A0ABB, 0X81C2C92E, 0X92722C85, | ||||||
|  |   0XA2BFE8A1, 0XA81A664B, 0XC24B8B70, 0XC76C51A3, | ||||||
|  |   0XD192E819, 0XD6990624, 0XF40E3585, 0X106AA070, | ||||||
|  |   0X19A4C116, 0X1E376C08, 0X2748774C, 0X34B0BCB5, | ||||||
|  |   0X391C0CB3, 0X4ED8AA4A, 0X5B9CCA4F, 0X682E6FF3, | ||||||
|  |   0X748F82EE, 0X78A5636F, 0X84C87814, 0X8CC70208, | ||||||
|  |   0X90BEFFFA, 0XA4506CEB, 0XBEF9A3F7, 0XC67178F2, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | sha256_process (sha256_context *ctx) | ||||||
|  | { | ||||||
|  |   uint32_t i; | ||||||
|  |   uint32_t *p = ctx->wbuf; | ||||||
|  |   uint32_t v[8]; | ||||||
|  | 
 | ||||||
|  |   memcpy (v, ctx->state, 8 * sizeof (uint32_t)); | ||||||
|  | 
 | ||||||
|  |   v_cycle0 ( 0); v_cycle0 ( 1); v_cycle0 ( 2); v_cycle0 ( 3); | ||||||
|  |   v_cycle0 ( 4); v_cycle0 ( 5); v_cycle0 ( 6); v_cycle0 ( 7); | ||||||
|  |   v_cycle0 ( 8); v_cycle0 ( 9); v_cycle0 (10); v_cycle0 (11); | ||||||
|  |   v_cycle0 (12); v_cycle0 (13); v_cycle0 (14); v_cycle0 (15); | ||||||
|  | 
 | ||||||
|  |   for (i = 16; i < 64; i += 16) | ||||||
|  |     { | ||||||
|  |       v_cycle ( 0, i); v_cycle ( 1, i); v_cycle ( 2, i); v_cycle ( 3, i); | ||||||
|  |       v_cycle ( 4, i); v_cycle ( 5, i); v_cycle ( 6, i); v_cycle ( 7, i); | ||||||
|  |       v_cycle ( 8, i); v_cycle ( 9, i); v_cycle (10, i); v_cycle (11, i); | ||||||
|  |       v_cycle (12, i); v_cycle (13, i); v_cycle (14, i); v_cycle (15, i); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |   ctx->state[0] += v[0]; | ||||||
|  |   ctx->state[1] += v[1]; | ||||||
|  |   ctx->state[2] += v[2]; | ||||||
|  |   ctx->state[3] += v[3]; | ||||||
|  |   ctx->state[4] += v[4]; | ||||||
|  |   ctx->state[5] += v[5]; | ||||||
|  |   ctx->state[6] += v[6]; | ||||||
|  |   ctx->state[7] += v[7]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | sha256_update (sha256_context *ctx, const unsigned char *input, | ||||||
|  |                unsigned int ilen) | ||||||
|  | { | ||||||
|  |   uint32_t left = (ctx->total[0] & SHA256_MASK); | ||||||
|  |   uint32_t fill = SHA256_BLOCK_SIZE - left; | ||||||
|  | 
 | ||||||
|  |   ctx->total[0] += ilen; | ||||||
|  |   if (ctx->total[0] < ilen) | ||||||
|  |     ctx->total[1]++; | ||||||
|  | 
 | ||||||
|  |   while (ilen >= fill) | ||||||
|  |     { | ||||||
|  |       memcpy (((unsigned char*)ctx->wbuf) + left, input, fill); | ||||||
|  |       sha256_process (ctx); | ||||||
|  |       input += fill; | ||||||
|  |       ilen -= fill; | ||||||
|  |       left = 0; | ||||||
|  |       fill = SHA256_BLOCK_SIZE; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |   memcpy (((unsigned char*)ctx->wbuf) + left, input, ilen); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | sha256_finish (sha256_context *ctx, unsigned char output[32]) | ||||||
|  | { | ||||||
|  |   uint32_t last = (ctx->total[0] & SHA256_MASK); | ||||||
|  | 
 | ||||||
|  |   ctx->wbuf[last >> 2] = __builtin_bswap32 (ctx->wbuf[last >> 2]); | ||||||
|  |   ctx->wbuf[last >> 2] &= 0xffffff80 << (8 * (~last & 3)); | ||||||
|  |   ctx->wbuf[last >> 2] |= 0x00000080 << (8 * (~last & 3)); | ||||||
|  |   ctx->wbuf[last >> 2] = __builtin_bswap32 (ctx->wbuf[last >> 2]); | ||||||
|  | 
 | ||||||
|  |   if (last > SHA256_BLOCK_SIZE - 9) | ||||||
|  |     { | ||||||
|  |       if (last < 60) | ||||||
|  |         ctx->wbuf[15] = 0; | ||||||
|  |       sha256_process (ctx); | ||||||
|  |       last = 0; | ||||||
|  |     } | ||||||
|  |   else | ||||||
|  |     last = (last >> 2) + 1; | ||||||
|  | 
 | ||||||
|  |   while (last < 14) | ||||||
|  |     ctx->wbuf[last++] = 0; | ||||||
|  | 
 | ||||||
|  |   ctx->wbuf[14] = __builtin_bswap32 ((ctx->total[0] >> 29) | (ctx->total[1] << 3)); | ||||||
|  |   ctx->wbuf[15] = __builtin_bswap32 (ctx->total[0] << 3); | ||||||
|  |   sha256_process (ctx); | ||||||
|  | 
 | ||||||
|  |   memcpy_output_bswap32 (output, ctx->state); | ||||||
|  |   memset (ctx, 0, sizeof (sha256_context)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static const uint32_t initial_state[8] = | ||||||
|  | { | ||||||
|  |   0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, | ||||||
|  |   0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | sha256_start (sha256_context *ctx) | ||||||
|  | { | ||||||
|  |   ctx->total[0] = ctx->total[1] = 0; | ||||||
|  |   memcpy (ctx->state, initial_state, 8 * sizeof(uint32_t)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void | ||||||
|  | sha256 (const unsigned char *input, unsigned int ilen, | ||||||
|  |         unsigned char output[32]) | ||||||
|  | { | ||||||
|  |   sha256_context ctx; | ||||||
|  | 
 | ||||||
|  |   sha256_start (&ctx); | ||||||
|  |   sha256_update (&ctx, input, ilen); | ||||||
|  |   sha256_finish (&ctx, output); | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								lib/toolbox/sha256.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								lib/toolbox/sha256.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | #define SHA256_DIGEST_SIZE  32 | ||||||
|  | #define SHA256_BLOCK_SIZE   64 | ||||||
|  | 
 | ||||||
|  | typedef struct | ||||||
|  | { | ||||||
|  |   uint32_t total[2]; | ||||||
|  |   uint32_t state[8]; | ||||||
|  |   uint32_t wbuf[16]; | ||||||
|  | } sha256_context; | ||||||
|  | 
 | ||||||
|  | void sha256 (const unsigned char *input, unsigned int ilen, | ||||||
|  | 	     unsigned char output[32]); | ||||||
|  | void sha256_start (sha256_context *ctx); | ||||||
|  | void sha256_finish (sha256_context *ctx, unsigned char output[32]); | ||||||
|  | void sha256_update (sha256_context *ctx, const unsigned char *input, | ||||||
|  | 		    unsigned int ilen); | ||||||
|  | void sha256_process (sha256_context *ctx); | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Nikolay Minaylov
						Nikolay Minaylov