diff options
Diffstat (limited to 'sem2/src/main.rs')
| -rw-r--r-- | sem2/src/main.rs | 243 |
1 files changed, 205 insertions, 38 deletions
diff --git a/sem2/src/main.rs b/sem2/src/main.rs index adf47b8..7c458f6 100644 --- a/sem2/src/main.rs +++ b/sem2/src/main.rs @@ -1,54 +1,221 @@ -use fastrand; -use inquire::Text; -use std::time::Instant; +use inquire::{Select, Text}; +use std::fs::{self, File}; +use std::io::{self, Write}; +use std::path::{Path, PathBuf}; + +use crate::elgamal::{decrypt_text, encrypt_text, OpenKey, SecretKey}; +use crate::mpn::Number; mod algo; +mod elgamal; mod mpn; mod program; -fn main() { - let radix = 10; - - let q_text = match Text::new("Введите число q:").prompt() { - Ok(text) => text, - Err(_) => return, - }; - let q = match mpn::Number::parse(&q_text, radix as u8) { - Ok(number) => number, - Err(what) => { - println!("{what}"); - return; +fn files_recursive(dir: &Path) -> io::Result<Vec<PathBuf>> { + let mut dir_front = Vec::new(); + let mut files = Vec::new(); + dir_front.push(dir.to_owned()); + while dir_front.len() != 0 { + let dir = dir_front.pop().unwrap(); + for entry in fs::read_dir(dir)? { + let path = entry?.path(); + if path.is_dir() { + dir_front.push(path.clone()); + } else { + files.push(path.clone()); + } } - }; - - if !algo::rabin_miller_test(&q, 10) { - println!("Число q должно быть простым"); - return; } + return Ok(files); +} - let mut p; - loop { - let s = mpn::Number::random_num(fastrand::usize(1..=30), radix); - println!("s = {s}"); - p = q.clone() * s + 1.into(); - if algo::rabin_miller_test(&p, 10) { - break; +fn dirs_recursive(dir: &Path) -> io::Result<Vec<PathBuf>> { + let mut dir_front = Vec::new(); + let mut dirs = Vec::new(); + dir_front.push(dir.to_owned()); + dirs.push(dir.to_owned()); + while dir_front.len() != 0 { + let dir = dir_front.pop().unwrap(); + for entry in fs::read_dir(dir)? { + let path = entry?.path(); + if path.is_dir() { + dir_front.push(path.clone()); + dirs.push(path.clone()); + } } } - println!("Сгенерированное простое p: {p}"); + return Ok(dirs); +} - let t_start = Instant::now(); - let g = program::find_of_order(&p, &q); - let t_elapsed = t_start.elapsed(); +fn write_keys( + open: OpenKey, + open_path: String, + secret: SecretKey, + secret_path: String, +) { + let mut open_file = File::create(open_path).unwrap(); + let key = format!("{} {} {}", open.y, open.g, open.p); + open_file.write_all(key.as_bytes()).unwrap(); - match g { - Ok(res) => { - println!("Найденный элемент g: {res}"); - } - Err(msg) => { - println!("{msg}"); + let mut secret_file = File::create(secret_path).unwrap(); + let key = format!("{}", secret.x); + secret_file.write_all(key.as_bytes()).unwrap(); +} + +fn read_open_key(path: String) -> OpenKey { + let open_text = fs::read_to_string(path).unwrap(); + let numbers = open_text.split(" ").collect::<Vec<&str>>(); + let y = Number::parse(numbers[0], 10).unwrap(); + let g = Number::parse(numbers[1], 10).unwrap(); + let p = Number::parse(numbers[2], 10).unwrap(); + return OpenKey { y, g, p }; +} + +fn read_secret_key(path: String) -> SecretKey { + let secret_text = fs::read_to_string(path).unwrap(); + let x = Number::parse(&secret_text, 10).unwrap(); + return SecretKey { x }; +} + +fn main() { + let operation = Select::new( + "Выберите тип операции:", + vec!["Генерация ключей", "Зашифрование", "Расшифрование"], + ) + .prompt() + .unwrap(); + + if operation == "Генерация ключей" { + let dir_entries = dirs_recursive(Path::new(".")) + .unwrap() + .into_iter() + .map(|e| e.to_str().unwrap().to_owned()) + .collect::<Vec<String>>(); + let result_path = + Select::new("Выберите куда сохранить результат:", dir_entries) + .prompt() + .unwrap(); + let open_name = Text::new("Имя для файла с открытым ключом:") + .prompt() + .unwrap(); + let secret_name = Text::new("Имя для файла с закрытым ключом:") + .prompt() + .unwrap(); + let p_text = Text::new("Введите простое p:").prompt().unwrap(); + let p = Number::parse(&p_text, 10).unwrap(); + if !algo::rabin_miller_test(&p, 10) { + println!("Число p должно быть простым"); return; } + let (op, cl) = elgamal::generate_keypair(&p); + let open_path = Path::new(&result_path) + .join(&open_name) + .to_string_lossy() + .to_string(); + let secret_path = Path::new(&result_path) + .join(&secret_name) + .to_string_lossy() + .to_string(); + write_keys(op, open_path, cl, secret_path); } - println!("Операция выполнена за {} наносекунд", t_elapsed.as_nanos()); + if operation == "Зашифрование" { + let entries = files_recursive(Path::new(".")) + .unwrap() + .into_iter() + .map(|e| e.to_str().unwrap().to_owned()) + .collect::<Vec<String>>(); + let open_name = + Select::new("Выберите файл с открытым ключом:", entries.clone()) + .prompt() + .unwrap(); + let plain_file = + Select::new("Выберите файл для зашифрования:", entries) + .prompt() + .unwrap(); + + let dir_entries = dirs_recursive(Path::new(".")) + .unwrap() + .into_iter() + .map(|e| e.to_str().unwrap().to_owned()) + .collect::<Vec<String>>(); + let result_path = + Select::new("Выберите куда сохранить результат:", dir_entries) + .prompt() + .unwrap(); + + let cipher_name = + Text::new("Введите название для файла с шифротекстом:") + .prompt() + .unwrap(); + + let open_key = read_open_key(open_name); + let plaintext = fs::read_to_string(plain_file).unwrap(); + println!("{plaintext}"); + println!("Отфильтрованный текст:"); + let plaintext = elgamal::filter_text(&plaintext); + println!("{plaintext}"); + let cipher = encrypt_text(&plaintext, open_key); + + let mut elements = Vec::new(); + for (a, b) in &cipher { + let elem = format!("{},{}", a, b); + elements.push(elem); + } + let ciphertext = elements.join(":"); + println!("Полученный шифротекст: {ciphertext}"); + let cipher_path = Path::new(&result_path) + .join(&cipher_name) + .to_string_lossy() + .to_string(); + fs::write(cipher_path, ciphertext.as_bytes()) + .expect("Не получилось записать шифротекст"); + } + + if operation == "Расшифрование" { + let entries = files_recursive(Path::new(".")) + .unwrap() + .into_iter() + .map(|e| e.to_str().unwrap().to_owned()) + .collect::<Vec<String>>(); + let secret_name = + Select::new("Выберите файл с закрытым ключом:", entries.clone()) + .prompt() + .unwrap(); + let open_name = + Select::new("Выберите файл с открытым ключом:", entries.clone()) + .prompt() + .unwrap(); + let cipher_file = + Select::new("Выберите файл для расшифрования:", entries) + .prompt() + .unwrap(); + + let dir_entries = dirs_recursive(Path::new(".")) + .unwrap() + .into_iter() + .map(|e| e.to_str().unwrap().to_owned()) + .collect::<Vec<String>>(); + let result_path = + Select::new("Выберите куда сохранить результат:", dir_entries) + .prompt() + .unwrap(); + let plain_name = + Text::new("Введите название для файла с расшифровкой:") + .prompt() + .unwrap(); + + let open = read_open_key(open_name); + let secret = read_secret_key(secret_name); + let ciphertext = fs::read_to_string(cipher_file).unwrap(); + let plaintext = decrypt_text(&ciphertext, secret, open); + println!("Расшифрованный текст:"); + println!("{plaintext}"); + + let plain_path = Path::new(&result_path) + .join(&plain_name) + .to_string_lossy() + .to_string(); + fs::write(plain_path, plaintext.as_bytes()) + .expect("Не получилось записать расшифровку"); + } } |