diff --git a/Cargo.lock b/Cargo.lock index 715fde2..e6a1b2c 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", + "inout", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -67,6 +77,12 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + [[package]] name = "bitflags" version = "1.3.2" @@ -79,6 +95,15 @@ version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +[[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 = "bluer" version = "0.17.4" @@ -132,6 +157,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[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" @@ -147,6 +178,40 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[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", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + [[package]] name = "custom_debug" version = "0.6.2" @@ -268,6 +333,26 @@ dependencies = [ "thiserror", ] +[[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.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "displaydoc" version = "0.2.6" @@ -279,6 +364,18 @@ dependencies = [ "syn", ] +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "env_filter" version = "2.0.0" @@ -434,6 +531,7 @@ dependencies = [ "cfg-if", "libc", "r-efi", + "rand_core", ] [[package]] @@ -448,12 +546,32 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "inout" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" +dependencies = [ + "hybrid-array", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -519,6 +637,26 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "keccak" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aa" +dependencies = [ + "cfg-if", + "cpufeatures", +] + +[[package]] +name = "kem" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01737161ba802849cfd486b5bd209d38ba4943494c249a8126005170c7621edd" +dependencies = [ + "crypto-common", + "rand_core", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -569,6 +707,33 @@ dependencies = [ "windows-sys 0.61.2", ] +[[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", + "sha3", + "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 = "nix" version = "0.29.0" @@ -645,6 +810,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +[[package]] +name = "pkcs8" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.33" @@ -674,6 +849,8 @@ checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" dependencies = [ "cobs", "defmt", + "embedded-io 0.4.0", + "embedded-io 0.6.1", "serde", ] @@ -701,6 +878,12 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "regex" version = "1.12.4" @@ -779,6 +962,16 @@ dependencies = [ "zmij", ] +[[package]] +name = "sha3" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be176f1a57ce4e3d31c1a166222d9768de5954f811601fb7ca06fc8203905ce1" +dependencies = [ + "digest", + "keccak", +] + [[package]] name = "signal-hook-registry" version = "1.4.8" @@ -805,6 +998,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "spki" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "strsim" version = "0.11.1" @@ -913,6 +1116,12 @@ dependencies = [ "tokio", ] +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + [[package]] name = "unicode-ident" version = "1.0.24" @@ -995,10 +1204,12 @@ dependencies = [ "bluer", "env_logger", "futures-lite", + "getrandom", "jiff", "log", "tokio", "water-pod-common", + "wharrgarbl", "winnow", ] @@ -1006,10 +1217,52 @@ dependencies = [ name = "water-pod-common" version = "0.1.0" dependencies = [ + "aead", "defmt", "jiff", "postcard", + "rand_core", "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", + "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", + "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]] @@ -1109,6 +1362,32 @@ dependencies = [ "memchr", ] +[[package]] +name = "zerocopy" +version = "0.8.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" + [[package]] name = "zmij" version = "1.0.21" diff --git a/Cargo.toml b/Cargo.toml index 230d03d..77aef80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,8 @@ edition.workspace = true [dependencies] water-pod-common = { path = "./water-pod-common" } tokio = { version = "1", features = ["io-std", "io-util", "net", "rt", "macros", "signal", "sync"] } +wharrgarbl = { git = "https://tangled.org/sachy.dev/wharrgarbl", package = "wharrgarbl" } +getrandom = { version = "0.4.2", features = ["sys_rng"] } env_logger = "0.11" log = "0.4" bluer = { version = "0.17.4", features = ["full"] } diff --git a/src/main.rs b/src/main.rs index 0f4233c..7d8deb1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,10 @@ use std::time::Duration; use bluer::l2cap::{SocketAddr, Stream}; +use getrandom::{SysRng, rand_core::UnwrapErr}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use water_pod_common::{Request, Response}; +use wharrgarbl::handshake::ServerHandshake; mod scan; @@ -31,21 +33,35 @@ async fn main() -> Result<(), std::io::Error> { let target_sa = SocketAddr::new(device.address(), addr_type, SPSM_L2CAP_WATER); let mut stream = Stream::connect(target_sa).await?; - let mut buf = vec![0; 251]; + let server = ServerHandshake::new(None); + + let mut buf = vec![0; 2510]; + + let mut wrapped_rng = UnwrapErr(SysRng); - log::info!("LISTENING FROM: {}", device.address()); if let Ok(read) = stream.read(&mut buf).await - && let Ok(Request::TimeSync(mut sync)) = Request::from_bytes(&buf[..read]) + && let Ok(aead) = + Response::respond_to_pairing(server, &mut wrapped_rng, &mut buf[..read].into()) { - sync.set_t1(); - tokio::time::sleep(Duration::from_millis(1)).await; - sync.set_t2(); - let resp = Response::TimeSync(sync); - let resp = resp.to_bytes(&mut buf).unwrap(); + let (mut send, mut recv) = aead.split(); + + log::info!("LISTENING FROM: {}", device.address()); + if let Ok(read) = stream.read(&mut buf).await + && let Ok(Request::TimeSync(mut sync)) = + Request::from_bytes(buf[..read].into(), &mut recv) + { + sync.set_t1(); + tokio::time::sleep(Duration::from_millis(1)).await; + sync.set_t2(); + let resp = Response::TimeSync(sync); + let resp = resp.to_bytes(&mut send).unwrap(); + + stream.write(&resp).await.ok(); - stream.write(resp).await.ok(); + log::info!("SUCCESSFUL SYNC with {}", device.address()); - log::info!("SUCCESSFUL SYNC with {}", device.address()); + adapter.remove_device(device.address()).await.ok(); + } } } Ok(()) diff --git a/water-pod-common/Cargo.toml b/water-pod-common/Cargo.toml index 353976a..c1f8160 100644 --- a/water-pod-common/Cargo.toml +++ b/water-pod-common/Cargo.toml @@ -5,10 +5,13 @@ version.workspace = true edition.workspace = true [dependencies] +aead = { version = "0.6.0", features = ["alloc"] } serde = { version = "1", default-features = false } jiff = { version = "0.2.32", default-features = false } -postcard = { version = "1", default-features = false } +postcard = { version = "1", default-features = false, features = ["alloc"] } defmt = { version = "1.0", optional = true } +wharrgarbl = { git = "https://tangled.org/sachy.dev/wharrgarbl", package = "wharrgarbl" } +rand_core = { version = "0.10", default-features = false } [features] default = ["server"] diff --git a/water-pod-common/src/lib.rs b/water-pod-common/src/lib.rs index 970bdfe..442301a 100644 --- a/water-pod-common/src/lib.rs +++ b/water-pod-common/src/lib.rs @@ -1,6 +1,14 @@ #![no_std] +extern crate alloc; + +use alloc::vec::Vec; use jiff::{SignedDuration, Timestamp}; +use rand_core::CryptoRng; +use wharrgarbl::{ + Neko128, NekoClientHandshake128, NekoServerHandshake128, + transport::{AeadTransport, RecvState, SendState}, +}; #[derive(Debug, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -14,25 +22,65 @@ pub enum Request { pub enum Response { TimeSync(TimeSyncMs), FetchCommands(Command), + Error, } impl Request { - pub fn to_bytes<'a>(self, buf: &'a mut [u8]) -> Result<&'a mut [u8], postcard::Error> { - postcard::to_slice(&self, buf) + pub fn request_pairing( + client: &mut NekoClientHandshake128, + rng: &mut impl CryptoRng, + buf: &mut Vec, + ) -> aead::Result<()> { + client.send(rng, buf) + } + + pub fn finish_pairing( + mut client: NekoClientHandshake128, + ciphertext: &[u8], + ) -> aead::Result> { + client.receive(ciphertext) } - pub fn from_bytes(buf: &[u8]) -> Result { - postcard::from_bytes(buf) + pub fn to_bytes<'b>(self, send: &mut SendState<'b, Neko128>) -> aead::Result> { + let mut payload = postcard::to_allocvec(&self).map_err(|_| aead::Error)?; + + send.encrypt(&mut payload, b"water-pod")?; + + Ok(payload) + } + + pub fn from_bytes<'a>( + mut buf: Vec, + recv: &mut RecvState<'a, Neko128>, + ) -> aead::Result { + recv.decrypt(&mut buf, b"water-pod")?; + postcard::from_bytes(&buf).map_err(|_| aead::Error) } } impl Response { - pub fn to_bytes<'a>(self, buf: &'a mut [u8]) -> Result<&'a mut [u8], postcard::Error> { - postcard::to_slice(&self, buf) + pub fn respond_to_pairing( + mut server: NekoServerHandshake128, + rng: &mut impl CryptoRng, + buf: &mut Vec, + ) -> aead::Result> { + server.respond(rng, buf) + } + + pub fn to_bytes<'b>(self, send: &mut SendState<'b, Neko128>) -> aead::Result> { + let mut payload = postcard::to_allocvec(&self).map_err(|_| aead::Error)?; + + send.encrypt(&mut payload, b"water-pod")?; + + Ok(payload) } - pub fn from_bytes(buf: &[u8]) -> Result { - postcard::from_bytes(buf) + pub fn from_bytes<'a>( + mut buf: Vec, + recv: &mut RecvState<'a, Neko128>, + ) -> aead::Result { + recv.decrypt(&mut buf, b"water-pod")?; + postcard::from_bytes(&buf).map_err(|_| aead::Error) } }