Browse Source

added CRC32 checksum and a justfile

master
Isabelle L. 5 years ago
parent
commit
18b3c7c1e4
5 changed files with 69 additions and 31 deletions
  1. +1
    -0
      Cargo.toml
  2. +8
    -6
      README.md
  3. +4
    -0
      justfile
  4. +54
    -23
      src/lib.rs
  5. +2
    -2
      src/message.rs

+ 1
- 0
Cargo.toml View File

@@ -14,3 +14,4 @@ chrono = "0.4.11"
ring = "0.16.13"
anyhow = "1.0.30"
thiserror = "1.0.17"
crc32fast = "1.2.0"

+ 8
- 6
README.md View File

@@ -5,9 +5,11 @@
I don't know whether or not this is a super practical way of doing things
but i'm lazy and it seems to work so gonna roll with it lol

| segment size | usage |
|--------------|-------------------------------------|
| 1 byte | u8 signifies the type of packet |
| 8 byte | u64 length of the packet contents |
| 32 byte | SHA256 packet contents checksum |
| `u64::MAX` | packet contents |
| segment size | usage |
|--------------|--------------------------------------------|
| 1 byte | u8 signifies the type of packet |
| 8 byte | u64 length of the packet contents |
| 4 byte | CRC32 packet contents checksum |
| 32 byte | SHA256 packet contents integrity check |
| `u64::MAX` | packet contents |


+ 4
- 0
justfile View File

@@ -0,0 +1,4 @@
alias b := build

build:
cargo build

+ 54
- 23
src/lib.rs View File

@@ -5,12 +5,13 @@
//! I don't know whether or not this is a super practical way of doing things
//! but i'm lazy and it seems to work so gonna roll with it lol
//!
//! | segment size | usage |
//! |--------------|-------------------------------------|
//! | 1 byte | u8 signifies the type of packet |
//! | 8 byte | u64 length of the packet contents |
//! | 32 byte | SHA256 packet contents checksum |
//! | `u64::MAX` | packet contents |
//! | segment size | usage |
//! |--------------|--------------------------------------------|
//! | 1 byte | u8 signifies the type of packet |
//! | 8 byte | u64 length of the packet contents |
//! | 4 byte | CRC32 packet contents checksum |
//! | 32 byte | SHA256 packet contents integrity check |
//! | `u64::MAX` | packet contents |
//!

use futures_util::io::{AsyncReadExt, AsyncWriteExt};
@@ -35,21 +36,33 @@ pub trait Sendable: Sized {
/// data to be sent
pub struct Packet {
kind: PacketKind,
checksum: Vec<u8>,
integrity_hash: Vec<u8>,
contents: Vec<u8>,
}

impl Packet {
/// create a new `Packet`
pub fn new(kind: PacketKind, contents: Vec<u8>) -> Packet {
let checksum = digest::digest(&digest::SHA256, &contents).as_ref().to_vec();
let integrity_hash = digest::digest(&digest::SHA256, &contents).as_ref().to_vec();
Packet {
kind,
checksum,
integrity_hash,
contents,
}
}

// generate a checksum from the packet
fn generate_checksum(&self) -> u32 {
// combine integrity hash and contents
let mut hash_and_contents = self.integrity_hash.clone();
hash_and_contents.extend_from_slice(&self.contents);

// generate checksum
let mut hasher = crc32fast::Hasher::new();
hasher.update(hash_and_contents.as_ref());
hasher.finalize()
}

fn to_network_packet(&self) -> NetworkPacket {
let mut contents: Vec<u8> = Vec::new();

@@ -61,29 +74,43 @@ impl Packet {
contents.extend_from_slice(&contents_length.to_le_bytes());

// write checksum
contents.extend_from_slice(&self.checksum.as_ref());
let checksum = self.generate_checksum();
contents.extend_from_slice(&checksum.to_le_bytes());

// write contents
// write hash and contents
contents.extend_from_slice(&self.integrity_hash);
contents.extend_from_slice(&self.contents);

NetworkPacket(contents)
}

/// verifies SHA256 checksum
/// verifies SHA256 integrity
pub fn verify_integrity(&self) -> Result<()> {
let found = digest::digest(&digest::SHA256, &self.contents)
let expected = digest::digest(&digest::SHA256, &self.contents)
.as_ref()
.to_vec();
if found == self.checksum {

if expected == self.integrity_hash {
Ok(())
} else {
Err(IlmpError::BadChecksumIntegrity {
expected: self.checksum.clone(),
found,
Err(IlmpError::BadHashIntegrity {
found: self.integrity_hash.clone(),
expected,
}
.into())
}
}

/// verifies CRC32 checksum
pub fn verify_checksum(&self, expected: u32) -> Result<()> {
let found = self.generate_checksum();

if found == expected {
Ok(())
} else {
Err(IlmpError::BadChecksumIntegrity { expected, found })
}
}
}

/// kinds of packets that can be sent
@@ -108,7 +135,9 @@ impl PacketKind {
#[derive(Error, Debug)]
pub enum IlmpError {
#[error("checksum integrity check failed: (expected {expected:?} found {found:?})")]
BadChecksumIntegrity { expected: Vec<u8>, found: Vec<u8> },
BadChecksumIntegrity { expected: u32, found: u32 },
#[error("hash integrity check failed: (expected {expected:?} found {found:?})")]
BadHashIntegrity { expected: Vec<u8>, found: Vec<u8> },
#[error("std::io error")]
// external error conversions
StdIo(#[from] std::io::Error),
@@ -125,17 +154,18 @@ pub async fn read<S>(stream: &mut S) -> Result<Option<Packet>>
where
S: AsyncReadExt + Unpin,
{
let mut info_buf = [0u8; 9];
let mut info_buf = [0u8; 13];
let check = stream.read(&mut info_buf).await?;
if check == 0 {
return Ok(None);
}

let kind = PacketKind::from_u8(info_buf[0]).unwrap();
let length = u32::from_le_bytes(info_buf[1..9].try_into().unwrap()) as usize;
let length = u64::from_le_bytes(info_buf[1..9].try_into().unwrap()) as usize;
let checksum = u32::from_le_bytes(info_buf[10..14].try_into().unwrap());

let mut checksum: Vec<u8> = vec![0; 32];
stream.read(&mut checksum).await?;
let mut integrity_hash: Vec<u8> = vec![0; 32];
stream.read(&mut integrity_hash).await?;

let mut contents: Vec<u8> = vec![0; length];
stream.read(&mut contents).await?;
@@ -143,9 +173,10 @@ where
let packet = Packet {
kind,
contents,
checksum,
integrity_hash,
};
packet.verify_integrity()?;
packet.verify_checksum(checksum)?;

Ok(Some(packet))
}


+ 2
- 2
src/message.rs View File

@@ -31,12 +31,12 @@ impl Message {
impl crate::Sendable for Message {
fn to_packet(&self) -> Result<Packet> {
let contents: Vec<u8> = serde_json::to_string(&self)?.into_bytes();
let checksum = digest::digest(&digest::SHA256, &contents).as_ref().to_vec();
let integrity_hash = digest::digest(&digest::SHA256, &contents).as_ref().to_vec();
let kind = PacketKind::Message;

Ok(Packet {
kind,
checksum,
integrity_hash,
contents,
})
}


Loading…
Cancel
Save