feat: added connection and authentication

client can now generate a server binary, and try to connect to it and
get capabilities
This commit is contained in:
Andrew Rioux
2023-09-02 22:29:13 -04:00
parent cda6388596
commit 4449a771e2
12 changed files with 606 additions and 67 deletions

View File

@@ -5,6 +5,7 @@ edition = "2021"
[dependencies]
anyhow = "1.0.75"
ecies-ed25519 = { version = "0.5.1", features = ["serde"] }
ed25519-dalek = "1.0.1"
rand = "0.7"
rmp-serde = "1.1.2"

View File

@@ -1,17 +1,51 @@
use std::{net::SocketAddr, path::PathBuf, sync::Arc};
use ed25519_dalek::{Keypair, Signer};
use sparse_05_common::messages::CONNECT_MESSAGE;
use anyhow::{bail, Context};
use ed25519_dalek::{Keypair, Signature, Signer, Verifier};
use rmp_serde::decode::ReadSlice;
use sparse_05_common::messages::{Capabilities, Response, CONNECTED_MESSAGE, CONNECT_MESSAGE};
use tokio::{fs, net::UdpSocket};
use crate::configs::ClientConfig;
enum State {
Authenticating,
Ready,
UploadingFile,
DownloadingFile,
}
struct Connection {
config: ClientConfig,
foreign_sign_pubkey: ed25519_dalek::PublicKey,
foreign_enc_pubkey: ecies_ed25519::PublicKey,
}
impl Connection {
fn decrypt_and_verify(&self, data: &[u8]) -> anyhow::Result<Response> {
if data.len() < 65 {
bail!("unable to parse out signature from message");
}
let signature: [u8; 64] = data[..64].try_into().unwrap();
self.foreign_sign_pubkey
.verify(data, &Signature::from(signature))?;
let data = ecies_ed25519::decrypt(&self.config.enc_privkey, &data[64..])?;
Ok(rmp_serde::from_slice(&data)?)
}
fn encrypt_and_sign(&self, data: &[u8]) -> anyhow::Result<Vec<u8>> {
let mut rng = rand::thread_rng();
let data = ecies_ed25519::encrypt(&self.foreign_enc_pubkey, data, &mut rng)?;
let signature = self.config.keypair.sign(&data);
Ok([&signature.to_bytes(), &*data].concat())
}
}
pub async fn connect(config: PathBuf, ip: SocketAddr) -> anyhow::Result<()> {
let config = fs::read(&config).await?;
let config: ClientConfig = rmp_serde::from_slice(&config)?;
@@ -21,7 +55,84 @@ pub async fn connect(config: PathBuf, ip: SocketAddr) -> anyhow::Result<()> {
let connect_signature = config.keypair.sign(CONNECT_MESSAGE).to_bytes();
let connect_msg = &[&connect_signature, CONNECT_MESSAGE].concat();
remote.send_to(connect_msg, ip).await?;
let mut counter = 0;
let (foreign_sign_pubkey, foreign_enc_pubkey, capabilities) = loop {
if counter > 5 {
bail!("could not connect to server");
}
remote.send_to(connect_msg, ip).await?;
let mut buf = [0u8; 2000];
match tokio::time::timeout(
std::time::Duration::from_millis(250),
remote.recv_from(&mut buf),
)
.await
{
Ok(packet) => {
let (count, addr) = packet?;
if addr != ip {
bail!("received response from wrong source");
}
let data = &buf[..count];
if data.len() < 65 {
bail!("could not get signature from server");
}
let signature: [u8; 64] = data[..64].try_into().unwrap();
let data = &data[64..];
let Ok(foreign_keys) = ecies_ed25519::decrypt(&config.enc_privkey, data) else {
counter += 1;
continue;
};
if foreign_keys.len()
< ed25519_dalek::PUBLIC_KEY_LENGTH + ecies_ed25519::PUBLIC_KEY_LENGTH
{
bail!("could not get public keys from the server");
}
let foreign_sign_pubkey = ed25519_dalek::PublicKey::from_bytes(
&foreign_keys[..ed25519_dalek::PUBLIC_KEY_LENGTH],
)?;
let foreign_enc_pubkey = ecies_ed25519::PublicKey::from_bytes(
&foreign_keys[ed25519_dalek::PUBLIC_KEY_LENGTH
..(ed25519_dalek::PUBLIC_KEY_LENGTH + ecies_ed25519::PUBLIC_KEY_LENGTH)],
)?;
let capabilities: Capabilities = rmp_serde::from_slice(
&foreign_keys
[(ed25519_dalek::PUBLIC_KEY_LENGTH + ecies_ed25519::PUBLIC_KEY_LENGTH)..],
)?;
foreign_sign_pubkey.verify(data, &Signature::from(signature))?;
break (foreign_sign_pubkey, foreign_enc_pubkey, capabilities);
}
Err(_) => {
counter += 1;
}
}
};
let connection = Connection {
config,
foreign_enc_pubkey,
foreign_sign_pubkey,
};
remote
.send_to(&connection.encrypt_and_sign(CONNECTED_MESSAGE)?, ip)
.await?;
println!("connected! {:?}", capabilities);
Ok(())
}

View File

@@ -16,6 +16,7 @@ pub const SPARSE_SERVER_BINARY: &'static [u8] =
pub async fn generate(mut name: PathBuf, port: u16) -> anyhow::Result<()> {
let mut csprng = rand::thread_rng();
let keypair = Keypair::generate(&mut csprng);
let (enc_privkey, enc_pubkey) = ecies_ed25519::generate_keypair(&mut csprng);
let mut file = fs::OpenOptions::new()
.write(true)
@@ -28,11 +29,17 @@ pub async fn generate(mut name: PathBuf, port: u16) -> anyhow::Result<()> {
file.write_all(CONFIG_SEPARATOR).await?;
file.write_all(&port.to_be_bytes()[..]).await?;
file.write_all(keypair.public.as_bytes()).await?;
file.write_all(enc_pubkey.as_bytes()).await?;
let config = ClientConfig { keypair, port };
let config = ClientConfig {
keypair,
enc_privkey,
enc_pubkey,
port,
};
let mut file_part = name.file_name().unwrap().to_owned();
file_part.push(OsString::from(".conf"));
file_part.push(OsString::from(".scon"));
name.pop();
name.push(file_part);
let mut file = fs::OpenOptions::new()

View File

@@ -4,5 +4,7 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct ClientConfig {
pub keypair: Keypair,
pub enc_pubkey: ecies_ed25519::PublicKey,
pub enc_privkey: ecies_ed25519::SecretKey,
pub port: u16,
}