From b9338c4b0046a9dcc4360ed8d7c782c707fd4f15 Mon Sep 17 00:00:00 2001 From: Anzor Magomedagaev Date: Tue, 13 May 2025 21:52:32 +0400 Subject: [PATCH 01/11] =?UTF-8?q?=D0=B2=D1=8B=D0=BF=D0=BE=D0=BB=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BF=D0=B5=D1=80=D0=B2=D0=B0=D1=8F=20?= =?UTF-8?q?=D1=87=D0=B0=D1=81=D1=82=D1=8C=20=D0=BB=D0=B0=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D1=80=D0=BD=D0=BE=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lab_2/part1/generation.cpp | 40 ++++++++++++++++++++++++++++++++++++ lab_2/part1/generation.java | 24 ++++++++++++++++++++++ lab_2/part1/sequenceCPP.txt | 1 + lab_2/part1/sequenceJAVA.txt | 1 + 4 files changed, 66 insertions(+) create mode 100644 lab_2/part1/generation.cpp create mode 100644 lab_2/part1/generation.java create mode 100644 lab_2/part1/sequenceCPP.txt create mode 100644 lab_2/part1/sequenceJAVA.txt diff --git a/lab_2/part1/generation.cpp b/lab_2/part1/generation.cpp new file mode 100644 index 000000000..5dbcce3e4 --- /dev/null +++ b/lab_2/part1/generation.cpp @@ -0,0 +1,40 @@ +#include +#include +#include + + +using namespace std; + +string getRandomSequence() { + + mt19937 gen(random_device{}()); + + uniform_int_distribution distribution(0,1); + + string sequence; + + for (size_t i = 0; i < 128; ++i) { + + sequence += to_string(distribution(gen)); + + } + + return sequence; + +} + +void saveToFile(const string& filename, const string& sequence) { + + ofstream file(filename); + + file << sequence; + +} + +int main() { + + string rndmSequence = getRandomSequence(); + + saveToFile("sequenceCPP.txt", rndmSequence); + +} \ No newline at end of file diff --git a/lab_2/part1/generation.java b/lab_2/part1/generation.java new file mode 100644 index 000000000..8bcd5ec14 --- /dev/null +++ b/lab_2/part1/generation.java @@ -0,0 +1,24 @@ +import java.io.FileWriter; +import java.io.IOException; +import java.util.Random; + +public class getRandomSequence { + public static final int BIT_LENGTH = 128; + + public static void main(String[] args) { + StringBuilder sequence = new StringBuilder(); + Random random = new Random(); + + for (int i = 0; i < BIT_LENGTH; i++) { + int bit = random.nextInt(2); + sequence.append(bit); + } + + try (FileWriter writer = new FileWriter("sequenceJAVA.txt")) { + writer.write(sequence.toString()); + System.out.println("Sequence saved to sequenceJAVA.txt"); + } catch (IOException e) { + System.err.println("Error writing to file: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/lab_2/part1/sequenceCPP.txt b/lab_2/part1/sequenceCPP.txt new file mode 100644 index 000000000..f39477603 --- /dev/null +++ b/lab_2/part1/sequenceCPP.txt @@ -0,0 +1 @@ +01000111101010111001110100100101001101110011100011101101101001111010000000000101110000000001001001011100111101101101011101111011 \ No newline at end of file diff --git a/lab_2/part1/sequenceJAVA.txt b/lab_2/part1/sequenceJAVA.txt new file mode 100644 index 000000000..a01c65cc5 --- /dev/null +++ b/lab_2/part1/sequenceJAVA.txt @@ -0,0 +1 @@ +01001011010100101101001100001011100110110011101011100101101010010100000111001001110101011110010110110001011101010100000100101111 \ No newline at end of file From 79a3f784e20f946241580c1bcc62427863547ce7 Mon Sep 17 00:00:00 2001 From: Anzor Magomedagaev Date: Tue, 13 May 2025 22:45:02 +0400 Subject: [PATCH 02/11] =?UTF-8?q?=D0=BD=D0=B0=D0=BF=D0=B8=D1=81=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B9?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D1=87=D1=82=D0=B5=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=B8=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D0=B8=20=D1=84=D0=B0?= =?UTF-8?q?=D0=B9=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lab_2/part2/test.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 lab_2/part2/test.py diff --git a/lab_2/part2/test.py b/lab_2/part2/test.py new file mode 100644 index 000000000..723e51d18 --- /dev/null +++ b/lab_2/part2/test.py @@ -0,0 +1,42 @@ +import math + + +from const import * + + +def read_file(filename: str) -> str: + """ + Reads sequence + + :param filename: Path to the file to read. + :return: sequence + """ + + try: + + with open(filename, 'r', encoding='utf-8') as file: + return file.read() + + except Exception as e: + + print(f"Error reading file: {e}") + + def write_file(filename: str, text: str) -> None: + """ + Writes and add text to a file. + + :param filename: Path to the file to write to. + :param text: The text + :return: None + """ + + try: + + with open(filename, 'w', encoding='utf-8') as file: + file.write(text) + + except Exception as e: + + print(f"Error writing file: {e}") + + From 789703cead1aaed04c8e34dc8a3076421eabbd9a Mon Sep 17 00:00:00 2001 From: Anzor Magomedagaev Date: Tue, 13 May 2025 23:12:00 +0400 Subject: [PATCH 03/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D1=81=D1=82=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lab_2/part2/test.py | 161 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 147 insertions(+), 14 deletions(-) diff --git a/lab_2/part2/test.py b/lab_2/part2/test.py index 723e51d18..9b096384f 100644 --- a/lab_2/part2/test.py +++ b/lab_2/part2/test.py @@ -1,15 +1,16 @@ import math +from scipy.special import gammainc from const import * def read_file(filename: str) -> str: """ - Reads sequence + Reads the sequence :param filename: Path to the file to read. - :return: sequence + :return: The sequence """ try: @@ -21,22 +22,154 @@ def read_file(filename: str) -> str: print(f"Error reading file: {e}") - def write_file(filename: str, text: str) -> None: - """ - Writes and add text to a file. - :param filename: Path to the file to write to. - :param text: The text - :return: None - """ +def write_file(filename: str, text: str) -> None: + """ + Writes the given text to a file. + + :param filename: Path to the file to write to. + :param text: The text + :return: None + """ + + try: + + with open(filename, 'w', encoding='utf-8') as file: + file.write(text) + + except Exception as e: + + print(f"Error writing file: {e}") + +def bit_frequency_analysis(bit_stream: str) -> float: + """ + Analyzes the frequency of bits in a binary string. + + :param bit_stream: The binary sequence + :return: Computed p-value + """ + + stream_length = len(bit_stream) + + if stream_length == 0: + raise ValueError("Empty bit stream provided") + + sum_bits = sum([1 if b == "1" else -1 for b in bit_stream]) + + p_val = math.erfc((abs(sum_bits) / math.sqrt(stream_length)) / math.sqrt(2)) + + return p_val + + +def consecutive_bits_test(bit_sequence: str) -> float: + """ + Checks for randomness by analyzing consecutive bit patterns. + + :param bit_sequence: The binary sequence + :return: Computed p-value + """ + + p_val = 0.0 + + seq_len = len(bit_sequence) + + prob_one = bit_sequence.count('1') / seq_len + + if abs(prob_one - 0.5) >= 2 / math.sqrt(seq_len): + return p_val + + transitions = 0 + + for i in range(seq_len - 1): + if bit_sequence[i] != bit_sequence[i + 1]: + transitions += 1 + + num = abs(transitions - 2 * seq_len * prob_one * (1 - prob_one)) + denom = 2 * math.sqrt(2 * seq_len) * prob_one * (1 - prob_one) + + return math.erfc(num / denom) + + +def max_ones_block_test(data: str) -> float: + """ + Evaluates the longest run of ones within fixed-length blocks. + + :param data: The binary sequence + :return: Computed p-value + """ + + data_len = len(data) + + if data_len < 128: + raise ValueError("Requires at least 128 bits") + + blocks_count = data_len // 8 + + freq_counts = [0, 0, 0, 0] + + for block_idx in range(blocks_count): + + current_block = data[block_idx * 8 : (block_idx + 1) * 8] + + max_run_len = 0 + current_run = 0 + + for bit in current_block: + + if bit == '1': + current_run += 1 + max_run_len = max(max_run_len, current_run) + else: + current_run = 0 + + match max_run_len: + case 0 | 1: + freq_counts[0] += 1 + case 2: + freq_counts[1] += 1 + case 3: + freq_counts[2] += 1 + case _: + freq_counts[3] += 1 + + chi_sq = 0.0 + + for i in range(len(freq_counts)): + chi_sq += (freq_counts[i] - 16 * PI[i]) ** 2 / (16 * PI[i]) + + p_val = gammainc(3 / 2, chi_sq / 2) + + return p_val + + +def main(): + + cpp_bits = read_file(cpp_sequence_txt) + java_bits = read_file(java_sequence_txt) + + cpp_freq_p = bit_frequency_analysis(cpp_bits) + cpp_runs_p = consecutive_bits_test(cpp_bits) + cpp_block_p = max_ones_block_test(cpp_bits) + + cpp_report = (f"CPP bit stream: {cpp_bits}\n\n" + f"Bit frequency analysis: {cpp_freq_p}\n" + f"Consecutive bits randomness test: {cpp_runs_p}\n" + f"Max ones block evaluation: {cpp_block_p}") + + write_file(res_test_cpp, cpp_report) - try: + java_freq_p = bit_frequency_analysis(java_bits) + java_runs_p = consecutive_bits_test(java_bits) + java_block_p = max_ones_block_test(java_bits) - with open(filename, 'w', encoding='utf-8') as file: - file.write(text) + java_report = (f"Java bit stream: {java_bits}\n\n" + f"Bit frequency analysis: {java_freq_p}\n" + f"Consecutive bits randomness test: {java_runs_p}\n" + f"Max ones block evaluation: {java_block_p}") - except Exception as e: + write_file(res_test_java, java_report) - print(f"Error writing file: {e}") +if __name__ == "__main__": + main() From bf11d51914f167d348197e0221a556acf435d8aa Mon Sep 17 00:00:00 2001 From: Anzor Magomedagaev Date: Tue, 13 May 2025 23:24:13 +0400 Subject: [PATCH 04/11] final version task2 --- lab_2/part2/const.py | 9 +++++++++ lab_2/part2/res_test_cpp.txt | 5 +++++ lab_2/part2/res_test_java.txt | 5 +++++ 3 files changed, 19 insertions(+) create mode 100644 lab_2/part2/const.py create mode 100644 lab_2/part2/res_test_cpp.txt create mode 100644 lab_2/part2/res_test_java.txt diff --git a/lab_2/part2/const.py b/lab_2/part2/const.py new file mode 100644 index 000000000..fdb59cd98 --- /dev/null +++ b/lab_2/part2/const.py @@ -0,0 +1,9 @@ + +cpp_sequence_txt = "../part1/sequenceCPP.txt" + +java_sequence_txt = "../part1/sequenceJAVA.txt" + +res_test_cpp = "res_test_cpp.txt" +res_test_java = "res_test_java.txt" + +PI = [0.2148, 0.3672, 0.2305, 0.1875] \ No newline at end of file diff --git a/lab_2/part2/res_test_cpp.txt b/lab_2/part2/res_test_cpp.txt new file mode 100644 index 000000000..8a8c85be7 --- /dev/null +++ b/lab_2/part2/res_test_cpp.txt @@ -0,0 +1,5 @@ +CPP sequence: 01000111101010111001110100100101001101110011100011101101101001111010000000000101110000000001001001011100111101101101011101111011 + +Frequency bit test: 0.7236736098317631 +Test for identical consecutive bits: 0.9911761003661306 +Test for the longest sequence of ones in a block: 0.9544660359991246 \ No newline at end of file diff --git a/lab_2/part2/res_test_java.txt b/lab_2/part2/res_test_java.txt new file mode 100644 index 000000000..7e9916e73 --- /dev/null +++ b/lab_2/part2/res_test_java.txt @@ -0,0 +1,5 @@ +Java sequence: 01001011010100101101001100001011100110110011101011100101101010010100000111001001110101011110010110110001011101010100000100101111 + +Frequency bit test: 0.8596837951986662 +Test for identical consecutive bits: 0.013203196374721247 +Test for the longest sequence of ones in a block: 0.35578609489358204 \ No newline at end of file From d8b065e2c7977a61919cac7b5f8f5d9adc6272b8 Mon Sep 17 00:00:00 2001 From: Anzor Magomedagaev Date: Mon, 9 Jun 2025 21:11:45 +0400 Subject: [PATCH 05/11] final version lab2 --- {lab_2 => lab2}/README.md | 0 lab2/consts.json | 7 ++ lab2/gen_cpp.cpp | 24 +++++ lab2/gen_java.java | 13 +++ lab2/main.py | 27 ++++++ lab2/result.json | 8 ++ lab2/sequence_cpp.cpp | 1 + lab2/sequence_java.txt | 1 + lab2/tests.py | 80 ++++++++++++++++ lab2/work_with_files.py | 51 ++++++++++ lab_2/part1/generation.cpp | 40 -------- lab_2/part1/generation.java | 24 ----- lab_2/part1/sequenceCPP.txt | 1 - lab_2/part1/sequenceJAVA.txt | 1 - lab_2/part2/const.py | 9 -- lab_2/part2/res_test_cpp.txt | 5 - lab_2/part2/res_test_java.txt | 5 - lab_2/part2/test.py | 175 ---------------------------------- 18 files changed, 212 insertions(+), 260 deletions(-) rename {lab_2 => lab2}/README.md (100%) create mode 100644 lab2/consts.json create mode 100644 lab2/gen_cpp.cpp create mode 100644 lab2/gen_java.java create mode 100644 lab2/main.py create mode 100644 lab2/result.json create mode 100644 lab2/sequence_cpp.cpp create mode 100644 lab2/sequence_java.txt create mode 100644 lab2/tests.py create mode 100644 lab2/work_with_files.py delete mode 100644 lab_2/part1/generation.cpp delete mode 100644 lab_2/part1/generation.java delete mode 100644 lab_2/part1/sequenceCPP.txt delete mode 100644 lab_2/part1/sequenceJAVA.txt delete mode 100644 lab_2/part2/const.py delete mode 100644 lab_2/part2/res_test_cpp.txt delete mode 100644 lab_2/part2/res_test_java.txt delete mode 100644 lab_2/part2/test.py diff --git a/lab_2/README.md b/lab2/README.md similarity index 100% rename from lab_2/README.md rename to lab2/README.md diff --git a/lab2/consts.json b/lab2/consts.json new file mode 100644 index 000000000..2967a41e9 --- /dev/null +++ b/lab2/consts.json @@ -0,0 +1,7 @@ +{ + "m": 8, + "pi": [0.2148, 0.3672, 0.2305, 0.1875], + "sequence_cpp": "sequence_cpp.txt", + "sequence_java": "sequence_java.txt", + "result": "result.json" +} \ No newline at end of file diff --git a/lab2/gen_cpp.cpp b/lab2/gen_cpp.cpp new file mode 100644 index 000000000..8a755a650 --- /dev/null +++ b/lab2/gen_cpp.cpp @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +void generate_bit_sequence() { + std::random_device rd; + std::mt19937_64 gen(rd()); + std::uniform_int_distribution dist(0, 1); + + std::bitset<128> bits; + for (int i = 0; i < 128; ++i) { + bits[i] = dist(gen); + } + + std::ofstream output_file("sequence_cpp.txt"); + output_file << bits; + output_file.close(); +} + +int main() { + generate_bit_sequence(); + return 0; +} \ No newline at end of file diff --git a/lab2/gen_java.java b/lab2/gen_java.java new file mode 100644 index 000000000..b831f7d8a --- /dev/null +++ b/lab2/gen_java.java @@ -0,0 +1,13 @@ +import java.io.FileWriter; +import java.io.IOException; + +public class Main { + public static void main(String[] args) { + StringBuilder bits = new StringBuilder(128); + for (int i = 0; i < 128; i++) { + bits.append((int) (Math.random() * 2)); + } + String sequence = bits.toString(); + System.out.println(sequence); + } +} \ No newline at end of file diff --git a/lab2/main.py b/lab2/main.py new file mode 100644 index 000000000..aa344ced0 --- /dev/null +++ b/lab2/main.py @@ -0,0 +1,27 @@ +from tests import frequency_bit_test, identical_consecutive_bits_test, longest_sequence_of_ones_test +from work_with_files import read_file, read_json, write_json + + +def main(): + try: + constants = read_json('consts.json') + + sequence_cpp = read_file(constants['sequence_cpp']) + sequence_java = read_file(constants['sequence_java']) + + stats = { + "C++ frequency bit test": frequency_bit_test(sequence_cpp), + "Java frequency bit test": frequency_bit_test(sequence_java), + "C++ identical bit sequence": identical_consecutive_bits_test(sequence_cpp), + "Java identical bit sequence": identical_consecutive_bits_test(sequence_java), + "C++ longest run of ones": longest_sequence_of_ones_test(sequence_cpp,constants['pi'],constants['m']), + "Java longest run of ones": longest_sequence_of_ones_test(sequence_java,constants['pi'],constants['m']) + } + + write_json(constants['result'], stats) + + except Exception as e: + print(e) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/lab2/result.json b/lab2/result.json new file mode 100644 index 000000000..2efaad225 --- /dev/null +++ b/lab2/result.json @@ -0,0 +1,8 @@ +{ + "C++ frequency bit test": 0.8596837951986662, + "Java frequency bit test": 0.4795001221869535, + "C++ identical bit sequence": 0.2899841563937249, + "Java identical bit sequence": 0.39923839789091575, + "C++ longest run of ones": 0.26745460619217515, + "Java longest run of ones": 0.21815226058275772 +} diff --git a/lab2/sequence_cpp.cpp b/lab2/sequence_cpp.cpp new file mode 100644 index 000000000..9e6c2189a --- /dev/null +++ b/lab2/sequence_cpp.cpp @@ -0,0 +1 @@ +11010011110110000011000011011001010000101001001000001100111101111101001011100011111011110111010110000011101100110000000100111011 \ No newline at end of file diff --git a/lab2/sequence_java.txt b/lab2/sequence_java.txt new file mode 100644 index 000000000..948c34e15 --- /dev/null +++ b/lab2/sequence_java.txt @@ -0,0 +1 @@ +10011101011001000111111110010010101100000100011011110011110001110001010000011111000110001100001110110001000110100010001001010010 \ No newline at end of file diff --git a/lab2/tests.py b/lab2/tests.py new file mode 100644 index 000000000..c1a98350e --- /dev/null +++ b/lab2/tests.py @@ -0,0 +1,80 @@ +import math + +from scipy.special import gammainc + + +def frequency_bit_test(sequence: str) -> float: + """ + Frequency bit test + :param sequence: bit sequence + :return: p-value + """ + n = len(sequence) + x = 0 + for i in sequence: + match i: + case '1': + x += 1 + case '0': + x += -1 + + s_n = abs(x) / math.sqrt(n) + p_value = math.erfc(s_n / math.sqrt(2)) + return p_value + + +def identical_consecutive_bits_test(sequence: str) -> float: + """ + Test for identical consecutive bits + :param sequence: bit sequence + :return: p-value + """ + n = len(sequence) + zeta = sequence.count('1') / n + + if abs(zeta - 0.5) >= (2 / math.sqrt(n)): + return 0.0 + else: + v_n = sum(1 for i in range(n - 1) if sequence[i] != sequence[i + 1]) + p_value = math.erfc(abs(v_n - 2 * n * zeta * (1 - zeta)) / (2 * math.sqrt(2 * n) * zeta * (1 - zeta))) + return p_value + + +def longest_sequence_of_ones_test(sequence: str, pi: list, m: int) -> float: + """ + Test for the longest sequence of ones in a block + :param sequence: bit sequence + :param pi: list of probabilities + :param m: block size + :return: p-value + """ + v = [0, 0, 0, 0] + + blocks = [sequence[i:i + m] for i in range(0, len(sequence), m)] + + for block in blocks: + counter = 0 + ones_count = 0 + + for i in block: + if i == '1': + counter += 1 + ones_count = max(ones_count, counter) + else: + counter = 0 + match ones_count: + case 0 | 1: + v[0] += 1 + case 2: + v[1] += 1 + case 3: + v[2] += 1 + case _: + v[3] += 1 + + chi_square = 0 + for i in range(0, 4): + chi_square += (((v[i] - 16 * pi[i]) ** 2) / (16 * pi[i])) + + p_value = gammainc(3 / 2, chi_square / 2) + return p_value \ No newline at end of file diff --git a/lab2/work_with_files.py b/lab2/work_with_files.py new file mode 100644 index 000000000..50e94f99c --- /dev/null +++ b/lab2/work_with_files.py @@ -0,0 +1,51 @@ +import json + + +def read_file(file_name: str) -> str: + """ + Reads the contents of the file + :param file_name: file name + :return: file contents + """ + try: + with open(file_name, 'r', encoding='utf-8') as file: + return file.read() + except FileNotFoundError: + raise FileNotFoundError(f"File not found") + except IOError: + raise IOError(f"Error reading file") + except Exception as e: + raise Exception("Error: {e}") + + +def read_json(file_name: str) -> dict: + """ + Reads the contents of a json file + :param file_name: file name + :return: dictionary + """ + try: + with open(file_name, 'r', encoding='utf-8') as file: + return json.load(file) + except FileNotFoundError: + raise FileNotFoundError(f"File not found") + except IOError: + raise IOError(f"Error reading file") + except Exception as e: + raise Exception("Error: {e}") + + +def write_json(file_name: str, text:float)->None: + """ + Writes the content to a json file + :param file_name: file name + :param text: text + :return: None + """ + try: + with open(file_name, 'w', encoding='utf-8') as file: + json.dump(text, file, ensure_ascii=False, indent=4) + except IOError: + raise IOError(f"Couldn't write to a file") + except Exception as e: + raise Exception("Error: {e}") \ No newline at end of file diff --git a/lab_2/part1/generation.cpp b/lab_2/part1/generation.cpp deleted file mode 100644 index 5dbcce3e4..000000000 --- a/lab_2/part1/generation.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include -#include - - -using namespace std; - -string getRandomSequence() { - - mt19937 gen(random_device{}()); - - uniform_int_distribution distribution(0,1); - - string sequence; - - for (size_t i = 0; i < 128; ++i) { - - sequence += to_string(distribution(gen)); - - } - - return sequence; - -} - -void saveToFile(const string& filename, const string& sequence) { - - ofstream file(filename); - - file << sequence; - -} - -int main() { - - string rndmSequence = getRandomSequence(); - - saveToFile("sequenceCPP.txt", rndmSequence); - -} \ No newline at end of file diff --git a/lab_2/part1/generation.java b/lab_2/part1/generation.java deleted file mode 100644 index 8bcd5ec14..000000000 --- a/lab_2/part1/generation.java +++ /dev/null @@ -1,24 +0,0 @@ -import java.io.FileWriter; -import java.io.IOException; -import java.util.Random; - -public class getRandomSequence { - public static final int BIT_LENGTH = 128; - - public static void main(String[] args) { - StringBuilder sequence = new StringBuilder(); - Random random = new Random(); - - for (int i = 0; i < BIT_LENGTH; i++) { - int bit = random.nextInt(2); - sequence.append(bit); - } - - try (FileWriter writer = new FileWriter("sequenceJAVA.txt")) { - writer.write(sequence.toString()); - System.out.println("Sequence saved to sequenceJAVA.txt"); - } catch (IOException e) { - System.err.println("Error writing to file: " + e.getMessage()); - } - } -} \ No newline at end of file diff --git a/lab_2/part1/sequenceCPP.txt b/lab_2/part1/sequenceCPP.txt deleted file mode 100644 index f39477603..000000000 --- a/lab_2/part1/sequenceCPP.txt +++ /dev/null @@ -1 +0,0 @@ -01000111101010111001110100100101001101110011100011101101101001111010000000000101110000000001001001011100111101101101011101111011 \ No newline at end of file diff --git a/lab_2/part1/sequenceJAVA.txt b/lab_2/part1/sequenceJAVA.txt deleted file mode 100644 index a01c65cc5..000000000 --- a/lab_2/part1/sequenceJAVA.txt +++ /dev/null @@ -1 +0,0 @@ -01001011010100101101001100001011100110110011101011100101101010010100000111001001110101011110010110110001011101010100000100101111 \ No newline at end of file diff --git a/lab_2/part2/const.py b/lab_2/part2/const.py deleted file mode 100644 index fdb59cd98..000000000 --- a/lab_2/part2/const.py +++ /dev/null @@ -1,9 +0,0 @@ - -cpp_sequence_txt = "../part1/sequenceCPP.txt" - -java_sequence_txt = "../part1/sequenceJAVA.txt" - -res_test_cpp = "res_test_cpp.txt" -res_test_java = "res_test_java.txt" - -PI = [0.2148, 0.3672, 0.2305, 0.1875] \ No newline at end of file diff --git a/lab_2/part2/res_test_cpp.txt b/lab_2/part2/res_test_cpp.txt deleted file mode 100644 index 8a8c85be7..000000000 --- a/lab_2/part2/res_test_cpp.txt +++ /dev/null @@ -1,5 +0,0 @@ -CPP sequence: 01000111101010111001110100100101001101110011100011101101101001111010000000000101110000000001001001011100111101101101011101111011 - -Frequency bit test: 0.7236736098317631 -Test for identical consecutive bits: 0.9911761003661306 -Test for the longest sequence of ones in a block: 0.9544660359991246 \ No newline at end of file diff --git a/lab_2/part2/res_test_java.txt b/lab_2/part2/res_test_java.txt deleted file mode 100644 index 7e9916e73..000000000 --- a/lab_2/part2/res_test_java.txt +++ /dev/null @@ -1,5 +0,0 @@ -Java sequence: 01001011010100101101001100001011100110110011101011100101101010010100000111001001110101011110010110110001011101010100000100101111 - -Frequency bit test: 0.8596837951986662 -Test for identical consecutive bits: 0.013203196374721247 -Test for the longest sequence of ones in a block: 0.35578609489358204 \ No newline at end of file diff --git a/lab_2/part2/test.py b/lab_2/part2/test.py deleted file mode 100644 index 9b096384f..000000000 --- a/lab_2/part2/test.py +++ /dev/null @@ -1,175 +0,0 @@ -import math - -from scipy.special import gammainc - -from const import * - - -def read_file(filename: str) -> str: - """ - Reads the sequence - - :param filename: Path to the file to read. - :return: The sequence - """ - - try: - - with open(filename, 'r', encoding='utf-8') as file: - return file.read() - - except Exception as e: - - print(f"Error reading file: {e}") - - -def write_file(filename: str, text: str) -> None: - """ - Writes the given text to a file. - - :param filename: Path to the file to write to. - :param text: The text - :return: None - """ - - try: - - with open(filename, 'w', encoding='utf-8') as file: - file.write(text) - - except Exception as e: - - print(f"Error writing file: {e}") - -def bit_frequency_analysis(bit_stream: str) -> float: - """ - Analyzes the frequency of bits in a binary string. - - :param bit_stream: The binary sequence - :return: Computed p-value - """ - - stream_length = len(bit_stream) - - if stream_length == 0: - raise ValueError("Empty bit stream provided") - - sum_bits = sum([1 if b == "1" else -1 for b in bit_stream]) - - p_val = math.erfc((abs(sum_bits) / math.sqrt(stream_length)) / math.sqrt(2)) - - return p_val - - -def consecutive_bits_test(bit_sequence: str) -> float: - """ - Checks for randomness by analyzing consecutive bit patterns. - - :param bit_sequence: The binary sequence - :return: Computed p-value - """ - - p_val = 0.0 - - seq_len = len(bit_sequence) - - prob_one = bit_sequence.count('1') / seq_len - - if abs(prob_one - 0.5) >= 2 / math.sqrt(seq_len): - return p_val - - transitions = 0 - - for i in range(seq_len - 1): - if bit_sequence[i] != bit_sequence[i + 1]: - transitions += 1 - - num = abs(transitions - 2 * seq_len * prob_one * (1 - prob_one)) - denom = 2 * math.sqrt(2 * seq_len) * prob_one * (1 - prob_one) - - return math.erfc(num / denom) - - -def max_ones_block_test(data: str) -> float: - """ - Evaluates the longest run of ones within fixed-length blocks. - - :param data: The binary sequence - :return: Computed p-value - """ - - data_len = len(data) - - if data_len < 128: - raise ValueError("Requires at least 128 bits") - - blocks_count = data_len // 8 - - freq_counts = [0, 0, 0, 0] - - for block_idx in range(blocks_count): - - current_block = data[block_idx * 8 : (block_idx + 1) * 8] - - max_run_len = 0 - current_run = 0 - - for bit in current_block: - - if bit == '1': - current_run += 1 - max_run_len = max(max_run_len, current_run) - else: - current_run = 0 - - match max_run_len: - case 0 | 1: - freq_counts[0] += 1 - case 2: - freq_counts[1] += 1 - case 3: - freq_counts[2] += 1 - case _: - freq_counts[3] += 1 - - chi_sq = 0.0 - - for i in range(len(freq_counts)): - chi_sq += (freq_counts[i] - 16 * PI[i]) ** 2 / (16 * PI[i]) - - p_val = gammainc(3 / 2, chi_sq / 2) - - return p_val - - -def main(): - - cpp_bits = read_file(cpp_sequence_txt) - java_bits = read_file(java_sequence_txt) - - cpp_freq_p = bit_frequency_analysis(cpp_bits) - cpp_runs_p = consecutive_bits_test(cpp_bits) - cpp_block_p = max_ones_block_test(cpp_bits) - - cpp_report = (f"CPP bit stream: {cpp_bits}\n\n" - f"Bit frequency analysis: {cpp_freq_p}\n" - f"Consecutive bits randomness test: {cpp_runs_p}\n" - f"Max ones block evaluation: {cpp_block_p}") - - write_file(res_test_cpp, cpp_report) - - java_freq_p = bit_frequency_analysis(java_bits) - java_runs_p = consecutive_bits_test(java_bits) - java_block_p = max_ones_block_test(java_bits) - - java_report = (f"Java bit stream: {java_bits}\n\n" - f"Bit frequency analysis: {java_freq_p}\n" - f"Consecutive bits randomness test: {java_runs_p}\n" - f"Max ones block evaluation: {java_block_p}") - - write_file(res_test_java, java_report) - - -if __name__ == "__main__": - main() - From e5e875977815f733dae42e84111e23d16fd85cc0 Mon Sep 17 00:00:00 2001 From: Anzor Magomedagaev Date: Tue, 10 Jun 2025 00:48:52 +0400 Subject: [PATCH 06/11] f --- lab_3/asymmetric_cripto.py | 80 +++++++++++++++++++++++++++++++ lab_3/decrypted_text.txt | 1 + lab_3/encrypted_symmetric_key.bin | 2 + lab_3/encrypted_text.txt | 0 4 files changed, 83 insertions(+) create mode 100644 lab_3/asymmetric_cripto.py create mode 100644 lab_3/decrypted_text.txt create mode 100644 lab_3/encrypted_symmetric_key.bin create mode 100644 lab_3/encrypted_text.txt diff --git a/lab_3/asymmetric_cripto.py b/lab_3/asymmetric_cripto.py new file mode 100644 index 000000000..1006ca315 --- /dev/null +++ b/lab_3/asymmetric_cripto.py @@ -0,0 +1,80 @@ +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import padding, rsa +from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey + + +class AsymmetricEncryption: + """ Класс для асимметричного шифрования с использованием алгоритма RSA """ + + @staticmethod + def generate_rsa_keys() -> tuple[RSAPrivateKey, RSAPublicKey]: + """ + Генерирует пару RSA ключей + :return: кортеж из приватного и публичного ключей + """ + private_key = rsa.generate_private_key( + public_exponent=65537, + key_size=2048 + ) + return private_key, private_key.public_key() + + @staticmethod + def serialization_asymmetric_public_key(public_key: RSAPublicKey) -> bytes: + """ + Сериализует публичный RSA ключ в PEM формат + :param public_key: публичный ключ + :return: публичный ключ в PEM формате + """ + pem_public_key = public_key.public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo + ) + return pem_public_key + + @staticmethod + def serialization_asymmetric_private_key(private_key: RSAPrivateKey) -> bytes: + """ + Сериализует приватный RSA ключ в PEM формат + :param private_key: приватный ключ + :return: приватный ключ в PEM формате + """ + pem_private_key = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption() + ) + return pem_private_key + + @staticmethod + def rsa_encrypt(public_key: RSAPublicKey, data: bytes) -> bytes: + """ + Шифрует данные + :param public_key: публичный ключ + :param data: данные + :return: зашифрованные данные + """ + return public_key.encrypt( + data, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), + label=None + ) + ) + + @staticmethod + def rsa_decrypt(private_key: RSAPrivateKey, encrypted_data: bytes) -> bytes: + """ + Расшифровывает данные + :param private_key: приватный ключ + :param encrypted_data: зашифрованные данные + :return: расшифрованные данные + """ + return private_key.decrypt( + encrypted_data, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), + label=None + ) + ) \ No newline at end of file diff --git a/lab_3/decrypted_text.txt b/lab_3/decrypted_text.txt new file mode 100644 index 000000000..36e4d809f --- /dev/null +++ b/lab_3/decrypted_text.txt @@ -0,0 +1 @@ +У него в пятнадцати верстах от постоялого дворика хорошее имение в двести душ, или, как он выражается с тех пор, как размежевался с крестьянами и завел «ферму», — в две тысячи десятин земли. Отец его, боевой генерал 1812 года, полуграмотный, грубый, но не злой русский человек, всю жизнь свою тянул лямку, командовал сперва бригадой, потом дивизией и постоянно жил в провинции, где в силу своего чина играл довольно значительную роль. Николай Петрович родился на юге России, подобно старшему своему брату Павлу, о котором речь впереди, и воспитывался до четырнадцатилетнего возраста дома, окруженный дешевыми гувернерами, развязными, но подобострастными адъютантами и прочими полковыми и штабными личностями. Родительница его, из фамилии Колязиных, в девицах Agathe, а в генеральшах Агафоклея Кузьминишна Кирсанова, принадлежала к числу «матушек-командирш», носила пышные чепцы и шумные шелковые платья, в церкви подходила первая ко кресту, говорила громко и много, допускала детей утром к ручке, на ночь их благословляла, — словом, жила в свое удовольствие. В качестве генеральского сына Николай Петрович — хотя не только не отличался храбростью, но даже заслужил прозвище трусишки — должен был, подобно брату Павлу, поступить в военную службу; но он переломил себе ногу в самый тот день, когда уже прибыло известие об его определении, и, пролежав два месяца в постели, на всю жизнь остался «хроменьким». Отец махнул на него рукой и пустил его по штатской. Он повез его в Петербург, как только ему минул восемнадцатый год, и поместил его в университет. Кстати, брат его о ту пору вышел офицером в гвардейский полк. Молодые люди стали жить вдвоем, на одной квартире, под отдаленным надзором двоюродного дяди с материнской стороны, Ильи Колязина, важного чиновника. \ No newline at end of file diff --git a/lab_3/encrypted_symmetric_key.bin b/lab_3/encrypted_symmetric_key.bin new file mode 100644 index 000000000..03b198f00 --- /dev/null +++ b/lab_3/encrypted_symmetric_key.bin @@ -0,0 +1,2 @@ +SH����lя�܎ ��?� +�����sE��v[��!^Όr��C,�n\���� ���<�\f�¦8[�ҩ� �֭RiP�1(`(1}U,�1���:��ի�4M�H��u��J������,+v�@˷���\b '�2Z�`����Ύ���F�^�CNvX��b/��m3����i��R|��\�ß�z�M�=*�����#C��)�=�NN���^�Gկ�b��A��N��<V3¶���M��X���(��3 diff --git a/lab_3/encrypted_text.txt b/lab_3/encrypted_text.txt new file mode 100644 index 000000000..e69de29bb From 93e0e2ff1fa9a4179b26d10c46f4cc9e15845bf3 Mon Sep 17 00:00:00 2001 From: Anzor Magomedagaev Date: Tue, 10 Jun 2025 00:50:03 +0400 Subject: [PATCH 07/11] f --- lab_3/original_text.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 lab_3/original_text.txt diff --git a/lab_3/original_text.txt b/lab_3/original_text.txt new file mode 100644 index 000000000..36e4d809f --- /dev/null +++ b/lab_3/original_text.txt @@ -0,0 +1 @@ +У него в пятнадцати верстах от постоялого дворика хорошее имение в двести душ, или, как он выражается с тех пор, как размежевался с крестьянами и завел «ферму», — в две тысячи десятин земли. Отец его, боевой генерал 1812 года, полуграмотный, грубый, но не злой русский человек, всю жизнь свою тянул лямку, командовал сперва бригадой, потом дивизией и постоянно жил в провинции, где в силу своего чина играл довольно значительную роль. Николай Петрович родился на юге России, подобно старшему своему брату Павлу, о котором речь впереди, и воспитывался до четырнадцатилетнего возраста дома, окруженный дешевыми гувернерами, развязными, но подобострастными адъютантами и прочими полковыми и штабными личностями. Родительница его, из фамилии Колязиных, в девицах Agathe, а в генеральшах Агафоклея Кузьминишна Кирсанова, принадлежала к числу «матушек-командирш», носила пышные чепцы и шумные шелковые платья, в церкви подходила первая ко кресту, говорила громко и много, допускала детей утром к ручке, на ночь их благословляла, — словом, жила в свое удовольствие. В качестве генеральского сына Николай Петрович — хотя не только не отличался храбростью, но даже заслужил прозвище трусишки — должен был, подобно брату Павлу, поступить в военную службу; но он переломил себе ногу в самый тот день, когда уже прибыло известие об его определении, и, пролежав два месяца в постели, на всю жизнь остался «хроменьким». Отец махнул на него рукой и пустил его по штатской. Он повез его в Петербург, как только ему минул восемнадцатый год, и поместил его в университет. Кстати, брат его о ту пору вышел офицером в гвардейский полк. Молодые люди стали жить вдвоем, на одной квартире, под отдаленным надзором двоюродного дяди с материнской стороны, Ильи Колязина, важного чиновника. \ No newline at end of file From 95466d52f915165df06f4e46b52c5113e5d0baf5 Mon Sep 17 00:00:00 2001 From: Anzor Magomedagaev Date: Tue, 10 Jun 2025 00:50:40 +0400 Subject: [PATCH 08/11] f --- lab_3/private_key.pem | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 lab_3/private_key.pem diff --git a/lab_3/private_key.pem b/lab_3/private_key.pem new file mode 100644 index 000000000..d4ad3a44c --- /dev/null +++ b/lab_3/private_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAmu7q9JRs4tXfeD5jimIVQ68LsnYF0sdCVa/OAKqO2RpZ82ZY +UaQbz9xEQEVbxZaGVXvaEE7z/ZCbksmiw2JNXFx/3Dqx+hnxBXew/ER3Us8S0fdy +RI8XF37br1Ctx+cKSV2Eg5VlYXZNNXMCHPk85sALi7U4AM1iQ8Im7slQq4mtv+Ao +s7CudwlWhKhU1+83U79dSzhY1eKEVrzZ4l9zxVsJz+fJwqPTpNaJRlY8ynE1Y/ea +WMcc2qdYTEjTUvfqY+8mZw0k8+ou/2maNn4pJiZ41Ysvt8wWTrCtrSbEmdcAb890 +Ub9X4JKlqrE2Q4Kugz/+uyEfrUbw9yyMdJC8gwIDAQABAoIBAA+qWapqOYpECsjr +MgBjg3fpAptEULlruVrVoFQz6qasAe1Y61Qx7jf5sxL2kF1tp16MW9OrUANS9FAG +wETWMzFEDw+TBbzek560Z/pR5+jBFEuTpAOnnjObeZYD59ZfF4ysfoIZgHs2zX66 +hrusPcqtH128cJGwMp/cSTh6tYPqiwYIlFPzV45FjsekcFW/aDIvx9Uz4gcO5L7J +QN+Z3M9OYdAsJW/5bGnnYkI69xJNjjuWusXLXAhYzMD2Dqf6MeJkEJAbX706xvpR +bM8sgfQ9hHEWZDbA3/paVs2UhsN7Bj+WLHLpVLi+Hvv9g5TIcX+bAmPWS0yDkcgn +odfe1FECgYEA0v8r6R64ET2fRt7rNKUFUhW7qjtIQ5jeIsGV198EpEK7wo7jLybc +9VWF9Wuu/d4ne2PXHJXGBthDMfH+qhd7hhFGc5MedPl2cmJACuecrhFrxzPpx8ZY +ipfCocQJoXC5ZlkYmAwqUdLDhsP/Wj7ewwddmH2Exm531qZgLwIGxZECgYEAu/qS +bkS5bhaBVdrPzjt2InPF2QASHAo8xfaByeeWhV4Rc+4/tTPXO9O8gt7f/FQ+bNNz +F+zC2vOBN5Kkk5ZHVcstBH2q+FpRk9BkpMi8T6Xufk2+8s2T0IK+e8tQsuS+a9dN +N8A69y1voY2HyR1/4kmVjxnKgm9u9Cg3yJNyhtMCgYEAv6q2q7yQ/nBY2Js1VAw3 +qho98GSLv4QE/dOWl5NqdwB76T+9Vh7ahy4aUxdvzgNZIDhQtxHC4oLff2ZRrRdJ +yT62HdTdzOqz0zI29PDynhkLK9iXnDcsRTGYxzP6f6GTeUqkEbKzWsK3hRtUQhls +aAOv3Q7gZxUAXYejRfB0UFECgYB+SagotrkREcOQZ3GmruH94WOxFtAT0Hjl0md9 +ur2wGfOFvDFGzm4yPlzuW0eFoR9TQ3eWQjTinidYq4cvtA12wQocc0TyltMpiB6l +akrBA8xHRHodayl8MupABubPWMfpcXrqEpZKy1as5YWtAsmQwDjfK8eWe8DB/WcE +tLKDiwKBgAxCwy95E/e4cyOA9s3SkhFpyEGs56YLHeRUmOtsbRnu6dC0nNJs2ZiZ +Ku/qB9+9evqEEUYN75mtZlE8DHGT8zhxI8MWta+v6OkWPANcdxgRecnxSHbmMjLu +kh+hqSHnPwwatbO9s78ml3FocCM6uT8dLmJSz8uA0dQDzMTQzpHa +-----END RSA PRIVATE KEY----- \ No newline at end of file From f938c9482f3883b3a5e85df3b3adc5ca9031311d Mon Sep 17 00:00:00 2001 From: Anzor Magomedagaev Date: Tue, 10 Jun 2025 00:51:38 +0400 Subject: [PATCH 09/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=B0=D0=B1=D0=BB=D0=B8=D0=BA?= =?UTF-8?q?=20=D0=BA=D0=BB=D1=8E=D1=87=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lab_3/public_key.pem | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 lab_3/public_key.pem diff --git a/lab_3/public_key.pem b/lab_3/public_key.pem new file mode 100644 index 000000000..5abebeb8b --- /dev/null +++ b/lab_3/public_key.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmu7q9JRs4tXfeD5jimIV +Q68LsnYF0sdCVa/OAKqO2RpZ82ZYUaQbz9xEQEVbxZaGVXvaEE7z/ZCbksmiw2JN +XFx/3Dqx+hnxBXew/ER3Us8S0fdyRI8XF37br1Ctx+cKSV2Eg5VlYXZNNXMCHPk8 +5sALi7U4AM1iQ8Im7slQq4mtv+Aos7CudwlWhKhU1+83U79dSzhY1eKEVrzZ4l9z +xVsJz+fJwqPTpNaJRlY8ynE1Y/eaWMcc2qdYTEjTUvfqY+8mZw0k8+ou/2maNn4p +JiZ41Ysvt8wWTrCtrSbEmdcAb890Ub9X4JKlqrE2Q4Kugz/+uyEfrUbw9yyMdJC8 +gwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file From f9b0f11744cc9faaa42cea49d721028107501400 Mon Sep 17 00:00:00 2001 From: Anzor Magomedagaev Date: Tue, 10 Jun 2025 00:53:30 +0400 Subject: [PATCH 10/11] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B0=20?= =?UTF-8?q?=D1=81=D0=B8=D0=BC=D0=BC=D0=B5=D1=82=D1=80=D0=B8=D1=87=D0=BD?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=20=D1=88=D0=B8=D1=84=D1=80=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D1=81=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=D0=BC=20AES?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lab_3/settings.json | 9 +++++ lab_3/symmetric_crypto.py | 73 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 lab_3/settings.json create mode 100644 lab_3/symmetric_crypto.py diff --git a/lab_3/settings.json b/lab_3/settings.json new file mode 100644 index 000000000..816eecaa0 --- /dev/null +++ b/lab_3/settings.json @@ -0,0 +1,9 @@ +{ + "public_key" : "public_key.pem", + "private_key" : "private_key.pem", + "encrypted_symmetric_key" : "encrypted_symmetric_key.bin", + "original_text" : "original_text.txt", + "encrypted_text" : "encrypted_text.txt", + "decrypted_text" : "decrypted_text.txt", + "key_size": 256 +} \ No newline at end of file diff --git a/lab_3/symmetric_crypto.py b/lab_3/symmetric_crypto.py new file mode 100644 index 000000000..e3e01d22d --- /dev/null +++ b/lab_3/symmetric_crypto.py @@ -0,0 +1,73 @@ +import os + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import padding +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + + +class SymmetricalEncryption: + """ Класс для симметричного шифрования с использованием алгоритма AES """ + + @staticmethod + def generate_key(key_size: int) -> bytes: + """ + Генерирует ключ + :param key_size: размер ключа в битах + :return: ключ + """ + return os.urandom(key_size // 8) + + @staticmethod + def padding_data(data: bytes) -> bytes: + """ + Добавляет паддинг к данным + :param data: данные + :return: данные с добавленным паддингом + """ + padder = padding.ANSIX923(128).padder() + padded_data = padder.update(data) + padder.finalize() + return padded_data + + @staticmethod + def encrypt_data(data: bytes, key: bytes) -> bytes: + """ + Шифрует данные + :param data: данные + :param key: ключ + :return: зашифрованные данные + """ + iv = os.urandom(16) + + cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()) + encryptor = cipher.encryptor() + ciphertext = encryptor.update(SymmetricalEncryption.padding_data(data)) + encryptor.finalize() + + return iv + ciphertext + + @staticmethod + def unpadding_data(data: bytes) -> bytes: + """ + Удаляет паддинг из данных + :param data: данные + :return: данные без паддинга + """ + unpadder = padding.ANSIX923(128).unpadder() + unpadded_data = unpadder.update(data) + unpadder.finalize() + return unpadded_data + + @staticmethod + def decrypt_data(data: bytes, key: bytes) -> bytes: + """ + Расшифровывает данные + :param data: данные + :param key: ключ + :return: расшифрованные данные + """ + iv = data[:16] + ciphertext = data[16:] + + cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()) + decryptor = cipher.decryptor() + padded_data = decryptor.update(ciphertext) + decryptor.finalize() + + return SymmetricalEncryption.unpadding_data(padded_data) From 18d54a8056ea16aad5961e5a90daab405268d7ea Mon Sep 17 00:00:00 2001 From: Anzor Magomedagaev Date: Tue, 10 Jun 2025 01:08:13 +0400 Subject: [PATCH 11/11] =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=BD=D0=BD=D0=B0=D1=8F=20final=20version=20=D1=81=20?= =?UTF-8?q?=D1=83=D0=B6=D0=B5=20=D1=81=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD=D1=8B=D0=BC=D0=B8=20=D0=BA?= =?UTF-8?q?=D0=BB=D1=8E=D1=87=D0=B0=D0=BC=D0=B8=20=D0=B8=20=D0=B7=D0=B0?= =?UTF-8?q?=D1=88=D0=B8=D1=84=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD=D1=8B?= =?UTF-8?q?=D0=BC=D0=B8=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lab_3/encrypted_symmetric_key.bin | Bin 478 -> 256 bytes lab_3/encrypted_text.txt | 0 lab_3/main.py | 171 ++++++++++++++++++++++++++++++ lab_3/private_key.pem | 27 ----- lab_3/public_key.pem | 9 -- lab_3/work_with_files.py | 65 ++++++++++++ 6 files changed, 236 insertions(+), 36 deletions(-) delete mode 100644 lab_3/encrypted_text.txt create mode 100644 lab_3/main.py delete mode 100644 lab_3/private_key.pem delete mode 100644 lab_3/public_key.pem create mode 100644 lab_3/work_with_files.py diff --git a/lab_3/encrypted_symmetric_key.bin b/lab_3/encrypted_symmetric_key.bin index 03b198f006c755487afdc009bef3c6606ae93a6b..a4e87ebec57179e8deb7199c352b7b6dcec3db17 100644 GIT binary patch literal 256 zcmV+b0ssD4af9#sDfNF^AU2Zoi&&yafe^!noNXF%zmQh>CbeH2oh=17`khC4m7c3zfM)Dp76YLQKY1UN5O{WN}?#Dq2$s GvAIQBD}sdp literal 478 zcmWIcc)x!y9OZ~#><4o0^l?Lk?12<77lh3Mp`?IRu`7gK77d}r6ywhI6hYX|IzT!v z2Eu`mAj3o;OdB8-lLjOXEwcb=zO)iZC;;)bwL$fn0YHYKMuLW6ZK#d_kS%QpB!qz& zh^!#g)zv`S#1}|F9bO6%_kvK!q@0d+8IbRAdOKW{DJF?iomn2pH;Muh32+G@<6Iw{ zC+`Mi#sRUjUs(i1G)W&q=NbcPaR?hkWkQ%iH4qx)@5A$fL=_PGG6D%(Eg%6$96**b zzcY|z0%A=dwgqB8KOg}?AY0w9t_PAy5CKOZB?iReP&GD;VaA8H0R=!2Aqm8wumB>c PJAo_>AZ7((V_q%*Fw{Hj diff --git a/lab_3/encrypted_text.txt b/lab_3/encrypted_text.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/lab_3/main.py b/lab_3/main.py new file mode 100644 index 000000000..7a9083d98 --- /dev/null +++ b/lab_3/main.py @@ -0,0 +1,171 @@ +import argparse + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import serialization + +from asymmetric_cripto import AsymmetricEncryption +from symmetric_crypto import SymmetricalEncryption +from work_with_files import read_binary_file, write_binary_file, read_json, write_json + + +def generate_keys(key_size, public_key_path: str, + private_key_path: str, + encrypted_symmetric_key_path: str ) -> None: + """ + Генерирует все ключи + :param key_size: размер симметричного ключа + :param public_key_path: путь для сохранения публичного RSA ключа + :param private_key_path: путь для сохранения приватного RSA ключа + :param encrypted_symmetric_key_path: путь для сохранения зашифрованного симметричного ключа + """ + try: + symmetric_key = SymmetricalEncryption.generate_key(key_size) + private_key, public_key = AsymmetricEncryption.generate_rsa_keys() + + serialized_public = AsymmetricEncryption.serialization_asymmetric_public_key(public_key) + serialized_private = AsymmetricEncryption.serialization_asymmetric_private_key(private_key) + + encrypted_symmetric_key = AsymmetricEncryption.rsa_encrypt(public_key, symmetric_key) + + write_binary_file(public_key_path, serialized_public) + write_binary_file(private_key_path, serialized_private) + write_binary_file(encrypted_symmetric_key_path, encrypted_symmetric_key) + + except Exception as e: + raise RuntimeError(f"Ошибка в процессе генерации ключей: {str(e)}") + + +def encrypt_data(original_text_path: str, + private_key_path: str, + encrypted_symmetric_key_path: str, + encrypt_text_path: str) -> None: + """ + Шифрует данные + :param original_text_path: путь к файлу с исходными данными для шифрования + :param private_key_path: путь к файлу с приватным RSA ключом + :param encrypted_symmetric_key_path: путь к файлу с зашифрованным симметричным ключом + :param encrypt_text_path: путь для сохранения зашифрованных данных + """ + try: + original_text = read_binary_file(original_text_path) + private_key_bytes = read_binary_file(private_key_path) + encrypted_symmetric_key = read_binary_file(encrypted_symmetric_key_path) + + private_key = serialization.load_pem_private_key( + private_key_bytes, + password=None, + backend=default_backend() + ) + + symmetric_key = AsymmetricEncryption.rsa_decrypt(private_key, encrypted_symmetric_key) + + encrypted_text = SymmetricalEncryption.encrypt_data(original_text, symmetric_key) + write_binary_file(encrypt_text_path, encrypted_text) + except Exception as e: + raise RuntimeError(f"Ошибка в процессе шифрования данных: {str(e)}") + + +def decrypt_data(encrypted_text_path: str, + private_key_path: str, + encrypted_symmetric_key_path: str, + decrypted_text_path: str) -> None: + """ + Дешифрует данные + :param encrypted_text_path: путь к файлц с зашифрованными данными + :param private_key_path: путь к файлу с приватным RSA ключом + :param encrypted_symmetric_key_path: путь к файлу с зашифрованным симметричным ключом + :param decrypted_text_path: путь к файлу для сохранения расшифрованных данных + :return: + """ + try: + encrypted_text = read_binary_file(encrypted_text_path) + private_key_bytes = read_binary_file(private_key_path) + encrypted_symmetric_key = read_binary_file(encrypted_symmetric_key_path) + + private_key = serialization.load_pem_private_key( + private_key_bytes, + password=None, + backend=default_backend() + ) + + symmetric_key = AsymmetricEncryption.rsa_decrypt(private_key, encrypted_symmetric_key) + + decrypted_text = SymmetricalEncryption.decrypt_data(encrypted_text, symmetric_key) + write_binary_file(decrypted_text_path, decrypted_text) + except Exception as e: + raise RuntimeError(f"Ошибка в процессе дешифрования данных: {str(e)}") + + +def update_key_size(key_size: int) -> None: + """ + Изменяет размер ключа в settings.json + :param key_size: новый размер ключа + """ + try: + if key_size not in [128, 192, 256]: + raise ValueError("Размер ключа не подходит. Допустимые значения: 128, 192, 256") + + settings = read_json('settings.json') + settings['key_size'] = key_size + write_json('settings.json', settings) + print(f"Размер ключа изменен на {key_size} бит") + + except Exception as e: + raise RuntimeError(f"Ошибка при изменении размера ключа: {str(e)}") + + +def main() -> None: + try: + parser = argparse.ArgumentParser() + + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('-gen', '--generation', action='store_true', help='Режим генерации ключей') + group.add_argument('-enc', '--encryption', action='store_true', help='Режим шифрования') + group.add_argument('-dec', '--decryption', action='store_true', help='Режим дешифрования') + group.add_argument('-key','--key-size', type=int, help='Изменить размер ключа') + + args = parser.parse_args() + + settings = read_json('settings.json') + + match (args.generation, args.encryption, args.decryption, args.key_size): + case (True, False, False, None): + print(f"Запуск генерации ключей ({settings['key_size']} бит)...") + generate_keys( + settings['key_size'], + settings['public_key'], + settings['private_key'], + settings['encrypted_symmetric_key'] + ) + print("Генерация ключей завершена успешно!") + + case (False, True, False, None): + print("Запуск шифрования данных...") + encrypt_data( + settings['original_text'], + settings['private_key'], + settings['encrypted_symmetric_key'], + settings['encrypted_text'] + ) + print("Шифрование завершено успешно!") + + case (False, False, True, None): + print("Запуск дешифрования данных...") + decrypt_data( + settings['encrypted_text'], + settings['private_key'], + settings['encrypted_symmetric_key'], + settings['decrypted_text'] + ) + print("Дешифрование завершено успешно!") + + case (False, False, False, size): + update_key_size(size) + case _: + raise ValueError("Неверная комбинация режимов работы") + + except Exception as e: + print(f"Ошибка: {str(e)}") + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/lab_3/private_key.pem b/lab_3/private_key.pem deleted file mode 100644 index d4ad3a44c..000000000 --- a/lab_3/private_key.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAmu7q9JRs4tXfeD5jimIVQ68LsnYF0sdCVa/OAKqO2RpZ82ZY -UaQbz9xEQEVbxZaGVXvaEE7z/ZCbksmiw2JNXFx/3Dqx+hnxBXew/ER3Us8S0fdy -RI8XF37br1Ctx+cKSV2Eg5VlYXZNNXMCHPk85sALi7U4AM1iQ8Im7slQq4mtv+Ao -s7CudwlWhKhU1+83U79dSzhY1eKEVrzZ4l9zxVsJz+fJwqPTpNaJRlY8ynE1Y/ea -WMcc2qdYTEjTUvfqY+8mZw0k8+ou/2maNn4pJiZ41Ysvt8wWTrCtrSbEmdcAb890 -Ub9X4JKlqrE2Q4Kugz/+uyEfrUbw9yyMdJC8gwIDAQABAoIBAA+qWapqOYpECsjr -MgBjg3fpAptEULlruVrVoFQz6qasAe1Y61Qx7jf5sxL2kF1tp16MW9OrUANS9FAG -wETWMzFEDw+TBbzek560Z/pR5+jBFEuTpAOnnjObeZYD59ZfF4ysfoIZgHs2zX66 -hrusPcqtH128cJGwMp/cSTh6tYPqiwYIlFPzV45FjsekcFW/aDIvx9Uz4gcO5L7J -QN+Z3M9OYdAsJW/5bGnnYkI69xJNjjuWusXLXAhYzMD2Dqf6MeJkEJAbX706xvpR -bM8sgfQ9hHEWZDbA3/paVs2UhsN7Bj+WLHLpVLi+Hvv9g5TIcX+bAmPWS0yDkcgn -odfe1FECgYEA0v8r6R64ET2fRt7rNKUFUhW7qjtIQ5jeIsGV198EpEK7wo7jLybc -9VWF9Wuu/d4ne2PXHJXGBthDMfH+qhd7hhFGc5MedPl2cmJACuecrhFrxzPpx8ZY -ipfCocQJoXC5ZlkYmAwqUdLDhsP/Wj7ewwddmH2Exm531qZgLwIGxZECgYEAu/qS -bkS5bhaBVdrPzjt2InPF2QASHAo8xfaByeeWhV4Rc+4/tTPXO9O8gt7f/FQ+bNNz -F+zC2vOBN5Kkk5ZHVcstBH2q+FpRk9BkpMi8T6Xufk2+8s2T0IK+e8tQsuS+a9dN -N8A69y1voY2HyR1/4kmVjxnKgm9u9Cg3yJNyhtMCgYEAv6q2q7yQ/nBY2Js1VAw3 -qho98GSLv4QE/dOWl5NqdwB76T+9Vh7ahy4aUxdvzgNZIDhQtxHC4oLff2ZRrRdJ -yT62HdTdzOqz0zI29PDynhkLK9iXnDcsRTGYxzP6f6GTeUqkEbKzWsK3hRtUQhls -aAOv3Q7gZxUAXYejRfB0UFECgYB+SagotrkREcOQZ3GmruH94WOxFtAT0Hjl0md9 -ur2wGfOFvDFGzm4yPlzuW0eFoR9TQ3eWQjTinidYq4cvtA12wQocc0TyltMpiB6l -akrBA8xHRHodayl8MupABubPWMfpcXrqEpZKy1as5YWtAsmQwDjfK8eWe8DB/WcE -tLKDiwKBgAxCwy95E/e4cyOA9s3SkhFpyEGs56YLHeRUmOtsbRnu6dC0nNJs2ZiZ -Ku/qB9+9evqEEUYN75mtZlE8DHGT8zhxI8MWta+v6OkWPANcdxgRecnxSHbmMjLu -kh+hqSHnPwwatbO9s78ml3FocCM6uT8dLmJSz8uA0dQDzMTQzpHa ------END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/lab_3/public_key.pem b/lab_3/public_key.pem deleted file mode 100644 index 5abebeb8b..000000000 --- a/lab_3/public_key.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmu7q9JRs4tXfeD5jimIV -Q68LsnYF0sdCVa/OAKqO2RpZ82ZYUaQbz9xEQEVbxZaGVXvaEE7z/ZCbksmiw2JN -XFx/3Dqx+hnxBXew/ER3Us8S0fdyRI8XF37br1Ctx+cKSV2Eg5VlYXZNNXMCHPk8 -5sALi7U4AM1iQ8Im7slQq4mtv+Aos7CudwlWhKhU1+83U79dSzhY1eKEVrzZ4l9z -xVsJz+fJwqPTpNaJRlY8ynE1Y/eaWMcc2qdYTEjTUvfqY+8mZw0k8+ou/2maNn4p -JiZ41Ysvt8wWTrCtrSbEmdcAb890Ub9X4JKlqrE2Q4Kugz/+uyEfrUbw9yyMdJC8 -gwIDAQAB ------END PUBLIC KEY----- \ No newline at end of file diff --git a/lab_3/work_with_files.py b/lab_3/work_with_files.py new file mode 100644 index 000000000..d6b3927ab --- /dev/null +++ b/lab_3/work_with_files.py @@ -0,0 +1,65 @@ +import json + + +def read_json(file_name: str) -> dict: + """ + Считывает содержимое json-файла + :param file_name: путь к файлу + :return: словарь + """ + try: + with open(file_name, 'r', encoding='utf-8') as file: + return json.load(file) + except FileNotFoundError: + raise FileNotFoundError(f"Файл не найден") + except IOError: + raise IOError(f"Ошибка чтения файла") + except Exception as e: + raise Exception(f"Ошибка: {str(e)}") + + +def write_json(file_name: str, text: dict) -> None: + """ + Записывает данные в json-файл + :param file_name: путь к файлу + :param text: данные + """ + try: + with open(file_name, 'w', encoding='utf-8') as file: + json.dump(text, file, ensure_ascii=False, indent=4) + except IOError: + raise IOError(f"Ошибка записи в файл") + except Exception as e: + raise Exception(f"Ошибка: {str(e)}") + + +def read_binary_file(file_name: str) -> bytes: + """ + Считывает содержимое бинарного файла + :param file_name: путь к файлу + :return: содержимое файла в бинарном формате + """ + try: + with open(file_name, 'rb') as file: + return file.read() + except FileNotFoundError: + raise FileNotFoundError(f"Файл не найден") + except IOError: + raise IOError(f"Ошибка чтения файла") + except Exception as e: + raise Exception(f"Ошибка: {str(e)}") + + +def write_binary_file(file_name: str, text: bytes) -> None: + """ + Записывает данные в бинарный файл + :param file_name: путь к файлу + :param text: данные для записи + """ + try: + with open(file_name, 'wb') as file: + file.write(text) + except IOError: + raise IOError(f"Ошибка записи в файл") + except Exception as e: + raise Exception(f"Ошибка: {str(e)}")