Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Воган Ли - Python для хакеров (Библиотека программиста) - 2023.pdf
Скачиваний:
5
Добавлен:
07.04.2024
Размер:
14.76 Mб
Скачать

Глава4.Отправкасуперсекретныхсообщенийспомощьюкнижногошифра      355

punct_by_author = dict()

for author in strings_by_author:

tokens = nltk.word_tokenize(strings_by_author[author]) punct_by_author[author] = ([token for token in tokens

if token in PUNCT_SET]) print("Number punctuation marks in {} = {}"

.format(author, len(punct_by_author[author]))) return punct_by_author

def convert_punct_to_number(punct_by_author, author):

"""Возвращаем список знаков препинания, преобразованных в численные значения."""

heat_vals = []

for char in punct_by_author[author]: if char == ';':

value = 1 else:

value = 2 heat_vals.append(value)

return heat_vals

if __name__ == '__main__': main()

Глава 4. Отправка суперсекретных сообщений с помощью книжного шифра

Составление графика символов

practice_barchart.py

"""Рисуем столбчатую диаграмму символов из файла текста.""" import sys

import os import operator

from collections import Counter import matplotlib.pyplot as plt

def load_file(infile):

"""Считываем и возвращаем файл текста в виде строки символов в нижнем регистре."""

with open(infile) as f: text = f.read().lower()

return text

def main():

infile = 'lost.txt'

if not os.path.exists(infile):

print("File {} not found. Terminating.".format(infile), file=sys.stderr)

sys.exit(1)

356      Решения для практических проектов

text = load_file(infile)

#Создаем диаграмму символов в тексте и их частотности. char_freq = Counter(text)

char_freq = Counter(text)

char_freq_sorted = sorted(char_freq.items(), key=operator.itemgetter(1), reverse=True)

x, y = zip(*char_freq_sorted) # * для разделения ('распаковки')

итераторов.

fig, ax = plt.subplots() ax.bar(x, y)

fig.show()

if __name__ == '__main__': main()

Отправка секретов шифром времен Второй мировой войны

practice_WWII_words.py

"""Книжный шифр, использующий роман "Затерянный мир". Для слов, отсутствующих в книге, пишется их первая буква.

Отмечайте 'режим первой буквы', заключая слова между чередующимися

'a a' и 'the the'.

Реализация: Эрик Т. Мортенсон

"""

import sys import os import random import string

from collections import defaultdict, Counter

def main():

message = input("Enter plaintext or ciphertext: ") process = input("Enter 'encrypt' or 'decrypt': ") shift = int(input("Shift value (1-365) = ")) infile = input("Enter filename with extension: ")

if not os.path.exists(infile):

print("File {} not found. Terminating.".format(infile), file=sys.stderr)

sys.exit(1)

word_list = load_file(infile) word_dict = make_dict(word_list, shift)

letter_dict = make_letter_dict(word_list)

if process == 'encrypt':

ciphertext = encrypt(message, word_dict, letter_dict) count = Counter(ciphertext)

encryptedWordList = [] for number in ciphertext:

encryptedWordList.append(word_list[number - shift])

Глава4.Отправкасуперсекретныхсообщенийспомощьюкнижногошифра      357

print("\nencrypted word list = \n {} \n"

.format(' '.join(encryptedWordList))) print("encrypted ciphertext = \n {}\n".format(ciphertext))

# Проверяем шифрование, расшифровывая криптограмму. print("decrypted plaintext = ")

singleFirstCheck = False

for cnt, i in enumerate(ciphertext):

if word_list[ciphertext[cnt]-shift] == 'a' and \ word_list[ciphertext[cnt+1]-shift] == 'a':

continue

if word_list[ciphertext[cnt]-shift] == 'a' and \ word_list[ciphertext[cnt-1]-shift] == 'a':

singleFirstCheck = True continue

if singleFirstCheck == True and cnt<len(ciphertext)-1 and \ word_list[ciphertext[cnt]-shift] == 'the' and \

word_list[ciphertext[cnt+1]-shift] == 'the':

continue

if singleFirstCheck == True and \ word_list[ciphertext[cnt]-shift] == 'the' and \

word_list[ciphertext[cnt-1]-shift] == 'the': singleFirstCheck = False

print(' ', end='', flush=True) continue

if singleFirstCheck == True:

print(word_list[i - shift][0], end = '', flush=True) if singleFirstCheck == False:

print(word_list[i - shift], end=' ', flush=True)

elif process == 'decrypt':

plaintext = decrypt(message, word_list, shift) print("\ndecrypted plaintext = \n {}".format(plaintext))

def load_file(infile):

"""Считываем и возвращаем текстовый файл в виде списка слов в нижнем регистре."""

with open(infile, encoding='utf-8') as file:

words = [word.lower() for line in file for word in line.split()] words_no_punct = ["".join(char for char in word if char not in \

string.punctuation) for word in words]

return words_no_punct

def make_dict(word_list, shift):

"""Возвращаем словарь символов в качестве ключей и смещенные индексы в качестве значений."""

word_dict = defaultdict(list)

for index, word in enumerate(word_list): word_dict[word].append(index + shift)

return word_dict

358      Решения для практических проектов

def make_letter_dict(word_list): firstLetterDict = defaultdict(list) for word in word_list:

if len(word) > 0:

if word[0].isalpha(): firstLetterDict[word[0]].append(word)

return firstLetterDict

def encrypt(message, word_dict, letter_dict):

"""Возвращаем список индексов, представляющих символы в сообщении.""" encrypted = []

# Удаляем пунктуацию из слов сообщения. messageWords = message.lower().split()

messageWordsNoPunct = ["".join(char for char in word if char not in \ string.punctuation) for word in messageWords]

for word in messageWordsNoPunct: if len(word_dict[word]) > 1:

index = random.choice(word_dict[word])

elif len(word_dict[word]) == 1: # Random.choice дает сбой, если есть всего 1 выбор.

index = word_dict[word][0]

elif len(word_dict[word]) == 0: # Слова нет в word_dict. encrypted.append(random.choice(word_dict['a'])) encrypted.append(random.choice(word_dict['a']))

for letter in word:

if letter not in letter_dict.keys():

print('\nLetter {} not in letter-to-word dictionary.'

.format(letter), file=sys.stderr) continue

if len(letter_dict[letter])>1:

newWord =random.choice(letter_dict[letter]) else:

newWord = letter_dict[letter][0] if len(word_dict[newWord])>1:

index = random.choice(word_dict[newWord]) else:

index = word_dict[newWord][0] encrypted.append(index)

encrypted.append(random.choice(word_dict['the'])) encrypted.append(random.choice(word_dict['the'])) continue

encrypted.append(index) return encrypted

def decrypt(message, word_list, shift):

"""Расшифровываем строку криптограммы и возвращаем строку слов в виде открытого текста.

Здесь отображается, как выглядит открытый текст до извлечения первых букв.

"""

plaintextList = []