Browse Source

8 bit key; PRNG; XOR encryption

master
Gitea 2 years ago
parent
commit
9b4cc60653
  1. 46
      src/crypt/keys.rs
  2. 3
      src/crypt/mod.rs
  3. 20
      src/crypt/rand.rs
  4. 50
      src/crypt/xor.rs
  5. 1
      src/main.rs
  6. 9
      src/nodes/node.rs
  7. 1
      src/protocol/mod.rs
  8. 43
      src/protocol/packets.rs
  9. 35
      src/protocol/specs.rs

46
src/crypt/keys.rs

@ -0,0 +1,46 @@
/*
ddtu - digital data transferring utility
Copyright (C) 2022 Kasyanov Nikolay Alexeyevich (Unbewohnte)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
*/
use crate::crypt::rand;
use std::time::{SystemTime, UNIX_EPOCH};
pub struct Key8bit {
pub k: u8,
}
impl Key8bit {
pub fn new(key: u8) -> Key8bit {
return Key8bit{
k: key,
}
}
pub fn new_random() -> Key8bit {
return Key8bit{
k: rand::rand_u16(SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as u16) as u8,
}
}
}
#[cfg(test)]
mod tests {
use crate::crypt::keys::Key8bit;
#[test]
fn test_key8bit_generation() {
assert_eq!(Key8bit::new(255).k, 255);
Key8bit::new_random();
}
}

3
src/crypt/mod.rs

@ -0,0 +1,3 @@
pub mod keys;
pub mod rand;
pub mod xor;

20
src/protocol/constants.rs → src/crypt/rand.rs

@ -14,9 +14,19 @@ GNU Affero General Public License for more details.
*/ */
pub const CONNECTION_SHUTDOWN_PACKET_ID: u8 = 1; pub fn rand_u16(seed: u16) -> u16 {
pub const TEXT_PACKET_ID: u8 = 2; return ((seed & 47851) + (seed >> 8 | 7943)) as u16;
pub const FILEINFO_PACKET_ID: u8 = 3; }
pub const FILEDATA_PACKET_ID: u8 = 4;
pub const CHUNK_SIZE: usize = 262_144; // 256 KB #[cfg(test)]
mod tests {
use crate::crypt::rand::rand_u16;
#[test]
fn test_rand_u16() {
assert_eq!(rand_u16(10), 7953);
assert_eq!(rand_u16(12345), 20320);
assert_eq!(rand_u16(60000), 51791);
assert_eq!(rand_u16(64550), 55329);
}
}

50
src/crypt/xor.rs

@ -0,0 +1,50 @@
/*
ddtu - digital data transferring utility
Copyright (C) 2022 Kasyanov Nikolay Alexeyevich (Unbewohnte)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
*/
use crate::crypt::keys::Key8bit;
pub fn encrypt(plain: &mut [u8], key: &Key8bit) {
for i in 0..plain.len() {
plain[i] = plain[i] ^ key.k;
}
}
pub fn decrypt(encrypted: &mut[u8], key: &Key8bit) {
for i in 0..encrypted.len() {
encrypted[i] = encrypted[i] ^ key.k;
}
}
#[cfg(test)]
mod tests {
use crate::crypt::keys::Key8bit;
use crate::crypt::xor;
#[test]
fn test_xor() {
let plaintext = "plain text 123";
let mut plaintext_bytes: Vec<u8> = Vec::with_capacity(plaintext.bytes().len());
for b in plaintext.bytes() {
plaintext_bytes.push(b);
}
let key = Key8bit::new(45);
xor::encrypt(&mut plaintext_bytes, &key);
xor::decrypt(&mut plaintext_bytes, &key);
assert_eq!(String::from_utf8_lossy(&plaintext_bytes), plaintext);
}
}

1
src/main.rs

@ -16,6 +16,7 @@ GNU Affero General Public License for more details.
mod util; mod util;
mod protocol; mod protocol;
mod args; mod args;
mod crypt;
mod fsys; mod fsys;
use args::parser::{Args, RunMode}; use args::parser::{Args, RunMode};

9
src/nodes/node.rs

@ -0,0 +1,9 @@
pub struct Node {
}
impl Node {
pub fn new() -> Node {
return Node{};
}
}

1
src/protocol/mod.rs

@ -1,3 +1,2 @@
pub mod packets; pub mod packets;
pub mod constants;
pub mod specs; pub mod specs;

43
src/protocol/packets.rs

@ -15,7 +15,6 @@ GNU Affero General Public License for more details.
use crate::util::error::Error; use crate::util::error::Error;
use crate::util::buf_read::{read_u128_slice, read_utf8_string_slice}; use crate::util::buf_read::{read_u128_slice, read_utf8_string_slice};
use crate::protocol::constants;
use crate::protocol::specs::*; use crate::protocol::specs::*;
use crate::fsys::file::ChunkedFile; use crate::fsys::file::ChunkedFile;
@ -46,7 +45,7 @@ impl Packet for TextPacket {
fn as_bytes(&self) -> Vec<u8> { fn as_bytes(&self) -> Vec<u8> {
let mut packet_as_bytes: Vec<u8> = Vec::<u8>::new(); let mut packet_as_bytes: Vec<u8> = Vec::<u8>::new();
packet_as_bytes.extend_from_slice(&constants::TEXT_PACKET_ID.to_be_bytes()); packet_as_bytes.extend_from_slice(&TEXT_PACKET_ID.to_be_bytes());
let text_length: u128 = self.text.len() as u128; let text_length: u128 = self.text.len() as u128;
packet_as_bytes.extend_from_slice(&text_length.to_be_bytes()); packet_as_bytes.extend_from_slice(&text_length.to_be_bytes());
@ -64,7 +63,7 @@ impl Packet for TextPacket {
// retrieve and check for packet type byte // retrieve and check for packet type byte
match packet_bytes[0].to_be() { match packet_bytes[0].to_be() {
constants::TEXT_PACKET_ID => {} TEXT_PACKET_ID => {}
_ => { _ => {
return Some(Error::new("packet type is not of a text packet")); return Some(Error::new("packet type is not of a text packet"));
} }
@ -207,7 +206,7 @@ impl Packet for FileInfoPacket {
pub struct FileDataPacket { pub struct FileDataPacket {
pub file_id: u128, pub file_id: u128,
pub chunk_no: u128, pub chunk_no: u128,
pub chunk: [u8; constants::CHUNK_SIZE], pub chunk: [u8; CHUNK_SIZE],
} }
impl FileDataPacket { impl FileDataPacket {
@ -215,7 +214,7 @@ impl FileDataPacket {
return FileDataPacket { return FileDataPacket {
file_id: 0, file_id: 0,
chunk_no: 0, chunk_no: 0,
chunk: [0; constants::CHUNK_SIZE], chunk: [0; CHUNK_SIZE],
} }
} }
} }
@ -272,7 +271,39 @@ impl Packet for ConnectionShutdownPacket {
} }
fn as_bytes(&self) -> Vec<u8> { fn as_bytes(&self) -> Vec<u8> {
return vec!(constants::CONNECTION_SHUTDOWN_PACKET_ID.to_be_bytes()[0]); return vec!(CONNECTION_SHUTDOWN_PACKET_ID.to_be_bytes()[0]);
}
fn from_bytes(&mut self, _packet_bytes: Vec<u8>) -> Option<Error> {
return None;
}
}
pub struct HandshakePaket {
pub protocol_version: u8,
pub use_encryption: bool,
pub encryption_type: u8,
pub encryption_key: Vec<u8>,
}
impl HandshakePaket {
fn empty() -> HandshakePaket {
return HandshakePaket{
protocol_version: PROTOCOL_LATEST_VERSION,
use_encryption: false,
encryption_type: ECRYPTION_XOR,
encryption_key: vec!(0, 0, 0, 0, 0, 0, 0, 0),
};
}
}
impl Packet for HandshakePaket {
fn get_type(&self) -> PacketType {
return PacketType::Handshake;
}
fn as_bytes(&self) -> Vec<u8> {
return vec!(HANDSHAKE_PACKET_ID.to_be_bytes()[0]);
} }
fn from_bytes(&mut self, _packet_bytes: Vec<u8>) -> Option<Error> { fn from_bytes(&mut self, _packet_bytes: Vec<u8>) -> Option<Error> {

35
src/protocol/specs.rs

@ -20,10 +20,11 @@ GNU Affero General Public License for more details.
First 16 bytes - the total packet length First 16 bytes - the total packet length
The next 1 byte - number that represents this packet's type (ID) where: The next 1 byte - number that represents this packet's type (ID) where:
1: CONNECTION SHUTDOWN PACKET 1: HANDSHAKE PACKET
2: TEXT PACKET 2: CONNECTION SHUTDOWN PACKET
3: FILEINFO PACKET 3: TEXT PACKET
4: FILEDATA PACKET 4: FILEINFO PACKET
5: FILEDATA PACKET
Then the internal structure varies from one packet type to the other, Then the internal structure varies from one packet type to the other,
but the content-types are encoded as follows: but the content-types are encoded as follows:
@ -34,19 +35,35 @@ String - u128 representing the string length and then UTF-8 encoded character by
*/ */
use crate::util::error::Error; use crate::util::error::Error;
use crate::protocol::constants;
use crate::protocol::packets::*; use crate::protocol::packets::*;
use std::net; use std::net;
use std::io::Write; use std::io::Write;
use std::io::Read; use std::io::Read;
// Protocol versioning
pub const PROTOCOL_LATEST_VERSION: u8 = 1;
// Packets' IDs
pub const HANDSHAKE_PACKET_ID: u8 = 1;
pub const CONNECTION_SHUTDOWN_PACKET_ID: u8 = 2;
pub const TEXT_PACKET_ID: u8 = 3;
pub const FILEINFO_PACKET_ID: u8 = 4;
pub const FILEDATA_PACKET_ID: u8 = 5;
// File chunk size
pub const CHUNK_SIZE: usize = 262_144; // 256 KB
// Encryption types
pub const ECRYPTION_XOR: u8 = 1;
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
pub enum PacketType { pub enum PacketType {
ConnectionShutdown, ConnectionShutdown,
TextData, TextData,
FileInfo, FileInfo,
FileData, FileData,
Handshake,
} }
pub trait Packet { pub trait Packet {
@ -104,11 +121,11 @@ pub fn read_next_packet(conn: &mut net::TcpStream) -> Result<Box<dyn Packet>, Er
let packet_type_byte: u8 = u8::from_be_bytes([packet_bytes[0]]); let packet_type_byte: u8 = u8::from_be_bytes([packet_bytes[0]]);
match packet_type_byte { match packet_type_byte {
constants::CONNECTION_SHUTDOWN_PACKET_ID => { CONNECTION_SHUTDOWN_PACKET_ID => {
return Ok(Box::new(ConnectionShutdownPacket{})); return Ok(Box::new(ConnectionShutdownPacket{}));
} }
constants::TEXT_PACKET_ID => { TEXT_PACKET_ID => {
let mut new_text_packet: TextPacket = TextPacket::empty(); let mut new_text_packet: TextPacket = TextPacket::empty();
let result = new_text_packet.from_bytes(packet_bytes); let result = new_text_packet.from_bytes(packet_bytes);
match result { match result {
@ -122,7 +139,7 @@ pub fn read_next_packet(conn: &mut net::TcpStream) -> Result<Box<dyn Packet>, Er
} }
} }
constants::FILEINFO_PACKET_ID => { FILEINFO_PACKET_ID => {
let mut new_fileinfo_packet: FileInfoPacket = FileInfoPacket::empty(); let mut new_fileinfo_packet: FileInfoPacket = FileInfoPacket::empty();
let result = new_fileinfo_packet.from_bytes(packet_bytes); let result = new_fileinfo_packet.from_bytes(packet_bytes);
match result { match result {
@ -136,7 +153,7 @@ pub fn read_next_packet(conn: &mut net::TcpStream) -> Result<Box<dyn Packet>, Er
} }
} }
constants::FILEDATA_PACKET_ID => { FILEDATA_PACKET_ID => {
let mut new_filedata_packet: FileDataPacket = FileDataPacket::empty(); let mut new_filedata_packet: FileDataPacket = FileDataPacket::empty();
let result = new_filedata_packet.from_bytes(packet_bytes); let result = new_filedata_packet.from_bytes(packet_bytes);
match result { match result {

Loading…
Cancel
Save