Шифрование / дешифрование данных в Python с солью - PullRequest
16 голосов
/ 21 июня 2011

Я хотел бы знать, в основном, как я могу зашифровать данные сгенерированным солт-ключом, а затем расшифровать их с помощью python?

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

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

Я обнаружил, что модуль mcrypt лучше всего с этим работает, но не так много документации для модуля python-mcrypt (в настоящее время он устарел и не поддерживается).

Ответы [ 2 ]

44 голосов
/ 24 июня 2011

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

В своем ответе я использовал pycrypto, поэтому нам нужно импортировать несколько таких библиотек.

import Crypto.Random
from Crypto.Cipher import AES
import hashlib

Чтобы улучшить читабельность, я определил несколько констант, которые я буду использовать позже.

# salt size in bytes
SALT_SIZE = 16

# number of iterations in the key generation
NUMBER_OF_ITERATIONS = 20

# the size multiple required for AES
AES_MULTIPLE = 16

Чтобы использовать соль, я разработал схему шифрования на основе пароля. Я использовал стандарт RSA PKCS # 5 для генерации и заполнения ключей шифрования на основе пароля, адаптированный для алгоритма шифрования AES.

Для генерации ключа пароль и соль объединяются. Эта комбинация хэшируется столько раз, сколько требуется.

def generate_key(password, salt, iterations):
    assert iterations > 0

    key = password + salt

    for i in range(iterations):
        key = hashlib.sha256(key).digest()  

    return key

Чтобы дополнить текст, вы выясните, сколько дополнительных байтов у вас есть, помимо четного числа, равного 16. Если это 0, вы добавляете 16 байтов заполнения, если это 1, вы добавляете 15 и т. Д. всегда добавляйте отступы. Символ, которым вы дополняете, является символом с тем же значением, что и число байтов заполнения (chr(padding_size)), чтобы помочь удалить заполнение в конце (ord(padded_text[-1])).

def pad_text(text, multiple):
    extra_bytes = len(text) % multiple

    padding_size = multiple - extra_bytes

    padding = chr(padding_size) * padding_size

    padded_text = text + padding

    return padded_text

def unpad_text(padded_text):
    padding_size = ord(padded_text[-1])

    text = padded_text[:-padding_size]

    return text

Шифрование требует генерации случайной соли и использования ее вместе с паролем для генерации ключа шифрования. Текст дополняется с помощью вышеуказанной функции pad_text, а затем шифруется с помощью объекта шифрования. Зашифрованный текст и соль объединяются и возвращаются в результате. Если вы хотите отправить его в виде открытого текста, вам необходимо закодировать его с помощью base64.

def encrypt(plaintext, password):
    salt = Crypto.Random.get_random_bytes(SALT_SIZE)

    key = generate_key(password, salt, NUMBER_OF_ITERATIONS)

    cipher = AES.new(key, AES.MODE_ECB)

    padded_plaintext = pad_text(plaintext, AES_MULTIPLE)

    ciphertext = cipher.encrypt(padded_plaintext)

    ciphertext_with_salt = salt + ciphertext

    return ciphertext_with_salt

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

def decrypt(ciphertext, password):
    salt = ciphertext[0:SALT_SIZE]

    ciphertext_sans_salt = ciphertext[SALT_SIZE:]

    key = generate_key(password, salt, NUMBER_OF_ITERATIONS)

    cipher = AES.new(key, AES.MODE_ECB)

    padded_plaintext = cipher.decrypt(ciphertext_sans_salt)

    plaintext = unpad_text(padded_plaintext)

    return plaintext

Дайте мне знать, если у вас есть другие вопросы / разъяснения.

1 голос
/ 06 сентября 2016

Вам не нужно ничего, кроме RNCryptor :

import rncryptor

data = '...'
password = '...'

# rncryptor.RNCryptor's methods
cryptor = rncryptor.RNCryptor()
encrypted_data = cryptor.encrypt(data, password)
decrypted_data = cryptor.decrypt(encrypted_data, password)
assert data == decrypted_data

# rncryptor's functions
encrypted_data = rncryptor.encrypt(data, password)
decrypted_data = rncryptor.decrypt(encrypted_data, password)
assert data == decrypted_data

Он обеспечивает семантически безопасное (случайное соль и IV для каждого шифрования) шифрование и включает в себябезопасная проверка целостности (зашифрованный текст не может быть изменен без уведомления) через HMAC.

RNCryptor также имеет определенный формат данных, поэтому вам не нужно думать об этом и реализациях во многих языках .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...