如何使用 PyCrypto 解密使用 OpenSSL 加密的内容?

发布于 2024-12-25 20:33:00 字数 2080 浏览 1 评论 0原文

我有几个使用 OpenSSL 加密的字符串。例如:

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

我想用Python解密这些东西。我正在尝试使用 PyCrypto。这是使用上述数据的 exmaple 脚本:

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. 如何生成正确的值?我使用的技术取自博客,但如果 IV 始终与块大小(16 字节)匹配,则 MD5 将永远无法工作。即使我能弄清楚密钥的另一半来自哪里,PyCrypto 也会因为太长而拒绝它。

我意识到我还需要删除填充,但为了简洁起见,我省略了它。

I have several strings that were encrypted using OpenSSL. For instance:

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

I would like to decrypt these things using Python. I'm attempting to use PyCrypto. Here's an exmaple script using the above data:

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'

Here's the output:

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

You can see that the salt matches, and the key matches the first half of what OpenSSL shows, so I seem to be on the right track, but there are two main questions:

  1. Why are the values for key and iv from OpenSSL twice as long as PyCrypto (and presumably AES256) allows?
  2. How do I generate the correct values? The technique I'm using was taken from a blog, but if the IV is always supposed to match the block size (16 bytes), MD5 will never work. And even if I could figure out where the other half of the key comes from, PyCrypto would refuse it for being too long.

I realize I'll need to remove the padding as well, but I left that out for brevity.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

后eg是否自 2025-01-01 20:33:00

您遇到三个问题:

  1. 您在 OpenSSL 中使用 AES256(32 字节密钥),在 Python 代码中使用 AES128(16 字节密钥)。
  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'

You have three problems:

  1. You use AES256 (32 byte key) in OpenSSL and AES128 (16 byte key) in your python code.
  2. The IV computation is wrong. Each step in the OpenSSL's key derivation function uses the the MD5 digest computed last.
  3. You mix up binary and hexadecimal representation. Keep any conversion to hexadecimal as the last step, before visualization.

The following code should be correct:

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'
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文