From 0ad046d1d2afd422ad69a76ba5b4169bc1bb1fcd Mon Sep 17 00:00:00 2001 From: Sachymetsu Date: Sat, 18 Jul 2026 15:16:59 +0200 Subject: [PATCH] Custom pairing --- Cargo.lock | 261 +++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 3 + src/ble.rs | 12 +-- src/client.rs | 71 ++++++++++-- src/error.rs | 8 +- src/packet_pool.rs | 18 +++- 6 files changed, 344 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 13dc994..f051004 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aead" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1973cfbc1a2daf9cf550e74e1f088c28e7f7d8c1e1418fb6c9dc5184b7e84c99" +dependencies = [ + "crypto-common 0.2.2", + "inout", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -71,6 +81,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + [[package]] name = "bit-set" version = "0.8.0" @@ -113,6 +129,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + [[package]] name = "bt-hci" version = "0.8.1" @@ -177,6 +202,12 @@ dependencies = [ "pure-rust-locales", ] +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + [[package]] name = "cobs" version = "0.3.0" @@ -202,6 +233,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "cordyceps" version = "0.3.4" @@ -253,6 +290,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc-any" version = "2.5.1" @@ -284,6 +330,25 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", + "rand_core 0.10.1", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + [[package]] name = "cyw43" version = "0.7.0" @@ -409,14 +474,34 @@ dependencies = [ "defmt 1.1.1", ] +[[package]] +name = "der" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69dedd701da44b0536442edf09c81a64b0ab97a7a4a5e3d1971f00027cbc63d" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", + "block-buffer 0.10.4", + "crypto-common 0.1.7", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "crypto-common 0.2.2", ] [[package]] @@ -682,6 +767,12 @@ dependencies = [ "nb 1.1.0", ] +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + [[package]] name = "embedded-io" version = "0.6.1" @@ -930,6 +1021,17 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "hybrid-array" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +dependencies = [ + "ctutils", + "typenum", + "zeroize", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -946,6 +1048,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "inout" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" +dependencies = [ + "hybrid-array", +] + [[package]] name = "itertools" version = "0.14.0" @@ -985,7 +1096,27 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", +] + +[[package]] +name = "keccak" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aa" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", +] + +[[package]] +name = "kem" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01737161ba802849cfd486b5bd209d38ba4943494c249a8126005170c7621edd" +dependencies = [ + "crypto-common 0.2.2", + "rand_core 0.10.1", ] [[package]] @@ -1003,7 +1134,7 @@ dependencies = [ "pico-args", "regex", "regex-syntax", - "sha3", + "sha3 0.10.9", "string_cache", "term", "unicode-xid", @@ -1081,6 +1212,33 @@ version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" +[[package]] +name = "ml-kem" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e15f3e5b957493873e396a66914e83e616b6afe335cdef7efe5c6e1216aba66" +dependencies = [ + "hybrid-array", + "kem", + "module-lattice", + "pkcs8", + "rand_core 0.10.1", + "sha3 0.11.0", + "zeroize", +] + +[[package]] +name = "module-lattice" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c61b87c9683ab7cb1c6871d261ad5479b6b10ceb52c4352aaca3b5d35a8febe" +dependencies = [ + "ctutils", + "hybrid-array", + "num-traits", + "zeroize", +] + [[package]] name = "nb" version = "0.1.3" @@ -1265,6 +1423,16 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "pkcs8" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "portable-atomic" version = "1.14.0" @@ -1291,6 +1459,8 @@ checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" dependencies = [ "cobs", "defmt 1.1.1", + "embedded-io 0.4.0", + "embedded-io 0.6.1", "serde", ] @@ -1361,6 +1531,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "redox_syscall" version = "0.5.18" @@ -1464,6 +1640,7 @@ dependencies = [ name = "sachy-water" version = "0.1.0" dependencies = [ + "aead", "cortex-m", "cortex-m-rt", "critical-section", @@ -1482,11 +1659,13 @@ dependencies = [ "panic-probe", "portable-atomic", "postcard", + "rand_core 0.10.1", "rlsf", "sachy-fmt", "static_cell", "trouble-host", "water-pod-common", + "wharrgarbl", ] [[package]] @@ -1567,8 +1746,18 @@ version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" dependencies = [ - "digest", - "keccak", + "digest 0.10.7", + "keccak 0.1.6", +] + +[[package]] +name = "sha3" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1" +dependencies = [ + "digest 0.11.3", + "keccak 0.2.0", ] [[package]] @@ -1616,6 +1805,16 @@ dependencies = [ "rgb", ] +[[package]] +name = "spki" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -1887,12 +2086,54 @@ dependencies = [ [[package]] name = "water-pod-common" version = "0.1.0" -source = "git+https://tangled.org/sachy.dev/water-pod#5e79f8573ff527cf567c883842d1384bdf3d3105" +source = "git+https://tangled.org/sachy.dev/water-pod#f528cadeb83149cce65fc820ef696126b9a69de4" dependencies = [ + "aead", "defmt 1.1.1", "jiff", "postcard", + "rand_core 0.10.1", "serde", + "wharrgarbl", +] + +[[package]] +name = "wharrgarbl" +version = "0.1.0" +source = "git+https://tangled.org/sachy.dev/wharrgarbl#375ccf6cec94d16380468f2a052634b20924c70f" +dependencies = [ + "aead", + "ctutils", + "hybrid-array", + "ml-kem", + "rand_core 0.10.1", + "wharrgarbl-neko", + "wharrgarbl-utils", + "zeroize", +] + +[[package]] +name = "wharrgarbl-neko" +version = "0.1.0" +source = "git+https://tangled.org/sachy.dev/wharrgarbl#375ccf6cec94d16380468f2a052634b20924c70f" +dependencies = [ + "aead", + "ctutils", + "hybrid-array", + "keccak 0.2.0", + "wharrgarbl-utils", + "zerocopy", + "zeroize", +] + +[[package]] +name = "wharrgarbl-utils" +version = "0.1.0" +source = "git+https://tangled.org/sachy.dev/wharrgarbl#375ccf6cec94d16380468f2a052634b20924c70f" +dependencies = [ + "aead", + "ctutils", + "zeroize", ] [[package]] @@ -1947,3 +2188,9 @@ dependencies = [ "quote", "syn 2.0.119", ] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" diff --git a/Cargo.toml b/Cargo.toml index 91baee9..8b829f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,9 @@ trouble-host = { version = "0.6.0", default-features = false, features = ["perip jiff = { version = "0.2.32", default-features = false, features = ["alloc"] } postcard = { version = "1", default-features = false } embedded-io = "0.7.1" +wharrgarbl = { git = "https://tangled.org/sachy.dev/wharrgarbl", package = "wharrgarbl" } +rand_core = { version = "0.10", default-features = false } +aead = { version = "0.6.0" } [profile.dev] debug = true diff --git a/src/ble.rs b/src/ble.rs index 9af9b78..15ac511 100644 --- a/src/ble.rs +++ b/src/ble.rs @@ -11,7 +11,7 @@ use trouble_host::{ AdStructure, Advertisement, AdvertisementParameters, BR_EDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE, }, - l2cap::{L2capChannel, L2capChannelConfig}, + l2cap::L2capChannel, prelude::ExternalController, }; @@ -97,6 +97,8 @@ async fn ble_run(spawner: Spawner, controller: BleController, mut control: Contr ..Default::default() }; + let l2cap_config = AllocPacketPool::l2cap_config(); + loop { TimerActor::wait_for_wake().await; control.gpio_set(0, true).await; @@ -118,13 +120,7 @@ async fn ble_run(spawner: Spawner, controller: BleController, mut control: Contr .with_timeout(Duration::from_secs(30)) .await { - match L2capChannel::accept( - stack, - &connection, - &[SPSM_L2CAP_WATER], - &L2capChannelConfig::default(), - ) - .await + match L2capChannel::accept(stack, &connection, &[SPSM_L2CAP_WATER], &l2cap_config).await { Ok(channel) => { let mut client = PodClient::new(channel, stack); diff --git a/src/client.rs b/src/client.rs index 0638133..2714136 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,6 +1,14 @@ +use core::convert::Infallible; + +use embassy_rp::clocks::RoscRng; +use rand_core::{TryCryptoRng, TryRng}; use sachy_fmt::{error, info}; use trouble_host::l2cap::L2capChannel; use water_pod_common::{Request, Response, TimeSyncMs}; +use wharrgarbl::{ + Neko128, NekoClientHandshake128, + transport::{AeadTransport, RecvState, SendState}, +}; use crate::{ ble::BleStack, @@ -9,6 +17,27 @@ use crate::{ timer::TimerActor, }; +struct WrappedRng; + +impl TryRng for WrappedRng { + type Error = Infallible; + + fn try_next_u32(&mut self) -> Result { + Ok(RoscRng.next_u32()) + } + + fn try_next_u64(&mut self) -> Result { + Ok(RoscRng.next_u64()) + } + + fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> { + RoscRng.fill_bytes(dst); + Ok(()) + } +} + +impl TryCryptoRng for WrappedRng {} + pub struct PodClient { channel: L2capChannel<'static, AllocPacketPool>, stack: &'static BleStack, @@ -19,19 +48,25 @@ impl PodClient { Self { channel, stack } } - async fn sync(&mut self, buf: &mut [u8]) -> PicoResult<()> { + async fn sync<'a>( + &mut self, + send: &mut SendState<'a, Neko128>, + recv: &mut RecvState<'a, Neko128>, + ) -> PicoResult<()> { let now0 = TimerActor::now().await; info!("Starting at {}", now0); let req = Request::TimeSync(TimeSyncMs::new(now0)); - let req = req.to_bytes(buf)?; + let req = req.to_bytes(send)?; - self.channel.send(self.stack, req).await?; + self.channel.send(self.stack, &req).await?; - let read = self.channel.receive(self.stack, buf).await?; + let mut payload = alloc::vec![0u8; DATA_MTU]; + let read = self.channel.receive(self.stack, &mut payload).await?; + payload.truncate(read); - if let Response::TimeSync(sync) = Response::from_bytes(&buf[..read])? { + if let Response::TimeSync(sync) = Response::from_bytes(payload, recv)? { let now3 = TimerActor::now().await; let time = sync.calc_synced_time(now3)?; @@ -44,11 +79,31 @@ impl PodClient { Ok(()) } + pub async fn pair(&mut self) -> PicoResult> { + let mut client = NekoClientHandshake128::new(None); + + let mut buf = alloc::vec::Vec::new(); + + Request::request_pairing(&mut client, &mut WrappedRng, &mut buf)?; + + self.channel.send(self.stack, &buf).await.ok(); + + let paired = self.channel.receive(self.stack, &mut buf).await?; + + let aead = Request::finish_pairing(client, &buf[..paired])?; + + Ok(aead) + } + pub async fn run(&mut self) { - let mut payload = alloc::vec![0u8; DATA_MTU]; + if let Ok(aead) = self.pair().await { + let (mut send, mut recv) = aead.split(); - if let Err(e) = self.sync(&mut payload).await { - error!("Sync Failure: {}", e); + if let Err(e) = self.sync(&mut send, &mut recv).await { + error!("Sync Failure: {}", e); + } + } else { + error!("Failed to pair with remote host"); } } } diff --git a/src/error.rs b/src/error.rs index 3a695f0..789f6dd 100644 --- a/src/error.rs +++ b/src/error.rs @@ -11,7 +11,7 @@ pub type PicoResult = Result; pub enum PicoError { ClientReqResMismatch, Time(jiff::Error), - SerDe(postcard::Error), + MessageError, Ble(BleHostError<::Error>), } @@ -21,9 +21,9 @@ impl From for PicoError { } } -impl From for PicoError { - fn from(value: postcard::Error) -> Self { - Self::SerDe(value) +impl From for PicoError { + fn from(_value: aead::Error) -> Self { + Self::MessageError } } diff --git a/src/packet_pool.rs b/src/packet_pool.rs index 4a8866e..7196d06 100644 --- a/src/packet_pool.rs +++ b/src/packet_pool.rs @@ -1,13 +1,27 @@ use alloc::boxed::Box; -use trouble_host::{Packet, PacketPool}; +use trouble_host::{ + Packet, PacketPool, + l2cap::{CreditFlowPolicy, L2capChannelConfig}, +}; -pub const MTU: usize = 251; +pub const MTU: usize = 2510; pub const DATA_MTU: usize = MTU - 6; pub struct AllocPacketPool; #[repr(transparent)] pub struct PacketBuf(Box<[u8; MTU]>); +impl AllocPacketPool { + pub fn l2cap_config() -> L2capChannelConfig { + L2capChannelConfig { + mtu: Some(DATA_MTU as u16), + mps: Some(251 - 4), + flow_policy: CreditFlowPolicy::Every(50), + initial_credits: Some(200), + } + } +} + impl PacketPool for AllocPacketPool { type Packet = PacketBuf; -- 2.51.2