From 5e6c11ca9390d7431731330b07b5d68e888feda5 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Sat, 10 Jun 2023 01:03:41 +0200 Subject: [PATCH] Import from working prototype --- .gitignore | 2 + .gitmodules | 3 + CMakeDoxyfile.in | 289 ++++++ CMakeDoxygenDefaults.cmake | 695 ++++++++++++++ CMakeLists.txt | 63 ++ README.md | 141 +++ cmake_install.cmake | 55 ++ elf2uf2/CMakeCache.txt | 374 ++++++++ elf2uf2/Makefile | 181 ++++ elf2uf2/boot_uf2_headers/Makefile | 140 +++ elf2uf2/boot_uf2_headers/cmake_install.cmake | 44 + elf2uf2/cmake_install.cmake | 60 ++ elf2uf2/elf2uf2 | Bin 0 -> 99632 bytes .../src/ELF2UF2Build-stamp/ELF2UF2Build-done | 0 .../ELF2UF2Build-source_dirinfo.txt | 9 + elf2uf2/tmp/ELF2UF2Build-cfgcmd.txt | 1 + elf2uf2/tmp/ELF2UF2Build-mkdirs.cmake | 22 + generated/pico_base/pico/config_autogen.h | 11 + generated/pico_base/pico/version.h | 19 + lib/wolfssl | 1 + msc_content/Makefile | 7 + msc_content/mep.c | 896 ++++++++++++++++++ pico-sdk | 1 + pico_sdk_import.cmake | 62 ++ src/cdc-protocol.c | 260 +++++ src/cryptoengine.c | 246 +++++ src/cryptoengine.h | 119 +++ src/display.c | 180 ++++ src/display.h | 71 ++ src/flash.c | 228 +++++ src/flash.h | 32 + src/font_twisted.c | Bin 0 -> 16280 bytes src/fsm.c | 56 ++ src/fsm.h | 38 + src/hid.c | 240 +++++ src/hid.h | 26 + src/msc_disk.c | 265 ++++++ src/password_safe.c | 341 +++++++ src/tusb_config.h | 114 +++ src/ui.c | 583 ++++++++++++ src/ui.h | 47 + src/usb_descriptors.c | 221 +++++ src/usb_descriptors.h | 37 + src/user_settings.h | 108 +++ 44 files changed, 6288 insertions(+) create mode 100644 .gitmodules create mode 100644 CMakeDoxyfile.in create mode 100644 CMakeDoxygenDefaults.cmake create mode 100644 CMakeLists.txt create mode 100644 README.md create mode 100644 cmake_install.cmake create mode 100644 elf2uf2/CMakeCache.txt create mode 100644 elf2uf2/Makefile create mode 100644 elf2uf2/boot_uf2_headers/Makefile create mode 100644 elf2uf2/boot_uf2_headers/cmake_install.cmake create mode 100644 elf2uf2/cmake_install.cmake create mode 100755 elf2uf2/elf2uf2 create mode 100644 elf2uf2/src/ELF2UF2Build-stamp/ELF2UF2Build-done create mode 100644 elf2uf2/src/ELF2UF2Build-stamp/ELF2UF2Build-source_dirinfo.txt create mode 100644 elf2uf2/tmp/ELF2UF2Build-cfgcmd.txt create mode 100644 elf2uf2/tmp/ELF2UF2Build-mkdirs.cmake create mode 100644 generated/pico_base/pico/config_autogen.h create mode 100644 generated/pico_base/pico/version.h create mode 160000 lib/wolfssl create mode 100644 msc_content/Makefile create mode 100644 msc_content/mep.c create mode 160000 pico-sdk create mode 100644 pico_sdk_import.cmake create mode 100644 src/cdc-protocol.c create mode 100644 src/cryptoengine.c create mode 100644 src/cryptoengine.h create mode 100644 src/display.c create mode 100644 src/display.h create mode 100644 src/flash.c create mode 100644 src/flash.h create mode 100644 src/font_twisted.c create mode 100644 src/fsm.c create mode 100644 src/fsm.h create mode 100644 src/hid.c create mode 100644 src/hid.h create mode 100644 src/msc_disk.c create mode 100644 src/password_safe.c create mode 100644 src/tusb_config.h create mode 100644 src/ui.c create mode 100644 src/ui.h create mode 100644 src/usb_descriptors.c create mode 100644 src/usb_descriptors.h create mode 100644 src/user_settings.h diff --git a/.gitignore b/.gitignore index 5c6a3b6..f82d5c2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ core *.bin *.elf *.uf2 +CMakeCache.txt +elf2uf2/boot_uf2_headers/CMakeFiles diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..4b0cfc3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/wolfssl"] + path = lib/wolfssl + url = https://github.com/wolfssl/wolfssl.git diff --git a/CMakeDoxyfile.in b/CMakeDoxyfile.in new file mode 100644 index 0000000..7dcb8d9 --- /dev/null +++ b/CMakeDoxyfile.in @@ -0,0 +1,289 @@ +# +# DO NOT EDIT! THIS FILE WAS GENERATED BY CMAKE! +# + +DOXYFILE_ENCODING = @DOXYGEN_DOXYFILE_ENCODING@ +PROJECT_NAME = @DOXYGEN_PROJECT_NAME@ +PROJECT_NUMBER = @DOXYGEN_PROJECT_NUMBER@ +PROJECT_BRIEF = @DOXYGEN_PROJECT_BRIEF@ +PROJECT_LOGO = @DOXYGEN_PROJECT_LOGO@ +OUTPUT_DIRECTORY = @DOXYGEN_OUTPUT_DIRECTORY@ +CREATE_SUBDIRS = @DOXYGEN_CREATE_SUBDIRS@ +CREATE_SUBDIRS_LEVEL = @DOXYGEN_CREATE_SUBDIRS_LEVEL@ +ALLOW_UNICODE_NAMES = @DOXYGEN_ALLOW_UNICODE_NAMES@ +OUTPUT_LANGUAGE = @DOXYGEN_OUTPUT_LANGUAGE@ +BRIEF_MEMBER_DESC = @DOXYGEN_BRIEF_MEMBER_DESC@ +REPEAT_BRIEF = @DOXYGEN_REPEAT_BRIEF@ +ABBREVIATE_BRIEF = @DOXYGEN_ABBREVIATE_BRIEF@ +ALWAYS_DETAILED_SEC = @DOXYGEN_ALWAYS_DETAILED_SEC@ +INLINE_INHERITED_MEMB = @DOXYGEN_INLINE_INHERITED_MEMB@ +FULL_PATH_NAMES = @DOXYGEN_FULL_PATH_NAMES@ +STRIP_FROM_PATH = @DOXYGEN_STRIP_FROM_PATH@ +STRIP_FROM_INC_PATH = @DOXYGEN_STRIP_FROM_INC_PATH@ +SHORT_NAMES = @DOXYGEN_SHORT_NAMES@ +JAVADOC_AUTOBRIEF = @DOXYGEN_JAVADOC_AUTOBRIEF@ +JAVADOC_BANNER = @DOXYGEN_JAVADOC_BANNER@ +QT_AUTOBRIEF = @DOXYGEN_QT_AUTOBRIEF@ +MULTILINE_CPP_IS_BRIEF = @DOXYGEN_MULTILINE_CPP_IS_BRIEF@ +PYTHON_DOCSTRING = @DOXYGEN_PYTHON_DOCSTRING@ +INHERIT_DOCS = @DOXYGEN_INHERIT_DOCS@ +SEPARATE_MEMBER_PAGES = @DOXYGEN_SEPARATE_MEMBER_PAGES@ +TAB_SIZE = @DOXYGEN_TAB_SIZE@ +ALIASES = @DOXYGEN_ALIASES@ +OPTIMIZE_OUTPUT_FOR_C = @DOXYGEN_OPTIMIZE_OUTPUT_FOR_C@ +OPTIMIZE_OUTPUT_JAVA = @DOXYGEN_OPTIMIZE_OUTPUT_JAVA@ +OPTIMIZE_FOR_FORTRAN = @DOXYGEN_OPTIMIZE_FOR_FORTRAN@ +OPTIMIZE_OUTPUT_VHDL = @DOXYGEN_OPTIMIZE_OUTPUT_VHDL@ +OPTIMIZE_OUTPUT_SLICE = @DOXYGEN_OPTIMIZE_OUTPUT_SLICE@ +EXTENSION_MAPPING = @DOXYGEN_EXTENSION_MAPPING@ +MARKDOWN_SUPPORT = @DOXYGEN_MARKDOWN_SUPPORT@ +TOC_INCLUDE_HEADINGS = @DOXYGEN_TOC_INCLUDE_HEADINGS@ +AUTOLINK_SUPPORT = @DOXYGEN_AUTOLINK_SUPPORT@ +BUILTIN_STL_SUPPORT = @DOXYGEN_BUILTIN_STL_SUPPORT@ +CPP_CLI_SUPPORT = @DOXYGEN_CPP_CLI_SUPPORT@ +SIP_SUPPORT = @DOXYGEN_SIP_SUPPORT@ +IDL_PROPERTY_SUPPORT = @DOXYGEN_IDL_PROPERTY_SUPPORT@ +DISTRIBUTE_GROUP_DOC = @DOXYGEN_DISTRIBUTE_GROUP_DOC@ +GROUP_NESTED_COMPOUNDS = @DOXYGEN_GROUP_NESTED_COMPOUNDS@ +SUBGROUPING = @DOXYGEN_SUBGROUPING@ +INLINE_GROUPED_CLASSES = @DOXYGEN_INLINE_GROUPED_CLASSES@ +INLINE_SIMPLE_STRUCTS = @DOXYGEN_INLINE_SIMPLE_STRUCTS@ +TYPEDEF_HIDES_STRUCT = @DOXYGEN_TYPEDEF_HIDES_STRUCT@ +LOOKUP_CACHE_SIZE = @DOXYGEN_LOOKUP_CACHE_SIZE@ +NUM_PROC_THREADS = @DOXYGEN_NUM_PROC_THREADS@ +EXTRACT_ALL = @DOXYGEN_EXTRACT_ALL@ +EXTRACT_PRIVATE = @DOXYGEN_EXTRACT_PRIVATE@ +EXTRACT_PRIV_VIRTUAL = @DOXYGEN_EXTRACT_PRIV_VIRTUAL@ +EXTRACT_PACKAGE = @DOXYGEN_EXTRACT_PACKAGE@ +EXTRACT_STATIC = @DOXYGEN_EXTRACT_STATIC@ +EXTRACT_LOCAL_CLASSES = @DOXYGEN_EXTRACT_LOCAL_CLASSES@ +EXTRACT_LOCAL_METHODS = @DOXYGEN_EXTRACT_LOCAL_METHODS@ +EXTRACT_ANON_NSPACES = @DOXYGEN_EXTRACT_ANON_NSPACES@ +RESOLVE_UNNAMED_PARAMS = @DOXYGEN_RESOLVE_UNNAMED_PARAMS@ +HIDE_UNDOC_MEMBERS = @DOXYGEN_HIDE_UNDOC_MEMBERS@ +HIDE_UNDOC_CLASSES = @DOXYGEN_HIDE_UNDOC_CLASSES@ +HIDE_FRIEND_COMPOUNDS = @DOXYGEN_HIDE_FRIEND_COMPOUNDS@ +HIDE_IN_BODY_DOCS = @DOXYGEN_HIDE_IN_BODY_DOCS@ +INTERNAL_DOCS = @DOXYGEN_INTERNAL_DOCS@ +CASE_SENSE_NAMES = @DOXYGEN_CASE_SENSE_NAMES@ +HIDE_SCOPE_NAMES = @DOXYGEN_HIDE_SCOPE_NAMES@ +HIDE_COMPOUND_REFERENCE= @DOXYGEN_HIDE_COMPOUND_REFERENCE@ +SHOW_HEADERFILE = @DOXYGEN_SHOW_HEADERFILE@ +SHOW_INCLUDE_FILES = @DOXYGEN_SHOW_INCLUDE_FILES@ +SHOW_GROUPED_MEMB_INC = @DOXYGEN_SHOW_GROUPED_MEMB_INC@ +FORCE_LOCAL_INCLUDES = @DOXYGEN_FORCE_LOCAL_INCLUDES@ +INLINE_INFO = @DOXYGEN_INLINE_INFO@ +SORT_MEMBER_DOCS = @DOXYGEN_SORT_MEMBER_DOCS@ +SORT_BRIEF_DOCS = @DOXYGEN_SORT_BRIEF_DOCS@ +SORT_MEMBERS_CTORS_1ST = @DOXYGEN_SORT_MEMBERS_CTORS_1ST@ +SORT_GROUP_NAMES = @DOXYGEN_SORT_GROUP_NAMES@ +SORT_BY_SCOPE_NAME = @DOXYGEN_SORT_BY_SCOPE_NAME@ +STRICT_PROTO_MATCHING = @DOXYGEN_STRICT_PROTO_MATCHING@ +GENERATE_TODOLIST = @DOXYGEN_GENERATE_TODOLIST@ +GENERATE_TESTLIST = @DOXYGEN_GENERATE_TESTLIST@ +GENERATE_BUGLIST = @DOXYGEN_GENERATE_BUGLIST@ +GENERATE_DEPRECATEDLIST= @DOXYGEN_GENERATE_DEPRECATEDLIST@ +ENABLED_SECTIONS = @DOXYGEN_ENABLED_SECTIONS@ +MAX_INITIALIZER_LINES = @DOXYGEN_MAX_INITIALIZER_LINES@ +SHOW_USED_FILES = @DOXYGEN_SHOW_USED_FILES@ +SHOW_FILES = @DOXYGEN_SHOW_FILES@ +SHOW_NAMESPACES = @DOXYGEN_SHOW_NAMESPACES@ +FILE_VERSION_FILTER = @DOXYGEN_FILE_VERSION_FILTER@ +LAYOUT_FILE = @DOXYGEN_LAYOUT_FILE@ +CITE_BIB_FILES = @DOXYGEN_CITE_BIB_FILES@ +QUIET = @DOXYGEN_QUIET@ +WARNINGS = @DOXYGEN_WARNINGS@ +WARN_IF_UNDOCUMENTED = @DOXYGEN_WARN_IF_UNDOCUMENTED@ +WARN_IF_DOC_ERROR = @DOXYGEN_WARN_IF_DOC_ERROR@ +WARN_IF_INCOMPLETE_DOC = @DOXYGEN_WARN_IF_INCOMPLETE_DOC@ +WARN_NO_PARAMDOC = @DOXYGEN_WARN_NO_PARAMDOC@ +WARN_AS_ERROR = @DOXYGEN_WARN_AS_ERROR@ +WARN_FORMAT = @DOXYGEN_WARN_FORMAT@ +WARN_LINE_FORMAT = @DOXYGEN_WARN_LINE_FORMAT@ +WARN_LOGFILE = @DOXYGEN_WARN_LOGFILE@ +INPUT = @DOXYGEN_INPUT@ +INPUT_ENCODING = @DOXYGEN_INPUT_ENCODING@ +FILE_PATTERNS = @DOXYGEN_FILE_PATTERNS@ +RECURSIVE = @DOXYGEN_RECURSIVE@ +EXCLUDE = @DOXYGEN_EXCLUDE@ +EXCLUDE_SYMLINKS = @DOXYGEN_EXCLUDE_SYMLINKS@ +EXCLUDE_PATTERNS = @DOXYGEN_EXCLUDE_PATTERNS@ +EXCLUDE_SYMBOLS = @DOXYGEN_EXCLUDE_SYMBOLS@ +EXAMPLE_PATH = @DOXYGEN_EXAMPLE_PATH@ +EXAMPLE_PATTERNS = @DOXYGEN_EXAMPLE_PATTERNS@ +EXAMPLE_RECURSIVE = @DOXYGEN_EXAMPLE_RECURSIVE@ +IMAGE_PATH = @DOXYGEN_IMAGE_PATH@ +INPUT_FILTER = @DOXYGEN_INPUT_FILTER@ +FILTER_PATTERNS = @DOXYGEN_FILTER_PATTERNS@ +FILTER_SOURCE_FILES = @DOXYGEN_FILTER_SOURCE_FILES@ +FILTER_SOURCE_PATTERNS = @DOXYGEN_FILTER_SOURCE_PATTERNS@ +USE_MDFILE_AS_MAINPAGE = @DOXYGEN_USE_MDFILE_AS_MAINPAGE@ +SOURCE_BROWSER = @DOXYGEN_SOURCE_BROWSER@ +INLINE_SOURCES = @DOXYGEN_INLINE_SOURCES@ +STRIP_CODE_COMMENTS = @DOXYGEN_STRIP_CODE_COMMENTS@ +REFERENCED_BY_RELATION = @DOXYGEN_REFERENCED_BY_RELATION@ +REFERENCES_RELATION = @DOXYGEN_REFERENCES_RELATION@ +REFERENCES_LINK_SOURCE = @DOXYGEN_REFERENCES_LINK_SOURCE@ +SOURCE_TOOLTIPS = @DOXYGEN_SOURCE_TOOLTIPS@ +USE_HTAGS = @DOXYGEN_USE_HTAGS@ +VERBATIM_HEADERS = @DOXYGEN_VERBATIM_HEADERS@ +CLANG_ASSISTED_PARSING = @DOXYGEN_CLANG_ASSISTED_PARSING@ +CLANG_ADD_INC_PATHS = @DOXYGEN_CLANG_ADD_INC_PATHS@ +CLANG_OPTIONS = @DOXYGEN_CLANG_OPTIONS@ +CLANG_DATABASE_PATH = @DOXYGEN_CLANG_DATABASE_PATH@ +ALPHABETICAL_INDEX = @DOXYGEN_ALPHABETICAL_INDEX@ +IGNORE_PREFIX = @DOXYGEN_IGNORE_PREFIX@ +GENERATE_HTML = @DOXYGEN_GENERATE_HTML@ +HTML_OUTPUT = @DOXYGEN_HTML_OUTPUT@ +HTML_FILE_EXTENSION = @DOXYGEN_HTML_FILE_EXTENSION@ +HTML_HEADER = @DOXYGEN_HTML_HEADER@ +HTML_FOOTER = @DOXYGEN_HTML_FOOTER@ +HTML_STYLESHEET = @DOXYGEN_HTML_STYLESHEET@ +HTML_EXTRA_STYLESHEET = @DOXYGEN_HTML_EXTRA_STYLESHEET@ +HTML_EXTRA_FILES = @DOXYGEN_HTML_EXTRA_FILES@ +HTML_COLORSTYLE_HUE = @DOXYGEN_HTML_COLORSTYLE_HUE@ +HTML_COLORSTYLE_SAT = @DOXYGEN_HTML_COLORSTYLE_SAT@ +HTML_COLORSTYLE_GAMMA = @DOXYGEN_HTML_COLORSTYLE_GAMMA@ +HTML_TIMESTAMP = @DOXYGEN_HTML_TIMESTAMP@ +HTML_DYNAMIC_MENUS = @DOXYGEN_HTML_DYNAMIC_MENUS@ +HTML_DYNAMIC_SECTIONS = @DOXYGEN_HTML_DYNAMIC_SECTIONS@ +HTML_INDEX_NUM_ENTRIES = @DOXYGEN_HTML_INDEX_NUM_ENTRIES@ +GENERATE_DOCSET = @DOXYGEN_GENERATE_DOCSET@ +DOCSET_FEEDNAME = @DOXYGEN_DOCSET_FEEDNAME@ +DOCSET_FEEDURL = @DOXYGEN_DOCSET_FEEDURL@ +DOCSET_BUNDLE_ID = @DOXYGEN_DOCSET_BUNDLE_ID@ +DOCSET_PUBLISHER_ID = @DOXYGEN_DOCSET_PUBLISHER_ID@ +DOCSET_PUBLISHER_NAME = @DOXYGEN_DOCSET_PUBLISHER_NAME@ +GENERATE_HTMLHELP = @DOXYGEN_GENERATE_HTMLHELP@ +CHM_FILE = @DOXYGEN_CHM_FILE@ +HHC_LOCATION = @DOXYGEN_HHC_LOCATION@ +GENERATE_CHI = @DOXYGEN_GENERATE_CHI@ +CHM_INDEX_ENCODING = @DOXYGEN_CHM_INDEX_ENCODING@ +BINARY_TOC = @DOXYGEN_BINARY_TOC@ +TOC_EXPAND = @DOXYGEN_TOC_EXPAND@ +GENERATE_QHP = @DOXYGEN_GENERATE_QHP@ +QCH_FILE = @DOXYGEN_QCH_FILE@ +QHP_NAMESPACE = @DOXYGEN_QHP_NAMESPACE@ +QHP_VIRTUAL_FOLDER = @DOXYGEN_QHP_VIRTUAL_FOLDER@ +QHP_CUST_FILTER_NAME = @DOXYGEN_QHP_CUST_FILTER_NAME@ +QHP_CUST_FILTER_ATTRS = @DOXYGEN_QHP_CUST_FILTER_ATTRS@ +QHP_SECT_FILTER_ATTRS = @DOXYGEN_QHP_SECT_FILTER_ATTRS@ +QHG_LOCATION = @DOXYGEN_QHG_LOCATION@ +GENERATE_ECLIPSEHELP = @DOXYGEN_GENERATE_ECLIPSEHELP@ +ECLIPSE_DOC_ID = @DOXYGEN_ECLIPSE_DOC_ID@ +DISABLE_INDEX = @DOXYGEN_DISABLE_INDEX@ +GENERATE_TREEVIEW = @DOXYGEN_GENERATE_TREEVIEW@ +FULL_SIDEBAR = @DOXYGEN_FULL_SIDEBAR@ +ENUM_VALUES_PER_LINE = @DOXYGEN_ENUM_VALUES_PER_LINE@ +TREEVIEW_WIDTH = @DOXYGEN_TREEVIEW_WIDTH@ +EXT_LINKS_IN_WINDOW = @DOXYGEN_EXT_LINKS_IN_WINDOW@ +OBFUSCATE_EMAILS = @DOXYGEN_OBFUSCATE_EMAILS@ +HTML_FORMULA_FORMAT = @DOXYGEN_HTML_FORMULA_FORMAT@ +FORMULA_FONTSIZE = @DOXYGEN_FORMULA_FONTSIZE@ +FORMULA_TRANSPARENT = @DOXYGEN_FORMULA_TRANSPARENT@ +FORMULA_MACROFILE = @DOXYGEN_FORMULA_MACROFILE@ +USE_MATHJAX = @DOXYGEN_USE_MATHJAX@ +MATHJAX_VERSION = @DOXYGEN_MATHJAX_VERSION@ +MATHJAX_FORMAT = @DOXYGEN_MATHJAX_FORMAT@ +MATHJAX_RELPATH = @DOXYGEN_MATHJAX_RELPATH@ +MATHJAX_EXTENSIONS = @DOXYGEN_MATHJAX_EXTENSIONS@ +MATHJAX_CODEFILE = @DOXYGEN_MATHJAX_CODEFILE@ +SEARCHENGINE = @DOXYGEN_SEARCHENGINE@ +SERVER_BASED_SEARCH = @DOXYGEN_SERVER_BASED_SEARCH@ +EXTERNAL_SEARCH = @DOXYGEN_EXTERNAL_SEARCH@ +SEARCHENGINE_URL = @DOXYGEN_SEARCHENGINE_URL@ +SEARCHDATA_FILE = @DOXYGEN_SEARCHDATA_FILE@ +EXTERNAL_SEARCH_ID = @DOXYGEN_EXTERNAL_SEARCH_ID@ +EXTRA_SEARCH_MAPPINGS = @DOXYGEN_EXTRA_SEARCH_MAPPINGS@ +GENERATE_LATEX = @DOXYGEN_GENERATE_LATEX@ +LATEX_OUTPUT = @DOXYGEN_LATEX_OUTPUT@ +LATEX_CMD_NAME = @DOXYGEN_LATEX_CMD_NAME@ +MAKEINDEX_CMD_NAME = @DOXYGEN_MAKEINDEX_CMD_NAME@ +LATEX_MAKEINDEX_CMD = @DOXYGEN_LATEX_MAKEINDEX_CMD@ +COMPACT_LATEX = @DOXYGEN_COMPACT_LATEX@ +PAPER_TYPE = @DOXYGEN_PAPER_TYPE@ +EXTRA_PACKAGES = @DOXYGEN_EXTRA_PACKAGES@ +LATEX_HEADER = @DOXYGEN_LATEX_HEADER@ +LATEX_FOOTER = @DOXYGEN_LATEX_FOOTER@ +LATEX_EXTRA_STYLESHEET = @DOXYGEN_LATEX_EXTRA_STYLESHEET@ +LATEX_EXTRA_FILES = @DOXYGEN_LATEX_EXTRA_FILES@ +PDF_HYPERLINKS = @DOXYGEN_PDF_HYPERLINKS@ +USE_PDFLATEX = @DOXYGEN_USE_PDFLATEX@ +LATEX_BATCHMODE = @DOXYGEN_LATEX_BATCHMODE@ +LATEX_HIDE_INDICES = @DOXYGEN_LATEX_HIDE_INDICES@ +LATEX_BIB_STYLE = @DOXYGEN_LATEX_BIB_STYLE@ +LATEX_TIMESTAMP = @DOXYGEN_LATEX_TIMESTAMP@ +LATEX_EMOJI_DIRECTORY = @DOXYGEN_LATEX_EMOJI_DIRECTORY@ +GENERATE_RTF = @DOXYGEN_GENERATE_RTF@ +RTF_OUTPUT = @DOXYGEN_RTF_OUTPUT@ +COMPACT_RTF = @DOXYGEN_COMPACT_RTF@ +RTF_HYPERLINKS = @DOXYGEN_RTF_HYPERLINKS@ +RTF_STYLESHEET_FILE = @DOXYGEN_RTF_STYLESHEET_FILE@ +RTF_EXTENSIONS_FILE = @DOXYGEN_RTF_EXTENSIONS_FILE@ +GENERATE_MAN = @DOXYGEN_GENERATE_MAN@ +MAN_OUTPUT = @DOXYGEN_MAN_OUTPUT@ +MAN_EXTENSION = @DOXYGEN_MAN_EXTENSION@ +MAN_SUBDIR = @DOXYGEN_MAN_SUBDIR@ +MAN_LINKS = @DOXYGEN_MAN_LINKS@ +GENERATE_XML = @DOXYGEN_GENERATE_XML@ +XML_OUTPUT = @DOXYGEN_XML_OUTPUT@ +XML_PROGRAMLISTING = @DOXYGEN_XML_PROGRAMLISTING@ +XML_NS_MEMB_FILE_SCOPE = @DOXYGEN_XML_NS_MEMB_FILE_SCOPE@ +GENERATE_DOCBOOK = @DOXYGEN_GENERATE_DOCBOOK@ +DOCBOOK_OUTPUT = @DOXYGEN_DOCBOOK_OUTPUT@ +GENERATE_AUTOGEN_DEF = @DOXYGEN_GENERATE_AUTOGEN_DEF@ +GENERATE_PERLMOD = @DOXYGEN_GENERATE_PERLMOD@ +PERLMOD_LATEX = @DOXYGEN_PERLMOD_LATEX@ +PERLMOD_PRETTY = @DOXYGEN_PERLMOD_PRETTY@ +PERLMOD_MAKEVAR_PREFIX = @DOXYGEN_PERLMOD_MAKEVAR_PREFIX@ +ENABLE_PREPROCESSING = @DOXYGEN_ENABLE_PREPROCESSING@ +MACRO_EXPANSION = @DOXYGEN_MACRO_EXPANSION@ +EXPAND_ONLY_PREDEF = @DOXYGEN_EXPAND_ONLY_PREDEF@ +SEARCH_INCLUDES = @DOXYGEN_SEARCH_INCLUDES@ +INCLUDE_PATH = @DOXYGEN_INCLUDE_PATH@ +INCLUDE_FILE_PATTERNS = @DOXYGEN_INCLUDE_FILE_PATTERNS@ +PREDEFINED = @DOXYGEN_PREDEFINED@ +EXPAND_AS_DEFINED = @DOXYGEN_EXPAND_AS_DEFINED@ +SKIP_FUNCTION_MACROS = @DOXYGEN_SKIP_FUNCTION_MACROS@ +TAGFILES = @DOXYGEN_TAGFILES@ +GENERATE_TAGFILE = @DOXYGEN_GENERATE_TAGFILE@ +ALLEXTERNALS = @DOXYGEN_ALLEXTERNALS@ +EXTERNAL_GROUPS = @DOXYGEN_EXTERNAL_GROUPS@ +EXTERNAL_PAGES = @DOXYGEN_EXTERNAL_PAGES@ +DIA_PATH = @DOXYGEN_DIA_PATH@ +HIDE_UNDOC_RELATIONS = @DOXYGEN_HIDE_UNDOC_RELATIONS@ +HAVE_DOT = @DOXYGEN_HAVE_DOT@ +DOT_NUM_THREADS = @DOXYGEN_DOT_NUM_THREADS@ +DOT_FONTNAME = @DOXYGEN_DOT_FONTNAME@ +DOT_FONTSIZE = @DOXYGEN_DOT_FONTSIZE@ +DOT_FONTPATH = @DOXYGEN_DOT_FONTPATH@ +CLASS_GRAPH = @DOXYGEN_CLASS_GRAPH@ +COLLABORATION_GRAPH = @DOXYGEN_COLLABORATION_GRAPH@ +GROUP_GRAPHS = @DOXYGEN_GROUP_GRAPHS@ +UML_LOOK = @DOXYGEN_UML_LOOK@ +UML_LIMIT_NUM_FIELDS = @DOXYGEN_UML_LIMIT_NUM_FIELDS@ +DOT_UML_DETAILS = @DOXYGEN_DOT_UML_DETAILS@ +DOT_WRAP_THRESHOLD = @DOXYGEN_DOT_WRAP_THRESHOLD@ +TEMPLATE_RELATIONS = @DOXYGEN_TEMPLATE_RELATIONS@ +INCLUDE_GRAPH = @DOXYGEN_INCLUDE_GRAPH@ +INCLUDED_BY_GRAPH = @DOXYGEN_INCLUDED_BY_GRAPH@ +CALL_GRAPH = @DOXYGEN_CALL_GRAPH@ +CALLER_GRAPH = @DOXYGEN_CALLER_GRAPH@ +GRAPHICAL_HIERARCHY = @DOXYGEN_GRAPHICAL_HIERARCHY@ +DIRECTORY_GRAPH = @DOXYGEN_DIRECTORY_GRAPH@ +DIR_GRAPH_MAX_DEPTH = @DOXYGEN_DIR_GRAPH_MAX_DEPTH@ +DOT_IMAGE_FORMAT = @DOXYGEN_DOT_IMAGE_FORMAT@ +INTERACTIVE_SVG = @DOXYGEN_INTERACTIVE_SVG@ +DOT_PATH = @DOXYGEN_DOT_PATH@ +DOTFILE_DIRS = @DOXYGEN_DOTFILE_DIRS@ +MSCFILE_DIRS = @DOXYGEN_MSCFILE_DIRS@ +DIAFILE_DIRS = @DOXYGEN_DIAFILE_DIRS@ +PLANTUML_JAR_PATH = @DOXYGEN_PLANTUML_JAR_PATH@ +PLANTUML_CFG_FILE = @DOXYGEN_PLANTUML_CFG_FILE@ +PLANTUML_INCLUDE_PATH = @DOXYGEN_PLANTUML_INCLUDE_PATH@ +DOT_GRAPH_MAX_NODES = @DOXYGEN_DOT_GRAPH_MAX_NODES@ +MAX_DOT_GRAPH_DEPTH = @DOXYGEN_MAX_DOT_GRAPH_DEPTH@ +DOT_TRANSPARENT = @DOXYGEN_DOT_TRANSPARENT@ +DOT_MULTI_TARGETS = @DOXYGEN_DOT_MULTI_TARGETS@ +GENERATE_LEGEND = @DOXYGEN_GENERATE_LEGEND@ +DOT_CLEANUP = @DOXYGEN_DOT_CLEANUP@ diff --git a/CMakeDoxygenDefaults.cmake b/CMakeDoxygenDefaults.cmake new file mode 100644 index 0000000..2976718 --- /dev/null +++ b/CMakeDoxygenDefaults.cmake @@ -0,0 +1,695 @@ +# +# DO NOT EDIT! THIS FILE WAS GENERATED BY CMAKE! +# + +if(NOT DEFINED DOXYGEN_DOXYFILE_ENCODING) + set(DOXYGEN_DOXYFILE_ENCODING UTF-8) +endif() +if(NOT DEFINED DOXYGEN_PROJECT_NAME) + set(DOXYGEN_PROJECT_NAME "My Project") +endif() +if(NOT DEFINED DOXYGEN_CREATE_SUBDIRS) + set(DOXYGEN_CREATE_SUBDIRS NO) +endif() +if(NOT DEFINED DOXYGEN_CREATE_SUBDIRS_LEVEL) + set(DOXYGEN_CREATE_SUBDIRS_LEVEL 8) +endif() +if(NOT DEFINED DOXYGEN_ALLOW_UNICODE_NAMES) + set(DOXYGEN_ALLOW_UNICODE_NAMES NO) +endif() +if(NOT DEFINED DOXYGEN_OUTPUT_LANGUAGE) + set(DOXYGEN_OUTPUT_LANGUAGE English) +endif() +if(NOT DEFINED DOXYGEN_BRIEF_MEMBER_DESC) + set(DOXYGEN_BRIEF_MEMBER_DESC YES) +endif() +if(NOT DEFINED DOXYGEN_REPEAT_BRIEF) + set(DOXYGEN_REPEAT_BRIEF YES) +endif() +if(NOT DEFINED DOXYGEN_ABBREVIATE_BRIEF) + set(DOXYGEN_ABBREVIATE_BRIEF "The $name class" + "The $name widget" + "The $name file" + is + provides + specifies + contains + represents + a + an + the) +endif() +if(NOT DEFINED DOXYGEN_ALWAYS_DETAILED_SEC) + set(DOXYGEN_ALWAYS_DETAILED_SEC NO) +endif() +if(NOT DEFINED DOXYGEN_INLINE_INHERITED_MEMB) + set(DOXYGEN_INLINE_INHERITED_MEMB NO) +endif() +if(NOT DEFINED DOXYGEN_FULL_PATH_NAMES) + set(DOXYGEN_FULL_PATH_NAMES YES) +endif() +if(NOT DEFINED DOXYGEN_SHORT_NAMES) + set(DOXYGEN_SHORT_NAMES NO) +endif() +if(NOT DEFINED DOXYGEN_JAVADOC_AUTOBRIEF) + set(DOXYGEN_JAVADOC_AUTOBRIEF NO) +endif() +if(NOT DEFINED DOXYGEN_JAVADOC_BANNER) + set(DOXYGEN_JAVADOC_BANNER NO) +endif() +if(NOT DEFINED DOXYGEN_QT_AUTOBRIEF) + set(DOXYGEN_QT_AUTOBRIEF NO) +endif() +if(NOT DEFINED DOXYGEN_MULTILINE_CPP_IS_BRIEF) + set(DOXYGEN_MULTILINE_CPP_IS_BRIEF NO) +endif() +if(NOT DEFINED DOXYGEN_PYTHON_DOCSTRING) + set(DOXYGEN_PYTHON_DOCSTRING YES) +endif() +if(NOT DEFINED DOXYGEN_INHERIT_DOCS) + set(DOXYGEN_INHERIT_DOCS YES) +endif() +if(NOT DEFINED DOXYGEN_SEPARATE_MEMBER_PAGES) + set(DOXYGEN_SEPARATE_MEMBER_PAGES NO) +endif() +if(NOT DEFINED DOXYGEN_TAB_SIZE) + set(DOXYGEN_TAB_SIZE 4) +endif() +if(NOT DEFINED DOXYGEN_OPTIMIZE_OUTPUT_FOR_C) + set(DOXYGEN_OPTIMIZE_OUTPUT_FOR_C NO) +endif() +if(NOT DEFINED DOXYGEN_OPTIMIZE_OUTPUT_JAVA) + set(DOXYGEN_OPTIMIZE_OUTPUT_JAVA NO) +endif() +if(NOT DEFINED DOXYGEN_OPTIMIZE_FOR_FORTRAN) + set(DOXYGEN_OPTIMIZE_FOR_FORTRAN NO) +endif() +if(NOT DEFINED DOXYGEN_OPTIMIZE_OUTPUT_VHDL) + set(DOXYGEN_OPTIMIZE_OUTPUT_VHDL NO) +endif() +if(NOT DEFINED DOXYGEN_OPTIMIZE_OUTPUT_SLICE) + set(DOXYGEN_OPTIMIZE_OUTPUT_SLICE NO) +endif() +if(NOT DEFINED DOXYGEN_MARKDOWN_SUPPORT) + set(DOXYGEN_MARKDOWN_SUPPORT YES) +endif() +if(NOT DEFINED DOXYGEN_TOC_INCLUDE_HEADINGS) + set(DOXYGEN_TOC_INCLUDE_HEADINGS 5) +endif() +if(NOT DEFINED DOXYGEN_AUTOLINK_SUPPORT) + set(DOXYGEN_AUTOLINK_SUPPORT YES) +endif() +if(NOT DEFINED DOXYGEN_BUILTIN_STL_SUPPORT) + set(DOXYGEN_BUILTIN_STL_SUPPORT NO) +endif() +if(NOT DEFINED DOXYGEN_CPP_CLI_SUPPORT) + set(DOXYGEN_CPP_CLI_SUPPORT NO) +endif() +if(NOT DEFINED DOXYGEN_SIP_SUPPORT) + set(DOXYGEN_SIP_SUPPORT NO) +endif() +if(NOT DEFINED DOXYGEN_IDL_PROPERTY_SUPPORT) + set(DOXYGEN_IDL_PROPERTY_SUPPORT YES) +endif() +if(NOT DEFINED DOXYGEN_DISTRIBUTE_GROUP_DOC) + set(DOXYGEN_DISTRIBUTE_GROUP_DOC NO) +endif() +if(NOT DEFINED DOXYGEN_GROUP_NESTED_COMPOUNDS) + set(DOXYGEN_GROUP_NESTED_COMPOUNDS NO) +endif() +if(NOT DEFINED DOXYGEN_SUBGROUPING) + set(DOXYGEN_SUBGROUPING YES) +endif() +if(NOT DEFINED DOXYGEN_INLINE_GROUPED_CLASSES) + set(DOXYGEN_INLINE_GROUPED_CLASSES NO) +endif() +if(NOT DEFINED DOXYGEN_INLINE_SIMPLE_STRUCTS) + set(DOXYGEN_INLINE_SIMPLE_STRUCTS NO) +endif() +if(NOT DEFINED DOXYGEN_TYPEDEF_HIDES_STRUCT) + set(DOXYGEN_TYPEDEF_HIDES_STRUCT NO) +endif() +if(NOT DEFINED DOXYGEN_LOOKUP_CACHE_SIZE) + set(DOXYGEN_LOOKUP_CACHE_SIZE 0) +endif() +if(NOT DEFINED DOXYGEN_NUM_PROC_THREADS) + set(DOXYGEN_NUM_PROC_THREADS 1) +endif() +if(NOT DEFINED DOXYGEN_EXTRACT_ALL) + set(DOXYGEN_EXTRACT_ALL NO) +endif() +if(NOT DEFINED DOXYGEN_EXTRACT_PRIVATE) + set(DOXYGEN_EXTRACT_PRIVATE NO) +endif() +if(NOT DEFINED DOXYGEN_EXTRACT_PRIV_VIRTUAL) + set(DOXYGEN_EXTRACT_PRIV_VIRTUAL NO) +endif() +if(NOT DEFINED DOXYGEN_EXTRACT_PACKAGE) + set(DOXYGEN_EXTRACT_PACKAGE NO) +endif() +if(NOT DEFINED DOXYGEN_EXTRACT_STATIC) + set(DOXYGEN_EXTRACT_STATIC NO) +endif() +if(NOT DEFINED DOXYGEN_EXTRACT_LOCAL_CLASSES) + set(DOXYGEN_EXTRACT_LOCAL_CLASSES YES) +endif() +if(NOT DEFINED DOXYGEN_EXTRACT_LOCAL_METHODS) + set(DOXYGEN_EXTRACT_LOCAL_METHODS NO) +endif() +if(NOT DEFINED DOXYGEN_EXTRACT_ANON_NSPACES) + set(DOXYGEN_EXTRACT_ANON_NSPACES NO) +endif() +if(NOT DEFINED DOXYGEN_RESOLVE_UNNAMED_PARAMS) + set(DOXYGEN_RESOLVE_UNNAMED_PARAMS YES) +endif() +if(NOT DEFINED DOXYGEN_HIDE_UNDOC_MEMBERS) + set(DOXYGEN_HIDE_UNDOC_MEMBERS NO) +endif() +if(NOT DEFINED DOXYGEN_HIDE_UNDOC_CLASSES) + set(DOXYGEN_HIDE_UNDOC_CLASSES NO) +endif() +if(NOT DEFINED DOXYGEN_HIDE_FRIEND_COMPOUNDS) + set(DOXYGEN_HIDE_FRIEND_COMPOUNDS NO) +endif() +if(NOT DEFINED DOXYGEN_HIDE_IN_BODY_DOCS) + set(DOXYGEN_HIDE_IN_BODY_DOCS NO) +endif() +if(NOT DEFINED DOXYGEN_INTERNAL_DOCS) + set(DOXYGEN_INTERNAL_DOCS NO) +endif() +if(NOT DEFINED DOXYGEN_CASE_SENSE_NAMES) + set(DOXYGEN_CASE_SENSE_NAMES YES) +endif() +if(NOT DEFINED DOXYGEN_HIDE_SCOPE_NAMES) + set(DOXYGEN_HIDE_SCOPE_NAMES NO) +endif() +if(NOT DEFINED DOXYGEN_HIDE_COMPOUND_REFERENCE) + set(DOXYGEN_HIDE_COMPOUND_REFERENCE NO) +endif() +if(NOT DEFINED DOXYGEN_SHOW_HEADERFILE) + set(DOXYGEN_SHOW_HEADERFILE YES) +endif() +if(NOT DEFINED DOXYGEN_SHOW_INCLUDE_FILES) + set(DOXYGEN_SHOW_INCLUDE_FILES YES) +endif() +if(NOT DEFINED DOXYGEN_SHOW_GROUPED_MEMB_INC) + set(DOXYGEN_SHOW_GROUPED_MEMB_INC NO) +endif() +if(NOT DEFINED DOXYGEN_FORCE_LOCAL_INCLUDES) + set(DOXYGEN_FORCE_LOCAL_INCLUDES NO) +endif() +if(NOT DEFINED DOXYGEN_INLINE_INFO) + set(DOXYGEN_INLINE_INFO YES) +endif() +if(NOT DEFINED DOXYGEN_SORT_MEMBER_DOCS) + set(DOXYGEN_SORT_MEMBER_DOCS YES) +endif() +if(NOT DEFINED DOXYGEN_SORT_BRIEF_DOCS) + set(DOXYGEN_SORT_BRIEF_DOCS NO) +endif() +if(NOT DEFINED DOXYGEN_SORT_MEMBERS_CTORS_1ST) + set(DOXYGEN_SORT_MEMBERS_CTORS_1ST NO) +endif() +if(NOT DEFINED DOXYGEN_SORT_GROUP_NAMES) + set(DOXYGEN_SORT_GROUP_NAMES NO) +endif() +if(NOT DEFINED DOXYGEN_SORT_BY_SCOPE_NAME) + set(DOXYGEN_SORT_BY_SCOPE_NAME NO) +endif() +if(NOT DEFINED DOXYGEN_STRICT_PROTO_MATCHING) + set(DOXYGEN_STRICT_PROTO_MATCHING NO) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_TODOLIST) + set(DOXYGEN_GENERATE_TODOLIST YES) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_TESTLIST) + set(DOXYGEN_GENERATE_TESTLIST YES) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_BUGLIST) + set(DOXYGEN_GENERATE_BUGLIST YES) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_DEPRECATEDLIST) + set(DOXYGEN_GENERATE_DEPRECATEDLIST YES) +endif() +if(NOT DEFINED DOXYGEN_MAX_INITIALIZER_LINES) + set(DOXYGEN_MAX_INITIALIZER_LINES 30) +endif() +if(NOT DEFINED DOXYGEN_SHOW_USED_FILES) + set(DOXYGEN_SHOW_USED_FILES YES) +endif() +if(NOT DEFINED DOXYGEN_SHOW_FILES) + set(DOXYGEN_SHOW_FILES YES) +endif() +if(NOT DEFINED DOXYGEN_SHOW_NAMESPACES) + set(DOXYGEN_SHOW_NAMESPACES YES) +endif() +if(NOT DEFINED DOXYGEN_QUIET) + set(DOXYGEN_QUIET NO) +endif() +if(NOT DEFINED DOXYGEN_WARNINGS) + set(DOXYGEN_WARNINGS YES) +endif() +if(NOT DEFINED DOXYGEN_WARN_IF_UNDOCUMENTED) + set(DOXYGEN_WARN_IF_UNDOCUMENTED YES) +endif() +if(NOT DEFINED DOXYGEN_WARN_IF_DOC_ERROR) + set(DOXYGEN_WARN_IF_DOC_ERROR YES) +endif() +if(NOT DEFINED DOXYGEN_WARN_IF_INCOMPLETE_DOC) + set(DOXYGEN_WARN_IF_INCOMPLETE_DOC YES) +endif() +if(NOT DEFINED DOXYGEN_WARN_NO_PARAMDOC) + set(DOXYGEN_WARN_NO_PARAMDOC NO) +endif() +if(NOT DEFINED DOXYGEN_WARN_AS_ERROR) + set(DOXYGEN_WARN_AS_ERROR NO) +endif() +if(NOT DEFINED DOXYGEN_WARN_FORMAT) + set(DOXYGEN_WARN_FORMAT "$file:$line: $text") +endif() +if(NOT DEFINED DOXYGEN_WARN_LINE_FORMAT) + set(DOXYGEN_WARN_LINE_FORMAT "at line $line of file $file") +endif() +if(NOT DEFINED DOXYGEN_INPUT_ENCODING) + set(DOXYGEN_INPUT_ENCODING UTF-8) +endif() +if(NOT DEFINED DOXYGEN_FILE_PATTERNS) + set(DOXYGEN_FILE_PATTERNS *.c + *.cc + *.cxx + *.cpp + *.c++ + *.java + *.ii + *.ixx + *.ipp + *.i++ + *.inl + *.idl + *.ddl + *.odl + *.h + *.hh + *.hxx + *.hpp + *.h++ + *.l + *.cs + *.d + *.php + *.php4 + *.php5 + *.phtml + *.inc + *.m + *.markdown + *.md + *.mm + *.dox + *.py + *.pyw + *.f90 + *.f95 + *.f03 + *.f08 + *.f18 + *.f + *.for + *.vhd + *.vhdl + *.ucf + *.qsf + *.ice) +endif() +if(NOT DEFINED DOXYGEN_RECURSIVE) + set(DOXYGEN_RECURSIVE NO) +endif() +if(NOT DEFINED DOXYGEN_EXCLUDE_SYMLINKS) + set(DOXYGEN_EXCLUDE_SYMLINKS NO) +endif() +if(NOT DEFINED DOXYGEN_EXAMPLE_PATTERNS) + set(DOXYGEN_EXAMPLE_PATTERNS *) +endif() +if(NOT DEFINED DOXYGEN_EXAMPLE_RECURSIVE) + set(DOXYGEN_EXAMPLE_RECURSIVE NO) +endif() +if(NOT DEFINED DOXYGEN_FILTER_SOURCE_FILES) + set(DOXYGEN_FILTER_SOURCE_FILES NO) +endif() +if(NOT DEFINED DOXYGEN_SOURCE_BROWSER) + set(DOXYGEN_SOURCE_BROWSER NO) +endif() +if(NOT DEFINED DOXYGEN_INLINE_SOURCES) + set(DOXYGEN_INLINE_SOURCES NO) +endif() +if(NOT DEFINED DOXYGEN_STRIP_CODE_COMMENTS) + set(DOXYGEN_STRIP_CODE_COMMENTS YES) +endif() +if(NOT DEFINED DOXYGEN_REFERENCED_BY_RELATION) + set(DOXYGEN_REFERENCED_BY_RELATION NO) +endif() +if(NOT DEFINED DOXYGEN_REFERENCES_RELATION) + set(DOXYGEN_REFERENCES_RELATION NO) +endif() +if(NOT DEFINED DOXYGEN_REFERENCES_LINK_SOURCE) + set(DOXYGEN_REFERENCES_LINK_SOURCE YES) +endif() +if(NOT DEFINED DOXYGEN_SOURCE_TOOLTIPS) + set(DOXYGEN_SOURCE_TOOLTIPS YES) +endif() +if(NOT DEFINED DOXYGEN_USE_HTAGS) + set(DOXYGEN_USE_HTAGS NO) +endif() +if(NOT DEFINED DOXYGEN_VERBATIM_HEADERS) + set(DOXYGEN_VERBATIM_HEADERS YES) +endif() +if(NOT DEFINED DOXYGEN_CLANG_ASSISTED_PARSING) + set(DOXYGEN_CLANG_ASSISTED_PARSING NO) +endif() +if(NOT DEFINED DOXYGEN_CLANG_ADD_INC_PATHS) + set(DOXYGEN_CLANG_ADD_INC_PATHS YES) +endif() +if(NOT DEFINED DOXYGEN_ALPHABETICAL_INDEX) + set(DOXYGEN_ALPHABETICAL_INDEX YES) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_HTML) + set(DOXYGEN_GENERATE_HTML YES) +endif() +if(NOT DEFINED DOXYGEN_HTML_OUTPUT) + set(DOXYGEN_HTML_OUTPUT html) +endif() +if(NOT DEFINED DOXYGEN_HTML_FILE_EXTENSION) + set(DOXYGEN_HTML_FILE_EXTENSION .html) +endif() +if(NOT DEFINED DOXYGEN_HTML_COLORSTYLE_HUE) + set(DOXYGEN_HTML_COLORSTYLE_HUE 220) +endif() +if(NOT DEFINED DOXYGEN_HTML_COLORSTYLE_SAT) + set(DOXYGEN_HTML_COLORSTYLE_SAT 100) +endif() +if(NOT DEFINED DOXYGEN_HTML_COLORSTYLE_GAMMA) + set(DOXYGEN_HTML_COLORSTYLE_GAMMA 80) +endif() +if(NOT DEFINED DOXYGEN_HTML_TIMESTAMP) + set(DOXYGEN_HTML_TIMESTAMP NO) +endif() +if(NOT DEFINED DOXYGEN_HTML_DYNAMIC_MENUS) + set(DOXYGEN_HTML_DYNAMIC_MENUS YES) +endif() +if(NOT DEFINED DOXYGEN_HTML_DYNAMIC_SECTIONS) + set(DOXYGEN_HTML_DYNAMIC_SECTIONS NO) +endif() +if(NOT DEFINED DOXYGEN_HTML_INDEX_NUM_ENTRIES) + set(DOXYGEN_HTML_INDEX_NUM_ENTRIES 100) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_DOCSET) + set(DOXYGEN_GENERATE_DOCSET NO) +endif() +if(NOT DEFINED DOXYGEN_DOCSET_FEEDNAME) + set(DOXYGEN_DOCSET_FEEDNAME "Doxygen generated docs") +endif() +if(NOT DEFINED DOXYGEN_DOCSET_BUNDLE_ID) + set(DOXYGEN_DOCSET_BUNDLE_ID org.doxygen.Project) +endif() +if(NOT DEFINED DOXYGEN_DOCSET_PUBLISHER_ID) + set(DOXYGEN_DOCSET_PUBLISHER_ID org.doxygen.Publisher) +endif() +if(NOT DEFINED DOXYGEN_DOCSET_PUBLISHER_NAME) + set(DOXYGEN_DOCSET_PUBLISHER_NAME Publisher) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_HTMLHELP) + set(DOXYGEN_GENERATE_HTMLHELP NO) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_CHI) + set(DOXYGEN_GENERATE_CHI NO) +endif() +if(NOT DEFINED DOXYGEN_BINARY_TOC) + set(DOXYGEN_BINARY_TOC NO) +endif() +if(NOT DEFINED DOXYGEN_TOC_EXPAND) + set(DOXYGEN_TOC_EXPAND NO) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_QHP) + set(DOXYGEN_GENERATE_QHP NO) +endif() +if(NOT DEFINED DOXYGEN_QHP_NAMESPACE) + set(DOXYGEN_QHP_NAMESPACE org.doxygen.Project) +endif() +if(NOT DEFINED DOXYGEN_QHP_VIRTUAL_FOLDER) + set(DOXYGEN_QHP_VIRTUAL_FOLDER doc) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_ECLIPSEHELP) + set(DOXYGEN_GENERATE_ECLIPSEHELP NO) +endif() +if(NOT DEFINED DOXYGEN_ECLIPSE_DOC_ID) + set(DOXYGEN_ECLIPSE_DOC_ID org.doxygen.Project) +endif() +if(NOT DEFINED DOXYGEN_DISABLE_INDEX) + set(DOXYGEN_DISABLE_INDEX NO) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_TREEVIEW) + set(DOXYGEN_GENERATE_TREEVIEW NO) +endif() +if(NOT DEFINED DOXYGEN_FULL_SIDEBAR) + set(DOXYGEN_FULL_SIDEBAR NO) +endif() +if(NOT DEFINED DOXYGEN_ENUM_VALUES_PER_LINE) + set(DOXYGEN_ENUM_VALUES_PER_LINE 4) +endif() +if(NOT DEFINED DOXYGEN_TREEVIEW_WIDTH) + set(DOXYGEN_TREEVIEW_WIDTH 250) +endif() +if(NOT DEFINED DOXYGEN_EXT_LINKS_IN_WINDOW) + set(DOXYGEN_EXT_LINKS_IN_WINDOW NO) +endif() +if(NOT DEFINED DOXYGEN_OBFUSCATE_EMAILS) + set(DOXYGEN_OBFUSCATE_EMAILS YES) +endif() +if(NOT DEFINED DOXYGEN_HTML_FORMULA_FORMAT) + set(DOXYGEN_HTML_FORMULA_FORMAT png) +endif() +if(NOT DEFINED DOXYGEN_FORMULA_FONTSIZE) + set(DOXYGEN_FORMULA_FONTSIZE 10) +endif() +if(NOT DEFINED DOXYGEN_FORMULA_TRANSPARENT) + set(DOXYGEN_FORMULA_TRANSPARENT YES) +endif() +if(NOT DEFINED DOXYGEN_USE_MATHJAX) + set(DOXYGEN_USE_MATHJAX NO) +endif() +if(NOT DEFINED DOXYGEN_MATHJAX_VERSION) + set(DOXYGEN_MATHJAX_VERSION MathJax_2) +endif() +if(NOT DEFINED DOXYGEN_MATHJAX_FORMAT) + set(DOXYGEN_MATHJAX_FORMAT HTML-CSS) +endif() +if(NOT DEFINED DOXYGEN_SEARCHENGINE) + set(DOXYGEN_SEARCHENGINE YES) +endif() +if(NOT DEFINED DOXYGEN_SERVER_BASED_SEARCH) + set(DOXYGEN_SERVER_BASED_SEARCH NO) +endif() +if(NOT DEFINED DOXYGEN_EXTERNAL_SEARCH) + set(DOXYGEN_EXTERNAL_SEARCH NO) +endif() +if(NOT DEFINED DOXYGEN_SEARCHDATA_FILE) + set(DOXYGEN_SEARCHDATA_FILE searchdata.xml) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_LATEX) + set(DOXYGEN_GENERATE_LATEX YES) +endif() +if(NOT DEFINED DOXYGEN_LATEX_OUTPUT) + set(DOXYGEN_LATEX_OUTPUT latex) +endif() +if(NOT DEFINED DOXYGEN_MAKEINDEX_CMD_NAME) + set(DOXYGEN_MAKEINDEX_CMD_NAME makeindex) +endif() +if(NOT DEFINED DOXYGEN_LATEX_MAKEINDEX_CMD) + set(DOXYGEN_LATEX_MAKEINDEX_CMD makeindex) +endif() +if(NOT DEFINED DOXYGEN_COMPACT_LATEX) + set(DOXYGEN_COMPACT_LATEX NO) +endif() +if(NOT DEFINED DOXYGEN_PAPER_TYPE) + set(DOXYGEN_PAPER_TYPE a4) +endif() +if(NOT DEFINED DOXYGEN_PDF_HYPERLINKS) + set(DOXYGEN_PDF_HYPERLINKS YES) +endif() +if(NOT DEFINED DOXYGEN_USE_PDFLATEX) + set(DOXYGEN_USE_PDFLATEX YES) +endif() +if(NOT DEFINED DOXYGEN_LATEX_BATCHMODE) + set(DOXYGEN_LATEX_BATCHMODE NO) +endif() +if(NOT DEFINED DOXYGEN_LATEX_HIDE_INDICES) + set(DOXYGEN_LATEX_HIDE_INDICES NO) +endif() +if(NOT DEFINED DOXYGEN_LATEX_BIB_STYLE) + set(DOXYGEN_LATEX_BIB_STYLE plain) +endif() +if(NOT DEFINED DOXYGEN_LATEX_TIMESTAMP) + set(DOXYGEN_LATEX_TIMESTAMP NO) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_RTF) + set(DOXYGEN_GENERATE_RTF NO) +endif() +if(NOT DEFINED DOXYGEN_RTF_OUTPUT) + set(DOXYGEN_RTF_OUTPUT rtf) +endif() +if(NOT DEFINED DOXYGEN_COMPACT_RTF) + set(DOXYGEN_COMPACT_RTF NO) +endif() +if(NOT DEFINED DOXYGEN_RTF_HYPERLINKS) + set(DOXYGEN_RTF_HYPERLINKS NO) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_MAN) + set(DOXYGEN_GENERATE_MAN NO) +endif() +if(NOT DEFINED DOXYGEN_MAN_OUTPUT) + set(DOXYGEN_MAN_OUTPUT man) +endif() +if(NOT DEFINED DOXYGEN_MAN_EXTENSION) + set(DOXYGEN_MAN_EXTENSION .3) +endif() +if(NOT DEFINED DOXYGEN_MAN_LINKS) + set(DOXYGEN_MAN_LINKS NO) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_XML) + set(DOXYGEN_GENERATE_XML NO) +endif() +if(NOT DEFINED DOXYGEN_XML_OUTPUT) + set(DOXYGEN_XML_OUTPUT xml) +endif() +if(NOT DEFINED DOXYGEN_XML_PROGRAMLISTING) + set(DOXYGEN_XML_PROGRAMLISTING YES) +endif() +if(NOT DEFINED DOXYGEN_XML_NS_MEMB_FILE_SCOPE) + set(DOXYGEN_XML_NS_MEMB_FILE_SCOPE NO) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_DOCBOOK) + set(DOXYGEN_GENERATE_DOCBOOK NO) +endif() +if(NOT DEFINED DOXYGEN_DOCBOOK_OUTPUT) + set(DOXYGEN_DOCBOOK_OUTPUT docbook) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_AUTOGEN_DEF) + set(DOXYGEN_GENERATE_AUTOGEN_DEF NO) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_PERLMOD) + set(DOXYGEN_GENERATE_PERLMOD NO) +endif() +if(NOT DEFINED DOXYGEN_PERLMOD_LATEX) + set(DOXYGEN_PERLMOD_LATEX NO) +endif() +if(NOT DEFINED DOXYGEN_PERLMOD_PRETTY) + set(DOXYGEN_PERLMOD_PRETTY YES) +endif() +if(NOT DEFINED DOXYGEN_ENABLE_PREPROCESSING) + set(DOXYGEN_ENABLE_PREPROCESSING YES) +endif() +if(NOT DEFINED DOXYGEN_MACRO_EXPANSION) + set(DOXYGEN_MACRO_EXPANSION NO) +endif() +if(NOT DEFINED DOXYGEN_EXPAND_ONLY_PREDEF) + set(DOXYGEN_EXPAND_ONLY_PREDEF NO) +endif() +if(NOT DEFINED DOXYGEN_SEARCH_INCLUDES) + set(DOXYGEN_SEARCH_INCLUDES YES) +endif() +if(NOT DEFINED DOXYGEN_SKIP_FUNCTION_MACROS) + set(DOXYGEN_SKIP_FUNCTION_MACROS YES) +endif() +if(NOT DEFINED DOXYGEN_ALLEXTERNALS) + set(DOXYGEN_ALLEXTERNALS NO) +endif() +if(NOT DEFINED DOXYGEN_EXTERNAL_GROUPS) + set(DOXYGEN_EXTERNAL_GROUPS YES) +endif() +if(NOT DEFINED DOXYGEN_EXTERNAL_PAGES) + set(DOXYGEN_EXTERNAL_PAGES YES) +endif() +if(NOT DEFINED DOXYGEN_HIDE_UNDOC_RELATIONS) + set(DOXYGEN_HIDE_UNDOC_RELATIONS YES) +endif() +if(NOT DEFINED DOXYGEN_HAVE_DOT) + set(DOXYGEN_HAVE_DOT YES) +endif() +if(NOT DEFINED DOXYGEN_DOT_NUM_THREADS) + set(DOXYGEN_DOT_NUM_THREADS 0) +endif() +if(NOT DEFINED DOXYGEN_DOT_FONTNAME) + set(DOXYGEN_DOT_FONTNAME Helvetica) +endif() +if(NOT DEFINED DOXYGEN_DOT_FONTSIZE) + set(DOXYGEN_DOT_FONTSIZE 10) +endif() +if(NOT DEFINED DOXYGEN_CLASS_GRAPH) + set(DOXYGEN_CLASS_GRAPH YES) +endif() +if(NOT DEFINED DOXYGEN_COLLABORATION_GRAPH) + set(DOXYGEN_COLLABORATION_GRAPH YES) +endif() +if(NOT DEFINED DOXYGEN_GROUP_GRAPHS) + set(DOXYGEN_GROUP_GRAPHS YES) +endif() +if(NOT DEFINED DOXYGEN_UML_LOOK) + set(DOXYGEN_UML_LOOK NO) +endif() +if(NOT DEFINED DOXYGEN_UML_LIMIT_NUM_FIELDS) + set(DOXYGEN_UML_LIMIT_NUM_FIELDS 10) +endif() +if(NOT DEFINED DOXYGEN_DOT_UML_DETAILS) + set(DOXYGEN_DOT_UML_DETAILS NO) +endif() +if(NOT DEFINED DOXYGEN_DOT_WRAP_THRESHOLD) + set(DOXYGEN_DOT_WRAP_THRESHOLD 17) +endif() +if(NOT DEFINED DOXYGEN_TEMPLATE_RELATIONS) + set(DOXYGEN_TEMPLATE_RELATIONS NO) +endif() +if(NOT DEFINED DOXYGEN_INCLUDE_GRAPH) + set(DOXYGEN_INCLUDE_GRAPH YES) +endif() +if(NOT DEFINED DOXYGEN_INCLUDED_BY_GRAPH) + set(DOXYGEN_INCLUDED_BY_GRAPH YES) +endif() +if(NOT DEFINED DOXYGEN_CALL_GRAPH) + set(DOXYGEN_CALL_GRAPH NO) +endif() +if(NOT DEFINED DOXYGEN_CALLER_GRAPH) + set(DOXYGEN_CALLER_GRAPH NO) +endif() +if(NOT DEFINED DOXYGEN_GRAPHICAL_HIERARCHY) + set(DOXYGEN_GRAPHICAL_HIERARCHY YES) +endif() +if(NOT DEFINED DOXYGEN_DIRECTORY_GRAPH) + set(DOXYGEN_DIRECTORY_GRAPH YES) +endif() +if(NOT DEFINED DOXYGEN_DIR_GRAPH_MAX_DEPTH) + set(DOXYGEN_DIR_GRAPH_MAX_DEPTH 1) +endif() +if(NOT DEFINED DOXYGEN_DOT_IMAGE_FORMAT) + set(DOXYGEN_DOT_IMAGE_FORMAT png) +endif() +if(NOT DEFINED DOXYGEN_INTERACTIVE_SVG) + set(DOXYGEN_INTERACTIVE_SVG NO) +endif() +if(NOT DEFINED DOXYGEN_DOT_GRAPH_MAX_NODES) + set(DOXYGEN_DOT_GRAPH_MAX_NODES 50) +endif() +if(NOT DEFINED DOXYGEN_MAX_DOT_GRAPH_DEPTH) + set(DOXYGEN_MAX_DOT_GRAPH_DEPTH 0) +endif() +if(NOT DEFINED DOXYGEN_DOT_TRANSPARENT) + set(DOXYGEN_DOT_TRANSPARENT NO) +endif() +if(NOT DEFINED DOXYGEN_DOT_MULTI_TARGETS) + set(DOXYGEN_DOT_MULTI_TARGETS NO) +endif() +if(NOT DEFINED DOXYGEN_GENERATE_LEGEND) + set(DOXYGEN_GENERATE_LEGEND YES) +endif() +if(NOT DEFINED DOXYGEN_DOT_CLEANUP) + set(DOXYGEN_DOT_CLEANUP YES) +endif() diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b811f44 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,63 @@ +cmake_minimum_required(VERSION 3.5) + +include(${CMAKE_CURRENT_SOURCE_DIR}/pico-sdk/lib/tinyusb/hw/bsp/family_support.cmake) + +# gets PROJECT name for the example (e.g. -) +family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR}) + +project(${PROJECT}) + +# Checks this example is valid for the family and initializes the project +family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}) + +add_executable(${PROJECT}) + +# Example source +target_sources(${PROJECT} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/src/password_safe.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/ui.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/display.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/font_twisted.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/msc_disk.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/cryptoengine.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/cdc-protocol.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/fsm.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/flash.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/hid.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/wc_port.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/wolfmath.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/hash.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/memory.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/misc.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/ecc.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/curve25519.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/pwdbased.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/hmac.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/chacha.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/sha.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/sha256.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/sha512.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/ge_low_mem.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/fe_low_mem.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/ge_operations.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/sp_int.c + #${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/sp_armthumb.c + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/sp_c32.c + ) + +# Example include +target_include_directories(${PROJECT} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl + ) + + target_compile_definitions( ${PROJECT} PUBLIC WOLFSSL_USER_SETTINGS) + + + target_link_libraries(${PROJECT} PUBLIC pico_stdlib) + target_link_libraries(${PROJECT} PUBLIC pico_multicore) + +# Configure compilation flags and libraries for the example... see the corresponding function +# in hw/bsp/FAMILY/family.cmake for details. +family_configure_device_example(${PROJECT}) diff --git a/README.md b/README.md new file mode 100644 index 0000000..5431dcf --- /dev/null +++ b/README.md @@ -0,0 +1,141 @@ +# Motenpoche + +Motenpoche ([mot-ɑ̃-pɔʃ] - French for "word in your pocket") is a physical password +vault to carry around your secrets securely. It can be unlocked with a main +passphrase and it will automatically paste passwords selected from your collection. + +Passwords can be provisioned with the help of a host-side command line tool that +can be run on a GNU/Linux PC. + +## Status + +This project is still in an early alpha phase and has not been properly tested yet. +Use at your own risk, no guarantee provided on loss of secret information, service +profiles, bank details or other relevant information. The author and the +contributors recommends not to use this software for any purpose rather than +security auditing, research and study, and they cannot be held responsible or any +damage of any kind resulting from any proper or improper use. + +## Software License + +The software distributed in this project is uniquely released under the terms of +GNU GPL v.2. + +## What is this for + +I'm lazy and skeptical when it comes to distributed password managers. I don't +like the idea of keeping a wallet of passwords on a cloud server. On the other +hand, I'm oftern traveling and carrying a laptop, where I must periodically update +my password database if I want to access services when I'm abroad. + +This system was created to have a temporary physical storage that can be carried +around (and lost, or forgotten on a public transportation...) with reduced risk. + +## Hardware design + +## How it works + +The siple idea behind it is that the device does not carry any secret in plain +text. The passwords are stored on an external SPI flash, encrypted and signed with +unique keys created when the device is initialized. +The encryption key is symmetrical (ChaCha) and can be derived on board using the +main passphrase, which is entered through the rotary and the confirm button. + +The signature key (Ecc256) is created during device initialization on the PC. The +key is used to sign the passwords to be added to the vault. + +Passwords can be provisioned using the host tool, either manually or importing +them from a CSV file, previously exported from e.g. a software password manager +or a web browser. + +When the device is unlocked, selecting the service needed from the "Services" menu +will paste the password onto the PC. The user should ensureto select the right +password box before activating the service on the device to prevent password leaks +in clear text on the PC screen. + +Multiple paste modes are available from the "Settings" menu onboard. The device +can for example fill username + password web forms automatically, by typing in the +username, then the TAB key, then the password and finally ENTER. + +### Initialization + +The device can be initialized using a TOFU (Trust on First Use) mechanism. When +the device is in "factory mode", it can be initialized using the host command line +application, selecting the "TOFU" function. The application will then ask to input +(and confirm) the main password that will be used to unlock the device. +As mentioned, this procedure also creates the main signature key to provision +passwords. If you want to be able to add passwords to the vault from different +PCs, ensure that you carry a copy of the key generated in `~/.pvault/`. + +### Adding password services + +Passwords can be provisioned using the host tool, either manually or importing +them from a CSV file. The information is then encrypted on the PC using the main +password, signed using the signature key and transmitted to the device. + +The device must be unlocked in order to receive password services to add to the +database. Uploading a single password may take a few seconds because the device +verifies that the source of the information is trusted. + + +### What does the PC see + +When you connect motenpoche to your PC, it will show up as three different +devices: + +- A USB drive, containing the source and the binary of the host command line tool `mep` [TODO] + +- A serial port (typically /dev/ttyACM0), used by the host command line tool to communicate +with the device, initialize it after factory reset and upload passwords. + +- A HID keyboard device. Motenpoche will use a 'fake' keyboard to input the selected +password when requested. + +### Security considerations + +- The algorithm used to generate the encryption key is PBKDF2, using SHA512 for +hashing, and a random salt generated when the device is initialized + +- Neither the passwords, nor the main secret, or any private key is ever stored +on the device. When the device is turned off, the storage is encrypted. + +- Password checking is performed on board by decrypting the signature stored in the +initial settings page, and then checking for the integrity (sha) and +authenticity (ecc signature) of the page itself. +Each password is then decrypted on demand and sent to the PC through the HID +keyboard device. + +- Passwords can still be intercepted by a keylogger, e.g. using a USB sniffer. +(This is not very different from an actual USB keyboard). + +- Main keys and passwords are never transmitted via USB. + + +### Future development + +- The command line tool `mep` might have a function to "rekey" the device, changing +the salt and the constant part of the IV used for the encryption + +- Store private keys / custom secret files in the storage device. Those would be +invisible until the device is unlocked. + +## Compiling and flashing to Raspberry-pi pico: + +To compile the firmware run the following from the source directory: + +``` +mkdir build +cd build +cmake .. -DFAMILY=rp2040 -DPICO_SDK_PATH=/path/to/motenpoche/pico-sdk +``` + +### Host tool + +A copy of the host tool `mep` is in the `msc_content` directory. Compile using +"make", then run the tool pointing it to the correct USB serial device, e.g.: + +``` + ./mep /dev/ttyACM0 +``` + + diff --git a/cmake_install.cmake b/cmake_install.cmake new file mode 100644 index 0000000..96cb980 --- /dev/null +++ b/cmake_install.cmake @@ -0,0 +1,55 @@ +# Install script for directory: /home/dan/src/rp2040-mixer + +# Set the install prefix +if(NOT DEFINED CMAKE_INSTALL_PREFIX) + set(CMAKE_INSTALL_PREFIX "/usr/local") +endif() +string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + if(BUILD_TYPE) + string(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + else() + set(CMAKE_INSTALL_CONFIG_NAME "Release") + endif() + message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +endif() + +# Set the component getting installed. +if(NOT CMAKE_INSTALL_COMPONENT) + if(COMPONENT) + message(STATUS "Install component: \"${COMPONENT}\"") + set(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + else() + set(CMAKE_INSTALL_COMPONENT) + endif() +endif() + +# Is this installation the result of a crosscompile? +if(NOT DEFINED CMAKE_CROSSCOMPILING) + set(CMAKE_CROSSCOMPILING "TRUE") +endif() + +# Set default install directory permissions. +if(NOT DEFINED CMAKE_OBJDUMP) + set(CMAKE_OBJDUMP "/usr/bin/arm-none-eabi-objdump") +endif() + +if(NOT CMAKE_INSTALL_LOCAL_ONLY) + # Include the install script for each subdirectory. + include("/home/dan/src/rp2040-mixer/pico-sdk/cmake_install.cmake") + +endif() + +if(CMAKE_INSTALL_COMPONENT) + set(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INSTALL_COMPONENT}.txt") +else() + set(CMAKE_INSTALL_MANIFEST "install_manifest.txt") +endif() + +string(REPLACE ";" "\n" CMAKE_INSTALL_MANIFEST_CONTENT + "${CMAKE_INSTALL_MANIFEST_FILES}") +file(WRITE "/home/dan/src/rp2040-mixer/${CMAKE_INSTALL_MANIFEST}" + "${CMAKE_INSTALL_MANIFEST_CONTENT}") diff --git a/elf2uf2/CMakeCache.txt b/elf2uf2/CMakeCache.txt new file mode 100644 index 0000000..857e4a6 --- /dev/null +++ b/elf2uf2/CMakeCache.txt @@ -0,0 +1,374 @@ +# This is the CMakeCache file. +# For build in directory: /home/dan/src/rp2040-mixer/elf2uf2 +# It was generated by CMake: /usr/bin/cmake +# You can edit this file to change values found and used by cmake. +# If you do not want to change any of the values, simply exit the editor. +# If you do want to change a value, simply edit, save, and exit the editor. +# The syntax for the file is as follows: +# KEY:TYPE=VALUE +# KEY is the name of a variable in the cache. +# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. +# VALUE is the current value for the KEY. + +######################## +# EXTERNAL cache entries +######################## + +//Path to a program. +CMAKE_ADDR2LINE:FILEPATH=/usr/bin/addr2line + +//Path to a program. +CMAKE_AR:FILEPATH=/usr/bin/ar + +//Choose the type of build, options are: None Debug Release RelWithDebInfo +// MinSizeRel ... +CMAKE_BUILD_TYPE:STRING= + +//Enable/Disable color output during build. +CMAKE_COLOR_MAKEFILE:BOOL=ON + +//CXX compiler +CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/c++ + +//A wrapper around 'ar' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_CXX_COMPILER_AR:FILEPATH=/usr/bin/gcc-ar-12 + +//A wrapper around 'ranlib' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_CXX_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-12 + +//Flags used by the CXX compiler during all build types. +CMAKE_CXX_FLAGS:STRING= + +//Flags used by the CXX compiler during DEBUG builds. +CMAKE_CXX_FLAGS_DEBUG:STRING=-g + +//Flags used by the CXX compiler during MINSIZEREL builds. +CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the CXX compiler during RELEASE builds. +CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the CXX compiler during RELWITHDEBINFO builds. +CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG + +//C compiler +CMAKE_C_COMPILER:FILEPATH=/usr/bin/cc + +//A wrapper around 'ar' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_C_COMPILER_AR:FILEPATH=/usr/bin/gcc-ar-12 + +//A wrapper around 'ranlib' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_C_COMPILER_RANLIB:FILEPATH=/usr/bin/gcc-ranlib-12 + +//Flags used by the C compiler during all build types. +CMAKE_C_FLAGS:STRING= + +//Flags used by the C compiler during DEBUG builds. +CMAKE_C_FLAGS_DEBUG:STRING=-g + +//Flags used by the C compiler during MINSIZEREL builds. +CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the C compiler during RELEASE builds. +CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the C compiler during RELWITHDEBINFO builds. +CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG + +//Path to a program. +CMAKE_DLLTOOL:FILEPATH=CMAKE_DLLTOOL-NOTFOUND + +//Flags used by the linker during all build types. +CMAKE_EXE_LINKER_FLAGS:STRING= + +//Flags used by the linker during DEBUG builds. +CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during MINSIZEREL builds. +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during RELEASE builds. +CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during RELWITHDEBINFO builds. +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Enable/Disable output of compile commands during generation. +CMAKE_EXPORT_COMPILE_COMMANDS:BOOL= + +//Value Computed by CMake. +CMAKE_FIND_PACKAGE_REDIRECTS_DIR:STATIC=/home/dan/src/rp2040-mixer/elf2uf2/CMakeFiles/pkgRedirects + +//Install path prefix, prepended onto install directories. +CMAKE_INSTALL_PREFIX:PATH=/usr/local + +//Path to a program. +CMAKE_LINKER:FILEPATH=/usr/bin/ld + +//Path to a program. +CMAKE_MAKE_PROGRAM:FILEPATH=/usr/bin/gmake + +//Flags used by the linker during the creation of modules during +// all build types. +CMAKE_MODULE_LINKER_FLAGS:STRING= + +//Flags used by the linker during the creation of modules during +// DEBUG builds. +CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during the creation of modules during +// MINSIZEREL builds. +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during the creation of modules during +// RELEASE builds. +CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during the creation of modules during +// RELWITHDEBINFO builds. +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_NM:FILEPATH=/usr/bin/nm + +//Path to a program. +CMAKE_OBJCOPY:FILEPATH=/usr/bin/objcopy + +//Path to a program. +CMAKE_OBJDUMP:FILEPATH=/usr/bin/objdump + +//Value Computed by CMake +CMAKE_PROJECT_DESCRIPTION:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_HOMEPAGE_URL:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_NAME:STATIC=elf2uf2 + +//Path to a program. +CMAKE_RANLIB:FILEPATH=/usr/bin/ranlib + +//Path to a program. +CMAKE_READELF:FILEPATH=/usr/bin/readelf + +//Flags used by the linker during the creation of shared libraries +// during all build types. +CMAKE_SHARED_LINKER_FLAGS:STRING= + +//Flags used by the linker during the creation of shared libraries +// during DEBUG builds. +CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during the creation of shared libraries +// during MINSIZEREL builds. +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during the creation of shared libraries +// during RELEASE builds. +CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during the creation of shared libraries +// during RELWITHDEBINFO builds. +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//If set, runtime paths are not added when installing shared libraries, +// but are added when building. +CMAKE_SKIP_INSTALL_RPATH:BOOL=NO + +//If set, runtime paths are not added when using shared libraries. +CMAKE_SKIP_RPATH:BOOL=NO + +//Flags used by the linker during the creation of static libraries +// during all build types. +CMAKE_STATIC_LINKER_FLAGS:STRING= + +//Flags used by the linker during the creation of static libraries +// during DEBUG builds. +CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during the creation of static libraries +// during MINSIZEREL builds. +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during the creation of static libraries +// during RELEASE builds. +CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during the creation of static libraries +// during RELWITHDEBINFO builds. +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_STRIP:FILEPATH=/usr/bin/strip + +//If this value is on, makefiles will be generated without the +// .SILENT directive, and all commands will be echoed to the console +// during the make. This is useful for debugging only. With Visual +// Studio IDE projects all commands are done without /nologo. +CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE + +//Value Computed by CMake +elf2uf2_BINARY_DIR:STATIC=/home/dan/src/rp2040-mixer/elf2uf2 + +//Value Computed by CMake +elf2uf2_IS_TOP_LEVEL:STATIC=ON + +//Value Computed by CMake +elf2uf2_SOURCE_DIR:STATIC=/home/dan/src/rp2040-mixer/pico-sdk/tools/elf2uf2 + + +######################## +# INTERNAL cache entries +######################## + +//ADVANCED property for variable: CMAKE_ADDR2LINE +CMAKE_ADDR2LINE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_AR +CMAKE_AR-ADVANCED:INTERNAL=1 +//This is the directory where this CMakeCache.txt was created +CMAKE_CACHEFILE_DIR:INTERNAL=/home/dan/src/rp2040-mixer/elf2uf2 +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3 +//Minor version of cmake used to create the current loaded cache +CMAKE_CACHE_MINOR_VERSION:INTERNAL=24 +//Patch version of cmake used to create the current loaded cache +CMAKE_CACHE_PATCH_VERSION:INTERNAL=2 +//ADVANCED property for variable: CMAKE_COLOR_MAKEFILE +CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1 +//Path to CMake executable. +CMAKE_COMMAND:INTERNAL=/usr/bin/cmake +//Path to cpack program executable. +CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack +//Path to ctest program executable. +CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest +//ADVANCED property for variable: CMAKE_CXX_COMPILER +CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_COMPILER_AR +CMAKE_CXX_COMPILER_AR-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_COMPILER_RANLIB +CMAKE_CXX_COMPILER_RANLIB-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS +CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG +CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL +CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE +CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO +CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER +CMAKE_C_COMPILER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER_AR +CMAKE_C_COMPILER_AR-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER_RANLIB +CMAKE_C_COMPILER_RANLIB-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS +CMAKE_C_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG +CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL +CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE +CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO +CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_DLLTOOL +CMAKE_DLLTOOL-ADVANCED:INTERNAL=1 +//Executable file format +CMAKE_EXECUTABLE_FORMAT:INTERNAL=ELF +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS +CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG +CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE +CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXPORT_COMPILE_COMMANDS +CMAKE_EXPORT_COMPILE_COMMANDS-ADVANCED:INTERNAL=1 +//Name of external makefile project generator. +CMAKE_EXTRA_GENERATOR:INTERNAL= +//Name of generator. +CMAKE_GENERATOR:INTERNAL=Unix Makefiles +//Generator instance identifier. +CMAKE_GENERATOR_INSTANCE:INTERNAL= +//Name of generator platform. +CMAKE_GENERATOR_PLATFORM:INTERNAL= +//Name of generator toolset. +CMAKE_GENERATOR_TOOLSET:INTERNAL= +//Source directory with the top level CMakeLists.txt file for this +// project +CMAKE_HOME_DIRECTORY:INTERNAL=/home/dan/src/rp2040-mixer/pico-sdk/tools/elf2uf2 +//Install .so files without execute permission. +CMAKE_INSTALL_SO_NO_EXE:INTERNAL=1 +//ADVANCED property for variable: CMAKE_LINKER +CMAKE_LINKER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MAKE_PROGRAM +CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS +CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG +CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE +CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_NM +CMAKE_NM-ADVANCED:INTERNAL=1 +//number of local generators +CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=2 +//ADVANCED property for variable: CMAKE_OBJCOPY +CMAKE_OBJCOPY-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_OBJDUMP +CMAKE_OBJDUMP-ADVANCED:INTERNAL=1 +//Platform information initialized +CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RANLIB +CMAKE_RANLIB-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_READELF +CMAKE_READELF-ADVANCED:INTERNAL=1 +//Path to CMake installation. +CMAKE_ROOT:INTERNAL=/usr/share/cmake-3.24 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS +CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG +CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE +CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH +CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_RPATH +CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS +CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG +CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE +CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STRIP +CMAKE_STRIP-ADVANCED:INTERNAL=1 +//uname command +CMAKE_UNAME:INTERNAL=/bin/uname +//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE +CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 +//linker supports push/pop state +_CMAKE_LINKER_PUSHPOP_STATE_SUPPORTED:INTERNAL=TRUE + diff --git a/elf2uf2/Makefile b/elf2uf2/Makefile new file mode 100644 index 0000000..22a7e94 --- /dev/null +++ b/elf2uf2/Makefile @@ -0,0 +1,181 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.24 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Disable VCS-based implicit rules. +% : %,v + +# Disable VCS-based implicit rules. +% : RCS/% + +# Disable VCS-based implicit rules. +% : RCS/%,v + +# Disable VCS-based implicit rules. +% : SCCS/s.% + +# Disable VCS-based implicit rules. +% : s.% + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Command-line flag to silence nested $(MAKE). +$(VERBOSE)MAKESILENT = -s + +#Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E rm -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/dan/src/rp2040-mixer/pico-sdk/tools/elf2uf2 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/dan/src/rp2040-mixer/elf2uf2 + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." + /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /usr/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# The main all target +all: cmake_check_build_system + $(CMAKE_COMMAND) -E cmake_progress_start /home/dan/src/rp2040-mixer/elf2uf2/CMakeFiles /home/dan/src/rp2040-mixer/elf2uf2//CMakeFiles/progress.marks + $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 all + $(CMAKE_COMMAND) -E cmake_progress_start /home/dan/src/rp2040-mixer/elf2uf2/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +#============================================================================= +# Target rules for targets named elf2uf2 + +# Build rule for target. +elf2uf2: cmake_check_build_system + $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 elf2uf2 +.PHONY : elf2uf2 + +# fast build rule for target. +elf2uf2/fast: + $(MAKE) $(MAKESILENT) -f CMakeFiles/elf2uf2.dir/build.make CMakeFiles/elf2uf2.dir/build +.PHONY : elf2uf2/fast + +main.o: main.cpp.o +.PHONY : main.o + +# target to build an object file +main.cpp.o: + $(MAKE) $(MAKESILENT) -f CMakeFiles/elf2uf2.dir/build.make CMakeFiles/elf2uf2.dir/main.cpp.o +.PHONY : main.cpp.o + +main.i: main.cpp.i +.PHONY : main.i + +# target to preprocess a source file +main.cpp.i: + $(MAKE) $(MAKESILENT) -f CMakeFiles/elf2uf2.dir/build.make CMakeFiles/elf2uf2.dir/main.cpp.i +.PHONY : main.cpp.i + +main.s: main.cpp.s +.PHONY : main.s + +# target to generate assembly for a file +main.cpp.s: + $(MAKE) $(MAKESILENT) -f CMakeFiles/elf2uf2.dir/build.make CMakeFiles/elf2uf2.dir/main.cpp.s +.PHONY : main.cpp.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... rebuild_cache" + @echo "... elf2uf2" + @echo "... main.o" + @echo "... main.i" + @echo "... main.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/elf2uf2/boot_uf2_headers/Makefile b/elf2uf2/boot_uf2_headers/Makefile new file mode 100644 index 0000000..5ed5c17 --- /dev/null +++ b/elf2uf2/boot_uf2_headers/Makefile @@ -0,0 +1,140 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.24 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Disable VCS-based implicit rules. +% : %,v + +# Disable VCS-based implicit rules. +% : RCS/% + +# Disable VCS-based implicit rules. +% : RCS/%,v + +# Disable VCS-based implicit rules. +% : SCCS/s.% + +# Disable VCS-based implicit rules. +% : s.% + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Command-line flag to silence nested $(MAKE). +$(VERBOSE)MAKESILENT = -s + +#Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E rm -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/dan/src/rp2040-mixer/pico-sdk/tools/elf2uf2 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/dan/src/rp2040-mixer/elf2uf2 + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." + /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /usr/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# The main all target +all: cmake_check_build_system + cd /home/dan/src/rp2040-mixer/elf2uf2 && $(CMAKE_COMMAND) -E cmake_progress_start /home/dan/src/rp2040-mixer/elf2uf2/CMakeFiles /home/dan/src/rp2040-mixer/elf2uf2/boot_uf2_headers//CMakeFiles/progress.marks + cd /home/dan/src/rp2040-mixer/elf2uf2 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 boot_uf2_headers/all + $(CMAKE_COMMAND) -E cmake_progress_start /home/dan/src/rp2040-mixer/elf2uf2/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + cd /home/dan/src/rp2040-mixer/elf2uf2 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 boot_uf2_headers/clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + cd /home/dan/src/rp2040-mixer/elf2uf2 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 boot_uf2_headers/preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + cd /home/dan/src/rp2040-mixer/elf2uf2 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 boot_uf2_headers/preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + cd /home/dan/src/rp2040-mixer/elf2uf2 && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... rebuild_cache" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + cd /home/dan/src/rp2040-mixer/elf2uf2 && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/elf2uf2/boot_uf2_headers/cmake_install.cmake b/elf2uf2/boot_uf2_headers/cmake_install.cmake new file mode 100644 index 0000000..96164a9 --- /dev/null +++ b/elf2uf2/boot_uf2_headers/cmake_install.cmake @@ -0,0 +1,44 @@ +# Install script for directory: /home/dan/src/rp2040-mixer/pico-sdk/src/common/boot_uf2 + +# Set the install prefix +if(NOT DEFINED CMAKE_INSTALL_PREFIX) + set(CMAKE_INSTALL_PREFIX "/usr/local") +endif() +string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + if(BUILD_TYPE) + string(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + else() + set(CMAKE_INSTALL_CONFIG_NAME "") + endif() + message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +endif() + +# Set the component getting installed. +if(NOT CMAKE_INSTALL_COMPONENT) + if(COMPONENT) + message(STATUS "Install component: \"${COMPONENT}\"") + set(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + else() + set(CMAKE_INSTALL_COMPONENT) + endif() +endif() + +# Install shared libraries without execute permission? +if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) + set(CMAKE_INSTALL_SO_NO_EXE "1") +endif() + +# Is this installation the result of a crosscompile? +if(NOT DEFINED CMAKE_CROSSCOMPILING) + set(CMAKE_CROSSCOMPILING "FALSE") +endif() + +# Set default install directory permissions. +if(NOT DEFINED CMAKE_OBJDUMP) + set(CMAKE_OBJDUMP "/usr/bin/objdump") +endif() + diff --git a/elf2uf2/cmake_install.cmake b/elf2uf2/cmake_install.cmake new file mode 100644 index 0000000..72d9db9 --- /dev/null +++ b/elf2uf2/cmake_install.cmake @@ -0,0 +1,60 @@ +# Install script for directory: /home/dan/src/rp2040-mixer/pico-sdk/tools/elf2uf2 + +# Set the install prefix +if(NOT DEFINED CMAKE_INSTALL_PREFIX) + set(CMAKE_INSTALL_PREFIX "/usr/local") +endif() +string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + if(BUILD_TYPE) + string(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + else() + set(CMAKE_INSTALL_CONFIG_NAME "") + endif() + message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +endif() + +# Set the component getting installed. +if(NOT CMAKE_INSTALL_COMPONENT) + if(COMPONENT) + message(STATUS "Install component: \"${COMPONENT}\"") + set(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + else() + set(CMAKE_INSTALL_COMPONENT) + endif() +endif() + +# Install shared libraries without execute permission? +if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) + set(CMAKE_INSTALL_SO_NO_EXE "1") +endif() + +# Is this installation the result of a crosscompile? +if(NOT DEFINED CMAKE_CROSSCOMPILING) + set(CMAKE_CROSSCOMPILING "FALSE") +endif() + +# Set default install directory permissions. +if(NOT DEFINED CMAKE_OBJDUMP) + set(CMAKE_OBJDUMP "/usr/bin/objdump") +endif() + +if(NOT CMAKE_INSTALL_LOCAL_ONLY) + # Include the install script for each subdirectory. + include("/home/dan/src/rp2040-mixer/elf2uf2/boot_uf2_headers/cmake_install.cmake") + +endif() + +if(CMAKE_INSTALL_COMPONENT) + set(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INSTALL_COMPONENT}.txt") +else() + set(CMAKE_INSTALL_MANIFEST "install_manifest.txt") +endif() + +string(REPLACE ";" "\n" CMAKE_INSTALL_MANIFEST_CONTENT + "${CMAKE_INSTALL_MANIFEST_FILES}") +file(WRITE "/home/dan/src/rp2040-mixer/elf2uf2/${CMAKE_INSTALL_MANIFEST}" + "${CMAKE_INSTALL_MANIFEST_CONTENT}") diff --git a/elf2uf2/elf2uf2 b/elf2uf2/elf2uf2 new file mode 100755 index 0000000000000000000000000000000000000000..c42e434e521b119ee8c3fd775ea815047f0cd19d GIT binary patch literal 99632 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 literal 0 HcmV?d00001 diff --git a/elf2uf2/src/ELF2UF2Build-stamp/ELF2UF2Build-done b/elf2uf2/src/ELF2UF2Build-stamp/ELF2UF2Build-done new file mode 100644 index 0000000..e69de29 diff --git a/elf2uf2/src/ELF2UF2Build-stamp/ELF2UF2Build-source_dirinfo.txt b/elf2uf2/src/ELF2UF2Build-stamp/ELF2UF2Build-source_dirinfo.txt new file mode 100644 index 0000000..ac63e8f --- /dev/null +++ b/elf2uf2/src/ELF2UF2Build-stamp/ELF2UF2Build-source_dirinfo.txt @@ -0,0 +1,9 @@ +# This is a generated file and its contents are an internal implementation detail. +# The download step will be re-executed if anything in this file changes. +# No other meaning or use of this file is supported. + +method=source_dir +command= +source_dir=/home/dan/src/rp2040-mixer/pico-sdk/tools/elf2uf2 +work_dir= + diff --git a/elf2uf2/tmp/ELF2UF2Build-cfgcmd.txt b/elf2uf2/tmp/ELF2UF2Build-cfgcmd.txt new file mode 100644 index 0000000..07e8fc0 --- /dev/null +++ b/elf2uf2/tmp/ELF2UF2Build-cfgcmd.txt @@ -0,0 +1 @@ +cmd='/usr/bin/cmake;-GUnix Makefiles;' diff --git a/elf2uf2/tmp/ELF2UF2Build-mkdirs.cmake b/elf2uf2/tmp/ELF2UF2Build-mkdirs.cmake new file mode 100644 index 0000000..4e0dee1 --- /dev/null +++ b/elf2uf2/tmp/ELF2UF2Build-mkdirs.cmake @@ -0,0 +1,22 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +cmake_minimum_required(VERSION 3.5) + +file(MAKE_DIRECTORY + "/home/dan/src/rp2040-mixer/pico-sdk/tools/elf2uf2" + "/home/dan/src/rp2040-mixer/elf2uf2" + "/home/dan/src/rp2040-mixer/elf2uf2" + "/home/dan/src/rp2040-mixer/elf2uf2/tmp" + "/home/dan/src/rp2040-mixer/elf2uf2/src/ELF2UF2Build-stamp" + "/home/dan/src/rp2040-mixer/elf2uf2/src" + "/home/dan/src/rp2040-mixer/elf2uf2/src/ELF2UF2Build-stamp" +) + +set(configSubDirs ) +foreach(subDir IN LISTS configSubDirs) + file(MAKE_DIRECTORY "/home/dan/src/rp2040-mixer/elf2uf2/src/ELF2UF2Build-stamp/${subDir}") +endforeach() +if(cfgdir) + file(MAKE_DIRECTORY "/home/dan/src/rp2040-mixer/elf2uf2/src/ELF2UF2Build-stamp${cfgdir}") # cfgdir has leading slash +endif() diff --git a/generated/pico_base/pico/config_autogen.h b/generated/pico_base/pico/config_autogen.h new file mode 100644 index 0000000..8f5f44f --- /dev/null +++ b/generated/pico_base/pico/config_autogen.h @@ -0,0 +1,11 @@ +// AUTOGENERATED FROM PICO_CONFIG_HEADER_FILES and then PICO__CONFIG_HEADER_FILES +// DO NOT EDIT! + + +// based on PICO_CONFIG_HEADER_FILES: + +#include "/home/dan/src/rp2040-mixer/pico-sdk/src/boards/include/boards/pico.h" + +// based on PICO_RP2040_CONFIG_HEADER_FILES: + +#include "/home/dan/src/rp2040-mixer/pico-sdk/src/rp2_common/cmsis/include/cmsis/rename_exceptions.h" \ No newline at end of file diff --git a/generated/pico_base/pico/version.h b/generated/pico_base/pico/version.h new file mode 100644 index 0000000..96e417b --- /dev/null +++ b/generated/pico_base/pico/version.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +// --------------------------------------- +// THIS FILE IS AUTOGENERATED; DO NOT EDIT +// --------------------------------------- + +#ifndef _PICO_VERSION_H +#define _PICO_VERSION_H + +#define PICO_SDK_VERSION_MAJOR 1 +#define PICO_SDK_VERSION_MINOR 3 +#define PICO_SDK_VERSION_REVISION 0 +#define PICO_SDK_VERSION_STRING "1.3.0" + +#endif diff --git a/lib/wolfssl b/lib/wolfssl new file mode 160000 index 0000000..5a49b8c --- /dev/null +++ b/lib/wolfssl @@ -0,0 +1 @@ +Subproject commit 5a49b8c4366fbf45890fbf991c8a7ee50548596e diff --git a/msc_content/Makefile b/msc_content/Makefile new file mode 100644 index 0000000..058f708 --- /dev/null +++ b/msc_content/Makefile @@ -0,0 +1,7 @@ +all: mep + +mep: mep.c + gcc -g -ggdb -o mep mep.c -lwolfssl + +clean: + rm -f mep diff --git a/msc_content/mep.c b/msc_content/mep.c new file mode 100644 index 0000000..acf47e7 --- /dev/null +++ b/msc_content/mep.c @@ -0,0 +1,896 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "../src/cryptoengine.h" + +#include +#include +#include +#include +#include +#include +#include + +#define HOMEPATH_PREFIX "~/.pvault" +//#define HOMEPATH_PREFIX "/root/.pvault" + +#include +#include +#include + +#define MAX_SVC_NAME_LEN 16 + +static char pass_prompt[200] = ""; +static char pass_confirm[200] = ""; +static const char pass_prompt_phrase[] = "Enter your passphrase: "; +static const char pass_confirm_phrase[] = "Confirm your passphrase : "; + +static const char pass_prompt_svc[] = "Password: "; +static const char pass_confirm_svc[] = "Confirm Password: "; + +static int sfd = -1;; +static int pk_fd = -1; + +static struct vault_status Status = { }; +static int get_vault_status(void); + + +struct __attribute__((packed)) tofu_packet { + uint32_t cdc_magic; /* 0x5afeca5e */ + uint16_t cdc_cmd; + uint16_t cdc_len; + struct vault_header vh; +}; + +void clearScreen() { + system("clear"); +} + +void disableEcho() { + struct termios term; + tcgetattr(0, &term); + term.c_lflag &= ~ECHO; + tcsetattr(0, TCSANOW, &term); +} + +void enableEcho() { + struct termios term; + tcgetattr(0, &term); + term.c_lflag |= ECHO; + tcsetattr(0, TCSANOW, &term); +} + +void printPrompt() { + printf(pass_prompt); +} + +static void getPassword(char *password, int size) { + int i = 0; + char c; + + while (i < size - 1) { + c = getchar(); + if (c == '\n') { + break; + } + password[i++] = c; + if (i >= 99) + break; + } + + password[i] = '\0'; +} + +int confirmPassphrase(const char *passphrase) { + char confirmation[100]; + + printf(pass_confirm); + getPassword(confirmation, sizeof(confirmation)); + + return strcmp(passphrase, confirmation) == 0; +} + +static char passphrase[100]; +static int askpass(void) +{ + int ret = 0; + disableEcho(); + printPrompt(); + getPassword(passphrase, sizeof(passphrase)); + printf("\n"); + + if (confirmPassphrase(passphrase)) { + printf("\nConfirmed.\n"); + ret = 1; + } else { + printf("These passwords don't match. Please try again.\n"); + } + enableEcho(); + return ret; +} + + + +static int rate_to_constant(int baudrate) { +#ifdef __MACH__ +#define B(x) case x: return x +#else +#define B(x) case x: return B##x +#endif + switch(baudrate) { + B(50); B(75); B(110); B(134); B(150); + B(200); B(300); B(600); B(1200); B(1800); + B(2400); B(4800); B(9600); B(19200); B(38400); + B(57600); B(115200); B(230400); B(460800); B(500000); + B(576000); B(921600); B(1000000);B(1152000);B(1500000); +default: return 0; +} +#undef B +} + +/* Open serial port in raw mode, with custom baudrate if necessary */ +static int serial_open(const char *device, int rate) +{ + struct termios options; + int fd; + int speed = 0; + + /* Open and configure serial port */ + if ((fd = open(device,O_RDWR|O_NOCTTY)) == -1) + return -1; + + speed = rate_to_constant(rate); + +#ifndef __MACH__ + if (speed == 0) { + /* Custom divisor */ + struct serial_struct serinfo; + serinfo.reserved_char[0] = 0; + if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) + return -1; + serinfo.flags &= ~ASYNC_SPD_MASK; + serinfo.flags |= ASYNC_SPD_CUST; + serinfo.custom_divisor = (serinfo.baud_base + (rate / 2)) / rate; + if (serinfo.custom_divisor < 1) + serinfo.custom_divisor = 1; + if (ioctl(fd, TIOCSSERIAL, &serinfo) < 0) + return -1; + if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) + return -1; + if (serinfo.custom_divisor * rate != serinfo.baud_base) { + warnx("actual baudrate is %d / %d = %f", + serinfo.baud_base, serinfo.custom_divisor, + (float)serinfo.baud_base / serinfo.custom_divisor); + } + } +#endif + + fcntl(fd, F_SETFL, 0); + tcgetattr(fd, &options); + cfsetispeed(&options, speed ?: 460800); + cfsetospeed(&options, speed ?: 460800); + cfmakeraw(&options); + options.c_cflag |= (CLOCAL | CREAD); + options.c_cflag &= ~CRTSCTS; + if (tcsetattr(fd, TCSANOW, &options) != 0) + return -1; + + return fd; +} + +static int tofu(const char *password) +{ + int ret = 0, i; + int outlen = CRYPTO_KEY_SIZE; + int siglen = PK_SIGNATURE_SIZE; + uint8_t clr_sig[PK_SIGNATURE_SIZE]; + struct tofu_packet tofu; + uint8_t Ke[CRYPTO_KEY_SIZE], Sm[CRYPTO_KEY_SIZE]; + uint8_t resp[256]; + char privkey_fname[32]; + uint32_t mgc = 0xffffffff; + int hash, hash_len; + uint8_t iv[24]; + uint8_t sig_dec_verify[64]; + struct pollfd pfd; + uint32_t qxLen = CRYPTO_KEY_SIZE, qyLen = CRYPTO_KEY_SIZE, + dLen = CRYPTO_KEY_SIZE; + + + tofu.cdc_magic = VAULT_MAGIC; + tofu.cdc_cmd = CDC_TOFU_INIT; + tofu.cdc_len = sizeof(struct tofu_packet) - 8; + + tofu.vh.magic = VAULT_MAGIC; + tofu.vh.size = sizeof(struct tofu_packet) - 8; + + + ecc_key ecc; + ChaCha cha; + RNG rng; + + Sha512 sha; + + + /* Initialize Rng (needed for master key + salt + secret */ + wc_InitRng(&rng); + + /* Generate ID */ + wc_RNG_GenerateBlock(&rng, (void *)tofu.vh.id, 8); + sprintf(privkey_fname, "%08x-%08x.der", tofu.vh.id[0], tofu.vh.id[1]); + printf("ID: %s\n", privkey_fname); + + /* Generate salt */ + wc_RNG_GenerateBlock(&rng, tofu.vh.host_salt, SALT_LEN); + printf("Salt: "); + for (i = 0; i < SALT_LEN; i++) { + printf("%02x", tofu.vh.host_salt[i]); + } + printf("\n"); + + /* Derive device key (password based) to create encryption key */ + ret = wc_PBKDF2(Ke, password, strlen(password), tofu.vh.host_salt, SALT_LEN, 1000, CRYPTO_KEY_SIZE, WC_SHA512); + wc_Chacha_SetKey(&cha, Ke, CRYPTO_KEY_SIZE); + wc_Chacha_SetIV(&cha, tofu.vh.host_seed, 0); + + /* Generate master signing key */ + wc_ecc_init(&ecc); + wc_ecc_make_key(&rng, CRYPTO_KEY_SIZE, &ecc); + qxLen = CRYPTO_KEY_SIZE; + qyLen = CRYPTO_KEY_SIZE; + wc_ecc_export_public_raw(&ecc, tofu.vh.auth_pubkey, &qxLen, tofu.vh.auth_pubkey + CRYPTO_KEY_SIZE, &qyLen); + printf("Public signing key %d: ", qxLen + qyLen); + for (i = 0; i < qxLen + qyLen; i++) { + printf("%02x", tofu.vh.auth_pubkey[i]); + } + printf("\n"); + + + /* Generate key seed */ + wc_RNG_GenerateBlock(&rng, tofu.vh.host_seed, SEED_LEN); + printf("Seed: "); + for (i = 0; i < SEED_LEN; i++) { + printf("%02x", tofu.vh.host_seed[i]); + } + printf("\n"); + + wc_InitSha512(&sha); + for (hash = 0; hash < SHA_PAYLOAD_SIZE;) { + hash_len = WC_SHA512_BLOCK_SIZE; + if ((SHA_PAYLOAD_SIZE - hash) < hash_len) + hash_len = SHA_PAYLOAD_SIZE - hash; + wc_Sha512Update(&sha, ((uint8_t*)&tofu.vh) + hash, hash_len); + hash += hash_len; + printf("update %d/%d\n", hash, SHA_PAYLOAD_SIZE); + } + wc_Sha512Final(&sha, tofu.vh.digest); + printf("Digest (%d): ", sizeof(tofu.vh.digest)); + for (i = 0; i < sizeof(tofu.vh.digest); i++) { + printf("%02x ", tofu.vh.digest[i]); + if ((i % 16) == 15) + printf("\n"); + } + printf("\n"); + wc_Sha512Free(&sha); + + { + mp_int r, s; + mp_init(&r); mp_init(&s); + ret = wc_ecc_sign_hash_ex(tofu.vh.digest, VAULT_DIGEST_SIZE, &rng, &ecc, + &r, &s); + mp_to_unsigned_bin(&r, &clr_sig[0]); + mp_to_unsigned_bin(&s, &clr_sig[CRYPTO_KEY_SIZE]); + mp_clear(&r); + mp_clear(&s); + } + printf("Signature (%d) returned %d:\n", PK_SIGNATURE_SIZE, ret); + for (i = 0; i < PK_SIGNATURE_SIZE; i++) { + printf("%02x ", clr_sig[i]); + if ((i % 16) == 15) + printf("\n"); + } + printf("\n"); + { + int vr, vres; + mp_int r, s; + mp_init(&r); mp_init(&s); + mp_read_unsigned_bin(&r, &clr_sig[0], CRYPTO_KEY_SIZE); + mp_read_unsigned_bin(&s, &clr_sig[CRYPTO_KEY_SIZE], CRYPTO_KEY_SIZE); + vr = wc_ecc_verify_hash_ex(&r, &s, tofu.vh.digest, VAULT_DIGEST_SIZE, + &vres, &ecc); + mp_clear(&r); + mp_clear(&s); + printf("sanity check verify ret %d res %d\n", vr, vres); + } + + + wc_Chacha_SetIV(&cha, tofu.vh.host_seed, 0); + wc_Chacha_Process(&cha, tofu.vh.signature, clr_sig, siglen); + wc_Chacha_SetIV(&cha, tofu.vh.host_seed, 0); + wc_Chacha_Process(&cha, sig_dec_verify, tofu.vh.signature, siglen); + + if (memcmp(clr_sig, sig_dec_verify, siglen) != 0) { + printf("Error verifying chacha encryption\n"); + return 4; + } + + printf("Packet (%d): ", sizeof(tofu)); + for (i = 0; i < sizeof(tofu); i++) { + printf("%02x ", *(((uint8_t*)(&tofu)) + i)); + if ((i % 16) == 15) + printf("\n"); + } + printf("\n"); + + pfd.fd = sfd; + pfd.events = POLLIN; + for(i = 0; i < 10; i++) { + char buf[8]; + ret = poll(&pfd, 1, 100); + if (ret > 0) { + read(sfd, buf, 8); + } + } + + ret = write(sfd, &tofu, sizeof(tofu)); + printf("Sent %d/%d bvtes (tofu) \r\n", ret, sizeof(tofu)); + do { + ret = read(sfd, &mgc, 4); + } while (mgc != 0x5afeca5e); + + memcpy (resp, &mgc, 4); + ret = read(sfd, resp + 4, 64 + 4); + if (ret >= 4) { + uint16_t code = *((uint16_t *)(resp + 4)); + uint16_t len = *((uint16_t *)(resp + 6)); + + printf("received %d bytes: resp %04x len %04x\n", ret + 4, *((uint16_t *)(resp + 4)), *((uint16_t *)(resp + 6))); + if (ret > 4) { + printf("MSG: %s\r\n", resp + 8); + } + if (code == CDC_OK) { + int fd; + uint8_t privkey_buf[2 * CRYPTO_KEY_SIZE]; + char pkfname[MAX_PATH]; + char *homedir; + homedir = getenv("HOME"); + if (!homedir || strlen(homedir) == 0) { + perror("getenv(HOME)"); + exit(1); + } + + snprintf(pkfname, MAX_PATH - 1, "%s/.pvault/%s", homedir, privkey_fname); + printf("Saving private key %s\n", privkey_fname); + fd = open(pkfname, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) { + printf("FATAL Error opening private key: %s\n", strerror(errno)); + return 6; + } + outlen = 2 * CRYPTO_KEY_SIZE; + if (wc_ecc_export_private_raw(&ecc, privkey_buf, &qxLen, + privkey_buf + qxLen, &qyLen, + privkey_buf + qxLen + qyLen, &dLen) != 0) { + fprintf(stderr, "Unable to export private key to DER\n"); + exit(2); + } + outlen = qxLen + qyLen + dLen; + printf("Exporting private key (%d bytes)\n", outlen); + write(fd, privkey_buf, outlen); + wc_ecc_free(&ecc); + close(fd); + } + } + return 0; +} + +static void addservice(struct vault_service *vs, uint8_t *Ke) +{ + struct vault_service vs_local; + char gadget_passphrase[64]; + int ret; + uint8_t Ke_local[CRYPTO_KEY_SIZE]; + uint8_t eccRawKey[CRYPTO_KEY_SIZE * 3]; + uint8_t snd_buffer[sizeof(struct cdc_packet_hdr) + SVC_SIZE]; + struct cdc_packet_hdr *hdr = (struct cdc_packet_hdr *)snd_buffer; + int i; + struct pollfd pfd; + uint32_t mgc = 0; + int interactive = 0; + uint32_t slot = 0; + Sha512 sha; + ecc_key ecc; + ChaCha cha; + RNG rng; + strcpy(pass_prompt, pass_prompt_svc); + strcpy(pass_confirm, pass_confirm_svc); + + + if (!vs) { + vs = &vs_local; + Ke = Ke_local; + interactive = 1; + printf("Service name (max 16 char.) : "); + scanf("%s", vs->name); + printf("\n"); + printf("Username (empty = none) : "); + if (scanf("%s", vs->user) <= 0) + vs->user[0] = '\0'; + getchar(); + while(!askpass()) { + printf("Press a key to continue...\r\n"); + getchar(); + } + strcpy((char *)(vs->pass), passphrase); + } + vs->flags = SVC_FLAG_ACTIVE; + vs->reserved = 0; + + if (!Ke) { + printf("Unspecified key\n"); + return; + } + + + wc_InitSha512(&sha); + wc_Sha512Update(&sha, (uint8_t *)vs, WC_SHA512_BLOCK_SIZE); + wc_Sha512Final(&sha, vs->dig); + + printf("\n----- RECAP -----\n"); + printf("Service name: %s\n", vs->name); + printf("Username: %s\n", vs->user); + printf("Password: ******\n"); + printf("Sha: "); + for (i = 0; i < VAULT_DIGEST_SIZE; i++) { + printf("%02x", vs->dig[i]); + } + printf("\n-----------------\n\n"); + + + if (interactive) { + printf("Service configured, press a key to send, ctrl+c to abort...\r\n"); + disableEcho(); + printf("Enter gadget passphrase to encrypt and send info: "); + getPassword(gadget_passphrase, 64); + enableEcho(); + printf("\n"); + /* Derive device key (password based) to create encryption key */ + ret = wc_PBKDF2(Ke, gadget_passphrase, strlen(gadget_passphrase), + Status.salt, SALT_LEN, 1000, CRYPTO_KEY_SIZE, WC_SHA512); + + if (ret < 0) { + printf("Failed to derive password.\n"); + return; + } + } + + + lseek(pk_fd, SEEK_SET, 0); + ret = read(pk_fd, eccRawKey, CRYPTO_KEY_SIZE * 3); + if (ret != CRYPTO_KEY_SIZE * 3) { + printf("Error reading signing key\n"); + return; + } + + wc_ecc_init(&ecc); + if (wc_ecc_import_unsigned(&ecc, eccRawKey, eccRawKey + CRYPTO_KEY_SIZE, + eccRawKey + 2 * CRYPTO_KEY_SIZE, ECC_SECP256R1) < 0) { + printf("Failed importing signing key\n"); + return; + } + + slot = Status.first_avail; + + /* Initialize Rng (needed for sign)*/ + wc_InitRng(&rng); + + printf("Slot is %u\n", slot); + { + mp_int r, s; + mp_init(&r); mp_init(&s); + ret = wc_ecc_sign_hash_ex(vs->dig, VAULT_DIGEST_SIZE, &rng, &ecc, + &r, &s); + mp_to_unsigned_bin(&r, &vs->sig[0]); + mp_to_unsigned_bin(&s, &vs->sig[CRYPTO_KEY_SIZE]); + mp_clear(&r); + mp_clear(&s); + } + + printf("Signature (%d):\n", PK_SIGNATURE_SIZE); + for (i = 0; i < PK_SIGNATURE_SIZE; i++) { + printf("%02x ", vs->sig[i]); + if ((i % 16) == 15) + printf("\n"); + } + printf("\n"); + + wc_ecc_free(&ecc); + + /* Copy the part in clear (flags, reserved) */ + memcpy(snd_buffer + sizeof(struct cdc_packet_hdr), vs, SVC_ENC_OFF); + + /* Set Key and IV */ + wc_Chacha_SetKey(&cha, Ke, CRYPTO_KEY_SIZE); + wc_Chacha_SetIV(&cha, Status.seed, SVC_FLASH_OFFSET + slot * SVC_SIZE); + wc_Chacha_Process(&cha, snd_buffer + sizeof(struct cdc_packet_hdr) + SVC_ENC_OFF, + ((uint8_t *)(vs)) + SVC_ENC_OFF, SVC_ENC_SIZE); + + hdr->magic = VAULT_MAGIC; + hdr->cmd = CDC_ADDSERV; + hdr->len = SVC_SIZE; + + pfd.fd = sfd; + pfd.events = POLLIN; + for (i = 0; i < 10; i++) { + char buf[8]; + ret = poll(&pfd, 1, 10); + if (ret > 0) { + read(sfd, buf, 8); + } + } + + printf("Packet (%d): ", sizeof(snd_buffer)); + for (i = 0; i < sizeof(snd_buffer); i++) { + printf("%02x ", snd_buffer[i]); + if ((i % 16) == 15) + printf("\n"); + } + printf("\n"); + + printf("Sending svc packet... \n"); + write(sfd, snd_buffer, sizeof(snd_buffer)); + + for (i = 0; i < 3; i++) { + char buf[256]; + ret = poll(&pfd, 1, 5000); + if (ret > 0) { + uint16_t code; + do { + ret = read(sfd, &mgc, 4); + } while (mgc != 0x5afeca5e); + ret = read(sfd, buf, 256); + code = *((uint16_t *)(buf)); + + printf("Received response (code %02x, len %d): %s\n", + code, ret, (code == CDC_FAIL)?(buf + 4):""); + if ((code == CDC_FAIL) || ((code == CDC_OK) && ret == 4)) + break; + } + } + +} + + +char* removeQuotes(char* str) { + int len = strlen(str); + int i; + + for (i = 0; i < len; i++) + if (str[i] != '\"') + break; + str = str + i; + + len = strlen(str); + + for (i = len -1; i > 0; i--) + if (str[i] == '\"') + str[i] = '\0'; + return str; +} + +static void parseCSV(const char* filename) { + struct vault_service svc; + FILE* file = fopen(filename, "r"); + uint8_t cKe[CRYPTO_KEY_SIZE]; + int ret; + char gadget_passphrase[64 + 1]; + char line[1024]; + int header_line_skipped = 0; + if (file == NULL) { + printf("Failed to open the file.\n"); + return; + } + + printf("Enter gadget passphrase to encrypt and send info: "); + disableEcho(); + getPassword(gadget_passphrase, 64); + enableEcho(); + printf("\n"); + /* Derive device key (password based) to create encryption key */ + ret = wc_PBKDF2(cKe, gadget_passphrase, strlen(gadget_passphrase), + Status.salt, SALT_LEN, 1000, CRYPTO_KEY_SIZE, WC_SHA512); + + if (ret < 0) { + printf("Failed to derive password.\n"); + return; + } + + while (fgets(line, sizeof(line), file)) { + int i; + + // Skip header line + if (!header_line_skipped) { + header_line_skipped = 1; + continue; + } + + // Parse each line of the CSV + char* token = strtok(line, ","); + if (token == NULL) { + continue; + } + + // Remove quotes from the fields + token = removeQuotes(token); + char* url = token; + + // Strip "https:" if present + if (strncmp(url, "https:", 6) == 0) { + url += 6; + } + + // Strip "http:" if present + if (strncmp(url, "http:", 5) == 0) { + url += 6; + } + + // Strip slashes ("/") if present + while (*url == '/') { + url++; + } + + // Strip content after the domain name if present + char* slash = strchr(url, '/'); + if (slash != NULL) { + *slash = '\0'; + } + + // Parse the domain from right to left + char* domainStart = NULL; + char domain[MAX_SVC_NAME_LEN + 1] = ""; + char *domainDot = strrchr(url, '.'); + + if (domainDot != NULL) { + *domainDot=','; + domainStart = strrchr(url, '.'); + *domainDot='.'; + } + if (domainStart == NULL) { + strncpy(domain, url, MAX_SVC_NAME_LEN); + domain[strlen(url)] = '\0'; + } else { + int domainLen = strlen(domainStart + 1); + strncpy(domain, domainStart + 1, domainLen); + } + + // Store the extracted domain, user, and pass fields + memset(&svc, 0, sizeof(svc)); + printf("Domain: %s\n", domain); + strncpy(svc.name,domain, 16); + + token = strtok(NULL, ","); + if (token != NULL) { + token = removeQuotes(token); + strncpy(svc.user, token, sizeof(svc.user) - 1); + } + + token = strtok(NULL, ","); + if (token != NULL) { + token = removeQuotes(token); + strncpy(svc.pass, token, sizeof(svc.pass)); + } + for (i = 0; i < 3; i++) { + ret = get_vault_status(); + if (ret == 0) + break; + } + if (ret < 0) { + printf("Adding service: failed.\n"); + getchar(); + return; + } + addservice(&svc, cKe); + } + fclose(file); +} + + +void printMenu() { + printf("\n"); + printf("0) Device status\n"); + printf("1) TOFU\n"); + printf("2) Add service\n"); + printf("3) Import passwords from CSV\n"); + printf("q) Quit\n\n"); +} + +char getUserInput() { + char input; + printf("Choice: "); + scanf(" %c", &input); + getchar(); // Consume the newline character + return input; +} + +void processChoice(char choice) { + char csv_filename[PATH_MAX]; + switch (choice) { + case '0': + // Handle option 0 (Device status) + clearScreen(); + printf("Device status selected.\n"); + break; + case '1': + // Handle option 1 (TOFU) + clearScreen(); + printf("TOFU selected.\n"); + strcpy(pass_prompt, pass_prompt_phrase); + strcpy(pass_confirm, pass_confirm_phrase); + memset(passphrase, 0, sizeof(passphrase)); + while(!askpass()) { + printf("Press a key to continue...\r\n"); + getchar(); + } + + tofu(passphrase); + break; + case '2': + // Handle option 2 (Add service) + clearScreen(); + printf("Add service selected.\n"); + strcpy(pass_prompt, pass_prompt_phrase); + strcpy(pass_confirm, pass_confirm_phrase); + if (Status.state < 0x02) { + printf("Cannot add service: device not initialized.\n"); + break; + } + if (pk_fd < 0) { + printf("Cannot add service: private key not present for this device.\n"); + break; + } + addservice(NULL, NULL); + break; + case '3': + // Handle option 3 (Import CSV) + clearScreen(); + printf("CSV file: "); + scanf("%s", csv_filename); + getchar(); + parseCSV(csv_filename); + break; + case 'q': + case 'Q': + // Quit the program + printf("Quitting...\n"); + exit(0); + default: + printf("Invalid choice.\n"); + break; + } + + printf("Press Enter to continue...\n"); + getchar(); // Wait for Enter key +} + + +static int get_vault_status(void) +{ + uint32_t rcount = 0; + struct cdc_packet_hdr hdr; + int ret; + int i; + struct pollfd pfd; + uint8_t rxbuf[sizeof(struct cdc_packet_hdr) + sizeof(struct vault_status)]; + pfd.fd = sfd; + pfd.events = POLLIN; + + hdr.magic = VAULT_MAGIC; + hdr.cmd = CDC_STATUS; + hdr.len = 0; + for (i = 0; i < 3; i++) { + ret = write(sfd, &hdr, sizeof(hdr)); + if (ret <= 0) + return ret; + + ret = poll(&pfd, 1, 1000); + if (ret == 0) { + printf("Get status: timeout"); + continue; + } + if (ret < 0) { + perror("get_status(): polling device"); + return -1; + } + do { + ret = read(sfd, rxbuf + rcount, sizeof(rxbuf) - rcount); + if (ret < 0) { + return -1; + } + rcount += ret; + } while (rcount < sizeof(rxbuf)); + break; + } + if (rcount > 0) { + if (*(uint32_t *)(rxbuf) != VAULT_MAGIC) + return -2; + if (*(uint16_t *)(rxbuf + 4) != CDC_STATUS) + return -3; + memcpy(&Status, rxbuf + sizeof(struct cdc_packet_hdr), sizeof(Status)); + return 0; + } + return -1; +} + + +static const char vstatenames[][32] = { + "OFF", + "TOFU", + "BOOTUP", + "VERIFY_PASSPHRASE", + "VERIFY_FAILED", + "MAIN_MENU", + "SETTINGS_MENU", + "SERVICE_LIST" +}; + + + + +int main(int argc, char *argv[]) +{ + clearScreen(); + system("mkdir -p " HOMEPATH_PREFIX); + + if (argc != 2) { + fprintf(stderr, "Usage: %s TTY\n", argv[0]); + return 2; + } + + sfd = serial_open(argv[1], 115200); + if (sfd < 0) { + perror("serial_open"); + if (errno == EACCES) { + printf("\n\nPerhaps you should review your permission for %s, or 'sudo adduser $YOUR_USER dialout'\r\n", argv[1]); + } + return 1; + } + while (1) { + char choice; + if (get_vault_status() < 0) { + printf("Not connected\n"); + } else { + char pkfname[MAX_PATH]; + char *homedir; + homedir = getenv("HOME"); + if (!homedir || strlen(homedir) == 0) { + perror("getenv(HOME)"); + exit(1); + } + + snprintf(pkfname, MAX_PATH - 1, "%s/.pvault/%08x-%08x.der", homedir, Status.id[0], Status.id[1]); + printf("Device %08x-%08x Connected.\n", Status.id[0], Status.id[1]); + pk_fd = open(pkfname, O_RDONLY); + if (pk_fd < 0) { + perror("open"); + printf(pkfname); + printf("\n"); + + printf("Private key not available.\n"); + } else { + printf("Private key loaded.\n"); + } + printf("State: %s - Services: %hu. Spot: %hu\n", + vstatenames[Status.state], Status.services_active, Status.first_avail); + } + printMenu(); + choice = getUserInput(); + processChoice(choice); + } + + return 0; +} + diff --git a/pico-sdk b/pico-sdk new file mode 160000 index 0000000..2062372 --- /dev/null +++ b/pico-sdk @@ -0,0 +1 @@ +Subproject commit 2062372d203b372849d573f252cf7c6dc2800c0a diff --git a/pico_sdk_import.cmake b/pico_sdk_import.cmake new file mode 100644 index 0000000..28efe9e --- /dev/null +++ b/pico_sdk_import.cmake @@ -0,0 +1,62 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + ) + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + FetchContent_Populate(pico_sdk) + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/src/cdc-protocol.c b/src/cdc-protocol.c new file mode 100644 index 0000000..bc9fd48 --- /dev/null +++ b/src/cdc-protocol.c @@ -0,0 +1,260 @@ +/* Motenpoche + * + * (c) 2023 Daniele Lacamera + * + * + * Motenpoche 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 2 of the License, or + * (at your option) any later version. + * + * Motenpoche 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + */ + +#include +#include "class/cdc/cdc.h" +#include "class/cdc/cdc_device.h" +#include "bsp/board.h" +#include "wolfssl/wolfcrypt/settings.h" +#include "cryptoengine.h" +#include "flash.h" +#include "fsm.h" +#include "hardware/gpio.h" + +#include "display.h" + + +extern uint16_t flash_info; +extern int thread_control_ui; +extern void system_reboot(void); + +extern uint8_t checked_digest[]; + + + +// Invoked when cdc when line state changed e.g connected/disconnected +void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) +{ + (void) itf; + (void) rts; + + // TODO set some indicator + if ( dtr ) + { + // Terminal connected + + }else + { + // Terminal disconnected + } +} + + +static uint8_t cdc_rxbuf[MAX_CDC_CMD]; +static uint32_t cdc_rx_idx = 0; +static uint32_t cdc_rx_expected = 0xFFFFFFFF; +static int rx_busy = 0; + +static void send_OK(void) +{ + struct cdc_packet_hdr OKhdr; + OKhdr.magic = VAULT_MAGIC; + OKhdr.cmd = CDC_OK; + OKhdr.len = 0; + tud_cdc_write((void *)&OKhdr, 8); + tud_cdc_write_flush(); +} + +static void send_fail(char *errmsg) +{ + uint8_t failbuf[256 + 8]; + struct cdc_packet_hdr *hdr = (struct cdc_packet_hdr*)failbuf; + + memset(failbuf, 0, 256 + 8); + snprintf(failbuf + 8, 256, "%s", errmsg); + hdr->magic = VAULT_MAGIC; + hdr->cmd = CDC_FAIL; + hdr->len = strlen(failbuf + 8); + tud_cdc_write((void *)hdr, 8 + strlen(failbuf + 8)); + tud_cdc_write_flush(); +} + +static void parse_cmd(int rxbuf_size) +{ + struct cdc_packet_hdr *hdr; + uint16_t svc_active, svc_avail; + hdr = (struct cdc_packet_hdr *)(cdc_rxbuf); + switch(hdr->cmd & 0xFF) { + case CDC_STATUS: + int i; + enum vault_state st = fsm_get(); + struct vault_status *vst; + uint32_t n_st = (uint32_t)st; + uint8_t status_buffer[sizeof(struct cdc_packet_hdr) + + sizeof(struct vault_status)]; + + hdr = (struct cdc_packet_hdr *)status_buffer; + vst = (struct vault_status *)(status_buffer + + sizeof(struct cdc_packet_hdr)); + + hdr->magic = VAULT_MAGIC; + hdr->cmd = CDC_STATUS; + hdr->len = sizeof(struct cdc_packet_hdr) + sizeof(struct vault_status); + + memset(vst, 0, sizeof(struct vault_status)); + vst->state = fsm_get(); + if (cryptoengine_check_vault() == 0) { + cryptoengine_fill_vault_status(vst); + } + svc_active = 0; + svc_avail = 0; + cryptoengine_service_count(&svc_active, &svc_avail); + vst->services_active = svc_active; + vst->first_avail = svc_avail; + for (i = 0; i < sizeof(status_buffer);) { + int len = 64; + if ((sizeof(status_buffer) - i) < len) + len = (sizeof(status_buffer) - i); + tud_cdc_write((void *)status_buffer + i, len); + tud_cdc_write_flush(); + i += len; + } + break; + case CDC_TOFU_INIT: + if (fsm_get() != VAULT_TOFU) { + send_fail("Already provisioned"); + break; + } + if (hdr->len == sizeof(struct vault_header)) { + struct vault_header *vh = (struct vault_header *) + (cdc_rxbuf + sizeof(struct cdc_packet_hdr)); + if (rxbuf_size != (hdr->len + sizeof(struct cdc_packet_hdr))) { + char msg[64]; + sprintf(msg, "packet len mismatch exp: %d got %d", + (hdr->len + sizeof(struct cdc_packet_hdr)), + rxbuf_size); + send_fail(msg); + } + if (vh->magic != VAULT_MAGIC) { + send_fail("TOFU Rejected."); + break; + } + if (cryptoengine_hdr_sha_check(vh) < 0) { + send_fail("TOFU Rejected."); + break; + } + + /* Take control of display/buttons */ + thread_control_ui = 1; + sleep_ms(100); + display_clear(); + display_text(0, "Provisioning..."); + + flash_sector_erase(VAULT_FLASH_OFFSET); + flash_write(VAULT_FLASH_OFFSET, cdc_rxbuf + sizeof(struct cdc_packet_hdr), sizeof(struct vault_header)); + + display_text(1, "Confirming... "); + send_OK(); + display_text(2, "Rebooting... "); + system_reboot(); + break; + } else { + send_fail("TOFU Rejected."); + break; + } + break; + case CDC_CHALLENGE: + break; + + case CDC_REKEY: + break; + case CDC_ADDSERV: + int ret; + uint16_t count, idx; + struct vault_service *vs; + gpio_put(16,1); + if (rxbuf_size != SVC_SIZE + sizeof(struct cdc_packet_hdr)) { + char msg[64]; + sprintf(msg, "packet len mismatch exp: %d got %d", hdr->len, rxbuf_size); + send_fail(msg); + break; + } + vs = (struct vault_service *)(cdc_rxbuf +sizeof(struct cdc_packet_hdr)); + /* Retrieve the implicit destination slot (current first slot available) */ + cryptoengine_service_count(&count, &idx); + if (cryptoengine_check_vault() < 0) + break; + ret = cryptoengine_import_service(vs, idx); + if (ret == 0) + send_OK(); + else { + char msg[40]; + sprintf(msg, "failed import: svc %s retval %d", vs->name, ret); + send_fail(msg); + } + break; + + case CDC_DELSERV: + break; + default: + send_fail("Bad cmd"); + + } + rx_busy = 0; + +} + + +// Invoked when CDC interface received data from host +void tud_cdc_rx_cb(uint8_t itf) +{ + (void) itf; + char buf[64]; + uint32_t count; + struct cdc_packet_hdr *hdr; + + if (rx_busy) { + tud_cdc_read_flush(); + return; + } + count = tud_cdc_read(buf, sizeof(buf)); + + + if (count > 0) { + if (count + cdc_rx_idx > MAX_CDC_CMD) { + cdc_rx_idx = 0; + } + memcpy(cdc_rxbuf + cdc_rx_idx, buf, count); + hdr = (struct cdc_packet_hdr *)cdc_rxbuf; + if (cdc_rx_idx == 0) { + if (hdr->magic != VAULT_MAGIC) { + send_fail("Bad magic"); + cdc_rx_idx = 0; + return; + } + if (hdr->len > MAX_CDC_CMD) { + send_fail("Bad cmd: too big"); + cdc_rx_idx = 0; + return; + } + cdc_rx_expected = hdr->len + sizeof(struct cdc_packet_hdr); + } + cdc_rx_idx += count; + if (cdc_rx_idx >= cdc_rx_expected) { + rx_busy = 1; + parse_cmd(cdc_rx_expected); + if (cdc_rx_expected < cdc_rx_idx) { + memcpy(cdc_rxbuf, cdc_rxbuf + cdc_rx_expected, cdc_rx_idx - cdc_rx_expected); + } + cdc_rx_idx-=cdc_rx_expected; + } + } +} diff --git a/src/cryptoengine.c b/src/cryptoengine.c new file mode 100644 index 0000000..ac7223f --- /dev/null +++ b/src/cryptoengine.c @@ -0,0 +1,246 @@ +/* Motenpoche + * + * (c) 2023 Daniele Lacamera + * + * + * Motenpoche 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 2 of the License, or + * (at your option) any later version. + * + * Motenpoche 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + */ +#include "user_settings.h" +#include +#include "cryptoengine.h" +#include "fsm.h" +#include "flash.h" +#include "class/cdc/cdc.h" +#include "class/cdc/cdc_device.h" +#include "bsp/board.h" +#include "wolfssl/wolfcrypt/sha512.h" +#include "wolfssl/wolfcrypt/pwdbased.h" +#include "wolfssl/wolfcrypt/chacha.h" +#include "wolfssl/wolfcrypt/ecc.h" +#include "hardware/gpio.h" + +static struct vault_header hdr_cache; + +uint32_t sector_cache_id = 0xFFFFFFFF; +static ChaCha cha; +static ecc_key ecc; + +static struct vault_service svc_cache; +static int svc_cache_id = -1; + +int flash_decrypt_read_svc(struct vault_service *out, uint32_t addr) +{ + if (cryptoengine_check_vault() < 0) + return -1; + flash_read(addr, &svc_cache, SVC_SIZE); + memcpy(out, (uint8_t *)(&svc_cache), SVC_ENC_OFF); + wc_Chacha_SetIV(&cha, hdr_cache.host_seed, addr); + wc_Chacha_Process(&cha, (uint8_t *)out + SVC_ENC_OFF, ((uint8_t *)&svc_cache) + SVC_ENC_OFF, SVC_ENC_SIZE); + return 0; +} + +static int flash_encrypt_write_svc(const struct vault_service *svc, uint32_t idx) +{ + uint32_t addr = idx * SVC_SIZE + SVC_FLASH_OFFSET; + if (cryptoengine_check_vault() < 0) + return -1; + wc_Chacha_SetIV(&cha, hdr_cache.host_seed, addr); + wc_Chacha_Process(&cha, (uint8_t *)&svc_cache, (uint8_t *)svc, SVC_SIZE); + flash_write_svc(&svc_cache, idx); +} + +int cryptoengine_verify_passphrase(const char *passphrase, int *res) +{ + int ret = -1; + int i; + uint8_t SecretKey[CRYPTO_KEY_SIZE]; + uint8_t DecryptedSignature[PK_SIGNATURE_SIZE]; + mp_int r, s; + mp_init(&r); + mp_init(&s); + *res = 0; + + if (cryptoengine_check_vault() < 0) { + return -1; + } + + ret = wc_PBKDF2(SecretKey, passphrase, strlen(passphrase), hdr_cache.host_salt, SALT_LEN, 1000, 32, SHA512); + if (ret < 0) + return ret; + wc_Chacha_SetKey(&cha, SecretKey, CRYPTO_KEY_SIZE); + wc_Chacha_SetIV(&cha, hdr_cache.host_seed, 0); + wc_Chacha_Process(&cha, DecryptedSignature, hdr_cache.signature, PK_SIGNATURE_SIZE); + + wc_ecc_init(&ecc); + if (wc_ecc_import_unsigned(&ecc, hdr_cache.auth_pubkey, + hdr_cache.auth_pubkey + CRYPTO_KEY_SIZE, + NULL, ECC_SECP256R1) < 0) { + mp_free(&r); + mp_free(&s); + wc_ecc_free(&ecc); + return -1; + } + mp_read_unsigned_bin(&r, DecryptedSignature, CRYPTO_KEY_SIZE); + mp_read_unsigned_bin(&s, DecryptedSignature + CRYPTO_KEY_SIZE, + CRYPTO_KEY_SIZE); + + ret = wc_ecc_verify_hash_ex(&r, &s, hdr_cache.digest, VAULT_DIGEST_SIZE, + res, &ecc); + mp_free(&r); + mp_free(&s); + if ((ret < 0) || (*res != 1)) { + if (*res == 0) + gpio_put(16, 0); + + wc_ecc_free(&ecc); + } + return ret; +} + + +static void hdr_cache_load(void) +{ + flash_read(VAULT_FLASH_OFFSET, &hdr_cache, sizeof(struct vault_header)); +} + + +uint8_t checked_digest[VAULT_DIGEST_SIZE]; +int cryptoengine_hdr_sha_check(const struct vault_header *vh) +{ + Sha512 sha; + int hash, hash_len; + wc_InitSha512(&sha); + for (hash = 0; hash < SHA_PAYLOAD_SIZE;) { + hash_len = WC_SHA512_BLOCK_SIZE; + if ((SHA_PAYLOAD_SIZE - hash) < hash_len) + hash_len = SHA_PAYLOAD_SIZE - hash; + wc_Sha512Update(&sha, ((uint8_t*)vh) + hash, hash_len); + hash += hash_len; + } + wc_Sha512Final(&sha, checked_digest); + if(memcmp(checked_digest, vh->digest, VAULT_DIGEST_SIZE) != 0) { + return -1; + } + wc_Sha512Free(&sha); + return 0; +} + +int cryptoengine_svc_sha_check(const struct vault_service *vs) +{ + Sha512 sha; + int hash, hash_len; + const uint32_t svc_sha_payload_size = (sizeof(struct vault_service) - (VAULT_DIGEST_SIZE + PK_SIGNATURE_SIZE)); + wc_InitSha512(&sha); + for (hash = 0; hash < svc_sha_payload_size;) { + hash_len = WC_SHA512_BLOCK_SIZE; + if ((svc_sha_payload_size - hash) < hash_len) + hash_len = svc_sha_payload_size - hash; + wc_Sha512Update(&sha, ((uint8_t*)vs) + hash, hash_len); + hash += hash_len; + } + wc_Sha512Final(&sha, checked_digest); + if(memcmp(checked_digest, vs->dig, VAULT_DIGEST_SIZE) != 0) { + return -1; + } + wc_Sha512Free(&sha); + return 0; +} + +int cryptoengine_svc_sig_verify(const struct vault_service *vs, int *res) +{ + int ret; + mp_int r, s; + mp_init(&r); + mp_init(&s); + + mp_read_unsigned_bin(&r, vs->sig, CRYPTO_KEY_SIZE); + mp_read_unsigned_bin(&s, vs->sig + CRYPTO_KEY_SIZE, CRYPTO_KEY_SIZE); + + ret = wc_ecc_verify_hash_ex(&r, &s, vs->dig, VAULT_DIGEST_SIZE, res, &ecc); + mp_free(&r); + mp_free(&s); + return ret; +} + +int cryptoengine_check_vault(void) +{ + hdr_cache_load(); + if (hdr_cache.magic != VAULT_MAGIC) { + return -1; + } + /* Checking hdr integrity */ + if (cryptoengine_hdr_sha_check(&hdr_cache) < 0) + return -1; + + /* Vault seems valid, integrity check OK */ + return 0; +} + +int cryptoengine_import_service(struct vault_service *vs, uint32_t idx) +{ + uint32_t address = SVC_FLASH_OFFSET + SVC_SIZE * idx; + int res; + if (cryptoengine_check_vault() < 0) + return -1; + memcpy(&svc_cache, ((uint8_t *)vs), SVC_ENC_OFF); + wc_Chacha_SetIV(&cha, hdr_cache.host_seed, address); + wc_Chacha_Process(&cha, ((uint8_t *)&svc_cache) + SVC_ENC_OFF, + ((uint8_t *)vs) + SVC_ENC_OFF, SVC_ENC_SIZE); + if (cryptoengine_svc_sha_check(&svc_cache) < 0) { + return -1; + } + if ((cryptoengine_svc_sig_verify(&svc_cache, &res) < 0) || (res != 1)) + { + return -2; + } + flash_write_svc(vs, idx); + return 0; +} + +int cryptoengine_service_count(uint16_t *n_srv, uint16_t *first_avail) +{ + int i = 0; + *first_avail = (uint16_t)-1; + *n_srv = 0; + + struct vault_service svc; + if (cryptoengine_check_vault() < 0) + return -1; + + while (1) { + flash_read(SVC_FLASH_OFFSET + (i * SVC_SIZE), &svc, SVC_SIZE); + if (svc.flags == SVC_FLAG_ACTIVE) + (*n_srv)++; + else if (svc.flags == SVC_FLAG_ERASED) + *first_avail = i; + else if (svc.flags == SVC_FLAG_UNUSED) { + if (*first_avail == ((uint16_t)-1)) + *first_avail = i; + break; + } + i++; + } + return *n_srv; +} + +int cryptoengine_fill_vault_status(struct vault_status *vst) +{ + if (cryptoengine_check_vault() < 0) + return -1; + memcpy(vst->id, &hdr_cache.id, 2 * sizeof(uint32_t)); + memcpy(vst->salt, &hdr_cache.host_salt, SALT_LEN); + memcpy(vst->seed, &hdr_cache.host_seed, SEED_LEN); +} diff --git a/src/cryptoengine.h b/src/cryptoengine.h new file mode 100644 index 0000000..eed5ad2 --- /dev/null +++ b/src/cryptoengine.h @@ -0,0 +1,119 @@ +/* Motenpoche + * + * (c) 2023 Daniele Lacamera + * + * + * Motenpoche 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 2 of the License, or + * (at your option) any later version. + * + * Motenpoche 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + */ +#ifndef CRYPTOENGINE_H +#define CRYPTOENGINE_H +#include +#include +#define CRYPTO_KEY_SIZE 32 +#define PK_SIGNATURE_SIZE 64 +#define SEED_LEN 24 + +#define SALT_LEN 64 + +/* Use lower half of flash */ +#define VAULT_FLASH_OFFSET 0x00000000 +#define VAULT_FLASH_SIZE (512 * 1024) + +#define VAULT_DIGEST_SIZE WC_SHA512_DIGEST_SIZE +#define SHA_PAYLOAD_SIZE (sizeof(struct vault_header) - (PK_SIGNATURE_SIZE + VAULT_DIGEST_SIZE)) + + +#define VAULT_MAGIC 0x5AFECA5E +int cryptoengine_verify_passphrase(const char *passphrase, int *res); +int cryptoengine_check_vault(void); +struct __attribute__((packed)) vault_header { + uint32_t magic; /* 0x5afeca5e */ + uint32_t size; /* Including magic and size */ + uint32_t id[2]; + uint8_t auth_pubkey[2 * CRYPTO_KEY_SIZE]; /* pc-signP, used to authenticate header on rekey/changes */ + uint8_t host_salt[SALT_LEN]; /* current PBKDF2 salt. vS = PBKDF2(passphrase, SALT) */ + uint8_t host_seed[SEED_LEN]; /* current 'seed' used for IV */ + uint8_t digest[VAULT_DIGEST_SIZE]; /* SHA digest of this header */ + uint8_t signature[PK_SIGNATURE_SIZE]; /* Signature of the digest */ +}; + + +struct __attribute__((packed)) vault_status { + uint32_t id[2]; + uint8_t salt[SALT_LEN]; + uint8_t seed[SEED_LEN]; + uint16_t state; + uint16_t services_active; + uint16_t first_avail; +}; + +struct __attribute__((packed)) cdc_packet_hdr +{ + uint32_t magic; /* 0x5AFECA5E */ + uint16_t cmd; + uint16_t len; +}; + +#define CDC_STATUS 0x0000 +#define CDC_TOFU_INIT 0x0001 +#define CDC_CHALLENGE 0x0002 +#define CDC_REKEY 0x0003 +#define CDC_ADDSERV 0x0004 +#define CDC_DELSERV 0x0005 + +#define CDC_OK 0x0100 +#define CDC_FAIL 0x0800 + +#define MAX_CDC_CMD 512 + + +#define SETTINGS_FLASH_OFFSET 0x300 +#define SVC_FLASH_OFFSET 0x400 + +#define SVC_NAME_SIZE_LIMIT 16 +#define SVC_USER_NAME_MAX 32 +#define SVC_PASSWORD_MAX 64 + +#define SVC_FLAG_UNUSED 0xFFFFFFFF +#define SVC_FLAG_ERASED 0xDEADC0DE +#define SVC_FLAG_ACTIVE 0xAAAAAAAA + + +struct __attribute__((packed)) vault_service +{ + uint32_t flags; + uint32_t reserved; + char name[24]; + char user[32]; + char pass[64]; + uint8_t dig[64]; + uint8_t sig[64]; +}; + +#define SVC_ENC_SIZE (256 - 8) +#define SVC_ENC_OFF (8) +#define SVC_SIZE (256) + +int cryptoengine_hdr_sha_check(const struct vault_header *vh); +int cryptoengine_svc_sha_check(const struct vault_service *vs); +int cryptoengine_svc_sig_verify(const struct vault_service *vs, int *res); +int cryptoengine_import_service(struct vault_service *vs, uint32_t idx); + +int cryptoengine_service_count(uint16_t *n_srv, uint16_t *first_avail); +int cryptoengine_fill_vault_status(struct vault_status *vst); +int flash_decrypt_read_svc(struct vault_service *out, uint32_t addr); + +#endif diff --git a/src/display.c b/src/display.c new file mode 100644 index 0000000..c3b61e2 --- /dev/null +++ b/src/display.c @@ -0,0 +1,180 @@ +/* Motenpoche + * + * (c) 2023 Daniele Lacamera + * + * + * Motenpoche 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 2 of the License, or + * (at your option) any later version. + * + * Motenpoche 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + */ +#include +#include +#include "display.h" +#include "hardware/i2c.h" +#include "bsp/board.h" + +#define DISPLAY_I2C_ADDR 0x3C + +static uint8_t contrast = 0xcf; +static i2c_inst_t *i2c_inst = NULL; + + +static void display_send_data(const uint8_t *buf, int len) +{ + const uint8_t start_data = 0x40; + int i; + uint8_t data_buf[200]; + data_buf[0] = 0x40; + if (len > 199) + len = 199; + memcpy(data_buf + 1, buf, len); + if (!i2c_inst) + return; + i2c_write_blocking(i2c_inst, DISPLAY_I2C_ADDR, data_buf, len+1, 0); +} + +static void display_send_cmd(uint8_t cmd) +{ + uint8_t buf[2] = {0x00, cmd}; + if (!i2c_inst) + return; + i2c_write_blocking(i2c_inst, DISPLAY_I2C_ADDR, buf, 2, 0); +} + +static void display_send_cmd1(uint8_t cmd, uint8_t arg1) +{ + uint8_t buf[3] = {0x00, cmd, arg1}; + if (!i2c_inst) + return; + i2c_write_blocking(i2c_inst, DISPLAY_I2C_ADDR, buf, 3, 0); +} +static void display_send_cmd2(uint8_t cmd, uint8_t arg1, uint8_t arg2) +{ + uint8_t buf[4] = {0x00, cmd, arg1, arg2}; + if (!i2c_inst) + return; + i2c_write_blocking(i2c_inst, DISPLAY_I2C_ADDR, buf, 4, 0); +} + + +void display_scroll(uint8_t line) +{ + display_send_cmd1(SSD1306_SETSTARTLINE, (line % 0x40) + 0x40); +} + +void display_setcontrast(uint8_t c) +{ + contrast = c; + display_send_cmd1(SSD1306_SETCONTRAST, contrast); +} + +uint8_t display_getcontrast(void) +{ + return contrast; +} + +void display_clear(void) +{ + + int i,j; + uint8_t zeros[8] = {0, 0, 0, 0, 0, 0, 0, 0 }; + display_send_cmd(0x00); + display_send_cmd(0x10); + + for (i = 0; i < 8; i++) + { + display_send_cmd2(SSD1306_PAGEADDR, i, 0xFF); + for (j = 0; j < WIDTH; j++) + display_send_data(zeros, 8); + } +} + +void display_text(int row, const char *text) +{ + int k; + display_send_cmd(0x00); + display_send_cmd(0x10); + display_send_cmd2(SSD1306_PAGEADDR, 7 - row, 0xFF); + for(k = 0; k < strlen(text); k++) + display_send_data(fb_font[text[k]], 8); +} + +void display_text_inverse(int row, int col, const char *text) +{ + int k, j; + uint8_t inv_buf[8]; + uint8_t ones[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + int len = strlen(text); + if (len > 15) + len = 15; + display_send_cmd(0x00); + display_send_cmd(0x10); + sleep_us(1000); + display_send_cmd2(SSD1306_PAGEADDR, 7 - row, 0x00); + display_send_cmd2(SSD1306_COLUMNADDR, col << 3, WIDTH - 1); + for(k = 0; k < len; k++) { + for (j = 0; j < 8; j++) + inv_buf[j] = ~fb_font[text[k]][j]; + display_send_data(inv_buf, 8); + } + display_send_cmd2(SSD1306_COLUMNADDR, 0, WIDTH - 1); +} + + +int display_init(void *priv) +{ + int i; + int k = 0; + int row = 0; + volatile int j; + uint8_t dbuf2[64] = {}; + int page = 0; + int seg = 0; + volatile uint32_t now; + + i2c_inst = (i2c_inst_t *)priv; + + + for (i = 1; i < 64; i++) { + dbuf2[i] = 0; + } + display_send_cmd(SSD1306_DISPLAYOFF); + display_send_cmd1(0xD6, 0x01); + display_send_cmd(0xA1); + display_setcontrast(contrast); + display_send_cmd1(SSD1306_CHARGEPUMP, 0x14); + display_send_cmd1(SSD1306_MEMORYMODE, 0x00); + display_send_cmd1(SSD1306_SETCOMPINS, 0x12); + display_send_cmd1(SSD1306_SETDISPLAYOFFSET, 0x00); + display_send_cmd1(SSD1306_SETVCOMDETECT, 0x00); + display_send_cmd1(SSD1306_SETMULTIPLEX, 63); + display_send_cmd(SSD1306_COMSCANINC); + display_send_cmd(SSD1306_DISPLAYALLON_RESUME); + display_send_cmd(SSD1306_DISPLAYON); + display_send_cmd(0x2E); + + display_send_cmd2(SSD1306_PAGEADDR, 0, 0xFF); + display_send_cmd2(SSD1306_COLUMNADDR, 0, WIDTH - 1); + display_send_cmd1(SSD1306_SETSTARTLINE, 0); + display_send_cmd(0x00); + display_send_cmd(0x10); + for (page = 0; page < 8; page++) { + display_send_cmd2(SSD1306_PAGEADDR, page, 0xFF); + for (seg= 0; seg < 32; seg++) { + display_send_data(dbuf2, 8); + } + display_send_cmd1(SSD1306_SETSTARTLINE, row); + } + return 0; +} diff --git a/src/display.h b/src/display.h new file mode 100644 index 0000000..0ef3941 --- /dev/null +++ b/src/display.h @@ -0,0 +1,71 @@ +/* Motenpoche + * + * (c) 2023 Daniele Lacamera + * + * + * Motenpoche 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 2 of the License, or + * (at your option) any later version. + * + * Motenpoche 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + */ +#ifndef DISPLAY_H_INCLUDED +#define DISPLAY_H_INCLUDED +#include + +#define WIDTH 128 +#define PIXEL_HEIGHT 64 +#define HEIGHT (PIXEL_HEIGHT / 8) +extern const unsigned char fb_font[256][8]; +#define SSD1306_MEMORYMODE 0x20 +#define SSD1306_COLUMNADDR 0x21 +#define SSD1306_PAGEADDR 0x22 +#define SSD1306_SETCONTRAST 0x81 +#define SSD1306_CHARGEPUMP 0x8D +#define SSD1306_SEGREMAP 0xA0 +#define SSD1306_DISPLAYALLON_RESUME 0xA4 +#define SSD1306_DISPLAYALLON 0xA5 +#define SSD1306_NORMALDISPLAY 0xA6 +#define SSD1306_INVERTDISPLAY 0xA7 +#define SSD1306_SETMULTIPLEX 0xA8 +#define SSD1306_DISPLAYOFF 0xAE +#define SSD1306_DISPLAYON 0xAF +#define SSD1306_COMSCANINC 0xC0 +#define SSD1306_COMSCANDEC 0xC8 +#define SSD1306_SETDISPLAYOFFSET 0xD3 +#define SSD1306_SETDISPLAYCLOCKDIV 0xD5 +#define SSD1306_SETPRECHARGE 0xD9 +#define SSD1306_SETCOMPINS 0xDA +#define SSD1306_SETVCOMDETECT 0xDB +#define SSD1306_SETLOWCOLUMN 0x00 +#define SSD1306_SETHIGHCOLUMN 0x10 +#define SSD1306_SETSTARTLINE 0x40 +#define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26 +#define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27 +#define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29 +#define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A +#define SSD1306_DEACTIVATE_SCROLL 0x2E +#define SSD1306_ACTIVATE_SCROLL 0x2F +#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3 + + + + +int display_init(void *priv); +void display_text(int row, const char *text); +void display_text_inverse(int row, int col, const char *text); +void display_scroll(uint8_t line); +void display_setcontrast(uint8_t c); +uint8_t display_getcontrast(); +void display_clear(); + +#endif diff --git a/src/flash.c b/src/flash.c new file mode 100644 index 0000000..f664ec7 --- /dev/null +++ b/src/flash.c @@ -0,0 +1,228 @@ +/* Motenpoche + * + * (c) 2023 Daniele Lacamera + * + * + * Motenpoche 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 2 of the License, or + * (at your option) any later version. + * + * Motenpoche 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + */ +#include +#include +#include "hardware/gpio.h" +#include "flash.h" +#include "cryptoengine.h" + +#include "bsp/board.h" + + + +#define MDID 0x90 +#define RDSR 0x05 +#define WRSR 0x01 +# define ST_BUSY (1 << 0) +# define ST_WEL (1 << 1) +# define ST_BP0 (1 << 2) +# define ST_BP1 (1 << 3) +# define ST_BP2 (1 << 4) +# define ST_BP3 (1 << 5) +# define ST_AAI (1 << 6) +# define ST_BRO (1 << 7) +#define WREN 0x06 +#define WRDI 0x04 +#define SECTOR_ERASE 0x20 +#define BYTE_READ 0x03 +#define BYTE_WRITE 0x02 +#define EWSR 0x50 +#define EBSY 0x70 +#define DBSY 0x80 + + +#define SPI_FLASH_CS_PIN 5 + +static spi_inst_t *SPI = NULL; + +static void write_address(uint32_t address) +{ + uint8_t a0 = (uint8_t)((address & 0xFF0000) >> 16), + a1 = (uint8_t)((address & 0xFF00) >> 8), + a2 = (uint8_t)((address & 0xFF)); + spi_write_blocking(SPI, &a0, 1); + spi_write_blocking(SPI, &a1, 1); + spi_write_blocking(SPI, &a2, 1); +} + +static uint8_t read_status(void) +{ + uint8_t status; + uint8_t rdsr = RDSR; + gpio_put(SPI_FLASH_CS_PIN, 0); + spi_write_blocking(SPI, &rdsr, 1); + spi_read_blocking(SPI, 0xFF, &status, 1); + gpio_put(SPI_FLASH_CS_PIN, 1); + return status; +} + +uint8_t flash_read_status(void) +{ + return read_status(); +} + +static void spi_cmd(uint8_t cmd) +{ + gpio_put(SPI_FLASH_CS_PIN, 0); + spi_write_blocking(SPI, &cmd, 1); + gpio_put(SPI_FLASH_CS_PIN, 1); +} + +#ifndef GREEN_LED +#define GREEN_LED 16 +#endif +volatile uint8_t flash_status; +static void flash_write_enable(void) +{ + do { + spi_cmd(WREN); + flash_status = read_status(); + } while ((flash_status & ST_WEL) == 0); +} + +static void flash_write_disable(void) +{ + spi_cmd(WRDI); +} + +static void wait_busy(void) +{ + do { + flash_status = read_status(); + } while((flash_status & ST_BUSY) != 0); +} + +static int spi_flash_write_sb(uint32_t address, const void *data, int len) +{ + const uint8_t *buf = data; + uint8_t verify = 0; + int j = 0; + + wait_busy(); + if (len < 1) + return -1; + while (len > 0) { + uint8_t cmd = BYTE_WRITE; + flash_write_enable(); + gpio_put(SPI_FLASH_CS_PIN, 0); + spi_write_blocking(SPI, &cmd, 1); + write_address(address); + spi_write_blocking(SPI, &buf[j], 1); + gpio_put(SPI_FLASH_CS_PIN, 1); + + wait_busy(); + j++; + len--; + address++; + } + return 0; +} + +/* --- */ + +static uint16_t spi_flash_probe(void) +{ + uint8_t manuf, product, cmd[2]; + int i; + wait_busy(); + gpio_put(SPI_FLASH_CS_PIN, 0); + cmd[0] = MDID; + spi_write_blocking(SPI, cmd, 1); + write_address(0); + spi_read_blocking(SPI, 0xFF, &manuf, 1); + spi_read_blocking(SPI, 0xFF, &product, 1); + gpio_put(SPI_FLASH_CS_PIN, 1); + wait_busy(); + flash_write_enable(); + gpio_put(SPI_FLASH_CS_PIN, 0); + cmd[0] = WRSR; + cmd[1] = 0x00; + spi_write_blocking(SPI, cmd, 2); + gpio_put(SPI_FLASH_CS_PIN, 1); + return (uint16_t)(manuf << 8 | product); +} + +uint16_t flash_init(spi_inst_t *spi) +{ + uint16_t ret; + //uint32_t mgc = VAULT_MAGIC - 1; + SPI = spi; + ret = spi_flash_probe(); + return ret; +} + + + +int flash_sector_erase(uint32_t address) +{ + uint8_t cmd; + address &= (~(SPI_FLASH_SECTOR_SIZE - 1)); + + wait_busy(); + flash_write_enable(); + gpio_put(SPI_FLASH_CS_PIN, 0); + cmd = SECTOR_ERASE; + spi_write_blocking(SPI, &cmd, 1); + write_address(address); + gpio_put(SPI_FLASH_CS_PIN, 1); + wait_busy(); + return 0; +} + +int flash_read(uint32_t address, void *data, int len) +{ + uint8_t *buf = data, cmd; + int i = 0; + wait_busy(); + gpio_put(SPI_FLASH_CS_PIN, 0); + cmd = BYTE_READ; + spi_write_blocking(SPI, &cmd, 1); + write_address(address); + spi_read_blocking(SPI, 0xFF, buf, len); + gpio_put(SPI_FLASH_CS_PIN, 1); + return len; +} + +int flash_write(uint32_t address, const void *data, int len) +{ + int ret; + ret = spi_flash_write_sb(address, data, len); + wait_busy(); + return ret; +} + +static uint8_t flash_sector_write_cache[SPI_FLASH_SECTOR_SIZE]; +int flash_write_svc(struct vault_service *svc, int idx) +{ + const int svc_per_sector = SPI_FLASH_SECTOR_SIZE / SVC_SIZE; + uint32_t addr = SVC_FLASH_OFFSET + SVC_SIZE * idx; + uint32_t sector = addr / SPI_FLASH_SECTOR_SIZE; + uint32_t offset = addr - (sector * SPI_FLASH_SECTOR_SIZE); + + flash_read(sector * SPI_FLASH_SECTOR_SIZE, flash_sector_write_cache, + SPI_FLASH_SECTOR_SIZE); + memcpy(flash_sector_write_cache + offset, (uint8_t *)svc, SVC_SIZE); + flash_sector_erase(sector * SPI_FLASH_SECTOR_SIZE); + flash_write(sector * SPI_FLASH_SECTOR_SIZE, flash_sector_write_cache, + SPI_FLASH_SECTOR_SIZE); + return 0; +} + diff --git a/src/flash.h b/src/flash.h new file mode 100644 index 0000000..e73efae --- /dev/null +++ b/src/flash.h @@ -0,0 +1,32 @@ +/* Motenpoche + * + * (c) 2023 Daniele Lacamera + * + * + * Motenpoche 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 2 of the License, or + * (at your option) any later version. + * + * Motenpoche 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + */ +#ifndef FLASH_H +#define FLASH_H +#include "hardware/spi.h" +#include "cryptoengine.h" +#define SPI_FLASH_SECTOR_SIZE 0x1000 +uint16_t flash_init(spi_inst_t *spi); +int flash_sector_erase(uint32_t address); +int flash_read(uint32_t address, void *data, int len); +int flash_write(uint32_t address, const void *data, int len); +int flash_write_svc(struct vault_service *svc, int idx); +uint8_t flash_read_status(void); +#endif diff --git a/src/font_twisted.c b/src/font_twisted.c new file mode 100644 index 0000000000000000000000000000000000000000..a0c2b21485c008c9200c6fcdbeb424f44de7c41c GIT binary patch literal 16280 zcmbu^b#z=s6b5iyg1f`RA(Upb*=#nHVkIqw(iU1Yl(O0EwtK+Dh( zE%tnSu_xa#uH5@mT}`2@v)mI+=qz`P>Fn*UFgD*EmD)y^dgHdH8?&QYbEBgE(bSr# z_n)b$$*EMIXlC1KeWJSBXqMh6y;J$Wd{&Lmrt#S|K8MEV)c9N)pIhVeXnbCc=L?1W z_%5xF`7}Pi#uw1|f*M~);|pti5sfdZ@x?U0xW<>z_>vl5O5;mwd>M@|tMTPDzP!d) z(D;fPUrFOph?nxy|6ag1!pccrqz?_gc0WMCS7DycRU(#(l{R_pa4?*Cyki<8qB%>v_&sa8u`~$ z3VcoG4L0nIMaLYp`bEGS0dklLo zZ)3oHXKeAdNioL*86zl}RB#H2Ue6q*!O`RW@96|Q%{)ij6|l`%6tTs>j@$nDc4F z(Q)55_ngBM!)~^0GzC-F%$)m2{`ro3jlr+y;Wmb}Ctb;c?Z+HN8m~KTAvZ2MLG<;R z1BP0+6Y&1b@cC8aJ_HHJg#?3T^p+2+9tc>i@p)_2HS5a zmYl6Mu5sVTH)f9d;{Ar}@UGj0IS(EQo!gD1-0{HkK=9qi(^%S3YHmYhT*tDB5$4{6kr?Ezr7pZ_ zhcQPK-fy_hIxEg+-EihkbnG{r^LFj7K2o<8b0@mZ8n20L@U+>QdDdbjD=rhVW+=dr#TKqj_cfwy6J21~#bpEcx2T~!p?mIHa9OET3!iTnR@U6^I zp2>#efVHU_lywgbcO_dIi?2*l|mSg>u(G1TN3(3Lw8luUtn5@ICbg=_b4JK56I#?|M^ ze35xPczdjgKFi%<^GRD`9{(|7*-oSCXOQ_Z%rQr-IJfmUMm&Qb%N&D5p4&h?rOJcv zNOGQO+=&yH`L4|41w!FiiwuNc(7Q25TrO1~!*H|;d${C)>Si{0oO{NBv5QK#QlJ3;F9VP5@-=NP&M-&f=N zX?%Z;AE5CAHGYuB57zi08b4IyhiUw9jUS=$BQ<`M#*fzcF&aNsZ(V#;?}+H5$KG_$?a0RpYm5{C17sq47I4 zewW7Y*7!XdzgOe;Y5abTKcMjkHU5ysAJ+II8h=#dk7@jIjX$CBCpG?*#-G;sGa7$Z zFE##^#=qA1HyZy| + * + * + * Motenpoche 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 2 of the License, or + * (at your option) any later version. + * + * Motenpoche 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + */ +#include +#include "ui.h" +#include "display.h" +#include "bsp/board.h" +#include "fsm.h" +#include "ui.h" + +static enum vault_state vault_state = VAULT_OFF; +static volatile int ui_event_pending = 0; +static enum vault_state old_st = 0; + +void fsm_event_task(void) +{ + /* UI trigger */ + if (ui_event_pending) { + ui_event_pending = 0; + ui_event_cb(old_st, fsm_get()); + } +} + +/* state transactions: actions */ +void fsm_set(enum vault_state st) +{ + old_st = vault_state; + + if (st == vault_state) + return; + /* Change state */ + vault_state = st; + ui_event_cb(old_st, fsm_get()); +} + +enum vault_state fsm_get(void) +{ + return vault_state; +} diff --git a/src/fsm.h b/src/fsm.h new file mode 100644 index 0000000..efc6836 --- /dev/null +++ b/src/fsm.h @@ -0,0 +1,38 @@ +/* Motenpoche + * + * (c) 2023 Daniele Lacamera + * + * + * Motenpoche 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 2 of the License, or + * (at your option) any later version. + * + * Motenpoche 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + */ +#ifndef VAULT_FSM_H +#define VAULT_FSM_H +enum vault_state { + VAULT_OFF = 0, + VAULT_TOFU, + VAULT_BOOTUP, + VAULT_VERIFY_PASSPHRASE, + VAULT_VERIFY_FAILED, + /* From here on: Authenticated */ + VAULT_MAIN_MENU, + VAULT_SETTINGS_MENU, + VAULT_SERVICE_LIST +}; + +void fsm_set(enum vault_state st); +enum vault_state fsm_get(void); +void fsm_event_task(void); +#endif diff --git a/src/hid.c b/src/hid.c new file mode 100644 index 0000000..aa10fc1 --- /dev/null +++ b/src/hid.c @@ -0,0 +1,240 @@ +/* Motenpoche + * + * (c) 2023 Daniele Lacamera + * + * + * Motenpoche 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 2 of the License, or + * (at your option) any later version. + * + * Motenpoche 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + */ +#include +#include +#include "pico/stdlib.h" +#include "pico/multicore.h" +#include "hardware/gpio.h" +#include "hardware/adc.h" +#include "hardware/i2c.h" +#include "hardware/spi.h" +#include "cryptoengine.h" + +#include "bsp/board.h" + +#include "tusb.h" +#include "usb_descriptors.h" +#include "ui.h" + +static bool has_keyboard_key = false; + +/* USB HID: capslock */ +static int capslock_on = 0; + +/* USB HID: tx buffer */ +#define TX_BUFFER_SIZE 256 +static char tx_buffer_str[TX_BUFFER_SIZE]; +static volatile int tx_buffer_wr=0, tx_buffer_rd=0; + +/* ASCII to HID conversion */ +static const uint8_t const conv_table[128][2] = { HID_ASCII_TO_KEYCODE }; + +// Invoked when device is mounted +void tud_mount_cb(void) +{ +} + +// Invoked when device is unmounted +void tud_umount_cb(void) +{ +} + +// Invoked when usb bus is suspended +// remote_wakeup_en : if host allow us to perform remote wakeup +// Within 7ms, device must draw an average of current less than 2.5 mA from bus +void tud_suspend_cb(bool remote_wakeup_en) +{ + (void) remote_wakeup_en; +} + +// Invoked when usb bus is resumed +void tud_resume_cb(void) +{ +} + +/* USB: tud complete cb */ +void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len) +{ + (void) instance; + (void) len; + (void) report; + if (has_keyboard_key) { + tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL); + has_keyboard_key = false; + } else if (tx_buffer_rd > tx_buffer_wr) { + uint8_t modifier = 0; + uint8_t keycode[6] = {0}; + char c = tx_buffer_str[tx_buffer_wr]; + if (c == '\t') + keycode[0] = HID_KEY_TAB; + else { + modifier = conv_table[c][0]; + keycode[0] = conv_table[c][1]; + } + if (capslock_on) { + if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))) { + modifier = !modifier; + } + } + if (modifier) + modifier = KEYBOARD_MODIFIER_LEFTSHIFT; + tud_hid_keyboard_report(REPORT_ID_KEYBOARD, modifier, keycode); + has_keyboard_key = true; + tx_buffer_wr++; + } + +} + +/* USB HID: get report */ +uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) +{ + // TODO not Implemented + (void) instance; + (void) report_id; + (void) report_type; + (void) buffer; + (void) reqlen; + + return 0; +} + +/* Invoked when SET_REPORT control request or + * data on OUT endpoint ( Report ID = 0, Type = 0 ) are received + */ +void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) +{ + (void) instance; + + if (report_type == HID_REPORT_TYPE_OUTPUT) + { + // Set keyboard LED e.g Capslock, Numlock etc... + if (report_id == REPORT_ID_KEYBOARD) + { + // bufsize should be (at least) 1 + if ( bufsize < 1 ) return; + + uint8_t const kbd_leds = buffer[0]; + + if (kbd_leds & KEYBOARD_LED_CAPSLOCK) + { + capslock_on = 1; + }else + { + capslock_on = 0; + } + } + } +} + + +//--------------------------------------------------------------------+ +// USB HID +//--------------------------------------------------------------------+ + +static void send_hid_report(uint8_t report_id, uint32_t unused) +{ + (void)unused; + + if ( !tud_hid_ready() ) + return; + + switch(report_id) + { + case REPORT_ID_KEYBOARD: + { + // use to avoid send multiple consecutive zero report for keyboard + uint8_t modifier = 0; + + if (tx_buffer_rd > tx_buffer_wr) { + uint8_t keycode[6] = { 0 }; + char c = tx_buffer_str[tx_buffer_wr]; + if (c == '\t') + keycode[0] = HID_KEY_TAB; + else { + modifier = conv_table[c][0]; + keycode[0] = conv_table[c][1]; + } + if (capslock_on) { + if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))) { + modifier = !modifier; + } + } + if (modifier) + modifier = KEYBOARD_MODIFIER_LEFTSHIFT; + tud_hid_keyboard_report(REPORT_ID_KEYBOARD, modifier, keycode); + has_keyboard_key = true; + tx_buffer_wr++; + } else { + if (has_keyboard_key) + tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL); + has_keyboard_key = false; + } + } + break; + + + default: break; + } +} + +void hid_keys_string_send(const char *str) +{ + int len = strlen(str); + int i; + if (tx_buffer_rd == tx_buffer_wr) { + tx_buffer_rd = 0; + ForceZero(tx_buffer_str, TX_BUFFER_SIZE); + tx_buffer_wr = 0; + } + for(i = 0; i < len; i++) { + if (tx_buffer_rd >= TX_BUFFER_SIZE) + return; + tx_buffer_str[tx_buffer_rd++] = str[i]; + } + gpio_put(17, 0); +} + +// Every 10ms, we will sent 1 report for each HID profile (keyboard, mouse etc ..) +// tud_hid_report_complete_cb() is used to send the next report after previous one is complete +void hid_task(void) +{ + // Poll every 10ms + const uint32_t interval_ms = 10; + static uint32_t start_ms = 0; + if (!tud_inited()) + return; + + if ( board_millis() - start_ms < interval_ms) return; // not enough time + start_ms += interval_ms; + + // Remote wakeup + if ( tud_suspended() && (tx_buffer_rd > tx_buffer_wr)) + { + // Wake up host if we are in suspend mode + // and REMOTE_WAKEUP feature is enabled by host + tud_remote_wakeup(); + }else + { + // Send the 1st of report chain, the rest will be sent by tud_hid_report_complete_cb() + send_hid_report(REPORT_ID_KEYBOARD, 0); + gpio_put(17, 1); + } +} diff --git a/src/hid.h b/src/hid.h new file mode 100644 index 0000000..65a98d1 --- /dev/null +++ b/src/hid.h @@ -0,0 +1,26 @@ +/* Motenpoche + * + * (c) 2023 Daniele Lacamera + * + * + * Motenpoche 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 2 of the License, or + * (at your option) any later version. + * + * Motenpoche 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + */ +#ifndef HID_H_INCLUDED +#define HID_H_INCLUDED +void hid_task(void); +void hid_keys_string_send(const char *str); + +#endif diff --git a/src/msc_disk.c b/src/msc_disk.c new file mode 100644 index 0000000..a20ee41 --- /dev/null +++ b/src/msc_disk.c @@ -0,0 +1,265 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "bsp/board.h" +#include "tusb.h" + +#if CFG_TUD_MSC + +// whether host does safe-eject +static bool ejected = false; + +// Some MCU doesn't have enough 8KB SRAM to store the whole disk +// We will use Flash as read-only disk with board that has +// CFG_EXAMPLE_MSC_READONLY defined + +#define README_CONTENTS \ +"This is the password vault utilities directory.\r\n\r\nWork in progress\r\n" + +enum +{ + DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount + DISK_BLOCK_SIZE = 512 +}; + +#ifdef CFG_EXAMPLE_MSC_READONLY +const +#endif +uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = +{ + //------------- Block0: Boot Sector -------------// + // byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM; + // sector_per_cluster = 1; reserved_sectors = 1; + // fat_num = 1; fat12_root_entry_num = 16; + // sector_per_fat = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0; + // drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29; + // filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC"; + // FAT magic code at offset 510-511 + { + 0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00, + 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'V' , 'a' , 'u' , 'l' , 't' , + ' ' , 'T' , 'o' , 'o' , 'l' , 's' , 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00, + + // Zero up to 2 last bytes of FAT magic code + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA + }, + + //------------- Block1: FAT12 Table -------------// + { + 0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file + }, + + //------------- Block2: Root Directory -------------// + { + // first entry is volume label + 'V' , 'a' , 'u' , 'l' , 't' , ' ' , 'T' , 'o' , 'o' , 'l' , 's' , 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // second entry is readme file + 'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' , 'T' , 'X' , 'T' , 0x20, 0x00, 0xC6, 0x52, 0x6D, + 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00, + sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes) + }, + + //------------- Block3: Readme Content -------------// + README_CONTENTS +}; + +// Invoked when received SCSI_CMD_INQUIRY +// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) +{ + (void) lun; + + const char vid[] = "DLX"; + const char pid[] = "Vault tools"; + const char rev[] = "0.1a"; + + memcpy(vendor_id , vid, strlen(vid)); + memcpy(product_id , pid, strlen(pid)); + memcpy(product_rev, rev, strlen(rev)); +} + +// Invoked when received Test Unit Ready command. +// return true allowing host to read/write this LUN e.g SD card inserted +bool tud_msc_test_unit_ready_cb(uint8_t lun) +{ + (void) lun; + + // RAM disk is ready until ejected + if (ejected) { + tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00); + return false; + } + + return true; +} + +// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size +// Application update block count and block size +void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) +{ + (void) lun; + + *block_count = DISK_BLOCK_NUM; + *block_size = DISK_BLOCK_SIZE; +} + +// Invoked when received Start Stop Unit command +// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage +// - Start = 1 : active mode, if load_eject = 1 : load disk storage +bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) +{ + (void) lun; + (void) power_condition; + + if ( load_eject ) + { + if (start) + { + // load disk storage + }else + { + // unload disk storage + ejected = true; + } + } + + return true; +} + +// Callback invoked when received READ10 command. +// Copy disk's data to buffer (up to bufsize) and return number of copied bytes. +int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) +{ + (void) lun; + + // out of ramdisk + if ( lba >= DISK_BLOCK_NUM ) return -1; + + uint8_t const* addr = msc_disk[lba] + offset; + memcpy(buffer, addr, bufsize); + + return bufsize; +} + +bool tud_msc_is_writable_cb (uint8_t lun) +{ + (void) lun; + + /* Read only. */ + return false; +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and return number of written bytes +int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) +{ + (void) lun; + // out of ramdisk + if ( lba >= DISK_BLOCK_NUM ) + return -1; + /* Read only. Silently fail. */ + (void) lba; (void) offset; (void) buffer; + return bufsize; +} + +// Callback invoked when received an SCSI command not in built-in list below +// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE +// - READ10 and WRITE10 has their own callbacks +int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) +{ + // read10 & write10 has their own callback and MUST not be handled here + + void const* response = NULL; + int32_t resplen = 0; + + // most scsi handled is input + bool in_xfer = true; + + switch (scsi_cmd[0]) + { + case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + // Host is about to read/write etc ... better not to disconnect disk + resplen = 0; + break; + + default: + // Set Sense = Invalid Command Operation + tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); + + // negative means error -> tinyusb could stall and/or response with failed status + resplen = -1; + break; + } + + // return resplen must not larger than bufsize + if ( resplen > bufsize ) resplen = bufsize; + + if ( response && (resplen > 0) ) + { + if(in_xfer) + { + memcpy(buffer, response, resplen); + }else + { + // SCSI output + } + } + + return resplen; +} + +#endif diff --git a/src/password_safe.c b/src/password_safe.c new file mode 100644 index 0000000..d5bc189 --- /dev/null +++ b/src/password_safe.c @@ -0,0 +1,341 @@ +/* Motenpoche + * + * (c) 2023 Daniele Lacamera + * + * + * Motenpoche 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 2 of the License, or + * (at your option) any later version. + * + * Motenpoche 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + */ +#include +#include +#include "pico/stdlib.h" +#include "pico/multicore.h" +#include "hardware/gpio.h" +#include "hardware/adc.h" +#include "hardware/i2c.h" +#include "hardware/spi.h" +#include "cryptoengine.h" + +#include "bsp/board.h" + +#include "tusb.h" +#include "usb_descriptors.h" +#include "ui.h" + +#include "user_settings.h" +#include "wolfssl/wolfcrypt/settings.h" +#include "class/cdc/cdc.h" +#include "class/cdc/cdc_device.h" +#include "class/msc/msc.h" +#include "hardware/gpio.h" +#include "flash.h" +#include "display.h" +#include "hid.h" + + +void core1_main(void); +static volatile int main_plug = 1; +int thread_control_ui = 0; + + +/* DOUT */ + +#define RED_LED 17 +#define GREEN_LED 16 +#define PICO_LED PICO_DEFAULT_LED_PIN + +static uint Led[] = { + RED_LED, + GREEN_LED, + PICO_LED +}; + + +/* DIN */ +#define ROT_S0 19 +#define ROT_S1 20 +#define ROT_KEY 18 +#define OK_BUTTON 21 +#define BACK_BUTTON 22 + +/* I2C */ +#define I2C (&i2c1_inst) +#define I2C_BAUDRATE 48000 +#define I2C_SCL_PIN 27 +#define I2C_SDA_PIN 26 + +/* SPI */ +#define SPI (spi0) +#define SPI_BAUDRATE 100000 +#define SPI_SCLK_PIN 2 +#define SPI_MOSI_PIN 3 +#define SPI_MISO_PIN 4 +#define SPI_FLASH_CS_PIN 5 + + + +uint16_t flash_info = 0xFFFF; + +#define AIRCR *(volatile uint32_t *)(0xE000ED0C) +#define AIRCR_VKEY (0x05FA << 16) +#define AIRCR_SYSRESETREQ (1 << 2) +static void sys_reboot(void) +{ + AIRCR = AIRCR_SYSRESETREQ | AIRCR_VKEY; + while(1) + ; +} + +void system_reboot(void) +{ + int i; + main_plug = 0; + thread_control_ui = 2; + for (i = display_getcontrast(); i >= 0; i--) { + display_setcontrast(i); + sleep_ms(5); + } + display_clear(); +} + +void system_boot(void) +{ + int i, ret; + set_sys_clock_48mhz(); + multicore_reset_core1(); + //stdio_init_all(); + + printf("Initializing USB...\r\n"); + tusb_init(); + printf("Done.\r\n"); + + /* LED and Douts */ + printf("Setting LEDs\r\n"); + for (i = 0; i < 3; i++) { + gpio_init(Led[i]); + gpio_set_dir(Led[i], GPIO_OUT); + gpio_put(Led[i], 0); + } + gpio_put(RED_LED, 1); + gpio_put(GREEN_LED, 1); + printf("Done.\n"); + + /* BTN Dins */ + printf("Setting buttons and digital inputs...\r\n"); + gpio_init(ROT_S0); + gpio_init(ROT_S1); + gpio_init(ROT_KEY); + gpio_init(OK_BUTTON); + gpio_init(BACK_BUTTON); + gpio_set_dir(ROT_S0, GPIO_IN); + gpio_set_dir(ROT_S1, GPIO_IN); + gpio_set_dir(ROT_KEY, GPIO_IN); + gpio_set_dir(OK_BUTTON, GPIO_IN); + gpio_set_dir(BACK_BUTTON, GPIO_IN); + gpio_pull_down(ROT_S0); + gpio_pull_down(ROT_S1); + gpio_pull_up(ROT_KEY); + gpio_pull_down(OK_BUTTON); + gpio_pull_down(BACK_BUTTON); + printf("Done.\n"); + + + + printf("Initializing SPI Flash\r\n"); + gpio_init(SPI_SCLK_PIN); + gpio_init(SPI_MOSI_PIN); + gpio_init(SPI_MISO_PIN); + gpio_init(SPI_FLASH_CS_PIN); + gpio_set_function(SPI_SCLK_PIN, GPIO_FUNC_SPI); + gpio_set_function(SPI_MOSI_PIN, GPIO_FUNC_SPI); + gpio_set_function(SPI_MISO_PIN, GPIO_FUNC_SPI); + gpio_set_dir(SPI_FLASH_CS_PIN, GPIO_OUT); + gpio_put(SPI_FLASH_CS_PIN, 1); + spi_init(SPI, SPI_BAUDRATE); + flash_info = flash_init(SPI); + + printf("Initializing I2C Display\r\n"); + gpio_init(I2C_SDA_PIN); + gpio_init(I2C_SCL_PIN); + gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C); + gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C); + i2c_init(I2C, I2C_BAUDRATE); + ui_init(I2C); + printf("Done\r\n"); + + printf("Starting CPU Core 1\r\n"); + multicore_launch_core1(core1_main); + printf("Done\r\n"); + + gpio_put(RED_LED, 0); + printf("Init complete.\r\n"); +} + +#define ROT_UP 1 +#define ROT_DOWN 2 + +uint32_t rotary_action(void) +{ + uint32_t action = 0; + if (gpio_get(ROT_S0)) + action |= 1; + if (gpio_get(ROT_S1)) + action |= 2; + return action; +} + +int rot_updown(void) +{ + static int rot_up = 0; + static int rot_down = 0; + static uint32_t rotary_pos = 0; + uint32_t rotary_now; + rotary_now = rotary_action(); + if (rotary_now != rotary_pos) { + if ((rotary_pos == 0 && rotary_now == 3) || + (rotary_pos == 3 && rotary_now == 2) || + (rotary_pos == 2 && rotary_now == 0) || + (rotary_pos == 1 && rotary_now == 3)) { + rot_down++; + rot_up = 0; + } + if ((rotary_pos == 0 && rotary_now == 1) || + (rotary_pos == 3 && rotary_now == 1) || + (rotary_pos == 2 && rotary_now == 3) || + (rotary_pos == 1 && rotary_now == 0)) { + rot_up++; + rot_down = 0; + } + rotary_pos = rotary_now; + } + if (rot_up > 1) { + rot_up = 0; + return ROT_UP; + } + if (rot_down > 1) { + rot_down = 0; + return ROT_DOWN; + } + return 0; +} + +static uint32_t key_press_counter = 0; +static uint32_t ok_press_counter = 0; +static uint32_t back_press_counter = 0; + +void clear_input(void) +{ + key_press_counter = 0; + ok_press_counter = 0; + back_press_counter = 0; +} + +void poll_buttons(void) +{ + int rot_ud = 0; + + if (gpio_get(ROT_KEY) == 0) { + key_press_counter++; + } else { + key_press_counter = 0; + } + + if (gpio_get(OK_BUTTON) != 0) { + ok_press_counter++; + } else { + ok_press_counter = 0; + } + if (gpio_get(BACK_BUTTON) != 0) { + back_press_counter++; + } else { + back_press_counter = 0; + } + + if (ok_press_counter == 100) { + printf("OK: pressed\n"); + ui_confirm_button(); + return; + } + + if (key_press_counter == 100) { + printf("key: pressed\n"); + ui_key_button(); + return; + } + + if (back_press_counter == 100) { + printf("back: pressed\n"); + ui_back_button(); + return; + } + if ((fsm_get() == VAULT_BOOTUP) && (back_press_counter == 100000)) { + uint32_t i; + for (i = 0; i < VAULT_FLASH_SIZE; i+=SPI_FLASH_SECTOR_SIZE) + flash_sector_erase(i); + + system_reboot(); + return; + } + + rot_ud = rot_updown(); + + if (rot_ud == ROT_UP) { + ui_rot_up(); + sleep_ms(1); + return; + } + if (rot_ud == ROT_DOWN) { + ui_rot_down(); + sleep_ms(1); + return; + } +} + +uint8_t *fbuf = NULL; + + +static uint8_t flash_buf[4]; +int main(void) { + int i; + system_boot(); + printf("Loop started.\n"); + + + while (main_plug) { + uint32_t ms_tick = board_millis(); + if ((ms_tick % 10) == 0) { + if (thread_control_ui == 0) { + poll_buttons(); + } + } + if (thread_control_ui == 0) { + if ((ms_tick % 100) == 0) { + ui_task(); + } + } + } + + /* End of session. Goodbye. */ + multicore_reset_core1(); + sys_reboot(); +} + +void core1_main(void) +{ + while(1) { + hid_task(); + tud_task(); + } +} diff --git a/src/tusb_config.h b/src/tusb_config.h new file mode 100644 index 0000000..708c6b6 --- /dev/null +++ b/src/tusb_config.h @@ -0,0 +1,114 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef _TUSB_CONFIG_H_ +#define _TUSB_CONFIG_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//-------------------------------------------------------------------- +// COMMON CONFIGURATION +//-------------------------------------------------------------------- + +// defined by board.mk +#ifndef CFG_TUSB_MCU + #error CFG_TUSB_MCU must be defined +#endif + +// RHPort number used for device can be defined by board.mk, default to port 0 +#ifndef BOARD_DEVICE_RHPORT_NUM + #define BOARD_DEVICE_RHPORT_NUM 0 +#endif + +// RHPort max operational speed can defined by board.mk +// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed +#ifndef BOARD_DEVICE_RHPORT_SPEED + #if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \ + CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X) + #define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED + #else + #define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED + #endif +#endif + +// Device mode with rhport and speed defined by board.mk +#if BOARD_DEVICE_RHPORT_NUM == 0 + #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED) +#elif BOARD_DEVICE_RHPORT_NUM == 1 + #define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED) +#else + #error "Incorrect RHPort configuration" +#endif + +#ifndef CFG_TUSB_OS +#define CFG_TUSB_OS OPT_OS_NONE +#endif + +// CFG_TUSB_DEBUG is defined by compiler in DEBUG build +// #define CFG_TUSB_DEBUG 0 + +/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. + * Tinyusb use follows macros to declare transferring memory so that they can be put + * into those specific section. + * e.g + * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) + * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) + */ +#ifndef CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_SECTION +#endif + +#ifndef CFG_TUSB_MEM_ALIGN +#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) +#endif + +//-------------------------------------------------------------------- +// DEVICE CONFIGURATION +//-------------------------------------------------------------------- + +#ifndef CFG_TUD_ENDPOINT0_SIZE +#define CFG_TUD_ENDPOINT0_SIZE 64 +#endif + +//------------- CLASS -------------// +#define CFG_TUD_HID 1 +#define CFG_TUD_CDC 1 +#define CFG_TUD_MSC 1 +#define CFG_TUD_MIDI 0 +#define CFG_TUD_VENDOR 0 + +// HID buffer size Should be sufficient to hold ID (if any) + Data +#define CFG_TUD_HID_EP_BUFSIZE 16 +#define CFG_TUD_MSC_EP_BUFSIZE 64 +#define CFG_TUD_CDC_RX_BUFSIZE 64 +#define CFG_TUD_CDC_TX_BUFSIZE 64 + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CONFIG_H_ */ diff --git a/src/ui.c b/src/ui.c new file mode 100644 index 0000000..884f483 --- /dev/null +++ b/src/ui.c @@ -0,0 +1,583 @@ +/* Motenpoche + * + * (c) 2023 Daniele Lacamera + * + * + * Motenpoche 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 2 of the License, or + * (at your option) any later version. + * + * Motenpoche 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + */ +#include +#include "ui.h" +#include "display.h" +#include "bsp/board.h" +#include "hardware/gpio.h" +#include "cryptoengine.h" +#include "wolfssl/wolfcrypt/settings.h" +#include "wolfssl/wolfcrypt/misc.h" +#include "fsm.h" +#include "display.h" +#include "flash.h" +#include "hid.h" + + +#define PASSPHRASE_MAX 128 + +#ifndef GREEN_LED +#define GREEN_LED 16 +#endif + + +static const char welcome_message0[]= " There is no "; +static const char welcome_message1[]= "knowledge that "; +static const char welcome_message2[]= " is not power. "; + +extern void system_reboot(void); +static uint16_t service_list_selected = 0; +static uint16_t service_list_count = 0; +static void ui_service_list(uint32_t count); + + + +/* UI current state globals */ +static int current_row = 1; +static int current_char_pos = 0; +static char current_char = ' '; +static char passphrase[PASSPHRASE_MAX]; +static int blinking = 0; + +void ui_event_cb(enum vault_state old_st, enum vault_state st) +{ + int result = 0; + int ret = -1; + current_char = ' '; + (void)old_st; + switch (st) { + case VAULT_BOOTUP: + display_clear(); + display_text(0, "Type Passphrase"); + ForceZero(passphrase, PASSPHRASE_MAX); + current_char_pos = 0; + break; + case VAULT_VERIFY_PASSPHRASE: + char msg[17]; + display_text(0, "Authenticating.."); + display_text(1, " "); + display_text(2, " "); + display_text(3," "); + ret = cryptoengine_verify_passphrase(passphrase, &result); + if ((ret != 0) || (result != 1)) { + fsm_set(VAULT_VERIFY_FAILED); + return; + } + gpio_put(GREEN_LED, 0); + fsm_set(VAULT_MAIN_MENU); + return; + break; + case VAULT_MAIN_MENU: + display_text(0," "); + display_text(1," "); + display_text(2," "); + display_text(3," "); + display_text_inverse(0, 2, "[Main Menu]"); + break; + case VAULT_SETTINGS_MENU: + display_text(0," "); + display_text(1," "); + display_text(2," "); + display_text(3," "); + display_text_inverse(0, 3, "[Settings]"); + break; + case VAULT_SERVICE_LIST: + uint16_t count, spot; + cryptoengine_service_count(&count, &spot); + service_list_count = count; + display_text(0," "); + display_text(1," "); + display_text(2," "); + display_text(3," "); + display_text_inverse(0, 3, "[Services]"); + break; + } + ui_task(); +} + + +static const char main_menu_entry[3][17] = { + "[~ Services ~]", + "[~ Settings ~]", + "[~ Reboot ~]" +}; + + +#define MAINMENU_ENTRIES 3 + +static const char settings_menu_entry[3][17] = { + "[~ Keyb map ~]", + "[~ Paste mode ~]", + "[~ Forget All ~]" +}; +#define SETTINGSMENU_ENTRIES 3 + +static int menu_sel = 0; +static int old_menu_sel = 0xFF; + +static const char Keymaps[][17] = { + " [US]", + " [FR]", + " [DE]", + " [UK]", + " [IT]" +}; + +static int cur_keymap = 0; + +#define KEYMAPS_ENTRIES 5 + + +#define PASTEMODE_PASS_ONLY 0 +#define PASTEMODE_PASS_ENTER 1 +#define PASTEMODE_USER_TAB_PASS_ENTER 2 +#define PASTEMODE_USER_ENTER_PASS_ENTER 3 + +static const char PasteModes[][17] = { + "[Password only ]", + "[Password+Enter]", + "[UserTabPswdEnt]", + "[UserEntPswdEnt]" +}; + +static int cur_pastemode = 0; + +#define PASTEMODE_ENTRIES 4 + +static const char Are_you_sure[][17] = { + "Sure? NO ", + "Sure? Cancel", + "Sure? My mistake", + "Sure? Whut?", + "Sure? YES DO IT!" +}; + +static int cur_wipe_choice = 0; +#define AREYOUSURE_ENTRIES 5 + + + +static void mainmenu_action(void) +{ + switch (menu_sel) { + case 0: /* Services */ + fsm_set(VAULT_SERVICE_LIST); + break; + case 1: /* Settings */ + fsm_set(VAULT_SETTINGS_MENU); + break; + case 2: /* Reboot */ + system_reboot(); + break; + } +} + +static void settingsmenu_action(void) +{ + switch (menu_sel) { + case 0: /* Keymap */ + cur_keymap++; + if (cur_keymap == KEYMAPS_ENTRIES) + cur_keymap = 0; + break; + case 1: /* Paste mode */ + cur_pastemode++; + if (cur_pastemode == PASTEMODE_ENTRIES) + cur_pastemode = 0; + break; + case 2: /* Forget */ + cur_wipe_choice++; + if (cur_wipe_choice == AREYOUSURE_ENTRIES) + cur_wipe_choice = 0; + break; + } + /* Force redraw */ + old_menu_sel = 0xFF; +} + +static void settingsmenu_confirm(void) +{ + int i; + if ((menu_sel == 2) && (cur_wipe_choice == 4)) { + for (i = 0; i < VAULT_FLASH_SIZE; i+= SPI_FLASH_SECTOR_SIZE) + flash_sector_erase(i); + system_reboot(); + } else + settingsmenu_action(); +} + + +static void ui_service_list(uint32_t count) +{ + static int old_selected = -1; + int i = 0; + uint32_t address = SVC_FLASH_OFFSET; + uint32_t a_sel, a_prev = 0, a_next = 0; + struct vault_service svc; + + if (old_selected == (int)service_list_selected) + return; + old_selected = service_list_selected; + + if (count == 0) + return; + + + flash_read(address + service_list_selected * SVC_SIZE, + (void *)&svc, SVC_SIZE); + if (svc.flags != SVC_FLAG_ACTIVE) { + i = 0; + while (address < VAULT_FLASH_SIZE) { + flash_read(address + i * SVC_SIZE, &svc, SVC_SIZE); + if (svc.flags == SVC_FLAG_ACTIVE) { + service_list_selected = i; + break; + } + i += SVC_SIZE; + } + } + a_sel = SVC_FLASH_OFFSET + service_list_selected * SVC_SIZE; + a_next = 0; + a_prev = 0; + + /* Find previous entry */ + if (service_list_selected != 0) { + i = 1; + address = SVC_FLASH_OFFSET + SVC_SIZE * (service_list_selected - i); + while (address >= SVC_FLASH_OFFSET) { + flash_read(address, (void *)&svc, SVC_SIZE); + if (svc.flags == SVC_FLAG_ACTIVE) { + a_prev = address; + break; + } + i++; + address = SVC_FLASH_OFFSET + SVC_SIZE * (service_list_selected - i); + } + } + /* Find next entry */ + i = 1; + address = SVC_FLASH_OFFSET + SVC_SIZE * (service_list_selected + i); + while (address < VAULT_FLASH_SIZE) { + flash_read(address, (void *)&svc, SVC_SIZE); + if (svc.flags == SVC_FLAG_ACTIVE) { + a_next = address; + break; + } else if (svc.flags == SVC_FLAG_UNUSED) { + break; + } + i++; + address = SVC_FLASH_OFFSET + SVC_SIZE * (service_list_selected + i); + } + + display_text(1," "); + display_text(2," "); + display_text(3," "); + + if (a_prev != 0) { + flash_decrypt_read_svc(&svc, a_prev); + display_text(1, svc.name); + } + if (a_next != 0) { + flash_decrypt_read_svc(&svc, a_next); + display_text(3, svc.name); + } + flash_decrypt_read_svc(&svc, a_sel); + display_text_inverse(2, 0, svc.name); +} + + +static void paste_password(void) +{ + struct vault_service svc; + uint32_t address; + if (fsm_get() != VAULT_SERVICE_LIST) + return; + if (flash_decrypt_read_svc(&svc, SVC_FLASH_OFFSET + + service_list_selected * SVC_SIZE) < 0) + return; + + switch(cur_pastemode) { + case PASTEMODE_PASS_ONLY: + hid_keys_string_send(svc.pass); + break; + case PASTEMODE_PASS_ENTER: + hid_keys_string_send(svc.pass); + hid_keys_string_send("\r"); + break; + case PASTEMODE_USER_TAB_PASS_ENTER: + hid_keys_string_send(svc.user); + hid_keys_string_send("\t"); + hid_keys_string_send(svc.pass); + hid_keys_string_send("\r"); + break; + case PASTEMODE_USER_ENTER_PASS_ENTER: + hid_keys_string_send(svc.user); + hid_keys_string_send("\t"); + hid_keys_string_send(svc.pass); + hid_keys_string_send("\r"); + break; + } +} + +void ui_task(void) +{ + const uint32_t interval_ms = 500; + static uint32_t start_ms = 0; + + if ( board_millis() - start_ms >= interval_ms) { + blinking ^= 1; + start_ms = board_millis(); + } + + switch(fsm_get()) { + case VAULT_TOFU: + gpio_put(17, blinking ^ 1); + display_text(0, " Welcome!"); + display_text(1, "Run tools on PC "); + display_text(2, " to initialize "); + break; + case VAULT_BOOTUP: + char pass_prompt[16]; + int i; + int sz; + gpio_put(17, blinking ^ 1); + sz = current_char_pos; + if (sz > 15) + sz = 15; + memset(pass_prompt, 0, 16); + for (i = 0; i < sz; i++) { + pass_prompt[i] = '*'; + } + if (!blinking) + pass_prompt[sz] = current_char; + display_text(1, pass_prompt); + if (blinking) { + char cursor[2] = {current_char, 0}; + display_text_inverse(1, sz, cursor); + } + break; + case VAULT_VERIFY_PASSPHRASE: + display_text(2, "Verifying..."); + gpio_put(17, blinking ^ 1); + break; + case VAULT_VERIFY_FAILED: + display_text(0, " Bad Passphrase "); + gpio_put(17, 0); + if (blinking) { + display_text(1," "); + display_text(2," "); + display_text_inverse(1, 4, "(x_x)"); + display_text_inverse(2, 3, "Try again"); + } else { + display_text(1, " (x_x) "); + display_text(2, " "); + } + break; + case VAULT_MAIN_MENU: + display_text(2,main_menu_entry[menu_sel]); + break; + case VAULT_SETTINGS_MENU: + + if (old_menu_sel != menu_sel) { + old_menu_sel = menu_sel; + + display_text(1, " "); + display_text(2, " "); + display_text(3, " "); + display_text(2,settings_menu_entry[menu_sel]); + switch(menu_sel) { + case 0: /* Keymap */ + display_text(3, Keymaps[cur_keymap]); + break; + case 1: + display_text(3, PasteModes[cur_pastemode]); + break; + case 2: + display_text(3, Are_you_sure[cur_wipe_choice]); + break; + } + } + break; + case VAULT_SERVICE_LIST: + if (service_list_count == 0) { + display_text(2, " No Services "); + break; + } else { + ui_service_list(service_list_count); + } + break; + } +} + +void ui_key_button(void) +{ + static int alter = 0; + enum vault_state vs = fsm_get(); + if (vs == VAULT_BOOTUP) { + passphrase[current_char_pos] = current_char; + current_char_pos++; + if(current_char_pos >= PASSPHRASE_MAX) { + fsm_set(VAULT_VERIFY_FAILED); + return; + } + passphrase[current_char_pos] = 0; + gpio_put(17, alter); + alter ^=1; + } else if (vs == VAULT_MAIN_MENU) + mainmenu_action(); + else if (vs == VAULT_SETTINGS_MENU) + settingsmenu_action(); + else if (vs == VAULT_SERVICE_LIST) + paste_password(); +} + +void ui_back_button(void) +{ + enum vault_state vault_state = fsm_get(); + if (vault_state == VAULT_BOOTUP) { + if (current_char_pos > 0) { + passphrase[current_char_pos] = '\0'; + current_char_pos--; + } + display_text(1, " "); + } + else if (vault_state == VAULT_VERIFY_FAILED) { + current_char_pos = 0; + fsm_set(VAULT_BOOTUP); + } + else if (vault_state == VAULT_SETTINGS_MENU) + fsm_set(VAULT_MAIN_MENU); + else if (vault_state == VAULT_SERVICE_LIST) + fsm_set(VAULT_MAIN_MENU); +} + +void ui_confirm_button(void) +{ + enum vault_state vault_state = fsm_get(); + if (vault_state == VAULT_BOOTUP) { + current_char_pos = 0; + fsm_set(VAULT_VERIFY_PASSPHRASE); + } + else if (vault_state == VAULT_MAIN_MENU) + mainmenu_action(); + else if (vault_state == VAULT_SETTINGS_MENU) + settingsmenu_confirm(); + else if (vault_state == VAULT_SERVICE_LIST) + paste_password(); +} + +void ui_rot_up(void) +{ + enum vault_state vault_state = fsm_get(); + if (vault_state == VAULT_BOOTUP) { + current_char++; + if (current_char > 126) + current_char = ' '; + } + else if (vault_state == VAULT_MAIN_MENU) { + menu_sel++; + if (menu_sel == MAINMENU_ENTRIES) + menu_sel = 0; + } + else if (vault_state == VAULT_SETTINGS_MENU) { + menu_sel++; + cur_wipe_choice = 0; + if (menu_sel == MAINMENU_ENTRIES) + menu_sel = 0; + } + else if (vault_state == VAULT_SERVICE_LIST) { + if (service_list_selected > 0) + service_list_selected --; + } +} + +void ui_rot_down(void) +{ + enum vault_state vault_state = fsm_get(); + if (vault_state == VAULT_BOOTUP) { + current_char--; + if (current_char < ' ') + current_char = 126; + } + else if (vault_state == VAULT_MAIN_MENU) { + menu_sel--; + if (menu_sel < 0) + menu_sel = MAINMENU_ENTRIES - 1; + } + else if (vault_state == VAULT_SETTINGS_MENU) { + menu_sel--; + cur_wipe_choice = 0; + if (menu_sel < 0) + menu_sel = SETTINGSMENU_ENTRIES - 1; + } + else if (vault_state == VAULT_SERVICE_LIST) { + struct vault_service svc; + int next = service_list_selected + 1; + while (1) { + flash_read(SVC_FLASH_OFFSET + next * SVC_SIZE, &svc, SVC_SIZE); + if (svc.flags == SVC_FLAG_UNUSED) + return; /* Keep old value */ + else if (svc.flags == SVC_FLAG_ERASED) { + next++; + } else { + service_list_selected = next; + break; + } + } + } +} + +void ui_init(i2c_inst_t *i2c) +{ + int i; + display_init(i2c); + display_clear(); +#ifdef SHOW_MOTD + display_scroll(0x3f); + display_text(0, welcome_message0); + display_text(1, welcome_message1); + display_text(2, welcome_message2); + for (i = 0x3f; i >= 0x20; i--) { + display_scroll(i); + sleep_us(50000); + } + for (i = display_getcontrast(); i >= 0; i--) { + display_setcontrast(i); + sleep_us(10000); + } + display_scroll(0); + display_clear(); +#endif + display_setcontrast(0xcf); + current_char_pos = 0; + sleep_us(50000); + display_scroll(0x20); + + + if (cryptoengine_check_vault() < 0) + fsm_set(VAULT_TOFU); + else + fsm_set(VAULT_BOOTUP); +} + +void ui_event(uint32_t ev) +{ +} diff --git a/src/ui.h b/src/ui.h new file mode 100644 index 0000000..220fc1d --- /dev/null +++ b/src/ui.h @@ -0,0 +1,47 @@ +/* Motenpoche + * + * (c) 2023 Daniele Lacamera + * + * + * Motenpoche 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 2 of the License, or + * (at your option) any later version. + * + * Motenpoche 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + */ +#ifndef UI_H_INCLUDED +#define UI_H_INCLUDED +#include "hardware/i2c.h" +#include "fsm.h" + +#define UI_EV_SCROLL_UP (1 << 0) +#define UI_EV_SCROLL_DN (1 << 1) +#define UI_EV_KEY_PRESS (1 << 2) +#define UI_EV_BUTTON_OK (1 << 3) +#define UI_EV_BUTTON_BACK (1 << 4) + + +void ui_init(i2c_inst_t *i2c); +void ui_task(void); +void ui_event_cb(enum vault_state old_st, enum vault_state st); +void ui_event(uint32_t ev); +void ui_key_button(void); + +void ui_back_button(void); + +void ui_confirm_button(void); +void ui_rot_up(void); + +void ui_rot_down(void); + + +#endif diff --git a/src/usb_descriptors.c b/src/usb_descriptors.c new file mode 100644 index 0000000..19b2e64 --- /dev/null +++ b/src/usb_descriptors.c @@ -0,0 +1,221 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "tusb.h" +#include "usb_descriptors.h" +#include "class/cdc/cdc.h" +#include "class/cdc/cdc_device.h" +#include "class/msc/msc.h" + +/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug. + * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. + * + * Auto ProductID layout's Bitmap: + * [MSB] HID | MSC | CDC [LSB] + */ +#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) ) +#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ + _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) ) + +#define USB_VID 0xCafe +#define USB_BCD 0x0200 + +//--------------------------------------------------------------------+ +// Device Descriptors +//--------------------------------------------------------------------+ +tusb_desc_device_t const desc_device = +{ + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = USB_BCD, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + + // Use Interface Association Descriptor (IAD) for CDC + // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + + .idVendor = USB_VID, + .idProduct = USB_PID, + .bcdDevice = 0x0100, + + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + + .bNumConfigurations = 0x01 +}; + +// Invoked when received GET DEVICE DESCRIPTOR +// Application return pointer to descriptor +uint8_t const * tud_descriptor_device_cb(void) +{ + return (uint8_t const *) &desc_device; +} + +//--------------------------------------------------------------------+ +// HID Report Descriptor +//--------------------------------------------------------------------+ + +uint8_t const desc_hid_report[] = +{ + TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(REPORT_ID_KEYBOARD)), +// TUD_HID_REPORT_DESC_KEYBOARD(), +}; + +// Invoked when received GET HID REPORT DESCRIPTOR +// Application return pointer to descriptor +// Descriptor contents must exist long enough for transfer to complete +uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance) +{ + (void) instance; + return desc_hid_report; +} + +//--------------------------------------------------------------------+ +// Configuration Descriptor +//--------------------------------------------------------------------+ + +enum +{ + ITF_NUM_HID = 0, + ITF_NUM_CDC, + ITF_NUM_CDC_DATA, + ITF_NUM_MSC, + ITF_NUM_TOTAL +}; + + +#define EPNUM_HID 0x84 +#define EPNUM_CDC_NOTIF 0x81 +#define EPNUM_CDC_OUT 0x02 +#define EPNUM_CDC_IN 0x82 +#define EPNUM_MSC_OUT 0x03 +#define EPNUM_MSC_IN 0x83 + +#if 1 +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN + TUD_HID_DESC_LEN) +#else +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN + TUD_CDC_DESC_LEN) +#endif + + +// full speed configuration +uint8_t const desc_fs_configuration[] = +{ + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), + //TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + + // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval + TUD_HID_DESCRIPTOR(ITF_NUM_HID, 6, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10), + + // Interface number, string index, EP notification address and size, EP data address (out, in) and size. + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64), + + // Interface number, string index, EP Out & EP In address, EP size + TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64), + + + +}; + + +// Invoked when received GET CONFIGURATION DESCRIPTOR +// Application return pointer to descriptor +// Descriptor contents must exist long enough for transfer to complete +uint8_t const * tud_descriptor_configuration_cb(uint8_t index) +{ + (void) index; // for multiple configurations + +#if TUD_OPT_HIGH_SPEED + // Although we are highspeed, host may be fullspeed. + return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration; +#else + return desc_fs_configuration; +#endif +} + +//--------------------------------------------------------------------+ +// String Descriptors +//--------------------------------------------------------------------+ + +// array of pointer to string descriptors +char const* string_desc_arr [] = +{ + (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) + "Danielinux", // 1: Manufacturer + "Password Vault", // 2: Product + "052023", // 3: Serials, should use chip ID + "Command CDC", // 4: CDC Interface + "Virtual MSC", // 5: MSC Interface + "Virtual Keyboard" // 6: HID (Keyboard) +}; + +static uint16_t _desc_str[32]; + +// Invoked when received GET STRING DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) +{ + (void) langid; + + uint8_t chr_count; + + if ( index == 0) + { + memcpy(&_desc_str[1], string_desc_arr[0], 2); + chr_count = 1; + }else + { + // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. + // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors + + if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL; + + const char* str = string_desc_arr[index]; + + // Cap at max char + chr_count = strlen(str); + if ( chr_count > 31 ) chr_count = 31; + + // Convert ASCII string into UTF-16 + for(uint8_t i=0; i + * + * + * Motenpoche 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 2 of the License, or + * (at your option) any later version. + * + * Motenpoche 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * + */ + +/* user_settings.h for wolfcrypt */ + +#ifndef H_USER_SETTINGS_ +#define H_USER_SETTINGS_ + +/* System */ +#define WOLFSSL_GENERAL_ALIGNMENT 4 +#define SINGLE_THREADED +//#define WOLFSSL_SMALL_STACK +#define WOLFCRYPT_ONLY +#define TFM_TIMING_RESISTANT +#define HAVE_CHACHA +#define WOLFSSL_CHACHA +#define HAVE_SHA256 +#define WOLFSSL_SHA512 +#define HAVE_PBKDF2 +#define HAVE_AES +#define HAVE_AES_CBC +#define HAVE_AES_DECRYPT + + +#define HAVE_ECC +# define ECC_TIMING_RESISTANT +# define ECC_USER_CURVES /* enables only 256-bit by default */ +/* ECC options disabled to reduce size */ +# define NO_ECC_SIGN +# define NO_ECC_EXPORT +# define NO_ECC_DHE +# define NO_ECC_KEY_EXPORT +# define HAVE_ECC256 +# define FP_MAX_BITS (256 + 32) +# define SP_WORD_SIZE 32 +# ifndef ULLONG_MAX +# define ULLONG_MAX 18446744073709551615ULL +# endif +# define WOLFSSL_SP +# define WOLFSSL_SP_MATH +# define WOLFSSL_HAVE_SP_ECC + +#define CUSTOM_RAND_GENERATE random_uint32 +#define CUSTOM_RAND_TYPE uint32_t + +#define ED25519_SMALL +#define WOLFSSL_CURVE25519 + +#define NO_INLINE + + +#define WOLFSSL_SP +#define WOLFSSL_SP_SMALL +#define WOLFSSL_SP_MATH +//#define WOLFSSL_SP_ARM_ARCH 4 +//#define WOLFSSL_SP_ARM_THUMB_ASM +#define SP_WORD_SIZE 32 +#define SINGLE_THREADED + +/* Disables - For minimum wolfCrypt build */ +#define NO_CMAC +#define NO_CODING +#define NO_RSA +#define NO_BIG_INT +#define NO_ASN +#define NO_RC4 +#define NO_SHA +#define NO_DH +#define NO_DSA +#define NO_MD4 +#define NO_RABBIT +#define NO_MD5 +#define NO_SIG_WRAPPER +#define NO_CERT +#define NO_SESSION_CACHE +#define NO_HC128 +#define NO_DES3 +#define NO_WRITEV +#define NO_DEV_RANDOM +#define NO_FILESYSTEM +#define NO_MAIN_DRIVER +#define NO_OLD_RNGNAME +#define NO_WOLFSSL_DIR +#define WOLFSSL_NO_SOCK + + +#define WOLFSSL_SP_NO_MALLOC +#define WOLFSSL_SP_NO_DYN_STACK + +#endif /* !H_USER_SETTINGS_ */