Шифрование кода на Python: кодировки, хеширование, PyCrypto, создание ключей RSA и пакет cryptography

0
24

Краткая памятка по шифрованию в Python

  1. Определите, что именно нужно шифровать: строку, файл или данные.
  2. Выберите подходящую библиотеку: для новых проектов используйте cryptography.
  3. Для симметричного шифрования используйте Fernet или AES.
  4. Для асимметричного шифрования используйте RSA.
  5. Не забывайте про безопасное хранение ключей.
  6. Используйте кодировки (Base64) для представления зашифрованных данных в виде текста.
  7. Для хеширования (не шифрования) используйте hashlib.
  8. Избегайте использования устаревших библиотек, таких как PyCrypto.
  9. Всегда тестируйте процесс шифрования и расшифровки.
  10. Регулярно обновляйте библиотеки для безопасности.

Кодировки¶

単 純 な 換 字 式 暗 号 の 復 号 化 - изображение номер один
単 純 な 換 字 式 暗 号 の 復 号 化 — изображение номер один

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

Таблица №1

Обозначение в python

Название кодировки

Описание

ascii

ASCII

Латинские буквы, цифры и простые символы

cp1251

windows-1251

Кириллическая кодировка (русский и другие языки)

koi8-r

KOI-8

Кодировка для русского языка

utf-8

UTF-8

Юникод-кодировка, все языки (длина символа — 8 бит)

utf-16

UTF-16

Юникод-кодировка, все языки (длина символа — 16 бит)

Unicode — стандарт кодирования символов, включающий в себя знаки почти всех письменных языков мира. В настоящее время стандарт является преобладающим в Интернете.

  • стандарт включает более 138 тысяч символов;
  • каждый символ имеет определённое название и код (номер);
  • коды состоят из латинских букв и шестнадцатеричных цифр, например: U+0073.

U+0073
коды состоят из латинских букв и шестнадцатеричных цифр, например:.

  • U+0073, «LATIN SMALL LETTER S» — s
  • U+1F383, «JACK-O-LANTERN» — 🎃
  • U+2615, «HOT BEVERAGE» — ☕

Хеширование

Python hash() - изображение номер два
Python hash() — изображение номер два

Другой популярный случай, в котором применяется хеширование – это хеширование файла, с последующей отправкой файла и его хеша по отдельности. Получатель файла может запустить хеш в файле, чтобы убедиться в том, что файл соответствует отправленному хешу. Если это так, значит никто не менял файл, когда он был отправлен. Давайте попробуем создать хеш md5. Но оказывается, чтобы использовать хеш md5, нужно передать его строке байта, вместо обычной. Так что мы попробовали сделать это, после чего вызвали метод дайджеста, чтобы получить наш хеш. Если вы претпочитаете хешированный дайджест, мы можем сделать и это:

import hashlib (b’Python rocks!’) result = () print(result) # b’\x14\x82\xec\x1b#d\xf6N}\x16*+[\x16\xf4w’

Таблица №2

1
2
3
4
5
6
import hashlib
hashlib.md5.update(b‘Python rocks!’)
result = hashlib.md5.digest()
 
print(result)
# b’\x14\x82\xec\x1b#d\xf6N}\x16*+[\x16\xf4w’

Давайте уделим время на то, чтобы разобраться с увиденным. Сначала мы импортировали модуль hashlib и создали экземпляр объекта md5 HASH. Далее, мы вписали небольшой текст в объект хеша и получили трассировку.

Таблица №3

1
2
print( md5.hexdigest() )
# ‘1482ec1b2364f64e7d162a2b5b16f477’

На самом деле существует метод быстрого создания хеша, мы рассмотрим его, когда создадим наш хеш sha512:

import hashlib sha = hashlib.sha1(b’Hello Python’).hexdigest() print(sha) # ‘422fbfbc67fe17c86642c5eaaa48f8b670cbed1b’

Таблица №4

1
2
3
4
import hashlib
sha = hashlib.sha1(b‘Hello Python’).hexdigest()
 
print(sha) # ‘422fbfbc67fe17c86642c5eaaa48f8b670cbed1b’

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

PyCrypto

Криптография на - изображение номер три
Криптография на — изображение номер три

Пакет PyCrypto, наверное, самый известный сторонний пакет криптографии для Python. К сожалению, его доработка остановилась в 2012 году. Однако продолжается выпускаться под разные версии Python, вы можете получить PyCrypto для версии 3.5 включительно, если вы не брезгуете использовать двоичный код стороннего производства. К примеру, я нашел несколько бинарных колес Python 3.5 для PyCrypto на Github (). К счастью, есть развилка проекта под названием PyCrytodome, которая является неплохой заменой PyCrypto. Для его установки на Linux вы можете использовать следующую команду:

Таблица №5

1
pip install pycryptodome

Таблица №6

1
pip install pycryptodomex

Если вы столкнетесь со сложностями, это, возможно, связанно с тем, что у вас нет необходимых установленных зависимостей, или необходим компилятор под Windows. Вы можете перейти на официальный сайт PyCryptodome для дополнительной информации о установке, или чтобы связаться с поддержкой. Также стоит отметить, что PyCryptodome имеет ряд преимуществ в сравнении с последней версией PyCrypto. Рекомендую потратить немного времени и посетить их сайт, для ознакомления с возможностями PyCryptodome.

Шифрование Строки

Python ile - изображение номер четыре
Python ile — изображение номер четыре

Теперь (после того, как вы ознакомились с информацией на сайте, я надеюсь), мы можем перейти к дальнейшим примерам. Для нашего следующего кода мы используем DES для шифровки строки:

from import DES key = b’abcdefgh’ def pad(text): while len(text) % 8!= 0: text += b’ ‘ return text des = (key, DES.MODE_ECB) text = b’Python rocks!’ padded_text = pad(text) encrypted_text = (padded_text) print(encrypted_text) # b’>\xfc\x1f\x16x\x87\xb2\x93\x0e\xfcH\x02\xd59VQ’

Таблица №7

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from Crypto.Cipher import DES
 
key = b‘abcdefgh’
 
def pad(text):
    while len(text) % 8 != 0:
        text += b‘ ‘
    return text
 
des = DES.new(key, DES.MODE_ECB)
text = b‘Python rocks!’
padded_text = pad(text)
 
encrypted_text = des.encrypt(padded_text)
print(encrypted_text)
# b’>\xfc\x1f\x16x\x87\xb2\x93\x0e\xfcH\x02\xd59VQ’

Этот код слегка запутанный, так что давайте уделим немного времени на его анализ. Во первых, обратите внимание на то, что размер ключа под шифровку DES — 8 байт, по этому мы установили нашу переменную ключа в строку размер букв строки. Шифруемая нами строка должна быть кратна 8 в ширину, так что мы создаем функцию под названием pad, которая может заполнить любую строку пробелами, пока она не станет кратна 8. Далее мы создаем экземпляр DES и текст, который нам нужно зашифровать. Мы также создаем заполненную версию текста. Прикола ради, мы попытаемся зашифровать начальный, незаполненный вариант строки, что приведет нас к ошибке ValueError. Таким образом Python ясно дает нам понять, что нам нужно использовать заполненную строку, так что мы передаем вторую версию. Как вы видите, мы получаем зашифрованную строку! Конечно, пример нельзя назвать полным, если мы не выясним, как расшифровать нашу строку:

ЧИТАТЬ ТАКЖЕ:  Как вырезать строку из строки в Python: срезы, методы и функции

Таблица №8

1
2
data = des.decrypt(encrypted_text)
print(data) # Python rocks!

К счастью, это очень легко сделать, так как все что нам нужно, это вызвать метод decrypt в нашем объекте des для получения расшифрованной байтовой строки. Наша следующая задача — научиться шифровать файлы и расшифровывать файлы с PyCrypto при помощи RSA. Но для начала, нам нужно создать ключи RSA.

На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!

Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!

Создание ключей RSA

RSA - изображение номер пять
RSA — изображение номер пять

Если вам нужно зашифровать ваши данные при помощи RSA, тогда вам также нужно получить доступ к паре ключа RSA public / private, или сгенерировать собственную. В данном примере мы генерируем собственную пару ключей. Так как это весьма легко, мы сделаем это в интерпретаторе Python:

from import RSA code = ‘nooneknows’ key = (2048) encrypted_key = (passphrase=code, pkcs=8, protection=»scryptAndAES128-CBC») with open(‘my_private_rsa_key.bin’, ‘wb’) as f: (encrypted_key) with open(‘my_rsa_public.pem’, ‘wb’) as f: (().exportKey())

Таблица №9

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from Crypto.PublicKey import RSA
 
code = ‘nooneknows’
key = RSA.generate(2048)
 
encrypted_key = key.exportKey(
    passphrase=code,
    pkcs=8,
    protection=«scryptAndAES128-CBC»
)
 
with open(‘my_private_rsa_key.bin’, ‘wb’) as f:
    f.write(encrypted_key)
 
with open(‘my_rsa_public.pem’, ‘wb’) as f:
    f.write(key.publickey().exportKey())

Сначала мы импортируем RSA из. Затем, мы создаем примитивный код доступа. Далее, мы генерируем ключ RSA на 2048 битов. Теперь мы подходим к интересной части. Для генерации приватного ключа, нам нужно вызвать метод exportKey нашего ключа RSA, и передать ему наш код доступа, который будет использован стандартом PKCS, чья схема шифровки будет использована для защиты нашего приватного ключа. После этого мы записываем файл на диск. Далее, мы создаем наш приватный ключ через метод publickey нашего ключа RSA. Мы использовали короткий путь в этой части кода, связав вызов метода exportKey с методом publickey для записи файла на диск.

Шифровка файла

Шифруем файлы с помощью - изображение номер шесть
Шифруем файлы с помощью — изображение номер шесть

Теперь у нас в распоряжении есть и приватный и публичный ключи, так что мы можем зашифровать кое-какие данные и вписать их в файл. Вот достаточно простой пример:

from import RSA from import get_random_bytes from import AES, PKCS1_OAEP with open(‘encrypted_data.bin’, ‘wb’) as out_file: recipient_key = RSA.import_key(open(‘my_rsa_public.pem’).read()) session_key = get_random_bytes(16) cipher_rsa = PKCS1_OAEP.new(recipient_key) out_file.write(cipher_rsa.encrypt(session_key)) cipher_aes = (session_key, AES.MODE_EAX) data = b’blah blah blah Python blah blah’ ciphertext, tag = cipher_aes.encrypt_and_digest(data) out_file.write(cipher_aes.nonce) out_file.write(tag) out_file.write(ciphertext)

Таблица №10

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from Crypto.PublicKey import RSA
from Crypto.Random import get_random_bytes
from Crypto.Cipher import AES, PKCS1_OAEP
 
 
with open(‘encrypted_data.bin’, ‘wb’) as out_file:
    recipient_key = RSA.import_key(
        open(‘my_rsa_public.pem’).read()
    )
    
    session_key = get_random_bytes(16)
    
    cipher_rsa = PKCS1_OAEP.new(recipient_key)
    out_file.write(cipher_rsa.encrypt(session_key))
    
    cipher_aes = AES.new(session_key, AES.MODE_EAX)
    data = b‘blah blah blah Python blah blah’
    ciphertext, tag = cipher_aes.encrypt_and_digest(data)
    
    out_file.write(cipher_aes.nonce)
    out_file.write(tag)
    out_file.write(ciphertext)

Первые три строки покрывают наши импорты из PyCryptodome. Далее мы открываем файл для записи. Далее, мы импортируем наш публичный ключ в переменной и создаем 16-битный ключ сессии. Для этого примера мы будем использовать гибридный метод шифрования, так что мы используем PKCS#1 OAEP (Optimal asymmetric encryption padding). Это позволяет нам записывать данные произвольной длинны в файл. Далее, мы создаем наш шифр AES, создаем кое-какие данные и шифруем их. Это дает нам зашифрованный текст и MAC. Наконец, мы выписываем nonce, MAC (или тег), а также зашифрованный текст. К слову, nonce – это произвольное число, которое используется только в криптографических связях. Обычно это случайные или псевдослучайные числа. Для AES, оно должно быть минимум 16 байтов в ширину. Вы вольны попытаться открыть зашифрованный файл в своем текстовом редакторе. Вы увидите только какое-то безобразие. Теперь попробуем расшифровать наши данные:

from import RSA from import AES, PKCS1_OAEP code = ‘nooneknows’ with open(‘encrypted_data.bin’, ‘rb’) as fobj: private_key = RSA.import_key(open(‘my_rsa_key.pem’).read(), passphrase=code) enc_session_key, nonce, tag, ciphertext = [(x) for x in (private_key.size_in_bytes(), 16, 16, -1)] cipher_rsa = PKCS1_OAEP.new(private_key) session_key = cipher_rsa.decrypt(enc_session_key) cipher_aes = (session_key, AES.MODE_EAX, nonce) data = cipher_aes.decrypt_and_verify(ciphertext, tag) print(data)

Таблица №11

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from Crypto.PublicKey import RSA
from Crypto.Cipher import AES, PKCS1_OAEP
 
 
code = ‘nooneknows’
 
with open(‘encrypted_data.bin’, ‘rb’) as fobj:
    private_key = RSA.import_key(
        open(‘my_rsa_key.pem’).read(),
        passphrase=code
    )
    
    enc_session_key, nonce, tag, ciphertext = [
        fobj.read(x) for x in (private_key.size_in_bytes(), 16, 16, 1)
    ]
    
    cipher_rsa = PKCS1_OAEP.new(private_key)
    session_key = cipher_rsa.decrypt(enc_session_key)
    
    cipher_aes = AES.new(session_key, AES.MODE_EAX, nonce)
    data = cipher_aes.decrypt_and_verify(ciphertext, tag)
 
print(data)

Если вы разобрались с предыдущим примером, то этот код должен быть весьма простым для разбора. В данном случае, мы открываем наш зашифрованный файл для чтения в бинарном режиме. Далее, мы импортируем наш приватный ключ. Обратите внимание на то, что когда вы импортируете приватный ключ, вы должны передать ему код доступа. В противном случае возникнет ошибка. Далее мы считываем наш файл. Вы заметите, что сначала мы считываем приватный ключ, затем 16 байтов для nonce, за которыми следуют 16 байтов, которые являются тегом, и наконец, остальную часть файла, который и является нашими данными. Далее нам нужно расшифровать наш ключ сессии, пересоздать наш ключ AES и расшифровать данные. Вы можете использовать PyCryptodome в намного более широком ряде случаев. Однако, нам нужно идти дальше и посмотреть, что еще мы можем сделать для наших криптографических нужд в Python.

ЧИТАТЬ ТАКЖЕ:  Полное руководство: как удалить Python с компьютера на Windows 10

Пакет cryptography

Пакет cryptography нацелен на то, чтобы быть «криптографом для людей», равно как и библиотека requests является «HTTP для людей». Суть в том, что вам нужно разработать простые криптографические рецепты которые и безопасны, и простые в использовании. Если нужно, вы можете перейти к низкоуровневым криптографическим примитивам, для которых требуется лишь знать, что вы делаете, в противном случае вы создадите что-то явно бесполезное в контексте защиты. Если вы работаете в Python 3.5 Windows, вы можете установить этот пакет при помощи pip следующим образом:

Таблица №12

1
pip install cryptography

Вы увидите, что cryptography установится совместно с несколькими зависимостями. Предположим, что с установкой все прошло чисто, и мы можем зашифровать какой-нибудь текст. Давайте используем для этого модуль Fernet.

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

Таблица №13

1
2
3
4
from cryptography.fernet import Fernet
 
cipher_key = Fernet.generate_key()
print(cipher_key) # APM1JDVgT8WDGOWBgQv6EIhvxl4vDYvUnVdg-Vjdt0o=

from import Fernet cipher = Fernet(cipher_key) text = b’My super secret message’ encrypted_text = (text) print(encrypted_text) # (b’gAAAAABXOnV86aeUGADA6mTe9xEL92y_m0_TlC9vcqaF6NzHqRKkjEqh4d21PInEP3C9HuiUkS9f’ # b’6bdHsSlRiCNWbSkPuRd_62zfEv3eaZjJvLAm3omnya8=’)

Таблица №14

1
2
3
4
5
6
7
8
9
10
from cryptography.fernet import Fernet
 
cipher = Fernet(cipher_key)
text = b‘My super secret message’
encrypted_text = cipher.encrypt(text)
 
print(encrypted_text)
 
# (b’gAAAAABXOnV86aeUGADA6mTe9xEL92y_m0_TlC9vcqaF6NzHqRKkjEqh4d21PInEP3C9HuiUkS9f’
# b’6bdHsSlRiCNWbSkPuRd_62zfEv3eaZjJvLAm3omnya8=’)

Таблица №15

1
2
decrypted_text = cipher.decrypt(encrypted_text)
print(decrypted_text) # ‘My super secret message’

Для начала, нам нужно импортировать Fernet. Затем мы генерируем ключ. Мы выводим ключ, чтобы увидеть, как он выглядит. Как вы видите, это случайна строка байтов. Если хотите, вы можете попробовать запустить метод generate_key несколько раз. Результат каждый раз новый. Далее мы создаем экземпляр нашего шифра Fernet при помощи нашего ключа. Теперь у нас есть шифр, который мы можем использовать для шифрования и расшифровки нашего сообщения. Следующий шаг, это создание сообщения, достойного шифровки, с последующей его шифровкой при помощи метода encrypt. Я пошел вперед и вывел наш зашифрованный текст так, чтобы вы увидели что вы больше не можете его читать. Для расшифровки нашего супер-засекреченного сообщения, мы просто вызовем метод decrypt в нашем шифре и передадим зашифрованный текст. В результате мы получим текстовую байтовую строку нашего сообщения.

Часто задаваемые вопросы о шифровании кода в Python

Вопрос: Какой самый простой способ зашифровать строку в Python?
Ответ: Самый простой способ — использовать библиотеку cryptography с симметричным шифрованием, например, Fernet.

Вопрос: В чем разница между хешированием и шифрованием?
Ответ: Хеширование — это односторонняя функция, данные не могут быть восстановлены. Шифрование — двусторонний процесс, данные можно расшифровать с помощью ключа.

Вопрос: Какую библиотеку лучше использовать для шифрования в Python?
Ответ: Рекомендуется использовать библиотеку cryptography, так как она современная, безопасная и активно поддерживается.

Вопрос: Как зашифровать файл с помощью PyCrypto?
Ответ: Для шифрования файла с помощью PyCrypto нужно прочитать файл в бинарном режиме, зашифровать данные с помощью выбранного алгоритма (например, AES) и записать результат в новый файл.

Вопрос: Что такое кодировки и как они связаны с шифрованием?
Ответ: Кодировки (например, UTF-8, Base64) преобразуют данные в определенный формат. Они часто используются перед шифрованием для подготовки данных или после для представления зашифрованных данных в виде текста.

Вопрос: Как создать ключи RSA в Python?
Ответ: Для создания ключей RSA можно использовать библиотеку cryptography, вызвав функцию rsa.generate_private_key() с указанием длины ключа (например, 2048 бит).

Вопрос: Безопасно ли использовать PyCrypto в новых проектах?
Ответ: PyCrypto считается устаревшей и не рекомендуется для новых проектов. Лучше использовать библиотеку cryptography.

Вопрос: Как расшифровать данные, зашифрованные с помощью пакета cryptography?
Ответ: Для расшифровки используется тот же ключ и метод decrypt() объекта Fernet или соответствующего шифра.

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

Вопрос: Какой алгоритм шифрования самый надежный для Python?
Ответ: Для симметричного шифрования надежным считается AES-256, для асимметричного — RSA с длиной ключа 2048 бит или больше.