From 427512ff2034efd16867168be666a1ee912d2023 Mon Sep 17 00:00:00 2001 From: velesikamid Date: Tue, 18 Mar 2025 18:41:52 +0400 Subject: [PATCH 1/9] Did lab1 --- lab_1/.gitignore | 174 ++++++++++++++++++++++++++ lab_1/frequencies.json | 36 ++++++ lab_1/key.json | 35 ++++++ lab_1/main.py | 16 +++ lab_1/result.txt | 99 +++++++++++++++ lab_1/result7.txt | 14 +++ lab_1/settings.json | 40 ++++++ lab_1/task_1/encryption.py | 26 ++++ lab_1/task_1/encryption_settings.json | 6 + lab_1/task_1/text.txt | 99 +++++++++++++++ lab_1/task_2/cod7.txt | 14 +++ lab_1/task_2/decryption.py | 18 +++ lab_1/task_2/decryption_settings.json | 6 + lab_1/text.txt | 99 +++++++++++++++ lab_1/tools/work_with_files.py | 21 ++++ 15 files changed, 703 insertions(+) create mode 100644 lab_1/.gitignore create mode 100644 lab_1/frequencies.json create mode 100644 lab_1/key.json create mode 100644 lab_1/main.py create mode 100644 lab_1/result.txt create mode 100644 lab_1/result7.txt create mode 100644 lab_1/settings.json create mode 100644 lab_1/task_1/encryption.py create mode 100644 lab_1/task_1/encryption_settings.json create mode 100644 lab_1/task_1/text.txt create mode 100644 lab_1/task_2/cod7.txt create mode 100644 lab_1/task_2/decryption.py create mode 100644 lab_1/task_2/decryption_settings.json create mode 100644 lab_1/text.txt create mode 100644 lab_1/tools/work_with_files.py diff --git a/lab_1/.gitignore b/lab_1/.gitignore new file mode 100644 index 000000000..1800114dc --- /dev/null +++ b/lab_1/.gitignore @@ -0,0 +1,174 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# UV +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +#uv.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# Ruff stuff: +.ruff_cache/ + +# PyPI configuration file +.pypirc \ No newline at end of file diff --git a/lab_1/frequencies.json b/lab_1/frequencies.json new file mode 100644 index 000000000..cceeacad9 --- /dev/null +++ b/lab_1/frequencies.json @@ -0,0 +1,36 @@ +{ + "-": 0.11584699453551912, + "e": 0.08196721311475409, + "0": 0.08087431693989071, + "2": 0.08087431693989071, + "6": 0.06448087431693988, + "n": 0.060109289617486336, + "i": 0.060109289617486336, + "w": 0.0546448087431694, + "m": 0.040437158469945354, + "8": 0.036065573770491806, + "q": 0.034972677595628415, + "r": 0.030601092896174863, + "5": 0.029508196721311476, + "\\": 0.025136612021857924, + "3": 0.02185792349726776, + "/": 0.020765027322404372, + ";": 0.019672131147540985, + "`": 0.017486338797814208, + "s": 0.015300546448087432, + "7": 0.015300546448087432, + "t": 0.014207650273224045, + "\n": 0.014207650273224045, + "1": 0.012021857923497269, + "k": 0.009836065573770493, + "o": 0.008743169398907104, + "z": 0.008743169398907104, + "c": 0.007650273224043716, + "p": 0.00546448087431694, + "f": 0.003278688524590164, + "d": 0.003278688524590164, + "9": 0.003278688524590164, + "x": 0.001092896174863388, + "4": 0.001092896174863388, + "?": 0.001092896174863388 +} \ No newline at end of file diff --git a/lab_1/key.json b/lab_1/key.json new file mode 100644 index 000000000..35fe1f564 --- /dev/null +++ b/lab_1/key.json @@ -0,0 +1,35 @@ +{ + "-": " ", + "e": "О", + "0": "Е", + "2": "И", + "6": "А", + "n": "С", + "i": "Т", + "w": "Н", + "m": "Р", + "8": "В", + "q": "М", + "r": "П", + "5": "Д", + "\\": "Л", + "3": "З", + "/": "К", + ";": "Ы", + "`": "Я", + "s": "Ь", + "7": "Б", + "t": "Х", + "1": "Й", + "k": "Ч", + "o": "У", + "z": "Ю", + "c": "Щ", + "p": "Ф", + "f": "Ц", + "d": "Ш", + "9": "Г", + "x": "Э", + "4": "Ж", + "?": "." +} \ No newline at end of file diff --git a/lab_1/main.py b/lab_1/main.py new file mode 100644 index 000000000..6738cd730 --- /dev/null +++ b/lab_1/main.py @@ -0,0 +1,16 @@ +import task_1.encryption as t1 +import task_2.decryption as t2 +from tools.work_with_files import read_json + + +def main(): + settings = read_json("settings.json") + encryption_settings = read_json(settings["encryption_settings"]) + decryption_settings = read_json(settings["decryption_settings"]) + t1.encrypt(settings["alphabet"], encryption_settings["in_filename"], encryption_settings["out_filename"], encryption_settings["key"]) + t1.decrypt(settings["alphabet"], encryption_settings["out_filename"], encryption_settings["result_filename"], encryption_settings["key"]) + t2.decrypt(decryption_settings["frequencies_filename"], decryption_settings["in_filename"], decryption_settings["out_filename"], decryption_settings["key"]) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/lab_1/result.txt b/lab_1/result.txt new file mode 100644 index 000000000..37db338fc --- /dev/null +++ b/lab_1/result.txt @@ -0,0 +1,99 @@ +ОЫПЧМШНШЪГ, +ТВЮОСЁ,ЮЦОЭНХЩО,ЗНЪМЭРРС, +ТЯЦ ОЗПЮООУ, +П Р ЧИЧРАГИАГЮЦ АЪГЩЕ, +АУВЮУЛЪВРХЛЪ ДЦВФЛШЗАЖ ЯЦЮЦОЬХЯЮЕ +РЮВТЮ-РЪ НЕЦОХ +АЛЛШЮМЛБ ЦПМЛШЗКЩЕ. +АЖ УЦАЪРШУЖ: +ЭИКЛПЮШЯЛРРЩПЮАБГПК, +ЯРЪ ТИПЛИЧФСВИЫИ +ШООЗЦМЛЛХЯК ЦРЕЩЬ, +ХЮОПКЯШ ЯЦОМ ЧИЮРЕЫЦЮЫРШХЖШАБГПК, +ИЮШОЩЗСРЕЫЗ— +КРЪЖЮЬАЖЮРАЫГЦС,ПКЛФЗ. +ЙЙБШФЯК! +ФГЩЯПКЩЛНХЗЙЙБШУЖ. +ЭНЮУНРУЖЛВК,ЮВТЮЗАЛСЮХКФЩХЗЙЙДАТМШ +ОЗ ЖЛПТЯЦ ЫЦЦМДЛ,ЮУАУХЯЩНРЖЮО ЬВЙС, +ЧОФШЯЦОСНЭИЭЛСЬНЙЖМПНЕРОЪЦК. +ЭНЮУНРУЖЛВК, +ВТЮЗЭЛВПЩНЧОЗХМШ ФВКЯ, +КЮЬАЧКМЬОЖНЛЩОЬЗ ЯРХСЮНЫБН +Э БЦБЪ ШЗКЯЧРЕПЗ,ПЯРЪ ЭНЮЫОЩФСЛ— +ТСРАПХГЭЕБЗЛМСПШМЦ АЦ ЖТШС. +ЛШЮМШ ЪЗЙФЦВ +ЙФЦРЗЛС ВКЖРАБГ. +БЮУЪГОХЗАФДШЪПК ЭИЮЬААЩРЪЯЭГГ. +ЪЦБРАПТЖЫИБЗКЪРАТЯК УУЯРЬП— +ЦО И ЧЬПКЮЫЛРЯГОНЮФЮЭОАЪМКНЛН. +ЗХФЙК —ЗИЪРРЙЙЗ! +ХМЛКБЦ-ЮОПКВЬУУ +ЕМ ЭЦАЪЙПОЖУНЛЕ,ЛНЮКМХ АУЯООЩ +АЛП ЖКЯЮПЛСДУПЙСЬЬПРЮОЬНЛ +СЕПХЯЫРРКЖЧ ТНЙФЧРКМ. +ЭЫЮЦТЮЗДЛИЧЗЛМСПХЯЛПРУСНЕПЙМЧЬЗЦЗ +НХЗНМДРУ,ЛНХЗ ЧЕТИЙЛИПХГЛРВЛЯЧСО? +ФХПФЯЧО,ЗПЛОЯВРЩОЩЗВЯШЮС, +КБЦЮЦРХЧИФМПКЮЦАЖТГЛОАЪЯОАЫЩЭ. +БЦБРАПРЮК, +ЧМР ФРИФЙП СШ, +ХМЛЗ НЙЪ ЧХЯЙЩШСЮЬАСЦРЯ, +ЩНЯСБРЙЭЯПКЮЦО И СЛЛХЩХ БШЬШ, +ЯРЪБПХГЛСЬЦРЬЕБГЮЧЮФЩИЯЮПШАЪТВ. +ЮОБЗРЬЮЬЗ ЖЛП— +ЬУАЩИФМПТЯНАЪЦК. +ШЗЭЛСЪУМЩИЫЩЭЛНРМЮЭТРТЯЩОЬ, +ВТЮЙ,ЛНХЗПЮРРМЯК ЭРЮЪ ЪЦК, +АН К АЛСНИБГ +О ВЛЯЬЕПЧЪКНЮФ. +ЛНЙЖШАО! +К ЬЫХФЛПКЯЭ, +ЫЮОААЗ ЖЛРЗРЪСЪИ +О УУЯУАДЗСЭТРУЩА: +ЯРЪ ОЗНЬЕФЗАММШЗЛМПЮТЯУ +АН К ИПЮРРЯЖОАЫЗАЛСЪИЛРАЫИУ. +ЭЦЮОЫПХГЛЗЭИЙФ, +ЯРЪ ТЗПЫЛЮ ЛЪМПМЩШУ, +АЛРРПАЪРЮЯГЩНЮФЮНУ НЗЛБКЪГ +СПЪМПОПРЮШУЖИЬЭЬ, +ХЮОПХГЛПЮСКЯ, +ТСРАПХГЭЕБЗЛМСПШМЦ АЦ ЖТШС… +ТХЧГЬЬПЛМРАПЧОЪШЫР. +ЯПКЮООЧШЯЭТХЗЖЩОЬ. +Ф ЖЫАЭТТЫЬЛИПФЩЭЛНЗНЪ-ШХМШУ. +ЖЛГЮКМЬЮППЯЛП ИЕРНШЯЛЖМПКЖЩОЬ: +АВРУЯЛИПЩЙМВРЗОЯЛХКМШУ! +ПСГЮМЛК О +АЛУФИОС ЭНДЩЫДЗХЯВАЪА. +ОЗАЭПЮФЛФЛПКЯГУПЛОЯСБХСЙ ВЩРМЛЮЩРЗ. +РЮООБЗРСПХШЪ +ЯПЩМЪБИРРЗ ТИКЛМЖЫПЗ, +ТЯЦОТЗЭЛБКУ, +ИПЯРЪ АЦЮШНЮЕЮЭТРУМЭЬ! +ЙЙБШФЯК! +ЩИМЗРЪЪЛП РЭЮНЮЗКЩЕ: +ЭЛИЧЙГТАЫЗНМДХХЪК АЗИЬУЖР. +ТХЧГЬЬПКЮЭОТНРЭКЮСЮЭТЮШМЩЕ +ЖЮЭАЬВЗЛЯ ЦПЮНКСЮЫОЯЫРВИЪ. +К АЪЯЧ ЭНЮЮЕЬ, +ЦЕЬЗ ЖЛПЪМПДР. +ЩЕПФСВИЫЗ Ж ОЗАМС, +ИМКПДРЪ СВЙЪ ИЛЗШХ. +УАППЛММОЗАЪЛЛХМЭТШ +ЖЛСТНРЧОУЦЮЮРВМЯ +ГЮЪМО ШМРФ ДЦРЗ ФЦЮЧА-ФЯЩШР. +ЫРЮЩРФТХЗКЩЕ… +ЭЛЗЭИЬ: ТВЮЩЕПЪЯЛ— +ОЖОЕБНЮОЫ +ЩЮЭЕ ГГУНКФ,ЛУЬХЩШ ЬЫДСМ; +ХЮОПХГЛНВОЛМ ТИКЛНР ЯЛМРНРМ, +РЮЭАЬЗЭЛВРФ +ЩИПТЯЫЕЫГИФ ЭНЮЩУЦНЛ. +ЦРАФТХЗРМК, +ИМКПКЯЭ ТНВСТППАСЗФИ, +ПЮМЮЦУИНЗЛОСХМОЛХХЛЪЙПЩГЩИ. +ПЛП РАСТАЪАФЕЬ, +ОААЗНЪМЭЖЧФЙПКПСГФИ +УНРТМШЫЩЗАМШ +ЩГЬГХСЮССХХЖЩ. \ No newline at end of file diff --git a/lab_1/result7.txt b/lab_1/result7.txt new file mode 100644 index 000000000..0f8e5ba3d --- /dev/null +++ b/lab_1/result7.txt @@ -0,0 +1,14 @@ +ЗА НЕСКОЛЬКО ПОСЛЕДНИХ ДЕСЯТИЛЕТИЙ ТРЕБОВАНИЯ К ИНФОРМАЦИОННОЙ +БЕЗОПАСНОСТИ СУЩЕСТВЕННО ИЗМЕНИЛИСЬ ДО НАЧАЛА ШИРОКОГО ИСПОЛЬЗОВАНИЯ +АВТОМАТИЗИРОВАННЫХ СИСТЕМ ОБРАБОТКИ ДАННЫХ БЕЗОПАСНОСТЬ ИНФОРМАЦИИ +ДОСТИГАЛАСЬ ИСКЛЮЧИТЕЛЬНО ФИЗИЧЕСКИМИ И АДМИНИСТРАТИВНЫМИ МЕРАМИ С +ПОЯВЛЕНИЕМ КОМПЬЮТЕРОВ СТАЛА ОЧЕВИДНОЙ НЕОБХОДИМОСТЬ ИСПОЛЬЗОВАНИЯ +АВТОМАТИЧЕСКИХ СРЕДСТВ ЗАЩИТЫ ФАЙЛОВ ДАННЫХ И ПРОГРАММНОЙ СРЕДЫ +СЛЕДУЮЩИЙ ЭТАП РАЗВИТИЯ АВТОМАТИЧЕСКИХ СРЕДСТВ ЗАЩИТЫ СВЯЗАН С ПОЯВЛЕНИЕМ +РАСПРЕДЕЛЕННЫХ СИСТЕМ ОБРАБОТКИ ДАННЫХ И КОМПЬЮТЕРНЫХ СЕТЕЙ В КОТОРЫХ +СРЕДСТВА СЕТЕВОЙ БЕЗОПАСНОСТИ ИСПОЛЬЗУЮТСЯ В ПЕРВУЮ ОЧЕРЕДЬ ДЛЯ ЗАЩИТЫ +ПЕРЕДАВАЕМЫХ ПО СЕТЯМ ДАННЫХ В НАИБОЛЕЕ ПОЛНОЙ ТРАКТОВКЕ ПОД СРЕДСТВАМИ +СЕТЕВОЙ БЕЗОПАСНОСТИ МЫ БУДЕМ ИМЕТЬ В ВИДУ МЕРЫ ПРЕДОТВРАЩЕНИЯ +НАРУШЕНИЙ БЕЗОПАСНОСТИ КОТОРЫЕ ВОЗНИКАЮТ ПРИ ПЕРЕДАЧЕ ИНФОРМАЦИИ ПО +СЕТЯМ А ТАКЖЕ МЕРЫ ПОЗВОЛЯЮЩИЕ ОПРЕДЕЛЯТЬ ЧТО ТАКИЕ НАРУШЕНИЯ БЕЗОПАСНОСТИ +ИМЕЛИ МЕСТО. \ No newline at end of file diff --git a/lab_1/settings.json b/lab_1/settings.json new file mode 100644 index 000000000..c15cc09f1 --- /dev/null +++ b/lab_1/settings.json @@ -0,0 +1,40 @@ +{ + "alphabet": "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ ", + "frequency": { + " ": 0.128675, + "О": 0.096456, + "И": 0.075312, + "Е": 0.072292, + "А": 0.064841, + "Н": 0.061820, + "Т": 0.061619, + "С": 0.051953, + "Р": 0.040677, + "В": 0.039267, + "М": 0.029803, + "Л": 0.029400, + "Д": 0.026983, + "Я": 0.026379, + "К": 0.025977, + "П": 0.024768, + "З": 0.015908, + "Ы": 0.015707, + "Ь": 0.015103, + "У": 0.013290, + "Ч": 0.011679, + "Ж": 0.010673, + "Г": 0.009867, + "Х": 0.008659, + "Ф": 0.007249, + "Й": 0.006847, + "Ю": 0.006847, + "Б": 0.006645, + "Ц": 0.005034, + "Ш": 0.004229, + "Щ": 0.003625, + "Э": 0.002416, + "Ъ": 0.000000 + }, + "encryption_settings": "task_1/encryption_settings.json", + "decryption_settings": "task_2/decryption_settings.json" +} \ No newline at end of file diff --git a/lab_1/task_1/encryption.py b/lab_1/task_1/encryption.py new file mode 100644 index 000000000..445a76ebe --- /dev/null +++ b/lab_1/task_1/encryption.py @@ -0,0 +1,26 @@ +from tools.work_with_files import read_txt, write_to_txt + + +def encrypt(alphabet: str, in_filename: str, out_filename: str, key: str) -> None: + text = read_txt(in_filename) + result = "" + for i in range(len(text)): + char = text[i].upper() + if char in alphabet: + result += alphabet[(alphabet.index(char) + alphabet.index(key[i % len(key)])) % len(alphabet)] + else: + result += char + write_to_txt(out_filename, result) + + +def decrypt(alphabet: str, in_filename: str, out_filename: str, key: str) -> None: + ciphertext = read_txt(in_filename) + result = "" + for i in range(len(ciphertext)): + char = ciphertext[i].upper() + if char in alphabet: + result += alphabet[(alphabet.index(char) - alphabet.index(key[i % len(key)])) % len(alphabet)] + else: + result += char + write_to_txt(out_filename, result) + \ No newline at end of file diff --git a/lab_1/task_1/encryption_settings.json b/lab_1/task_1/encryption_settings.json new file mode 100644 index 000000000..501a62a42 --- /dev/null +++ b/lab_1/task_1/encryption_settings.json @@ -0,0 +1,6 @@ +{ + "in_filename": "task_1/text.txt", + "out_filename": "result.txt", + "key": "МАРИЯ", + "result_filename": "text.txt" +} \ No newline at end of file diff --git a/lab_1/task_1/text.txt b/lab_1/task_1/text.txt new file mode 100644 index 000000000..ddbf13c3d --- /dev/null +++ b/lab_1/task_1/text.txt @@ -0,0 +1,99 @@ +Вы помните, +Вы всё, конечно, помните, +Как я стоял, +Приблизившись к стене, +Взволнованно ходили вы по комнате +И что-то резкое +В лицо бросали мне. +Вы говорили: +Нам пора расстаться, +Что вас измучила +Моя шальная жизнь, +Что вам пора за дело приниматься, +А мой удел — +Катиться дальше, вниз. +Любимая! +Меня вы не любили. +Не знали вы, что в сонмище людском +Я был как лошадь, загнанная в мыле, +Пришпоренная смелым ездоком. +Не знали вы, +Что я в сплошном дыму, +В развороченном бурей быте +С того и мучаюсь, что не пойму — +Куда несет нас рок событий. +Лицом к лицу +Лица не увидать. +Большое видится на расстоянье. +Когда кипит морская гладь — +Корабль в плачевном состоянье. +Земля — корабль! +Но кто-то вдруг +За новой жизнью, новой славой +В прямую гущу бурь и вьюг +Ее направил величаво. +Ну кто ж из нас на палубе большой +Не падал, не блевал и не ругался? +Их мало, с опытной душой, +Кто крепким в качке оставался. +Тогда и я, +Под дикий шум, +Но зрело знающий работу, +Спустился в корабельный трюм, +Чтоб не смотреть людскую рвоту. +Тот трюм был — +Русским кабаком. +И я склонился над стаканом, +Чтоб, не страдая ни о ком, +Себя сгубить +В угаре пьяном. +Любимая! +Я мучил вас, +У вас была тоска +В глазах усталых: +Что я пред вами напоказ +Себя растрачивал в скандалах. +Но вы не знали, +Что в сплошном дыму, +В развороченном бурей быте +С того и мучаюсь, +Что не пойму, +Куда несет нас рок событий… +Теперь года прошли. +Я в возрасте ином. +И чувствую и мыслю по-иному. +И говорю за праздничным вином: +Хвала и слава рулевому! +Сегодня я +В ударе нежных чувств. +Я вспомнил вашу грустную усталость. +И вот теперь +Я сообщить вам мчусь, +Каков я был, +И что со мною сталось! +Любимая! +Сказать приятно мне: +Я избежал паденья с кручи. +Теперь в Советской стороне +Я самый яростный попутчик. +Я стал не тем, +Кем был тогда. +Не мучил бы я вас, +Как это было раньше. +За знамя вольности +И светлого труда +Готов идти хоть до Ла-Манша. +Простите мне… +Я знаю: вы не та — +Живете вы +С серьезным, умным мужем; +Что не нужна вам наша маета, +И сам я вам +Ни капельки не нужен. +Живите так, +Как вас ведет звезда, +Под кущей обновленной сени. +С приветствием, +Вас помнящий всегда +Знакомый ваш +Сергей Есенин. \ No newline at end of file diff --git a/lab_1/task_2/cod7.txt b/lab_1/task_2/cod7.txt new file mode 100644 index 000000000..dd5cb02de --- /dev/null +++ b/lab_1/task_2/cod7.txt @@ -0,0 +1,14 @@ +36-w0n/e\s/e-ren\05w2t-50n`i2\0i21-im07e86w2`-/-2wpemq6f2ewwe1- +703er6nweni2-noc0ni80wwe-23q0w2\2ns-5e-w6k6\6-d2me/e9e-2nre\s3e86w2`- +68ieq6i232me86ww;t-n2ni0q-e7m67ei/2-56ww;t-703er6nwenis-2wpemq6f22- +5eni296\6ns-2n/\zk2i0\swe-p232k0n/2q2-2-65q2w2nim6i28w;q2-q0m6q2-n- +re`8\0w20q-/eqrszi0me8-ni6\6-ek0825we1-w0e7te52qenis-2nre\s3e86w2`- +68ieq6i2k0n/2t-nm05ni8-36c2i;-p61\e8-56ww;t-2-rme9m6qqwe1-nm05;- +n\05ozc21-xi6r-m6382i2`-68ieq6i2k0n/2t-nm05ni8-36c2i;-n8`36w-n-re`8\0w20q- +m6nrm050\0ww;t-n2ni0q-e7m67ei/2-56ww;t-2-/eqrszi0mw;t-n0i01-8-/eiem;t- +nm05ni86-n0i08e1-703er6nweni2-2nre\s3ozin`-8-r0m8oz-ek0m05s-5\`-36c2i;- +r0m056860q;t-re-n0i`q-56ww;t-8-w627e\00-re\we1-im6/ie8/0-re5-nm05ni86q2- +n0i08e1-703er6nweni2-q;-7o50q-2q0is-8-825o-q0m;-rm05ei8m6c0w2`- +w6mod0w21-703er6nweni2-/eiem;0-8e3w2/6zi-rm2-r0m056k0-2wpemq6f22-re- +n0i`q-6-i6/40-q0m;-re38e\`zc20-erm050\`is-kie-i6/20-w6mod0w2`-703er6nweni2- +2q0\2-q0nie? \ No newline at end of file diff --git a/lab_1/task_2/decryption.py b/lab_1/task_2/decryption.py new file mode 100644 index 000000000..648eeb406 --- /dev/null +++ b/lab_1/task_2/decryption.py @@ -0,0 +1,18 @@ +from collections import Counter + +from tools.work_with_files import write_to_json, read_json, read_txt, write_to_txt + +def analyze_frequency(text: str, frequencies_filename: str) -> None: + counter = Counter(char for char in text) + total = len(text) + frequencies = {char: count / total for char, count in counter.items()} + write_to_json(dict(sorted(frequencies.items(), key=lambda item: item[1], reverse=True)), frequencies_filename) + + +def decrypt(frequences_filename: str, in_filename: str, out_filename: str, key_filename: str): + ciphertext = read_txt(in_filename) + analyze_frequency(ciphertext, frequences_filename) + + key = read_json(key_filename) + result = "".join(key.get(char, char) for char in ciphertext) + write_to_txt(out_filename, result) diff --git a/lab_1/task_2/decryption_settings.json b/lab_1/task_2/decryption_settings.json new file mode 100644 index 000000000..5e70e9055 --- /dev/null +++ b/lab_1/task_2/decryption_settings.json @@ -0,0 +1,6 @@ +{ + "in_filename": "task_2/cod7.txt", + "out_filename": "result7.txt", + "frequencies_filename": "frequencies.json", + "key": "key.json" +} \ No newline at end of file diff --git a/lab_1/text.txt b/lab_1/text.txt new file mode 100644 index 000000000..5085ebce4 --- /dev/null +++ b/lab_1/text.txt @@ -0,0 +1,99 @@ +ВЫ ПОМНИТЕ, +ВЫ ВСЁ, КОНЕЧНО, ПОМНИТЕ, +КАК Я СТОЯЛ, +ПРИБЛИЗИВШИСЬ К СТЕНЕ, +ВЗВОЛНОВАННО ХОДИЛИ ВЫ ПО КОМНАТЕ +И ЧТО-ТО РЕЗКОЕ +В ЛИЦО БРОСАЛИ МНЕ. +ВЫ ГОВОРИЛИ: +НАМ ПОРА РАССТАТЬСЯ, +ЧТО ВАС ИЗМУЧИЛА +МОЯ ШАЛЬНАЯ ЖИЗНЬ, +ЧТО ВАМ ПОРА ЗА ДЕЛО ПРИНИМАТЬСЯ, +А МОЙ УДЕЛ — +КАТИТЬСЯ ДАЛЬШЕ, ВНИЗ. +ЛЮБИМАЯ! +МЕНЯ ВЫ НЕ ЛЮБИЛИ. +НЕ ЗНАЛИ ВЫ, ЧТО В СОНМИЩЕ ЛЮДСКОМ +Я БЫЛ КАК ЛОШАДЬ, ЗАГНАННАЯ В МЫЛЕ, +ПРИШПОРЕННАЯ СМЕЛЫМ ЕЗДОКОМ. +НЕ ЗНАЛИ ВЫ, +ЧТО Я В СПЛОШНОМ ДЫМУ, +В РАЗВОРОЧЕННОМ БУРЕЙ БЫТЕ +С ТОГО И МУЧАЮСЬ, ЧТО НЕ ПОЙМУ — +КУДА НЕСЕТ НАС РОК СОБЫТИЙ. +ЛИЦОМ К ЛИЦУ +ЛИЦА НЕ УВИДАТЬ. +БОЛЬШОЕ ВИДИТСЯ НА РАССТОЯНЬЕ. +КОГДА КИПИТ МОРСКАЯ ГЛАДЬ — +КОРАБЛЬ В ПЛАЧЕВНОМ СОСТОЯНЬЕ. +ЗЕМЛЯ — КОРАБЛЬ! +НО КТО-ТО ВДРУГ +ЗА НОВОЙ ЖИЗНЬЮ, НОВОЙ СЛАВОЙ +В ПРЯМУЮ ГУЩУ БУРЬ И ВЬЮГ +ЕЕ НАПРАВИЛ ВЕЛИЧАВО. +НУ КТО Ж ИЗ НАС НА ПАЛУБЕ БОЛЬШОЙ +НЕ ПАДАЛ, НЕ БЛЕВАЛ И НЕ РУГАЛСЯ? +ИХ МАЛО, С ОПЫТНОЙ ДУШОЙ, +КТО КРЕПКИМ В КАЧКЕ ОСТАВАЛСЯ. +ТОГДА И Я, +ПОД ДИКИЙ ШУМ, +НО ЗРЕЛО ЗНАЮЩИЙ РАБОТУ, +СПУСТИЛСЯ В КОРАБЕЛЬНЫЙ ТРЮМ, +ЧТОБ НЕ СМОТРЕТЬ ЛЮДСКУЮ РВОТУ. +ТОТ ТРЮМ БЫЛ — +РУССКИМ КАБАКОМ. +И Я СКЛОНИЛСЯ НАД СТАКАНОМ, +ЧТОБ, НЕ СТРАДАЯ НИ О КОМ, +СЕБЯ СГУБИТЬ +В УГАРЕ ПЬЯНОМ. +ЛЮБИМАЯ! +Я МУЧИЛ ВАС, +У ВАС БЫЛА ТОСКА +В ГЛАЗАХ УСТАЛЫХ: +ЧТО Я ПРЕД ВАМИ НАПОКАЗ +СЕБЯ РАСТРАЧИВАЛ В СКАНДАЛАХ. +НО ВЫ НЕ ЗНАЛИ, +ЧТО В СПЛОШНОМ ДЫМУ, +В РАЗВОРОЧЕННОМ БУРЕЙ БЫТЕ +С ТОГО И МУЧАЮСЬ, +ЧТО НЕ ПОЙМУ, +КУДА НЕСЕТ НАС РОК СОБЫТИЙ… +ТЕПЕРЬ ГОДА ПРОШЛИ. +Я В ВОЗРАСТЕ ИНОМ. +И ЧУВСТВУЮ И МЫСЛЮ ПО-ИНОМУ. +И ГОВОРЮ ЗА ПРАЗДНИЧНЫМ ВИНОМ: +ХВАЛА И СЛАВА РУЛЕВОМУ! +СЕГОДНЯ Я +В УДАРЕ НЕЖНЫХ ЧУВСТВ. +Я ВСПОМНИЛ ВАШУ ГРУСТНУЮ УСТАЛОСТЬ. +И ВОТ ТЕПЕРЬ +Я СООБЩИТЬ ВАМ МЧУСЬ, +КАКОВ Я БЫЛ, +И ЧТО СО МНОЮ СТАЛОСЬ! +ЛЮБИМАЯ! +СКАЗАТЬ ПРИЯТНО МНЕ: +Я ИЗБЕЖАЛ ПАДЕНЬЯ С КРУЧИ. +ТЕПЕРЬ В СОВЕТСКОЙ СТОРОНЕ +Я САМЫЙ ЯРОСТНЫЙ ПОПУТЧИК. +Я СТАЛ НЕ ТЕМ, +КЕМ БЫЛ ТОГДА. +НЕ МУЧИЛ БЫ Я ВАС, +КАК ЭТО БЫЛО РАНЬШЕ. +ЗА ЗНАМЯ ВОЛЬНОСТИ +И СВЕТЛОГО ТРУДА +ГОТОВ ИДТИ ХОТЬ ДО ЛА-МАНША. +ПРОСТИТЕ МНЕ… +Я ЗНАЮ: ВЫ НЕ ТА — +ЖИВЕТЕ ВЫ +С СЕРЬЕЗНЫМ, УМНЫМ МУЖЕМ; +ЧТО НЕ НУЖНА ВАМ НАША МАЕТА, +И САМ Я ВАМ +НИ КАПЕЛЬКИ НЕ НУЖЕН. +ЖИВИТЕ ТАК, +КАК ВАС ВЕДЕТ ЗВЕЗДА, +ПОД КУЩЕЙ ОБНОВЛЕННОЙ СЕНИ. +С ПРИВЕТСТВИЕМ, +ВАС ПОМНЯЩИЙ ВСЕГДА +ЗНАКОМЫЙ ВАШ +СЕРГЕЙ ЕСЕНИН. \ No newline at end of file diff --git a/lab_1/tools/work_with_files.py b/lab_1/tools/work_with_files.py new file mode 100644 index 000000000..75d5f3d60 --- /dev/null +++ b/lab_1/tools/work_with_files.py @@ -0,0 +1,21 @@ +from json import load, dump + + +def read_json(filename: str) -> dict: + with open(filename, "r", encoding="utf-8") as file: + return load(file) + + +def write_to_json(dictionary: dict, filename: str) -> None: + with open(filename, "w", encoding="utf-8") as file: + dump(dictionary, file, ensure_ascii=False, indent=4) + + +def read_txt(filename: str) -> str: + with open(filename, "r", encoding="utf-8") as file: + return file.read() + + +def write_to_txt(filename: str, data: str) -> None: + with open(filename, "w", encoding="utf-8") as file: + file.write(data) \ No newline at end of file From 7d548643823df42184256ee12a75d25598137eac Mon Sep 17 00:00:00 2001 From: velesikamid Date: Tue, 18 Mar 2025 19:33:44 +0400 Subject: [PATCH 2/9] Added some beauty) --- lab_1/main.py | 43 ++++++++++++++++++++++++++++++---- lab_1/task_1/encryption.py | 41 ++++++++++++++++++++++++++++---- lab_1/task_2/decryption.py | 35 ++++++++++++++++++++++++--- lab_1/tools/work_with_files.py | 37 +++++++++++++++++++++++++++-- 4 files changed, 141 insertions(+), 15 deletions(-) diff --git a/lab_1/main.py b/lab_1/main.py index 6738cd730..e63e137de 100644 --- a/lab_1/main.py +++ b/lab_1/main.py @@ -1,16 +1,49 @@ +""" +Main module for performing encryption and decryption tasks based on settings. +""" + import task_1.encryption as t1 import task_2.decryption as t2 from tools.work_with_files import read_json -def main(): +def main() -> None: + """ + Main function to execute the encryption and decryption process. + + This function reads settings from a JSON file, performs encryption using + the specified parameters, and then performs decryption on the encrypted + text and another set of data using frequency analysis. + + :raises FileNotFoundError: If any of the required JSON files are not found. + :raises json.JSONDecodeError: If any of the JSONs contain invalid data. + :raises KeyError: If expected keys are missing in the settings JSON. + """ settings = read_json("settings.json") encryption_settings = read_json(settings["encryption_settings"]) decryption_settings = read_json(settings["decryption_settings"]) - t1.encrypt(settings["alphabet"], encryption_settings["in_filename"], encryption_settings["out_filename"], encryption_settings["key"]) - t1.decrypt(settings["alphabet"], encryption_settings["out_filename"], encryption_settings["result_filename"], encryption_settings["key"]) - t2.decrypt(decryption_settings["frequencies_filename"], decryption_settings["in_filename"], decryption_settings["out_filename"], decryption_settings["key"]) + + t1.encrypt( + settings["alphabet"], + encryption_settings["in_filename"], + encryption_settings["out_filename"], + encryption_settings["key"] + ) + + t1.decrypt( + settings["alphabet"], + encryption_settings["out_filename"], + encryption_settings["result_filename"], + encryption_settings["key"] + ) + + t2.decrypt( + decryption_settings["frequencies_filename"], + decryption_settings["in_filename"], + decryption_settings["out_filename"], + decryption_settings["key"] + ) if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/lab_1/task_1/encryption.py b/lab_1/task_1/encryption.py index 445a76ebe..d0db19f40 100644 --- a/lab_1/task_1/encryption.py +++ b/lab_1/task_1/encryption.py @@ -1,26 +1,57 @@ +""" +Module for encrypting and decrypting text using a Vigenère cipher. +""" + from tools.work_with_files import read_txt, write_to_txt -def encrypt(alphabet: str, in_filename: str, out_filename: str, key: str) -> None: +def encrypt(alphabet: str, + in_filename: str, + out_filename: str, + key: str) -> None: + """ + Encrypts a text file using a Vigenère cipher. + + :param alphabet: The alphabet to use for encryption. + :param in_filename: Name of the input file to encrypt. + :param out_filename: Name of the output file for the encrypted text. + :param key: The encryption key. + :raises FileNotFoundError: If the input file is not found. + """ text = read_txt(in_filename) result = "" for i in range(len(text)): char = text[i].upper() if char in alphabet: - result += alphabet[(alphabet.index(char) + alphabet.index(key[i % len(key)])) % len(alphabet)] + result += alphabet[(alphabet.index(char) + + alphabet.index(key[i % len(key)])) + % len(alphabet)] else: result += char write_to_txt(out_filename, result) -def decrypt(alphabet: str, in_filename: str, out_filename: str, key: str) -> None: +def decrypt(alphabet: str, + in_filename: str, + out_filename: str, + key: str) -> None: + """ + Decrypts a text file that was encrypted using a Vigenère cipher. + + :param alphabet: The alphabet to use for decryption. + :param in_filename: Name of the input file to decrypt. + :param out_filename: Name of the output file for the decrypted text. + :param key: The decryption key (must be the same as the encryption key). + :raises FileNotFoundError: If the input file is not found. + """ ciphertext = read_txt(in_filename) result = "" for i in range(len(ciphertext)): char = ciphertext[i].upper() if char in alphabet: - result += alphabet[(alphabet.index(char) - alphabet.index(key[i % len(key)])) % len(alphabet)] + result += alphabet[(alphabet.index(char) + - alphabet.index(key[i % len(key)])) + % len(alphabet)] else: result += char write_to_txt(out_filename, result) - \ No newline at end of file diff --git a/lab_1/task_2/decryption.py b/lab_1/task_2/decryption.py index 648eeb406..894ef1679 100644 --- a/lab_1/task_2/decryption.py +++ b/lab_1/task_2/decryption.py @@ -1,15 +1,44 @@ +""" +Module for frequency analysis and substitution cipher decryption. +""" + from collections import Counter -from tools.work_with_files import write_to_json, read_json, read_txt, write_to_txt +from tools.work_with_files import * + def analyze_frequency(text: str, frequencies_filename: str) -> None: + """ + Analyzes character frequency in text and saves sorted results to JSON. + + :param text: Input text for frequency analysis + :param frequencies_filename: Output JSON filename for frequencies + :raises FileNotFoundError: If output file path is invalid + :raises PermissionError: If no write permissions for output file + """ counter = Counter(char for char in text) total = len(text) frequencies = {char: count / total for char, count in counter.items()} - write_to_json(dict(sorted(frequencies.items(), key=lambda item: item[1], reverse=True)), frequencies_filename) + write_to_json(dict(sorted(frequencies.items(), + key=lambda item: item[1], + reverse=True)), + frequencies_filename) + +def decrypt(frequences_filename: str, + in_filename: str, + out_filename: str, + key_filename: str) -> None: + """ + Decrypts text using substitution cipher based on frequency analysis key. -def decrypt(frequences_filename: str, in_filename: str, out_filename: str, key_filename: str): + :param frequences_filename: JSON file to store ciphertext frequencies + :param in_filename: Input file with encrypted text + :param out_filename: Output file for decrypted text + :param key_filename: JSON file with substitution mapping + :raises FileNotFoundError: If any input file is missing + :raises json.JSONDecodeError: If key file contains invalid JSON + """ ciphertext = read_txt(in_filename) analyze_frequency(ciphertext, frequences_filename) diff --git a/lab_1/tools/work_with_files.py b/lab_1/tools/work_with_files.py index 75d5f3d60..e7802262e 100644 --- a/lab_1/tools/work_with_files.py +++ b/lab_1/tools/work_with_files.py @@ -1,21 +1,54 @@ +""" +Module for working with JSON and TXT files. +""" + from json import load, dump def read_json(filename: str) -> dict: + """ + Reads data from a JSON file. + + :param filename: Name of the file to read. + :return: Dictionary with data from the file. + :raises FileNotFoundError: If the file is not found. + :raises json.JSONDecodeError: If the file contains invalid JSON. + """ with open(filename, "r", encoding="utf-8") as file: return load(file) def write_to_json(dictionary: dict, filename: str) -> None: + """ + Writes a dictionary to a JSON file. + + :param dictionary: Dictionary to write to the file. + :param filename: Name of the file to write. + :raises TypeError: If a non-dictionary is passed. + """ with open(filename, "w", encoding="utf-8") as file: dump(dictionary, file, ensure_ascii=False, indent=4) def read_txt(filename: str) -> str: + """ + Reads the contents of a TXT file. + + :param filename: Name of the file to read. + :return: String with the file contents. + :raises FileNotFoundError: If the file is not found. + """ with open(filename, "r", encoding="utf-8") as file: return file.read() - + def write_to_txt(filename: str, data: str) -> None: + """ + Writes a string to a TXT file. + + :param filename: Name of the file to write. + :param data: String to write to the file. + :raises TypeError: If a non-string is passed. + """ with open(filename, "w", encoding="utf-8") as file: - file.write(data) \ No newline at end of file + file.write(data) From 9b4137762fa63b3b011a24852b85f8347f3d00f7 Mon Sep 17 00:00:00 2001 From: velesikamid Date: Tue, 18 Mar 2025 19:48:05 +0400 Subject: [PATCH 3/9] Added requirements.txt --- lab_1/requirements.txt | Bin 0 -> 44 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lab_1/requirements.txt diff --git a/lab_1/requirements.txt b/lab_1/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..6d6ba287ffa9a31fea73641ebd6ba9ca1a222eb2 GIT binary patch literal 44 qcmezWuYjSFA( Date: Tue, 13 May 2025 13:45:40 +0400 Subject: [PATCH 4/9] Added exceptions --- lab_1/tools/work_with_files.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/lab_1/tools/work_with_files.py b/lab_1/tools/work_with_files.py index e7802262e..b86455785 100644 --- a/lab_1/tools/work_with_files.py +++ b/lab_1/tools/work_with_files.py @@ -14,8 +14,11 @@ def read_json(filename: str) -> dict: :raises FileNotFoundError: If the file is not found. :raises json.JSONDecodeError: If the file contains invalid JSON. """ - with open(filename, "r", encoding="utf-8") as file: - return load(file) + try: + with open(filename, "r", encoding="utf-8") as file: + return load(file) + except Exception as e: + print(f"Error: {e}") def write_to_json(dictionary: dict, filename: str) -> None: @@ -26,8 +29,11 @@ def write_to_json(dictionary: dict, filename: str) -> None: :param filename: Name of the file to write. :raises TypeError: If a non-dictionary is passed. """ - with open(filename, "w", encoding="utf-8") as file: - dump(dictionary, file, ensure_ascii=False, indent=4) + try: + with open(filename, "w", encoding="utf-8") as file: + dump(dictionary, file, ensure_ascii=False, indent=4) + except Exception as e: + print(f"Error: {e}") def read_txt(filename: str) -> str: @@ -38,8 +44,11 @@ def read_txt(filename: str) -> str: :return: String with the file contents. :raises FileNotFoundError: If the file is not found. """ - with open(filename, "r", encoding="utf-8") as file: - return file.read() + try: + with open(filename, "r", encoding="utf-8") as file: + return file.read() + except Exception as e: + print(f"Error: {e}") def write_to_txt(filename: str, data: str) -> None: @@ -50,5 +59,8 @@ def write_to_txt(filename: str, data: str) -> None: :param data: String to write to the file. :raises TypeError: If a non-string is passed. """ - with open(filename, "w", encoding="utf-8") as file: - file.write(data) + try: + with open(filename, "w", encoding="utf-8") as file: + file.write(data) + except Exception as e: + print(f"Error: {e}") From 44c358baa45eb54512ebba2cf44f283800f36908 Mon Sep 17 00:00:00 2001 From: velesikamid Date: Tue, 13 May 2025 19:00:48 +0400 Subject: [PATCH 5/9] Did lab2 --- lab_1/frequencies.json | 36 -------- lab_1/key.json | 35 -------- lab_1/main.py | 49 ---------- lab_1/requirements.txt | Bin 44 -> 0 bytes lab_1/result.txt | 99 --------------------- lab_1/result7.txt | 14 --- lab_1/settings.json | 40 --------- lab_1/task_1/encryption.py | 57 ------------ lab_1/task_1/encryption_settings.json | 6 -- lab_1/task_1/text.txt | 99 --------------------- lab_1/task_2/cod7.txt | 14 --- lab_1/task_2/decryption.py | 47 ---------- lab_1/task_2/decryption_settings.json | 6 -- lab_1/text.txt | 99 --------------------- lab_1/tools/work_with_files.py | 66 -------------- {lab_1 => lab_2}/.gitignore | 0 lab_2/constants.py | 3 + lab_2/random_sequences/random.cpp | 24 +++++ lab_2/random_sequences/random.java | 20 +++++ lab_2/random_sequences/random_sequences.py | 2 + lab_2/requirements.txt | Bin 0 -> 102 bytes lab_2/results.txt | 8 ++ lab_2/tests.py | 84 +++++++++++++++++ 23 files changed, 141 insertions(+), 667 deletions(-) delete mode 100644 lab_1/frequencies.json delete mode 100644 lab_1/key.json delete mode 100644 lab_1/main.py delete mode 100644 lab_1/requirements.txt delete mode 100644 lab_1/result.txt delete mode 100644 lab_1/result7.txt delete mode 100644 lab_1/settings.json delete mode 100644 lab_1/task_1/encryption.py delete mode 100644 lab_1/task_1/encryption_settings.json delete mode 100644 lab_1/task_1/text.txt delete mode 100644 lab_1/task_2/cod7.txt delete mode 100644 lab_1/task_2/decryption.py delete mode 100644 lab_1/task_2/decryption_settings.json delete mode 100644 lab_1/text.txt delete mode 100644 lab_1/tools/work_with_files.py rename {lab_1 => lab_2}/.gitignore (100%) create mode 100644 lab_2/constants.py create mode 100644 lab_2/random_sequences/random.cpp create mode 100644 lab_2/random_sequences/random.java create mode 100644 lab_2/random_sequences/random_sequences.py create mode 100644 lab_2/requirements.txt create mode 100644 lab_2/results.txt create mode 100644 lab_2/tests.py diff --git a/lab_1/frequencies.json b/lab_1/frequencies.json deleted file mode 100644 index cceeacad9..000000000 --- a/lab_1/frequencies.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "-": 0.11584699453551912, - "e": 0.08196721311475409, - "0": 0.08087431693989071, - "2": 0.08087431693989071, - "6": 0.06448087431693988, - "n": 0.060109289617486336, - "i": 0.060109289617486336, - "w": 0.0546448087431694, - "m": 0.040437158469945354, - "8": 0.036065573770491806, - "q": 0.034972677595628415, - "r": 0.030601092896174863, - "5": 0.029508196721311476, - "\\": 0.025136612021857924, - "3": 0.02185792349726776, - "/": 0.020765027322404372, - ";": 0.019672131147540985, - "`": 0.017486338797814208, - "s": 0.015300546448087432, - "7": 0.015300546448087432, - "t": 0.014207650273224045, - "\n": 0.014207650273224045, - "1": 0.012021857923497269, - "k": 0.009836065573770493, - "o": 0.008743169398907104, - "z": 0.008743169398907104, - "c": 0.007650273224043716, - "p": 0.00546448087431694, - "f": 0.003278688524590164, - "d": 0.003278688524590164, - "9": 0.003278688524590164, - "x": 0.001092896174863388, - "4": 0.001092896174863388, - "?": 0.001092896174863388 -} \ No newline at end of file diff --git a/lab_1/key.json b/lab_1/key.json deleted file mode 100644 index 35fe1f564..000000000 --- a/lab_1/key.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "-": " ", - "e": "О", - "0": "Е", - "2": "И", - "6": "А", - "n": "С", - "i": "Т", - "w": "Н", - "m": "Р", - "8": "В", - "q": "М", - "r": "П", - "5": "Д", - "\\": "Л", - "3": "З", - "/": "К", - ";": "Ы", - "`": "Я", - "s": "Ь", - "7": "Б", - "t": "Х", - "1": "Й", - "k": "Ч", - "o": "У", - "z": "Ю", - "c": "Щ", - "p": "Ф", - "f": "Ц", - "d": "Ш", - "9": "Г", - "x": "Э", - "4": "Ж", - "?": "." -} \ No newline at end of file diff --git a/lab_1/main.py b/lab_1/main.py deleted file mode 100644 index e63e137de..000000000 --- a/lab_1/main.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -Main module for performing encryption and decryption tasks based on settings. -""" - -import task_1.encryption as t1 -import task_2.decryption as t2 -from tools.work_with_files import read_json - - -def main() -> None: - """ - Main function to execute the encryption and decryption process. - - This function reads settings from a JSON file, performs encryption using - the specified parameters, and then performs decryption on the encrypted - text and another set of data using frequency analysis. - - :raises FileNotFoundError: If any of the required JSON files are not found. - :raises json.JSONDecodeError: If any of the JSONs contain invalid data. - :raises KeyError: If expected keys are missing in the settings JSON. - """ - settings = read_json("settings.json") - encryption_settings = read_json(settings["encryption_settings"]) - decryption_settings = read_json(settings["decryption_settings"]) - - t1.encrypt( - settings["alphabet"], - encryption_settings["in_filename"], - encryption_settings["out_filename"], - encryption_settings["key"] - ) - - t1.decrypt( - settings["alphabet"], - encryption_settings["out_filename"], - encryption_settings["result_filename"], - encryption_settings["key"] - ) - - t2.decrypt( - decryption_settings["frequencies_filename"], - decryption_settings["in_filename"], - decryption_settings["out_filename"], - decryption_settings["key"] - ) - - -if __name__ == "__main__": - main() diff --git a/lab_1/requirements.txt b/lab_1/requirements.txt deleted file mode 100644 index 6d6ba287ffa9a31fea73641ebd6ba9ca1a222eb2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44 qcmezWuYjSFA( None: - """ - Encrypts a text file using a Vigenère cipher. - - :param alphabet: The alphabet to use for encryption. - :param in_filename: Name of the input file to encrypt. - :param out_filename: Name of the output file for the encrypted text. - :param key: The encryption key. - :raises FileNotFoundError: If the input file is not found. - """ - text = read_txt(in_filename) - result = "" - for i in range(len(text)): - char = text[i].upper() - if char in alphabet: - result += alphabet[(alphabet.index(char) - + alphabet.index(key[i % len(key)])) - % len(alphabet)] - else: - result += char - write_to_txt(out_filename, result) - - -def decrypt(alphabet: str, - in_filename: str, - out_filename: str, - key: str) -> None: - """ - Decrypts a text file that was encrypted using a Vigenère cipher. - - :param alphabet: The alphabet to use for decryption. - :param in_filename: Name of the input file to decrypt. - :param out_filename: Name of the output file for the decrypted text. - :param key: The decryption key (must be the same as the encryption key). - :raises FileNotFoundError: If the input file is not found. - """ - ciphertext = read_txt(in_filename) - result = "" - for i in range(len(ciphertext)): - char = ciphertext[i].upper() - if char in alphabet: - result += alphabet[(alphabet.index(char) - - alphabet.index(key[i % len(key)])) - % len(alphabet)] - else: - result += char - write_to_txt(out_filename, result) diff --git a/lab_1/task_1/encryption_settings.json b/lab_1/task_1/encryption_settings.json deleted file mode 100644 index 501a62a42..000000000 --- a/lab_1/task_1/encryption_settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "in_filename": "task_1/text.txt", - "out_filename": "result.txt", - "key": "МАРИЯ", - "result_filename": "text.txt" -} \ No newline at end of file diff --git a/lab_1/task_1/text.txt b/lab_1/task_1/text.txt deleted file mode 100644 index ddbf13c3d..000000000 --- a/lab_1/task_1/text.txt +++ /dev/null @@ -1,99 +0,0 @@ -Вы помните, -Вы всё, конечно, помните, -Как я стоял, -Приблизившись к стене, -Взволнованно ходили вы по комнате -И что-то резкое -В лицо бросали мне. -Вы говорили: -Нам пора расстаться, -Что вас измучила -Моя шальная жизнь, -Что вам пора за дело приниматься, -А мой удел — -Катиться дальше, вниз. -Любимая! -Меня вы не любили. -Не знали вы, что в сонмище людском -Я был как лошадь, загнанная в мыле, -Пришпоренная смелым ездоком. -Не знали вы, -Что я в сплошном дыму, -В развороченном бурей быте -С того и мучаюсь, что не пойму — -Куда несет нас рок событий. -Лицом к лицу -Лица не увидать. -Большое видится на расстоянье. -Когда кипит морская гладь — -Корабль в плачевном состоянье. -Земля — корабль! -Но кто-то вдруг -За новой жизнью, новой славой -В прямую гущу бурь и вьюг -Ее направил величаво. -Ну кто ж из нас на палубе большой -Не падал, не блевал и не ругался? -Их мало, с опытной душой, -Кто крепким в качке оставался. -Тогда и я, -Под дикий шум, -Но зрело знающий работу, -Спустился в корабельный трюм, -Чтоб не смотреть людскую рвоту. -Тот трюм был — -Русским кабаком. -И я склонился над стаканом, -Чтоб, не страдая ни о ком, -Себя сгубить -В угаре пьяном. -Любимая! -Я мучил вас, -У вас была тоска -В глазах усталых: -Что я пред вами напоказ -Себя растрачивал в скандалах. -Но вы не знали, -Что в сплошном дыму, -В развороченном бурей быте -С того и мучаюсь, -Что не пойму, -Куда несет нас рок событий… -Теперь года прошли. -Я в возрасте ином. -И чувствую и мыслю по-иному. -И говорю за праздничным вином: -Хвала и слава рулевому! -Сегодня я -В ударе нежных чувств. -Я вспомнил вашу грустную усталость. -И вот теперь -Я сообщить вам мчусь, -Каков я был, -И что со мною сталось! -Любимая! -Сказать приятно мне: -Я избежал паденья с кручи. -Теперь в Советской стороне -Я самый яростный попутчик. -Я стал не тем, -Кем был тогда. -Не мучил бы я вас, -Как это было раньше. -За знамя вольности -И светлого труда -Готов идти хоть до Ла-Манша. -Простите мне… -Я знаю: вы не та — -Живете вы -С серьезным, умным мужем; -Что не нужна вам наша маета, -И сам я вам -Ни капельки не нужен. -Живите так, -Как вас ведет звезда, -Под кущей обновленной сени. -С приветствием, -Вас помнящий всегда -Знакомый ваш -Сергей Есенин. \ No newline at end of file diff --git a/lab_1/task_2/cod7.txt b/lab_1/task_2/cod7.txt deleted file mode 100644 index dd5cb02de..000000000 --- a/lab_1/task_2/cod7.txt +++ /dev/null @@ -1,14 +0,0 @@ -36-w0n/e\s/e-ren\05w2t-50n`i2\0i21-im07e86w2`-/-2wpemq6f2ewwe1- -703er6nweni2-noc0ni80wwe-23q0w2\2ns-5e-w6k6\6-d2me/e9e-2nre\s3e86w2`- -68ieq6i232me86ww;t-n2ni0q-e7m67ei/2-56ww;t-703er6nwenis-2wpemq6f22- -5eni296\6ns-2n/\zk2i0\swe-p232k0n/2q2-2-65q2w2nim6i28w;q2-q0m6q2-n- -re`8\0w20q-/eqrszi0me8-ni6\6-ek0825we1-w0e7te52qenis-2nre\s3e86w2`- -68ieq6i2k0n/2t-nm05ni8-36c2i;-p61\e8-56ww;t-2-rme9m6qqwe1-nm05;- -n\05ozc21-xi6r-m6382i2`-68ieq6i2k0n/2t-nm05ni8-36c2i;-n8`36w-n-re`8\0w20q- -m6nrm050\0ww;t-n2ni0q-e7m67ei/2-56ww;t-2-/eqrszi0mw;t-n0i01-8-/eiem;t- -nm05ni86-n0i08e1-703er6nweni2-2nre\s3ozin`-8-r0m8oz-ek0m05s-5\`-36c2i;- -r0m056860q;t-re-n0i`q-56ww;t-8-w627e\00-re\we1-im6/ie8/0-re5-nm05ni86q2- -n0i08e1-703er6nweni2-q;-7o50q-2q0is-8-825o-q0m;-rm05ei8m6c0w2`- -w6mod0w21-703er6nweni2-/eiem;0-8e3w2/6zi-rm2-r0m056k0-2wpemq6f22-re- -n0i`q-6-i6/40-q0m;-re38e\`zc20-erm050\`is-kie-i6/20-w6mod0w2`-703er6nweni2- -2q0\2-q0nie? \ No newline at end of file diff --git a/lab_1/task_2/decryption.py b/lab_1/task_2/decryption.py deleted file mode 100644 index 894ef1679..000000000 --- a/lab_1/task_2/decryption.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -Module for frequency analysis and substitution cipher decryption. -""" - -from collections import Counter - -from tools.work_with_files import * - - -def analyze_frequency(text: str, frequencies_filename: str) -> None: - """ - Analyzes character frequency in text and saves sorted results to JSON. - - :param text: Input text for frequency analysis - :param frequencies_filename: Output JSON filename for frequencies - :raises FileNotFoundError: If output file path is invalid - :raises PermissionError: If no write permissions for output file - """ - counter = Counter(char for char in text) - total = len(text) - frequencies = {char: count / total for char, count in counter.items()} - write_to_json(dict(sorted(frequencies.items(), - key=lambda item: item[1], - reverse=True)), - frequencies_filename) - - -def decrypt(frequences_filename: str, - in_filename: str, - out_filename: str, - key_filename: str) -> None: - """ - Decrypts text using substitution cipher based on frequency analysis key. - - :param frequences_filename: JSON file to store ciphertext frequencies - :param in_filename: Input file with encrypted text - :param out_filename: Output file for decrypted text - :param key_filename: JSON file with substitution mapping - :raises FileNotFoundError: If any input file is missing - :raises json.JSONDecodeError: If key file contains invalid JSON - """ - ciphertext = read_txt(in_filename) - analyze_frequency(ciphertext, frequences_filename) - - key = read_json(key_filename) - result = "".join(key.get(char, char) for char in ciphertext) - write_to_txt(out_filename, result) diff --git a/lab_1/task_2/decryption_settings.json b/lab_1/task_2/decryption_settings.json deleted file mode 100644 index 5e70e9055..000000000 --- a/lab_1/task_2/decryption_settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "in_filename": "task_2/cod7.txt", - "out_filename": "result7.txt", - "frequencies_filename": "frequencies.json", - "key": "key.json" -} \ No newline at end of file diff --git a/lab_1/text.txt b/lab_1/text.txt deleted file mode 100644 index 5085ebce4..000000000 --- a/lab_1/text.txt +++ /dev/null @@ -1,99 +0,0 @@ -ВЫ ПОМНИТЕ, -ВЫ ВСЁ, КОНЕЧНО, ПОМНИТЕ, -КАК Я СТОЯЛ, -ПРИБЛИЗИВШИСЬ К СТЕНЕ, -ВЗВОЛНОВАННО ХОДИЛИ ВЫ ПО КОМНАТЕ -И ЧТО-ТО РЕЗКОЕ -В ЛИЦО БРОСАЛИ МНЕ. -ВЫ ГОВОРИЛИ: -НАМ ПОРА РАССТАТЬСЯ, -ЧТО ВАС ИЗМУЧИЛА -МОЯ ШАЛЬНАЯ ЖИЗНЬ, -ЧТО ВАМ ПОРА ЗА ДЕЛО ПРИНИМАТЬСЯ, -А МОЙ УДЕЛ — -КАТИТЬСЯ ДАЛЬШЕ, ВНИЗ. -ЛЮБИМАЯ! -МЕНЯ ВЫ НЕ ЛЮБИЛИ. -НЕ ЗНАЛИ ВЫ, ЧТО В СОНМИЩЕ ЛЮДСКОМ -Я БЫЛ КАК ЛОШАДЬ, ЗАГНАННАЯ В МЫЛЕ, -ПРИШПОРЕННАЯ СМЕЛЫМ ЕЗДОКОМ. -НЕ ЗНАЛИ ВЫ, -ЧТО Я В СПЛОШНОМ ДЫМУ, -В РАЗВОРОЧЕННОМ БУРЕЙ БЫТЕ -С ТОГО И МУЧАЮСЬ, ЧТО НЕ ПОЙМУ — -КУДА НЕСЕТ НАС РОК СОБЫТИЙ. -ЛИЦОМ К ЛИЦУ -ЛИЦА НЕ УВИДАТЬ. -БОЛЬШОЕ ВИДИТСЯ НА РАССТОЯНЬЕ. -КОГДА КИПИТ МОРСКАЯ ГЛАДЬ — -КОРАБЛЬ В ПЛАЧЕВНОМ СОСТОЯНЬЕ. -ЗЕМЛЯ — КОРАБЛЬ! -НО КТО-ТО ВДРУГ -ЗА НОВОЙ ЖИЗНЬЮ, НОВОЙ СЛАВОЙ -В ПРЯМУЮ ГУЩУ БУРЬ И ВЬЮГ -ЕЕ НАПРАВИЛ ВЕЛИЧАВО. -НУ КТО Ж ИЗ НАС НА ПАЛУБЕ БОЛЬШОЙ -НЕ ПАДАЛ, НЕ БЛЕВАЛ И НЕ РУГАЛСЯ? -ИХ МАЛО, С ОПЫТНОЙ ДУШОЙ, -КТО КРЕПКИМ В КАЧКЕ ОСТАВАЛСЯ. -ТОГДА И Я, -ПОД ДИКИЙ ШУМ, -НО ЗРЕЛО ЗНАЮЩИЙ РАБОТУ, -СПУСТИЛСЯ В КОРАБЕЛЬНЫЙ ТРЮМ, -ЧТОБ НЕ СМОТРЕТЬ ЛЮДСКУЮ РВОТУ. -ТОТ ТРЮМ БЫЛ — -РУССКИМ КАБАКОМ. -И Я СКЛОНИЛСЯ НАД СТАКАНОМ, -ЧТОБ, НЕ СТРАДАЯ НИ О КОМ, -СЕБЯ СГУБИТЬ -В УГАРЕ ПЬЯНОМ. -ЛЮБИМАЯ! -Я МУЧИЛ ВАС, -У ВАС БЫЛА ТОСКА -В ГЛАЗАХ УСТАЛЫХ: -ЧТО Я ПРЕД ВАМИ НАПОКАЗ -СЕБЯ РАСТРАЧИВАЛ В СКАНДАЛАХ. -НО ВЫ НЕ ЗНАЛИ, -ЧТО В СПЛОШНОМ ДЫМУ, -В РАЗВОРОЧЕННОМ БУРЕЙ БЫТЕ -С ТОГО И МУЧАЮСЬ, -ЧТО НЕ ПОЙМУ, -КУДА НЕСЕТ НАС РОК СОБЫТИЙ… -ТЕПЕРЬ ГОДА ПРОШЛИ. -Я В ВОЗРАСТЕ ИНОМ. -И ЧУВСТВУЮ И МЫСЛЮ ПО-ИНОМУ. -И ГОВОРЮ ЗА ПРАЗДНИЧНЫМ ВИНОМ: -ХВАЛА И СЛАВА РУЛЕВОМУ! -СЕГОДНЯ Я -В УДАРЕ НЕЖНЫХ ЧУВСТВ. -Я ВСПОМНИЛ ВАШУ ГРУСТНУЮ УСТАЛОСТЬ. -И ВОТ ТЕПЕРЬ -Я СООБЩИТЬ ВАМ МЧУСЬ, -КАКОВ Я БЫЛ, -И ЧТО СО МНОЮ СТАЛОСЬ! -ЛЮБИМАЯ! -СКАЗАТЬ ПРИЯТНО МНЕ: -Я ИЗБЕЖАЛ ПАДЕНЬЯ С КРУЧИ. -ТЕПЕРЬ В СОВЕТСКОЙ СТОРОНЕ -Я САМЫЙ ЯРОСТНЫЙ ПОПУТЧИК. -Я СТАЛ НЕ ТЕМ, -КЕМ БЫЛ ТОГДА. -НЕ МУЧИЛ БЫ Я ВАС, -КАК ЭТО БЫЛО РАНЬШЕ. -ЗА ЗНАМЯ ВОЛЬНОСТИ -И СВЕТЛОГО ТРУДА -ГОТОВ ИДТИ ХОТЬ ДО ЛА-МАНША. -ПРОСТИТЕ МНЕ… -Я ЗНАЮ: ВЫ НЕ ТА — -ЖИВЕТЕ ВЫ -С СЕРЬЕЗНЫМ, УМНЫМ МУЖЕМ; -ЧТО НЕ НУЖНА ВАМ НАША МАЕТА, -И САМ Я ВАМ -НИ КАПЕЛЬКИ НЕ НУЖЕН. -ЖИВИТЕ ТАК, -КАК ВАС ВЕДЕТ ЗВЕЗДА, -ПОД КУЩЕЙ ОБНОВЛЕННОЙ СЕНИ. -С ПРИВЕТСТВИЕМ, -ВАС ПОМНЯЩИЙ ВСЕГДА -ЗНАКОМЫЙ ВАШ -СЕРГЕЙ ЕСЕНИН. \ No newline at end of file diff --git a/lab_1/tools/work_with_files.py b/lab_1/tools/work_with_files.py deleted file mode 100644 index b86455785..000000000 --- a/lab_1/tools/work_with_files.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -Module for working with JSON and TXT files. -""" - -from json import load, dump - - -def read_json(filename: str) -> dict: - """ - Reads data from a JSON file. - - :param filename: Name of the file to read. - :return: Dictionary with data from the file. - :raises FileNotFoundError: If the file is not found. - :raises json.JSONDecodeError: If the file contains invalid JSON. - """ - try: - with open(filename, "r", encoding="utf-8") as file: - return load(file) - except Exception as e: - print(f"Error: {e}") - - -def write_to_json(dictionary: dict, filename: str) -> None: - """ - Writes a dictionary to a JSON file. - - :param dictionary: Dictionary to write to the file. - :param filename: Name of the file to write. - :raises TypeError: If a non-dictionary is passed. - """ - try: - with open(filename, "w", encoding="utf-8") as file: - dump(dictionary, file, ensure_ascii=False, indent=4) - except Exception as e: - print(f"Error: {e}") - - -def read_txt(filename: str) -> str: - """ - Reads the contents of a TXT file. - - :param filename: Name of the file to read. - :return: String with the file contents. - :raises FileNotFoundError: If the file is not found. - """ - try: - with open(filename, "r", encoding="utf-8") as file: - return file.read() - except Exception as e: - print(f"Error: {e}") - - -def write_to_txt(filename: str, data: str) -> None: - """ - Writes a string to a TXT file. - - :param filename: Name of the file to write. - :param data: String to write to the file. - :raises TypeError: If a non-string is passed. - """ - try: - with open(filename, "w", encoding="utf-8") as file: - file.write(data) - except Exception as e: - print(f"Error: {e}") diff --git a/lab_1/.gitignore b/lab_2/.gitignore similarity index 100% rename from lab_1/.gitignore rename to lab_2/.gitignore diff --git a/lab_2/constants.py b/lab_2/constants.py new file mode 100644 index 000000000..14e185703 --- /dev/null +++ b/lab_2/constants.py @@ -0,0 +1,3 @@ +PI = [0.2148, 0.3672, 0.2305, 0.1875] + +OUTPUT = "results.txt" diff --git a/lab_2/random_sequences/random.cpp b/lab_2/random_sequences/random.cpp new file mode 100644 index 000000000..10efc43bf --- /dev/null +++ b/lab_2/random_sequences/random.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +std::bitset<128> generate_random_binary_sequence() { + std::random_device rd; + std::mt19937_64 gen(rd()); + std::uniform_int_distribution dist(0, UINT64_MAX); + + uint64_t part1 = dist(gen); + uint64_t part2 = dist(gen); + + std::bitset<128> result(part1); + result <<= 64; + result |= part2; + + return result; +} + +int main() { + std::bitset<128> random_sequence = generate_random_binary_sequence(); + std::cout << "Random 128-bit binary sequence: " << random_sequence << std::endl; + return 0; +} \ No newline at end of file diff --git a/lab_2/random_sequences/random.java b/lab_2/random_sequences/random.java new file mode 100644 index 000000000..28f11c269 --- /dev/null +++ b/lab_2/random_sequences/random.java @@ -0,0 +1,20 @@ +import java.util.Random; + +public class Main +{ + public static String generate_random_binary_sequence() { + Random random = new Random(); + StringBuilder binary_string = new StringBuilder(128); + + for (int i = 0; i < 128; ++i) { + binary_string.append(random.nextBoolean() ? '1' : '0'); + } + + return binary_string.toString(); + } + + public static void main(String[] args) { + String random_sequence = generate_random_binary_sequence(); + System.out.println("Random 128-bit binary sequence: " + random_sequence); + } +} \ No newline at end of file diff --git a/lab_2/random_sequences/random_sequences.py b/lab_2/random_sequences/random_sequences.py new file mode 100644 index 000000000..0ba9a2b0b --- /dev/null +++ b/lab_2/random_sequences/random_sequences.py @@ -0,0 +1,2 @@ +CPP = "01100000000011101100011101001010000110101001111000010110000101100111100011111110100100011110101110011101001010111110110001101110" +JAVA = "10000010100101000001000100100101100000000111001001010001110100111011000110101011111011110011111001100110000101011100100010010001" diff --git a/lab_2/requirements.txt b/lab_2/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..6883ee8e2be9a83183e780630bbb29d4e8a2caca GIT binary patch literal 102 zcmezWFOQ*=A(x?mp_0KC2#px@z}S?5mw^i`n#_>TkiwA4P|Q#QRFeZ_!PFTt7z0%s YfK?VVBr{~fO)&(D8#0&zNn@}q0NKS51ONa4 literal 0 HcmV?d00001 diff --git a/lab_2/results.txt b/lab_2/results.txt new file mode 100644 index 000000000..727939eb9 --- /dev/null +++ b/lab_2/results.txt @@ -0,0 +1,8 @@ +Pvalue of Frequency bitwise test: 0.7236736098317631 +Pvalue of Test for identical consecutive bits: 0.4859663683620416 +Pvalue of Test for the longest sequence of units in a block: 0.4641878475985987 + +Pvalue of Frequency bitwise test: 0.21592493894014045 +Pvalue of Test for identical consecutive bits: 0.8910439364805282 +Pvalue of Test for the longest sequence of units in a block: 0.9629608942072102 + diff --git a/lab_2/tests.py b/lab_2/tests.py new file mode 100644 index 000000000..4efc6a53c --- /dev/null +++ b/lab_2/tests.py @@ -0,0 +1,84 @@ +import math + +from scipy.special import gammainc + +import constants as c +import random_sequences.random_sequences as rs + + +def frequency_bitwise_test(sequence: str) -> float: + n = len(sequence) + s = abs(1 / math.sqrt(n) * (sequence.count("1") - sequence.count("0"))) + return math.erfc(s / math.sqrt(2)) + + +def consecutive_bits_test(sequence: str) -> float: + n = len(sequence) + p = sequence.count("1") / n + if abs(p - 0.5) >= 2 / math.sqrt(n): + return 0 + + v = sum(sequence[i] != sequence[i + 1] for i in range(n - 1)) + return math.erfc( + abs(v - 2 * n * p * (1 - p)) / (2 * math.sqrt(2 * n) * p * (1 - p)) + ) + + +def longest_sequence_of_units_test(sequence: str) -> float: + n = len(sequence) + v = [0, 0, 0, 0] + for i in range(0, n, 8): + max_length = 0 + current_length = 0 + for j in sequence[i:i + 8]: + if j == "1": + current_length += 1 + max_length = max(max_length, current_length) + else: + current_length = 0 + + match max_length: + case 0: + v[0] += 1 + case 1: + v[0] += 1 + case 2: + v[1] += 1 + case 3: + v[2] += 1 + case _: + v[3] += 1 + + he2 = sum((v[i] - 16 * c.PI[i])**2 / (16 * c.PI[i]) for i in range(4)) + return gammainc(3 / 2, he2 / 2) + + +def save_results_to_file(fr: float, cb: float, ls: float, path: str) -> None: + with open(path, "a") as file: + print(f"Pvalue of Frequency bitwise test: {fr}", file=file) + print( + f"Pvalue of Test for identical consecutive bits: {cb}", + file=file + ) + print( + "Pvalue of Test for the longest sequence " + + f"of units in a block: {ls}", + file=file + ) + print("", file=file) + + +def main(): + fr_cpp = frequency_bitwise_test(rs.CPP) + cb_cpp = consecutive_bits_test(rs.CPP) + ls_cpp = longest_sequence_of_units_test(rs.CPP) + save_results_to_file(fr_cpp, cb_cpp, ls_cpp, c.OUTPUT) + + fr_java = frequency_bitwise_test(rs.JAVA) + cb_java = consecutive_bits_test(rs.JAVA) + ls_java = longest_sequence_of_units_test(rs.JAVA) + save_results_to_file(fr_java, cb_java, ls_java, c.OUTPUT) + + +if __name__ == "__main__": + main() From a9b44cfbf0f256c7c87b8acba565916c68d83de0 Mon Sep 17 00:00:00 2001 From: student Date: Tue, 27 May 2025 16:38:15 +0400 Subject: [PATCH 6/9] Made corrections --- lab_2/constants.json | 5 + lab_2/constants.py | 3 - lab_2/random_sequences/random.cpp | 33 ++++-- lab_2/random_sequences/random.java | 35 ++++-- lab_2/random_sequences/random_sequences.json | 4 + lab_2/random_sequences/random_sequences.py | 2 - lab_2/requirements.txt | Bin 102 -> 166 bytes lab_2/results.txt | 8 -- lab_2/tests.py | 107 ++++++++++++++----- lab_2/tools/work_with_files.py | 66 ++++++++++++ 10 files changed, 204 insertions(+), 59 deletions(-) create mode 100644 lab_2/constants.json delete mode 100644 lab_2/constants.py create mode 100644 lab_2/random_sequences/random_sequences.json delete mode 100644 lab_2/random_sequences/random_sequences.py delete mode 100644 lab_2/results.txt create mode 100644 lab_2/tools/work_with_files.py diff --git a/lab_2/constants.json b/lab_2/constants.json new file mode 100644 index 000000000..ec8a2375b --- /dev/null +++ b/lab_2/constants.json @@ -0,0 +1,5 @@ +{ + "PI": [0.2148, 0.3672, 0.2305, 0.1875], + + "OUTPUT": "results.txt" +} \ No newline at end of file diff --git a/lab_2/constants.py b/lab_2/constants.py deleted file mode 100644 index 14e185703..000000000 --- a/lab_2/constants.py +++ /dev/null @@ -1,3 +0,0 @@ -PI = [0.2148, 0.3672, 0.2305, 0.1875] - -OUTPUT = "results.txt" diff --git a/lab_2/random_sequences/random.cpp b/lab_2/random_sequences/random.cpp index 10efc43bf..071b84332 100644 --- a/lab_2/random_sequences/random.cpp +++ b/lab_2/random_sequences/random.cpp @@ -2,14 +2,25 @@ #include #include -std::bitset<128> generate_random_binary_sequence() { - std::random_device rd; - std::mt19937_64 gen(rd()); - std::uniform_int_distribution dist(0, UINT64_MAX); +/** + * @brief Generates a random 128-bit binary sequence + * + * This function generates a uniformly distributed random 128-bit binary sequence + * using the Mersenne Twister algorithm for random number generation. + * + * @return std::bitset<128> A bitset containing the generated 128-bit sequence + */ +std::bitset<128> generateRandomBinarySequence() +{ + std::random_device rd; // True random number generator for seeding + std::mt19937_64 gen(rd()); // Mersenne Twister 64-bit RNG + std::uniform_int_distribution dist(0, UINT64_MAX); // Uniform distribution + // Generate two 64-bit random numbers uint64_t part1 = dist(gen); uint64_t part2 = dist(gen); + // Combine into 128-bit bitset std::bitset<128> result(part1); result <<= 64; result |= part2; @@ -17,8 +28,16 @@ std::bitset<128> generate_random_binary_sequence() { return result; } -int main() { - std::bitset<128> random_sequence = generate_random_binary_sequence(); - std::cout << "Random 128-bit binary sequence: " << random_sequence << std::endl; +/** + * @brief Main function demonstrating the binary sequence generator + * + * Generates and prints a random 128-bit binary sequence to standard output. + * + * @return int Returns 0 on successful execution + */ +int main() +{ + std::bitset<128> randomSequence = generateRandomBinarySequence(); + std::cout << "Random 128-bit binary sequence: " << randomSequence << std::endl; return 0; } \ No newline at end of file diff --git a/lab_2/random_sequences/random.java b/lab_2/random_sequences/random.java index 28f11c269..6702aa80e 100644 --- a/lab_2/random_sequences/random.java +++ b/lab_2/random_sequences/random.java @@ -1,20 +1,35 @@ import java.util.Random; -public class Main -{ - public static String generate_random_binary_sequence() { +/** + * A utility class for generating random binary sequences. + */ +public class Main { + + /** + * Generates a random 128-bit binary sequence as a string of '0's and '1's. + * Each bit in the sequence is randomly generated with equal probability of being 0 or 1. + * + * @return A string of length 128 representing the randomly generated binary sequence. + */ + public static String generateRandomBinarySequence() { Random random = new Random(); - StringBuilder binary_string = new StringBuilder(128); + StringBuilder binaryString = new StringBuilder(128); for (int i = 0; i < 128; ++i) { - binary_string.append(random.nextBoolean() ? '1' : '0'); + binaryString.append(random.nextBoolean() ? '1' : '0'); } - return binary_string.toString(); + return binaryString.toString(); } - public static void main(String[] args) { - String random_sequence = generate_random_binary_sequence(); - System.out.println("Random 128-bit binary sequence: " + random_sequence); - } + /** + * Main method that demonstrates the usage of the binary sequence generator. + * Generates and prints a random 128-bit binary sequence. + * + * @param args Command line arguments (not used). + */ + public static void main(String[] args) { + String randomSequence = generateRandomBinarySequence(); + System.out.println("Random 128-bit binary sequence: " + randomSequence); + } } \ No newline at end of file diff --git a/lab_2/random_sequences/random_sequences.json b/lab_2/random_sequences/random_sequences.json new file mode 100644 index 000000000..a15104da9 --- /dev/null +++ b/lab_2/random_sequences/random_sequences.json @@ -0,0 +1,4 @@ +{ + "CPP": "01100000000011101100011101001010000110101001111000010110000101100111100011111110100100011110101110011101001010111110110001101110", + "JAVA": "10000010100101000001000100100101100000000111001001010001110100111011000110101011111011110011111001100110000101011100100010010001" +} \ No newline at end of file diff --git a/lab_2/random_sequences/random_sequences.py b/lab_2/random_sequences/random_sequences.py deleted file mode 100644 index 0ba9a2b0b..000000000 --- a/lab_2/random_sequences/random_sequences.py +++ /dev/null @@ -1,2 +0,0 @@ -CPP = "01100000000011101100011101001010000110101001111000010110000101100111100011111110100100011110101110011101001010111110110001101110" -JAVA = "10000010100101000001000100100101100000000111001001010001110100111011000110101011111011110011111001100110000101011100100010010001" diff --git a/lab_2/requirements.txt b/lab_2/requirements.txt index 6883ee8e2be9a83183e780630bbb29d4e8a2caca..c35b98ec80172719b3e1dd0395eda987cad02ba8 100644 GIT binary patch literal 166 zcmX|)%L;=)3`Nhn&`+^A6~&ETQ-unSubD3V`PQ2VB_xELJ7<31$U$ObqTt2CtQxds z?YnNPc;@Y-qod_Psjdjzxhef2ddlci#JX{2Z_U}um}EKh%b?Vi3v!stEJ?ZXZwa~w IYR$^&2_YaFy8r+H delta 32 icmZ3+m?ruEUmim#LoP!BLnVVP5E?P)fwAetNM8V)t_TAF diff --git a/lab_2/results.txt b/lab_2/results.txt deleted file mode 100644 index 727939eb9..000000000 --- a/lab_2/results.txt +++ /dev/null @@ -1,8 +0,0 @@ -Pvalue of Frequency bitwise test: 0.7236736098317631 -Pvalue of Test for identical consecutive bits: 0.4859663683620416 -Pvalue of Test for the longest sequence of units in a block: 0.4641878475985987 - -Pvalue of Frequency bitwise test: 0.21592493894014045 -Pvalue of Test for identical consecutive bits: 0.8910439364805282 -Pvalue of Test for the longest sequence of units in a block: 0.9629608942072102 - diff --git a/lab_2/tests.py b/lab_2/tests.py index 4efc6a53c..8e9d28806 100644 --- a/lab_2/tests.py +++ b/lab_2/tests.py @@ -1,18 +1,47 @@ -import math +"""Statistical tests for random binary sequences. -from scipy.special import gammainc +This module implements NIST-style randomness tests for binary sequences: +- Frequency (monobit) test +- Consecutive bits (runs) test +- Longest run of ones in a block test +""" -import constants as c -import random_sequences.random_sequences as rs +import math +from scipy.special import gammainc +from tools.work_with_files import read_json def frequency_bitwise_test(sequence: str) -> float: + """Perform frequency (monobit) test on binary sequence. + + Computes the proportion of ones versus zeros in the sequence. + A truly random sequence should have approximately equal counts. + + Args: + sequence: Binary string (e.g. "010110..."). + + Returns: + P-value from the normal distribution ERFC function. + Values close to 0 indicate non-randomness. + """ n = len(sequence) s = abs(1 / math.sqrt(n) * (sequence.count("1") - sequence.count("0"))) return math.erfc(s / math.sqrt(2)) def consecutive_bits_test(sequence: str) -> float: + """Perform runs test on binary sequence. + + Counts the number of transitions between 0 and 1. + Too few or too many transitions suggest non-randomness. + + Args: + sequence: Binary string to analyze. + + Returns: + P-value. Returns 0 if the sequence is clearly biased + (proportion of ones differs significantly from 0.5). + """ n = len(sequence) p = sequence.count("1") / n if abs(p - 0.5) >= 2 / math.sqrt(n): @@ -25,8 +54,21 @@ def consecutive_bits_test(sequence: str) -> float: def longest_sequence_of_units_test(sequence: str) -> float: + """Perform longest run of ones in 8-bit blocks test. + + Splits the sequence into 8-bit blocks and analyzes + the distribution of the longest runs of ones. + + Args: + sequence: Binary string to test. + + Returns: + P-value from the chi-squared test with 3 degrees of freedom. + """ + c = read_json("constants.json") n = len(sequence) v = [0, 0, 0, 0] + for i in range(0, n, 8): max_length = 0 current_length = 0 @@ -38,9 +80,7 @@ def longest_sequence_of_units_test(sequence: str) -> float: current_length = 0 match max_length: - case 0: - v[0] += 1 - case 1: + case 0 | 1: v[0] += 1 case 2: v[1] += 1 @@ -49,35 +89,44 @@ def longest_sequence_of_units_test(sequence: str) -> float: case _: v[3] += 1 - he2 = sum((v[i] - 16 * c.PI[i])**2 / (16 * c.PI[i]) for i in range(4)) + he2 = sum((v[i] - 16 * c["PI"][i])**2 / (16 * c["PI"][i]) for i in range(4)) return gammainc(3 / 2, he2 / 2) def save_results_to_file(fr: float, cb: float, ls: float, path: str) -> None: - with open(path, "a") as file: - print(f"Pvalue of Frequency bitwise test: {fr}", file=file) - print( - f"Pvalue of Test for identical consecutive bits: {cb}", - file=file - ) - print( - "Pvalue of Test for the longest sequence " + - f"of units in a block: {ls}", - file=file - ) - print("", file=file) + """Save test results to specified file path. + + Args: + fr: P-value from frequency test. + cb: P-value from runs test. + ls: P-value from longest run test. + path: Output file path. + """ + try: + with open(path, "a") as file: + print(f"Pvalue of Frequency bitwise test: {fr}", file=file) + print(f"Pvalue of Test for identical consecutive bits: {cb}", file=file) + print("Pvalue of Test for the longest sequence " + + f"of units in a block: {ls}", file=file) + print("", file=file) + except Exception as e: + print(f"Error: {e}") def main(): - fr_cpp = frequency_bitwise_test(rs.CPP) - cb_cpp = consecutive_bits_test(rs.CPP) - ls_cpp = longest_sequence_of_units_test(rs.CPP) - save_results_to_file(fr_cpp, cb_cpp, ls_cpp, c.OUTPUT) - - fr_java = frequency_bitwise_test(rs.JAVA) - cb_java = consecutive_bits_test(rs.JAVA) - ls_java = longest_sequence_of_units_test(rs.JAVA) - save_results_to_file(fr_java, cb_java, ls_java, c.OUTPUT) + """Execute all tests on predefined sequences and save results.""" + rs = read_json("random_sequences/random_sequences.json") + c = read_json("constants.json") + + fr_cpp = frequency_bitwise_test(rs["CPP"]) + cb_cpp = consecutive_bits_test(rs["CPP"]) + ls_cpp = longest_sequence_of_units_test(rs["CPP"]) + save_results_to_file(fr_cpp, cb_cpp, ls_cpp, c["OUTPUT"]) + + fr_java = frequency_bitwise_test(rs["JAVA"]) + cb_java = consecutive_bits_test(rs["JAVA"]) + ls_java = longest_sequence_of_units_test(rs["JAVA"]) + save_results_to_file(fr_java, cb_java, ls_java, c["OUTPUT"]) if __name__ == "__main__": diff --git a/lab_2/tools/work_with_files.py b/lab_2/tools/work_with_files.py new file mode 100644 index 000000000..b86455785 --- /dev/null +++ b/lab_2/tools/work_with_files.py @@ -0,0 +1,66 @@ +""" +Module for working with JSON and TXT files. +""" + +from json import load, dump + + +def read_json(filename: str) -> dict: + """ + Reads data from a JSON file. + + :param filename: Name of the file to read. + :return: Dictionary with data from the file. + :raises FileNotFoundError: If the file is not found. + :raises json.JSONDecodeError: If the file contains invalid JSON. + """ + try: + with open(filename, "r", encoding="utf-8") as file: + return load(file) + except Exception as e: + print(f"Error: {e}") + + +def write_to_json(dictionary: dict, filename: str) -> None: + """ + Writes a dictionary to a JSON file. + + :param dictionary: Dictionary to write to the file. + :param filename: Name of the file to write. + :raises TypeError: If a non-dictionary is passed. + """ + try: + with open(filename, "w", encoding="utf-8") as file: + dump(dictionary, file, ensure_ascii=False, indent=4) + except Exception as e: + print(f"Error: {e}") + + +def read_txt(filename: str) -> str: + """ + Reads the contents of a TXT file. + + :param filename: Name of the file to read. + :return: String with the file contents. + :raises FileNotFoundError: If the file is not found. + """ + try: + with open(filename, "r", encoding="utf-8") as file: + return file.read() + except Exception as e: + print(f"Error: {e}") + + +def write_to_txt(filename: str, data: str) -> None: + """ + Writes a string to a TXT file. + + :param filename: Name of the file to write. + :param data: String to write to the file. + :raises TypeError: If a non-string is passed. + """ + try: + with open(filename, "w", encoding="utf-8") as file: + file.write(data) + except Exception as e: + print(f"Error: {e}") From 402304eb295eaea4a08c693a4560417b8efa1fd1 Mon Sep 17 00:00:00 2001 From: student Date: Tue, 27 May 2025 18:31:05 +0400 Subject: [PATCH 7/9] Started lab3 --- lab_2/constants.json | 5 - lab_2/random_sequences/random.cpp | 43 ------ lab_2/random_sequences/random.java | 35 ----- lab_2/random_sequences/random_sequences.json | 4 - lab_2/requirements.txt | Bin 166 -> 0 bytes lab_2/tests.py | 133 ------------------- lab_2/tools/work_with_files.py | 66 --------- {lab_2 => lab_3}/.gitignore | 0 lab_3/file_manager.py | 24 ++++ lab_3/settings.json | 8 ++ lab_3/utils.py | 26 ++++ 11 files changed, 58 insertions(+), 286 deletions(-) delete mode 100644 lab_2/constants.json delete mode 100644 lab_2/random_sequences/random.cpp delete mode 100644 lab_2/random_sequences/random.java delete mode 100644 lab_2/random_sequences/random_sequences.json delete mode 100644 lab_2/requirements.txt delete mode 100644 lab_2/tests.py delete mode 100644 lab_2/tools/work_with_files.py rename {lab_2 => lab_3}/.gitignore (100%) create mode 100644 lab_3/file_manager.py create mode 100644 lab_3/settings.json create mode 100644 lab_3/utils.py diff --git a/lab_2/constants.json b/lab_2/constants.json deleted file mode 100644 index ec8a2375b..000000000 --- a/lab_2/constants.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "PI": [0.2148, 0.3672, 0.2305, 0.1875], - - "OUTPUT": "results.txt" -} \ No newline at end of file diff --git a/lab_2/random_sequences/random.cpp b/lab_2/random_sequences/random.cpp deleted file mode 100644 index 071b84332..000000000 --- a/lab_2/random_sequences/random.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include - -/** - * @brief Generates a random 128-bit binary sequence - * - * This function generates a uniformly distributed random 128-bit binary sequence - * using the Mersenne Twister algorithm for random number generation. - * - * @return std::bitset<128> A bitset containing the generated 128-bit sequence - */ -std::bitset<128> generateRandomBinarySequence() -{ - std::random_device rd; // True random number generator for seeding - std::mt19937_64 gen(rd()); // Mersenne Twister 64-bit RNG - std::uniform_int_distribution dist(0, UINT64_MAX); // Uniform distribution - - // Generate two 64-bit random numbers - uint64_t part1 = dist(gen); - uint64_t part2 = dist(gen); - - // Combine into 128-bit bitset - std::bitset<128> result(part1); - result <<= 64; - result |= part2; - - return result; -} - -/** - * @brief Main function demonstrating the binary sequence generator - * - * Generates and prints a random 128-bit binary sequence to standard output. - * - * @return int Returns 0 on successful execution - */ -int main() -{ - std::bitset<128> randomSequence = generateRandomBinarySequence(); - std::cout << "Random 128-bit binary sequence: " << randomSequence << std::endl; - return 0; -} \ No newline at end of file diff --git a/lab_2/random_sequences/random.java b/lab_2/random_sequences/random.java deleted file mode 100644 index 6702aa80e..000000000 --- a/lab_2/random_sequences/random.java +++ /dev/null @@ -1,35 +0,0 @@ -import java.util.Random; - -/** - * A utility class for generating random binary sequences. - */ -public class Main { - - /** - * Generates a random 128-bit binary sequence as a string of '0's and '1's. - * Each bit in the sequence is randomly generated with equal probability of being 0 or 1. - * - * @return A string of length 128 representing the randomly generated binary sequence. - */ - public static String generateRandomBinarySequence() { - Random random = new Random(); - StringBuilder binaryString = new StringBuilder(128); - - for (int i = 0; i < 128; ++i) { - binaryString.append(random.nextBoolean() ? '1' : '0'); - } - - return binaryString.toString(); - } - - /** - * Main method that demonstrates the usage of the binary sequence generator. - * Generates and prints a random 128-bit binary sequence. - * - * @param args Command line arguments (not used). - */ - public static void main(String[] args) { - String randomSequence = generateRandomBinarySequence(); - System.out.println("Random 128-bit binary sequence: " + randomSequence); - } -} \ No newline at end of file diff --git a/lab_2/random_sequences/random_sequences.json b/lab_2/random_sequences/random_sequences.json deleted file mode 100644 index a15104da9..000000000 --- a/lab_2/random_sequences/random_sequences.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "CPP": "01100000000011101100011101001010000110101001111000010110000101100111100011111110100100011110101110011101001010111110110001101110", - "JAVA": "10000010100101000001000100100101100000000111001001010001110100111011000110101011111011110011111001100110000101011100100010010001" -} \ No newline at end of file diff --git a/lab_2/requirements.txt b/lab_2/requirements.txt deleted file mode 100644 index c35b98ec80172719b3e1dd0395eda987cad02ba8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 166 zcmX|)%L;=)3`Nhn&`+^A6~&ETQ-unSubD3V`PQ2VB_xELJ7<31$U$ObqTt2CtQxds z?YnNPc;@Y-qod_Psjdjzxhef2ddlci#JX{2Z_U}um}EKh%b?Vi3v!stEJ?ZXZwa~w IYR$^&2_YaFy8r+H diff --git a/lab_2/tests.py b/lab_2/tests.py deleted file mode 100644 index 8e9d28806..000000000 --- a/lab_2/tests.py +++ /dev/null @@ -1,133 +0,0 @@ -"""Statistical tests for random binary sequences. - -This module implements NIST-style randomness tests for binary sequences: -- Frequency (monobit) test -- Consecutive bits (runs) test -- Longest run of ones in a block test -""" - -import math -from scipy.special import gammainc -from tools.work_with_files import read_json - - -def frequency_bitwise_test(sequence: str) -> float: - """Perform frequency (monobit) test on binary sequence. - - Computes the proportion of ones versus zeros in the sequence. - A truly random sequence should have approximately equal counts. - - Args: - sequence: Binary string (e.g. "010110..."). - - Returns: - P-value from the normal distribution ERFC function. - Values close to 0 indicate non-randomness. - """ - n = len(sequence) - s = abs(1 / math.sqrt(n) * (sequence.count("1") - sequence.count("0"))) - return math.erfc(s / math.sqrt(2)) - - -def consecutive_bits_test(sequence: str) -> float: - """Perform runs test on binary sequence. - - Counts the number of transitions between 0 and 1. - Too few or too many transitions suggest non-randomness. - - Args: - sequence: Binary string to analyze. - - Returns: - P-value. Returns 0 if the sequence is clearly biased - (proportion of ones differs significantly from 0.5). - """ - n = len(sequence) - p = sequence.count("1") / n - if abs(p - 0.5) >= 2 / math.sqrt(n): - return 0 - - v = sum(sequence[i] != sequence[i + 1] for i in range(n - 1)) - return math.erfc( - abs(v - 2 * n * p * (1 - p)) / (2 * math.sqrt(2 * n) * p * (1 - p)) - ) - - -def longest_sequence_of_units_test(sequence: str) -> float: - """Perform longest run of ones in 8-bit blocks test. - - Splits the sequence into 8-bit blocks and analyzes - the distribution of the longest runs of ones. - - Args: - sequence: Binary string to test. - - Returns: - P-value from the chi-squared test with 3 degrees of freedom. - """ - c = read_json("constants.json") - n = len(sequence) - v = [0, 0, 0, 0] - - for i in range(0, n, 8): - max_length = 0 - current_length = 0 - for j in sequence[i:i + 8]: - if j == "1": - current_length += 1 - max_length = max(max_length, current_length) - else: - current_length = 0 - - match max_length: - case 0 | 1: - v[0] += 1 - case 2: - v[1] += 1 - case 3: - v[2] += 1 - case _: - v[3] += 1 - - he2 = sum((v[i] - 16 * c["PI"][i])**2 / (16 * c["PI"][i]) for i in range(4)) - return gammainc(3 / 2, he2 / 2) - - -def save_results_to_file(fr: float, cb: float, ls: float, path: str) -> None: - """Save test results to specified file path. - - Args: - fr: P-value from frequency test. - cb: P-value from runs test. - ls: P-value from longest run test. - path: Output file path. - """ - try: - with open(path, "a") as file: - print(f"Pvalue of Frequency bitwise test: {fr}", file=file) - print(f"Pvalue of Test for identical consecutive bits: {cb}", file=file) - print("Pvalue of Test for the longest sequence " + - f"of units in a block: {ls}", file=file) - print("", file=file) - except Exception as e: - print(f"Error: {e}") - - -def main(): - """Execute all tests on predefined sequences and save results.""" - rs = read_json("random_sequences/random_sequences.json") - c = read_json("constants.json") - - fr_cpp = frequency_bitwise_test(rs["CPP"]) - cb_cpp = consecutive_bits_test(rs["CPP"]) - ls_cpp = longest_sequence_of_units_test(rs["CPP"]) - save_results_to_file(fr_cpp, cb_cpp, ls_cpp, c["OUTPUT"]) - - fr_java = frequency_bitwise_test(rs["JAVA"]) - cb_java = consecutive_bits_test(rs["JAVA"]) - ls_java = longest_sequence_of_units_test(rs["JAVA"]) - save_results_to_file(fr_java, cb_java, ls_java, c["OUTPUT"]) - - -if __name__ == "__main__": - main() diff --git a/lab_2/tools/work_with_files.py b/lab_2/tools/work_with_files.py deleted file mode 100644 index b86455785..000000000 --- a/lab_2/tools/work_with_files.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -Module for working with JSON and TXT files. -""" - -from json import load, dump - - -def read_json(filename: str) -> dict: - """ - Reads data from a JSON file. - - :param filename: Name of the file to read. - :return: Dictionary with data from the file. - :raises FileNotFoundError: If the file is not found. - :raises json.JSONDecodeError: If the file contains invalid JSON. - """ - try: - with open(filename, "r", encoding="utf-8") as file: - return load(file) - except Exception as e: - print(f"Error: {e}") - - -def write_to_json(dictionary: dict, filename: str) -> None: - """ - Writes a dictionary to a JSON file. - - :param dictionary: Dictionary to write to the file. - :param filename: Name of the file to write. - :raises TypeError: If a non-dictionary is passed. - """ - try: - with open(filename, "w", encoding="utf-8") as file: - dump(dictionary, file, ensure_ascii=False, indent=4) - except Exception as e: - print(f"Error: {e}") - - -def read_txt(filename: str) -> str: - """ - Reads the contents of a TXT file. - - :param filename: Name of the file to read. - :return: String with the file contents. - :raises FileNotFoundError: If the file is not found. - """ - try: - with open(filename, "r", encoding="utf-8") as file: - return file.read() - except Exception as e: - print(f"Error: {e}") - - -def write_to_txt(filename: str, data: str) -> None: - """ - Writes a string to a TXT file. - - :param filename: Name of the file to write. - :param data: String to write to the file. - :raises TypeError: If a non-string is passed. - """ - try: - with open(filename, "w", encoding="utf-8") as file: - file.write(data) - except Exception as e: - print(f"Error: {e}") diff --git a/lab_2/.gitignore b/lab_3/.gitignore similarity index 100% rename from lab_2/.gitignore rename to lab_3/.gitignore diff --git a/lab_3/file_manager.py b/lab_3/file_manager.py new file mode 100644 index 000000000..1c09418f0 --- /dev/null +++ b/lab_3/file_manager.py @@ -0,0 +1,24 @@ +import os +from cryptography.hazmat.primitives import serialization + + +class FileManager: + def check_files_exist(paths: list) -> None: + """ + Checks whether the specified files exist. + + :param paths: List of file paths to check. + :raises SystemExit: If any file is not found. + """ + for path in paths: + if not os.path.exists(path): + print(f"[!] File is not found: {path}") + exit(1) + + + def save_public_key(filename: str, public_key) -> None: + with open(filename, "wb") as file: + file.write(public_key.public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo + )) \ No newline at end of file diff --git a/lab_3/settings.json b/lab_3/settings.json new file mode 100644 index 000000000..904699d45 --- /dev/null +++ b/lab_3/settings.json @@ -0,0 +1,8 @@ +{ + "initial_file": "text.txt", + "encrypted_file": "encrypted_text.txt", + "decrypted_file": "decrypted_text.txt", + "symmetric_key": "symmetric_key.txt", + "public_key": "public_key.txt", + "secret_key": "secret_key.txt" +} \ No newline at end of file diff --git a/lab_3/utils.py b/lab_3/utils.py new file mode 100644 index 000000000..7f9fec00a --- /dev/null +++ b/lab_3/utils.py @@ -0,0 +1,26 @@ +import json +import argparse + + +def load_settings() -> dict: + """ + Loads the settings from a JSON configuration file. + + :return: Dictionary containing configuration settings. + :raises SystemExit: If the settings.json file is not found. + """ + try: + with open("settings.json") as file: + return json.load(file) + except FileNotFoundError: + print("[!] File settings.json is not found.") + exit(1) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Hybrid cryptosystem") + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument("-gen", "--generation", action="store_true", help="Key generation") + group.add_argument("-enc", "--encryption", action="store_true", help="Data encryption") + group.add_argument("-dec", "--decryption", action="store_true", help="Data decryption") + return parser.parse_args() \ No newline at end of file From 1081867fc1ba2082b241cd9fb5c1c781f5998a44 Mon Sep 17 00:00:00 2001 From: velesikamid Date: Mon, 9 Jun 2025 03:53:25 +0400 Subject: [PATCH 8/9] Almost did lab3 --- lab_3/asymmetric_cipher.py | 45 +++++++++++++++++ lab_3/data.txt | 99 +++++++++++++++++++++++++++++++++++++ lab_3/encrypted_data.txt | Bin 0 -> 3904 bytes lab_3/encrypted_key.txt | Bin 0 -> 256 bytes lab_3/file_manager.py | 24 --------- lab_3/file_utils.py | 20 ++++++++ lab_3/helpers.py | 22 +++++++++ lab_3/main.py | 63 +++++++++++++++++++++++ lab_3/output.txt | 99 +++++++++++++++++++++++++++++++++++++ lab_3/rsa_private_key.txt | 27 ++++++++++ lab_3/rsa_pub_key.txt | 9 ++++ lab_3/settings.json | 11 ++--- lab_3/symmetric_cipher.py | 23 +++++++++ lab_3/utils.py | 26 ---------- 14 files changed, 412 insertions(+), 56 deletions(-) create mode 100644 lab_3/asymmetric_cipher.py create mode 100644 lab_3/data.txt create mode 100644 lab_3/encrypted_data.txt create mode 100644 lab_3/encrypted_key.txt delete mode 100644 lab_3/file_manager.py create mode 100644 lab_3/file_utils.py create mode 100644 lab_3/helpers.py create mode 100644 lab_3/main.py create mode 100644 lab_3/output.txt create mode 100644 lab_3/rsa_private_key.txt create mode 100644 lab_3/rsa_pub_key.txt create mode 100644 lab_3/symmetric_cipher.py delete mode 100644 lab_3/utils.py diff --git a/lab_3/asymmetric_cipher.py b/lab_3/asymmetric_cipher.py new file mode 100644 index 000000000..2d1f5f063 --- /dev/null +++ b/lab_3/asymmetric_cipher.py @@ -0,0 +1,45 @@ +import os +from cryptography.hazmat.primitives.asymmetric import rsa, padding +from cryptography.hazmat.primitives import serialization, hashes + + +class AsymmetricCipher: + @staticmethod + def generate_rsa_keypair() -> tuple: + private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) + return private_key, private_key.public_key() + + @staticmethod + def encrypt(key: bytes, public_key) -> bytes: + return public_key.encrypt( + key, + padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), label=None) + ) + + @staticmethod + def decrypt(encrypted_key: bytes, private_key) -> bytes: + return private_key.decrypt( + encrypted_key, + padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), label=None) + ) + + @staticmethod + def serialize_public_key(public_key) -> bytes: + return public_key.public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo + ) + + @staticmethod + def serialize_private_key(private_key) -> bytes: + return private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption() + ) + + @staticmethod + def load_private_key(data: bytes): + return serialization.load_pem_private_key(data, password=None) \ No newline at end of file diff --git a/lab_3/data.txt b/lab_3/data.txt new file mode 100644 index 000000000..ddbf13c3d --- /dev/null +++ b/lab_3/data.txt @@ -0,0 +1,99 @@ +Вы помните, +Вы всё, конечно, помните, +Как я стоял, +Приблизившись к стене, +Взволнованно ходили вы по комнате +И что-то резкое +В лицо бросали мне. +Вы говорили: +Нам пора расстаться, +Что вас измучила +Моя шальная жизнь, +Что вам пора за дело приниматься, +А мой удел — +Катиться дальше, вниз. +Любимая! +Меня вы не любили. +Не знали вы, что в сонмище людском +Я был как лошадь, загнанная в мыле, +Пришпоренная смелым ездоком. +Не знали вы, +Что я в сплошном дыму, +В развороченном бурей быте +С того и мучаюсь, что не пойму — +Куда несет нас рок событий. +Лицом к лицу +Лица не увидать. +Большое видится на расстоянье. +Когда кипит морская гладь — +Корабль в плачевном состоянье. +Земля — корабль! +Но кто-то вдруг +За новой жизнью, новой славой +В прямую гущу бурь и вьюг +Ее направил величаво. +Ну кто ж из нас на палубе большой +Не падал, не блевал и не ругался? +Их мало, с опытной душой, +Кто крепким в качке оставался. +Тогда и я, +Под дикий шум, +Но зрело знающий работу, +Спустился в корабельный трюм, +Чтоб не смотреть людскую рвоту. +Тот трюм был — +Русским кабаком. +И я склонился над стаканом, +Чтоб, не страдая ни о ком, +Себя сгубить +В угаре пьяном. +Любимая! +Я мучил вас, +У вас была тоска +В глазах усталых: +Что я пред вами напоказ +Себя растрачивал в скандалах. +Но вы не знали, +Что в сплошном дыму, +В развороченном бурей быте +С того и мучаюсь, +Что не пойму, +Куда несет нас рок событий… +Теперь года прошли. +Я в возрасте ином. +И чувствую и мыслю по-иному. +И говорю за праздничным вином: +Хвала и слава рулевому! +Сегодня я +В ударе нежных чувств. +Я вспомнил вашу грустную усталость. +И вот теперь +Я сообщить вам мчусь, +Каков я был, +И что со мною сталось! +Любимая! +Сказать приятно мне: +Я избежал паденья с кручи. +Теперь в Советской стороне +Я самый яростный попутчик. +Я стал не тем, +Кем был тогда. +Не мучил бы я вас, +Как это было раньше. +За знамя вольности +И светлого труда +Готов идти хоть до Ла-Манша. +Простите мне… +Я знаю: вы не та — +Живете вы +С серьезным, умным мужем; +Что не нужна вам наша маета, +И сам я вам +Ни капельки не нужен. +Живите так, +Как вас ведет звезда, +Под кущей обновленной сени. +С приветствием, +Вас помнящий всегда +Знакомый ваш +Сергей Есенин. \ No newline at end of file diff --git a/lab_3/encrypted_data.txt b/lab_3/encrypted_data.txt new file mode 100644 index 0000000000000000000000000000000000000000..1c3568bbf7057296b75080a4953b8d062e3b05fb GIT binary patch literal 3904 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 None: - """ - Checks whether the specified files exist. - - :param paths: List of file paths to check. - :raises SystemExit: If any file is not found. - """ - for path in paths: - if not os.path.exists(path): - print(f"[!] File is not found: {path}") - exit(1) - - - def save_public_key(filename: str, public_key) -> None: - with open(filename, "wb") as file: - file.write(public_key.public_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PublicFormat.SubjectPublicKeyInfo - )) \ No newline at end of file diff --git a/lab_3/file_utils.py b/lab_3/file_utils.py new file mode 100644 index 000000000..0715bdb10 --- /dev/null +++ b/lab_3/file_utils.py @@ -0,0 +1,20 @@ +import os + + +class FileManager: + @staticmethod + def read_file(path: str) -> bytes: + with open(path, 'rb') as file: + return file.read() + + @staticmethod + def write_file(path: str, data: bytes) -> None: + with open(path, 'wb') as file: + file.write(data) + + @staticmethod + def ensure_exists(paths: list): + for path in paths: + if not os.path.exists(path): + print(f"[!] Не найден файл: {path}") + exit(1) \ No newline at end of file diff --git a/lab_3/helpers.py b/lab_3/helpers.py new file mode 100644 index 000000000..5e4d25b05 --- /dev/null +++ b/lab_3/helpers.py @@ -0,0 +1,22 @@ +import argparse +import json + + +class AppTools: + @staticmethod + def load_config() -> dict: + try: + with open('settings.json', 'r') as file: + return json.load(file) + except FileNotFoundError: + print("[!] Файл settings.json не найден.") + exit(1) + + @staticmethod + def get_args(): + parser = argparse.ArgumentParser(description="Гибридная криптосистема") + mode = parser.add_mutually_exclusive_group(required=True) + mode.add_argument('-gen', '--create_keys', action='store_true', help='Создание ключей') + mode.add_argument('-enc', '--encrypt', action='store_true', help='Шифрование') + mode.add_argument('-dec', '--decrypt', action='store_true', help='Дешифрование') + return parser.parse_args() \ No newline at end of file diff --git a/lab_3/main.py b/lab_3/main.py new file mode 100644 index 000000000..bd8b02a18 --- /dev/null +++ b/lab_3/main.py @@ -0,0 +1,63 @@ +from helpers import AppTools +from file_utils import FileManager +from asymmetric_cipher import AsymmetricCipher +from symmetric_cipher import SymmetricCipher +import os + + +def create_keys(config): + print("[*] Генерация ключей...") + sym_key = os.urandom(16) + + priv_key, pub_key = AsymmetricCipher.generate_rsa_keypair() + encrypted_sym_key = AsymmetricCipher.encrypt(sym_key, pub_key) + + FileManager.write_file("rsa_pub_key.txt", AsymmetricCipher.serialize_public_key(pub_key)) + FileManager.write_file("rsa_private_key.txt", AsymmetricCipher.serialize_private_key(priv_key)) + FileManager.write_file(config['encoded_sym_key'], encrypted_sym_key) + + print("[+] Ключи успешно созданы.") + + +def encrypt_data(config): + print("[*] Загрузка данных для шифрования...") + FileManager.ensure_exists([config['rsa_private'], config['encoded_sym_key'], config['plain_data']]) + + private_key = AsymmetricCipher.load_private_key(FileManager.read_file(config['rsa_private'])) + sym_key = AsymmetricCipher.decrypt(FileManager.read_file(config['encoded_sym_key']), private_key) + plaintext = FileManager.read_file(config['plain_data']) + + encrypted = SymmetricCipher.encrypt(plaintext, sym_key) + FileManager.write_file(config['encrypted_data'], encrypted) + + print("[+] Данные зашифрованы.") + + +def decrypt_data(config): + print("[*] Загрузка данных для дешифровки...") + FileManager.ensure_exists([config['rsa_private'], config['encoded_sym_key'], config['encrypted_data']]) + + private_key = AsymmetricCipher.load_private_key(FileManager.read_file(config['rsa_private'])) + sym_key = AsymmetricCipher.decrypt(FileManager.read_file(config['encoded_sym_key']), private_key) + encrypted_data = FileManager.read_file(config['encrypted_data']) + + decrypted = SymmetricCipher.decrypt(encrypted_data, sym_key) + FileManager.write_file(config['decrypted_output'], decrypted) + + print("[+] Данные расшифрованы.") + + +def main(): + args = AppTools.get_args() + config = AppTools.load_config() + + if args.create_keys: + create_keys(config) + elif args.encrypt: + encrypt_data(config) + elif args.decrypt: + decrypt_data(config) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/lab_3/output.txt b/lab_3/output.txt new file mode 100644 index 000000000..ddbf13c3d --- /dev/null +++ b/lab_3/output.txt @@ -0,0 +1,99 @@ +Вы помните, +Вы всё, конечно, помните, +Как я стоял, +Приблизившись к стене, +Взволнованно ходили вы по комнате +И что-то резкое +В лицо бросали мне. +Вы говорили: +Нам пора расстаться, +Что вас измучила +Моя шальная жизнь, +Что вам пора за дело приниматься, +А мой удел — +Катиться дальше, вниз. +Любимая! +Меня вы не любили. +Не знали вы, что в сонмище людском +Я был как лошадь, загнанная в мыле, +Пришпоренная смелым ездоком. +Не знали вы, +Что я в сплошном дыму, +В развороченном бурей быте +С того и мучаюсь, что не пойму — +Куда несет нас рок событий. +Лицом к лицу +Лица не увидать. +Большое видится на расстоянье. +Когда кипит морская гладь — +Корабль в плачевном состоянье. +Земля — корабль! +Но кто-то вдруг +За новой жизнью, новой славой +В прямую гущу бурь и вьюг +Ее направил величаво. +Ну кто ж из нас на палубе большой +Не падал, не блевал и не ругался? +Их мало, с опытной душой, +Кто крепким в качке оставался. +Тогда и я, +Под дикий шум, +Но зрело знающий работу, +Спустился в корабельный трюм, +Чтоб не смотреть людскую рвоту. +Тот трюм был — +Русским кабаком. +И я склонился над стаканом, +Чтоб, не страдая ни о ком, +Себя сгубить +В угаре пьяном. +Любимая! +Я мучил вас, +У вас была тоска +В глазах усталых: +Что я пред вами напоказ +Себя растрачивал в скандалах. +Но вы не знали, +Что в сплошном дыму, +В развороченном бурей быте +С того и мучаюсь, +Что не пойму, +Куда несет нас рок событий… +Теперь года прошли. +Я в возрасте ином. +И чувствую и мыслю по-иному. +И говорю за праздничным вином: +Хвала и слава рулевому! +Сегодня я +В ударе нежных чувств. +Я вспомнил вашу грустную усталость. +И вот теперь +Я сообщить вам мчусь, +Каков я был, +И что со мною сталось! +Любимая! +Сказать приятно мне: +Я избежал паденья с кручи. +Теперь в Советской стороне +Я самый яростный попутчик. +Я стал не тем, +Кем был тогда. +Не мучил бы я вас, +Как это было раньше. +За знамя вольности +И светлого труда +Готов идти хоть до Ла-Манша. +Простите мне… +Я знаю: вы не та — +Живете вы +С серьезным, умным мужем; +Что не нужна вам наша маета, +И сам я вам +Ни капельки не нужен. +Живите так, +Как вас ведет звезда, +Под кущей обновленной сени. +С приветствием, +Вас помнящий всегда +Знакомый ваш +Сергей Есенин. \ No newline at end of file diff --git a/lab_3/rsa_private_key.txt b/lab_3/rsa_private_key.txt new file mode 100644 index 000000000..d88fdea17 --- /dev/null +++ b/lab_3/rsa_private_key.txt @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAuC0NCuHTX6yzAx4bmgqw9GSh8bGFzz5FcOEJ6tLI0GEzd2G1 +K+DGwUFqlh4V/r2uMD+zuXT0LGiLn94R5wv7ClMlnhtzfJx+b8sX2tcZXb829WW3 +dCxjoLh3rjLlAfLS9RKrm9vqOmw0+fKFvujiv7j2dJhvRzyGYCqUvGMNTN2QWKCJ +ab75d4fVgAnDxYP5LKRSsqL5a6PltZFXSoF8WW3jOpFrk1lGnTYCaCJLudZUtW6/ +20jRrlBtfyWxxC12cHEmGLflEkC9RDQ7ebr1NoRw8toA6EijPZknKimMjPchb+KM +CClPHk2V9oCgmlwhRBfmyasTeD8oq/5Efkb7uwIDAQABAoIBAAXGx/Nw7MfB62Vs +ItJ8hltL8rZZaoh6/AOT01NNpCXA/rO+WUfUh3dVPWoS7H6uZVG3FcR50hS4fLSZ +avdTrV6ACByC4ObmI6MO/CMNfwqtLiSZOZ1HrSJD1uEcUIl0m8A7Ay3iwmBtt2Wl +gSNhO4dm3jf+9fKGh/JpM3wLIUYpWTg0eq7xTtyPqBIXCC1a53hZ8S2zc6Q1XSWf +h8idVrhDgTfd5mSGRp6+IPCKDaAuOI4DFNiCRpBN0lIcapWIIpH+EzWtj2k6GxPO +cF973o9cf2+GEkzCRMfQWKVuLLdbN9G0FTTskikA1cEkDhnLdFM7qrNyXtTKuotE +2AfuSA0CgYEA2aD4tMMp9ljdsWS+HnomjQFW7+OrvT1k9/RJwjZAaDnnysCvVhyN +5SYsklDPwKAlBewfbZGIZKRLFTdiuIKw3dHN+Vh3F0mKxBHQg7KKNS3hpoSrR8I5 +vdI9Yp0GtBszdWUytt83/XbpbPi+L+eIis+e4DE1fi8bOYpauYSnI10CgYEA2KYh +5ckFAGVnPpqRC679a8OBgP4W44w2qiEYFJgRlfKJFkAUfedMg8ZHMF2wzXQBjAhv +yGggEQ21jxaJiNyEPi9W3dInYsPZ/bD8gstVHIqHKtMf3Loh4luWfsWzjBhZmd48 +pAbIdUOh1ut5rS7teljTNCoawYp0yJXaLifagfcCgYBRcLDBjGtOmfDUapvO8e0t +RTwQZ4WkOq5nL87OU9kEZ+766+JxehwLjZ6OXplwPz27mqIkMZr19pl2ZhSWcanY +SKQo1Fc0qru4JeZ+8jhQMExKMUmbf+51v5BjL9oLWkaGfwlcb+oW+wHdWrRpXt60 ++3877I5VGzG39bN/y0l0rQKBgQDGVPBbR/eIMUyfBykZpQzihowb5oBVt5qjjMBa +ugv/VZUiBW+9Au4NBItPP7YHn9d6to5+zLPuaLp5T4yA+j8mHnhLgYQE6n65vDiu +FC7KfhbXoYddrhgu/OF9FMgVzITaU5T4JC2HDG8wLUmqvXcxtfdDnff4jiPzLRwb +fOiQaQKBgGJhaJOuZhas+e7kfCvLiLRDNc7sCRwuE82d5b+poftNgnXBHfqJ/rHR +wykhQvXm5kik9AZYXnVJIYHOW46xGTJtzRVyvJimJRz36/AalVcILVH9RtRFrezI +SsLiJatK6yoT+Nb2LsPWwqIqi1kdVl4egobiWYvmW1Fy53VAQAYk +-----END RSA PRIVATE KEY----- diff --git a/lab_3/rsa_pub_key.txt b/lab_3/rsa_pub_key.txt new file mode 100644 index 000000000..8aeed6c60 --- /dev/null +++ b/lab_3/rsa_pub_key.txt @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuC0NCuHTX6yzAx4bmgqw +9GSh8bGFzz5FcOEJ6tLI0GEzd2G1K+DGwUFqlh4V/r2uMD+zuXT0LGiLn94R5wv7 +ClMlnhtzfJx+b8sX2tcZXb829WW3dCxjoLh3rjLlAfLS9RKrm9vqOmw0+fKFvuji +v7j2dJhvRzyGYCqUvGMNTN2QWKCJab75d4fVgAnDxYP5LKRSsqL5a6PltZFXSoF8 +WW3jOpFrk1lGnTYCaCJLudZUtW6/20jRrlBtfyWxxC12cHEmGLflEkC9RDQ7ebr1 +NoRw8toA6EijPZknKimMjPchb+KMCClPHk2V9oCgmlwhRBfmyasTeD8oq/5Efkb7 +uwIDAQAB +-----END PUBLIC KEY----- diff --git a/lab_3/settings.json b/lab_3/settings.json index 904699d45..8fb8a0b4d 100644 --- a/lab_3/settings.json +++ b/lab_3/settings.json @@ -1,8 +1,7 @@ { - "initial_file": "text.txt", - "encrypted_file": "encrypted_text.txt", - "decrypted_file": "decrypted_text.txt", - "symmetric_key": "symmetric_key.txt", - "public_key": "public_key.txt", - "secret_key": "secret_key.txt" + "encoded_sym_key": "encrypted_key.txt", + "rsa_private": "rsa_private_key.txt", + "plain_data": "data.txt", + "encrypted_data": "encrypted_data.txt", + "decrypted_output": "output.txt" } \ No newline at end of file diff --git a/lab_3/symmetric_cipher.py b/lab_3/symmetric_cipher.py new file mode 100644 index 000000000..8a6f61131 --- /dev/null +++ b/lab_3/symmetric_cipher.py @@ -0,0 +1,23 @@ +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.primitives import padding as sym_pad +import os + + +class SymmetricCipher: + @staticmethod + def encrypt(data: bytes, key: bytes) -> bytes: + padder = sym_pad.ANSIX923(128).padder() + padded = padder.update(data) + padder.finalize() + iv = os.urandom(16) + cipher = Cipher(algorithms.SEED(key), modes.CBC(iv)) + encrypted = cipher.encryptor().update(padded) + cipher.encryptor().finalize() + return iv + encrypted + + @staticmethod + def decrypt(encrypted_data: bytes, key: bytes) -> bytes: + iv = encrypted_data[:16] + content = encrypted_data[16:] + cipher = Cipher(algorithms.SEED(key), modes.CBC(iv)) + decrypted_padded = cipher.decryptor().update(content) + cipher.decryptor().finalize() + unpadder = sym_pad.ANSIX923(128).unpadder() + return unpadder.update(decrypted_padded) + unpadder.finalize() \ No newline at end of file diff --git a/lab_3/utils.py b/lab_3/utils.py deleted file mode 100644 index 7f9fec00a..000000000 --- a/lab_3/utils.py +++ /dev/null @@ -1,26 +0,0 @@ -import json -import argparse - - -def load_settings() -> dict: - """ - Loads the settings from a JSON configuration file. - - :return: Dictionary containing configuration settings. - :raises SystemExit: If the settings.json file is not found. - """ - try: - with open("settings.json") as file: - return json.load(file) - except FileNotFoundError: - print("[!] File settings.json is not found.") - exit(1) - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser(description="Hybrid cryptosystem") - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument("-gen", "--generation", action="store_true", help="Key generation") - group.add_argument("-enc", "--encryption", action="store_true", help="Data encryption") - group.add_argument("-dec", "--decryption", action="store_true", help="Data decryption") - return parser.parse_args() \ No newline at end of file From 05120d4767e896154fa09dccd6c8e794e0be772e Mon Sep 17 00:00:00 2001 From: student Date: Mon, 9 Jun 2025 16:18:51 +0400 Subject: [PATCH 9/9] Did lab3 --- lab_3/asymmetric_cipher.py | 109 ++++++++++++++++++++++++++----------- lab_3/encrypted_data.txt | Bin 3904 -> 3904 bytes lab_3/encrypted_key.txt | Bin 256 -> 256 bytes lab_3/file_utils.py | 48 +++++++++++----- lab_3/helpers.py | 44 +++++++++------ lab_3/main.py | 90 ++++++++++++++++++------------ lab_3/rsa_private_key.txt | 50 ++++++++--------- lab_3/rsa_pub_key.txt | 14 ++--- lab_3/symmetric_cipher.py | 59 ++++++++++++++------ 9 files changed, 266 insertions(+), 148 deletions(-) diff --git a/lab_3/asymmetric_cipher.py b/lab_3/asymmetric_cipher.py index 2d1f5f063..1b44869c4 100644 --- a/lab_3/asymmetric_cipher.py +++ b/lab_3/asymmetric_cipher.py @@ -1,45 +1,88 @@ import os +from typing import Tuple from cryptography.hazmat.primitives.asymmetric import rsa, padding +from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey, RSAPrivateKey from cryptography.hazmat.primitives import serialization, hashes -class AsymmetricCipher: - @staticmethod - def generate_rsa_keypair() -> tuple: - private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) - return private_key, private_key.public_key() +def generate_rsa_keypair() -> Tuple[RSAPrivateKey, RSAPublicKey]: + """ + Generates a new RSA private-public key pair. - @staticmethod - def encrypt(key: bytes, public_key) -> bytes: - return public_key.encrypt( - key, - padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), - algorithm=hashes.SHA256(), label=None) - ) + :returns: A tuple containing the RSA private key and corresponding public key. + """ + private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) + return private_key, private_key.public_key() - @staticmethod - def decrypt(encrypted_key: bytes, private_key) -> bytes: - return private_key.decrypt( - encrypted_key, - padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), - algorithm=hashes.SHA256(), label=None) - ) - @staticmethod - def serialize_public_key(public_key) -> bytes: - return public_key.public_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PublicFormat.SubjectPublicKeyInfo +def encrypt(key: bytes, public_key: RSAPublicKey) -> bytes: + """ + Encrypts data using the given RSA public key with OAEP padding. + + :param key: Symmetric key or data to encrypt. + :param public_key: RSA public key used for encryption. + :returns: Encrypted data as bytes. + """ + return public_key.encrypt( + key, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), + label=None ) + ) + - @staticmethod - def serialize_private_key(private_key) -> bytes: - return private_key.private_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PrivateFormat.TraditionalOpenSSL, - encryption_algorithm=serialization.NoEncryption() +def decrypt(encrypted_key: bytes, private_key: RSAPrivateKey) -> bytes: + """ + Decrypts data using the given RSA private key with OAEP padding. + + :param encrypted_key: Encrypted data to decrypt. + :param private_key: RSA private key used for decryption. + :returns: Decrypted data as bytes. + """ + return private_key.decrypt( + encrypted_key, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), + label=None ) + ) + + +def serialize_public_key(public_key: RSAPublicKey) -> bytes: + """ + Serializes an RSA public key to PEM format. + + :param public_key: RSA public key to serialize. + :returns: Serialized public key in PEM format. + """ + return public_key.public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo + ) + + +def serialize_private_key(private_key: RSAPrivateKey) -> bytes: + """ + Serializes an RSA private key to PEM format without encryption. + + :param private_key: RSA private key to serialize. + :returns: Serialized private key in PEM format. + """ + return private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption() + ) + + +def load_private_key(data: bytes) -> RSAPrivateKey: + """ + Loads an RSA private key from PEM-encoded data. - @staticmethod - def load_private_key(data: bytes): - return serialization.load_pem_private_key(data, password=None) \ No newline at end of file + :param data: PEM-encoded private key bytes. + :returns: Deserialized RSA private key object. + """ + return serialization.load_pem_private_key(data, password=None) \ No newline at end of file diff --git a/lab_3/encrypted_data.txt b/lab_3/encrypted_data.txt index 1c3568bbf7057296b75080a4953b8d062e3b05fb..ae99d7e5e1908cfdd157378425e7231f62127b02 100644 GIT binary patch literal 3904 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 O`}_SozM?fh`9IPBeXKM9 literal 3904 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 GUYhRqB-h`E zaqajo5_J}aEV&Nt@EuVM>ovMRMRVApUA!CHaNG{Jat|+{k^J%pVH3jO<&#B~#SM&p z7!}|h@Mp`F?(*c^5heC-&v8?Sv_%Ooh(_Cr>h)NPkQ){n$L$V@<8?+sx>|-u6Ev;b zu5xyEm!3lY&e*|0ZH`~CvvQj6dZr bytes: - with open(path, 'rb') as file: - return file.read() +def read_file(path: str) -> bytes: + """ + Reads binary data from the specified file path. - @staticmethod - def write_file(path: str, data: bytes) -> None: - with open(path, 'wb') as file: - file.write(data) + :param path: Path to the file to be read. + :returns: Contents of the file as bytes. + """ + with open(path, 'rb') as file: + return file.read() - @staticmethod - def ensure_exists(paths: list): - for path in paths: - if not os.path.exists(path): - print(f"[!] Не найден файл: {path}") - exit(1) \ No newline at end of file + +def write_file(path: str, data: bytes) -> None: + """ + Writes binary data to the specified file path. + + :param path: Path to the file where data should be written. + :param data: Data to write to the file. + """ + with open(path, 'wb') as file: + file.write(data) + + +def ensure_exists(paths: List[str]) -> None: + """ + Checks whether all specified file paths exist. + Terminates the program if any of the files is missing. + + :param paths: List of file paths to check. + :raises SystemExit: If any file does not exist. + """ + for path in paths: + if not os.path.exists(path): + print(f"[!] File not found: {path}") + exit(1) \ No newline at end of file diff --git a/lab_3/helpers.py b/lab_3/helpers.py index 5e4d25b05..fa63930b7 100644 --- a/lab_3/helpers.py +++ b/lab_3/helpers.py @@ -1,22 +1,32 @@ import argparse import json +from typing import Any, Dict -class AppTools: - @staticmethod - def load_config() -> dict: - try: - with open('settings.json', 'r') as file: - return json.load(file) - except FileNotFoundError: - print("[!] Файл settings.json не найден.") - exit(1) +def load_config() -> Dict[str, Any]: + """ + Loads configuration settings from the 'settings.json' file. - @staticmethod - def get_args(): - parser = argparse.ArgumentParser(description="Гибридная криптосистема") - mode = parser.add_mutually_exclusive_group(required=True) - mode.add_argument('-gen', '--create_keys', action='store_true', help='Создание ключей') - mode.add_argument('-enc', '--encrypt', action='store_true', help='Шифрование') - mode.add_argument('-dec', '--decrypt', action='store_true', help='Дешифрование') - return parser.parse_args() \ No newline at end of file + :returns: A dictionary containing configuration settings. + :raises SystemExit: If the file 'settings.json' is not found. + """ + try: + with open('settings.json', 'r') as file: + return json.load(file) + except FileNotFoundError: + print("[!] settings.json file not found.") + exit(1) + + +def get_args() -> argparse.Namespace: + """ + Parses command-line arguments for hybrid cryptosystem operations. + + :returns: Parsed command-line arguments as a namespace object. + """ + parser = argparse.ArgumentParser(description="Hybrid Cryptosystem") + mode = parser.add_mutually_exclusive_group(required=True) + mode.add_argument('-gen', '--create_keys', action='store_true', help='Generate keys') + mode.add_argument('-enc', '--encrypt', action='store_true', help='Encrypt data') + mode.add_argument('-dec', '--decrypt', action='store_true', help='Decrypt data') + return parser.parse_args() \ No newline at end of file diff --git a/lab_3/main.py b/lab_3/main.py index bd8b02a18..912b195f2 100644 --- a/lab_3/main.py +++ b/lab_3/main.py @@ -1,55 +1,77 @@ -from helpers import AppTools -from file_utils import FileManager -from asymmetric_cipher import AsymmetricCipher -from symmetric_cipher import SymmetricCipher +import helpers +import file_utils +import asymmetric_cipher +import symmetric_cipher import os +from typing import Dict, Any -def create_keys(config): - print("[*] Генерация ключей...") - sym_key = os.urandom(16) +def create_keys(config: Dict[str, Any]) -> None: + """ + Generates a symmetric AES key and an RSA key pair, encrypts the symmetric key + with the RSA public key, and saves all keys to files. - priv_key, pub_key = AsymmetricCipher.generate_rsa_keypair() - encrypted_sym_key = AsymmetricCipher.encrypt(sym_key, pub_key) + :param config: Configuration dictionary containing the path to store the encrypted symmetric key. + """ + print("[*] Generating keys...") + sym_key = os.urandom(16) + priv_key, pub_key = asymmetric_cipher.generate_rsa_keypair() + encrypted_sym_key = asymmetric_cipher.encrypt(sym_key, pub_key) - FileManager.write_file("rsa_pub_key.txt", AsymmetricCipher.serialize_public_key(pub_key)) - FileManager.write_file("rsa_private_key.txt", AsymmetricCipher.serialize_private_key(priv_key)) - FileManager.write_file(config['encoded_sym_key'], encrypted_sym_key) + file_utils.write_file("rsa_pub_key.txt", asymmetric_cipher.serialize_public_key(pub_key)) + file_utils.write_file("rsa_private_key.txt", asymmetric_cipher.serialize_private_key(priv_key)) + file_utils.write_file(config['encoded_sym_key'], encrypted_sym_key) - print("[+] Ключи успешно созданы.") + print("[+] Keys successfully generated.") -def encrypt_data(config): - print("[*] Загрузка данных для шифрования...") - FileManager.ensure_exists([config['rsa_private'], config['encoded_sym_key'], config['plain_data']]) +def encrypt_data(config: Dict[str, Any]) -> None: + """ + Encrypts plaintext data using a symmetric key that is decrypted from a previously + RSA-encrypted file. Saves the encrypted result to a file. - private_key = AsymmetricCipher.load_private_key(FileManager.read_file(config['rsa_private'])) - sym_key = AsymmetricCipher.decrypt(FileManager.read_file(config['encoded_sym_key']), private_key) - plaintext = FileManager.read_file(config['plain_data']) + :param config: Configuration dictionary containing paths to the RSA private key, + encrypted symmetric key, plaintext input, and encrypted output. + """ + print("[*] Loading data for encryption...") + file_utils.ensure_exists([config['rsa_private'], config['encoded_sym_key'], config['plain_data']]) - encrypted = SymmetricCipher.encrypt(plaintext, sym_key) - FileManager.write_file(config['encrypted_data'], encrypted) + private_key = asymmetric_cipher.load_private_key(file_utils.read_file(config['rsa_private'])) + sym_key = asymmetric_cipher.decrypt(file_utils.read_file(config['encoded_sym_key']), private_key) + plaintext = file_utils.read_file(config['plain_data']) + encrypted = symmetric_cipher.encrypt(plaintext, sym_key) - print("[+] Данные зашифрованы.") + file_utils.write_file(config['encrypted_data'], encrypted) + print("[+] Data encrypted successfully.") -def decrypt_data(config): - print("[*] Загрузка данных для дешифровки...") - FileManager.ensure_exists([config['rsa_private'], config['encoded_sym_key'], config['encrypted_data']]) +def decrypt_data(config: Dict[str, Any]) -> None: + """ + Decrypts encrypted data using a symmetric key that is decrypted from a file + encrypted with RSA. Saves the decrypted output to a file. - private_key = AsymmetricCipher.load_private_key(FileManager.read_file(config['rsa_private'])) - sym_key = AsymmetricCipher.decrypt(FileManager.read_file(config['encoded_sym_key']), private_key) - encrypted_data = FileManager.read_file(config['encrypted_data']) + :param config: Configuration dictionary containing paths to the RSA private key, + encrypted symmetric key, encrypted input, and decrypted output. + """ + print("[*] Loading data for decryption...") + file_utils.ensure_exists([config['rsa_private'], config['encoded_sym_key'], config['encrypted_data']]) - decrypted = SymmetricCipher.decrypt(encrypted_data, sym_key) - FileManager.write_file(config['decrypted_output'], decrypted) + private_key = asymmetric_cipher.load_private_key(file_utils.read_file(config['rsa_private'])) + sym_key = asymmetric_cipher.decrypt(file_utils.read_file(config['encoded_sym_key']), private_key) + encrypted_data = file_utils.read_file(config['encrypted_data']) + decrypted = symmetric_cipher.decrypt(encrypted_data, sym_key) - print("[+] Данные расшифрованы.") + file_utils.write_file(config['decrypted_output'], decrypted) + print("[+] Data decrypted successfully.") -def main(): - args = AppTools.get_args() - config = AppTools.load_config() +def main() -> None: + """ + Parses command-line arguments and performs the selected action: + key generation, encryption, or decryption. + """ + args = helpers.get_args() + config = helpers.load_config() if args.create_keys: create_keys(config) diff --git a/lab_3/rsa_private_key.txt b/lab_3/rsa_private_key.txt index d88fdea17..b09a83ddc 100644 --- a/lab_3/rsa_private_key.txt +++ b/lab_3/rsa_private_key.txt @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/lab_3/rsa_pub_key.txt b/lab_3/rsa_pub_key.txt index 8aeed6c60..607275f5d 100644 --- a/lab_3/rsa_pub_key.txt +++ b/lab_3/rsa_pub_key.txt @@ -1,9 +1,9 @@ -----BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuC0NCuHTX6yzAx4bmgqw -9GSh8bGFzz5FcOEJ6tLI0GEzd2G1K+DGwUFqlh4V/r2uMD+zuXT0LGiLn94R5wv7 -ClMlnhtzfJx+b8sX2tcZXb829WW3dCxjoLh3rjLlAfLS9RKrm9vqOmw0+fKFvuji -v7j2dJhvRzyGYCqUvGMNTN2QWKCJab75d4fVgAnDxYP5LKRSsqL5a6PltZFXSoF8 -WW3jOpFrk1lGnTYCaCJLudZUtW6/20jRrlBtfyWxxC12cHEmGLflEkC9RDQ7ebr1 -NoRw8toA6EijPZknKimMjPchb+KMCClPHk2V9oCgmlwhRBfmyasTeD8oq/5Efkb7 -uwIDAQAB +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqu7SPXGk36KgM4kKtwhK +CyDZINa7uHZuAmQcNF/NlnFU9/o3liuseD0LbgAbXhp85lQHaP0rjsSI9cT0mFmM +SpHWeWccZsIPvnSZrGi214zDY9z3lQSnEtF5j1g+CdGr/VCF/UnCLqN4mZbeeM4t +1r1XNV1Xd/JJdhFd/ThbFWF0MicnsTPoLfEQXDE6hZtxh67xC5wE+qqGRrPEjdbn +SZG0E4/ThSSiXv0omHlTm9xg5vBr9+/jeWz2JAJw1TphYSQVB0SogSXQvYBoZjPT +4xMu3GrTGMmCHeSlqBKNU9L9ENeDGP6N9hsxGnvexrKjl4Vg8HYqQU5/WgV+EJrR +RwIDAQAB -----END PUBLIC KEY----- diff --git a/lab_3/symmetric_cipher.py b/lab_3/symmetric_cipher.py index 8a6f61131..10f01c77d 100644 --- a/lab_3/symmetric_cipher.py +++ b/lab_3/symmetric_cipher.py @@ -3,21 +3,46 @@ import os -class SymmetricCipher: - @staticmethod - def encrypt(data: bytes, key: bytes) -> bytes: - padder = sym_pad.ANSIX923(128).padder() - padded = padder.update(data) + padder.finalize() - iv = os.urandom(16) - cipher = Cipher(algorithms.SEED(key), modes.CBC(iv)) - encrypted = cipher.encryptor().update(padded) + cipher.encryptor().finalize() - return iv + encrypted +def encrypt(data: bytes, key: bytes) -> bytes: + """Encrypt data using SEED algorithm in CBC mode with ANSIX923 padding. - @staticmethod - def decrypt(encrypted_data: bytes, key: bytes) -> bytes: - iv = encrypted_data[:16] - content = encrypted_data[16:] - cipher = Cipher(algorithms.SEED(key), modes.CBC(iv)) - decrypted_padded = cipher.decryptor().update(content) + cipher.decryptor().finalize() - unpadder = sym_pad.ANSIX923(128).unpadder() - return unpadder.update(decrypted_padded) + unpadder.finalize() \ No newline at end of file + :param data: Raw bytes to be encrypted. Length must be compatible with padding + :param key: Encryption key (16 bytes for SEED-128, 32 bytes for SEED-256) + :return: Encrypted data in format: IV (16 bytes) + ciphertext + :raises ValueError: If key length is invalid for SEED algorithm + :raises TypeError: If input data is not bytes + """ + if len(key) not in {16, 32}: + raise ValueError("SEED key must be 16 or 32 bytes long") + + padder = sym_pad.ANSIX923(128).padder() + padded = padder.update(data) + padder.finalize() + iv = os.urandom(16) + cipher = Cipher(algorithms.SEED(key), modes.CBC(iv)) + encryptor = cipher.encryptor() + encrypted = encryptor.update(padded) + encryptor.finalize() + return iv + encrypted + + +def decrypt(encrypted_data: bytes, key: bytes) -> bytes: + """Decrypt data encrypted with SEED-CBC-ANSIX923. + + :param encrypted_data: Encrypted data in format: IV (16 bytes) + ciphertext + :param key: Decryption key (same as used for encryption) + :return: Original decrypted data + :raises ValueError: If key is invalid or encrypted_data is too short + :raises TypeError: If inputs are not bytes + :raises PaddingError: If padding is corrupted + """ + if len(encrypted_data) < 16: + raise ValueError("Encrypted data must contain at least 16 bytes (IV)") + if len(key) not in {16, 32}: + raise ValueError("SEED key must be 16 or 32 bytes long") + + iv = encrypted_data[:16] + content = encrypted_data[16:] + cipher = Cipher(algorithms.SEED(key), modes.CBC(iv)) + decryptor = cipher.decryptor() + decrypted_padded = decryptor.update(content) + decryptor.finalize() + unpadder = sym_pad.ANSIX923(128).unpadder() + return unpadder.update(decrypted_padded) + unpadder.finalize() \ No newline at end of file