Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions lab1/caesar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
def encrypt(plaintext: str, shift: int) -> str:
"""
Функция encrypt возвращает входную строку plaintext,
зашифрованную шифром Цезаря на входной сдвиг shift
по ascii-кодам отдельных символов строки
"""
total_symbols = 126 - 31
output = ''

interval_begin = 32
interval_end = 126
for symbol in plaintext:

if interval_begin <= ord(symbol) <= interval_end:
output += chr((ord(symbol) - interval_begin + shift) % total_symbols + interval_begin)
else:
output += symbol

return output

def decrypt(ciphertext: str, shift: int) -> str:
"""
Функция decrypt возвращает строку ciphertext,
расшифрованную шифром Цезаря на входной сдвиг shift
по ascii-кодам отдельных символов строки
путем вызова функции encrypt со сдвигом -shift,
то есть шифрует на противоположный сдвиг
"""
return encrypt(ciphertext, -shift)
69 changes: 69 additions & 0 deletions lab1/hack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import caesar
import random


def error(text: str) -> int:
"""
для каждого символа входной строки сравнивает
эталонную процентную частоту использования символа
и аналогичную величину для входной строки.
"""

# словарь эталонной процентной частоты использования символов с ascii-кодами в отрезке [32,126]
# сгенерирован с помощью DeepSeek
standart_fraquency = {
' ': 17.1662,
'e': 10.2911, 't': 7.9483, 'a': 7.4825, 'o': 7.2201,
'n': 6.7703, 'i': 6.3456, 's': 6.1473, 'r': 5.9951,
'h': 5.2448, 'l': 4.1253, 'd': 3.7879, 'c': 3.3854,
'u': 2.7584, 'm': 2.7055, 'f': 2.4063, 'p': 2.1885,
'g': 2.0306, 'w': 1.9541, 'y': 1.8510, 'b': 1.8194,
'v': 1.0077, 'k': 0.9678, 'x': 0.1923, 'j': 0.1533,
'q': 0.0957, 'z': 0.0776,
'E': 0.6492, 'T': 0.5976, 'A': 0.5801, 'O': 0.5043,
'N': 0.4920, 'I': 0.4653, 'S': 0.4301, 'R': 0.4200,
'H': 0.3853, 'L': 0.3201, 'D': 0.2852, 'C': 0.2725,
'U': 0.1901, 'M': 0.1782, 'F': 0.1512, 'P': 0.1403,
'G': 0.1252, 'W': 0.1201, 'Y': 0.1152, 'B': 0.1052,
'V': 0.0721, 'K': 0.0652, 'X': 0.0452, 'J': 0.0352,
'Q': 0.0252, 'Z': 0.0201,
',': 1.2345, '.': 1.1201, '"': 0.8654, "'": 0.7543,
'?': 0.4521, '!': 0.3521, ':': 0.2854, ';': 0.2154,
'-': 0.1854, '(': 0.1452, ')': 0.1452, '[': 0.0452,
']': 0.0452, '{': 0.0252, '}': 0.0252, '<': 0.0152,
'>': 0.0152, '/': 0.1254, '\\': 0.0152, '|': 0.0102,
'`': 0.0854, '~': 0.0152, '@': 0.0352, '#': 0.0452,
'$': 0.0854, '%': 0.0452, '^': 0.0152, '&': 0.0552,
'*': 0.0652, '_': 0.0954, '+': 0.0352, '=': 0.0452,
'0': 1.2345, '1': 0.9854, '2': 0.7543, '3': 0.4521,
'4': 0.3521, '5': 0.2854, '6': 0.2154, '7': 0.1854,
'8': 0.1452, '9': 0.1252
}


letters = set(text)

#анаголичный словарь для входной строки:
fraquency = {}
for letter in letters:
fraquency[letter] = 100 * text.count(letter) / len(text)

#возвращаем общюю ошибку -- сумму разниц процентов использования для каждого символа
return sum(abs(fraquency[letter] - standart_fraquency[letter]) for letter in letters)


def hack(ciphertext: str) -> tuple[str, int]:
"""
перебором всевозможных сдвигов выбирает текст с минимальной ошибкой
возвращет полученный текст и сдвиг,минимизирующий ошибку
"""
min_error = float('+inf')
interval_begin = 32
interval_end = 126
for shift in range(interval_end - interval_begin + 1):
decrypted_error = error(caesar.decrypt(ciphertext, shift))
if decrypted_error < min_error:
min_error = decrypted_error
answer = (caesar.decrypt(ciphertext, shift), shift)

return answer
61 changes: 61 additions & 0 deletions lab1/rsa.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
def is_prime(n: int) -> bool:
return n >= 2 and all(n % divider !=0 for divider in range(2,int(n**0.5)+1))

def gcd(a: int, b: int) -> int:
while b !=0:
a, b = b, a % b
return a

def multiplicative_inverse(e: int, phi:int) -> int:
"""
ищет натуральное число, которое при умножении на e по модулю phi даёт 1
с помощью последовательного перебора натуральных n
"""
assert gcd(e, phi) == 1
n = 0
while (phi * n + 1) % e != 0:
n+=1
return (phi * n + 1)//e

#return pow(e, -1, phi)

def generate_keypair(p: int, q: int) -> tuple[tuple[int, int], tuple[int, int]]:
"""
генерирует открытый и закрытый ключи
"""
n = p * q
phi = (p - 1) * (q - 1)
e = 2
while gcd(e,phi) != 1:
e+=1
d = multiplicative_inverse(e, phi)

return ((e, n), (d, n))

def encrypt(public_key: tuple[int, int], text: str) -> list[int]:
"""
шифрует входную строку с помощью закрытого ключа
возвращает список зашифрованных ascii-кодов
"""

e, n = public_key
cipher_list = [None for _ in range(len(text))]
for i in range(len(text)):
#зашифровывает символ, находя остаток от деления на n его ascii-кода в степени e
encrypted_symbol = pow(ord(text[i]), e, n)
cipher_list[i] = encrypted_symbol
return cipher_list

def decrypt(private_key: tuple[int, int], cipher_list: list[int]) -> str:
"""
дешифрует входную строку с помощью закрытого ключа
возвращает список зашифрованных ascii-кодов
"""
d, n = private_key
messege = ''
for encrypted_symbol in cipher_list:
#расшифровывает символ, находя остаток от деления на n его ascii-кода в степени d
decrypted_symbol = pow(encrypted_symbol,d,n)
messege+= chr(decrypted_symbol)
return messege

51 changes: 51 additions & 0 deletions lab1/vigenere.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
def encrypt(plaintext: str, keyword: str) -> str:
"""
Функция шифрует входную строку шифром Виженера с помощью ключевого слова
"""
alphabet = sorted(list(set(('qwertyuiopasdfghjklzxcvbnm'))))
assert len(alphabet) == 26
a_ascii_code = ord('a')
key_numbers = [ord(letter) - a_ascii_code for letter in keyword.lower() if letter in alphabet]


total_symbols = 126 - 31
output = ''

interval_begin = 32
interval_end = 126
for i in range(len(plaintext)):
symbol = plaintext[i]
shift = key_numbers[i % len(key_numbers)]

if interval_begin <= ord(symbol) <= interval_end:
output += chr((ord(symbol) - interval_begin + shift) % total_symbols + interval_begin)
else:
output += symbol

return output

def decrypt(ciphertext: str, keyword: str) -> str:
"""
Функция дешифрует входную строку шифром Виженера с помощью ключевого слова
[шифрует с противоположным сдвигом]
"""
alphabet = sorted(list(set(('qwertyuiopasdfghjklzxcvbnm'))))
assert len(alphabet) == 26
a_ascii_code = ord('a')
key_numbers = [ord(letter) - a_ascii_code for letter in keyword.lower() if letter in alphabet]

total_symbols = 126 - 31
output = ''

interval_begin = 32
interval_end = 126
for i in range(len(ciphertext)):
symbol = ciphertext[i]
shift = key_numbers[i % len(key_numbers)]

if interval_begin <= ord(symbol) <= interval_end:
output += chr((ord(symbol) - interval_begin - shift) % total_symbols + interval_begin)
else:
output += symbol

return output
Loading