lab3
This commit is contained in:
53
Cargo.lock
generated
53
Cargo.lock
generated
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
242
src/main.rs
242
src/main.rs
@@ -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
69
src/rsa.rs
Normal 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
40
src/utils.rs
Normal 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()
|
||||
}
|
||||
Reference in New Issue
Block a user