Descifrando AES CBC en python de OpenSSL AES
Necesito descifrar un archivo cifrado en OpenSSL con python pero no entiendo las opciones de pycrypto.
Aquí lo que hago en 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"
Lo intenté (que obviamente no funcionará)
obj2 = AES.new("mypassword", AES.MODE_CBC)
output = obj2.decrypt(text)
Solo quiero hacer el segundo paso en Python, pero al mirar la muestra:
https://pypi.org/project/pycrypto/
obj2 = AES.new('This is a key123', AES.MODE_CBC, 'This is an IV456')
obj2.decrypt(ciphertext)
No necesito IV, ¿cómo especifico la sal? el hash pbkdf2? También me miran este hilo
¿Cómo descifrar archivos cifrados con OpenSSL AES en Python?
pero no ayudó.
¿Alguien puede mostrarme cómo hacer esto usando Python?
gracias.
Respuestas
La declaración OpenSSL usa PBKDF2 para crear una clave de 32 bytes y un IV de 16 bytes. Para esto, se genera implícitamente un salt aleatorio de 8 bytes y se aplican la contraseña especificada, el recuento de iteraciones y el resumen (predeterminado: SHA-256). El par clave / IV se utiliza para cifrar el texto sin formato con AES-256 en modo CBC y relleno PKCS7, s. aquí . El resultado se devuelve en formato OpenSSL, que comienza con la codificación ASCII de 8 bytes de Salted__ , seguida de la sal de 8 bytes y el texto cifrado real, todos codificados en Base64. La sal es necesaria para el descifrado, de modo que la clave y el IV se puedan reconstruir.
Tenga en cuenta que la contraseña en la declaración OpenSSL en realidad se pasa sin comillas, es decir, en la declaración OpenSSL publicada, las comillas son parte de la contraseña.
Para el descifrado en Python, la sal y el texto cifrado real deben determinarse primero a partir de los datos cifrados. Con la sal se puede reconstruir el par clave / IV. Finalmente, el par clave / IV se puede utilizar para el descifrado.
Ejemplo: con la declaración OpenSSL publicada, el texto sin formato
The quick brown fox jumps over the lazy dog
fue encriptado en el texto cifrado
U2FsdGVkX18A+AhjLZpfOq2HilY+8MyrXcz3lHMdUII2cud0DnnIcAtomToclwWOtUUnoyTY2qCQQXQfwDYotw==
El descifrado con Python es posible de la siguiente manera (usando 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)
Editar - Con respecto a su comentario: 16 MB deberían ser posibles, pero para datos más grandes, el texto cifrado generalmente se leería de un archivo y los datos descifrados se escribirían en un archivo, en contraste con el ejemplo publicado anteriormente.
La posibilidad de descifrar los datos en un solo paso depende en última instancia de la memoria disponible. Si la memoria no es suficiente, los datos deben procesarse en trozos.
Al usar fragmentos, tendría más sentido no codificar en Base64 los datos cifrados, sino almacenarlos directamente en formato binario. Esto es posible omitiendo la -aopción en la declaración OpenSSL. De lo contrario, debe asegurarse de que siempre se carguen múltiplos enteros del tamaño del bloque (en relación con el texto cifrado sin codificar), donde 3 bytes del texto cifrado sin codificar corresponden a 4 bytes del texto cifrado codificado en Base64.
En el caso del texto cifrado almacenado en binario: Durante el descifrado, solo se debe leer (binario) el primer bloque (16 bytes) en el primer paso. A partir de esto, se puede determinar la sal (los bytes 8 a 16), luego la clave y el IV (análogo al código publicado arriba).
El resto del texto cifrado se puede leer (binario) en fragmentos de tamaño adecuado (= un múltiplo del tamaño del bloque, por ejemplo, 1024 bytes). Cada fragmento se cifra / descifra por separado, consulte múltiples llamadas cifradas / descifradas . Para leer / escribir archivos en fragmentos con Python, consulte, por ejemplo, aquí .
Los detalles adicionales se responden mejor dentro del alcance de una pregunta separada.