OpenSSL AES에서 Python으로 AES CBC 해독

Sep 30 2020

Python으로 OpenSSL에서 암호화 된 파일의 암호를 해독해야하지만 pycrypto의 옵션을 이해하지 못합니다.

OpenSSL에서 수행하는 작업

  1. openssl enc -aes-256-cbc -a -salt -pbkdf2 -iter 100000 -in "clear.txt"-out "crypt.txt"-pass pass : "mypassword"

  2. 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)

파이썬에서 두 번째 단계를 수행하고 싶지만 샘플을 볼 때 :

https://pypi.org/project/pycrypto/

obj2 = AES.new('This is a key123', AES.MODE_CBC, 'This is an IV456')
obj2.decrypt(ciphertext)

IV가 필요하지 않습니다. 소금은 어떻게 지정합니까? pbkdf2 해시? 나는 또한이 스레드를 본다

Python에서 OpenSSL AES 암호화 파일을 해독하는 방법은 무엇입니까?

그러나 도움이되지 않았습니다.

누군가 파이썬을 사용하여 이것을 수행하는 방법을 보여줄 수 있습니까?

감사합니다.

답변

4 Topaco Sep 30 2020 at 04:16

OpenSSL 문은 PBKDF2를 사용하여 32 바이트 키와 16 바이트 IV를 만듭니다. 이를 위해 임의의 8 바이트 솔트가 암시 적으로 생성되고 지정된 암호, 반복 횟수 및 다이제스트 (기본값 : SHA-256)가 적용됩니다. 키 / IV 쌍은 CBC 모드에서 AES-256 및 PKCS7 패딩, s를 사용하여 일반 텍스트를 암호화하는 데 사용됩니다. 여기 . 결과는 OpenSSL 형식으로 반환됩니다.이 형식은 Salted__ 의 8 바이트 ASCII 인코딩으로 시작 하고 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)

편집 -귀하의 의견과 관련하여 : 16MB가 가능해야하지만, 더 큰 데이터의 경우 일반적으로 파일에서 암호문을 읽고 복호화 된 데이터가 위에 게시 된 예와 달리 파일에 기록됩니다.
데이터를 한 단계로 해독 할 수 있는지 여부는 궁극적으로 사용 가능한 메모리에 따라 다릅니다. 메모리가 충분하지 않으면 데이터를 청크로 처리해야합니다.
청크를 사용할 때 Base64로 암호화 된 데이터를 인코딩하지 않고 바이너리 형식으로 직접 저장하는 것이 더 합리적입니다. OpenSSL 문에서 -a 옵션 을 생략하면 가능 합니다. 그렇지 않으면 블록 크기의 정수 배수 (디코딩되지 않은 암호문에 상대적)가 항상로드되도록해야합니다. 여기서 디코딩 된 암호문의 3 바이트는 Base64로 인코딩 된 암호문의 4 바이트에 해당합니다.

이진 저장 암호문의 경우 : 해독하는 동안 첫 번째 단계에서 첫 번째 블록 (16 바이트) 만 (이진) 읽어야합니다. 이로부터 솔트 (바이트 8 ~ 16), 키 및 IV (위에 게시 된 코드와 유사 함)를 결정할 수 있습니다.
나머지 암호문은 적절한 크기의 청크 (= 블록 크기의 배수, 예 : 1024 바이트)로 (이진) 읽을 수 있습니다. 각 청크는 개별적으로 암호화 / 복호화됩니다. 다중 encrypt / decrypt-calls 참조 . Python을 사용하여 청크 단위로 파일을 읽고 쓰려면 여기를 참조 하십시오 .
자세한 내용은 별도의 질문 범위 내에서 가장 잘 답변됩니다.