commit 7d9739244d504ae5431f3084f6acc2c92f7bdb9b Author: c0repwn3r Date: Wed Jan 25 18:24:51 2023 -0500 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1de5659 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/libsptprp/src/cryptography.rs b/libsptprp/src/cryptography.rs new file mode 100644 index 0000000..dca0e0e --- /dev/null +++ b/libsptprp/src/cryptography.rs @@ -0,0 +1,8 @@ +use blake2::Blake2s256; +use blake2::Digest; + +pub fn HASH(data: &(impl AsRef<[u8]> + ?Sized)) -> [u8; 32] { + let mut hasher = Blake2s256::new(); + hasher.update(data); + hasher.finalize().try_into().unwrap() +} \ No newline at end of file diff --git a/libsptprp/src/packets/clientbound.rs b/libsptprp/src/packets/clientbound.rs new file mode 100644 index 0000000..8ef7ad1 --- /dev/null +++ b/libsptprp/src/packets/clientbound.rs @@ -0,0 +1,53 @@ +use crate::packets::{PacketParseError, SptprpPacket}; + +#[derive(Debug, PartialEq)] +pub struct ChannelNotReadyPacket { + pub channel: [u8; 32] +} +impl SptprpPacket for ChannelNotReadyPacket { + const PACKET_ID: u8 = 0x02; + + fn to_bytes(&self) -> Vec { + let mut bytes = vec![0x02]; + bytes.extend_from_slice(&self.channel); + bytes + } + + fn from_bytes(bytes: &Vec) -> Result { + if bytes.len() != 33 { + return Err(PacketParseError::IncorrectPacketLength) + } + if bytes[0] != 0x02u8 { + return Err(PacketParseError::IncorrectPacketType) + } + Ok(Self { + channel: bytes[1..].try_into().unwrap() + }) + } +} + +#[derive(Debug, PartialEq)] +pub struct ChannelReadyPacket { + pub channel: [u8; 32] +} +impl SptprpPacket for ChannelReadyPacket { + const PACKET_ID: u8 = 0x03; + + fn to_bytes(&self) -> Vec { + let mut bytes = vec![0x03]; + bytes.extend_from_slice(&self.channel); + bytes + } + + fn from_bytes(bytes: &Vec) -> Result { + if bytes.len() != 33 { + return Err(PacketParseError::IncorrectPacketLength) + } + if bytes[0] != 0x03u8 { + return Err(PacketParseError::IncorrectPacketType) + } + Ok(Self { + channel: bytes[1..].try_into().unwrap() + }) + } +} \ No newline at end of file diff --git a/libsptprp/src/packets/initbound.rs b/libsptprp/src/packets/initbound.rs new file mode 100644 index 0000000..e69de29 diff --git a/libsptprp/src/packets/mod.rs b/libsptprp/src/packets/mod.rs new file mode 100644 index 0000000..5951ec9 --- /dev/null +++ b/libsptprp/src/packets/mod.rs @@ -0,0 +1,17 @@ +pub mod clientbound; +pub mod initbound; +pub mod recvbound; +pub mod relaybound; + +#[derive(Debug)] +pub enum PacketParseError { + IncorrectPacketType, + IncorrectPacketLength +} + +pub trait SptprpPacket { + const PACKET_ID: u8; + + fn to_bytes(&self) -> Vec; + fn from_bytes(bytes: &Vec) -> Result where Self: Sized; +} diff --git a/libsptprp/src/packets/recvbound.rs b/libsptprp/src/packets/recvbound.rs new file mode 100644 index 0000000..e69de29 diff --git a/libsptprp/src/packets/relaybound.rs b/libsptprp/src/packets/relaybound.rs new file mode 100644 index 0000000..1109910 --- /dev/null +++ b/libsptprp/src/packets/relaybound.rs @@ -0,0 +1,71 @@ +use crate::packets::{PacketParseError, SptprpPacket}; + +#[derive(Debug, PartialEq)] +pub struct ChannelWaitPacket { + pub channel: [u8; 32] +} +impl SptprpPacket for ChannelWaitPacket { + const PACKET_ID: u8 = 0x01; + + fn to_bytes(&self) -> Vec { + let mut bytes = vec![0x01]; + bytes.extend_from_slice(&self.channel); + bytes + } + + fn from_bytes(bytes: &Vec) -> Result { + if bytes.len() != 33 { + return Err(PacketParseError::IncorrectPacketLength) + } + if bytes[0] != 0x01u8 { + return Err(PacketParseError::IncorrectPacketType) + } + Ok(Self { + channel: bytes[1..].try_into().unwrap() + }) + } +} + +#[derive(Debug, PartialEq)] +pub struct RelayDataPacket { + pub channel: [u8; 32], + pub data_len: u64, + pub data: Vec +} +impl SptprpPacket for RelayDataPacket { + const PACKET_ID: u8 = 0x04; + + fn to_bytes(&self) -> Vec { + let mut bytes = vec![4u8]; + bytes.extend_from_slice(&self.channel); + bytes.extend_from_slice(&self.data_len.to_le_bytes()); + bytes.extend_from_slice(&self.data[..]); + bytes.push(0xfe); + bytes + } + + fn from_bytes(bytes: &Vec) -> Result where Self: Sized { + + if bytes.len() < 42 { + return Err(PacketParseError::IncorrectPacketLength) + } + + if bytes[0] != 0x04 && bytes[bytes.len()-1] != 0xfe { + return Err(PacketParseError::IncorrectPacketType) + } + + let channel = &bytes[1..33]; + let data_len = u64::from_le_bytes(bytes[33..41].try_into().unwrap()); + let data = &bytes[41..41 + data_len as usize]; + + if bytes[40 + data_len as usize + 1] != 0xfe { + return Err(PacketParseError::IncorrectPacketType) + } + + Ok(Self { + channel: channel.try_into().unwrap(), + data_len, + data: data.to_vec(), + }) + } +} \ No newline at end of file diff --git a/libsptprp/src/tests.rs b/libsptprp/src/tests.rs new file mode 100644 index 0000000..8ed32e8 --- /dev/null +++ b/libsptprp/src/tests.rs @@ -0,0 +1,52 @@ +use crate::cryptography::HASH; +use crate::packets::clientbound::{ChannelNotReadyPacket, ChannelReadyPacket}; +use crate::packets::relaybound::{ChannelWaitPacket, RelayDataPacket}; +use crate::packets::SptprpPacket; + +#[test] +pub fn pkt_channel_wait() { + assert_eq!(ChannelWaitPacket { + channel: [0u8; 32], + }.to_bytes(), [1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8]); + assert_eq!(ChannelWaitPacket { + channel: [0u8; 32], + }, ChannelWaitPacket::from_bytes(&vec![1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8]).unwrap()) +} + +#[test] +pub fn pkt_channel_not_ready() { + assert_eq!(ChannelNotReadyPacket { + channel: [0u8; 32], + }.to_bytes(), [2u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8]); + assert_eq!(ChannelNotReadyPacket { + channel: [0u8; 32], + }, ChannelNotReadyPacket::from_bytes(&vec![2u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8]).unwrap()) +} +#[test] +pub fn pkt_channel_ready() { + assert_eq!(ChannelReadyPacket { + channel: [0u8; 32], + }.to_bytes(), [3u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8]); + assert_eq!(ChannelReadyPacket { + channel: [0u8; 32], + }, ChannelReadyPacket::from_bytes(&vec![3u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8]).unwrap()) +} + +#[test] +pub fn hash() { + assert_eq!(HASH("hello"), [25u8, 33, 59, 172, 197, 141, 238, 109, 189, 227, 206, 185, 164, 124, 187, 51, 11, 61, 134, 248, 204, 168, 153, 126, 176, 11, 228, 86, 241, 64, 202, 37]) +} + +#[test] +pub fn pkt_relay() { + assert_eq!(RelayDataPacket { + channel: [0u8; 32], + data_len: 1, + data: vec![42u8], + }.to_bytes(), [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 42, 254]); + assert_eq!(RelayDataPacket { + channel: [0u8; 32], + data_len: 1, + data: vec![42u8] + }, RelayDataPacket::from_bytes(&vec![4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 42, 254]).unwrap()) +} \ No newline at end of file