diff --git a/src/keygen.rs b/src/keygen.rs new file mode 100644 index 0000000..b691fa4 --- /dev/null +++ b/src/keygen.rs @@ -0,0 +1,109 @@ +use core::str; + +use crate::utils::*; + +struct EllipticCurve { + a: i128, + b: i128, + r#mod: i128, +} +impl EllipticCurve { + pub fn new(a: i128, b: i128, r#mod: i128) -> Self { + EllipticCurve { + a: a, + b: b, + r#mod: r#mod, + } + } + + pub fn y(&self, x: i128) -> i128 { + (x.pow(3) + self.b * x + self.a) % self.r#mod + } + pub fn random(&self) -> (i128, i128) { + let mut start = rand::random::() % self.r#mod; + let i_count = rand::random::(); + + for _ in 0..i_count { + start = self.y(start); + } + + (start, self.y(start)) + } +} + +pub struct Person { + pub name: String, + private_key: Option, + pub public_key: Option, + pub shared_key: Option, +} +impl Person { + pub fn new(name: &str) -> Self { + Person { + name: name.to_string(), + private_key: None, + public_key: None, + shared_key: None, + } + } + + pub fn gen_keys(&mut self, start: u32, r#mod: u32) { + let private = rand::random::(); + self.private_key = Some(private.into()); + let public = mod_pow(start, private.into(), r#mod); + self.public_key = Some(public); + eprintln!( + "{}: private: {} -> public: {}", + self.name, + self.private_key.unwrap(), + self.public_key.unwrap() + ); + } + + pub fn gen_shared(&mut self, public: u32, r#mod: u32) { + self.shared_key = Some(mod_pow(public, self.private_key.unwrap(), r#mod)) + } + + pub fn diffie_hellman(p1: &mut Self, p2: &mut Self) { + let r = rand::random::(); + let mut m: u32 = 4; + while m < r || !is_prime(m) { + m = rand::random::(); + } + p1.gen_keys(r.into(), m.into()); + p2.gen_keys(r.into(), m.into()); + p1.gen_shared(p2.public_key.unwrap(), m.into()); + p2.gen_shared(p1.public_key.unwrap(), m.into()); + assert_eq!(p1.shared_key, p2.shared_key); + } + + fn xor_cipher(msg: &[u8], key: u32) -> Vec { + let key_bytes = key.to_le_bytes(); + let key_len = key_bytes.len(); + + msg.iter() + .enumerate() + .map(|(i, &byte)| byte ^ key_bytes[i % key_len]) + .collect() + } + + pub fn send(&self, msg_raw: &[u8], target: &Self) { + let encrypted_raw = Self::xor_cipher(msg_raw, self.shared_key.unwrap()); + let encrypted = str::from_utf8(&encrypted_raw).unwrap_or("not displayable"); + let msg = str::from_utf8(&msg_raw).unwrap_or("not displayable"); + eprintln!( + "[{}] Sending message '{}' ({}) to {}", + self.name, msg, encrypted, target.name + ); + target.recv(&encrypted_raw, self); + } + fn recv(&self, msg_raw: &[u8], source: &Self) { + let decrypted_raw = Self::xor_cipher(msg_raw, self.shared_key.unwrap()); + let decrypted = str::from_utf8(&decrypted_raw).unwrap_or("not displayable"); + let msg = str::from_utf8(&msg_raw).unwrap_or("not displayable"); + eprintln!( + "[{}] Received message '{}' ({}) from {}", + self.name, decrypted, msg, source.name + ); + } +} diff --git a/src/main.rs b/src/main.rs index 831a179..a6aff1a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,15 @@ +use keygen::Person; + +mod keygen; mod pollard_rho; +mod utils; fn main() { + let mut alice = Person::new("alice"); + let mut bob = Person::new("bob"); + Person::diffie_hellman(&mut alice, &mut bob); + alice.send(b"Hello World", &bob); + /* let mut n = 0; while n % 2 == 0 { n = rand::random::(); @@ -10,4 +19,5 @@ fn main() { "Generated random number {}, got prime divisor {}", n, n_primediv ); + */ } diff --git a/src/pollard_rho.rs b/src/pollard_rho.rs index 3dff6f9..203fb7e 100644 --- a/src/pollard_rho.rs +++ b/src/pollard_rho.rs @@ -1,3 +1,4 @@ +use crate::utils::{is_prime, mod_pow}; use gcd::Gcd; /** @@ -40,32 +41,3 @@ pub fn pollard_rho(n: u32) -> u32 { div } - -/** - * Discrete/Modular exponentiation - * - * Highly memory efficient because the full result is never stored, but shortened by defined modulo instead. - * We can use that because the prime divisor required for our algorithm is guarenteed to be smaller - * than n. - * - * Counterpart function to the discrete logarithm. - */ -fn mod_pow(base: u32, exp: u32, r#mod: u32) -> u32 { - let mut result = 1; - for _ in 0..exp - 1 { - result = (result * base) % r#mod; - } - result -} - -/** - * very primitive prime checker - */ -fn is_prime(n: u32) -> bool { - for i in (3..=(n as f32).sqrt() as u32).step_by(2) { - if n % i == 0 { - return false; - } - } - true -} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..59dea37 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,28 @@ +/** + * Discrete/Modular exponentiation + * + * Highly memory efficient because the full result is never stored, but shortened by defined modulo instead. + * We can use that because the prime divisor required for our algorithm is guarenteed to be smaller + * than n. + * + * Counterpart function to the discrete logarithm. + */ +pub fn mod_pow(base: u32, exp: u32, r#mod: u32) -> u32 { + let mut result: u64 = 1; + for _ in 0..exp - 1 { + result = (result * u64::from(base)) % u64::from(r#mod); + } + u32::try_from(result).unwrap() +} + +/** + * very primitive prime checker + */ +pub fn is_prime(n: u32) -> bool { + for i in (3..=(n as f32).sqrt() as u32).step_by(2) { + if n % i == 0 { + return false; + } + } + true +}