การถอดรหัส 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 ซึ่งเริ่มต้นด้วยการเข้ารหัส ASCII 8 ไบต์ของSalted__ตามด้วยเกลือ 8 ไบต์และไซเฟอร์เท็กซ์จริงเข้ารหัส Base64 ทั้งหมด เกลือเป็นสิ่งจำเป็นสำหรับการถอดรหัสดังนั้นจึงสามารถสร้างคีย์และ IV ขึ้นมาใหม่ได้
โปรดทราบว่ารหัสผ่านในคำสั่ง OpenSSL นั้นถูกส่งผ่านโดยไม่มีเครื่องหมายอัญประกาศกล่าวคือในคำสั่ง OpenSSL ที่โพสต์เครื่องหมายคำพูดเป็นส่วนหนึ่งของรหัสผ่าน
สำหรับการถอดรหัสใน Python นั้นจะต้องกำหนด salt และ ciphertext จากข้อมูลที่เข้ารหัสก่อน ด้วยเกลือสามารถสร้างคีย์ / คู่ IV ขึ้นใหม่ได้ ในที่สุดก็สามารถใช้คู่คีย์ / IV สำหรับการถอดรหัสได้
ตัวอย่าง: ด้วยคำสั่ง OpenSSL ที่โพสต์ข้อความธรรมดา
The quick brown fox jumps over the lazy dog
ถูกเข้ารหัสเป็น ciphertext
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 MB แต่สำหรับข้อมูลที่มีขนาดใหญ่ขึ้นโดยทั่วไปข้อความเข้ารหัสจะถูกอ่านจากไฟล์และข้อมูลที่ถอดรหัสจะถูกเขียนลงในไฟล์ซึ่งตรงกันข้ามกับตัวอย่างที่โพสต์ไว้ด้านบน
การถอดรหัสข้อมูลในขั้นตอนเดียวนั้นขึ้นอยู่กับหน่วยความจำที่มีอยู่หรือไม่ หากหน่วยความจำไม่เพียงพอข้อมูลจะต้องถูกประมวลผลเป็นชิ้น ๆ
เมื่อใช้ชิ้นส่วนมันจะสมเหตุสมผลกว่าที่จะไม่เข้ารหัส Base64 ข้อมูลที่เข้ารหัส แต่เก็บไว้ในรูปแบบไบนารีโดยตรง สิ่งนี้เป็นไปได้โดยการละเว้นอ็อพชัน-aในคำสั่ง OpenSSL มิฉะนั้นจะต้องมั่นใจว่าจะมีการโหลดจำนวนเต็มทวีคูณของขนาดบล็อกเสมอ (เทียบกับไซเฟอร์เท็กซ์ที่ไม่ได้ถอดรหัส) โดยที่ 3 ไบต์ของไซเฟอร์เท็กซ์ที่ไม่ได้ถอดรหัสจะสอดคล้องกับ 4 ไบต์ของการเข้ารหัส Base64
ในกรณีของการเข้ารหัสไบนารีที่เก็บไว้: ในระหว่างการถอดรหัสเฉพาะบล็อกแรก (16 ไบต์) เท่านั้นที่ควรอ่าน (ไบนารี) ในขั้นตอนแรก จากสิ่งนี้สามารถกำหนดเกลือได้ (ไบต์ 8 ถึง 16) จากนั้นคีย์และ IV (คล้ายกับรหัสที่โพสต์ด้านบน)
ส่วนที่เหลือของไซเฟอร์เท็กซ์สามารถ (ไบนารี) อ่านเป็นกลุ่มขนาดที่เหมาะสม (= จำนวนหลายขนาดของบล็อกเช่น 1024 ไบต์) แต่ละกลุ่มจะถูกเข้ารหัส / ถอดรหัสแยกกันดูการเข้ารหัส / ถอดรหัส - การโทรหลายรายการ สำหรับการอ่าน / เขียนไฟล์ใน chunks กับงูหลามเห็นเช่นที่นี่
รายละเอียดเพิ่มเติมเป็นคำตอบที่ดีที่สุดภายในขอบเขตของคำถามแยกต่างหาก