From 032e1fa27ff9faa9a5d82624dbfc5fe8a48c339c Mon Sep 17 00:00:00 2001 From: Andrew Guschin Date: Sun, 11 Dec 2022 12:43:48 +0400 Subject: =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0?= =?UTF-8?q?=205=20=D0=BB=D0=B0=D0=B1=D0=BE=D1=80=D0=B0=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=BD=D0=B0=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lab5/src/check_window.rs | 90 +++++++++++++++++++++++++++++++ lab5/src/forge_window.rs | 91 +++++++++++++++++++++++++++++++ lab5/src/generate_window.rs | 128 ++++++++++++++++++++++++++++++++++++++++++++ lab5/src/main.rs | 44 +++++++++++++++ lab5/src/sign_window.rs | 101 ++++++++++++++++++++++++++++++++++ lab5/src/utils.rs | 32 +++++++++++ lab5/src/window_state.rs | 6 +++ 7 files changed, 492 insertions(+) create mode 100644 lab5/src/check_window.rs create mode 100644 lab5/src/forge_window.rs create mode 100644 lab5/src/generate_window.rs create mode 100644 lab5/src/main.rs create mode 100644 lab5/src/sign_window.rs create mode 100644 lab5/src/utils.rs create mode 100644 lab5/src/window_state.rs (limited to 'lab5/src') diff --git a/lab5/src/check_window.rs b/lab5/src/check_window.rs new file mode 100644 index 0000000..216f1dc --- /dev/null +++ b/lab5/src/check_window.rs @@ -0,0 +1,90 @@ +use crate::utils::{adler64, powmod}; +use crate::window_state::WindowState; +use eframe::egui; + +pub struct Window { + message: String, + signature: String, + key: String, + correct: Option, + error: Option, +} + +impl Default for Window { + fn default() -> Self { + Self { + message: String::new(), + signature: String::new(), + key: String::new(), + correct: None, + error: None, + } + } +} + +impl Window { + fn check(&mut self) { + let split = self.key.split(",").collect::>(); + if split.len() != 2 { + self.correct = None; + self.error = Some("Неверный формат ключа".to_string()); + return; + } + let y = match split[0].parse::() { + Ok(num) => num, + Err(_) => { + self.correct = None; + self.error = Some("Не удалось прочитать открытый ключ".to_string()); + return; + } + }; + let p = match split[1].parse::() { + Ok(num) => num, + Err(_) => { + self.correct = None; + self.error = Some("Не удалось прочитать модуль".to_string()); + return; + } + }; + + let signature = match self.signature.parse::() { + Ok(num) => num, + Err(_) => { + self.correct = None; + self.error = Some("Не удалось прочитать подпись".to_string()); + return; + } + }; + + let h = adler64(self.message.as_bytes()) % p; + self.correct = Some(powmod(signature, h, p) == y); + } +} + +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.signature)); + ui.label("Открытый ключ:"); + let resp3 = ui.add(egui::TextEdit::singleline(&mut self.key)); + if resp1.changed() || resp2.changed() || resp3.changed() { + self.correct = None; + } + + if ui.button("Проверить подпись").clicked() { + self.check(); + } + + if let Some(true) = &self.correct { + ui.label("Подпись верна"); + } else if let Some(false) = &self.correct { + ui.label("Подпись не соответствует сообщению"); + } + } +} diff --git a/lab5/src/forge_window.rs b/lab5/src/forge_window.rs new file mode 100644 index 0000000..72347b8 --- /dev/null +++ b/lab5/src/forge_window.rs @@ -0,0 +1,91 @@ +use crate::utils::{adler64, inverse_mod, powmod}; +use crate::window_state::WindowState; +use eframe::egui; + +pub struct Window { + message: String, + key: String, + signed: Option, + error: Option, +} + +impl Default for Window { + fn default() -> Self { + Self { + message: String::new(), + key: String::new(), + signed: None, + error: None, + } + } +} + +impl Window { + fn sign(&mut self) { + let split = self.key.split(",").collect::>(); + if split.len() != 2 { + self.signed = None; + self.error = Some("Неверный формат ключа".to_string()); + return; + } + let y = match split[0].parse::() { + Ok(num) => num, + Err(_) => { + self.signed = None; + self.error = Some("Не удалось прочитать открытый ключ".to_string()); + return; + } + }; + let p = match split[1].parse::() { + Ok(num) => num, + Err(_) => { + self.signed = None; + self.error = Some("Не удалось прочитать модуль".to_string()); + return; + } + }; + + let h = adler64(self.message.as_bytes()) % p; + let h1 = inverse_mod(h as i64, p as i64) as u64; + self.signed = Some(powmod(y, h1, p)); + } +} + +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.signed = None; + self.error = None; + } + + if ui.button("Подписать").clicked() { + self.sign(); + } + + if let Some(signature) = &self.signed { + let mut tmp = signature.to_string(); + ui.horizontal(|ui| { + ui.label("Подпись:"); + ui.add_enabled(false, egui::TextEdit::singleline(&mut tmp)); + }); + if ui.button("Скопировать подпись").clicked() { + ui.output().copied_text = tmp.clone(); + } + if ui.button("Скопировать сообщение").clicked() { + ui.output().copied_text = self.message.clone(); + } + } + + if let Some(error) = &self.error { + ui.label(error); + } + } +} diff --git a/lab5/src/generate_window.rs b/lab5/src/generate_window.rs new file mode 100644 index 0000000..25beb22 --- /dev/null +++ b/lab5/src/generate_window.rs @@ -0,0 +1,128 @@ +use crate::utils::powmod; +use crate::window_state::WindowState; +use eframe::egui; + +#[derive(PartialEq, Eq)] +enum State { + Idle, + Requested, + Generated, +} + +pub struct Window { + state: State, + p: u64, + g: u64, + a: u64, + y: u64, +} + +impl Default for Window { + fn default() -> Self { + Self { + state: State::Idle, + p: 0, + g: 0, + a: 0, + y: 0, + } + } +} + +fn min_order(x: u64, order: u64) -> u64 { + let mut min = 0; + let mut pow = x; + for power in 1..order { + if pow == 1 { + min = power; + break; + } + pow = (pow * x) % order; + } + return min; +} + +impl Window { + fn generate(&mut self) { + let primes = erathosphene(10000); + let i = fastrand::usize(4..primes.len()); + self.p = primes[i as usize]; + + for i in 1..self.p { + if min_order(i, self.p) == self.p - 1 { + self.g = i; + break; + } + } + + self.a = fastrand::u64(1..=self.p - 1); + self.y = powmod(self.g, self.a, self.p); + } +} + +fn erathosphene(n: u64) -> Vec { + 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("Модуль p:"); + let mut tmp = self.p.to_string(); + ui.add_enabled(false, egui::TextEdit::singleline(&mut tmp)); + }); + ui.horizontal(|ui| { + ui.label("Порождающий элемент g группы Z_p:"); + let mut tmp = self.g.to_string(); + ui.add_enabled(false, egui::TextEdit::singleline(&mut tmp)); + }); + ui.horizontal(|ui| { + ui.label("Секретный ключ a:"); + let mut tmp = self.a.to_string(); + ui.add_enabled(false, egui::TextEdit::singleline(&mut tmp)); + }); + ui.horizontal(|ui| { + ui.label("Публичный ключ y:"); + let mut tmp = self.y.to_string(); + ui.add_enabled(false, egui::TextEdit::singleline(&mut tmp)); + }); + if ui.button("Скопировать публичный ключ").clicked() { + ui.output().copied_text = format!("{},{}", self.y, self.p); + } + if ui.button("Скопировать секретный ключ").clicked() { + ui.output().copied_text = format!("{},{},{}", self.g, self.a, self.p); + } + } + } +} diff --git a/lab5/src/main.rs b/lab5/src/main.rs new file mode 100644 index 0000000..d056ebb --- /dev/null +++ b/lab5/src/main.rs @@ -0,0 +1,44 @@ +mod utils; +mod window_state; + +mod check_window; +mod forge_window; +mod generate_window; +mod sign_window; + +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>, +} + +impl Default for Application { + fn default() -> Self { + Self { + labs: vec![ + Box::new(generate_window::Window::default()), + Box::new(sign_window::Window::default()), + Box::new(check_window::Window::default()), + Box::new(forge_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/lab5/src/sign_window.rs b/lab5/src/sign_window.rs new file mode 100644 index 0000000..1a574e4 --- /dev/null +++ b/lab5/src/sign_window.rs @@ -0,0 +1,101 @@ +use crate::utils::{adler64, inverse_mod, powmod}; +use crate::window_state::WindowState; +use eframe::egui; + +pub struct Window { + message: String, + key: String, + signed: Option, + error: Option, +} + +impl Default for Window { + fn default() -> Self { + Self { + message: String::new(), + key: String::new(), + signed: None, + error: None, + } + } +} + +impl Window { + fn sign(&mut self) { + let split = self.key.split(",").collect::>(); + if split.len() != 3 { + self.signed = None; + self.error = Some("Неверный формат ключа".to_string()); + return; + } + let g = match split[0].parse::() { + Ok(num) => num, + Err(_) => { + self.signed = None; + self.error = Some("Не удалось прочитать закрытый ключ".to_string()); + return; + } + }; + let a = match split[1].parse::() { + Ok(num) => num, + Err(_) => { + self.signed = None; + self.error = Some("Не удалось прочитать закрытый ключ".to_string()); + return; + } + }; + let p = match split[2].parse::() { + Ok(num) => num, + Err(_) => { + self.signed = None; + self.error = Some("Не удалось прочитать модуль".to_string()); + return; + } + }; + + let h = adler64(self.message.as_bytes()) % p; + let h1 = inverse_mod(h as i64, p as i64) as u64; + + let z = (h1 * a) % (p - 1); + self.signed = Some(powmod(g, z, p)); + } +} + +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.signed = None; + self.error = None; + } + + if ui.button("Подписать").clicked() { + self.sign(); + } + + if let Some(signature) = &self.signed { + let mut tmp = signature.to_string(); + ui.horizontal(|ui| { + ui.label("Подпись:"); + ui.add_enabled(false, egui::TextEdit::singleline(&mut tmp)); + }); + if ui.button("Скопировать подпись").clicked() { + ui.output().copied_text = tmp.clone(); + } + if ui.button("Скопировать сообщение").clicked() { + ui.output().copied_text = self.message.clone(); + } + } + + if let Some(error) = &self.error { + ui.label(error); + } + } +} diff --git a/lab5/src/utils.rs b/lab5/src/utils.rs new file mode 100644 index 0000000..34f87b3 --- /dev/null +++ b/lab5/src/utils.rs @@ -0,0 +1,32 @@ +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 adler64(buf: &[u8]) -> u64 { + let mod64 = 4294967291u64; + let mut s1 = 1u64; + let mut s2 = 0u64; + + for n in buf { + s1 = (s1 + *n as u64) % mod64; + s2 = (s2 + s1) % mod64; + } + return (s2 << 32) | s1; +} + +pub fn inverse_mod(x: i64, m: i64) -> i64 { + let (_, x, _) = extended_gcd(x, m); + return (x % m + m) % m; +} + +pub 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); +} diff --git a/lab5/src/window_state.rs b/lab5/src/window_state.rs new file mode 100644 index 0000000..ba8e57e --- /dev/null +++ b/lab5/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); +} -- cgit v1.2.3