当前位置: 首页 > 知识库问答 >
问题:

使用openssl_encrypt AES-CBC实现Python到PHP兼容的AES加密

潘皓
2023-03-14

我有一个Python应用程序和PHP网站,通过一些特定的网络层发送消息进行通信。我的任务是使用该通道发送所有AES加密和Base64编码的消息。加密密钥是为双方手动预共享的。

在PHP中,我使用以下代码创建名为$payload的最终消息文本:

 $key = substr('abdsbfuibewuiuizasbfeuiwhfashgfhj56urfgh56rt7856rh', 0, 32);
 $magic = 'THISISANENCRYPTEDMESSAGE';

 function crypted($data) {
      global $key, $magic;

       // serialize
       $payload = json_encode($data);

       // encrypt and get base64 string with padding (==):
       $payload = @openssl_encrypt($payload, 'AES-192-CBC', $key);

       // prepend with magic
       $payload = $magic.$payload;
       return $payload;
    }

我在我的Python应用程序中收到这样的消息,去掉了魔力,得到了base64字节的数据。我找不到一个示例来使兼容的AES密码来解码此消息的问题。

Key和“Magic”只是双方预先共享和已知的值,这是正确的吗?我需要静脉注射吗?

这里是Python解决方案,所以它对我的加密消息不起作用。

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


class AESCipher:

    class InvalidBlockSizeError(Exception):
        """Raised for invalid block sizes"""
        pass

    def __init__(self, key):
        self.key = key
        self.iv = bytes(key[0:16], 'utf-8')

    def __pad(self, text):
        text_length = len(text)
        amount_to_pad = AES.block_size - (text_length % AES.block_size)
        if amount_to_pad == 0:
            amount_to_pad = AES.block_size
        pad = chr(amount_to_pad)
        return text + pad * amount_to_pad

    def __unpad(self, text):
        pad = ord(text[-1])
        return text[:-pad]

    def encrypt( self, raw ):
        raw = self.__pad(raw)
        cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
        return b64encode(cipher.encrypt(raw))

    def decrypt( self, enc ):
        enc = b64decode(enc)
        cipher = AES.new(self.key, AES.MODE_CBC, self.iv )
        r = cipher.decrypt(enc)  # type: bytes
        return self.__unpad(r.decode("utf-8", errors='strict'))

由于解码问题,它在最后一行失败。“忽略”解码模式返回空字符串。

# with magic: "THISISANENCRYPTEDMESSAGE8wZVLZpm7UNyUf26Kds9Gwl2TBsPRo3zYDFQ59405wI="
# contains: {'test': 'hello world'}
payload = '8wZVLZpm7UNyUf26Kds9Gwl2TBsPRo3zYDFQ59405wI='

aes = AESCipher('abdsbfuibewuiuizasbfeuiwhfashgfh')
print(aes.decrypt(payload))

加薪:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "../test.py", line 36, in decrypt
    return self.__unpad(cipher.decrypt(enc).decode("utf-8"))
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x9e in position 0: invalid start byte

我错过了什么?

共有1个答案

夔高寒
2023-03-14

您正在使用密码块链接,但没有向openSSL_encrypt()传递IV;这意味着IV是NUL字节的16倍。但是您的Python代码使用密钥作为IV,因此将产生完全不同的解密结果。

接下来,选择aes-192-cbc,而不是aes-256-cbc,因此只有192位用于密钥。192位==24字节,而不是你想象的32。

您还需要完全删除__unpad()html" target="_blank">调用,加密数据中没有填充,在解密之前从末尾删除数据只会导致解密失败。

因此,要在Python端解密,使用24个字符作为密钥,给出一个16倍\x00的IV,并传入从base64解码的所有数据:

>>> from Crypto.Cipher import AES
>>> from base64 import b64decode
>>> key = 'abdsbfuibewuiuizasbfeuiwhfashgfh'[:24]
>>> key
'abdsbfuibewuiuizasbfeuiw'
>>> payload = '8wZVLZpm7UNyUf26Kds9Gwl2TBsPRo3zYDFQ59405wI='
>>> enc = b64decode(payload)
>>> cipher = AES.new(key, AES.MODE_CBC, '\x00' * 16)
>>> cipher.decrypt(enc)
b'{"test":"hello world"}\n\n\n\n\n\n\n\n\n\n'

如果要使用完整的32个字符的密钥,请改用AES-256-CBC。

您真的希望产生一个随机的IV,这样窥探通信量的人就无法确定模式(相同的有效负载每次产生相同的加密消息)。生成IV,将其包含在发送的数据中,并在Python端提取它以传递给aes.new()函数。

 类似资料:
  • 我已经从这个站点编译了一些AES实现代码,它应该执行128位密钥加密。我测试了可以正常工作的加密/解密程序。 然而,如果我用上面提到的代码加密任何东西,然后尝试用linux内置的openssl工具解密,我就是无法解密它,它甚至会记录错误的幻数错误。同样,如果我用openssl加密任何东西,并尝试用代码解密,那么就不会起作用。我试过两个cbc欧洲央行。 如果他们都在实施AES,它不应该以同样的方式工

  • 并在Javascript函数中替换这一行: 用这个: 这个很管用!但是对于我自己的密码&我加密的数据,这个JS解密代码不起作用。请帮帮我?

  • 我只想用这3种模式测试openSSL中的AES:128192和256密钥长度,但我解密的文本与我的输入不同,我不知道为什么。此外,当我传递一个巨大的输入长度(比如1024字节)时,我的程序显示。。。我的意见总是一样的,但这并不重要,至少现在是这样。代码如下: 编辑: 当我将输出大小更改为而不是时,我得到了结果: 那么,是否有可能存在Outpus大小和IV大小的问题?它们应该有什么尺寸(AES-CB

  • 我最近在Java中使用了AES CBC 128算法来加密数据。现在我需要用PHP重建算法,但我不知道如何重建,因为互联网上的PHP算法返回不同的结果。也许你能帮我。 这是要加密的Java代码: 这是我的php代码: 当我从java加密加密数据时,此结果无法在Php解密上解密。 你们能帮我构建一个PHP脚本吗?它可以返回与java加密相同的结果?

  • 我已经设法使它能够处理不包含og a-zA-Z0-9之外的字符和一些特殊字符的文本,但如果我使用丹麦字母,如ielouangØ,解密的文本会显示?而不是实际的字母。所有文件都保存为UTF-8,头字符集=UTF-8 Javascript - input: "tester for php: 我试过选项0,OPENSSL_ZERO_PADDING和OPENSSL_RAW_DATA,结果相同。有人能帮我吗

  • 问题内容: Java 256位AES加密 基本上,我正在做的是编写一个程序,该程序将加密通过TCP / IP发送的请求,然后由服务器程序解密。加密将需要是AES,并且进行一些研究后发现我需要使用CBC和PKCS5Padding。所以基本上我也需要一个秘密密钥和一个IV。 我正在开发的应用程序是用于手机的,因此我想使用Java安全包来减小尺寸。我已经完成了设计,但是不确定IV和共享密钥的实现。 这是