diff --git a/.gitignore b/.gitignore index 9ebf338..9baea0d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /target -secret.asc -public.asc +secret.gpg +public.gpg diff --git a/Cargo.lock b/Cargo.lock index f6f05be..59d67e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -596,6 +596,7 @@ dependencies = [ "ircparser", "openssl", "pgp", + "rand", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index bec9772..2dbac81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,4 @@ base64 = "0.21.4" ircparser = "0.2.1" openssl = "0.10" pgp = "0.10.2" +rand = "0.8.5" diff --git a/src/main.rs b/src/main.rs index b3b389e..13088b1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,9 @@ 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 std::collections::HashMap; use std::net::{Shutdown, TcpStream}; use std::sync::mpsc; @@ -25,15 +29,51 @@ macro_rules! try_recv { }; } -fn main() -> Result<(), Box> { - let args = env::args(); +fn bytes_to_privmsg_base64(message: Vec, reciever: &str) -> String { + let mut command = String::new(); + for line in general_purpose::STANDARD + .encode(message) + .chars() + .collect::>() + .chunks(50) + .map(|c| c.iter().collect::()) + { + command.push_str(&format!("PRIVMSG {reciever} {line}\n")); + } - let server = args.collect::>()[1].clone(); + command +} + +fn encrypt(key: &SignedPublicKey, message: &str) -> Result, 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(key: &SignedSecretKey, message: Vec, password: &str) -> Result<&str, pgp::errors::Error> { + let message = Message::from_bytes(message.as_slice())?; + + let (message, _) = message.decrypt(|| password.to_string(), &[key])?; + + Ok(String::from_utf8_lossy( + message.get_content()?.unwrap_or(String::new()), + )) +} + +fn main() -> Result<(), Box> { + let args = env::args().collect::>(); + + let server = args[1].clone(); + let default_password = String::new(); + let passwd = args.get(2).unwrap_or(&default_password); let stream = TcpStream::connect(format!("{server}:6697"))?; - let public_key = general_purpose::STANDARD.encode(fs::read("public.asc")?); - let secret_key = general_purpose::STANDARD.encode(fs::read("secret.asc")?); + let public_key = fs::read("public.gpg")?; + let secret_key = SignedSecretKey::from_bytes(fs::read("secret.gpg")?.as_slice())?; let reader_stream = match stream.try_clone() { Ok(stream) => stream, @@ -70,7 +110,8 @@ fn main() -> Result<(), Box> { ) }); - let mut negotiated_users: HashMap = HashMap::new(); + let mut keys: HashMap = HashMap::new(); + let mut userstring: Option = None; loop { let recieved = try_recv!(listener_channel_rx); @@ -79,29 +120,18 @@ fn main() -> Result<(), Box> { let command = &ircparser::parse(&recieved).expect("Got an invalid IRC instruction")[0]; if command.command == "PRIVMSG" && !command.params[0].starts_with("#") { - if !negotiated_users.get(&command.params[0]).is_none() { + let reciever = &command.params[0]; + if !keys.contains_key(reciever) { dbg!(recieved); - let reciever = &command.params[0]; writer_channel_tx.send(format!("PRIVMSG {reciever} START_KEY\n"))?; - for line in public_key - .chars() - .collect::>() - .chunks(50) - .map(|c| c.iter().collect::()) - .collect::>() - { - dbg!(&line); - writer_channel_tx - .send(format!("PRIVMSG {reciever} {}", line.clone() + "\n"))?; - } + writer_channel_tx + .send(bytes_to_privmsg_base64(public_key.clone(), reciever))?; writer_channel_tx.send(format!("PRIVMSG {reciever} END_KEY\n"))?; let mut foreign_key: Vec = Vec::new(); while !foreign_key.contains(&"END_KEY".to_string()) { - dbg!("Trying to recv"); let recieved_raw = writer_channel_rx.recv()?; - dbg!(&recieved_raw); let recieved = &ircparser::parse(&recieved_raw).unwrap()[0]; let begin_source_reciever = format!(":{reciever}!"); @@ -119,7 +149,23 @@ fn main() -> Result<(), Box> { foreign_key.push(recieved.params[1].clone()); } foreign_key.pop(); + let foreign_key = foreign_key.concat(); + + let foreign_key = general_purpose::STANDARD.decode(foreign_key)?; + + let key = SignedPublicKey::from_bytes(foreign_key.as_slice())?; + + keys.insert(reciever.to_string(), key); } + + let foreign_key = keys.get(reciever).unwrap(); + + writer_channel_tx.send("START_MESSAGE".to_string())?; + writer_channel_tx.send(bytes_to_privmsg_base64( + encrypt(&foreign_key, &command.params[1])?, + reciever, + ))?; + writer_channel_tx.send("END_MESSAGE".to_string())?; } else { dbg!(&recieved); writer_channel_tx.send(recieved)?; @@ -128,7 +174,56 @@ fn main() -> Result<(), Box> { let recieved = try_recv!(writer_channel_rx); if recieved != "" { - dbg!(&recieved); + let recieved_parsed = &ircparser::parse(&recieved).unwrap()[0]; + + if recieved_parsed.command != "PRIVMSG" + || recieved_parsed + .params + .get(0) + .unwrap_or(&"".to_string()) + .starts_with("#") + { + continue; + } + + let reciever = recieved_parsed.source.clone(); + let reciever = { + let full_reciever = reciever.unwrap().chars().collect::>(); + let start_pos = full_reciever.iter().position(|&x| x == ':').unwrap() + 1; + let end_pos = full_reciever.iter().position(|&x| x == '!').unwrap(); + full_reciever[start_pos..end_pos].iter().collect::() + }; + + if recieved_parsed.params[1] == "START_MESSAGE" { + let mut encrypted_message: Vec = 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) + { + writer_channel_tx.send(recieved_raw)?; + 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 encrypted_message = Message::from_bytes(encrypted_message.as_slice())?; + + let passwd = passwd.clone(); + let decrypted_message = + encrypted_message.decrypt(|| passwd.to_string(), &[&secret_key]); + } listener_channel_tx.send(recieved)?; } }