diff options
| author | Andrew Guschin <guschin.drew@gmail.com> | 2022-11-13 11:50:28 +0400 |
|---|---|---|
| committer | Andrew Guschin <guschin.drew@gmail.com> | 2022-11-13 11:50:28 +0400 |
| commit | 4862c2cf3eafdb6fa017a4e86a6fad8b4fc64171 (patch) | |
| tree | 6f0600b01d01b479ced7cba77e21a8970c2e0300 /lab2/src | |
| parent | 31ede18fb5752b4524868be845b88d26bda13754 (diff) | |
Добавлена вторая лаба
Diffstat (limited to 'lab2/src')
| -rw-r--r-- | lab2/src/compute_window.rs | 62 | ||||
| -rw-r--r-- | lab2/src/decrypt_window.rs | 114 | ||||
| -rw-r--r-- | lab2/src/encrypt_window.rs | 92 | ||||
| -rw-r--r-- | lab2/src/generate_window.rs | 156 | ||||
| -rw-r--r-- | lab2/src/main.rs | 45 | ||||
| -rw-r--r-- | lab2/src/utils.rs | 20 | ||||
| -rw-r--r-- | lab2/src/window_state.rs | 6 |
7 files changed, 495 insertions, 0 deletions
diff --git a/lab2/src/compute_window.rs b/lab2/src/compute_window.rs new file mode 100644 index 0000000..6a9a7e8 --- /dev/null +++ b/lab2/src/compute_window.rs @@ -0,0 +1,62 @@ +use crate::utils::powmod; +use crate::window_state::WindowState; +use eframe::egui; + +pub struct Window { + e: u64, + k: u64, + phi: u64, + closed: Option<u64>, + error: Option<String>, +} + +impl Default for Window { + fn default() -> Self { + Self { + e: 0, + k: 0, + phi: 0, + closed: None, + error: None, + } + } +} + +impl Window { + fn compute(&mut self) { + self.closed = Some(powmod(self.e, self.k - 1, self.phi)); + } +} + +impl WindowState for Window { + fn get_name(&self) -> &str { + "Вычисление секретной экспоненты" + } + + fn update(&mut self, ui: &mut egui::Ui) { + ui.label("Открытая экспонента e:"); + let resp1 = ui.add(egui::DragValue::new(&mut self.e)); + ui.label("Модуль phi(e):"); + let resp2 = ui.add(egui::DragValue::new(&mut self.phi).clamp_range(1..=u64::MAX)); + ui.label("Порядок k элемента e по модулю phi(n):"); + let resp3 = ui.add(egui::DragValue::new(&mut self.k).clamp_range(1..=u64::MAX)); + if resp1.changed() || resp2.changed() || resp3.changed() { + self.closed = None; + self.error = None; + } + + if ui.button("Вычислить секретную экспоненту d").clicked() { + self.compute(); + } + + if let Some(d) = &self.closed { + let mut tmp = d.to_string(); + ui.label("Секретная экспонента d:"); + ui.add_enabled(false, egui::TextEdit::singleline(&mut tmp)); + } + + if let Some(err) = &self.error { + ui.label(err); + } + } +} diff --git a/lab2/src/decrypt_window.rs b/lab2/src/decrypt_window.rs new file mode 100644 index 0000000..aee9893 --- /dev/null +++ b/lab2/src/decrypt_window.rs @@ -0,0 +1,114 @@ +use crate::utils::{from_bytes, powmod}; +use crate::window_state::WindowState; +use base64; +use eframe::egui; + +pub struct Window { + ciphertext: String, + key: String, + message: Option<String>, + error: Option<String>, +} + +impl Default for Window { + fn default() -> Self { + Self { + ciphertext: String::new(), + key: String::new(), + message: None, + error: None, + } + } +} + +impl Window { + fn decrypt(&mut self) { + let split = self.key.split(",").collect::<Vec<&str>>(); + if split.len() != 2 { + self.message = None; + self.error = Some("Неверный формат ключа".to_string()); + return; + } + let d = match split[0].parse::<u64>() { + Ok(num) => num, + Err(_) => { + self.message = None; + self.error = Some("Не удалось прочитать открытую экспоненту".to_string()); + return; + } + }; + let n = match split[1].parse::<u64>() { + Ok(num) => num, + Err(_) => { + self.message = None; + self.error = Some("Не удалось прочитать модуль".to_string()); + return; + } + }; + + let cipher = match base64::decode(&self.ciphertext) { + Ok(v) => v, + Err(_) => { + self.message = None; + self.error = Some("Введён некорректный шифротекст".to_string()); + return; + } + }; + if cipher.len() == 0 || cipher.len() % 4 != 0 { + self.message = None; + self.error = Some("Введён некорректный шифротекст".to_string()); + return; + } + let mut nums = Vec::new(); + for i in 0..cipher.len() / 4 { + let num = from_bytes( + cipher[4 * i], + cipher[4 * i + 1], + cipher[4 * i + 2], + cipher[4 * i + 3], + ); + nums.push(powmod(num, d, n) as u8); + } + let message = match String::from_utf8(nums) { + Ok(m) => m, + Err(_) => { + self.message = None; + self.error = Some("Расшифрованное сообщение не является UTF-8".to_string()); + return; + } + }; + self.message = Some(message); + } +} + +impl WindowState for Window { + fn get_name(&self) -> &str { + "Расшифрование сообщения" + } + + fn update(&mut self, ui: &mut egui::Ui) { + ui.label("Шифротекст:"); + let resp1 = ui.add(egui::TextEdit::multiline(&mut self.ciphertext)); + ui.label("Закрытый ключ:"); + let resp2 = ui.add(egui::TextEdit::singleline(&mut self.key)); + if resp1.changed() || resp2.changed() { + self.message = None; + self.error = None; + } + if ui.button("Расшифровать").clicked() { + self.decrypt(); + } + + if let Some(text) = &self.message { + let mut tmp = text.clone(); + ui.label("Расшифрованное сообщение:"); + ui.add_enabled(false, egui::TextEdit::multiline(&mut tmp)); + if ui.button("Скопировать сообщение").clicked() { + ui.output().copied_text = tmp.clone(); + } + } + if let Some(error) = &self.error { + ui.label(error); + } + } +} diff --git a/lab2/src/encrypt_window.rs b/lab2/src/encrypt_window.rs new file mode 100644 index 0000000..62899ba --- /dev/null +++ b/lab2/src/encrypt_window.rs @@ -0,0 +1,92 @@ +use crate::utils::{powmod, to_bytes}; +use crate::window_state::WindowState; +use base64; +use eframe::egui; + +pub struct Window { + message: String, + key: String, + encrypted: Option<String>, + error: Option<String>, +} + +impl Default for Window { + fn default() -> Self { + Self { + message: String::new(), + key: String::new(), + encrypted: None, + error: None, + } + } +} + +impl Window { + fn encrypt(&mut self) { + let split = self.key.split(",").collect::<Vec<&str>>(); + if split.len() != 2 { + self.encrypted = None; + self.error = Some("Неверный формат ключа".to_string()); + return; + } + let e = match split[0].parse::<u64>() { + Ok(num) => num, + Err(_) => { + self.encrypted = None; + self.error = Some("Не удалось прочитать открытую экспоненту".to_string()); + return; + } + }; + let n = match split[1].parse::<u64>() { + Ok(num) => num, + Err(_) => { + self.encrypted = None; + self.error = Some("Не удалось прочитать модуль".to_string()); + return; + } + }; + + let mut cipher = Vec::new(); + for byte in self.message.clone().into_bytes() { + let encr = powmod(byte as u64, e, n); + let bytes = to_bytes(encr); + cipher.push(bytes.0); + cipher.push(bytes.1); + cipher.push(bytes.2); + cipher.push(bytes.3); + } + self.encrypted = Some(base64::encode(cipher)); + } +} + +impl WindowState for Window { + fn get_name(&self) -> &str { + "Шифрование сообщения" + } + + fn update(&mut self, ui: &mut egui::Ui) { + ui.label("Сообщение для зашифрования:"); + let resp1 = ui.add(egui::TextEdit::multiline(&mut self.message)); + ui.label("Открытый ключ:"); + let resp2 = ui.add(egui::TextEdit::singleline(&mut self.key)); + if resp1.changed() || resp2.changed() { + self.encrypted = None; + self.error = None; + } + if ui.button("Зашифровать").clicked() { + self.encrypt(); + } + + if let Some(cipertext) = &self.encrypted { + let mut tmp = cipertext.clone(); + ui.label("Зашифрованное сообщение:"); + ui.add_enabled(false, egui::TextEdit::multiline(&mut tmp)); + if ui.button("Скопировать шифротекст").clicked() { + ui.output().copied_text = tmp.clone(); + } + } + if let Some(error) = &self.error { + ui.label(error); + } + } +} diff --git a/lab2/src/generate_window.rs b/lab2/src/generate_window.rs new file mode 100644 index 0000000..56a572a --- /dev/null +++ b/lab2/src/generate_window.rs @@ -0,0 +1,156 @@ +use crate::window_state::WindowState; +use eframe::egui; + +#[derive(PartialEq, Eq)] +enum State { + Idle, + Requested, + Generated, +} + +pub struct Window { + state: State, + n: u64, + e: u64, + d: u64, + k: u64, + phi: u64, +} + +impl Default for Window { + fn default() -> Self { + Self { + state: State::Idle, + n: 0, + e: 0, + d: 0, + k: 0, + phi: 0, + } + } +} + +impl Window { + fn generate(&mut self) { + let primes = erathosphene(10000); + let i = fastrand::usize(4..primes.len()); + let mut j = fastrand::usize(4..primes.len()); + while j == i { + j = fastrand::usize(..primes.len()); + } + + let p = primes[i as usize]; + let q = primes[j as usize]; + self.n = p * q; + + self.phi = (p - 1) * (q - 1); + let mut e = self.phi; + loop { + let (d, x, _) = extended_gcd(e as i64, self.phi as i64); + if d != 1 { + e = fastrand::u64(2..self.phi); + } else { + self.e = e; + self.d = if x < 0 { x + self.phi as i64 } else { x } as u64; + break; + } + } + + let mut i = e; + let mut order = 1; + loop { + if i == 1 { + break; + } else { + order += 1; + i = (i * e) % self.phi; + } + } + + self.k = order; + } +} + +fn extended_gcd(a: i64, b: i64) -> (i64, i64, i64) { + if a == 0 { + return (b, 0, 1); + } + let (d, x, y) = extended_gcd(b % a, a); + return (d, y - (b / a) * x, x); +} + +fn erathosphene(n: u64) -> Vec<u64> { + let mut is_prime = vec![true; n as usize]; + let mut p = 2; + while p * p < n { + let mut cur = p * p; + while cur < n { + is_prime[cur as usize] = false; + cur += p; + } + while !is_prime[(p + 1) as usize] { + p += 1; + } + p += 1 + } + let mut primes = Vec::new(); + is_prime.iter().enumerate().for_each(|(i, p)| { + if *p { + primes.push(i as u64); + } + }); + return primes; +} + +impl WindowState for Window { + fn get_name(&self) -> &str { + "Генерация ключей" + } + + fn update(&mut self, ui: &mut egui::Ui) { + if ui.button("Сгенерировать").clicked() { + self.state = State::Requested; + } + if self.state == State::Requested { + self.generate(); + self.state = State::Generated; + } + if self.state == State::Generated { + ui.horizontal(|ui| { + ui.label("Модуль n:"); + let mut tmp = self.n.to_string(); + ui.add_enabled(false, egui::TextEdit::singleline(&mut tmp)); + }); + ui.horizontal(|ui| { + ui.label("Открытая экспонента e:"); + let mut tmp = self.e.to_string(); + ui.add_enabled(false, egui::TextEdit::singleline(&mut tmp)); + }); + ui.horizontal(|ui| { + ui.label("Секретная экспонента d:"); + let mut tmp = self.d.to_string(); + ui.add_enabled(false, egui::TextEdit::singleline(&mut tmp)); + }); + if ui.button("Скопировать открытый ключ").clicked() { + ui.output().copied_text = format!("{},{}", self.e, self.n); + } + if ui.button("Скопировать закрытый ключ").clicked() { + ui.output().copied_text = format!("{},{}", self.d, self.n); + } + + ui.label("Порядок элемента e по модулю phi(n):"); + let mut tmp = self.k.to_string(); + ui.add_enabled(false, egui::TextEdit::singleline(&mut tmp)); + if ui.button("Скопировать открытую экспоненту e").clicked() + { + ui.output().copied_text = format!("{}", self.e); + } + if ui.button("Скопировать phi(n)").clicked() { + ui.output().copied_text = format!("{}", self.phi); + } + if ui.button("Скопировать порядок").clicked() { + ui.output().copied_text = format!("{}", self.k); + } + } + } +} diff --git a/lab2/src/main.rs b/lab2/src/main.rs new file mode 100644 index 0000000..162666e --- /dev/null +++ b/lab2/src/main.rs @@ -0,0 +1,45 @@ +mod window_state; + +mod compute_window; +mod decrypt_window; +mod encrypt_window; +mod generate_window; + +mod utils; + +use crate::window_state::WindowState; +use eframe::egui; + +fn main() { + let options = eframe::NativeOptions::default(); + eframe::run_native( + "Криптографические методы защиты информации", + options, + Box::new(|_cc| Box::new(Application::default())), + ); +} + +struct Application { + labs: Vec<Box<dyn WindowState>>, +} + +impl Default for Application { + fn default() -> Self { + Self { + labs: vec![ + Box::new(generate_window::Window::default()), + Box::new(encrypt_window::Window::default()), + Box::new(decrypt_window::Window::default()), + Box::new(compute_window::Window::default()), + ], + } + } +} + +impl eframe::App for Application { + fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + for window in &mut self.labs { + egui::Window::new(window.get_name()).show(ctx, |ui| window.update(ui)); + } + } +} diff --git a/lab2/src/utils.rs b/lab2/src/utils.rs new file mode 100644 index 0000000..801a108 --- /dev/null +++ b/lab2/src/utils.rs @@ -0,0 +1,20 @@ +pub fn powmod(x: u64, p: u64, m: u64) -> u64 { + let mut res = x; + for _ in 1..p { + res = (res * x) % m; + } + return res; +} + +pub fn to_bytes(x: u64) -> (u8, u8, u8, u8) { + return ( + ((x >> 0) & 0xFF) as u8, + ((x >> 8) & 0xFF) as u8, + ((x >> 16) & 0xFF) as u8, + ((x >> 24) & 0xFF) as u8, + ); +} + +pub fn from_bytes(x1: u8, x2: u8, x3: u8, x4: u8) -> u64 { + return (x1 as u64) << 0 | (x2 as u64) << 8 | (x3 as u64) << 16 | (x4 as u64) << 24; +} diff --git a/lab2/src/window_state.rs b/lab2/src/window_state.rs new file mode 100644 index 0000000..ba8e57e --- /dev/null +++ b/lab2/src/window_state.rs @@ -0,0 +1,6 @@ +use eframe::egui; + +pub trait WindowState { + fn get_name(&self) -> &str; + fn update(&mut self, ui: &mut egui::Ui); +} |