aboutsummaryrefslogtreecommitdiffstats
path: root/src/packet_content.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/packet_content.rs')
-rw-r--r--src/packet_content.rs255
1 files changed, 225 insertions, 30 deletions
diff --git a/src/packet_content.rs b/src/packet_content.rs
index 3897f2d..f19d36e 100644
--- a/src/packet_content.rs
+++ b/src/packet_content.rs
@@ -1,7 +1,10 @@
+use std::{fmt::{Debug, Display}, rc::Rc};
+
use chrono::{DateTime, Local, Utc};
+use hex::encode;
use tokio_util::bytes::{Buf, Bytes};
use structdiff::{Difference, StructDiff};
-use crate::crypto::{PublicKey, SharedSecret};
+use crate::{crypto::PublicKey, identity::Keystore};
#[derive(PartialEq, Debug, Clone, Difference)]
#[difference(expose)]
@@ -23,6 +26,24 @@ pub enum PacketContent {
}
impl PacketContent {
+ fn justified_name(&self) -> &str{
+ match self {
+ PacketContent::Request(_) => " REQUEST | ",
+ PacketContent::Response(_) => " RESPONSE | ",
+ PacketContent::Text(_) => " TEXT | ",
+ PacketContent::Ack(_) => " ACK | ",
+ PacketContent::Advert(_) => " ADVERT | ",
+ PacketContent::GroupText(_) => " GROUP TXT | ",
+ PacketContent::GroupData(_) => " GRP. DATA | ",
+ PacketContent::AnonReq(_) => " ANON REQ. | ",
+ PacketContent::Path(_) => " PATH | ",
+ PacketContent::Trace(_) => " TRACE | ",
+ PacketContent::Multipart(_) => " MULTIPART | ",
+ PacketContent::Raw(_) => " RAW | ",
+ PacketContent::Invalid => " INVALID | ",
+ }
+ }
+
pub fn new(header: u8, bytes: Bytes) -> PacketContent {
// Specialize based on the Payload Type from the header
match (header & 0x3C) >> 2 {
@@ -44,6 +65,28 @@ impl PacketContent {
}
}
+impl Display for PacketContent {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str(self.justified_name())?;
+
+ match self {
+ PacketContent::Request(c) => std::fmt::Display::fmt(&c, f),
+ PacketContent::Response(c) => std::fmt::Display::fmt(&c, f),
+ PacketContent::Text(c) => std::fmt::Display::fmt(&c, f),
+ PacketContent::Ack(c) => std::fmt::Display::fmt(&c, f),
+ PacketContent::Advert(c) => std::fmt::Display::fmt(&c, f),
+ PacketContent::GroupText(c) => std::fmt::Display::fmt(&c, f),
+ PacketContent::GroupData(c) => std::fmt::Display::fmt(&c, f),
+ PacketContent::AnonReq(c) => std::fmt::Display::fmt(&c, f),
+ PacketContent::Path(c) => std::fmt::Display::fmt(&c, f),
+ PacketContent::Trace(c) => std::fmt::Display::fmt(&c, f),
+ PacketContent::Multipart(c) => std::fmt::Display::fmt(&c, f),
+ PacketContent::Raw(c) => std::fmt::Display::fmt(&c, f),
+ PacketContent::Invalid => f.write_str("INVALID")
+ }
+ }
+}
+
#[derive(PartialEq, Debug, Clone)]
pub enum NodeType {
Chat,
@@ -101,10 +144,15 @@ impl From<Bytes> for PeerToPeerCipher {
}
impl PeerToPeerCipher {
- pub fn try_decrypt(&mut self, key: SharedSecret) -> bool {
- let decrypt = key.mac_then_decrypt(self.mac, self.ciphertext.clone());
-
- if let Some(cleartext) = decrypt {
+ pub fn try_decrypt(&mut self, keystore: &Keystore) -> bool {
+ let decrypt = keystore.decrypt_and_id_p2p(
+ self.source,
+ self.destination,
+ self.mac,
+ &self.ciphertext
+ );
+
+ if let Some((cleartext, _, _)) = decrypt {
self.cleartext = Some(cleartext);
true
} else {
@@ -121,13 +169,28 @@ pub struct Request {
impl From<Bytes> for Request {
fn from(value: Bytes) -> Self {
-
Request {
cipher: PeerToPeerCipher::from(value)
}
}
}
+impl Display for Request {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_fmt(format_args!("({:2x?}) -> ({:2x?}) MAC: {:4x?} ",
+ self.cipher.source,
+ self.cipher.destination,
+ self.cipher.mac
+ ))?;
+
+ if let Some(cleartext) = &self.cipher.cleartext {
+ f.write_fmt(format_args!("TODO"))
+ } else {
+ f.write_str("ENCRYPTED")
+ }
+ }
+}
+
#[derive(PartialEq, Debug, Clone, Difference)]
#[difference(expose)]
pub struct Response {
@@ -136,14 +199,28 @@ pub struct Response {
impl From<Bytes> for Response {
fn from(value: Bytes) -> Self {
-
-
Response {
cipher: PeerToPeerCipher::from(value)
}
}
}
+impl Display for Response {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_fmt(format_args!("({:2x?}) -> ({:2x?}) MAC: {:4x?} ",
+ self.cipher.source,
+ self.cipher.destination,
+ self.cipher.mac
+ ))?;
+
+ if let Some(cleartext) = &self.cipher.cleartext {
+ f.write_fmt(format_args!(""))
+ } else {
+ f.write_str("ENCRYPTED")
+ }
+ }
+}
+
#[derive(PartialEq, Debug, Clone)]
pub struct Text {
pub(crate) cipher: PeerToPeerCipher,
@@ -155,6 +232,22 @@ impl From<Bytes> for Text {
}
}
+impl Display for Text {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_fmt(format_args!("({:2x?}) -> ({:2x?}) MAC: {:4x?} ",
+ self.cipher.source,
+ self.cipher.destination,
+ self.cipher.mac
+ ))?;
+
+ if let Some(cleartext) = &self.cipher.cleartext {
+ f.write_fmt(format_args!("Cleartext implementation TODO"))
+ } else {
+ f.write_str("ENCRYPTED")
+ }
+ }
+}
+
#[derive(PartialEq, Debug, Clone)]
pub struct Ack {
checksum: u32
@@ -167,6 +260,12 @@ impl From<Bytes> for Ack {
}
}
+impl Display for Ack {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_fmt(format_args!("Checksum: {:4x?}", self.checksum))
+ }
+}
+
#[derive(PartialEq, Debug, Clone, Difference)]
#[difference(expose)]
pub struct Advert {
@@ -256,6 +355,25 @@ impl From<Bytes> for Advert {
}
}
+impl Display for Advert {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.node_type.fmt(f)?;
+ f.write_str(" \"")?;
+ f.write_str(&self.name)?;
+ f.write_fmt(format_args!("\" ({:2x?}) at: ", self.public_key.hash_prefix()))?;
+ std::fmt::Display::fmt(&self.timestamp, f)?;
+
+ match (self.latitude, self.longitude) {
+ (Some(lat), Some(lon)) => {
+ f.write_fmt(format_args!(" location: {}, {}", lat, lon))?;
+ },
+ _ => {},
+ }
+
+ Ok(())
+ }
+}
+
#[derive(PartialEq, Debug, Clone, Difference)]
#[difference(expose)]
pub struct GroupText {
@@ -292,15 +410,17 @@ impl From<Bytes> for GroupText {
}
impl GroupText {
- pub fn try_decrypt(&mut self, key: SharedSecret) -> bool {
- let decrypt_reault = key.mac_then_decrypt(
+ pub fn try_decrypt(&mut self, keysore: &Keystore) -> bool {
+ let decrypt_result = keysore.decrypt_and_id_group(
+ self.hash,
self.mac,
- self.ciphertext.clone()
+ &self.ciphertext
);
- if let Some(cleartext) = decrypt_reault {
- self.cleartext = Some(ClearText::from(cleartext));
-
+ if let Some((cleartext, group)) = decrypt_result {
+ let mut cleartext = ClearText::from(cleartext);
+ cleartext.crypto_recipient = group.name.clone();
+ self.cleartext = Some(cleartext);
true
} else {
false
@@ -308,6 +428,21 @@ impl GroupText {
}
}
+impl Display for GroupText {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ if let Some(cleartext) = &self.cleartext {
+ f.write_fmt(format_args!("({:2x?}) Mac: {:4x?} Group {}: {}",
+ self.hash,
+ self.mac,
+ cleartext.crypto_recipient,
+ cleartext.message.replace("\n", "\\n"))
+ )
+ } else {
+ f.write_fmt(format_args!("({:2x?}) Mac: {:4x?} ENCRYPTED", self.hash, self.mac))
+ }
+ }
+}
+
#[derive(PartialEq, Debug, Clone)]
pub enum MessageType {
Plain,
@@ -331,12 +466,14 @@ impl From<u8> for MessageType {
#[derive(PartialEq, Debug, Clone, Difference)]
#[difference(expose)]
pub struct ClearText {
- timestamp: DateTime<Utc>,
- message_type: MessageType,
- attempts: u8,
- sender_hash: u32,
- sender: Option<String>,
- message: String,
+ pub timestamp: DateTime<Utc>,
+ pub message_type: MessageType,
+ pub attempts: u8,
+ pub sender_hash: u32,
+ pub sender: Option<String>,
+ pub message: String,
+
+ pub crypto_recipient: Rc<String>
}
impl From<Bytes> for ClearText {
@@ -350,6 +487,7 @@ impl From<Bytes> for ClearText {
sender_hash: 0,
sender: None,
message: "".to_string(),
+ crypto_recipient: Rc::new("".to_string()),
};
// Just check for the whole fixed-size part at once
@@ -394,14 +532,20 @@ impl From<Bytes> for GroupData {
}
}
+impl Display for GroupData {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_fmt(format_args!("Payload: {}", encode(&self.payload)))
+ }
+}
+
#[derive(PartialEq, Debug, Clone, Difference)]
#[difference(expose)]
pub struct AnonReq {
- destination: u8,
- public_key: PublicKey,
- pub(crate) mac: u16,
- pub(crate) ciphertext: Bytes,
- request: Option<ClearAnonRequest>,
+ pub dest: u8,
+ pub public_key: PublicKey,
+ pub mac: u16,
+ pub ciphertext: Bytes,
+ pub request: Option<ClearAnonRequest>,
incomplete: bool
}
@@ -410,7 +554,7 @@ impl From<Bytes> for AnonReq {
let mut bytes = value;
let mut anon_req = AnonReq {
- destination: 0x00,
+ dest: 0x00,
public_key: PublicKey::default(),
mac: 0x0000,
ciphertext: Bytes::new(),
@@ -419,7 +563,7 @@ impl From<Bytes> for AnonReq {
};
if bytes.is_empty() { return anon_req; }
- anon_req.destination = bytes.get_u8();
+ anon_req.dest = bytes.get_u8();
if bytes.len() < 32 { return anon_req; }
if let Ok(pub_key) = PublicKey::try_from(bytes.split_to(32)) {
@@ -435,6 +579,18 @@ impl From<Bytes> for AnonReq {
}
}
+impl Display for AnonReq {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_fmt(format_args!("({:2x?}) -> ({:2x?}) MAC: {:4x?} ", self.public_key.hash_prefix(), self.dest, self.mac))?;
+
+ if let Some(cleartext) = &self.request {
+ f.write_fmt(format_args!("at: {} password: \"{}\"", cleartext.timestamp, cleartext.password))
+ } else {
+ f.write_str("ENCRYPTED")
+ }
+ }
+}
+
#[derive(PartialEq, Debug, Clone, Difference)]
#[difference(expose)]
pub struct ClearAnonRequest {
@@ -469,7 +625,6 @@ impl From<Bytes> for ClearAnonRequest {
}
}
-
#[derive(PartialEq, Debug, Clone)]
pub struct Path {
pub(crate) cipher: PeerToPeerCipher,
@@ -483,6 +638,12 @@ impl From<Bytes> for Path {
}
}
+impl Display for Path {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_fmt(format_args!("({:2x?}) -> ({:2x?}) MAC: {:4x?} ", self.cipher.source, self.cipher.destination, self.cipher.mac))
+ }
+}
+
#[derive(PartialEq, Debug, Clone)]
pub struct Trace {
tag: u32,
@@ -518,6 +679,12 @@ impl From<Bytes> for Trace {
}
}
+impl Display for Trace {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_fmt(format_args!("Todo"))
+ }
+}
+
#[derive(PartialEq, Debug, Clone)]
pub struct MultiPart {
payload: Bytes
@@ -529,18 +696,33 @@ impl From<Bytes> for MultiPart {
}
}
+impl Display for MultiPart {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_fmt(format_args!("Todo"))
+ }
+}
+
#[derive(PartialEq, Debug, Clone)]
pub struct Raw {
pub(crate) bytes: Bytes
}
+impl Display for Raw {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Debug::fmt(&self, f)
+ }
+}
+
#[cfg(test)]
mod tests {
+ use std::rc::Rc;
use std::str::FromStr;
use chrono::DateTime;
use hex::decode;
+ use crate::identity::Group;
+ use crate::identity::KeystoreInput;
use crate::packet::*;
use crate::crypto::*;
@@ -791,6 +973,7 @@ mod tests {
message_type: MessageType::Plain,
attempts: 0,
sender_hash: 0,
+ crypto_recipient: Rc::new("Public".to_owned()),
}),
incomplete: false
}),
@@ -798,7 +981,19 @@ mod tests {
};
let mut rhs_packet = Packet::from_str(sample).unwrap();
- _ = rhs_packet.try_decrypt(SharedSecret::new_from_group_secret(Bytes::copy_from_slice(&decode("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap())));
+
+ let keystore = KeystoreInput {
+ identities: vec![],
+ contacts: vec![],
+ groups: vec![
+ Group {
+ name: Rc::new("Public".to_owned()),
+ secret: SharedSecret::from_str("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap()
+ }
+ ]
+ }.compile();
+
+ _ = rhs_packet.try_decrypt(&keystore);
assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet));
}
@@ -854,7 +1049,7 @@ mod tests {
transport: [0, 0],
raw_content: Bytes::copy_from_slice(&decode("1234569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219c8b8fd2db15a7138098557cc291928b4358fa7522ddd41d35c99fb78f0def2b3e673d73d2").unwrap()),
content: PacketContent::AnonReq(AnonReq {
- destination: 0x12,
+ dest: 0x12,
public_key: PublicKey::try_from(Bytes::copy_from_slice(&decode("34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219c8b8f").unwrap())).unwrap(),
mac: 0xd2db,
ciphertext: Bytes::copy_from_slice(&decode("15a7138098557cc291928b4358fa7522ddd41d35c99fb78f0def2b3e673d73d2").unwrap()),