diff --git a/.coverage b/.coverage new file mode 100644 index 0000000..3aee33c Binary files /dev/null and b/.coverage differ diff --git a/.github/workflows/tests_git.yml b/.github/workflows/tests_git.yml new file mode 100644 index 0000000..3364128 --- /dev/null +++ b/.github/workflows/tests_git.yml @@ -0,0 +1,75 @@ +name: Python CI + +on: + push: + branches: [development] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.x' + + - name: Install dependencies + run: | + pip install -r requirements.txt + pip install flake8 flake8-html pytest-html + + - name: Run tests + run: | + mkdir -p reports/coverage reports/flake8 reports/junit + python -m pytest --cov=src tests/ --cov-report term --junitxml=reports/junit/junit.xml --html=reports/junit/index.html + coverage report + coverage xml -o reports/coverage/coverage.xml + coverage html -d reports/coverage + flake8 src --exit-zero --format=html --htmldir reports/flake8 --statistics --tee --output-file reports/flake8/flake8stats.txt + - name: Upload reports + uses: actions/upload-artifact@v4 + with: + name: reports + path: reports + update-badges: + needs: build + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout gh-pages + uses: actions/checkout@v4 + with: + ref: gh-pages + - name: Setup python + uses: actions/setup-python@v4 + with: + python-version: '3.x' + - name: Download reports + uses: actions/download-artifact@v4 + with: + name: reports + path: reports + - name: Create badges + run: | + pip install genbadge[all] + genbadge tests -o badges/tests.svg + genbadge coverage -o badges/coverage.svg + genbadge flake8 -o badges/flake8.svg + - name: Deploy badges + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: 'Update badges' + branch: gh-pages + file_pattern: 'badges/* reports/*' + skip_fetch: true + skip_checkout: true + - name: Checkout back + uses: actions/checkout@v4 + with: + ref: ${{ github.ref }} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2e11572 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# Python +__pycache__/ +*.pyc + +# Virtual environment +venv/ + +# IDE +.idea/ diff --git a/Main.py b/Main.py new file mode 100644 index 0000000..a7f6860 --- /dev/null +++ b/Main.py @@ -0,0 +1,31 @@ +from src.FileHandler import * +from src.CesarStatisticsDecipher import * +import argparse + + +def parse_arguments(): + parser = argparse.ArgumentParser(description='Encryption and decryption program') + parser.add_argument('-e', '--encrypt', action='store_true', help='Encrypt data') + parser.add_argument('-d', '--decrypt', action='store_true', help='Decrypt data') + parser.add_argument('-a', '--algorithm', choices=['caesar', 'vernam', 'vigenere', 'statistical_caesar'], + help='Encryption/Decryption algorithm') + parser.add_argument('-i', '--input_file', help='Input file') + parser.add_argument('-l', '--lang', choices=['rus', 'eng'], help='Language') + parser.add_argument('-k', '--key', default='', help='shift for cesar / key for vernam or vigenere / nothing for ' + 'statistical_caesar') + return parser.parse_args() + + +def main(): + args = parse_arguments() + file_handler = FileHandler() + if args.encrypt: + file_handler.encrypt_file(args.input_file, args.algorithm, args.lang, args.key) + elif args.decrypt: + file_handler.decrypt_file(args.input_file, args.algorithm, args.lang, args.key) + else: + print('Please specify whether you want to encrypt (-e) or decrypt (-d) the data.') + + +if __name__ == "__main__": + main() diff --git a/README.md b/README.md index 59cb97f..dc42abb 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +[![Python CI](https://github.com/kirillzol/Python-encryption/actions/workflows/tests_git.yml/badge.svg)](https://github.com/kirillzol/Python-encryption/actions/workflows/tests_git.yml) +[![tests](https://kirillzol.github.io/Python-encryption/badges/tests.svg)](https://kirillzol.github.io/Python-encryption/reports/junit/index.html) +[![cov](https://kirillzol.github.io/Python-encryption/badges/coverage.svg)](https://kirillzol.github.io/Python-encryption/reports/coverage/index.html) +[![flake8](https://kirillzol.github.io/Python-encryption/badges/flake8.svg)](https://kirillzol.github.io/Python-encryption/reports/flake8/index.html) + # Python-encryption ## Описание проекта @@ -25,9 +30,7 @@ - Cipher.py - содержит в себе 3 класса, внутри которых реализуются 3 основных алгоритма проекта. Класс для алгоритма Цезаря: имееет 2 атрибута - русский и английски алфавиты, а также функции кодирования и декодирования текстового файла по алфавиту и сдвигу. Класс для шифра Виженера - имеет функцию генерации ключа: она генерирует ключ циклически, пока его длина не станет равна длине исходного текста, а также функции кодирования и декодирования текстового файла по ключу. И наконец класс для шифра Вернама: функция генерации ключа: Создается случайная последовательность битов, которая должна быть такой же длины, как и текст, а также функции кодирования и декодирования текстового файла по ключу. -- CesarStatisticsDecipher.py - файл, в котором содержится класс CesarStatisticsDecipher - имеет атрибуты: русский и английски алфавиты, а так же статистические данные по каждому из языков. Метод collect_statistics_from_text возвращает статистические данные по тексту. find_opt_step находит статистически оптимальный сдвиг, сопоставляя данные по тексту и по языку. После чего вызывается decrypt из CesarCipher. - -- Steganography.py - содержит класс Steganography: generate_data - преобразует данные в бинарный формат (8-битный ASCII код каждого символа) и возвращает список бинарных кодов. modify_pixels - модифицирует пиксели изображения в соответствии с бинарными данными. Каждый бит данных встраивается в младший бит каждого компонента цвета RGB. encrypt - кодирует изображение. Она принимает объект изображения и данные, которые нужно внедрить. Затем она вызывает функцию modPix для модификации пикселей изображения. decrypt() - Функция для декодирования данных из изображения. +- CesarStatisticsDecipher.py - файл, в котором содержится класс CesarStatisticsDecipher - имеет атрибуты: русский и английски алфавиты, а так же статистические данные по каждому из языков. Метод collect_statistics_from_text возвращает статистические данные по тексту. find_opt_step находит статистически оптимальный сдвиг при помощи , сопоставляя данные по тексту и по языку. После чего вызывается decrypt из CesarCipher. - FileHandler.py содержит класс FileHandler, который отвечает за обработку файлов в проекте: read_file, generate_file - для чтения и записи файлов. Также этот класс содержит методы для обработки файлов, используемых в процессе шифрования и дешифрования: encrypt_file, decrypt_file. @@ -65,13 +68,6 @@ └── def __init__(self, text) └── def collect_statistics_from_text(text) └── def find_opt_step(text, alfavit, statistics_data_text, statistics_data_lang) -├── Steganography.py - └── class Steganography - └── def __init__(self, path) - └── def generate_data(path) - └── def modify_pixels(pix, data) - └── def encrypt(img, data) - └── def decrypt() ├── FileHandler.py └── class FileHandler └── def __init__(self, file_path): @@ -79,17 +75,56 @@ └── def generate_file(self, data) └── def encrypt_file(self, cipher) └── def decrypt_file(self, cipher) -├── Utils.py # вспомогательный файл, возможно не пригодится вовсе └── README.md ``` ## Стек технологий и используемые библиотеки - ### Стек технологий: Python: Основной язык программирования для разработки проекта. ### Используемые библиотеки: -- PIL (Python Imaging Library): Используется для работы с изображениями, включая извлечение пикселей, модификацию изображений и сохранение изображений. - argparse: Используется для обработки аргументов командной строки. - os: Используется для взаимодействия с операционной системой, включая создание директорий и работы с файлами. - math: Используется для выполнения математических операций, например, для вычисления ключей шифрования и дешифрования. - random: Используется для генерации случайных чисел, которые могут использоваться в алгоритмах шифрования. +## Тестирование +Снимок экрана 2024-04-17 в 23 07 30 + +## Инструкция по запуску +### Установка зависимостей: +Убедитесь, что у вас установлен Python версии 3.x. +``` +pip install -r requirements.txt +``` +### Запуск программы: +Программа предоставляет возможность шифрования и дешифрования файлов с использованием различных алгоритмов. +``` +python main.py -e -a caesar -i input.txt -l eng -k 3 +``` +Для шифрования файла input.txt с использованием алгоритма Цезаря на английском языке с ключом сдвига равным 3. +``` +python main.py -d -a vernam -i encrypted.txt -l rus -k secret_key +``` +Для дешифрования файла encrypted.txt с использованием алгоритма Вернама на русском языке с секретным ключом secret_key. + +### Опции командной строки: +- -e, --encrypt: Запуск программы в режиме шифрования. +- -d, --decrypt: Запуск программы в режиме дешифрования. +- -a, --algorithm: Выбор алгоритма шифрования/дешифрования (caesar, vernam, vigenere, statistical_caesar). +- -i, --input_file: Путь к входному файлу. +- -l, --lang: Язык текста (rus, eng). +- -k, --key: Ключ для шифрования/дешифрования (сдвиг для Цезаря, ключ для Вернама или Виженера). + +Примеры: + +Шифрование файла на английском языке с использованием алгоритма Виженера и ключа password123: +``` +python main.py -e -a vigenere -i input.txt -l eng -k password123 +``` +Дешифрование файла на русском языке с использованием алгоритма Цезаря и сдвига 5: +``` +python main.py -d -a caesar -i encrypted.txt -l rus -k 5 +``` + +Обратите внимание: +Перед запуском убедитесь, что у вас есть необходимые файлы для входных данных и выбраны правильные параметры для шифрования/дешифрования. +В случае использования алгоритма statistical_caesar ключ не требуется. diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5ade71b --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +pytest-cov +pytest diff --git a/src/CesarStatisticsDecipher.py b/src/CesarStatisticsDecipher.py new file mode 100644 index 0000000..f4ccf74 --- /dev/null +++ b/src/CesarStatisticsDecipher.py @@ -0,0 +1,110 @@ +from src.Cipher import * + + +class CesarStatisticsDecipher: + alphabets = dict(rus=["абвгдеёжзийклмнопрстуфхцчшщъыьэюя", "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"], + eng=["abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"], ) + + def __init__(self): + pass + + statistics_data_eng = { + 'a': 8.17, + 'b': 1.49, + 'c': 2.78, + 'd': 4.25, + 'e': 12.70, + 'f': 2.23, + 'g': 2.02, + 'h': 6.09, + 'i': 6.97, + 'j': 0.15, + 'k': 0.77, + 'l': 4.03, + 'm': 2.41, + 'n': 6.75, + 'o': 7.51, + 'p': 1.93, + 'q': 0.10, + 'r': 5.99, + 's': 6.33, + 't': 9.06, + 'u': 2.76, + 'v': 0.98, + 'w': 2.36, + 'x': 0.15, + 'y': 1.97, + 'z': 0.07 + } + + statistics_data_ru = { + 'а': 8.01, + 'б': 1.59, + 'в': 4.54, + 'г': 1.70, + 'д': 2.98, + 'е': 8.45, + 'ё': 0.04, + 'ж': 0.94, + 'з': 1.65, + 'и': 7.35, + 'й': 1.21, + 'к': 3.49, + 'л': 4.40, + 'м': 3.21, + 'н': 6.70, + 'о': 10.97, + 'п': 2.81, + 'р': 4.73, + 'с': 5.47, + 'т': 6.26, + 'у': 2.62, + 'ф': 0.26, + 'х': 0.97, + 'ц': 0.48, + 'ч': 1.44, + 'ш': 0.73, + 'щ': 0.36, + 'ъ': 0.04, + 'ы': 1.90, + 'ь': 1.74, + 'э': 0.32, + 'ю': 0.64, + 'я': 2.01 + } + + def collect_statistics_from_text(self, text: str, alph: str) -> dict: + dictionary = {i: 0 for i in self.alphabets[alph][0]} + l = 0 + for letter in text: + if letter.lower() in self.alphabets[alph][0]: + dictionary[letter.lower()] += 100 + l += 1 + for i in dictionary: + dictionary[i] /= l + return dictionary + + def generate_shifted_alph(self, shift: int, alph: str) -> str: + cyp = CesarCipher(shift) + return cyp.encrypt(alphabets[alph][0], alph) + + def find_opt_step(self, text: str, alph: str) -> int: + statistics_data_text = self.collect_statistics_from_text(text, alph) + if alph == 'eng': + statistics_data_lang = self.statistics_data_eng + else: + statistics_data_lang = self.statistics_data_ru + """using standard deviation""" + min_standard_deviation = 1000000 + res = 0 + lst = list(statistics_data_text.values()) + for i in range(0, len(alphabets[alph][0])): + new_alpha = self.generate_shifted_alph(i, alph) + temp_dictionary = {j: lst[(new_alpha.index(j)) % len(new_alpha)] for j in new_alpha} + standard_deviation = (sum( + (statistics_data_lang[char] - temp_dictionary[char]) ** 2 for char in new_alpha) / len( + new_alpha)) ** 0.5 + if min_standard_deviation > standard_deviation: + res, min_standard_deviation = i, standard_deviation + print(res) + return res diff --git a/src/Cipher.py b/src/Cipher.py new file mode 100644 index 0000000..45a65fb --- /dev/null +++ b/src/Cipher.py @@ -0,0 +1,128 @@ +class CesarCipher: + alphabets = dict( + rus="абвгдеёжзийклмнопрстуфхцчшщъыьэюя", + eng="abcdefghijklmnopqrstuvwxyz" + ) + + def __init__(self, shift): + self.shift = shift + + def encrypt(self, text: str, alph: str) -> str: + al = self.alphabets[alph] + data = '' + for char in text: + if char.lower() in al: + if char.lower() == char: + data += al[(al.find(char) + self.shift) % len(al)].lower() + else: + data += al[(al.find(char.lower()) + self.shift) % len(al)].upper() + else: + data += char + return data + + def decrypt(self, text: str, alph: str) -> str: + al = self.alphabets[alph] + data = '' + for char in text: + if char.lower() in al: + if char.lower() == char: + data += al[(al.find(char) - self.shift) % len(al)].lower() + else: + data += al[(al.find(char.lower()) - self.shift) % len(al)].upper() + else: + data += char + return data + + +def generate_vigenere_table(alphabet: str) -> dict: + vigenere_tableble = {} + delta = 0 + for i, char in enumerate(alphabet): + row = {} + for j in range(len(alphabet)): + row[alphabet[(i + j) % len(alphabet)]] = alphabet[(i + j + delta) % len(alphabet)] + vigenere_tableble[char] = row + delta += 1 + + return vigenere_tableble + + +alphabets = dict(rus=["абвгдеёжзийклмнопрстуфхцчшщъыьэюя", "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"], + eng=["abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"], + all="аАбБвВгГдДеЕёЁжЖзЗиИйЙкКлЛмМнНоОпПрРсСтТуУфФхХцЦчЧшШщЩъЪыЫьЬэЭюЮяЯaAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ") + + +def GenKey(keyword, text): + key = '' + j = 0 + for i in range(len(text)): + if text[i] in alphabets["all"]: + if text[i] == text[i].upper(): + key += keyword[j % len(keyword)].upper() + elif text[i] == text[i].lower(): + key += keyword[j % len(keyword)].lower() + j += 1 + else: + key += text[i] + return key + + +class VigenereCipher: + + def __init__(self, keyword): + self.keyword = keyword + + def encrypt(self, text: str, alph: str) -> str: + key = GenKey(self.keyword, text) + vigenere_tableble_small = generate_vigenere_table(alphabets[alph][0]) + vigenere_tableble_big = generate_vigenere_table(alphabets[alph][1]) + encrypted_text = '' + for i in range(len(text)): + if text[i] in alphabets[alph][0]: + encrypted_text += vigenere_tableble_small[text[i]][key[i]] + elif text[i] in alphabets[alph][1]: + encrypted_text += vigenere_tableble_big[text[i]][key[i]] + else: + encrypted_text += text[i] + return encrypted_text + + def decrypt(self, text: str, alph: str) -> str: + key = GenKey(self.keyword, text) + vigenere_tableble_small = generate_vigenere_table(alphabets[alph][0]) + vigenere_tableble_big = generate_vigenere_table(alphabets[alph][1]) + decrypted_text = '' + for i in range(len(text)): + if text[i] in alphabets[alph][0]: + decrypted_text += vigenere_tableble_small[text[i]][ + alphabets[alph][0][(len(alphabets[alph][0]) - alphabets[alph][0].find(key[i])) % len( + alphabets[alph][0])]] + elif text[i] in alphabets[alph][1]: + decrypted_text += vigenere_tableble_big[text[i]][ + alphabets[alph][1][(len(alphabets[alph][1]) - alphabets[alph][1].find(key[i])) % len( + alphabets[alph][1])]] + else: + decrypted_text += text[i] + return decrypted_text + + +class VernamCipher: + def __init__(self, keyword): + self.keyword = keyword + + def encrypt(self, text: str, alph: str) -> str: + key = GenKey(self.keyword, text) + result = '' + for text_char, key_char in zip(text, key): + if text_char not in alphabets["all"]: + result += text_char + else: + if text_char in alphabets[alph][0]: i = 0 + else: i = 1 + result += alphabets[alph][i][ + ((ord(text_char) - ord(alphabets[alph][i][0])) ^ (ord(key_char) - ord(alphabets[alph][i][0]))) % len( + alphabets[alph][i])] + return result + + def decrypt(self, text: str, alph: str) -> str: + return self.encrypt(text, alph) + diff --git a/src/FileHandler.py b/src/FileHandler.py new file mode 100644 index 0000000..f98b949 --- /dev/null +++ b/src/FileHandler.py @@ -0,0 +1,75 @@ +from src.CesarStatisticsDecipher import * +import os + + +class FileHandler: + def __init__(self): + pass + + def read_file(self, file_path: str) -> str: + with open(file_path, 'r') as file: + data = file.read() + return data + + def write_to_file(self, file_path: str, data: str): + with open(file_path, 'w') as file: + file.write(data) + + def encrypt_file(self, file_path: str, cipher: str, alph: str, key=''): + if cipher == "cesar": + shift = int(key) + data = self.read_file(file_path) + result = CesarCipher(shift).encrypt(data, alph) + dir_path = os.path.dirname(file_path) + result_file_path = os.path.join(dir_path, 'result.txt') + self.write_to_file(result_file_path, result) + + elif cipher == "vigenere": + keyword = key + data = self.read_file(file_path) + result = VigenereCipher(keyword).encrypt(data, alph) + dir_path = os.path.dirname(file_path) + result_file_path = os.path.join(dir_path, 'result.txt') + self.write_to_file(result_file_path, result) + + elif cipher == "vernam": + keyword = key + data = self.read_file(file_path) + result = VernamCipher(keyword).encrypt(data, alph) + dir_path = os.path.dirname(file_path) + result_file_path = os.path.join(dir_path, 'result.txt') + self.write_to_file(result_file_path, result) + + # + def decrypt_file(self, file_path: str, cipher: str, alph: str, key=''): + if cipher == "cesar": + shift = int(key) + data = self.read_file(file_path) + result = CesarCipher(shift).decrypt(data, alph) + dir_path = os.path.dirname(file_path) + result_file_path = os.path.join(dir_path, 'result.txt') + self.write_to_file(result_file_path, result) + + elif cipher == "vigenere": + keyword = key + data = self.read_file(file_path) + result = VigenereCipher(keyword).decrypt(data, alph) + dir_path = os.path.dirname(file_path) + result_file_path = os.path.join(dir_path, 'result.txt') + self.write_to_file(result_file_path, result) + + elif cipher == "vernam": + keyword = key + data = self.read_file(file_path) + result = VernamCipher(keyword).decrypt(data, alph) + dir_path = os.path.dirname(file_path) + result_file_path = os.path.join(dir_path, 'result.txt') + self.write_to_file(result_file_path, result) + + elif cipher == "statistical_caesar": + data = self.read_file(file_path) + shift = CesarStatisticsDecipher().find_opt_step(data, alph) + result = CesarCipher(shift).encrypt(data, alph) + dir_path = os.path.dirname(file_path) + result_file_path = os.path.join(dir_path, 'result.txt') + self.write_to_file(result_file_path, result) diff --git a/src/__pycache__/CesarStatisticsDecipher.cpython-312.pyc b/src/__pycache__/CesarStatisticsDecipher.cpython-312.pyc new file mode 100644 index 0000000..d6ec71a Binary files /dev/null and b/src/__pycache__/CesarStatisticsDecipher.cpython-312.pyc differ diff --git a/src/__pycache__/Cipher.cpython-312.pyc b/src/__pycache__/Cipher.cpython-312.pyc new file mode 100644 index 0000000..9806429 Binary files /dev/null and b/src/__pycache__/Cipher.cpython-312.pyc differ diff --git a/src/__pycache__/FileHandler.cpython-312.pyc b/src/__pycache__/FileHandler.cpython-312.pyc new file mode 100644 index 0000000..c17f832 Binary files /dev/null and b/src/__pycache__/FileHandler.cpython-312.pyc differ diff --git a/tests/Test.txt b/tests/Test.txt new file mode 100644 index 0000000..3fec188 --- /dev/null +++ b/tests/Test.txt @@ -0,0 +1,30 @@ +Мороз и солнце; день чудесный! +Еще ты дремлешь, друг прелестный — +Пора, красавица, проснись: +Открой сомкнуты негой взоры +Навстречу северной Авроры, +Звездою севера явись! +Вечор, ты помнишь, вьюга злилась, +На мутном небе мгла носилась; +Луна, как бледное пятно, +Сквозь тучи мрачные желтела, +И ты печальная сидела — +А нынче… погляди в окно: +Под голубыми небесами +Великолепными коврами, +Блестя на солнце, снег лежит; +Прозрачный лес один чернеет, +И ель сквозь иней зеленеет, +И речка подо льдом блестит. +Вся комната янтарным блеском +Озарена. Веселым треском +Трещит затопленная печь. +Приятно думать у лежанки. +Но знаешь: не велеть ли в санки +Кобылку бурую запречь? +Скользя по утреннему снегу, +Друг милый, предадимся бегу +Нетерпеливого коня +И навестим поля пустые, +Леса, недавно столь густые, +И берег, милый для меня. \ No newline at end of file diff --git a/tests/Test2.txt b/tests/Test2.txt new file mode 100644 index 0000000..30607b1 --- /dev/null +++ b/tests/Test2.txt @@ -0,0 +1,30 @@ +Тфцфн о чфсуьк; йкув эщйкчубп! +Кяк шб йцктскюв, йцщи хцкскчшубп — +Хфцё, рцёчёзоьё, хцфчуочв: +Фшрцфп чфтрущшб укифп знфцб +Уёзчшцкэщ чкзкцуфп Ёзцфцб, +Нзкнйфд чкзкцё езочв! +Зкэфц, шб хфтуоюв, звдиё нсосёчв, +Уё тщшуфт укжк тисё уфчосёчв; +Сщуё, рёр жскйуфк хешуф, +Чрзфнв шщэо тцёэубк мксшксё, +О шб хкэёсвуёе чойксё — +Ё убуэк… хфисейо з фруф: +Хфй ифсщжбто укжкчёто +Зксорфскхубто рфзцёто, +Жскчше уё чфсуьк, чуки скмош; +Хцфнцёэубп скч фйоу экцуккш, +О ксв чрзфнв оукп нкскуккш, +О цкэрё хфйф свйфт жскчшош. +Зче рфтуёшё еушёцубт жскчрфт +Фнёцкуё. Зкчксбт шцкчрфт +Шцкяош нёшфхскууёе хкэв. +Хцоешуф йщтёшв щ скмёуро. +Уф нуёкюв: ук зкскшв со з чёуро +Рфжбсрщ жщцщд нёхцкэв? +Чрфсвне хф щшцкууктщ чукищ, +Йцщи тосбп, хцкйёйотче жкищ +Укшкцхксозфиф рфуе +О уёзкчшот хфсе хщчшбк, +Скчё, укйёзуф чшфсв ищчшбк, +О жкцки, тосбп йсе ткуе. \ No newline at end of file diff --git a/tests/__pycache__/test_CesarStatisticsDecipher.cpython-312-pytest-8.1.1.pyc b/tests/__pycache__/test_CesarStatisticsDecipher.cpython-312-pytest-8.1.1.pyc new file mode 100644 index 0000000..5125a92 Binary files /dev/null and b/tests/__pycache__/test_CesarStatisticsDecipher.cpython-312-pytest-8.1.1.pyc differ diff --git a/tests/__pycache__/test_Cipher.cpython-312-pytest-8.1.1.pyc b/tests/__pycache__/test_Cipher.cpython-312-pytest-8.1.1.pyc new file mode 100644 index 0000000..6b9879a Binary files /dev/null and b/tests/__pycache__/test_Cipher.cpython-312-pytest-8.1.1.pyc differ diff --git a/tests/__pycache__/test_FileHandler.cpython-312-pytest-8.1.1.pyc b/tests/__pycache__/test_FileHandler.cpython-312-pytest-8.1.1.pyc new file mode 100644 index 0000000..9b2f136 Binary files /dev/null and b/tests/__pycache__/test_FileHandler.cpython-312-pytest-8.1.1.pyc differ diff --git a/tests/test_CesarStatisticsDecipher.py b/tests/test_CesarStatisticsDecipher.py new file mode 100644 index 0000000..9691cb2 --- /dev/null +++ b/tests/test_CesarStatisticsDecipher.py @@ -0,0 +1,9 @@ +from src.CesarStatisticsDecipher import CesarStatisticsDecipher + +def test_CesarStatisticsDecipher(): + cipher_obj = CesarStatisticsDecipher() + with open('tests/Test2.txt', 'r') as file: + data = file.read() + assert 27 == cipher_obj.find_opt_step(data, 'rus') + + diff --git a/tests/test_Cipher.py b/tests/test_Cipher.py new file mode 100644 index 0000000..17359e5 --- /dev/null +++ b/tests/test_Cipher.py @@ -0,0 +1,24 @@ +from src.Cipher import * + +def test_cipher(): + cesar_obj = CesarCipher(4) + cesar_obj_1 = CesarCipher(4) + + data = "Питон! Че у тебя тут за заварушка?" + data_1 = "Умцтс! Ыи ч циег цчц лд лдёдфчьод?" + + assert cesar_obj.encrypt(data, 'rus') == data_1 + assert cesar_obj_1.decrypt(data_1, 'rus') == data + + key = "Гуф" + vigenere_obj = VigenereCipher(key) + data_1 = 'Тьжсб! Лз ж жзфу хжж ку ьгхфужмну?' + assert vigenere_obj.encrypt(data, 'rus') == data_1 + assert vigenere_obj.decrypt(data_1, 'rus') == data + + vernam_obj = VernamCipher(key) + data_1 = 'Лъёмэ! Гё а ёёск раё дт тгруталит?' + assert vernam_obj.encrypt(data, 'rus') == data_1 + + + diff --git a/tests/test_FileHandler.py b/tests/test_FileHandler.py new file mode 100644 index 0000000..096bfcd --- /dev/null +++ b/tests/test_FileHandler.py @@ -0,0 +1,62 @@ +import shutil + +from src.FileHandler import FileHandler +import tempfile +import os + + +def test_FileHandler(): + file_handler = FileHandler() + + data = "Питон! Че у тебя тут за заварушка?" + data_1 = "Умцтс! Ыи ч циег цчц лд лдёдфчьод?" + temp_dir = tempfile.mkdtemp() + + try: + result_file_path = os.path.join(temp_dir, "result.txt") + file_handler.write_to_file(os.path.join(temp_dir, "temp_file.txt"), data) + file_handler.encrypt_file(os.path.join(temp_dir, "temp_file.txt"), 'cesar', 'rus', '4') + assert file_handler.read_file(result_file_path) == data_1 + file_handler.write_to_file(os.path.join(temp_dir, "temp_file.txt"), data_1) + file_handler.decrypt_file(os.path.join(temp_dir, "temp_file.txt"), 'cesar', 'rus', '4') + assert file_handler.read_file(result_file_path) == data + finally: + shutil.rmtree(temp_dir) + + key = "Гуф" + + temp_dir = tempfile.mkdtemp() + try: + result_file_path = os.path.join(temp_dir, "result.txt") + file_handler.write_to_file(os.path.join(temp_dir, "temp_file.txt"), data) + file_handler.encrypt_file(os.path.join(temp_dir, "temp_file.txt"), 'vigenere', 'rus', key) + data_1 = 'Тьжсб! Лз ж жзфу хжж ку ьгхфужмну?' + assert file_handler.read_file(result_file_path) == data_1 + file_handler.write_to_file(os.path.join(temp_dir, "temp_file.txt"), data_1) + file_handler.decrypt_file(os.path.join(temp_dir, "temp_file.txt"), 'vigenere', 'rus', key) + assert file_handler.read_file(result_file_path) == data + finally: + shutil.rmtree(temp_dir) + + temp_dir = tempfile.mkdtemp() + try: + result_file_path = os.path.join(temp_dir, "result.txt") + file_handler.write_to_file(os.path.join(temp_dir, "temp_file.txt"), data) + file_handler.encrypt_file(os.path.join(temp_dir, "temp_file.txt"), 'vernam', 'rus', key) + data_1 = 'Лъёмэ! Гё а ёёск раё дт тгруталит?' + assert file_handler.read_file(result_file_path) == data_1 + file_handler.write_to_file(os.path.join(temp_dir, "temp_file.txt"), data_1) + file_handler.decrypt_file(os.path.join(temp_dir, "temp_file.txt"), 'vernam', 'rus', key) + finally: + shutil.rmtree(temp_dir) + + data = file_handler.read_file("tests/Test2.txt") + temp_dir = tempfile.mkdtemp() + + try: + result_file = os.path.join(temp_dir, "result.txt") + file_handler.write_to_file(os.path.join(temp_dir, "temp_file.txt"), data) + file_handler.decrypt_file(os.path.join(temp_dir, "temp_file.txt"), 'statistical_caesar', 'rus') + assert os.path.exists(result_file) + finally: + shutil.rmtree(temp_dir)