diff --git a/.gitmodules b/.gitmodules index b6e5733..de2f8b2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "firmware2/libxkbcommon"] path = firmware2/libxkbcommon url = https://github.com/xkbcommon/libxkbcommon +[submodule "firmware2/spectre-api-c"] + path = firmware2/spectre-api-c + url = https://github.com/Limeth/spectre-api.git diff --git a/firmware2/.cargo/config.toml b/firmware2/.cargo/config.toml index 08e05bf..e078e91 100644 --- a/firmware2/.cargo/config.toml +++ b/firmware2/.cargo/config.toml @@ -13,18 +13,26 @@ rustflags = [ [env] LIBXKBCOMMON_BUILD_DIR = "libxkbcommon/build" +SPECTRE_API_BUILD_DIR = "spectre-api/build" +SPECTRE_API_SYS_CC = "xtensa-esp32s3-elf-cc.exe" ESP_LOG = "warn" # This is overkill, but we can afford it. SLINT_FONT_SIZES = "8,11,10,12,13,14,15,16,18,20,22,24,32" # Xtensa only: # Needed for nightly, until llvm upstream has support for Rust Xtensa. -[unstable] -build-std = ["alloc", "core"] +# TODO: RE-ENABLE WHEN acid-firmware IS MOVED TO ITS OWN SUBDIRECTORY. +# For now, `-Zbuild-std="core,alloc"` can be used instead. +# [unstable] +# build-std = ["alloc", "core"] + +[patch."https://github.com/Limeth/spectre-api-sys"] +spectre-api-sys = { path = "../../../rust/spectre-api-sys" } [patch.crates-io] rmk = { path = "../../../rust/rmk/rmk" } xkbcommon = { path = "../../../rust/xkbcommon-rs-ffi" } +scrypt = { path = "../../../rust/password-hashes/scrypt" } # [patch.crates-io] # esp-backtrace = { path = "../../../rust/esp-hal/esp-backtrace" } diff --git a/firmware2/Cargo.lock b/firmware2/Cargo.lock index f6882ef..6035a8a 100644 --- a/firmware2/Cargo.lock +++ b/firmware2/Cargo.lock @@ -38,13 +38,16 @@ dependencies = [ "log", "mutually_exclusive_features", "panic-rtt-target", + "password-hash 0.1.0", "paste", "printf-compat", "rand_core 0.6.4", "rmk", "rtt-target", + "sha2", "slint", "slint-build", + "spectre-api-sys", "static_cell", "xkbcommon 0.9.0 (git+https://github.com/Limeth/xkbcommon-rs?branch=esp32s3)", "xz2", @@ -186,6 +189,18 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash 0.5.0", +] + [[package]] name = "arraydeque" version = "0.5.1" @@ -447,6 +462,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + [[package]] name = "bincode" version = "2.0.1" @@ -550,6 +571,15 @@ dependencies = [ "core2", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -1482,6 +1512,18 @@ dependencies = [ "linux-raw-sys 0.6.5", ] +[[package]] +name = "duct" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e66e9c0c03d094e1a0ba1be130b849034aa80c3a2ab8ee94316bc809f3fa684" +dependencies = [ + "libc", + "os_pipe", + "shared_child", + "shared_thread", +] + [[package]] name = "dunce" version = "1.0.5" @@ -5245,6 +5287,16 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "os_pipe" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "p256" version = "0.13.2" @@ -5309,6 +5361,27 @@ dependencies = [ "swash", ] +[[package]] +name = "password-hash" +version = "0.1.0" +dependencies = [ + "argon2", + "itertools 0.14.0", + "scrypt", + "spectre-api-sys", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "paste" version = "1.0.15" @@ -5327,6 +5400,16 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -6178,7 +6261,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -6224,6 +6307,15 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + [[package]] name = "same-file" version = "1.0.6" @@ -6245,6 +6337,17 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scrypt" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" +dependencies = [ + "pbkdf2", + "salsa20", + "sha2", +] + [[package]] name = "sec1" version = "0.7.3" @@ -6425,6 +6528,23 @@ dependencies = [ "digest", ] +[[package]] +name = "shared_child" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e362d9935bc50f019969e2f9ecd66786612daae13e8f277be7bfb66e8bed3f7" +dependencies = [ + "libc", + "sigchld", + "windows-sys 0.60.2", +] + +[[package]] +name = "shared_thread" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52b86057fcb5423f5018e331ac04623e32d6b5ce85e33300f92c79a1973928b0" + [[package]] name = "shell-words" version = "1.1.1" @@ -6437,6 +6557,27 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "sigchld" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47106eded3c154e70176fc83df9737335c94ce22f821c32d17ed1db1f83badb1" +dependencies = [ + "libc", + "os_pipe", + "signal-hook", +] + +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + [[package]] name = "signal-hook-registry" version = "1.4.8" @@ -6635,6 +6776,14 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0f368519fc6c85fc1afdb769fb5a51123f6158013e143656e25a3485a0d401c" +[[package]] +name = "spectre-api-sys" +version = "0.1.0" +dependencies = [ + "bindgen", + "duct", +] + [[package]] name = "spin" version = "0.9.8" @@ -7807,15 +7956,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.60.2" @@ -8553,3 +8693,7 @@ dependencies = [ "syn 2.0.114", "winnow", ] + +[[patch.unused]] +name = "scrypt" +version = "0.12.0-rc.8" diff --git a/firmware2/Cargo.toml b/firmware2/Cargo.toml index 7a67c50..79196d0 100644 --- a/firmware2/Cargo.toml +++ b/firmware2/Cargo.toml @@ -1,3 +1,7 @@ +[workspace] +resolver = "3" +members = ["password-hash"] + [package] name = "acid-firmware" version = "0.1.0" @@ -71,6 +75,9 @@ rtt-target = { version = "0.6.2", features = ["log"], optional = true } panic-rtt-target = { version = "0.2.0", optional = true } enumset = "1.1.10" printf-compat = { version = "0.2.1", default-features = false } +spectre-api-sys = { git = "https://github.com/Limeth/spectre-api-sys" } +sha2 = { version = "0.10.9", default-features = false } +password-hash = { path = "password-hash" } # Crates for serial UART CLI embedded-cli = { version = "0.2.1", default-features = false, features = ["help", "macros"] } diff --git a/firmware2/build.rs b/firmware2/build.rs index 343eb29..792136d 100644 --- a/firmware2/build.rs +++ b/firmware2/build.rs @@ -55,6 +55,10 @@ fn main() { println!("cargo:rustc-link-lib=static=xkbcommon"); println!("cargo:rerun-if-changed={libxkbcommon_build_dir}/libxkbcommon.a"); + println!("cargo:rustc-link-search=native=../../../c/spectre-cli-linux/api/build"); + println!("cargo:rustc-link-lib=static=spectre"); + println!("cargo:rerun-if-changed=../../../c/spectre-cli-linux/api/build/libspectre.a"); + // Slint config and compilation { // Don't think this does anything: diff --git a/firmware2/libsodium-compile.sh b/firmware2/libsodium-compile.sh new file mode 100644 index 0000000..a08e176 --- /dev/null +++ b/firmware2/libsodium-compile.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +env CC=xtensa-esp32s3-elf-gcc CFLAGS="-ffreestanding -fno-builtin -mlongcalls" LDFLAGS="-nostdlib -static" ./configure --host xtensa-esp32s3 --disable-shared --enable-static --prefix="$PWD/install" diff --git a/firmware2/libxkbcommon-compile.sh b/firmware2/libxkbcommon-compile.sh index 2637d55..d8a87d3 100644 --- a/firmware2/libxkbcommon-compile.sh +++ b/firmware2/libxkbcommon-compile.sh @@ -24,7 +24,7 @@ pushd "$LIBXKBCOMMON_DIR" >/dev/null -Dx-locale-root=/usr/share/X11/locale \ $SETUP_ARGS meson compile -C "$BUILD_DIR_NAME" - $SCRIPT_DIR/libxkbcommon-redefine-syms.sh "$STATIC_LIB_PATH" "$STATIC_LIB_PATH" + $SCRIPT_DIR/redefine-syms.sh "__xkbc_" "$STATIC_LIB_PATH" "$STATIC_LIB_PATH" popd >/dev/null GREEN='\033[0;32m' diff --git a/firmware2/password-hash/Cargo.lock b/firmware2/password-hash/Cargo.lock new file mode 100644 index 0000000..b1770d0 --- /dev/null +++ b/firmware2/password-hash/Cargo.lock @@ -0,0 +1,603 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash 0.5.0", +] + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "duct" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e66e9c0c03d094e1a0ba1be130b849034aa80c3a2ab8ee94316bc809f3fa684" +dependencies = [ + "libc", + "os_pipe", + "shared_child", + "shared_thread", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "os_pipe" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "password-hash" +version = "0.1.0" +dependencies = [ + "argon2", + "itertools 0.14.0", + "scrypt", + "spectre-api-sys", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "scrypt" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" +dependencies = [ + "pbkdf2", + "salsa20", + "sha2", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shared_child" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e362d9935bc50f019969e2f9ecd66786612daae13e8f277be7bfb66e8bed3f7" +dependencies = [ + "libc", + "sigchld", + "windows-sys 0.60.2", +] + +[[package]] +name = "shared_thread" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52b86057fcb5423f5018e331ac04623e32d6b5ce85e33300f92c79a1973928b0" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "sigchld" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47106eded3c154e70176fc83df9737335c94ce22f821c32d17ed1db1f83badb1" +dependencies = [ + "libc", + "os_pipe", + "signal-hook", +] + +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "spectre-api-sys" +version = "0.1.0" +dependencies = [ + "bindgen", + "duct", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[patch.unused]] +name = "rmk" +version = "0.8.2" + +[[patch.unused]] +name = "scrypt" +version = "0.12.0-rc.8" + +[[patch.unused]] +name = "xkbcommon" +version = "0.9.0" diff --git a/firmware2/password-hash/Cargo.toml b/firmware2/password-hash/Cargo.toml new file mode 100644 index 0000000..d768587 --- /dev/null +++ b/firmware2/password-hash/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "password-hash" +version = "0.1.0" +edition = "2024" + +[lib] +name = "password_hash" +path = "src/lib.rs" + +[[bin]] +name = "password_hash" +path = "src/bin.rs" +required-features = ["cmd"] + +[features] +default = ["cmd"] +std = [] +cmd = ["std", "dep:scrypt", "dep:itertools", "dep:spectre-api-sys"] + +[dependencies] +argon2 = { version = "0.5.3", default-features = false, features = ["alloc"] } +itertools = { version = "0.14.0", optional = true } +scrypt = { version = "0.11.0", default-features = false, optional = true } +spectre-api-sys = { git = "https://github.com/Limeth/spectre-api-sys", optional = true } diff --git a/firmware2/password-hash/README.md b/firmware2/password-hash/README.md new file mode 100644 index 0000000..243d24a --- /dev/null +++ b/firmware2/password-hash/README.md @@ -0,0 +1,3 @@ +# Compiling + +Compile on Linux or in WSL. diff --git a/firmware2/password-hash/build.rs b/firmware2/password-hash/build.rs new file mode 100644 index 0000000..0614601 --- /dev/null +++ b/firmware2/password-hash/build.rs @@ -0,0 +1,27 @@ +use std::{env, path::PathBuf}; + +fn main() { + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + println!( + "cargo:rustc-link-search=native={}", + manifest_dir.join("../spectre-api-c/build-host").display() + ); + println!("cargo:rustc-link-lib=static=spectre"); + println!( + "cargo:rerun-if-changed={}", + manifest_dir + .join("../spectre-api-c/build-host/libspectre.a") + .display() + ); + + let libsodium_install_dir = PathBuf::from(env::var("LIBSODIUM_INSTALL_DIR").unwrap()); + println!( + "cargo:rustc-link-search=native={}", + libsodium_install_dir.join("lib").display() + ); + println!("cargo:rustc-link-lib=static=sodium"); + println!( + "cargo:rerun-if-changed={}", + libsodium_install_dir.join("lib/libsodium.a").display() + ); +} diff --git a/firmware2/password-hash/src/bin.rs b/firmware2/password-hash/src/bin.rs new file mode 100644 index 0000000..af7b6e4 --- /dev/null +++ b/firmware2/password-hash/src/bin.rs @@ -0,0 +1,56 @@ +#![feature(allocator_api)] + +use std::{ + alloc::Global, + ffi::CString, + io::{Write, stdin}, + iter::zip, + str::FromStr, +}; + +use itertools::Itertools; +use password_hash::derive_encryption_key; +use spectre_api_sys::SpectreAlgorithm; + +macro_rules! read_line { + ($lines:expr, $label:expr) => {{ + print!("{}: ", $label); + std::io::stdout().flush().unwrap(); + CString::from_str( + &$lines + .next() + .transpose() + .ok() + .flatten() + .unwrap_or_else(|| panic!("Expected {}.", $label)), + ) + .unwrap() + }}; +} + +fn main() { + let mut lines = stdin().lines(); + let username = read_line!(lines, "username"); + let secret = read_line!(lines, "secret"); + + let user_key = unsafe { + &*spectre_api_sys::spectre_user_key( + username.as_ptr(), + secret.as_ptr(), + SpectreAlgorithm::Current, + ) + }; + let encryption_key = derive_encryption_key(username.as_bytes(), secret.as_bytes(), Global); + let mut encrypted_user_key = encryption_key; + + assert_eq!(encrypted_user_key.len(), user_key.bytes.len()); + + for (dst_byte, user_byte) in zip(&mut encrypted_user_key, &user_key.bytes) { + *dst_byte ^= *user_byte; + } + + println!( + "\nEncrypted User Key:\n{:02x}", + encrypted_user_key.iter().format("") + ); +} diff --git a/firmware2/password-hash/src/blocks.rs b/firmware2/password-hash/src/blocks.rs new file mode 100644 index 0000000..52ec57f --- /dev/null +++ b/firmware2/password-hash/src/blocks.rs @@ -0,0 +1,51 @@ +use core::slice; + +use argon2::Block; + +pub(crate) struct Argon2Blocks { + p: core::ptr::NonNull, + len: usize, + alloc: A, +} + +impl Argon2Blocks { + /// Each block is 1 KiB. + /// Total size is `len` * 1 KiB + pub fn new_in(len: usize, alloc: A) -> Option { + use alloc::alloc::Layout; + + if len == 0 { + return None; + } + + let layout = Layout::array::(len).ok()?; + // SAFETY: `alloc_zeroed` is used correctly with non-zero layout + let p = alloc.allocate_zeroed(layout).ok()?.cast(); + + Some(Self { p, len, alloc }) + } +} + +impl AsMut<[Block]> for Argon2Blocks { + fn as_mut(&mut self) -> &mut [Block] { + unsafe { slice::from_raw_parts_mut(self.p.as_ptr(), self.len) } + } +} + +impl AsRef<[Block]> for Argon2Blocks { + fn as_ref(&self) -> &[Block] { + unsafe { slice::from_raw_parts(self.p.as_ptr(), self.len) } + } +} + +impl Drop for Argon2Blocks { + fn drop(&mut self) { + use alloc::alloc::Layout; + // SAFETY: layout was checked during construction + let layout = unsafe { Layout::array::(self.len).unwrap_unchecked() }; + // SAFETY: we use `dealloc` correctly with the previously allocated pointer + unsafe { + self.alloc.deallocate(self.p.cast(), layout); + } + } +} diff --git a/firmware2/password-hash/src/lib.rs b/firmware2/password-hash/src/lib.rs new file mode 100644 index 0000000..ee17948 --- /dev/null +++ b/firmware2/password-hash/src/lib.rs @@ -0,0 +1,53 @@ +//! scrypt memory requirements scale linearly with parameters `N` and `r`. +//! This makes it unsuitable for embedded environments with the parameters +//! used in Spectre. +//! Our work-around is to derive the Spectre _user key_ using scrypt on the +//! host, encrypt it with XOR using a key derived using argon2, which +//! has parameters for specifying the memory and time requirements separately. +//! This encrypted key is then stored on the keyboard, to be decrypted again. +#![cfg_attr(not(feature = "std"), no_std)] +#![feature(allocator_api)] + +extern crate alloc; + +use alloc::alloc::Allocator; +use argon2::{Algorithm, Argon2, ParamsBuilder, Version}; + +use crate::blocks::Argon2Blocks; + +pub mod blocks; + +pub type Key = [u8; 64]; + +/// KiB used by the argon2 algorithm. +/// Lower than the default, to fit in the constrained memory of embedded devices. +pub const ARGON2_M_COST: u32 = 1024; +/// Compensate the difficulty by increasing the iterations proportionally. +pub const ARGON2_T_COST: u32 = + argon2::Params::DEFAULT_T_COST * argon2::Params::DEFAULT_M_COST / ARGON2_M_COST; +pub const ARGON2_P_COST: u32 = argon2::Params::DEFAULT_P_COST; +pub const ARGON2_SALT_PREFIX: &[u8] = b"acid-firmware\0"; + +pub fn derive_encryption_key(username: &[u8], secret: &[u8], allocator: impl Allocator) -> Key { + let argon2 = Argon2::new( + Algorithm::Argon2id, + Version::default(), + ParamsBuilder::default() + .m_cost(ARGON2_M_COST) + .t_cost(ARGON2_T_COST) + .p_cost(ARGON2_P_COST) + .build() + .unwrap(), + ); + let mut blocks = Argon2Blocks::new_in(ARGON2_M_COST as usize, &allocator).unwrap(); + let mut key: Key = [0u8; _]; + // Username is prefixed to form a salt that is long enough for Argon2. + let mut salt = Vec::with_capacity_in(username.len() + ARGON2_SALT_PREFIX.len(), &allocator); + salt.extend_from_slice(ARGON2_SALT_PREFIX); + salt.extend_from_slice(username); + argon2 + .hash_password_into_with_memory(secret, &salt, &mut key, &mut blocks) + .unwrap(); + + key +} diff --git a/firmware2/libxkbcommon-redefine-syms.sh b/firmware2/redefine-syms.sh similarity index 86% rename from firmware2/libxkbcommon-redefine-syms.sh rename to firmware2/redefine-syms.sh index fd81f24..5b3ca63 100644 --- a/firmware2/libxkbcommon-redefine-syms.sh +++ b/firmware2/redefine-syms.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash -INPUT_LIB=$1 -OUTPUT_LIB=$2 -PREFIX="__xkbc_" +PREFIX=$1 +INPUT_LIB=$2 +OUTPUT_LIB=$3 -if [ "$#" -ne 2 ]; then - echo "Usage: $0 " +if [ "$#" -ne 3 ]; then + echo "Usage: $0 " exit 1 fi diff --git a/firmware2/spectre-api-c b/firmware2/spectre-api-c new file mode 160000 index 0000000..733e6d6 --- /dev/null +++ b/firmware2/spectre-api-c @@ -0,0 +1 @@ +Subproject commit 733e6d6d73bc9462d8ec9528dd96eee23846a3e3 diff --git a/firmware2/spectre-api-compile.sh b/firmware2/spectre-api-compile.sh new file mode 100644 index 0000000..0315124 --- /dev/null +++ b/firmware2/spectre-api-compile.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +meson setup build --wipe --cross-file ../../../kicad/acid/firmware2/cross-esp32s3.txt -Dlibsodium-install-dir="$LIBSODIUM_INSTALL_DIR" +meson compile -C build diff --git a/firmware2/src/crypto.rs b/firmware2/src/crypto.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/firmware2/src/crypto.rs @@ -0,0 +1 @@ + diff --git a/firmware2/src/ffi/alloc.rs b/firmware2/src/ffi/alloc.rs index 278e8ab..91f9d21 100644 --- a/firmware2/src/ffi/alloc.rs +++ b/firmware2/src/ffi/alloc.rs @@ -1,11 +1,13 @@ #![allow(unused_variables)] -use core::ffi::{c_size_t, c_void}; use core::alloc::GlobalAlloc; +use core::ffi::{c_size_t, c_void}; use enumset::EnumSet; use esp_alloc::EspHeap; +use crate::ffi::string::__xkbc_memcpy; + // Here we select the allocator to use for libxkbcommon. static XKBC_ALLOCATOR: &EspHeap = &crate::PSRAM_ALLOCATOR; @@ -16,6 +18,11 @@ pub unsafe extern "C" fn __xkbc_malloc(size: c_size_t) -> *mut c_void { unsafe { malloc_with_caps(size, EnumSet::empty()) as *mut _ } } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre_malloc(size: c_size_t) -> *mut c_void { + unsafe { __xkbc_malloc(size) } +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn __xkbc_calloc(number: c_size_t, size: c_size_t) -> *mut c_void { let total_size = number * size; @@ -32,11 +39,21 @@ pub unsafe extern "C" fn __xkbc_calloc(number: c_size_t, size: c_size_t) -> *mut } } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre_calloc(number: c_size_t, size: c_size_t) -> *mut c_void { + unsafe { __xkbc_calloc(number, size) } +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn __xkbc_realloc(ptr: *mut c_void, new_size: c_size_t) -> *mut c_void { unsafe { realloc_with_caps(ptr as *mut _, new_size, EnumSet::empty()) as *mut _ } } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre_realloc(ptr: *mut c_void, new_size: c_size_t) -> *mut c_void { + unsafe { __xkbc_realloc(ptr, new_size) } +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn __xkbc_free(ptr: *mut c_void) { if ptr.is_null() { @@ -54,6 +71,13 @@ pub unsafe extern "C" fn __xkbc_free(ptr: *mut c_void) { } } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre_free(ptr: *mut c_void) { + unsafe { + __xkbc_free(ptr); + } +} + unsafe fn malloc_with_caps(size: usize, caps: EnumSet) -> *mut u8 { let total_size = size + 4; @@ -77,10 +101,6 @@ unsafe fn realloc_with_caps( new_size: usize, caps: enumset::EnumSet, ) -> *mut u8 { - unsafe extern "C" { - fn memcpy(d: *mut u8, s: *const u8, l: usize); - } - unsafe { let p = malloc_with_caps(new_size, caps); if !p.is_null() && !ptr.is_null() { @@ -88,7 +108,7 @@ unsafe fn realloc_with_caps( (ptr as *const u32).sub(1).read_volatile() as usize, new_size, ); - memcpy(p, ptr, len); + __xkbc_memcpy(p as *mut _, ptr as *const _, len); __xkbc_free(ptr as *mut _); } p diff --git a/firmware2/src/ffi/crypto.rs b/firmware2/src/ffi/crypto.rs new file mode 100644 index 0000000..0bc809c --- /dev/null +++ b/firmware2/src/ffi/crypto.rs @@ -0,0 +1,137 @@ +use core::ffi::{c_char, c_int, c_size_t, c_uchar, c_ulonglong}; + +use sha2::{ + Digest, Sha256, + digest::{consts::U32, generic_array::GenericArray}, +}; + +// Just a way to mark non-null pointers. +// Rust's `NonNull` is for mutable pointers only. +pub type NonNullPtr

= P; + +#[unsafe(no_mangle)] +unsafe extern "C" fn __spre_crypto_hash_sha256( + data_out: NonNullPtr<*mut c_uchar>, + data_in: *const c_uchar, + data_in_len: c_ulonglong, +) -> c_int { + unsafe { + let data_out = &mut *(data_out as *mut GenericArray); + let data_in = core::slice::from_raw_parts(data_in, data_in_len as usize); + let mut digest = Sha256::new(); + digest.update(data_in); + digest.finalize_into_reset(data_out); + } + + 0 +} + +#[unsafe(no_mangle)] +#[must_use] +unsafe extern "C" fn __spre_crypto_pwhash_scryptsalsa208sha256_ll( + password: NonNullPtr<*const u8>, + password_len: c_size_t, + salt: NonNullPtr<*const u8>, + salt_len: c_size_t, + n: u64, + r: u32, + p: u32, + output: NonNullPtr<*mut u8>, + output_len: c_size_t, +) -> c_int { + unsafe { + let password: &[u8] = core::slice::from_raw_parts(password, password_len); + let salt: &[u8] = core::slice::from_raw_parts(salt, salt_len); + let output: &mut [u8] = core::slice::from_raw_parts_mut(output, output_len); + let log_n = n.ilog2() as u8; + + if n != 1 << log_n { + return -1; + } + + // TODO: Store encrypted password and decrypt it using argon2 + // let params = scrypt::Params::new(log_n, r, p).unwrap(); + // match scrypt::scrypt_in(password, salt, ¶ms, output, &PSRAM_ALLOCATOR) { + // Ok(()) => 0, + // Err(_) => -1, + // } + todo!() + } +} + +#[unsafe(no_mangle)] +unsafe extern "C" fn __spre_crypto_generichash_blake2b_salt_personal( + data_out: NonNullPtr<*mut c_uchar>, + data_out_len: c_size_t, + data_in: *const c_uchar, + data_in_len: c_ulonglong, + key: *const c_uchar, + keylen: c_size_t, + salt: *const c_uchar, + personal: *const c_uchar, +) -> c_int { + todo!() +} + +#[repr(C)] +struct crypto_hash_sha256_state { + state: [u32; 8], + count: u64, + buf: [u8; 64], +} + +struct crypto_auth_hmacsha256_state { + ictx: crypto_hash_sha256_state, + octx: crypto_hash_sha256_state, +} + +#[unsafe(no_mangle)] +unsafe extern "C" fn __spre_crypto_auth_hmacsha256_init( + state: NonNullPtr<*mut crypto_auth_hmacsha256_state>, + key: NonNullPtr<*const c_uchar>, + keylen: c_size_t, +) -> c_int { + todo!() +} + +#[unsafe(no_mangle)] +unsafe extern "C" fn __spre_crypto_auth_hmacsha256_update( + state: NonNullPtr<*mut crypto_auth_hmacsha256_state>, + data_in: *const c_uchar, + inlen: c_ulonglong, +) -> c_int { + todo!() +} + +#[unsafe(no_mangle)] +unsafe extern "C" fn __spre_crypto_auth_hmacsha256_final( + state: NonNullPtr<*mut crypto_auth_hmacsha256_state>, + out: NonNullPtr<*mut c_uchar>, +) -> c_int { + todo!() +} + +#[unsafe(no_mangle)] +unsafe extern "C" fn __spre_sodium_bin2base64( + b64: NonNullPtr<*mut c_char>, + b64_maxlen: c_size_t, + bin: *const c_uchar, + bin_len: c_size_t, + variant: c_int, +) -> *mut c_char { + todo!() +} + +#[unsafe(no_mangle)] +unsafe extern "C" fn __spre_sodium_base642bin( + bin: NonNullPtr<*mut c_uchar>, + bin_maxlen: c_size_t, + b64: *const c_char, + b64_len: c_size_t, + ignore: *const c_char, + bin_len: *mut c_size_t, + b64_end: *mut *const c_char, + variant: c_int, +) -> c_int { + todo!() +} diff --git a/firmware2/src/ffi/inout/mod.rs b/firmware2/src/ffi/inout/mod.rs index 6c39c39..98157e3 100644 --- a/firmware2/src/ffi/inout/mod.rs +++ b/firmware2/src/ffi/inout/mod.rs @@ -72,6 +72,15 @@ pub unsafe extern "C" fn __xkbc_fprintf( unsafe { __xkbc_vfprintf(stream, format, args.as_va_list()) } } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre_fprintf( + stream: *mut FILE, + format: *const c_char, + mut args: ... +) -> c_int { + unsafe { __xkbc_fprintf(stream, format) } +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn __xkbc_vfprintf( stream: *mut FILE, @@ -137,3 +146,43 @@ pub unsafe extern "C" fn __xkbc_vsnprintf( string_length as c_int } } + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre_sprintf( + string: *mut c_char, + format: *const c_char, + mut args: ... +) -> c_int { + unsafe { vsprintf(string, format, args.as_va_list()) } +} + +pub unsafe fn vsprintf(string: *mut c_char, format: *const c_char, ap: VaList) -> c_int { + let mut rust_buffer = String::new(); + unsafe { + printf_compat::format(format, ap, fmt_write(&mut rust_buffer)); + // __xkbc_strncpy would be preferrable, if it was available + __xkbc_memcpy( + string as *mut _, + rust_buffer.as_ptr() as *mut _, + rust_buffer.len(), + ); + *string.add(rust_buffer.len()) = 0; // Add terminating null byte. + rust_buffer.len() as c_int + } +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre_vsnprintf( + string: *mut c_char, + // Length in bytes **including the terminating null byte**. + size: c_size_t, + format: *const c_char, + ap: VaList, +) -> c_int { + unsafe { __xkbc_vsnprintf(string, size, format, ap) } +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre_sscanf(s: *const c_char, format: *const c_char, ...) -> c_int { + todo!() +} diff --git a/firmware2/src/ffi/mod.rs b/firmware2/src/ffi/mod.rs index c65f2ee..6062653 100644 --- a/firmware2/src/ffi/mod.rs +++ b/firmware2/src/ffi/mod.rs @@ -1,6 +1,7 @@ #![allow(unused_variables)] use core::{ + error, ffi::{c_char, c_int, c_long, c_longlong, c_size_t, c_void}, ptr::null_mut, }; @@ -8,9 +9,11 @@ use core::{ use inout::file::{FILE, STDERR, STDIN, STDOUT}; pub mod alloc; +pub mod crypto; pub mod gcc_runtime; pub mod inout; pub mod string; +pub mod time; #[allow(non_camel_case_types)] pub type c_intmax_t = c_longlong; @@ -38,6 +41,11 @@ pub unsafe extern "C" fn __xkbc___errno() -> *mut c_int { todo!() } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre___errno() -> *mut c_int { + unsafe { __xkbc___errno() } +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn __xkbc_qsort( base: *mut c_void, @@ -76,6 +84,11 @@ pub unsafe extern "C" fn __xkbc___getreent() -> *mut _reent { } } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre___getreent() -> *mut _reent { + unsafe { __xkbc___getreent() } +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn __xkbc_secure_getenv(name: *const c_char) -> *mut c_char { unsafe { __xkbc_getenv(name) } @@ -136,3 +149,12 @@ pub unsafe extern "C" fn __xkbc___assert_func( pub unsafe extern "C" fn __xkbc_atoi(s: *const c_char) -> c_int { todo!() } + +// TODO: What is this even for? +#[unsafe(no_mangle)] +pub static __spre__ctype_: [c_char; 0] = []; + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre_abort() -> ! { + panic!("`abort()` called.") +} diff --git a/firmware2/src/ffi/string.rs b/firmware2/src/ffi/string.rs index b4f0144..83d291d 100644 --- a/firmware2/src/ffi/string.rs +++ b/firmware2/src/ffi/string.rs @@ -33,6 +33,15 @@ pub unsafe extern "C" fn __xkbc_memset( dest_original } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre_memset( + dest_original: *mut c_void, + c: c_int, + n: c_size_t, +) -> *mut c_void { + unsafe { __xkbc_memset(dest_original, c, n) } +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn __xkbc_memmove( dst: *mut c_void, @@ -55,6 +64,15 @@ pub unsafe extern "C" fn __xkbc_memcpy( dst } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre_memcpy( + dst: *mut c_void, + src: *const c_void, + count: c_size_t, +) -> *mut c_void { + unsafe { __xkbc_memcpy(dst, src, count) } +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn __xkbc_memchr(s: *const c_void, c: c_int, n: c_size_t) -> *mut c_void { let mut s = s as *const c_uchar; @@ -90,6 +108,11 @@ pub unsafe extern "C" fn __xkbc_memcmp(s1: *const c_char, s2: *const c_char, n: } } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre_memcmp(s1: *const c_char, s2: *const c_char, n: c_size_t) -> c_int { + unsafe { __xkbc_memcmp(s1, s2, n) } +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn __xkbc_strpbrk(s: *const c_char, accept: *const c_char) -> *mut c_char { todo!() @@ -100,6 +123,11 @@ pub unsafe extern "C" fn __xkbc_strerror(errnum: c_int) -> *mut c_char { todo!() } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre_strerror(errnum: c_int) -> *mut c_char { + unsafe { __xkbc_strerror(errnum) } +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn __xkbc_strdup(string: *const c_char) -> *mut c_char { strndup_inner(string, unsafe { __xkbc_strlen(string) }) @@ -136,6 +164,11 @@ pub unsafe extern "C" fn __xkbc_strlen(mut s: *const c_char) -> c_size_t { result } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre_strlen(s: *const c_char) -> c_size_t { + unsafe { __xkbc_strlen(s) } +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn __xkbc_strnlen(s: *const c_char, maxlen: c_size_t) -> c_size_t { let found: *const c_char = @@ -168,6 +201,15 @@ pub unsafe extern "C" fn __xkbc_strncmp( } } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre_strncmp( + s1: *const c_char, + s2: *const c_char, + n: c_size_t, +) -> c_int { + unsafe { __xkbc_strncmp(s1, s2, n) } +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn __xkbc_strchr(cs: *const c_char, c: c_int) -> *mut c_char { todo!() @@ -198,3 +240,12 @@ pub unsafe extern "C" fn __xkbc_strtol( ) -> c_long { todo!() } + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre_strtol( + nptr: *const c_char, + endptr: *mut *mut c_char, + base: c_int, +) -> c_long { + unsafe { __xkbc_strtol(nptr, endptr, base) } +} diff --git a/firmware2/src/ffi/time.rs b/firmware2/src/ffi/time.rs new file mode 100644 index 0000000..b3c3cef --- /dev/null +++ b/firmware2/src/ffi/time.rs @@ -0,0 +1,20 @@ +use embassy_time::Instant; + +// TODO: Is this right? +pub type time_t = i64; + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __spre_time(time: *mut time_t) -> time_t { + // TODO: This currently measures the time since boot, + // but it should actually measure the time since the unix epoch. + let duration = Instant::now().duration_since(Instant::MIN); + let seconds_since_epoch = duration.as_secs() as time_t; + + if !time.is_null() { + unsafe { + *time = seconds_since_epoch; + } + } + + seconds_since_epoch +} diff --git a/firmware2/src/main.rs b/firmware2/src/main.rs index f5847ad..69e3274 100644 --- a/firmware2/src/main.rs +++ b/firmware2/src/main.rs @@ -22,6 +22,7 @@ use core::sync::atomic::{AtomicBool, Ordering}; use alloc::boxed::Box; use alloc::vec; +use argon2::{Algorithm, Argon2}; use embassy_executor::Spawner; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; @@ -40,9 +41,10 @@ use esp_hal::mcpwm::{McPwm, PeripheralClockConfig}; use esp_hal::psram::{FlashFreq, PsramConfig, PsramSize, SpiRamFreq, SpiTimingConfigCoreClock}; use esp_hal::system::Stack; use esp_hal::timer::timg::TimerGroup; +use esp_println::println; use esp_rtos::embassy::Executor; use esp_storage::FlashStorage; -use log::{error, info}; +use log::{error, info, warn}; use rmk::channel::{CONTROLLER_CHANNEL, ControllerSub}; use rmk::config::{BehaviorConfig, PositionalConfig, RmkConfig, StorageConfig, VialConfig}; use rmk::controller::{Controller, EventController}; @@ -56,9 +58,11 @@ use rmk::storage::async_flash_wrapper; use rmk::types::action::{Action, KeyAction}; use rmk::{initialize_keymap_and_storage, run_devices, run_rmk}; use slint::platform::software_renderer::Rgb565Pixel; +use spectre_api_sys::SpectreAlgorithm; use static_cell::StaticCell; use {esp_alloc as _, esp_backtrace as _}; +use crate::crypto::Argon2Blocks; use crate::keymap::create_hid_report_interceptor; use crate::logging::LOG_LEVEL_FILTER; use crate::matrix::IoeMatrix; @@ -68,6 +72,7 @@ use crate::vial::{CustomKeycodes, VIAL_KEYBOARD_DEF, VIAL_KEYBOARD_ID}; mutually_exclusive_features::none_or_one_of!["usb-log", "alt-log", "rtt-log"]; +mod crypto; mod ffi; mod keymap; mod logging; @@ -379,6 +384,21 @@ async fn main(_spawner: Spawner) { let mut user_controller = UserController::new(); + warn!("Yeet"); + + let key = password_hash::hash(&PSRAM_ALLOCATOR); + + warn!("Argon2 passed. Key = {key:02x?}"); + + unsafe { + let user_key = &*spectre_api_sys::spectre_user_key( + c"Jakub Hlusička".as_ptr(), + c"test".as_ptr(), + SpectreAlgorithm::Current, + ); + warn!("{user_key:?}"); + } + info!("Awaiting on all tasks..."); // TODO: Probably want to select! instead and re-try.