New MAJOR version

This commit is contained in:
vanten-s 2023-10-12 13:59:07 +02:00
parent 87f2b142c9
commit df0b58018d
Signed by: vanten-s
GPG key ID: DE3060396884D3F2
9 changed files with 314 additions and 221 deletions

17
Cargo.lock generated
View file

@ -437,6 +437,16 @@ dependencies = [
"zeroize",
]
[[package]]
name = "eyre"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb"
dependencies = [
"indenter",
"once_cell",
]
[[package]]
name = "ff"
version = "0.13.0"
@ -579,6 +589,12 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "indenter"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
[[package]]
name = "inout"
version = "0.1.3"
@ -593,6 +609,7 @@ name = "irc-e2e"
version = "0.1.0"
dependencies = [
"base64",
"eyre",
"ircparser",
"openssl",
"pgp",

View file

@ -7,6 +7,7 @@ edition = "2021"
[dependencies]
base64 = "0.21.4"
eyre = "0.6.8"
ircparser = "0.2.1"
openssl = "0.10"
pgp = "0.10.2"

49
src/client_handler.rs Normal file
View file

@ -0,0 +1,49 @@
use crate::helpers::bytes_to_privmsg_base64;
use crate::{encryption, helpers};
use pgp::{Deserializable, SignedPublicKey};
use std::collections::HashMap;
use std::sync::mpsc::{Receiver, Sender};
use eyre::Result;
pub fn handle_message_from_client(
recieved: &str,
public_key: &Vec<u8>,
server: &str,
keys: &mut HashMap<String, SignedPublicKey>,
writer_channel_tx: &Sender<String>,
writer_channel_rx: &Receiver<String>,
listener_channel_tx: &Sender<String>,
_listener_channel_rx: &Receiver<String>,
) -> Result<()> {
let command = &ircparser::parse(recieved).expect("Got an invalid IRC instruction")[0];
if command.command == "PRIVMSG" && !command.params[0].starts_with("#") {
let other = &command.params[0];
if !keys.contains_key(other) {
helpers::send_key(writer_channel_tx, other, public_key)?;
let key = helpers::recieve_message_base64(
writer_channel_rx,
listener_channel_tx,
"127.0.0.1",
server,
&other,
"END_KEY",
)?;
let key = SignedPublicKey::from_bytes(key.as_slice())?;
keys.insert(other.to_string(), key);
}
let foreign_key = keys.get(other).unwrap();
writer_channel_tx.send(format!("PRIVMSG {other} START_MESSAGE\r\n"))?;
writer_channel_tx.send(bytes_to_privmsg_base64(
&encryption::encrypt(&foreign_key, &command.params[1])?,
other,
))?;
writer_channel_tx.send(format!("PRIVMSG {other} END_MESSAGE\r\n"))?;
} else {
writer_channel_tx.send(recieved.replace("127.0.0.1", &server))?;
}
Ok(())
}

29
src/encryption.rs Normal file
View file

@ -0,0 +1,29 @@
use pgp::crypto::sym::SymmetricKeyAlgorithm;
use pgp::ser::Serialize;
use pgp::{Deserializable, Message, SignedPublicKey, SignedSecretKey};
use rand::prelude::*;
use eyre::Result;
pub fn encrypt(key: &SignedPublicKey, message: &str) -> Result<Vec<u8>, pgp::errors::Error> {
let message = Message::new_literal("none", message);
let mut rng = StdRng::from_entropy();
let message = message.encrypt_to_keys(&mut rng, SymmetricKeyAlgorithm::AES128, &[key])?;
Ok(message.to_bytes()?)
}
pub fn decrypt<'a>(
key: &'a SignedSecretKey,
message: Vec<u8>,
password: &'a str,
) -> Result<String, pgp::errors::Error> {
let message = Message::from_bytes(message.as_slice())?; // Convert message bytes to message object
let message = message.decrypt(|| password.to_string(), &[key])?.0; // Decrypt
let message = message.map(|x| x.unwrap()).collect::<Vec<Message>>(); // Get all messages
let message = &message[0]; // Get first message
let message = message.get_content()?.unwrap_or(Vec::new()); // Get message content as Vec<u8>
let message = String::from_utf8(message).unwrap(); // Convert to String
Ok(message)
}

92
src/helpers.rs Normal file
View file

@ -0,0 +1,92 @@
use base64::{engine::general_purpose, Engine as _};
use std::sync::mpsc::{self, Receiver, Sender};
use eyre::Result;
use ircparser;
static MAX_LENGTH: usize = 300;
fn forward(
message: &str,
stream: &Sender<String>,
server_local: &str,
server_forward: &str,
) -> Result<(), mpsc::SendError<String>> {
if ircparser::parse(message).unwrap()[0].command == "PRIVMSG" {
return Ok(())
}
stream.send(message.replace(&server_local, server_forward))
}
pub fn bytes_to_privmsg_base64(message: &Vec<u8>, reciever: &str) -> String {
let message_length = MAX_LENGTH - format!("PRIVMSG {reciever} :\r\n").len();
let encoded = general_purpose::STANDARD.encode(message);
let mut command = String::new();
for line in encoded
.chars()
.collect::<Vec<char>>()
.chunks(message_length)
.map(|c| c.iter().collect::<String>())
{
dbg!(&line);
command.push_str(&format!("PRIVMSG {reciever} :{line}\r\n"));
}
println!("{}", encoded);
println!("{}", command);
command
}
pub fn send_key(
sender: &Sender<String>,
reciever: &str,
key: &Vec<u8>,
) -> Result<()> {
sender.send(format!("PRIVMSG {reciever} :START_KEY\r\n"))?;
sender.send(bytes_to_privmsg_base64(key, reciever))?;
sender.send(format!("PRIVMSG {reciever} :END_KEY\r\n"))?;
Ok(())
}
pub fn get_nick(userstring: &str) -> String {
let userstring = userstring.chars().collect::<Vec<char>>();
let start_pos = userstring.iter().position(|&x| x == ':').unwrap() + 1;
let end_pos = userstring.iter().position(|&x| x == '!').unwrap();
userstring[start_pos..end_pos].iter().collect::<String>()
}
pub fn recieve_message_base64(
writer_channel_rx: &Receiver<String>,
forward_stream: &Sender<String>,
server_local: &str,
server_forward: &str,
sender: &str,
end: &str,
) -> Result<Vec<u8>> {
let mut message: Vec<String> = Vec::new();
while !message.contains(&end.to_string()) {
let recieved_raw = writer_channel_rx.recv()?;
let recieved = &ircparser::parse(&recieved_raw).unwrap()[0];
let begin_source_reciever = format!(":{sender}!");
if recieved.command != "PRIVMSG"
|| !recieved
.source
.clone()
.unwrap_or("".to_string())
.starts_with(&begin_source_reciever) || recieved.params[0].starts_with("#")
{
forward(&recieved_raw, forward_stream, server_local, server_forward)?;
continue;
}
message.push(recieved.params[1].clone());
}
message.pop();
let foreign_key = dbg!(message.concat());
let foreign_key = general_purpose::STANDARD.decode(foreign_key)?;
Ok(foreign_key)
}

View file

@ -1,6 +1,8 @@
use std::io::{ErrorKind, Read, Write};
use std::net::TcpListener;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
pub fn listen_to_client(tx: mpsc::Sender<String>, rx: mpsc::Receiver<String>, port: &str) {
let listener = TcpListener::bind("127.0.0.1:".to_string() + port).unwrap();
@ -19,7 +21,7 @@ pub fn listen_to_client(tx: mpsc::Sender<String>, rx: mpsc::Receiver<String>, po
match stream.read(&mut buf) {
Ok(_length) => buffer.push(buf[0]),
Err(_error) => match _error.kind() {
ErrorKind::WouldBlock => {},
ErrorKind::WouldBlock => {}
_ => {
dbg!(_error);
}
@ -37,5 +39,6 @@ pub fn listen_to_client(tx: mpsc::Sender<String>, rx: mpsc::Receiver<String>, po
}
let _ = tx.send(String::from_utf8_lossy(&buffer).to_string());
thread::sleep(Duration::from_millis(100));
}
}

View file

@ -1,81 +1,20 @@
use base64::{engine::general_purpose, Engine as _};
use ircparser;
use pgp::crypto::sym::SymmetricKeyAlgorithm;
use pgp::ser::Serialize;
use pgp::{Deserializable, Message, SignedPublicKey, SignedSecretKey};
use rand::prelude::*;
use pgp::{Deserializable, SignedPublicKey, SignedSecretKey};
use std::collections::HashMap;
use std::net::{Shutdown, TcpStream};
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
use std::{env, fs};
use eyre::Result;
mod client_handler;
mod encryption;
mod helpers;
mod listener_server;
mod server_handler;
mod writer_client;
macro_rules! try_recv {
($rx:ident) => {
match $rx.try_recv() {
Ok(recieved) => recieved,
Err(_e) => match _e {
mpsc::TryRecvError::Empty => String::new(),
mpsc::TryRecvError::Disconnected => {
panic!("Error!")
}
},
}
};
}
fn bytes_to_privmsg_base64(message: Vec<u8>, reciever: &str) -> String {
let mut command = String::new();
for line in general_purpose::STANDARD
.encode(message)
.chars()
.collect::<Vec<char>>()
.chunks(500)
.map(|c| c.iter().collect::<String>())
{
command.push_str(&format!("PRIVMSG {reciever} :{line}\r\n"));
}
println!("{}", command);
command
}
fn encrypt(key: &SignedPublicKey, message: &str) -> Result<Vec<u8>, pgp::errors::Error> {
let message = Message::new_literal("none", message);
let mut rng = StdRng::from_entropy();
let message = message.encrypt_to_keys(&mut rng, SymmetricKeyAlgorithm::AES128, &[key])?;
Ok(message.to_bytes()?)
}
fn decrypt<'a>(
key: &'a SignedSecretKey,
message: Vec<u8>,
password: &'a str,
) -> Result<String, pgp::errors::Error> {
let message = Message::from_bytes(message.as_slice())?; // Convert message bytes to message object
let message = message.decrypt(|| password.to_string(), &[key])?.0; // Decrypt
let message = message.map(|x| x.unwrap()).collect::<Vec<Message>>(); // Get all messages
let message = &message[0]; // Get first message
let message = message.get_content()?.unwrap_or(Vec::new()); // Get message content as Vec<u8>
let message = String::from_utf8(message).unwrap(); // Convert to String
Ok(message)
}
fn get_nick(userstring: &str) -> String {
let userstring = userstring.chars().collect::<Vec<char>>();
let start_pos = userstring.iter().position(|&x| x == ':').unwrap() + 1;
let end_pos = userstring.iter().position(|&x| x == '!').unwrap();
userstring[start_pos..end_pos].iter().collect::<String>()
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
fn main() -> Result<()> {
let mut args = env::args().collect::<Vec<String>>();
let server = args[1].clone();
@ -126,161 +65,44 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
});
let mut keys: HashMap<String, SignedPublicKey> = HashMap::new();
let mut userstring = String::new();
loop {
let recieved = try_recv!(listener_channel_rx);
match listener_channel_rx.try_recv() {
Ok(message) => client_handler::handle_message_from_client(
&message,
&public_key,
&server,
&mut keys,
&writer_channel_tx,
&writer_channel_rx,
&listener_channel_tx,
&listener_channel_rx,
)?,
Err(error) => match error {
mpsc::TryRecvError::Empty => {}
mpsc::TryRecvError::Disconnected => panic!("listener_channel_rx disconnected"),
},
};
if !recieved.is_empty() {
let command = &ircparser::parse(&recieved).expect("Got an invalid IRC instruction")[0];
match writer_channel_rx.try_recv() {
Ok(message) => server_handler::handle_message_from_server(
&message,
&public_key,
&secret_key,
&server,
&passwd,
&mut keys,
&writer_channel_tx,
&writer_channel_rx,
&listener_channel_tx,
&listener_channel_rx,
)?,
Err(error) => match error {
mpsc::TryRecvError::Empty => {}
mpsc::TryRecvError::Disconnected => panic!("writer_channel_rx disconnected"),
},
};
if command.command == "PRIVMSG" && !command.params[0].starts_with("#") {
let reciever = &command.params[0];
if !keys.contains_key(reciever) {
writer_channel_tx.send(format!("PRIVMSG {reciever} :START_KEY\r\n"))?;
writer_channel_tx
.send(bytes_to_privmsg_base64(public_key.clone(), reciever))?;
writer_channel_tx.send(format!("PRIVMSG {reciever} :END_KEY\r\n"))?;
let mut foreign_key: Vec<String> = Vec::new();
while !foreign_key.contains(&"END_KEY".to_string()) {
let recieved_raw = writer_channel_rx.recv()?;
let recieved = &ircparser::parse(&recieved_raw).unwrap()[0];
let begin_source_reciever = format!(":{reciever}!");
if recieved.command != "PRIVMSG"
|| !recieved
.source
.clone()
.unwrap_or("".to_string())
.starts_with(&begin_source_reciever)
{
listener_channel_tx.send(recieved_raw)?;
continue;
}
foreign_key.push(recieved.params[1].clone());
}
foreign_key.pop();
println!("Got a foreign key from {reciever}");
let foreign_key = foreign_key.concat();
dbg!(&foreign_key);
let foreign_key = general_purpose::STANDARD.decode(foreign_key)?;
dbg!("It's decoded");
let key = SignedPublicKey::from_bytes(foreign_key.as_slice())?;
dbg!("And I now got it's SignedPublicKey format");
keys.insert(reciever.to_string(), key);
}
let foreign_key = keys.get(reciever).unwrap();
writer_channel_tx.send(format!("PRIVMSG {reciever} START_MESSAGE\r\n"))?;
writer_channel_tx.send(bytes_to_privmsg_base64(
encrypt(&foreign_key, &command.params[1])?,
reciever,
))?;
writer_channel_tx.send(format!("PRIVMSG {reciever} END_MESSAGE\r\n"))?;
} else {
writer_channel_tx.send(recieved.replace("127.0.0.1", &server))?;
}
}
let recieved = try_recv!(writer_channel_rx);
if !recieved.is_empty() {
let recieved_parsed = &ircparser::parse(&recieved).unwrap()[0];
if recieved_parsed.command != "PRIVMSG"
|| recieved_parsed
.params
.get(0)
.unwrap_or(&String::new())
.starts_with("#")
{
listener_channel_tx.send(recieved.replace(&server, "127.0.0.1"))?;
continue;
}
dbg!(&recieved_parsed);
if recieved_parsed.params[1] == "START_MESSAGE" {
let reciever = get_nick(&recieved_parsed.source.clone().unwrap());
let sample_privmsg = recieved.clone();
let mut encrypted_message: Vec<String> = Vec::new();
while !encrypted_message.contains(&"END_MESSAGE".to_string()) {
let recieved_raw = writer_channel_rx.recv()?;
let recieved = &ircparser::parse(&recieved_raw).unwrap()[0];
let begin_source_reciever = format!(":{reciever}!");
if recieved.command != "PRIVMSG"
|| !recieved
.source
.clone()
.unwrap_or("".to_string())
.starts_with(&begin_source_reciever)
{
listener_channel_tx.send(recieved_raw.replace(&server, "127.0.0.1"))?;
continue;
}
encrypted_message.push(recieved.params[1].clone());
}
encrypted_message.pop();
let encrypted_message = encrypted_message.join("");
let encrypted_message = general_purpose::STANDARD.decode(encrypted_message)?;
let decrypted_message = decrypt(&secret_key, encrypted_message, &passwd)?;
listener_channel_tx
.send(sample_privmsg.replace("START_MESSAGE", &decrypted_message))?;
} else if recieved_parsed.params[1] == "START_KEY" {
let reciever = get_nick(&recieved_parsed.source.clone().unwrap());
let to_send = bytes_to_privmsg_base64(public_key.clone(), &reciever);
writer_channel_tx.send(to_send)?;
writer_channel_tx.send(format!("PRIVMSG {reciever} END_KEY\r\n"))?;
dbg!("Started Getting a key");
let reciever = get_nick(&recieved_parsed.source.clone().unwrap());
let mut foreign_key: Vec<String> = Vec::new();
while !foreign_key.contains(&"END_KEY".to_string()) {
let recieved_raw = writer_channel_rx.recv()?;
let recieved = &ircparser::parse(&recieved_raw).unwrap()[0];
let begin_source_reciever = format!(":{reciever}!");
if recieved.command != "PRIVMSG"
|| !recieved
.source
.clone()
.unwrap_or("".to_string())
.starts_with(&begin_source_reciever)
{
listener_channel_tx.send(recieved_raw.replace(&server, "127.0.0.1"))?;
continue;
}
foreign_key.push(recieved.params[1].clone());
}
foreign_key.pop();
dbg!("Got a foreign key from");
dbg!(&reciever);
let foreign_key = foreign_key.concat();
let foreign_key = general_purpose::STANDARD.decode(foreign_key)?;
dbg!("Decoded the key");
let key = SignedPublicKey::from_bytes(foreign_key.as_slice())?;
dbg!("Deserialized the key");
keys.insert(reciever.to_string(), key);
}
}
thread::sleep(Duration::from_millis(100));
}
}

77
src/server_handler.rs Normal file
View file

@ -0,0 +1,77 @@
use crate::{encryption, helpers};
use pgp::{Deserializable, SignedPublicKey, SignedSecretKey};
use std::collections::HashMap;
use std::sync::mpsc::{self, Receiver, Sender};
use eyre::Result as Result;
fn forward(
message: &str,
listener_channel_tx: &Sender<String>,
server: &str,
) -> Result<(), mpsc::SendError<String>> {
listener_channel_tx.send(message.replace(&server, "127.0.0.1"))
}
pub fn handle_message_from_server(
recieved: &str,
public_key: &Vec<u8>,
secret_key: &SignedSecretKey,
server: &str,
passwd: &str,
keys: &mut HashMap<String, SignedPublicKey>,
writer_channel_tx: &Sender<String>,
writer_channel_rx: &Receiver<String>,
listener_channel_tx: &Sender<String>,
_listener_channel_rx: &Receiver<String>,
) -> Result<()> {
let recieved_parsed = &ircparser::parse(&recieved).unwrap()[0];
if recieved_parsed.command != "PRIVMSG"
|| recieved_parsed
.params
.get(0)
.unwrap_or(&String::new())
.starts_with("#")
{
forward(recieved, listener_channel_tx, server)?;
return Ok(());
}
dbg!(&recieved_parsed);
if recieved_parsed.params[1] == "START_MESSAGE" {
let sender = helpers::get_nick(&recieved_parsed.source.clone().unwrap());
let message = helpers::recieve_message_base64(
writer_channel_rx,
listener_channel_tx,
&server,
"127.0.0.1",
&sender,
"END_MESSAGE",
)?; // Get
let message = encryption::decrypt(&secret_key, message, &passwd)?; // Decrypt
listener_channel_tx.send(recieved.replace("START_MESSAGE", &message))?; // Send
} else if recieved_parsed.params[1] == "START_KEY" {
let sender = helpers::get_nick(&recieved_parsed.source.clone().unwrap());
let to_send = helpers::bytes_to_privmsg_base64(&public_key, &sender);
writer_channel_tx.send(to_send)?;
writer_channel_tx.send(format!("PRIVMSG {sender} END_KEY\r\n"))?;
let foreign_key = helpers::recieve_message_base64(
writer_channel_rx,
listener_channel_tx,
&server,
"127.0.0.1",
&sender,
"END_KEY",
)?;
dbg!(&foreign_key);
let key = SignedPublicKey::from_bytes(foreign_key.as_slice())?;
println!("Got a key from {sender}");
keys.insert(sender.to_string(), key);
}
Ok(())
}

View file

@ -2,6 +2,8 @@ use openssl::ssl::{SslConnector, SslMethod};
use std::io::{ErrorKind, Write};
use std::net::TcpStream;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
pub fn write_to_server(
tcp_stream: TcpStream,
@ -52,5 +54,6 @@ pub fn write_to_server(
}
let _ = tx.send(dbg!(String::from_utf8_lossy(&buffer).to_string()));
thread::sleep(Duration::from_millis(100));
}
}