summaryrefslogtreecommitdiff
path: root/lab5/src
diff options
context:
space:
mode:
Diffstat (limited to 'lab5/src')
-rw-r--r--lab5/src/check_window.rs90
-rw-r--r--lab5/src/forge_window.rs91
-rw-r--r--lab5/src/generate_window.rs128
-rw-r--r--lab5/src/main.rs44
-rw-r--r--lab5/src/sign_window.rs101
-rw-r--r--lab5/src/utils.rs32
-rw-r--r--lab5/src/window_state.rs6
7 files changed, 492 insertions, 0 deletions
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<bool>,
+ error: Option<String>,
+}
+
+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::<Vec<&str>>();
+ if split.len() != 2 {
+ self.correct = None;
+ self.error = Some("Неверный формат ключа".to_string());
+ return;
+ }
+ let y = match split[0].parse::<u64>() {
+ Ok(num) => num,
+ Err(_) => {
+ self.correct = None;
+ self.error = Some("Не удалось прочитать открытый ключ".to_string());
+ return;
+ }
+ };
+ let p = match split[1].parse::<u64>() {
+ Ok(num) => num,
+ Err(_) => {
+ self.correct = None;
+ self.error = Some("Не удалось прочитать модуль".to_string());
+ return;
+ }
+ };
+
+ let signature = match self.signature.parse::<u64>() {
+ 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<u64>,
+ error: Option<String>,
+}
+
+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::<Vec<&str>>();
+ if split.len() != 2 {
+ self.signed = None;
+ self.error = Some("Неверный формат ключа".to_string());
+ return;
+ }
+ let y = match split[0].parse::<u64>() {
+ Ok(num) => num,
+ Err(_) => {
+ self.signed = None;
+ self.error = Some("Не удалось прочитать открытый ключ".to_string());
+ return;
+ }
+ };
+ let p = match split[1].parse::<u64>() {
+ 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<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("Модуль 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<Box<dyn WindowState>>,
+}
+
+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<u64>,
+ error: Option<String>,
+}
+
+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::<Vec<&str>>();
+ if split.len() != 3 {
+ self.signed = None;
+ self.error = Some("Неверный формат ключа".to_string());
+ return;
+ }
+ let g = match split[0].parse::<u64>() {
+ Ok(num) => num,
+ Err(_) => {
+ self.signed = None;
+ self.error = Some("Не удалось прочитать закрытый ключ".to_string());
+ return;
+ }
+ };
+ let a = match split[1].parse::<u64>() {
+ Ok(num) => num,
+ Err(_) => {
+ self.signed = None;
+ self.error = Some("Не удалось прочитать закрытый ключ".to_string());
+ return;
+ }
+ };
+ let p = match split[2].parse::<u64>() {
+ 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);
+}