1
0
This commit is contained in:
2024-10-10 01:04:48 +03:00
parent 85d882eefe
commit d88bd0ebc4
5 changed files with 335 additions and 71 deletions

53
Cargo.lock generated
View File

@@ -140,6 +140,31 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "dialoguer"
version = "0.11.0"
@@ -198,6 +223,12 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "information-security"
version = "0.1.0"
@@ -205,10 +236,12 @@ dependencies = [
"anyhow",
"clap",
"dialoguer",
"hex",
"itertools",
"ndarray",
"num",
"rand",
"rayon",
]
[[package]]
@@ -428,6 +461,26 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
[[package]]
name = "rayon"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]]
name = "rustix"
version = "0.38.36"

View File

@@ -7,7 +7,9 @@ edition = "2021"
anyhow = "1.0.86"
clap = { version = "4.5.17", features = ["derive"] }
dialoguer = "0.11.0"
hex = "0.4.3"
itertools = "0.13.0"
ndarray = "0.16.1"
num = { version = "0.4.3", features = ["rand", "num-bigint"] }
rand = "0.8.5"
rayon = "1.10.0"

View File

@@ -1,79 +1,179 @@
use rand::prelude::Distribution;
use ndarray::arr2;
use ndarray::Array2;
use core::str;
use hex::{FromHex, ToHex};
use num::BigUint;
use num::FromPrimitive;
pub fn bigfib_with_mod(n: &BigUint, modulo: &BigUint) -> BigUint {
let ZERO: BigUint = FromPrimitive::from_u64(0).unwrap();
let ONE: BigUint = FromPrimitive::from_u64(1).unwrap();
if n == &ZERO || n == &ONE {
return n.clone();
}
mod rsa;
mod utils;
let f: Vec<BigUint> = vec![ZERO.clone(), ONE.clone()];
let t: Array2<BigUint> = arr2(&[
[ZERO.clone(), ONE.clone()],
[ONE.clone(), ONE.clone()]
]);
let power_t = bigfib_matrix_power(&t, n, modulo);
let mut answer: BigUint = ZERO.clone();
for i in 0..2 {
answer = (answer + (&power_t[[0, i]] * &f[i])) % modulo;
}
return answer;
}
fn bigfib_matrix_power(mat: &Array2<BigUint>, pow: &BigUint, modulo: &BigUint) -> Array2<BigUint> {
let ONE: BigUint = FromPrimitive::from_u64(1).unwrap();
let TWO: BigUint = FromPrimitive::from_u64(2).unwrap();
if pow == &ONE {
return mat.clone();
}
if pow % &TWO == ONE {
return bigfib_multiply(
&mat,
&bigfib_matrix_power(mat, &(pow - ONE), modulo),
modulo
);
}
let x = bigfib_matrix_power(mat, &(pow / TWO), modulo);
bigfib_multiply(&x, &x, modulo)
}
fn bigfib_multiply(a: &Array2<BigUint>, b: &Array2<BigUint>, modulo: &BigUint) -> Array2<BigUint> {
let ZERO: BigUint = FromPrimitive::from_u64(0).unwrap();
let mut return_mat: Array2<BigUint> = arr2(&[
[ZERO.clone(), ZERO.clone()],
[ZERO.clone(), ZERO.clone()]
]);
for i in 0..2 {
for j in 0..2 {
for k in 0..2 {
let big_val: BigUint = &return_mat[[i, j]] + (&a[[i, k]] * &b[[k, j]]);
return_mat[[i, j]] = big_val % modulo;
}
}
}
return_mat
}
fn generate_prime() -> num::BigUint {
let two = num::BigUint::from(2u64);
let bits =num::bigint::RandomBits::new(64);
let mut rng = rand::thread_rng();
let mut number: num::BigUint = bits.sample(&mut rng);
while (true) {
let mod1 = two.modpow(&(&number - 1u64), &number);
let mod2 = bigfib_with_mod(&(&number + 1u64), &number);
}
number
enum Mode {
GenerateKey,
Encrypt,
Decrypt,
}
fn main() -> anyhow::Result<()> {
let mode = match dialoguer::Select::new()
.with_prompt("Select a mode")
.item("Generate key")
.item("Encrypt")
.item("Decrypt")
.default(1)
.interact()?
{
0 => Mode::GenerateKey,
1 => Mode::Encrypt,
2 => Mode::Decrypt,
_ => unreachable!(),
};
match mode {
Mode::GenerateKey => generate_key()?,
Mode::Encrypt => encrypt()?,
Mode::Decrypt => decrypt()?,
}
Ok(())
}
fn generate_key() -> anyhow::Result<()> {
let bits = dialoguer::Input::new()
.with_prompt("Enter the key size in bits")
.default(2048)
.validate_with(|input: &u64| {
if input < &16 {
Err("Key size must be at least 16 bits")
} else {
Ok(())
}
})
.interact()?;
let (public_key, private_key) = rsa::keygen(bits);
println!("Public key:");
println!("{}", public_key);
println!("Private key:");
println!("{}", private_key);
Ok(())
}
fn encrypt() -> anyhow::Result<()> {
let key_size = dialoguer::Input::new()
.with_prompt("Enter the key size in bits")
.default(2048u64)
.validate_with(|input: &u64| {
if input < &16 {
Err("Key size must be at least 16 bits")
} else {
Ok(())
}
})
.interact()?;
let chunk_size = (key_size / 8) as usize;
let safe_chunk_size = chunk_size - 1;
let n = dialoguer::Input::<BigUint>::new()
.with_prompt("Enter public key's N")
.interact()?;
let e = dialoguer::Input::<BigUint>::new()
.with_prompt("Enter public key's E")
.interact()?;
let public_key = rsa::PublicKey::new(n, e);
let data = dialoguer::Input::<String>::new()
.with_prompt("Enter data")
.interact()?
.as_bytes()
.to_vec();
println!();
println!("data (raw) = {:?}", data);
let chunks = data.chunks(safe_chunk_size);
let encrypted = chunks
.into_iter()
.flat_map(|chunk| utils::pad_vec(public_key.encrypt(chunk), chunk_size))
.collect::<Vec<_>>();
println!();
println!("encrypted (raw) = {:?}", encrypted);
println!(
"encrypted ({} bytes) = {:?}",
encrypted.len(),
encrypted.encode_hex::<String>()
);
Ok(())
}
fn decrypt() -> anyhow::Result<()> {
let key_size = dialoguer::Input::new()
.with_prompt("Enter the key size in bits")
.default(2048u64)
.validate_with(|input: &u64| {
if input < &8 {
Err("Key size must be at least 8 bits")
} else {
Ok(())
}
})
.interact()?;
let chunk_size = (key_size / 8) as usize;
let n = dialoguer::Input::<BigUint>::new()
.with_prompt("Enter private key's N")
.interact()?;
let d = dialoguer::Input::<BigUint>::new()
.with_prompt("Enter private key's D")
.interact()?;
let private_key = rsa::PrivateKey::new(n, d);
let encrypted = Vec::<u8>::from_hex(
dialoguer::Input::<String>::new()
.with_prompt("Enter encrypted data")
.interact()?,
)?;
println!();
println!("encrypted (raw) = {:?}", encrypted);
let chunks = encrypted.chunks(chunk_size);
let decrypted = chunks
.into_iter()
.flat_map(|chunk| private_key.decrypt(chunk))
.collect::<Vec<_>>();
println!();
println!("decrypted (raw) = {:?}", decrypted);
if let Ok(decrypted) = str::from_utf8(&decrypted) {
println!("decrypted = {:?}", decrypted);
}
Ok(())
}
// let key_size = 64 + 8;
// let chunk_size = (key_size / 8) as usize;
// let safe_chunk_size = chunk_size - 1;
// println!("key size = {} bits", key_size);
// println!("chunk size = {} bytes", chunk_size);
// println!("safe chunk size = {} bytes", safe_chunk_size);
// let (public_key, private_key) = rsa::keygen(key_size);
// let data = b"Hello, w";
// let encrypted = utils::pad_vec(public_key.encrypt(data), chunk_size);
// let decrypted = private_key.decrypt(&encrypted);
// println!("\nencrypted ({} bytes) = {:?}", encrypted.len(), encrypted);
// println!("decrypted = {}", str::from_utf8(&decrypted)?);

69
src/rsa.rs Normal file
View File

@@ -0,0 +1,69 @@
use std::fmt::{Display, Formatter};
use num::BigUint;
use crate::utils;
pub struct PublicKey {
n: BigUint,
e: BigUint,
}
impl PublicKey {
pub fn new(n: BigUint, e: BigUint) -> Self {
Self { n, e }
}
pub fn encrypt(&self, chunk: &[u8]) -> Vec<u8> {
let message = BigUint::from_bytes_le(chunk);
let encrypted = message.modpow(&self.e, &self.n);
encrypted.to_bytes_le()
}
}
impl Display for PublicKey {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "(n = {:?}, e = {:?})", self.n, self.e)
}
}
pub struct PrivateKey {
n: BigUint,
d: BigUint,
}
impl PrivateKey {
pub fn new(n: BigUint, d: BigUint) -> Self {
Self { n, d }
}
pub fn decrypt(&self, chunk: &[u8]) -> Vec<u8> {
let encrypted = BigUint::from_bytes_le(chunk);
let decrypted = encrypted.modpow(&self.d, &self.n);
decrypted.to_bytes_le()
}
}
impl Display for PrivateKey {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "(n = {:?}, d = {:?})", self.n, self.d)
}
}
pub fn keygen(bits: u64) -> (PublicKey, PrivateKey) {
let mut numbers = utils::generate_n_primes(2, bits / 2);
let p = numbers.pop().unwrap();
let q = numbers.pop().unwrap();
let n = &p * &q;
let phi = (p - 1u8) * (q - 1u8);
let e = BigUint::from(65537u32);
let d = e.modinv(&phi).unwrap();
let public_key = PublicKey::new(n.clone(), e);
let private_key = PrivateKey::new(n, d);
(public_key, private_key)
}

40
src/utils.rs Normal file
View File

@@ -0,0 +1,40 @@
use num::BigUint;
use rand::prelude::Distribution;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
pub fn pad_vec(mut chunk: Vec<u8>, chunk_size: usize) -> Vec<u8> {
if chunk.len() < chunk_size {
chunk.resize(chunk_size, 0u8);
}
chunk
}
pub fn generate_prime(bits: u64) -> BigUint {
let one = BigUint::from(1u8);
let two = BigUint::from(2u8);
let bits = num::bigint::RandomBits::new(bits);
let mut rng = rand::thread_rng();
let mut number: BigUint = bits.sample(&mut rng);
loop {
if number > one {
let mod1 = two.modpow(&(&number - 1u8), &number);
if mod1 == one {
break;
}
}
number = bits.sample(&mut rng);
}
number
}
pub fn generate_n_primes(n: usize, bits: u64) -> Vec<BigUint> {
(0..n)
.into_par_iter()
.map(|_| generate_prime(bits))
.collect()
}