From f5657847e9792564c17aaba09cde6cbdcf8e2ff4 Mon Sep 17 00:00:00 2001 From: x5113nc3x Date: Wed, 31 Jan 2024 19:39:41 +0700 Subject: [PATCH 01/11] rewrite with tokio and async --- Cargo.toml | 2 ++ examples/time.rs | 20 +++++++++++--------- src/helper_types.rs | 33 +++++++++++++++++++++++++++++---- src/lib.rs | 2 -- src/primitives/handshake.rs | 6 +++--- src/primitives/receive.rs | 32 ++++++++++++++++---------------- src/primitives/send.rs | 22 +++++++++++----------- src/tests.rs | 37 +++++++++++++++++++------------------ src/wrappers/client.rs | 23 ++++++++++++----------- 9 files changed, 103 insertions(+), 74 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a89e448..aa2c020 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ ciborium-io = "0.2.0" rand_core = "0.6.3" x25519-dalek = { version = "2.0.0-pre.1", optional = true } curve25519-dalek = { version = "4.0.0-pre.2", optional = true } +tokio = { version = "1.35", features = ["net", "io-util"]} [dev-dependencies] hex = "0.4.3" @@ -26,6 +27,7 @@ curve25519-dalek = "= 4.0.0-pre.2" rand = "0.8.5" base64 = "0.13.0" ciborium-io = { version = "0.2.0", features = ["alloc"]} +tokio = { version = "1.35", features = ["rt-multi-thread", "macros"]} [features] default = [] diff --git a/examples/time.rs b/examples/time.rs index 2296d81..0d326ea 100644 --- a/examples/time.rs +++ b/examples/time.rs @@ -1,9 +1,10 @@ use adnl::{AdnlBuilder, AdnlClient}; use std::error::Error; -use std::net::{SocketAddrV4, TcpStream}; +use std::net::SocketAddrV4; use x25519_dalek::StaticSecret; +use tokio::net::TcpStream; -pub fn connect( +pub async fn connect( ls_public: &str, ls_ip: &str, ls_port: u16, @@ -16,38 +17,39 @@ pub fn connect( // generate private key let local_secret = StaticSecret::new(rand::rngs::OsRng); - // use TcpStream as a transport for our ADNL connection - let transport = TcpStream::connect(SocketAddrV4::new(ls_ip.parse()?, ls_port))?; + // use TcpStream as transport for our ADNL connection + let transport = TcpStream::connect(SocketAddrV4::new(ls_ip.parse()?, ls_port)).await?; // build handshake using random session keys, encrypt it with ECDH(local_secret, remote_public) // then perform handshake over our TcpStream let client = AdnlBuilder::with_random_aes_params(&mut rand::rngs::OsRng) .perform_ecdh(local_secret, remote_public) - .perform_handshake(transport) + .perform_handshake(transport).await .map_err(|e| format!("{:?}", e))?; Ok(client) } -fn main() -> Result<(), Box> { +#[tokio::main] +async fn main() -> Result<(), Box> { // create AdnlClient let mut client = connect( "JhXt7H1dZTgxQTIyGiYV4f9VUARuDxFl/1kVBjLSMB8=", "65.21.74.140", 46427, - )?; + ).await?; // already serialized TL with gettime query let mut query = hex::decode("7af98bb435263e6c95d6fecb497dfd0aa5f031e7d412986b5ce720496db512052e8f2d100cdf068c7904345aad16000000000000")?; // send over ADNL, use random nonce client - .send(&mut query, &mut rand::random()) + .send(&mut query, &mut rand::random()).await .map_err(|e| format!("{:?}", e))?; // receive result into vector, use 8192 bytes buffer let mut result = Vec::::new(); client - .receive::<_, 8192>(&mut result) + .receive::<_, 8192>(&mut result).await .map_err(|e| format!("{:?}", e))?; // get time from serialized TL answer diff --git a/src/helper_types.rs b/src/helper_types.rs index bda0524..a6e9887 100644 --- a/src/helper_types.rs +++ b/src/helper_types.rs @@ -1,5 +1,9 @@ +use std::io::Error; +use std::pin::Pin; +use std::task::{Context, Poll}; use ciborium_io::{Read, Write}; use sha2::{Digest, Sha256}; +use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; pub trait CryptoRandom: rand_core::RngCore + rand_core::CryptoRng {} @@ -148,6 +152,26 @@ impl AdnlSecret { #[derive(Debug)] pub struct Empty; +impl AsyncWrite for Empty { + fn poll_write(self: Pin<&mut Self>, _cx: &mut Context<'_>, _buf: &[u8]) -> Poll> { + Poll::Ready(Ok(0)) + } + + fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } +} + +impl AsyncRead for Empty { + fn poll_read(self: Pin<&mut Self>, _cx: &mut Context<'_>, _buf: &mut ReadBuf<'_>) -> Poll> { + Poll::Ready(Ok(())) + } +} + impl Write for Empty { type Error = (); @@ -170,10 +194,11 @@ impl Read for Empty { /// Common error type #[derive(Debug)] -pub enum AdnlError { - ReadError(R::Error), - WriteError(W::Error), - ConsumeError(C::Error), +pub enum AdnlError { + ReadError(R), + WriteError(W), + ConsumeError(C), IntegrityError, TooShortPacket, + IoError(Error) } diff --git a/src/lib.rs b/src/lib.rs index 88cfd47..5b9dc1c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,3 @@ -#![cfg_attr(not(feature = "std"), no_std)] - pub use helper_types::{ AdnlAddress, AdnlAesParams, AdnlError, AdnlPrivateKey, AdnlPublicKey, AdnlSecret, Empty, }; diff --git a/src/primitives/handshake.rs b/src/primitives/handshake.rs index 56ae215..bd8f291 100644 --- a/src/primitives/handshake.rs +++ b/src/primitives/handshake.rs @@ -1,9 +1,9 @@ use crate::primitives::AdnlAes; use crate::{AdnlAddress, AdnlAesParams, AdnlClient, AdnlError, AdnlPublicKey, AdnlSecret, Empty}; use aes::cipher::KeyIvInit; -use ciborium_io::{Read, Write}; use ctr::cipher::StreamCipher; use sha2::{Digest, Sha256}; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; /// Handshake packet, must be sent from client to server prior to any datagrams pub struct AdnlHandshake { @@ -62,10 +62,10 @@ impl AdnlHandshake

{ } /// Send handshake over the given transport, build [`AdnlClient`] on top of it - pub fn perform_handshake( + pub async fn perform_handshake( &self, transport: T, ) -> Result, AdnlError> { - AdnlClient::perform_handshake(transport, self) + AdnlClient::perform_handshake(transport, self).await } } diff --git a/src/primitives/receive.rs b/src/primitives/receive.rs index 653468a..b99978b 100644 --- a/src/primitives/receive.rs +++ b/src/primitives/receive.rs @@ -1,9 +1,9 @@ use crate::primitives::AdnlAes; use crate::{AdnlAesParams, AdnlError, Empty}; use aes::cipher::KeyIvInit; -use ciborium_io::{Read, Write}; use ctr::cipher::StreamCipher; use sha2::{Digest, Sha256}; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; /// Low-level incoming datagram processor pub struct AdnlReceiver { @@ -25,7 +25,7 @@ impl AdnlReceiver { /// /// You can adjust `BUFFER` according to your memory requirements. /// Recommended size is 8192 bytes. - pub fn receive( + pub async fn receive( &mut self, transport: &mut R, consumer: &mut C, @@ -34,8 +34,8 @@ impl AdnlReceiver { let mut length = [0u8; 4]; log::debug!("reading length"); transport - .read_exact(&mut length) - .map_err(|e| AdnlError::ReadError(e))?; + .read_exact(&mut length).await + .map_err(|e| AdnlError::IoError(e))?; self.aes.apply_keystream(&mut length); let length = u32::from_le_bytes(length); log::debug!("length = {}", length); @@ -49,8 +49,8 @@ impl AdnlReceiver { let mut nonce = [0u8; 32]; log::debug!("reading nonce"); transport - .read_exact(&mut nonce) - .map_err(|e| AdnlError::ReadError(e))?; + .read_exact(&mut nonce).await + .map_err(|e| AdnlError::IoError(e))?; self.aes.apply_keystream(&mut nonce); hasher.update(nonce); @@ -65,13 +65,13 @@ impl AdnlReceiver { bytes_to_read ); transport - .read_exact(&mut buffer) - .map_err(|e| AdnlError::ReadError(e))?; + .read_exact(&mut buffer).await + .map_err(|e| AdnlError::IoError(e))?; self.aes.apply_keystream(&mut buffer); hasher.update(buffer); consumer - .write_all(&buffer) - .map_err(|e| AdnlError::ConsumeError(e))?; + .write_all(&buffer).await + .map_err(|e| AdnlError::IoError(e))?; bytes_to_read -= BUFFER; } @@ -80,21 +80,21 @@ impl AdnlReceiver { log::debug!("last chunk, {} bytes remaining", bytes_to_read); let buffer = &mut buffer[..bytes_to_read]; transport - .read_exact(buffer) - .map_err(|e| AdnlError::ReadError(e))?; + .read_exact(buffer).await + .map_err(|e| AdnlError::IoError(e))?; self.aes.apply_keystream(buffer); hasher.update(&buffer); consumer - .write_all(buffer) - .map_err(|e| AdnlError::ConsumeError(e))?; + .write_all(buffer).await + .map_err(|e| AdnlError::IoError(e))?; } } let mut given_hash = [0u8; 32]; log::debug!("reading hash"); transport - .read_exact(&mut given_hash) - .map_err(|e| AdnlError::ReadError(e))?; + .read_exact(&mut given_hash).await + .map_err(|e| AdnlError::IoError(e))?; self.aes.apply_keystream(&mut given_hash); let real_hash = hasher.finalize(); diff --git a/src/primitives/send.rs b/src/primitives/send.rs index 25d6f9e..ad0054d 100644 --- a/src/primitives/send.rs +++ b/src/primitives/send.rs @@ -1,7 +1,7 @@ use aes::cipher::KeyIvInit; -use ciborium_io::Write; use ctr::cipher::StreamCipher; use sha2::{Digest, Sha256}; +use tokio::io::AsyncWriteExt; use crate::primitives::AdnlAes; use crate::{AdnlAesParams, AdnlError, Empty}; @@ -26,7 +26,7 @@ impl AdnlSender { /// Send `buffer` over `transport` with `nonce`. Note that `nonce` must be random /// in order to prevent bit-flipping attacks when an attacker knows whole plaintext in datagram. - pub fn send( + pub async fn send( &mut self, transport: &mut W, nonce: &mut [u8; 32], @@ -49,18 +49,18 @@ impl AdnlSender { // write to transport transport - .write_all(&length) - .map_err(|e| AdnlError::WriteError(e))?; + .write_all(&length).await + .map_err(|e| AdnlError::IoError(e))?; transport - .write_all(nonce) - .map_err(|e| AdnlError::WriteError(e))?; + .write_all(nonce).await + .map_err(|e| AdnlError::IoError(e))?; transport - .write_all(buffer) - .map_err(|e| AdnlError::WriteError(e))?; + .write_all(buffer).await + .map_err(|e| AdnlError::IoError(e))?; transport - .write_all(&hash) - .map_err(|e| AdnlError::WriteError(e))?; - transport.flush().map_err(|e| AdnlError::WriteError(e))?; + .write_all(&hash).await + .map_err(|e| AdnlError::IoError(e))?; + transport.flush().await.map_err(|e| AdnlError::IoError(e))?; Ok(()) } diff --git a/src/tests.rs b/src/tests.rs index d55ed7a..a8500d7 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -62,34 +62,34 @@ fn test_handshake( ); } -#[test] -fn test_send_1() { +#[tokio::test] +async fn test_send_1() { let aes_params = hex::decode("b3d529e34b839a521518447b68343aebaae9314ac95aaacfdb687a2163d1a98638db306b63409ef7bc906b4c9dc115488cf90dfa964f520542c69e1a4a495edf9ae9ee72023203c8b266d552f251e8d724929733428c8e276ab3bd6291367336a6ab8dc3d36243419bd0b742f76691a5dec14edbd50f7c1b58ec961ae45be58cbf6623f3ec9705bd5d227761ec79cee377e2566ff668f863552bddfd6ff3a16b").unwrap(); let nonce = hex::decode("9a5ecd5d9afdfff2823e7520fa1c338f2baf1a21f51e6fdab0491d45a50066f7").unwrap(); let buffer = hex::decode("7af98bb471ff48e9b263959b17a04faae4a23501380d2aa932b09eac6f9846fcbae9bbcb0cdf068c7904345aad16000000000000").unwrap(); let expected_packet = hex::decode("250d70d08526791bc2b6278ded7bf2b051afb441b309dda06f76e4419d7c31d4d5baafc4ff71e0ebabe246d4ea19e3e579bd15739c8fc916feaf46ea7a6bc562ed1cf87c9bf4220eb037b9a0b58f663f0474b8a8b18fa24db515e41e4b02e509d8ef261a27ba894cbbecc92e59fc44bf5ff7c8281cb5e900").unwrap(); - test_send(aes_params, nonce, buffer, expected_packet); + test_send(aes_params, nonce, buffer, expected_packet).await; } -#[test] -fn test_send_2() { +#[tokio::test] +async fn test_send_2() { let aes_params = hex::decode("7e3c66de7c64d4bee4368e69560101991db4b084430a336cffe676c9ac0a795d8c98367309422a8e927e62ed657ba3eaeeb6acd3bbe5564057dfd1d60609a25a48963cbb7d14acf4fc83ec59254673bc85be22d04e80e7b83c641d37cae6e1d82a400bf159490bbc0048e69234ad89e999d792eefdaa56734202546d9188706e95e1272267206a8e7ee1f7c077f76bd26e494972e34d72e257bf20364dbf39b0").unwrap(); let nonce = hex::decode("d36d0683da23e62910fa0e8a9331dfc257db4cde0ba8d63893e88ac4de7d8d6c").unwrap(); let buffer = hex::decode("7af98bb47bcae111ea0e56457826b1aec7f0f59b9b6579678b3db3839d17b63eb60174f20cdf068c7904345aad16000000000000").unwrap(); let expected_packet = hex::decode("24c709a0f676750ddaeafc8564d84546bfc831af27fb66716de382a347a1c32adef1a27e597c8a07605a09087fff32511d314970cad3983baefff01e7ee51bb672b17f7914a6d3f229a13acb14cdc14d98beae8a1e96510756726913541f558c2ffac63ed6cb076d0e888c3c0bb014d9f229c2a3f62e0847").unwrap(); - test_send(aes_params, nonce, buffer, expected_packet); + test_send(aes_params, nonce, buffer, expected_packet).await; } -fn test_send(aes_params: Vec, nonce: Vec, buffer: Vec, expected_packet: Vec) { +async fn test_send(aes_params: Vec, nonce: Vec, buffer: Vec, expected_packet: Vec) { let mut nonce = nonce.try_into().unwrap(); let mut buffer = buffer; let aes_params: [u8; 160] = aes_params.try_into().unwrap(); let aes_params = AdnlAesParams::from(aes_params); let mut protocol_client = AdnlSender::new(&aes_params); let mut packet = Vec::::new(); - let _result = protocol_client.send(&mut packet, &mut nonce, &mut buffer); + let _result = protocol_client.send(&mut packet, &mut nonce, &mut buffer).await; assert_eq!( packet.as_slice(), &expected_packet, @@ -97,36 +97,37 @@ fn test_send(aes_params: Vec, nonce: Vec, buffer: Vec, expected_pack ); } -#[test] -fn test_recv_1() { +#[tokio::test] +async fn test_recv_1() { let encrypted_data = hex::decode("81e95e433c87c9ad2a716637b3a12644fbfb12dbd02996abc40ed2beb352483d6ecf9e2ad181a5abde4d4146ca3a8524739d3acebb2d7599cc6b81967692a62118997e16").unwrap(); let expected_data = Vec::new(); let aes_params = hex::decode("b3d529e34b839a521518447b68343aebaae9314ac95aaacfdb687a2163d1a98638db306b63409ef7bc906b4c9dc115488cf90dfa964f520542c69e1a4a495edf9ae9ee72023203c8b266d552f251e8d724929733428c8e276ab3bd6291367336a6ab8dc3d36243419bd0b742f76691a5dec14edbd50f7c1b58ec961ae45be58cbf6623f3ec9705bd5d227761ec79cee377e2566ff668f863552bddfd6ff3a16b").unwrap(); let aes_params: [u8; 160] = aes_params.try_into().unwrap(); let aes_params = AdnlAesParams::from(aes_params); let mut protocol_client = AdnlReceiver::new(&aes_params); - test_recv(&mut protocol_client, encrypted_data, expected_data); + test_recv(&mut protocol_client, encrypted_data, expected_data).await; let encrypted_data = hex::decode("4b72a32bf31894cce9ceffd2dd97176e502946524e45e62689bd8c5d31ad53603c5fd3b402771f707cd2747747fad9df52e6c23ceec9fa2ee5b0f68b61c33c7790db03d1c593798a29d716505cea75acdf0e031c25447c55c4d29d32caab29bd5a0787644843bafc04160c92140aab0ecc990927").unwrap(); let expected_data = hex::decode("1684ac0f71ff48e9b263959b17a04faae4a23501380d2aa932b09eac6f9846fcbae9bbcb080d0053e9a3ac3062000000").unwrap(); - test_recv(&mut protocol_client, encrypted_data, expected_data); + test_recv(&mut protocol_client, encrypted_data, expected_data).await; } -#[test] -fn test_recv_2() { +#[tokio::test] +async fn test_recv_2() { let encrypted_data = hex::decode("b75dcf27582beb4031d6d3700c9b7925bf84a78f2bd16b186484d36427a8824ac86e27cea81eb5bcbac447a37269845c65be51babd11c80627f81b4247f84df16d05c4f1").unwrap(); let expected_data = Vec::new(); let aes_params = hex::decode("7e3c66de7c64d4bee4368e69560101991db4b084430a336cffe676c9ac0a795d8c98367309422a8e927e62ed657ba3eaeeb6acd3bbe5564057dfd1d60609a25a48963cbb7d14acf4fc83ec59254673bc85be22d04e80e7b83c641d37cae6e1d82a400bf159490bbc0048e69234ad89e999d792eefdaa56734202546d9188706e95e1272267206a8e7ee1f7c077f76bd26e494972e34d72e257bf20364dbf39b0").unwrap(); let aes_params: [u8; 160] = aes_params.try_into().unwrap(); let aes_params = AdnlAesParams::from(aes_params); let mut protocol_client = AdnlReceiver::new(&aes_params); - test_recv(&mut protocol_client, encrypted_data, expected_data); + test_recv(&mut protocol_client, encrypted_data, expected_data).await; let encrypted_data = hex::decode("77ebea5a6e6c8758e7703d889abad16e7e3c4e0c10c4e81ca10d0d9abddabb6f008905133a070ff825ad3f4b0ae969e04dbd8b280864d3d2175f3bc7cf3deb31de5497fa43997d8e2acafb9a31de2a22ecb279b5854c00791216e39c2e65863539d82716fc020e9647b2dd99d0f14e4f553b645f").unwrap(); let expected_data = hex::decode("1684ac0f7bcae111ea0e56457826b1aec7f0f59b9b6579678b3db3839d17b63eb60174f2080d0053e90bb03062000000").unwrap(); - test_recv(&mut protocol_client, encrypted_data, expected_data); + test_recv(&mut protocol_client, encrypted_data, expected_data).await; } -fn test_recv(client: &mut AdnlReceiver, encrypted_packet: Vec, expected_data: Vec) { +async fn test_recv(client: &mut AdnlReceiver, encrypted_packet: Vec, expected_data: Vec) { let mut data = Vec::::new(); - let _r = client.receive::<_, _, 8192>(&mut encrypted_packet.as_slice(), &mut data); + let mut binding = encrypted_packet.as_slice(); + let _r = client.receive::<_, _, 8192>(&mut binding, &mut data).await; assert_eq!(data, expected_data.as_slice(), "incoming packet is wrong"); } diff --git a/src/wrappers/client.rs b/src/wrappers/client.rs index 8ab5933..a699869 100644 --- a/src/wrappers/client.rs +++ b/src/wrappers/client.rs @@ -1,23 +1,23 @@ use crate::{AdnlError, AdnlHandshake, AdnlPublicKey, AdnlReceiver, AdnlSender, Empty}; -use ciborium_io::{Read, Write}; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; /// Abstraction over [`AdnlSender`] and [`AdnlReceiver`] to keep things simple -pub struct AdnlClient { +pub struct AdnlClient { sender: AdnlSender, receiver: AdnlReceiver, transport: T, } -impl AdnlClient { +impl AdnlClient { /// Send `handshake` over `transport` and check that handshake was successful - pub fn perform_handshake( + pub async fn perform_handshake( mut transport: T, handshake: &AdnlHandshake

, ) -> Result> { // send handshake transport - .write_all(&handshake.to_bytes()) - .map_err(|e| AdnlError::WriteError(e))?; + .write_all(&handshake.to_bytes()).await + .map_err(|e| AdnlError::IoError(e))?; // receive empty message to ensure that server knows our AES keys let mut client = Self { @@ -25,32 +25,33 @@ impl AdnlClient { receiver: AdnlReceiver::new(handshake.aes_params()), transport, }; - client.receive::<_, 0>(&mut Empty).map_err(|e| match e { + client.receive::<_, 0>(&mut Empty).await.map_err(|e| match e { AdnlError::ReadError(err) => AdnlError::ReadError(err), AdnlError::WriteError(_) => unreachable!(), AdnlError::ConsumeError(err) => AdnlError::ConsumeError(err), AdnlError::IntegrityError => AdnlError::IntegrityError, AdnlError::TooShortPacket => AdnlError::TooShortPacket, + AdnlError::IoError(err) => AdnlError::IoError(err) })?; Ok(client) } /// Send `data` to another peer. Random `nonce` must be provided to eliminate bit-flipping attacks. - pub fn send( + pub async fn send( &mut self, data: &mut [u8], nonce: &mut [u8; 32], ) -> Result<(), AdnlError> { - self.sender.send(&mut self.transport, nonce, data) + self.sender.send(&mut self.transport, nonce, data).await } /// Receive data from another peer into `consumer` which will process the data. Set `BUFFER` /// according to your memory requirements, recommended size is 8192 bytes. - pub fn receive( + pub async fn receive( &mut self, consumer: &mut C, ) -> Result<(), AdnlError> { self.receiver - .receive::<_, _, BUFFER>(&mut self.transport, consumer) + .receive::<_, _, BUFFER>(&mut self.transport, consumer).await } } From 4bb648cb4a064c0371e34a78870a470e81fd7ca7 Mon Sep 17 00:00:00 2001 From: x5113nc3x Date: Wed, 7 Feb 2024 20:28:22 +0700 Subject: [PATCH 02/11] refactoring errors --- Cargo.toml | 2 ++ examples/time.rs | 26 ++++++++++++-------------- src/helper_types.rs | 19 +++++++++++++------ src/primitives/handshake.rs | 2 +- src/primitives/receive.rs | 16 ++++++++-------- src/primitives/send.rs | 12 ++++++------ src/wrappers/client.rs | 17 +++++------------ 7 files changed, 47 insertions(+), 47 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index aa2c020..8815a97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ rand_core = "0.6.3" x25519-dalek = { version = "2.0.0-pre.1", optional = true } curve25519-dalek = { version = "4.0.0-pre.2", optional = true } tokio = { version = "1.35", features = ["net", "io-util"]} +thiserror = "1" [dev-dependencies] hex = "0.4.3" @@ -28,6 +29,7 @@ rand = "0.8.5" base64 = "0.13.0" ciborium-io = { version = "0.2.0", features = ["alloc"]} tokio = { version = "1.35", features = ["rt-multi-thread", "macros"]} +anyhow = "1" [features] default = [] diff --git a/examples/time.rs b/examples/time.rs index 0d326ea..1d7edae 100644 --- a/examples/time.rs +++ b/examples/time.rs @@ -1,36 +1,36 @@ -use adnl::{AdnlBuilder, AdnlClient}; -use std::error::Error; +use adnl::{AdnlBuilder, AdnlClient, AdnlError}; use std::net::SocketAddrV4; use x25519_dalek::StaticSecret; use tokio::net::TcpStream; +use anyhow::{anyhow, Context, Result}; pub async fn connect( ls_public: &str, ls_ip: &str, ls_port: u16, -) -> Result, Box> { +) -> Result> { // decode liteserver public key - let remote_public: [u8; 32] = base64::decode(ls_public)? - .try_into() - .map_err(|_| "bad public key length")?; + let remote_public: [u8; 32] = base64::decode(ls_public) + .context("Error decode base64")? + .try_into().map_err(|_| anyhow!("Bad public key length"))?; // generate private key let local_secret = StaticSecret::new(rand::rngs::OsRng); // use TcpStream as transport for our ADNL connection - let transport = TcpStream::connect(SocketAddrV4::new(ls_ip.parse()?, ls_port)).await?; + let transport = TcpStream::connect(SocketAddrV4::new(ls_ip.parse()?, ls_port)).await + .context("Connection error")?; // build handshake using random session keys, encrypt it with ECDH(local_secret, remote_public) // then perform handshake over our TcpStream let client = AdnlBuilder::with_random_aes_params(&mut rand::rngs::OsRng) .perform_ecdh(local_secret, remote_public) - .perform_handshake(transport).await - .map_err(|e| format!("{:?}", e))?; + .perform_handshake(transport).await?; Ok(client) } #[tokio::main] -async fn main() -> Result<(), Box> { +async fn main() -> Result<()> { // create AdnlClient let mut client = connect( "JhXt7H1dZTgxQTIyGiYV4f9VUARuDxFl/1kVBjLSMB8=", @@ -43,14 +43,12 @@ async fn main() -> Result<(), Box> { // send over ADNL, use random nonce client - .send(&mut query, &mut rand::random()).await - .map_err(|e| format!("{:?}", e))?; + .send(&mut query, &mut rand::random()).await?; // receive result into vector, use 8192 bytes buffer let mut result = Vec::::new(); client - .receive::<_, 8192>(&mut result).await - .map_err(|e| format!("{:?}", e))?; + .receive::<_, 8192>(&mut result).await?; // get time from serialized TL answer println!( diff --git a/src/helper_types.rs b/src/helper_types.rs index a6e9887..b1d4e3a 100644 --- a/src/helper_types.rs +++ b/src/helper_types.rs @@ -3,6 +3,7 @@ use std::pin::Pin; use std::task::{Context, Poll}; use ciborium_io::{Read, Write}; use sha2::{Digest, Sha256}; +use thiserror::Error; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; pub trait CryptoRandom: rand_core::RngCore + rand_core::CryptoRng {} @@ -193,12 +194,18 @@ impl Read for Empty { } /// Common error type -#[derive(Debug)] -pub enum AdnlError { - ReadError(R), - WriteError(W), - ConsumeError(C), +#[derive(Debug, Error)] +pub enum AdnlError { + #[error("Read error")] + ReadError(Error), + #[error("Write error")] + WriteError(Error), + #[error("Consume error")] + ConsumeError(Error), + #[error("Integrity error")] IntegrityError, + #[error("TooShortPacket error")] TooShortPacket, - IoError(Error) + #[error(transparent)] + OtherError(#[from] Error) } diff --git a/src/primitives/handshake.rs b/src/primitives/handshake.rs index bd8f291..dcaa9cb 100644 --- a/src/primitives/handshake.rs +++ b/src/primitives/handshake.rs @@ -65,7 +65,7 @@ impl AdnlHandshake

{ pub async fn perform_handshake( &self, transport: T, - ) -> Result, AdnlError> { + ) -> Result, AdnlError> { AdnlClient::perform_handshake(transport, self).await } } diff --git a/src/primitives/receive.rs b/src/primitives/receive.rs index b99978b..3833aa7 100644 --- a/src/primitives/receive.rs +++ b/src/primitives/receive.rs @@ -29,13 +29,13 @@ impl AdnlReceiver { &mut self, transport: &mut R, consumer: &mut C, - ) -> Result<(), AdnlError> { + ) -> Result<(), AdnlError> { // read length let mut length = [0u8; 4]; log::debug!("reading length"); transport .read_exact(&mut length).await - .map_err(|e| AdnlError::IoError(e))?; + .map_err(AdnlError::ReadError)?; self.aes.apply_keystream(&mut length); let length = u32::from_le_bytes(length); log::debug!("length = {}", length); @@ -50,7 +50,7 @@ impl AdnlReceiver { log::debug!("reading nonce"); transport .read_exact(&mut nonce).await - .map_err(|e| AdnlError::IoError(e))?; + .map_err(AdnlError::ReadError)?; self.aes.apply_keystream(&mut nonce); hasher.update(nonce); @@ -66,12 +66,12 @@ impl AdnlReceiver { ); transport .read_exact(&mut buffer).await - .map_err(|e| AdnlError::IoError(e))?; + .map_err(AdnlError::ReadError)?; self.aes.apply_keystream(&mut buffer); hasher.update(buffer); consumer .write_all(&buffer).await - .map_err(|e| AdnlError::IoError(e))?; + .map_err(AdnlError::WriteError)?; bytes_to_read -= BUFFER; } @@ -81,12 +81,12 @@ impl AdnlReceiver { let buffer = &mut buffer[..bytes_to_read]; transport .read_exact(buffer).await - .map_err(|e| AdnlError::IoError(e))?; + .map_err(AdnlError::ReadError)?; self.aes.apply_keystream(buffer); hasher.update(&buffer); consumer .write_all(buffer).await - .map_err(|e| AdnlError::IoError(e))?; + .map_err(AdnlError::WriteError)?; } } @@ -94,7 +94,7 @@ impl AdnlReceiver { log::debug!("reading hash"); transport .read_exact(&mut given_hash).await - .map_err(|e| AdnlError::IoError(e))?; + .map_err(AdnlError::ReadError)?; self.aes.apply_keystream(&mut given_hash); let real_hash = hasher.finalize(); diff --git a/src/primitives/send.rs b/src/primitives/send.rs index ad0054d..91cb955 100644 --- a/src/primitives/send.rs +++ b/src/primitives/send.rs @@ -31,7 +31,7 @@ impl AdnlSender { transport: &mut W, nonce: &mut [u8; 32], buffer: &mut [u8], - ) -> Result<(), AdnlError> { + ) -> Result<(), AdnlError> { // remember not to send more than 4 GiB in a single packet let mut length = ((buffer.len() + 64) as u32).to_le_bytes(); @@ -50,17 +50,17 @@ impl AdnlSender { // write to transport transport .write_all(&length).await - .map_err(|e| AdnlError::IoError(e))?; + .map_err(AdnlError::WriteError)?; transport .write_all(nonce).await - .map_err(|e| AdnlError::IoError(e))?; + .map_err(AdnlError::WriteError)?; transport .write_all(buffer).await - .map_err(|e| AdnlError::IoError(e))?; + .map_err(AdnlError::WriteError)?; transport .write_all(&hash).await - .map_err(|e| AdnlError::IoError(e))?; - transport.flush().await.map_err(|e| AdnlError::IoError(e))?; + .map_err(AdnlError::WriteError)?; + transport.flush().await.map_err(AdnlError::WriteError)?; Ok(()) } diff --git a/src/wrappers/client.rs b/src/wrappers/client.rs index a699869..d974eb3 100644 --- a/src/wrappers/client.rs +++ b/src/wrappers/client.rs @@ -13,11 +13,11 @@ impl AdnlClient { pub async fn perform_handshake( mut transport: T, handshake: &AdnlHandshake

, - ) -> Result> { + ) -> Result { // send handshake transport .write_all(&handshake.to_bytes()).await - .map_err(|e| AdnlError::IoError(e))?; + .map_err(AdnlError::WriteError)?; // receive empty message to ensure that server knows our AES keys let mut client = Self { @@ -25,14 +25,7 @@ impl AdnlClient { receiver: AdnlReceiver::new(handshake.aes_params()), transport, }; - client.receive::<_, 0>(&mut Empty).await.map_err(|e| match e { - AdnlError::ReadError(err) => AdnlError::ReadError(err), - AdnlError::WriteError(_) => unreachable!(), - AdnlError::ConsumeError(err) => AdnlError::ConsumeError(err), - AdnlError::IntegrityError => AdnlError::IntegrityError, - AdnlError::TooShortPacket => AdnlError::TooShortPacket, - AdnlError::IoError(err) => AdnlError::IoError(err) - })?; + client.receive::<_, 0>(&mut Empty).await?; Ok(client) } @@ -41,7 +34,7 @@ impl AdnlClient { &mut self, data: &mut [u8], nonce: &mut [u8; 32], - ) -> Result<(), AdnlError> { + ) -> Result<(), AdnlError> { self.sender.send(&mut self.transport, nonce, data).await } @@ -50,7 +43,7 @@ impl AdnlClient { pub async fn receive( &mut self, consumer: &mut C, - ) -> Result<(), AdnlError> { + ) -> Result<(), AdnlError> { self.receiver .receive::<_, _, BUFFER>(&mut self.transport, consumer).await } From a2ef164e32dbe8eb6aa60fb93fa2c39c99534d5a Mon Sep 17 00:00:00 2001 From: x5113nc3x Date: Fri, 9 Feb 2024 21:23:26 +0700 Subject: [PATCH 03/11] delete features and Empty struct. --- Cargo.toml | 6 +---- examples/time.rs | 2 +- src/helper_types.rs | 48 ------------------------------------- src/lib.rs | 2 +- src/primitives/handshake.rs | 2 +- src/primitives/receive.rs | 2 +- src/primitives/send.rs | 2 +- src/wrappers/client.rs | 2 +- 8 files changed, 7 insertions(+), 59 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8815a97..d1d4fd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,6 @@ sha2 = "0.10.2" ctr = "0.9.1" aes = "0.8.1" log = "0.4.14" -ciborium-io = "0.2.0" rand_core = "0.6.3" x25519-dalek = { version = "2.0.0-pre.1", optional = true } curve25519-dalek = { version = "4.0.0-pre.2", optional = true } @@ -27,16 +26,13 @@ x25519-dalek = "= 2.0.0-pre.1" curve25519-dalek = "= 4.0.0-pre.2" rand = "0.8.5" base64 = "0.13.0" -ciborium-io = { version = "0.2.0", features = ["alloc"]} tokio = { version = "1.35", features = ["rt-multi-thread", "macros"]} anyhow = "1" [features] default = [] dalek = ["x25519-dalek", "curve25519-dalek"] -alloc = ["ciborium-io/alloc"] -std = ["ciborium-io/std"] [[example]] name = "time" -required-features = ["std", "dalek"] \ No newline at end of file +required-features = ["dalek"] \ No newline at end of file diff --git a/examples/time.rs b/examples/time.rs index 1d7edae..a3fbe7e 100644 --- a/examples/time.rs +++ b/examples/time.rs @@ -1,4 +1,4 @@ -use adnl::{AdnlBuilder, AdnlClient, AdnlError}; +use adnl::{AdnlBuilder, AdnlClient}; use std::net::SocketAddrV4; use x25519_dalek::StaticSecret; use tokio::net::TcpStream; diff --git a/src/helper_types.rs b/src/helper_types.rs index b1d4e3a..386cd45 100644 --- a/src/helper_types.rs +++ b/src/helper_types.rs @@ -1,10 +1,6 @@ use std::io::Error; -use std::pin::Pin; -use std::task::{Context, Poll}; -use ciborium_io::{Read, Write}; use sha2::{Digest, Sha256}; use thiserror::Error; -use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; pub trait CryptoRandom: rand_core::RngCore + rand_core::CryptoRng {} @@ -149,50 +145,6 @@ impl AdnlSecret { } } -/// Empty transport to use when there is nothing to read or write -#[derive(Debug)] -pub struct Empty; - -impl AsyncWrite for Empty { - fn poll_write(self: Pin<&mut Self>, _cx: &mut Context<'_>, _buf: &[u8]) -> Poll> { - Poll::Ready(Ok(0)) - } - - fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } - - fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } -} - -impl AsyncRead for Empty { - fn poll_read(self: Pin<&mut Self>, _cx: &mut Context<'_>, _buf: &mut ReadBuf<'_>) -> Poll> { - Poll::Ready(Ok(())) - } -} - -impl Write for Empty { - type Error = (); - - fn write_all(&mut self, _data: &[u8]) -> Result<(), Self::Error> { - Ok(()) - } - - fn flush(&mut self) -> Result<(), Self::Error> { - Ok(()) - } -} - -impl Read for Empty { - type Error = (); - - fn read_exact(&mut self, _data: &mut [u8]) -> Result<(), Self::Error> { - Ok(()) - } -} - /// Common error type #[derive(Debug, Error)] pub enum AdnlError { diff --git a/src/lib.rs b/src/lib.rs index 5b9dc1c..9ca6d46 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ pub use helper_types::{ - AdnlAddress, AdnlAesParams, AdnlError, AdnlPrivateKey, AdnlPublicKey, AdnlSecret, Empty, + AdnlAddress, AdnlAesParams, AdnlError, AdnlPrivateKey, AdnlPublicKey, AdnlSecret, }; pub use primitives::handshake::AdnlHandshake; pub use primitives::receive::AdnlReceiver; diff --git a/src/primitives/handshake.rs b/src/primitives/handshake.rs index dcaa9cb..b33b63a 100644 --- a/src/primitives/handshake.rs +++ b/src/primitives/handshake.rs @@ -1,5 +1,5 @@ use crate::primitives::AdnlAes; -use crate::{AdnlAddress, AdnlAesParams, AdnlClient, AdnlError, AdnlPublicKey, AdnlSecret, Empty}; +use crate::{AdnlAddress, AdnlAesParams, AdnlClient, AdnlError, AdnlPublicKey, AdnlSecret}; use aes::cipher::KeyIvInit; use ctr::cipher::StreamCipher; use sha2::{Digest, Sha256}; diff --git a/src/primitives/receive.rs b/src/primitives/receive.rs index 3833aa7..6f71f5c 100644 --- a/src/primitives/receive.rs +++ b/src/primitives/receive.rs @@ -1,5 +1,5 @@ use crate::primitives::AdnlAes; -use crate::{AdnlAesParams, AdnlError, Empty}; +use crate::{AdnlAesParams, AdnlError}; use aes::cipher::KeyIvInit; use ctr::cipher::StreamCipher; use sha2::{Digest, Sha256}; diff --git a/src/primitives/send.rs b/src/primitives/send.rs index 91cb955..d7ab951 100644 --- a/src/primitives/send.rs +++ b/src/primitives/send.rs @@ -4,7 +4,7 @@ use sha2::{Digest, Sha256}; use tokio::io::AsyncWriteExt; use crate::primitives::AdnlAes; -use crate::{AdnlAesParams, AdnlError, Empty}; +use crate::{AdnlAesParams, AdnlError}; /// Low-level outgoing datagram generator pub struct AdnlSender { diff --git a/src/wrappers/client.rs b/src/wrappers/client.rs index d974eb3..8988e8e 100644 --- a/src/wrappers/client.rs +++ b/src/wrappers/client.rs @@ -1,4 +1,4 @@ -use crate::{AdnlError, AdnlHandshake, AdnlPublicKey, AdnlReceiver, AdnlSender, Empty}; +use crate::{AdnlError, AdnlHandshake, AdnlPublicKey, AdnlReceiver, AdnlSender}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; /// Abstraction over [`AdnlSender`] and [`AdnlReceiver`] to keep things simple From db70e6c8112ae3a2391a655ad59dec6820912f39 Mon Sep 17 00:00:00 2001 From: x5113nc3x Date: Fri, 9 Feb 2024 21:23:43 +0700 Subject: [PATCH 04/11] add handshake fn --- src/primitives/receive.rs | 44 +++++++++++++++++++++++++++++++++++++++ src/wrappers/client.rs | 2 +- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/primitives/receive.rs b/src/primitives/receive.rs index 6f71f5c..9d52780 100644 --- a/src/primitives/receive.rs +++ b/src/primitives/receive.rs @@ -17,6 +17,50 @@ impl AdnlReceiver { aes: AdnlAes::new(aes_params.rx_key().into(), aes_params.rx_nonce().into()), } } + /// Receive handshake from `transport`. + pub async fn handshake( + &mut self, + transport: &mut R + ) -> Result<(), AdnlError> { + let mut length = [0u8; 4]; + log::debug!("reading length"); + transport + .read_exact(&mut length).await + .map_err(AdnlError::ReadError)?; + self.aes.apply_keystream(&mut length); + let length = u32::from_le_bytes(length); + log::debug!("length = {}", length); + if length < 64 { + return Err(AdnlError::TooShortPacket); + } + + let mut hasher = Sha256::new(); + + // read nonce + let mut nonce = [0u8; 32]; + log::debug!("reading nonce"); + transport + .read_exact(&mut nonce).await + .map_err(AdnlError::ReadError)?; + self.aes.apply_keystream(&mut nonce); + hasher.update(nonce); + + let mut given_hash = [0u8; 32]; + log::debug!("reading hash"); + transport + .read_exact(&mut given_hash).await + .map_err(AdnlError::ReadError)?; + self.aes.apply_keystream(&mut given_hash); + + let real_hash = hasher.finalize(); + if real_hash.as_slice() != given_hash { + return Err(AdnlError::IntegrityError); + } + + log::debug!("handshake finished successfully"); + + Ok(()) + } /// Receive datagram from `transport`. Received parts of the decrypted buffer /// will be sent to `consumer`, which usually can be just `Vec`. Note that diff --git a/src/wrappers/client.rs b/src/wrappers/client.rs index 8988e8e..7f94988 100644 --- a/src/wrappers/client.rs +++ b/src/wrappers/client.rs @@ -25,7 +25,7 @@ impl AdnlClient { receiver: AdnlReceiver::new(handshake.aes_params()), transport, }; - client.receive::<_, 0>(&mut Empty).await?; + client.receiver.handshake(&mut client.transport).await?; Ok(client) } From cf71650119a3d865a5cc3a3c4929e56352377ec8 Mon Sep 17 00:00:00 2001 From: x5113nc3x Date: Tue, 13 Feb 2024 12:01:09 +0700 Subject: [PATCH 05/11] add connect, change handshake and dependencies --- Cargo.toml | 13 ++++---- README.md | 62 ++++++++++----------------------------- examples/time.rs | 40 ++++--------------------- src/primitives/receive.rs | 44 --------------------------- src/wrappers/client.rs | 40 +++++++++++++++++++++++-- 5 files changed, 65 insertions(+), 134 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d1d4fd5..5239f18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,20 +17,21 @@ log = "0.4.14" rand_core = "0.6.3" x25519-dalek = { version = "2.0.0-pre.1", optional = true } curve25519-dalek = { version = "4.0.0-pre.2", optional = true } -tokio = { version = "1.35", features = ["net", "io-util"]} +tokio = { version = "1.36", features = ["net", "io-util"]} thiserror = "1" +rand = "0.8.5" +base64 = "0.13.0" +anyhow = "1" + [dev-dependencies] hex = "0.4.3" x25519-dalek = "= 2.0.0-pre.1" curve25519-dalek = "= 4.0.0-pre.2" -rand = "0.8.5" -base64 = "0.13.0" -tokio = { version = "1.35", features = ["rt-multi-thread", "macros"]} -anyhow = "1" +tokio = { version = "1.36", features = ["rt-multi-thread", "macros"]} [features] -default = [] +default = ["dalek"] dalek = ["x25519-dalek", "curve25519-dalek"] [[example]] diff --git a/README.md b/README.md index 47ae9e5..e72ad05 100644 --- a/README.md +++ b/README.md @@ -2,69 +2,39 @@ Minimal ADNL implementation in Rust (client-server only, without p2p for now). Specification of ADNL is available [here](https://github.com/tonstack/ton-docs/blob/main/ADNL/README.md). -| Feature | Status | -| ------------- | -------------------------------- | -| ADNL Client | ✅ Implemented | -| ADNL Server | ❌ Not implemented | -| ADNL P2P | ❌ Not implemented | -| async | ❌ Not implemented | -| ed25519 libs | curve25519_dalek + x25519_dalek | +| Feature | Status | +|--------------|---------------------------------| +| ADNL Client | ✅ Implemented | +| ADNL Server | ❌ Not implemented | +| ADNL P2P | ❌ Not implemented | +| async | ✅ Implemented | +| ed25519 libs | curve25519_dalek + x25519_dalek | ## Quickstart -Run this example: `cargo run --example time --features "std dalek"` +Run this example: `cargo run --example time` ```rust -use adnl::{AdnlBuilder, AdnlClient}; -use std::error::Error; -use std::net::{SocketAddrV4, TcpStream}; -use x25519_dalek::StaticSecret; +use adnl::AdnlClient; +use anyhow::Result; -pub fn connect( - ls_public: &str, - ls_ip: &str, - ls_port: u16, -) -> Result, Box> { - // decode liteserver public key - let remote_public: [u8; 32] = base64::decode(ls_public)? - .try_into() - .map_err(|_| "bad public key length")?; - - // generate private key - let local_secret = StaticSecret::new(rand::rngs::OsRng); - - // use TcpStream as a transport for our ADNL connection - let transport = TcpStream::connect(SocketAddrV4::new(ls_ip.parse()?, ls_port))?; - - // build handshake using random session keys, encrypt it with ECDH(local_secret, remote_public) - // then perform handshake over our TcpStream - let client = AdnlBuilder::with_random_aes_params(&mut rand::rngs::OsRng) - .perform_ecdh(local_secret, remote_public) - .perform_handshake(transport) - .map_err(|e| format!("{:?}", e))?; - Ok(client) -} - -fn main() -> Result<(), Box> { +#[tokio::main] +async fn main() -> Result<()> { // create AdnlClient - let mut client = connect( + let mut client = AdnlClient::connect( "JhXt7H1dZTgxQTIyGiYV4f9VUARuDxFl/1kVBjLSMB8=", "65.21.74.140", 46427, - )?; + ).await?; // already serialized TL with gettime query let mut query = hex::decode("7af98bb435263e6c95d6fecb497dfd0aa5f031e7d412986b5ce720496db512052e8f2d100cdf068c7904345aad16000000000000")?; // send over ADNL, use random nonce - client - .send(&mut query, &mut rand::random()) - .map_err(|e| format!("{:?}", e))?; + client.send(&mut query, &mut rand::random()).await?; // receive result into vector, use 8192 bytes buffer let mut result = Vec::::new(); - client - .receive::<_, 8192>(&mut result) - .map_err(|e| format!("{:?}", e))?; + client.receive::<_, 8192>(&mut result).await?; // get time from serialized TL answer println!( diff --git a/examples/time.rs b/examples/time.rs index a3fbe7e..7a6966d 100644 --- a/examples/time.rs +++ b/examples/time.rs @@ -1,38 +1,10 @@ -use adnl::{AdnlBuilder, AdnlClient}; -use std::net::SocketAddrV4; -use x25519_dalek::StaticSecret; -use tokio::net::TcpStream; -use anyhow::{anyhow, Context, Result}; - -pub async fn connect( - ls_public: &str, - ls_ip: &str, - ls_port: u16, -) -> Result> { - // decode liteserver public key - let remote_public: [u8; 32] = base64::decode(ls_public) - .context("Error decode base64")? - .try_into().map_err(|_| anyhow!("Bad public key length"))?; - - // generate private key - let local_secret = StaticSecret::new(rand::rngs::OsRng); - - // use TcpStream as transport for our ADNL connection - let transport = TcpStream::connect(SocketAddrV4::new(ls_ip.parse()?, ls_port)).await - .context("Connection error")?; - - // build handshake using random session keys, encrypt it with ECDH(local_secret, remote_public) - // then perform handshake over our TcpStream - let client = AdnlBuilder::with_random_aes_params(&mut rand::rngs::OsRng) - .perform_ecdh(local_secret, remote_public) - .perform_handshake(transport).await?; - Ok(client) -} +use adnl::AdnlClient; +use anyhow::Result; #[tokio::main] async fn main() -> Result<()> { // create AdnlClient - let mut client = connect( + let mut client = AdnlClient::connect( "JhXt7H1dZTgxQTIyGiYV4f9VUARuDxFl/1kVBjLSMB8=", "65.21.74.140", 46427, @@ -42,13 +14,11 @@ async fn main() -> Result<()> { let mut query = hex::decode("7af98bb435263e6c95d6fecb497dfd0aa5f031e7d412986b5ce720496db512052e8f2d100cdf068c7904345aad16000000000000")?; // send over ADNL, use random nonce - client - .send(&mut query, &mut rand::random()).await?; + client.send(&mut query, &mut rand::random()).await?; // receive result into vector, use 8192 bytes buffer let mut result = Vec::::new(); - client - .receive::<_, 8192>(&mut result).await?; + client.receive::<_, 8192>(&mut result).await?; // get time from serialized TL answer println!( diff --git a/src/primitives/receive.rs b/src/primitives/receive.rs index 9d52780..6f71f5c 100644 --- a/src/primitives/receive.rs +++ b/src/primitives/receive.rs @@ -17,50 +17,6 @@ impl AdnlReceiver { aes: AdnlAes::new(aes_params.rx_key().into(), aes_params.rx_nonce().into()), } } - /// Receive handshake from `transport`. - pub async fn handshake( - &mut self, - transport: &mut R - ) -> Result<(), AdnlError> { - let mut length = [0u8; 4]; - log::debug!("reading length"); - transport - .read_exact(&mut length).await - .map_err(AdnlError::ReadError)?; - self.aes.apply_keystream(&mut length); - let length = u32::from_le_bytes(length); - log::debug!("length = {}", length); - if length < 64 { - return Err(AdnlError::TooShortPacket); - } - - let mut hasher = Sha256::new(); - - // read nonce - let mut nonce = [0u8; 32]; - log::debug!("reading nonce"); - transport - .read_exact(&mut nonce).await - .map_err(AdnlError::ReadError)?; - self.aes.apply_keystream(&mut nonce); - hasher.update(nonce); - - let mut given_hash = [0u8; 32]; - log::debug!("reading hash"); - transport - .read_exact(&mut given_hash).await - .map_err(AdnlError::ReadError)?; - self.aes.apply_keystream(&mut given_hash); - - let real_hash = hasher.finalize(); - if real_hash.as_slice() != given_hash { - return Err(AdnlError::IntegrityError); - } - - log::debug!("handshake finished successfully"); - - Ok(()) - } /// Receive datagram from `transport`. Received parts of the decrypted buffer /// will be sent to `consumer`, which usually can be just `Vec`. Note that diff --git a/src/wrappers/client.rs b/src/wrappers/client.rs index 7f94988..83362c3 100644 --- a/src/wrappers/client.rs +++ b/src/wrappers/client.rs @@ -1,5 +1,9 @@ -use crate::{AdnlError, AdnlHandshake, AdnlPublicKey, AdnlReceiver, AdnlSender}; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use std::net::SocketAddrV4; +use anyhow::{anyhow, Context}; +use crate::{AdnlBuilder, AdnlError, AdnlHandshake, AdnlPublicKey, AdnlReceiver, AdnlSender}; +use tokio::io::{AsyncReadExt, AsyncWriteExt, empty}; +use tokio::net::TcpStream; +use x25519_dalek::StaticSecret; /// Abstraction over [`AdnlSender`] and [`AdnlReceiver`] to keep things simple pub struct AdnlClient { @@ -8,7 +12,36 @@ pub struct AdnlClient { transport: T, } +impl AdnlClient { + /// Create ADNL client use random private key and random AES params + pub async fn connect( + ls_public: &str, + ls_ip: &str, + ls_port: u16, + ) -> anyhow::Result> { + // decode liteserver public key + let remote_public: [u8; 32] = base64::decode(ls_public) + .context("Error decode base64")? + .try_into().map_err(|_| anyhow!("Bad public key length"))?; + + // generate private key + let local_secret = StaticSecret::new(rand::rngs::OsRng); + + // use TcpStream as transport for our ADNL connection + let transport = TcpStream::connect(SocketAddrV4::new(ls_ip.parse()?, ls_port)).await + .context("Connection error")?; + + // build handshake using random session keys, encrypt it with ECDH(local_secret, remote_public) + // then perform handshake over our TcpStream + let client = AdnlBuilder::with_random_aes_params(&mut rand::rngs::OsRng) + .perform_ecdh(local_secret, remote_public) + .perform_handshake(transport).await?; + Ok(client) + } +} + impl AdnlClient { + /// Send `handshake` over `transport` and check that handshake was successful pub async fn perform_handshake( mut transport: T, @@ -25,7 +58,8 @@ impl AdnlClient { receiver: AdnlReceiver::new(handshake.aes_params()), transport, }; - client.receiver.handshake(&mut client.transport).await?; + let mut empty = empty(); + client.receiver.receive::<_, _, 0>(&mut client.transport, &mut empty).await?; Ok(client) } From 4107b464f96b728f1863948a4efb458b863bf4b6 Mon Sep 17 00:00:00 2001 From: x5113nc3x Date: Tue, 13 Feb 2024 17:23:35 +0700 Subject: [PATCH 06/11] refactor connect func --- Cargo.toml | 5 ++--- README.md | 8 ++++++-- examples/time.rs | 8 ++++++-- src/helper_types.rs | 3 +++ src/wrappers/client.rs | 18 ++++++------------ 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5239f18..4eabc19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,15 +20,14 @@ curve25519-dalek = { version = "4.0.0-pre.2", optional = true } tokio = { version = "1.36", features = ["net", "io-util"]} thiserror = "1" rand = "0.8.5" -base64 = "0.13.0" -anyhow = "1" - [dev-dependencies] hex = "0.4.3" x25519-dalek = "= 2.0.0-pre.1" curve25519-dalek = "= 4.0.0-pre.2" tokio = { version = "1.36", features = ["rt-multi-thread", "macros"]} +base64 = "0.13.0" +anyhow = "1" [features] default = ["dalek"] diff --git a/README.md b/README.md index e72ad05..72cf891 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,17 @@ Run this example: `cargo run --example time` ```rust use adnl::AdnlClient; -use anyhow::Result; +use anyhow::{anyhow, Context, Result}; #[tokio::main] async fn main() -> Result<()> { + // decode liteserver public key + let remote_public: [u8; 32] = base64::decode("JhXt7H1dZTgxQTIyGiYV4f9VUARuDxFl/1kVBjLSMB8=") + .context("Error decode base64")? + .try_into().map_err(|_| anyhow!("Bad public key length"))?; // create AdnlClient let mut client = AdnlClient::connect( - "JhXt7H1dZTgxQTIyGiYV4f9VUARuDxFl/1kVBjLSMB8=", + remote_public, "65.21.74.140", 46427, ).await?; diff --git a/examples/time.rs b/examples/time.rs index 7a6966d..808fa6b 100644 --- a/examples/time.rs +++ b/examples/time.rs @@ -1,11 +1,15 @@ use adnl::AdnlClient; -use anyhow::Result; +use anyhow::{anyhow, Context, Result}; #[tokio::main] async fn main() -> Result<()> { + // decode liteserver public key + let remote_public: [u8; 32] = base64::decode("JhXt7H1dZTgxQTIyGiYV4f9VUARuDxFl/1kVBjLSMB8=") + .context("Error decode base64")? + .try_into().map_err(|_| anyhow!("Bad public key length"))?; // create AdnlClient let mut client = AdnlClient::connect( - "JhXt7H1dZTgxQTIyGiYV4f9VUARuDxFl/1kVBjLSMB8=", + remote_public, "65.21.74.140", 46427, ).await?; diff --git a/src/helper_types.rs b/src/helper_types.rs index 386cd45..4328782 100644 --- a/src/helper_types.rs +++ b/src/helper_types.rs @@ -1,4 +1,5 @@ use std::io::Error; +use std::net::AddrParseError; use sha2::{Digest, Sha256}; use thiserror::Error; @@ -158,6 +159,8 @@ pub enum AdnlError { IntegrityError, #[error("TooShortPacket error")] TooShortPacket, + #[error("Incorrect ip address")] + IncorrectAddr(AddrParseError), #[error(transparent)] OtherError(#[from] Error) } diff --git a/src/wrappers/client.rs b/src/wrappers/client.rs index 83362c3..7381f76 100644 --- a/src/wrappers/client.rs +++ b/src/wrappers/client.rs @@ -1,5 +1,4 @@ use std::net::SocketAddrV4; -use anyhow::{anyhow, Context}; use crate::{AdnlBuilder, AdnlError, AdnlHandshake, AdnlPublicKey, AdnlReceiver, AdnlSender}; use tokio::io::{AsyncReadExt, AsyncWriteExt, empty}; use tokio::net::TcpStream; @@ -14,27 +13,22 @@ pub struct AdnlClient { impl AdnlClient { /// Create ADNL client use random private key and random AES params - pub async fn connect( - ls_public: &str, + pub async fn connect( + ls_public: P, ls_ip: &str, ls_port: u16, - ) -> anyhow::Result> { - // decode liteserver public key - let remote_public: [u8; 32] = base64::decode(ls_public) - .context("Error decode base64")? - .try_into().map_err(|_| anyhow!("Bad public key length"))?; - + ) -> Result, AdnlError> { // generate private key let local_secret = StaticSecret::new(rand::rngs::OsRng); // use TcpStream as transport for our ADNL connection - let transport = TcpStream::connect(SocketAddrV4::new(ls_ip.parse()?, ls_port)).await - .context("Connection error")?; + let ip = ls_ip.parse().map_err(AdnlError::IncorrectAddr)?; + let transport = TcpStream::connect(SocketAddrV4::new(ip, ls_port)).await?; // build handshake using random session keys, encrypt it with ECDH(local_secret, remote_public) // then perform handshake over our TcpStream let client = AdnlBuilder::with_random_aes_params(&mut rand::rngs::OsRng) - .perform_ecdh(local_secret, remote_public) + .perform_ecdh(local_secret, ls_public) .perform_handshake(transport).await?; Ok(client) } From 94c41dbc551dd528239d209e1496c14cf1447ca2 Mon Sep 17 00:00:00 2001 From: Vadim Date: Tue, 13 Feb 2024 22:37:57 +0700 Subject: [PATCH 07/11] add different receive and send func --- Cargo.toml | 2 +- examples/time.rs | 4 ++-- src/tests.rs | 4 ++-- src/wrappers/client.rs | 24 ++++++++++++++++++++++-- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4eabc19..0bc64ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,4 +35,4 @@ dalek = ["x25519-dalek", "curve25519-dalek"] [[example]] name = "time" -required-features = ["dalek"] \ No newline at end of file +required-features = ["dalek"] diff --git a/examples/time.rs b/examples/time.rs index 808fa6b..c6db2fa 100644 --- a/examples/time.rs +++ b/examples/time.rs @@ -18,11 +18,11 @@ async fn main() -> Result<()> { let mut query = hex::decode("7af98bb435263e6c95d6fecb497dfd0aa5f031e7d412986b5ce720496db512052e8f2d100cdf068c7904345aad16000000000000")?; // send over ADNL, use random nonce - client.send(&mut query, &mut rand::random()).await?; + client.send(&mut query).await?; // receive result into vector, use 8192 bytes buffer let mut result = Vec::::new(); - client.receive::<_, 8192>(&mut result).await?; + client.receive(&mut result).await?; // get time from serialized TL answer println!( diff --git a/src/tests.rs b/src/tests.rs index a8500d7..8fb94c1 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -89,7 +89,7 @@ async fn test_send(aes_params: Vec, nonce: Vec, buffer: Vec, expecte let aes_params = AdnlAesParams::from(aes_params); let mut protocol_client = AdnlSender::new(&aes_params); let mut packet = Vec::::new(); - let _result = protocol_client.send(&mut packet, &mut nonce, &mut buffer).await; + let _result = protocol_client.send_with_nonce(&mut packet, &mut nonce, &mut buffer).await; assert_eq!( packet.as_slice(), &expected_packet, @@ -128,6 +128,6 @@ async fn test_recv_2() { async fn test_recv(client: &mut AdnlReceiver, encrypted_packet: Vec, expected_data: Vec) { let mut data = Vec::::new(); let mut binding = encrypted_packet.as_slice(); - let _r = client.receive::<_, _, 8192>(&mut binding, &mut data).await; + let _r = client.receive_with_buffer::<_, _, 8192>(&mut binding, &mut data).await; assert_eq!(data, expected_data.as_slice(), "incoming packet is wrong"); } diff --git a/src/wrappers/client.rs b/src/wrappers/client.rs index 7381f76..d5d37e5 100644 --- a/src/wrappers/client.rs +++ b/src/wrappers/client.rs @@ -13,6 +13,7 @@ pub struct AdnlClient { impl AdnlClient { /// Create ADNL client use random private key and random AES params + #[cfg(feature = "dalek")] pub async fn connect( ls_public: P, ls_ip: &str, @@ -56,19 +57,38 @@ impl AdnlClient { client.receiver.receive::<_, _, 0>(&mut client.transport, &mut empty).await?; Ok(client) } + + /// Send `data` to another peer with random nonce + pub async fn send( + &mut self, + data: &mut [u8], + ) -> Result<(), AdnlError> { + self.sender.send(&mut self.transport, &mut rand::random(), data).await + } /// Send `data` to another peer. Random `nonce` must be provided to eliminate bit-flipping attacks. - pub async fn send( + pub async fn send_with_nonce( &mut self, data: &mut [u8], nonce: &mut [u8; 32], ) -> Result<(), AdnlError> { self.sender.send(&mut self.transport, nonce, data).await } + + + /// Receive data from another peer into `consumer` which will process the data with + /// a `BUFFER` size of 8126 bytes. + pub async fn receive( + &mut self, + consumer: &mut C, + ) -> Result<(), AdnlError> { + self.receiver + .receive::<_, _, 8192>(&mut self.transport, consumer).await + } /// Receive data from another peer into `consumer` which will process the data. Set `BUFFER` /// according to your memory requirements, recommended size is 8192 bytes. - pub async fn receive( + pub async fn receive_with_buffer( &mut self, consumer: &mut C, ) -> Result<(), AdnlError> { From 1c4387a249e2fbe57ff909e43874abc89d9f9e81 Mon Sep 17 00:00:00 2001 From: x5113nc3x Date: Wed, 14 Feb 2024 12:28:34 +0700 Subject: [PATCH 08/11] fix connect argument and README --- README.md | 12 ++++++++---- examples/time.rs | 7 +++++-- src/wrappers/client.rs | 13 +++++-------- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 72cf891..65e774f 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Minimal ADNL implementation in Rust (client-server only, without p2p for now). S Run this example: `cargo run --example time` ```rust +use std::net::SocketAddrV4; use adnl::AdnlClient; use anyhow::{anyhow, Context, Result}; @@ -23,22 +24,24 @@ async fn main() -> Result<()> { let remote_public: [u8; 32] = base64::decode("JhXt7H1dZTgxQTIyGiYV4f9VUARuDxFl/1kVBjLSMB8=") .context("Error decode base64")? .try_into().map_err(|_| anyhow!("Bad public key length"))?; + + let ls_ip = "65.21.74.140"; + let ls_port = 46427; // create AdnlClient let mut client = AdnlClient::connect( remote_public, - "65.21.74.140", - 46427, + SocketAddrV4::new(ls_ip.parse()?, ls_port) ).await?; // already serialized TL with gettime query let mut query = hex::decode("7af98bb435263e6c95d6fecb497dfd0aa5f031e7d412986b5ce720496db512052e8f2d100cdf068c7904345aad16000000000000")?; // send over ADNL, use random nonce - client.send(&mut query, &mut rand::random()).await?; + client.send(&mut query).await?; // receive result into vector, use 8192 bytes buffer let mut result = Vec::::new(); - client.receive::<_, 8192>(&mut result).await?; + client.receive(&mut result).await?; // get time from serialized TL answer println!( @@ -47,4 +50,5 @@ async fn main() -> Result<()> { ); Ok(()) } + ``` diff --git a/examples/time.rs b/examples/time.rs index c6db2fa..04471dc 100644 --- a/examples/time.rs +++ b/examples/time.rs @@ -1,3 +1,4 @@ +use std::net::SocketAddrV4; use adnl::AdnlClient; use anyhow::{anyhow, Context, Result}; @@ -7,11 +8,13 @@ async fn main() -> Result<()> { let remote_public: [u8; 32] = base64::decode("JhXt7H1dZTgxQTIyGiYV4f9VUARuDxFl/1kVBjLSMB8=") .context("Error decode base64")? .try_into().map_err(|_| anyhow!("Bad public key length"))?; + + let ls_ip = "65.21.74.140"; + let ls_port = 46427; // create AdnlClient let mut client = AdnlClient::connect( remote_public, - "65.21.74.140", - 46427, + SocketAddrV4::new(ls_ip.parse()?, ls_port) ).await?; // already serialized TL with gettime query diff --git a/src/wrappers/client.rs b/src/wrappers/client.rs index d5d37e5..caedb0d 100644 --- a/src/wrappers/client.rs +++ b/src/wrappers/client.rs @@ -1,7 +1,6 @@ -use std::net::SocketAddrV4; use crate::{AdnlBuilder, AdnlError, AdnlHandshake, AdnlPublicKey, AdnlReceiver, AdnlSender}; use tokio::io::{AsyncReadExt, AsyncWriteExt, empty}; -use tokio::net::TcpStream; +use tokio::net::{TcpStream, ToSocketAddrs}; use x25519_dalek::StaticSecret; /// Abstraction over [`AdnlSender`] and [`AdnlReceiver`] to keep things simple @@ -14,17 +13,15 @@ pub struct AdnlClient { impl AdnlClient { /// Create ADNL client use random private key and random AES params #[cfg(feature = "dalek")] - pub async fn connect( + pub async fn connect( ls_public: P, - ls_ip: &str, - ls_port: u16, + ls_addr: A, ) -> Result, AdnlError> { // generate private key let local_secret = StaticSecret::new(rand::rngs::OsRng); // use TcpStream as transport for our ADNL connection - let ip = ls_ip.parse().map_err(AdnlError::IncorrectAddr)?; - let transport = TcpStream::connect(SocketAddrV4::new(ip, ls_port)).await?; + let transport = TcpStream::connect(ls_addr).await?; // build handshake using random session keys, encrypt it with ECDH(local_secret, remote_public) // then perform handshake over our TcpStream @@ -77,7 +74,7 @@ impl AdnlClient { /// Receive data from another peer into `consumer` which will process the data with - /// a `BUFFER` size of 8126 bytes. + /// a `BUFFER` size of 8192 bytes. pub async fn receive( &mut self, consumer: &mut C, From 2276948a5d8cf7e8b9dfb1ff7c7db3265660e4fa Mon Sep 17 00:00:00 2001 From: x5113nc3x Date: Wed, 14 Feb 2024 13:00:39 +0700 Subject: [PATCH 09/11] Update tests.rs --- src/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests.rs b/src/tests.rs index 8fb94c1..a8500d7 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -89,7 +89,7 @@ async fn test_send(aes_params: Vec, nonce: Vec, buffer: Vec, expecte let aes_params = AdnlAesParams::from(aes_params); let mut protocol_client = AdnlSender::new(&aes_params); let mut packet = Vec::::new(); - let _result = protocol_client.send_with_nonce(&mut packet, &mut nonce, &mut buffer).await; + let _result = protocol_client.send(&mut packet, &mut nonce, &mut buffer).await; assert_eq!( packet.as_slice(), &expected_packet, @@ -128,6 +128,6 @@ async fn test_recv_2() { async fn test_recv(client: &mut AdnlReceiver, encrypted_packet: Vec, expected_data: Vec) { let mut data = Vec::::new(); let mut binding = encrypted_packet.as_slice(); - let _r = client.receive_with_buffer::<_, _, 8192>(&mut binding, &mut data).await; + let _r = client.receive::<_, _, 8192>(&mut binding, &mut data).await; assert_eq!(data, expected_data.as_slice(), "incoming packet is wrong"); } From 694b4e6d6299336d6f693bcdab83d8ad4e0a9af9 Mon Sep 17 00:00:00 2001 From: x5113nc3x Date: Wed, 14 Feb 2024 13:19:22 +0700 Subject: [PATCH 10/11] fix code style --- README.md | 10 ++++------ examples/time.rs | 9 ++++----- src/helper_types.rs | 6 +++--- src/primitives/handshake.rs | 2 +- src/primitives/receive.rs | 21 ++++++++++++++------- src/primitives/send.rs | 14 +++++++++----- src/tests.rs | 4 +++- src/wrappers/client.rs | 29 ++++++++++++++++++----------- 8 files changed, 56 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 65e774f..35d58c7 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,10 @@ Minimal ADNL implementation in Rust (client-server only, without p2p for now). S Run this example: `cargo run --example time` ```rust -use std::net::SocketAddrV4; use adnl::AdnlClient; use anyhow::{anyhow, Context, Result}; +use std::net::SocketAddrV4; + #[tokio::main] async fn main() -> Result<()> { @@ -28,10 +29,8 @@ async fn main() -> Result<()> { let ls_ip = "65.21.74.140"; let ls_port = 46427; // create AdnlClient - let mut client = AdnlClient::connect( - remote_public, - SocketAddrV4::new(ls_ip.parse()?, ls_port) - ).await?; + let mut client = + AdnlClient::connect(remote_public, SocketAddrV4::new(ls_ip.parse()?, ls_port)).await?; // already serialized TL with gettime query let mut query = hex::decode("7af98bb435263e6c95d6fecb497dfd0aa5f031e7d412986b5ce720496db512052e8f2d100cdf068c7904345aad16000000000000")?; @@ -50,5 +49,4 @@ async fn main() -> Result<()> { ); Ok(()) } - ``` diff --git a/examples/time.rs b/examples/time.rs index 04471dc..6a38d1b 100644 --- a/examples/time.rs +++ b/examples/time.rs @@ -1,6 +1,7 @@ -use std::net::SocketAddrV4; use adnl::AdnlClient; use anyhow::{anyhow, Context, Result}; +use std::net::SocketAddrV4; + #[tokio::main] async fn main() -> Result<()> { @@ -12,10 +13,8 @@ async fn main() -> Result<()> { let ls_ip = "65.21.74.140"; let ls_port = 46427; // create AdnlClient - let mut client = AdnlClient::connect( - remote_public, - SocketAddrV4::new(ls_ip.parse()?, ls_port) - ).await?; + let mut client = + AdnlClient::connect(remote_public, SocketAddrV4::new(ls_ip.parse()?, ls_port)).await?; // already serialized TL with gettime query let mut query = hex::decode("7af98bb435263e6c95d6fecb497dfd0aa5f031e7d412986b5ce720496db512052e8f2d100cdf068c7904345aad16000000000000")?; diff --git a/src/helper_types.rs b/src/helper_types.rs index 4328782..b025bce 100644 --- a/src/helper_types.rs +++ b/src/helper_types.rs @@ -1,6 +1,6 @@ +use sha2::{Digest, Sha256}; use std::io::Error; use std::net::AddrParseError; -use sha2::{Digest, Sha256}; use thiserror::Error; pub trait CryptoRandom: rand_core::RngCore + rand_core::CryptoRng {} @@ -12,7 +12,7 @@ pub trait AdnlPublicKey { let mut hasher = Sha256::new(); hasher.update([0xc6, 0xb4, 0x13, 0x48]); // type id - always ed25519 hasher.update(self.to_bytes()); - AdnlAddress(hasher.finalize().try_into().unwrap()) + AdnlAddress(hasher.finalize().into()) } fn to_bytes(&self) -> [u8; 32]; @@ -162,5 +162,5 @@ pub enum AdnlError { #[error("Incorrect ip address")] IncorrectAddr(AddrParseError), #[error(transparent)] - OtherError(#[from] Error) + OtherError(#[from] Error), } diff --git a/src/primitives/handshake.rs b/src/primitives/handshake.rs index b33b63a..7696d4c 100644 --- a/src/primitives/handshake.rs +++ b/src/primitives/handshake.rs @@ -44,7 +44,7 @@ impl AdnlHandshake

{ let mut raw_params = self.aes_params.to_bytes(); let mut hasher = Sha256::new(); hasher.update(raw_params); - let hash: [u8; 32] = hasher.finalize().try_into().unwrap(); + let hash: [u8; 32] = hasher.finalize().into(); let mut key = [0u8; 32]; key[..16].copy_from_slice(&self.secret.as_bytes()[..16]); diff --git a/src/primitives/receive.rs b/src/primitives/receive.rs index 6f71f5c..a4cf14f 100644 --- a/src/primitives/receive.rs +++ b/src/primitives/receive.rs @@ -34,7 +34,8 @@ impl AdnlReceiver { let mut length = [0u8; 4]; log::debug!("reading length"); transport - .read_exact(&mut length).await + .read_exact(&mut length) + .await .map_err(AdnlError::ReadError)?; self.aes.apply_keystream(&mut length); let length = u32::from_le_bytes(length); @@ -49,7 +50,8 @@ impl AdnlReceiver { let mut nonce = [0u8; 32]; log::debug!("reading nonce"); transport - .read_exact(&mut nonce).await + .read_exact(&mut nonce) + .await .map_err(AdnlError::ReadError)?; self.aes.apply_keystream(&mut nonce); hasher.update(nonce); @@ -65,12 +67,14 @@ impl AdnlReceiver { bytes_to_read ); transport - .read_exact(&mut buffer).await + .read_exact(&mut buffer) + .await .map_err(AdnlError::ReadError)?; self.aes.apply_keystream(&mut buffer); hasher.update(buffer); consumer - .write_all(&buffer).await + .write_all(&buffer) + .await .map_err(AdnlError::WriteError)?; bytes_to_read -= BUFFER; } @@ -80,12 +84,14 @@ impl AdnlReceiver { log::debug!("last chunk, {} bytes remaining", bytes_to_read); let buffer = &mut buffer[..bytes_to_read]; transport - .read_exact(buffer).await + .read_exact(buffer) + .await .map_err(AdnlError::ReadError)?; self.aes.apply_keystream(buffer); hasher.update(&buffer); consumer - .write_all(buffer).await + .write_all(buffer) + .await .map_err(AdnlError::WriteError)?; } } @@ -93,7 +99,8 @@ impl AdnlReceiver { let mut given_hash = [0u8; 32]; log::debug!("reading hash"); transport - .read_exact(&mut given_hash).await + .read_exact(&mut given_hash) + .await .map_err(AdnlError::ReadError)?; self.aes.apply_keystream(&mut given_hash); diff --git a/src/primitives/send.rs b/src/primitives/send.rs index d7ab951..41a7e93 100644 --- a/src/primitives/send.rs +++ b/src/primitives/send.rs @@ -39,7 +39,7 @@ impl AdnlSender { let mut hasher = Sha256::new(); hasher.update(*nonce); hasher.update(&*buffer); - let mut hash: [u8; 32] = hasher.finalize().try_into().unwrap(); + let mut hash: [u8; 32] = hasher.finalize().into(); // encrypt packet self.aes.apply_keystream(&mut length); @@ -49,16 +49,20 @@ impl AdnlSender { // write to transport transport - .write_all(&length).await + .write_all(&length) + .await .map_err(AdnlError::WriteError)?; transport - .write_all(nonce).await + .write_all(nonce) + .await .map_err(AdnlError::WriteError)?; transport - .write_all(buffer).await + .write_all(buffer) + .await .map_err(AdnlError::WriteError)?; transport - .write_all(&hash).await + .write_all(&hash) + .await .map_err(AdnlError::WriteError)?; transport.flush().await.map_err(AdnlError::WriteError)?; diff --git a/src/tests.rs b/src/tests.rs index a8500d7..9474b04 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -89,7 +89,9 @@ async fn test_send(aes_params: Vec, nonce: Vec, buffer: Vec, expecte let aes_params = AdnlAesParams::from(aes_params); let mut protocol_client = AdnlSender::new(&aes_params); let mut packet = Vec::::new(); - let _result = protocol_client.send(&mut packet, &mut nonce, &mut buffer).await; + let _result = protocol_client + .send(&mut packet, &mut nonce, &mut buffer) + .await; assert_eq!( packet.as_slice(), &expected_packet, diff --git a/src/wrappers/client.rs b/src/wrappers/client.rs index caedb0d..0e07382 100644 --- a/src/wrappers/client.rs +++ b/src/wrappers/client.rs @@ -1,5 +1,5 @@ use crate::{AdnlBuilder, AdnlError, AdnlHandshake, AdnlPublicKey, AdnlReceiver, AdnlSender}; -use tokio::io::{AsyncReadExt, AsyncWriteExt, empty}; +use tokio::io::{empty, AsyncReadExt, AsyncWriteExt}; use tokio::net::{TcpStream, ToSocketAddrs}; use x25519_dalek::StaticSecret; @@ -27,13 +27,13 @@ impl AdnlClient { // then perform handshake over our TcpStream let client = AdnlBuilder::with_random_aes_params(&mut rand::rngs::OsRng) .perform_ecdh(local_secret, ls_public) - .perform_handshake(transport).await?; + .perform_handshake(transport) + .await?; Ok(client) } } impl AdnlClient { - /// Send `handshake` over `transport` and check that handshake was successful pub async fn perform_handshake( mut transport: T, @@ -41,7 +41,8 @@ impl AdnlClient { ) -> Result { // send handshake transport - .write_all(&handshake.to_bytes()).await + .write_all(&handshake.to_bytes()) + .await .map_err(AdnlError::WriteError)?; // receive empty message to ensure that server knows our AES keys @@ -51,16 +52,21 @@ impl AdnlClient { transport, }; let mut empty = empty(); - client.receiver.receive::<_, _, 0>(&mut client.transport, &mut empty).await?; + client + .receiver + .receive::<_, _, 0>(&mut client.transport, &mut empty) + .await?; Ok(client) } - + /// Send `data` to another peer with random nonce pub async fn send( &mut self, data: &mut [u8], ) -> Result<(), AdnlError> { - self.sender.send(&mut self.transport, &mut rand::random(), data).await + self.sender + .send(&mut self.transport, &mut rand::random(), data) + .await } /// Send `data` to another peer. Random `nonce` must be provided to eliminate bit-flipping attacks. @@ -71,8 +77,7 @@ impl AdnlClient { ) -> Result<(), AdnlError> { self.sender.send(&mut self.transport, nonce, data).await } - - + /// Receive data from another peer into `consumer` which will process the data with /// a `BUFFER` size of 8192 bytes. pub async fn receive( @@ -80,7 +85,8 @@ impl AdnlClient { consumer: &mut C, ) -> Result<(), AdnlError> { self.receiver - .receive::<_, _, 8192>(&mut self.transport, consumer).await + .receive::<_, _, 8192>(&mut self.transport, consumer) + .await } /// Receive data from another peer into `consumer` which will process the data. Set `BUFFER` @@ -90,6 +96,7 @@ impl AdnlClient { consumer: &mut C, ) -> Result<(), AdnlError> { self.receiver - .receive::<_, _, BUFFER>(&mut self.transport, consumer).await + .receive::<_, _, BUFFER>(&mut self.transport, consumer) + .await } } From 436943b28a4ecad9e967a0354c8b9715b194d3a9 Mon Sep 17 00:00:00 2001 From: x5113nc3x Date: Wed, 14 Feb 2024 13:30:49 +0700 Subject: [PATCH 11/11] dummy fixes --- examples/time.rs | 4 ++-- src/wrappers/client.rs | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/examples/time.rs b/examples/time.rs index 6a38d1b..bc044cf 100644 --- a/examples/time.rs +++ b/examples/time.rs @@ -2,13 +2,13 @@ use adnl::AdnlClient; use anyhow::{anyhow, Context, Result}; use std::net::SocketAddrV4; - #[tokio::main] async fn main() -> Result<()> { // decode liteserver public key let remote_public: [u8; 32] = base64::decode("JhXt7H1dZTgxQTIyGiYV4f9VUARuDxFl/1kVBjLSMB8=") .context("Error decode base64")? - .try_into().map_err(|_| anyhow!("Bad public key length"))?; + .try_into() + .map_err(|_| anyhow!("Bad public key length"))?; let ls_ip = "65.21.74.140"; let ls_port = 46427; diff --git a/src/wrappers/client.rs b/src/wrappers/client.rs index 0e07382..72c5049 100644 --- a/src/wrappers/client.rs +++ b/src/wrappers/client.rs @@ -60,10 +60,7 @@ impl AdnlClient { } /// Send `data` to another peer with random nonce - pub async fn send( - &mut self, - data: &mut [u8], - ) -> Result<(), AdnlError> { + pub async fn send(&mut self, data: &mut [u8]) -> Result<(), AdnlError> { self.sender .send(&mut self.transport, &mut rand::random(), data) .await @@ -78,7 +75,7 @@ impl AdnlClient { self.sender.send(&mut self.transport, nonce, data).await } - /// Receive data from another peer into `consumer` which will process the data with + /// Receive data from another peer into `consumer` which will process the data with /// a `BUFFER` size of 8192 bytes. pub async fn receive( &mut self,