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