add elliptic curves, diffie hellman and 'messaging'
This commit is contained in:
parent
7960658ef9
commit
ca5cc46cc6
6 changed files with 259 additions and 30 deletions
80
Cargo.lock
generated
80
Cargo.lock
generated
|
@ -2,6 +2,12 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
@ -19,6 +25,7 @@ name = "ec_crypto"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gcd",
|
"gcd",
|
||||||
|
"num",
|
||||||
"rand",
|
"rand",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -45,6 +52,79 @@ version = "0.2.167"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc"
|
checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||||
|
dependencies = [
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.46"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-iter"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.20"
|
version = "0.2.20"
|
||||||
|
|
|
@ -6,3 +6,4 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
gcd = "2.3.0"
|
gcd = "2.3.0"
|
||||||
|
num = "0.4.3"
|
||||||
|
|
125
src/keygen.rs
Normal file
125
src/keygen.rs
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
use core::str;
|
||||||
|
|
||||||
|
use num::{pow::Pow, Integer};
|
||||||
|
use rand::{distributions::Standard, prelude::Distribution};
|
||||||
|
|
||||||
|
use crate::utils::*;
|
||||||
|
|
||||||
|
struct EllipticCurve<BigInt>
|
||||||
|
where
|
||||||
|
BigInt: Integer,
|
||||||
|
{
|
||||||
|
a: BigInt,
|
||||||
|
b: BigInt,
|
||||||
|
r#mod: BigInt,
|
||||||
|
}
|
||||||
|
impl<BigInt> EllipticCurve<BigInt>
|
||||||
|
where
|
||||||
|
BigInt: Integer + std::marker::Copy + Pow<usize, Output = BigInt>,
|
||||||
|
Standard: Distribution<BigInt>,
|
||||||
|
{
|
||||||
|
pub fn new(a: BigInt, b: BigInt, r#mod: BigInt) -> Self {
|
||||||
|
EllipticCurve { a, b, r#mod }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn y(&self, x: BigInt) -> BigInt {
|
||||||
|
(x.pow(3) + self.b * x + self.a) % self.r#mod
|
||||||
|
}
|
||||||
|
pub fn random(&self) -> (BigInt, BigInt) {
|
||||||
|
let mut start = rand::random::<BigInt>() % self.r#mod;
|
||||||
|
let i_count = rand::random::<i8>();
|
||||||
|
|
||||||
|
for _ in 0..i_count {
|
||||||
|
start = self.y(start);
|
||||||
|
}
|
||||||
|
|
||||||
|
(start, self.y(start))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Person {
|
||||||
|
pub name: String,
|
||||||
|
private_key: Option<u32>,
|
||||||
|
pub public_key: Option<u32>,
|
||||||
|
pub shared_key: Option<u32>,
|
||||||
|
}
|
||||||
|
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::<u32>();
|
||||||
|
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 m: u32 = 17;
|
||||||
|
let curve = EllipticCurve::new(0, 7, m);
|
||||||
|
let gen = curve.random().1;
|
||||||
|
|
||||||
|
eprintln!(
|
||||||
|
"Start params: x³+{}x+{}, mod {}, generator {}",
|
||||||
|
0, 7, m, gen
|
||||||
|
);
|
||||||
|
|
||||||
|
p1.gen_keys(gen, m.into());
|
||||||
|
p2.gen_keys(gen, 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);
|
||||||
|
eprintln!(
|
||||||
|
"[{}] Shared key for {}: {}",
|
||||||
|
p1.name,
|
||||||
|
p2.name,
|
||||||
|
p1.shared_key.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn xor_cipher(msg: &[u8], key: u32) -> Vec<u8> {
|
||||||
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
10
src/main.rs
10
src/main.rs
|
@ -1,6 +1,15 @@
|
||||||
|
use keygen::Person;
|
||||||
|
|
||||||
|
mod keygen;
|
||||||
mod pollard_rho;
|
mod pollard_rho;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
fn main() {
|
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;
|
let mut n = 0;
|
||||||
while n % 2 == 0 {
|
while n % 2 == 0 {
|
||||||
n = rand::random::<u16>();
|
n = rand::random::<u16>();
|
||||||
|
@ -10,4 +19,5 @@ fn main() {
|
||||||
"Generated random number {}, got prime divisor {}",
|
"Generated random number {}, got prime divisor {}",
|
||||||
n, n_primediv
|
n, n_primediv
|
||||||
);
|
);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
use crate::utils::{is_prime, mod_pow};
|
||||||
use gcd::Gcd;
|
use gcd::Gcd;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the prime divisor for some number `n`
|
* Calculate the prime divisor for some number `n`
|
||||||
*
|
*
|
||||||
|
@ -40,32 +40,3 @@ pub fn pollard_rho(n: u32) -> u32 {
|
||||||
|
|
||||||
div
|
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
|
|
||||||
}
|
|
||||||
|
|
42
src/utils.rs
Normal file
42
src/utils.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
use std::ops::Div;
|
||||||
|
|
||||||
|
use num::Integer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<T>(mut base: T, mut exp: T, r#mod: T) -> T
|
||||||
|
where
|
||||||
|
T: Integer + Copy + std::ops::DivAssign + From<u8>,
|
||||||
|
u64: From<T>,
|
||||||
|
u128: From<T>,
|
||||||
|
{
|
||||||
|
let mut result: T = T::one();
|
||||||
|
base = base % r#mod;
|
||||||
|
while exp > T::zero() {
|
||||||
|
if exp.is_odd() {
|
||||||
|
result = (result * base) % r#mod;
|
||||||
|
}
|
||||||
|
base = (base * base) % r#mod;
|
||||||
|
exp /= T::from(2);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue