猿问

在 Python 和 PHP 上解密 AES256

我在使用 AES 加密时遇到问题,使用 PHP 进行加密并使用 Python 进行解密。


为了加密,我使用了这个 PHP 函数:


function cryptpass($arg1) {


    $k = '61b4c705859f4158d38090c1e38e8fdc4f3d29db007f012766276aa498835cf6';

    $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));

    $cipher = base64_encode(openssl_encrypt($arg1,'aes-256-cbc',$k,OPENSSL_RAW_DATA,$iv));

    return urlencode(base64_encode('{"cipher":"'.$cipher.'","i":"'.base64_encode($iv).'"}'));

}

我使用这个 Python 代码来解密:


def decryptpass(info):

   key = '61b4c705859f4158d38090c1e38e8fdc4f3d29db007f012766276aa498835cf6'

   data = json.loads(base64.b64decode(info))

   iv = base64.b64decode(data.get('i'))

   cipher = AES.new(key,AES.MODE_CBC,iv)

   return cipher.decrypt(data.get('cipher'))

但是在运行这段代码时,出现如下错误:


ValueError:AES 密钥的长度必须为 16、24 或 32 个字节


我知道我的密钥有 64 个字节,但 PHP 加密如何使用它?我尝试从密钥中删除最后 32 个字符,但这不起作用。


30秒到达战场
浏览 164回答 1
1回答

慕神8447489

您正在定义一个 64 个字符的密钥;那 64 个字符是十六进制数字既不存在也不存在,openssl_encrypt()不会以任何方式解码十六进制字符,它会逐字使用这些字符。但是,AES-256 仅采用32字节(== 256 位)而不是 64 字节的密钥,并且会openssl_encrypt() 默默地截断密钥。AES.new()另一方面,PyCrypto方法明确告诉您密钥太长,提醒您此处的错误,即您可能应该首先将十六进制密钥解码为字节。如果在 Python 中将密钥减少到 32 个字符,或者在两种情况下将密钥从十六进制转换为字节,则可以成功解密消息:$k = hex2bin('61b4c705859f4158d38090c1e38e8fdc4f3d29db007f012766276aa498835cf6');key = bytes.fromhex('61b4c705859f4158d38090c1e38e8fdc4f3d29db007f012766276aa498835cf6')我强烈建议解码而不是截断;32 个十六进制字符的熵要少得多(字节涵盖尽可能多的可能值,即 32 个十六进制字符的平方可编码值的数量,2 的 256 次方 vs. 2 的 128 次方)。因为base64openssl_encrypt()也对返回值进行编码,所以您需要cipher在 Python 端对值进行 base64 解码:>>> data = json.loads(base64.b64decode(info))>>> data{'cipher': 'Iu9VgH8DdxHdQgnq8o23ew==', 'i': 'Vz+wy5VS6toNHx7MEYl+/A=='}# base64:   ^^^^^^^^^^^^^^^^^^^^^^^^         ^^^^^^^^^^^^^^^^^^^^^^^^最后,向加密消息openssl_encrypt()添加PKCS#7 填充以使其适合 AES 块大小(16 字节),您需要在 Python 端再次删除该填充,PyCryptoAES.decrypt()方法不会为您执行此操作:# Decode from hex to create a key 256 bits (32 bytes) long:key = bytes.fromhex('61b4c705859f4158d38090c1e38e8fdc4f3d29db007f012766276aa498835cf6')# or, if you don't use hex2bin in PHP, truncate to 32 characters# key = b'61b4c705859f4158d38090c1e38e8fdc4f3d29db007f012766276aa498835cf6'[:32]def decryptpass(info):    data = json.loads(base64.b64decode(info))    iv = base64.b64decode(data['i'])    cipher = AES.new(key, AES.MODE_CBC, iv)    padded = cipher.decrypt(base64.b64decode(data['cipher']))    # manual PKCS#7 unpadding    return padded[:-padded[-1:]].decode()但是请注意,PyCrypto 项目已经6 年没有出现在新版本中,因此不应再相信它是安全的。你真的想在这里使用这个cryptography项目:from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modesfrom cryptography.hazmat.primitives import paddingfrom cryptography.hazmat.backends import default_backendkey = bytes.fromhex('61b4c705859f4158d38090c1e38e8fdc4f3d29db007f012766276aa498835cf6')def decrypt_aes_256(key, iv, encrypted):    decryptor = Cipher(        algorithms.AES(key), modes.CBC(iv), default_backend()    ).decryptor()    unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()    decrypted = decryptor.update(encrypted) + decryptor.finalize()    return unpadder.update(decrypted) + unpadder.finalize()def decryptpass(info):    data = json.loads(base64.b64decode(info))    iv = base64.b64decode(data['i'])    encrypted = base64.b64decode(data['cipher'])    return decrypt_aes_256(key, iv, encrypted).decode()演示,首先在 PHP 中:$ php -aInteractive shellphp > function cryptpass($arg1) {php {     $k = hex2bin('61b4c705859f4158d38090c1e38e8fdc4f3d29db007f012766276aa498835cf6');php {     $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));php {     $cipher = base64_encode(openssl_encrypt($arg1,'aes-256-cbc',$k,OPENSSL_RAW_DATA,$iv));php {     return urlencode(base64_encode('{"cipher":"'.$cipher.'","i":"'.base64_encode($iv).'"}'));php { }php > echo cryptpass("Hello, world!");eyJjaXBoZXIiOiJJdTlWZ0g4RGR4SGRRZ25xOG8yM2V3PT0iLCJpIjoiVnord3k1VlM2dG9OSHg3TUVZbCsvQT09In0%3D然后在 Python 中;具有cryptography如上定义的函数:>>> from urllib.parse import unquote>>> info = unquote("eyJjaXBoZXIiOiJJdTlWZ0g4RGR4SGRRZ25xOG8yM2V3PT0iLCJpIjoiVnord3k1VlM2dG9OSHg3TUVZbCsvQT09In0%3D")>>> decryptpass(info)'Hello, world!'
随时随地看视频慕课网APP

相关分类

Python
我要回答