2012-01-10 139 views
1

我有幾個使用OpenSSL加密的字符串。例如:如何使用OpenSSL加密的PyCrypto解密某些內容?

$ echo "original string" | openssl aes-256-cbc -p -a -pass pass:secret 
salt=B898FE40EC8155FD 
key=4899E518743EB0584B0811AE559ED8AD9F0B5FA31B0B998FEB8453B8E3A7B36C 
iv =EFA6105F30F6C462B3D135725A6E1618 
U2FsdGVkX1+4mP5A7IFV/VcgRs4ci/yupMErHjf5bkT5XrcowXK7z3VyyV1l2jvy 

我想用Python解密這些東西。我正在嘗試使用PyCrypto。下面是一個使用上面的數據
的一個實例腳本:

from base64 import b64decode, b64encode 
from hashlib import md5 
from Crypto.Cipher import AES 

secret = 'secret' 
encoded = 'U2FsdGVkX1+4mP5A7IFV/VcgRs4ci/yupMErHjf5bkT5XrcowXK7z3VyyV1l2jvy' 
encrypted = b64decode(encoded) 
salt = encrypted[8:16] 
data = encrypted[16:] 
key = md5(secret + salt).hexdigest() 
iv = md5(key + secret + salt).hexdigest()[0:16] # which 16 bytes? 
dec = AES.new(key, AES.MODE_CBC, iv) 
clear = dec.decrypt(data) 

try: 
    salt_hex = ''.join(["%X" % ord(c) for c in salt]) 
    print 'salt:  %s' % salt_hex 
    print 'expected: %s' % 'B898FE40EC8155FD' 
    print 'key:  %s' % key.upper() 
    print 'expected: %s' % '4899E518743EB0584B0811AE559ED8AD9F0B5FA31B0B998FEB8453B8E3A7B36C' 
    print 'iv:  %s' % iv 
    print 'expected: %s' % 'EFA6105F30F6C462B3D135725A6E1618' 
    print 'result: %s' % clear 
except UnicodeDecodeError: 
    print 'decryption failed' 

這裏的輸出:

salt:     B898FE40EC8155FD 
expected: B898FE40EC8155FD 
key:      4899E518743EB0584B0811AE559ED8AD 
expected: 4899E518743EB0584B0811AE559ED8AD9F0B5FA31B0B998FEB8453B8E3A7B36C 
iv:       17988376b72f4a81 
expected: EFA6105F30F6C462B3D135725A6E1618 
decryption failed 

你可以看到,鹽的比賽,關鍵的是什麼OpenSSL的節目上半場比賽,所以我似乎要在正確的軌道上,但有兩個主要問題:

  1. 爲什麼從OpenSSL的keyiv值的兩倍只要PyCrypto(大概AES256)允許?
  2. 如何生成正確的值?我使用的技術取自a blog,但如果IV始終與塊大小(16字節)匹配,則MD5將無法工作。即使我能夠確定密鑰的另一半來自哪裏,PyCrypto也會因爲太長而拒絕它。

我知道我需要刪除填充,但爲了簡潔起見我省略了這些。

回答

7

你有三個問題:

  1. 你在你的Python代碼使用OpenSSL和AES128(16字節的密鑰)AES256(32字節的密鑰)。
  2. IV計算錯誤。 OpenSSL的密鑰派生函數中的每個步驟都使用最後計算的MD5摘要。
  3. 混淆了二進制和十六進制表示法。作爲最後一步,在可視化之前將任何轉換保留爲十六進制。

下面的代碼應該是正確的:

from base64 import b64decode, b64encode 
from binascii import hexlify 
from Crypto.Cipher import AES 
from Crypto.Hash import MD5 

secret = 'secret' 
encoded = 'U2FsdGVkX1+4mP5A7IFV/VcgRs4ci/yupMErHjf5bkT5XrcowXK7z3VyyV1l2jvy' 
encrypted = b64decode(encoded) 
salt = encrypted[8:16] 
data = encrypted[16:] 

# We need 32 bytes for the AES key, and 16 bytes for the IV 
def openssl_kdf(req): 
    prev = '' 
    while req>0: 
     prev = MD5.new(prev+secret+salt).digest() 
     req -= 16 
     yield prev 
mat = ''.join([ x for x in openssl_kdf(32+16) ]) 
key = mat[0:32] 
iv = mat[32:48] 

dec = AES.new(key, AES.MODE_CBC, iv) 
clear = dec.decrypt(data) 

try: 
    salt_hex = ''.join(["%X" % ord(c) for c in salt]) 
    print 'salt:  %s' % salt_hex 
    print 'expected: %s' % 'B898FE40EC8155FD' 
    print 'key:  %s' % hexlify(key).upper() 
    print 'expected: %s' % '4899E518743EB0584B0811AE559ED8AD9F0B5FA31B0B998FEB8453B8E3A7B36C' 
    print 'iv:  %s' % hexlify(iv).upper() 
    print 'expected: %s' % 'EFA6105F30F6C462B3D135725A6E1618' 
    print 'result: %s' % clear 
except UnicodeDecodeError: 
    print 'decryption failed' 
+0

的偉大工程。謝謝!我想知道第3點,但是由於我對拳頭一半的關鍵字有正確的價值,我認爲這一定是正確的。 (另外,'AES.new'需要一個字符串作爲鍵。) – 2012-01-16 15:45:13