Расшифровка AES CBC в Python из OpenSSL AES
Мне нужно расшифровать файл, зашифрованный на OpenSSL, с помощью python, но я не понимаю возможности pycrypto.
Вот что я делаю в OpenSSL
openssl enc -aes-256-cbc -a -salt -pbkdf2 -iter 100000 -in "clear.txt" -out "crypt.txt" -pass pass: "mypassword"
openssl enc -d -aes-256-cbc -a -pbkdf2 -iter 100000 -in "crypt.txt" -out "out.txt" -pass pass: "mypassword"
Я пробовал (что явно не сработает)
obj2 = AES.new("mypassword", AES.MODE_CBC)
output = obj2.decrypt(text)
Я просто хочу сделать второй шаг в python, но, глядя на образец:
https://pypi.org/project/pycrypto/
obj2 = AES.new('This is a key123', AES.MODE_CBC, 'This is an IV456')
obj2.decrypt(ciphertext)
Мне не нужен IV, как мне указать соль? хеш pbkdf2? Я тоже смотрел эту ветку
Как расшифровать файлы с шифрованием OpenSSL AES в Python?
но не помогло.
Может ли кто-нибудь показать мне, как это сделать с помощью Python?
Спасибо.
Ответы
Оператор OpenSSL использует PBKDF2 для создания 32-байтового ключа и 16-байтового IV. Для этого неявно генерируется случайная 8-байтовая соль и применяется указанный пароль, количество итераций и дайджест (по умолчанию: SHA-256). Пара ключ / IV используется для шифрования открытого текста с помощью AES-256 в режиме CBC и заполнения PKCS7, s. здесь . Результат возвращается в формате OpenSSL, который начинается с 8- байтовой ASCII-кодировки Salted__ , за которой следует 8- байтовая соль и фактический зашифрованный текст, все в кодировке Base64. Соль нужна для расшифровки, чтобы можно было восстановить ключ и IV.
Обратите внимание, что пароль в операторе OpenSSL фактически передается без кавычек, то есть в опубликованном операторе OpenSSL кавычки являются частью пароля.
Для дешифрования в Python сначала необходимо определить соль и фактический зашифрованный текст из зашифрованных данных. С солью пара ключ / IV может быть восстановлена. Наконец, пара ключ / IV может использоваться для дешифрования.
Пример: с опубликованным оператором OpenSSL открытый текст
The quick brown fox jumps over the lazy dog
был зашифрован в зашифрованном виде
U2FsdGVkX18A+AhjLZpfOq2HilY+8MyrXcz3lHMdUII2cud0DnnIcAtomToclwWOtUUnoyTY2qCQQXQfwDYotw==
Расшифровка с помощью Python возможна следующим образом (с использованием PyCryptodome ):
from Crypto.Protocol.KDF import PBKDF2
from Crypto.Hash import SHA256
from Crypto.Util.Padding import unpad
from Crypto.Cipher import AES
import base64
# Determine salt and ciphertext
encryptedDataB64 = 'U2FsdGVkX18A+AhjLZpfOq2HilY+8MyrXcz3lHMdUII2cud0DnnIcAtomToclwWOtUUnoyTY2qCQQXQfwDYotw=='
encryptedData = base64.b64decode(encryptedDataB64)
salt = encryptedData[8:16]
ciphertext = encryptedData[16:]
# Reconstruct Key/IV-pair
pbkdf2Hash = PBKDF2(b'"mypassword"', salt, 32 + 16, count=100000, hmac_hash_module=SHA256)
key = pbkdf2Hash[0:32]
iv = pbkdf2Hash[32:32 + 16]
# Decrypt with AES-256 / CBC / PKCS7 Padding
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted = unpad(cipher.decrypt(ciphertext), 16)
print(decrypted)
Изменить - Что касается вашего комментария: 16 МБ должно быть возможно, но для больших данных зашифрованный текст обычно будет считываться из файла, а дешифрованные данные будут записаны в файл, в отличие от примера, опубликованного выше.
Возможность дешифрования данных за один шаг в конечном итоге зависит от доступной памяти. Если памяти недостаточно, данные должны обрабатываться порциями.
При использовании кусков было бы разумнее не кодировать зашифрованные данные Base64, а хранить их непосредственно в двоичном формате. Это возможно, если опустить параметр -a в операторе OpenSSL. В противном случае необходимо гарантировать, что всегда загружаются целые числа, кратные размеру блока (относительно недекодированного зашифрованного текста), где 3 байта незакодированного зашифрованного текста соответствуют 4 байтам зашифрованного текста, закодированного в Base64.
В случае двоичного сохраненного зашифрованного текста: во время дешифрования только первый блок (16 байтов) должен быть (двоичным) считан на первом этапе. Исходя из этого, можно определить соль (байты с 8 по 16), затем ключ и IV (аналогично опубликованному выше коду).
Остальная часть зашифрованного текста может быть (двоична) считана кусками подходящего размера (= кратному размеру блока, например 1024 байта). Каждый фрагмент шифруется / дешифруется отдельно, см. Несколько вызовов шифрования / дешифрования . Для чтения / записи файлов кусками с помощью Python см., Например, здесь .
На дополнительные подробности лучше всего ответить в рамках отдельного вопроса.