| @@ -1,8 +1,11 @@ | |||
| // namespacing | |||
| use crate::{Packet, PacketKind, Result}; | |||
| use chrono::prelude::*; | |||
| use serde::{Deserialize, Serialize}; | |||
| use uuid::Uuid; | |||
| /// packet to be used when server/client are coming to an agreement on | |||
| /// encryption key material | |||
| #[derive(Debug, Clone, Serialize, Deserialize)] | |||
| pub struct Agreement { | |||
| pub timestamp: i64, | |||
| @@ -11,10 +14,15 @@ pub struct Agreement { | |||
| } | |||
| impl Agreement { | |||
| /// creates a new agreement packet from a public key | |||
| pub fn new(public_key: Vec<u8>) -> Agreement { | |||
| let timestamp = Utc::now().timestamp(); | |||
| let message_id = Uuid::new_v4().as_u128(); | |||
| Agreement { timestamp, message_id, public_key } | |||
| Agreement { | |||
| timestamp, | |||
| message_id, | |||
| public_key, | |||
| } | |||
| } | |||
| } | |||
| @@ -1,13 +1,20 @@ | |||
| // namespacing | |||
| use crate::Packet; | |||
| use crate::Result; | |||
| use orion::aead::{self, SecretKey}; | |||
| use ring::digest; | |||
| /// trait that allows for me to be lazy | |||
| pub trait Encryption { | |||
| /// return the encryption kind | |||
| fn kind(&self) -> EncryptKind; | |||
| /// returns Option<SecretKey> | |||
| fn key(&self) -> Option<&SecretKey>; | |||
| fn encrypt(&self, packet: Packet) -> Packet; | |||
| fn decrypt(&self, packet: Packet) -> Packet; | |||
| /// encrypts the packet contents and updates the integrity hash | |||
| fn encrypt(&self, packet: &mut Packet) -> Result<()>; | |||
| /// decrypts the packet contents, should only be used after integrity is | |||
| /// validated | |||
| fn decrypt(&self, packet: &mut Packet) -> Result<()>; | |||
| } | |||
| /// uses ring's aead module | |||
| @@ -22,20 +29,27 @@ impl Encryption for SymmetricEncrypt { | |||
| Some(&self.0) | |||
| } | |||
| fn encrypt(&self, _packet: Packet) -> Packet { | |||
| todo!() | |||
| fn encrypt(&self, packet: &mut Packet) -> Result<()> { | |||
| packet.contents = aead::seal(self.key().unwrap(), &packet.contents)?; | |||
| packet.integrity_hash = digest::digest(&digest::SHA256, &packet.contents) | |||
| .as_ref() | |||
| .to_vec(); | |||
| Ok(()) | |||
| } | |||
| fn decrypt(&self, _packet: Packet) -> Packet { | |||
| todo!() | |||
| fn decrypt(&self, packet: &mut Packet) -> Result<()> { | |||
| packet.contents = aead::open(self.key().unwrap(), &packet.contents)?; | |||
| Ok(()) | |||
| } | |||
| } | |||
| impl SymmetricEncrypt { | |||
| /// creates a new symmetric encryption key wrapper struct | |||
| pub fn new(key: SecretKey) -> SymmetricEncrypt { | |||
| SymmetricEncrypt(key) | |||
| } | |||
| #[doc(hidden)] | |||
| /// dear future izzy, this is a really bad idea | |||
| pub fn clone(&self) -> Result<SymmetricEncrypt> { | |||
| Ok(SymmetricEncrypt::new(aead::SecretKey::from_slice( | |||
| @@ -47,6 +61,13 @@ impl SymmetricEncrypt { | |||
| /// literally not encryption whatsoever | |||
| pub struct NoEncrypt; | |||
| impl NoEncrypt { | |||
| /// why | |||
| pub fn new() -> NoEncrypt { | |||
| NoEncrypt | |||
| } | |||
| } | |||
| impl Encryption for NoEncrypt { | |||
| fn kind(&self) -> EncryptKind { | |||
| EncryptKind::None | |||
| @@ -58,19 +79,13 @@ impl Encryption for NoEncrypt { | |||
| } | |||
| // lol | |||
| fn encrypt(&self, packet: Packet) -> Packet { | |||
| packet | |||
| fn encrypt(&self, _packet: &mut Packet) -> Result<()> { | |||
| Ok(()) | |||
| } | |||
| // lol | |||
| fn decrypt(&self, packet: Packet) -> Packet { | |||
| packet | |||
| } | |||
| } | |||
| impl NoEncrypt { | |||
| pub fn new() -> NoEncrypt { | |||
| NoEncrypt | |||
| fn decrypt(&self, _packet: &mut Packet) -> Result<()> { | |||
| Ok(()) | |||
| } | |||
| } | |||
| @@ -15,6 +15,7 @@ | |||
| //! | `u64::MAX` | packet contents | | |||
| //! | |||
| // modules | |||
| mod message; | |||
| pub use message::Message; | |||
| mod agreement; | |||
| @@ -22,16 +23,18 @@ pub use agreement::Agreement; | |||
| /// encryption types and functions | |||
| pub mod encrypt; | |||
| // namespacing | |||
| use encrypt::{EncryptKind, Encryption}; | |||
| use futures_util::io::{AsyncReadExt, AsyncWriteExt}; | |||
| use orion::aead; | |||
| use ring::digest; | |||
| use std::convert::TryInto; | |||
| use std::marker::Unpin; | |||
| use thiserror::Error; | |||
| /// simple result | |||
| pub type Result<T> = std::result::Result<T, IlmpError>; | |||
| // packet that should be streamable | |||
| struct NetworkPacket(Vec<u8>); | |||
| /// a type of data that can be sent | |||
| @@ -73,6 +76,7 @@ impl Packet { | |||
| hasher.finalize() | |||
| } | |||
| // converts a to a network packet to be streamed | |||
| fn to_network_packet(&self) -> NetworkPacket { | |||
| let mut contents: Vec<u8> = Vec::new(); | |||
| @@ -168,15 +172,17 @@ pub enum IlmpError { | |||
| /// reads a `Packet` from a stream | |||
| /// | |||
| /// if `Ok(None)` is returned the stream has been disconnected. | |||
| pub async fn read<S>(stream: &mut S) -> Result<Option<Packet>> | |||
| pub async fn read<S, E>(stream: &mut S, encryption: &E) -> Result<Option<Packet>> | |||
| where | |||
| S: AsyncReadExt + Unpin, | |||
| E: Encryption, | |||
| { | |||
| let mut info_buf = [0u8; 14]; | |||
| let check = stream.read(&mut info_buf).await?; | |||
| if check == 0 { | |||
| return Ok(None); | |||
| } | |||
| print!("reading packet... "); | |||
| let kind = PacketKind::from_u8(info_buf[0]).unwrap(); | |||
| let encrypt_kind = EncryptKind::from_u8(info_buf[1]).unwrap(); | |||
| @@ -189,7 +195,7 @@ where | |||
| let mut contents: Vec<u8> = vec![0; length]; | |||
| stream.read(&mut contents).await?; | |||
| let packet = Packet { | |||
| let mut packet = Packet { | |||
| kind, | |||
| contents, | |||
| integrity_hash, | |||
| @@ -199,6 +205,10 @@ where | |||
| packet.verify_checksum(checksum)?; | |||
| packet.verify_integrity()?; | |||
| if packet.encrypt_kind == EncryptKind::Symmetric { | |||
| encryption.decrypt(&mut packet)?; | |||
| } | |||
| println!("[ Ok ]"); | |||
| Ok(Some(packet)) | |||
| } | |||
| @@ -209,20 +219,20 @@ where | |||
| P: Sendable, | |||
| E: Encryption, | |||
| { | |||
| print!("sending packet... "); | |||
| match encryption.kind() { | |||
| EncryptKind::None => { | |||
| let network_packet = packet.to_packet(encryption.kind())?.to_network_packet(); | |||
| stream.write(&network_packet.0).await?; | |||
| println!("[ Ok ]"); | |||
| Ok(()) | |||
| } | |||
| EncryptKind::Symmetric => { | |||
| let mut packet = packet.to_packet(encryption.kind())?; | |||
| packet.contents = aead::seal(encryption.key().unwrap(), &packet.contents)?; | |||
| packet.integrity_hash = digest::digest(&digest::SHA256, &packet.contents) | |||
| .as_ref() | |||
| .to_vec(); | |||
| encryption.encrypt(&mut packet)?; | |||
| let network_packet = packet.to_network_packet(); | |||
| stream.write(&network_packet.0).await?; | |||
| println!("[ Ok ]"); | |||
| Ok(()) | |||
| } | |||
| } | |||