libepf 0.1.0

Simple framework for secure encrypted communication
Documentation
use crate::pki::{EPFCertificate, EPFPKI_PUBLIC_KEY_LENGTH};

use serde::{Deserialize, Serialize};
use std::error::Error;
use tokio::io::AsyncReadExt;

pub const PROTOCOL_VERSION: u32 = 1;

#[derive(Serialize, Deserialize, Clone)]
pub struct EpfMessage {
    pub packet_id: u32,
    pub packet_data: Vec<u8>,
}

pub const PACKET_CLIENT_HELLO: u32 = 1;

#[derive(Serialize, Deserialize)]
pub struct EpfClientHello {
    pub protocol_version: u32,
    pub client_random: [u8; 24],
    pub client_certificate: Option<EPFCertificate>,
    pub client_x25519_public_key: [u8; EPFPKI_PUBLIC_KEY_LENGTH],
}

pub const PACKET_SERVER_HELLO: u32 = 2;

#[derive(Serialize, Deserialize)]
pub struct EpfServerHello {
    pub protocol_version: u32,
    pub server_certificate: EPFCertificate,
    pub server_random: [u8; 16],
    pub server_x25519_public_key: [u8; EPFPKI_PUBLIC_KEY_LENGTH],
}

pub const PACKET_FINISHED: u32 = 3;

#[derive(Serialize, Deserialize)]
pub struct EpfFinished {
    pub protocol_version: u32,
    pub encrypted_0x42: Vec<u8>,
}

pub const PACKET_APPLICATION_DATA: u32 = 4;

#[derive(Serialize, Deserialize)]
pub struct EpfApplicationData {
    pub protocol_version: u32,
    pub encrypted_application_data: Vec<u8>,
    pub nonce: [u8; 24],
}

#[derive(Clone)]
pub enum EpfClientState {
    NotStarted,
    WaitingForServerHello,
    WaitingForFinished,
    Transport,
    Closed,
}

#[derive(Clone)]
pub enum EpfServerState {
    WaitingForClientHello,
    WaitingForFinished,
    Transport,
    Closed,
}

pub fn encode_packet<T: Serialize>(
    id: u32,
    packet: &T,
) -> Result<Vec<u8>, rmp_serde::encode::Error> {
    let message_data = rmp_serde::to_vec(packet)?;
    let message_wrapper = EpfMessage {
        packet_id: id,
        packet_data: message_data,
    };
    let mut packet_data = rmp_serde::to_vec(&message_wrapper)?;

    let mut packet = (packet_data.len() as u64).to_le_bytes().to_vec();
    // Packet: 8-byte little-endian length prefix, packet data
    packet.append(&mut packet_data);
    Ok(packet)
}

pub async fn recv_packet<C: AsyncReadExt + Unpin>(
    stream: &mut C,
) -> Result<EpfMessage, Box<dyn Error>> {
    let packet_length = stream.read_u64_le().await?;

    let mut packet_data_buf = vec![0u8; packet_length as usize];
    stream.read_exact(&mut packet_data_buf).await?;
    let message: EpfMessage = rmp_serde::from_slice(&packet_data_buf)?;
    Ok(message)
}