Descriptografando AES CBC em python de OpenSSL AES
Preciso descriptografar um arquivo criptografado em OpenSSL com python, mas não estou entendendo as opções de pycrypto.
Aqui está o que eu faço no 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"
Eu tentei (o que obviamente não funcionará)
obj2 = AES.new("mypassword", AES.MODE_CBC)
output = obj2.decrypt(text)
Eu só quero fazer a segunda etapa em python, mas ao olhar para o exemplo:
https://pypi.org/project/pycrypto/
obj2 = AES.new('This is a key123', AES.MODE_CBC, 'This is an IV456')
obj2.decrypt(ciphertext)
Eu não preciso de IV, como especifico o sal? o hash pbkdf2? Eu também olhei para este tópico
Como descriptografar arquivos criptografados OpenSSL AES em Python?
mas não ajudou.
Alguém pode me mostrar como fazer isso usando python?
obrigado.
Respostas
A instrução OpenSSL usa PBKDF2 para criar uma chave de 32 bytes e um IV de 16 bytes. Para isso, um salt aleatório de 8 bytes é gerado implicitamente e a senha especificada, a contagem de iteração e o resumo (padrão: SHA-256) são aplicados. O par chave / IV é usado para criptografar o texto simples com AES-256 no modo CBC e preenchimento PKCS7, s. aqui . O resultado é retornado no formato OpenSSL, que começa com a codificação ASCII de 8 bytes de Salted__ , seguido pelo sal de 8 bytes e o texto cifrado real, todos codificados em Base64. O sal é necessário para a descriptografia, para que a chave e o IV possam ser reconstruídos.
Observe que a senha na instrução OpenSSL é, na verdade, passada sem aspas, ou seja, na instrução OpenSSL postada, as aspas fazem parte da senha.
Para a descriptografia em Python, o salt e o texto cifrado real devem primeiro ser determinados a partir dos dados criptografados. Com o sal, o par chave / IV pode ser reconstruído. Finalmente, o par chave / IV pode ser usado para descriptografia.
Exemplo: com a instrução OpenSSL postada, o texto simples
The quick brown fox jumps over the lazy dog
foi criptografado no texto cifrado
U2FsdGVkX18A+AhjLZpfOq2HilY+8MyrXcz3lHMdUII2cud0DnnIcAtomToclwWOtUUnoyTY2qCQQXQfwDYotw==
A descriptografia com Python é possível da seguinte forma (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 - Com relação ao seu comentário: 16 MB deve ser possível, mas para dados maiores, o texto cifrado geralmente seria lido de um arquivo e os dados descriptografados seriam gravados em um arquivo, em contraste com o exemplo postado acima.
Se os dados podem ser descriptografados em uma etapa, em última análise, depende da memória disponível. Se a memória não for suficiente, os dados devem ser processados em blocos.
Ao usar blocos, faria mais sentido não codificar os dados criptografados em Base64, mas armazená-los diretamente no formato binário. Isso é possível omitindo o -aopção na instrução OpenSSL. Caso contrário, deve-se garantir que sempre múltiplos inteiros do tamanho do bloco (em relação ao texto cifrado não codificado) sejam carregados, onde 3 bytes do texto cifrado não decodificado correspondem a 4 bytes do texto cifrado codificado em Base64.
No caso do texto cifrado armazenado binário: Durante a descriptografia, apenas o primeiro bloco (16 bytes) deve ser (binário) lido na primeira etapa. A partir disso, o sal pode ser determinado (os bytes 8 a 16), depois a chave e o IV (análogo ao código postado acima).
O resto do texto cifrado pode ser lido (binário) em pedaços de tamanho adequado (= um múltiplo do tamanho do bloco, por exemplo, 1024 bytes). Cada pedaço é criptografado / descriptografado separadamente, consulte várias chamadas para criptografar / descriptografar . Para ler / gravar arquivos em blocos com Python, veja, por exemplo, aqui .
Mais detalhes são respondidos melhor dentro do escopo de uma pergunta separada.