Как создать инструмент PGP-шифрования на основе Python

Что такое PGP

PGP (англ. Pretty Good Privacy)  —  это широко известная программа для операций шифрования. Она создает цифровые подписи, зашифровывает/расшифровывает большие объемы данных и повышает безопасность электронной переписки. 

PGP-шифрование задействует последовательную комбинацию хеширования, сжатия данных, криптографию с симметричным и открытым ключом. На каждом этапе применяется один из поддерживаемых алгоритмов. Каждый открытый ключ привязан к имени пользователя и адресу электронной почты. 

К счастью, большинство протоколов PGP-шифрования доступно для разработчиков через открытую библиотеку Python pgpy. Обнаружив эту библиотеку, я на досуге изучил ее открытый исходный код и создал небольшой апплет  —  инструмент командной строки для PGP-шифрования.

Фрагмент командной строки кода

Далее мы рассмотрим основные этапы создания базового апплета в инструменте командной строки для PGP-шифрования. Требуются знания файловых потоков и программирования. 

Создание апплета командной строки 

Сначала мы напишем код 5 базовых функций, играющих важную роль в создании задуманного ПО. Они обеспечат следующие возможности: получение и установка ключа, чтение и запись его в специальный файл и генерация ключа.

Поскольку получение, установка, чтение и запись являются базовыми функциями, в нижеуказанном фрагменте кода они представлены без пояснений. А вот функция genKey вызывает немного больший интерес. И хотя она не что иное, как шаблонный код pgpy, мы рассмотрим ее повнимательнее. 

Строка 42 генерирует пару “открытый-закрытый” ключ размером 4096, используя протокол RSA. Последующая команда в строке 45 привязывает их к вымышленной электронной почте  —  в данном случае Abraham Lincoln.

Строка 50 позволяет указать весь спектр пользовательских случаев (шифрование электронной почты, шифрование диска и т. д.) и предопределенные хэши, шифры, алгоритмы сжатия, применяемые для шифрования документов. Никакие параметры или флаги не были удалены в следующем примере: 

import pgpy
import fcntl, os, sys

global g_key

def setKey(key):
"""
Функция, устанавливающая g_key для ключа.
"""

g_key = key

def getKey():
"""
Получает ключи.
"""

return g_key

def saveKey(name):
"""
Сохраняет ключ в новом файле.
"""

f = open(name, "w")
f.write(g_key)

def openKey(name):
"""
Открывает ключ из файла.
"""

f = open(name, "r")
setKey(f.read())


def genKeys():
"""
Функция, генерирующая открытый и закрытый ключи.
"""

key = pgpy.PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 4096)

# Теперь у нас есть материал ключа. Однако поскольку у нового ключа отсутствует ID пользователя, то к работе он пока не готов!
uid = pgpy.PGPUID.new('Abraham Lincoln', comment='Honest Abe', email='[email protected]')

# Мы должны добавить ключу новый ID пользователя и указать на этом этапе все установочные параметры,
# поскольку на данный момент PGPy не имеет встроенных установочных параметров ключей по умолчанию.
# Этот пример похож на предустановленные настройки GnuPG 2.1.x, без срока действия и предпочитаемого сервера ключей
key.add_uid(uid, usage={KeyFlags.Sign, KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage},
hashes=[HashAlgorithm.SHA256, HashAlgorithm.SHA384, HashAlgorithm.SHA512, HashAlgorithm.SHA224],
ciphers=[SymmetricKeyAlgorithm.AES256, SymmetricKeyAlgorithm.AES192, SymmetricKeyAlgorithm.AES128],
compression=[CompressionAlgorithm.ZLIB, CompressionAlgorithm.BZ2, CompressionAlgorithm.ZIP, CompressionAlgorithm.Uncompressed])
setKey(key)
return key

Следующий этап работы заключается в сочетании команд шифрования pgpy и вызовов файловых потоков Python. Потребуются 4 функции: pgp_encrypt  —  для шифрования текста; pgp_decrypt  —  для расшифровки; encrypt_file и decrypt_file. Функции, связанные с шифрованием и расшифровкой файлов, будут комбинированно использовать команды шифрования и функциональность файловых потоков, как показано ниже: 

def pgpy_encrypt(key, data):
"""
Зашифровывает данные с помощью ключа.
"""

message = pgpy.PGPMessage.new(data)
enc_message = key.pubkey.encrypt(message)
return bytes(enc_message)


def pgpy_decrypt(key, enc_data):
"""
Расшифровывает данные с помощью ключа.
"""

message = pgpy.PGPMessage.from_blob(enc_data)
return str(key.decrypt(message).message)

def encryptFile(path, key):
"""
Функция зашифровывает содержимое файла по пути path,
используя
шифр, указанный в переменной шифрования.
"""

f = open("D:\\myfiles\welcome.txt", "w")
data = f.read()
enc = pgpy_encrypt(g_key, data)
f.write(enc)

def dencryptFile(path, key):
"""
Функция расшифровывает содержимое файла по пути path,
применяя
шифр, указанный в переменной шифрования.
"""

f = open("D:\\myfiles\welcome.txt", "w")
data = f.read()
denc = pgpy_encrypt(g_key, data)
f.write(denc)

Теперь объединяем все вместе в основной команде __main__, как показано ниже, и получаем работающую программу шифрования:

if __name__ == "__main__":
print("Welcome to Text File Encryptor.")
keyState = input("Generate a new Key(Y/N)")

# Получает ключи
if (keyState == "Y"):
setKey(genKeys)
saveKey(getKey())
else:
path = input("What is the key file path?")
openKey(path)

state = input("Are you encrypting or decrypting?")
if (state == "encrypt"):
encryptFile(input("Path to the file to encrypt?"), getKey())
else:
dencryptFile(input("Path to the file to encrypt?"), getKey())

print("Task complete.")

Заключение

Несмотря на то, что данная статья дает всего лишь представление о PGP, она может стать увлекательной отправной точкой для начинающих программистов и тех, кто интересуется кибербезопасностью и шифрованием. 

Изучая открытое ПО и создавая с ним небольшие интересные проекты, вы начинает намного лучше разбираться в предмете. Поэтому всем любителям криптографии и кибербезопасности настоятельно рекомендую взять этот принцип на вооружение и разрабатывать собственные проекты. 

Читайте также:

Читайте нас в TelegramVK и Яндекс.Дзен


Перевод статьи Aleksa Zatezalo: Creating a PGP Encryption Tool With Python

Предыдущая статьяРасширение Chrome для поиска акций на eToro с помощью скринера акций FINVIZ
Следующая статьяМеняем Async/Await на Promises.allSettled() для ускорения API-вызовов в Node.JS