Как использовать шифр AES-256: примеры криптографии Python

  • Главная
  • Как использовать шифр AES-256: примеры криптографии Python
Shape Image One
Как использовать шифр AES-256: примеры криптографии Python

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

pip3 install pycryptodomex

Данный алгоритм использует AES-256 в качестве алгоритма блочного шифрования, используя ключ, nonce, сообщение и заголовок в качестве входных данных. Длина заголовка — 16 байт. Зашифрованный текст формируется добавлением аутентификационного тега к промежуточному зашифрованному тексту, полученному в качестве выходных данных GCM-шифрования.

Шифрование

Теперь мы создаем функцию простого шифрования (plain_text, password). Эта функция использует пароль для шифрования простого текста. Поэтому любой, кто имеет доступ к зашифрованному тексту и паролю, сможет его расшифровать.

def encrypt(plain_text, password):
    # generate a random salt
    salt = get_random_bytes(AES.block_size)

    # use the Scrypt KDF to get a private key from the password
    private_key = hashlib.scrypt(
        password.encode(), salt=salt, n=2**14, r=8, p=1, dklen=32)

    # create cipher config
    cipher_config = AES.new(private_key, AES.MODE_GCM)

    # return a dictionary with the encrypted text
    cipher_text, tag = cipher_config.encrypt_and_digest(bytes(plain_text, 'utf-8'))
    return {
        'cipher_text': b64encode(cipher_text).decode('utf-8'),
        'salt': b64encode(salt).decode('utf-8'),
        'nonce': b64encode(cipher_config.nonce).decode('utf-8'),
        'tag': b64encode(tag).decode('utf-8')
    }

Замечания о функции encrypt ()

  1. nonce: случайный одноразовый номер (произвольное значение) должен быть случайным и уникальным значением каждый раз, когда наша функция шифрования используется с тем же ключом. Думайте об этом как о случайной соли для шифра. Библиотека предоставляет нам безопасный одноразовый номер.
  2. Scrypt: Scrypt используется для генерации безопасного закрытого ключа из пароля. 
  3. salt: новая случайная соль используется для каждого запуска нашего шифрования. Это делает невозможным для злоумышленника использовать предварительно вычисленные хэши в попытке взломать шифр.
  4. N является фактором стоимости. Это должно быть степень двойки, и чем он выше, тем надежнее ключ, но для его запуска требуется больше ресурсов.
  5. R — размер блока.
  6. P — коэффициент распараллеливания, полезный для работы на нескольких ядрах.
  7. Base64: мы кодируем все наши данные байтового типа в base64 — удобное строковое представление
  8. Tag: тег используется для аутентификации данных при использовании AES в режиме GCM. Это гарантирует, что никто не сможет изменить наши данные, если мы не узнаем об этом при расшифровке.

Дешифровка

def decrypt(enc_dict, password):
    # decode the dictionary entries from base64
    salt = b64decode(enc_dict['salt'])
    cipher_text = b64decode(enc_dict['cipher_text'])
    nonce = b64decode(enc_dict['nonce'])
    tag = b64decode(enc_dict['tag'])
    

    # generate the private key from the password and salt
    private_key = hashlib.scrypt(
        password.encode(), salt=salt, n=2**14, r=8, p=1, dklen=32)

    # create the cipher config
    cipher = AES.new(private_key, AES.MODE_GCM, nonce=nonce)

    # decrypt the cipher text
    decrypted = cipher.decrypt_and_verify(cipher_text, tag)

    return decrypted

Замечания о функции decrypt ()

Функция decrypt () нуждается в тех же salt, nonce и тag, которые мы использовали для шифрования. Для удобства разбора мы использовали словарь, но если бы вместо этого нам нужна была одна строка зашифрованного текста, мы могли бы использовать такую схему, как salt.nonce.tag.cipher_text. Параметры конфигурации функций Scrypt и AES должны совпадать с функцией шифрования. 

Полный код

Вы, вероятно, хотите увидеть все это в примере сценария. 

# AES 256 encryption/decryption using pycryptodome library

from base64 import b64encode, b64decode
import hashlib
from Cryptodome.Cipher import AES
import os
from Cryptodome.Random import get_random_bytes

def encrypt(plain_text, password):
    # generate a random salt
    salt = get_random_bytes(AES.block_size)

    # use the Scrypt KDF to get a private key from the password
    private_key = hashlib.scrypt(
        password.encode(), salt=salt, n=2**14, r=8, p=1, dklen=32)

    # create cipher config
    cipher_config = AES.new(private_key, AES.MODE_GCM)

    # return a dictionary with the encrypted text
    cipher_text, tag = cipher_config.encrypt_and_digest(bytes(plain_text, 'utf-8'))
    return {
        'cipher_text': b64encode(cipher_text).decode('utf-8'),
        'salt': b64encode(salt).decode('utf-8'),
        'nonce': b64encode(cipher_config.nonce).decode('utf-8'),
        'tag': b64encode(tag).decode('utf-8')
    }


def decrypt(enc_dict, password):
    # decode the dictionary entries from base64
    salt = b64decode(enc_dict['salt'])
    cipher_text = b64decode(enc_dict['cipher_text'])
    nonce = b64decode(enc_dict['nonce'])
    tag = b64decode(enc_dict['tag'])

    
    # generate the private key from the password and salt
    private_key = hashlib.scrypt(
        password.encode(), salt=salt, n=2**14, r=8, p=1, dklen=32)

    # create the cipher config
    cipher = AES.new(private_key, AES.MODE_GCM, nonce=nonce)

    # decrypt the cipher text
    decrypted = cipher.decrypt_and_verify(cipher_text, tag)

    return decrypted


def main():
    password = input("Password: ")

    # First let us encrypt secret message
    encrypted = encrypt("The secretest message here", password)
    print(encrypted)

    # Let us decrypt using our original password
    decrypted = decrypt(encrypted, password)
    print(bytes.decode(decrypted))

main()

Добавить комментарий