Joh*_*y99 2 php encryption interop aes python-3.x
我有一个 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;
}
Run Code Online (Sandbox Code Playgroud)
我在我的 Python 应用程序中收到了这样的消息,剥离了魔法,获取了 base64 字节数据。我找不到样本来制作兼容的 AES 密码来解码此消息的问题。
密钥和“魔法”只是双方预先共享和已知的值,这是正确的吗?我需要静脉注射吗?
Here is Python solution from SO that does not work for my crypted messages.
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'))
Run Code Online (Sandbox Code Playgroud)
It fails on last line with decode problem. "ignore" decoding mode returns empty string.
# with magic: "THISISANENCRYPTEDMESSAGE8wZVLZpm7UNyUf26Kds9Gwl2TBsPRo3zYDFQ59405wI="
# contains: {'test': 'hello world'}
payload = '8wZVLZpm7UNyUf26Kds9Gwl2TBsPRo3zYDFQ59405wI='
aes = AESCipher('abdsbfuibewuiuizasbfeuiwhfashgfh')
print(aes.decrypt(payload))
Run Code Online (Sandbox Code Playgroud)
Raises:
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
Run Code Online (Sandbox Code Playgroud)
What am i missing?
您正在使用Cipher Block Chaining,但没有将 IV 传递给openssl_encrypt(); 这意味着 IV 是 NUL 字节的 16 倍。但是您的 Python 代码使用密钥作为 IV,因此会产生完全不同的解密结果。
接下来,您选择了AES-192-CBC,而不是AES-256-CBC,因此密钥仅使用 192 位。192 位 == 24 字节,而不是您想象的 32位。
您还需要__unpad()完全挂断电话,您的加密数据中没有填充,在解密之前从末尾删除数据只会导致解密失败。
因此,要在 Python 端解密,请使用 24 个字符作为密钥,给出 16 次的 IV \x00,然后传入您从 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'
Run Code Online (Sandbox Code Playgroud)
如果您想使用密钥的完整 32 个字符,请改用 AES-256-CBC。
你真的想产生一个随机的 IV,这样窥探流量的人就无法确定模式(相同的有效负载每次产生相同的加密消息)。生成IV,将其包含在您发送的数据中,并在Python 端提取它以传递给AES.new()函数。
| 归档时间: |
|
| 查看次数: |
5121 次 |
| 最近记录: |