亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在 Python 和 PHP 上解密 AES256

在 Python 和 PHP 上解密 AES256

30秒到達戰場 2021-11-30 15:45:16
我在使用 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 個字符,但這不起作用。
查看完整描述

1 回答

?
慕神8447489

TA貢獻1780條經驗 獲得超1個贊

您正在定義一個 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 塊大?。?6 字節),您需要在 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, modes

from cryptography.hazmat.primitives import padding

from cryptography.hazmat.backends import default_backend


key = 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 -a

Interactive shell


php > 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!'


查看完整回答
反對 回復 2021-11-30
  • 1 回答
  • 0 關注
  • 217 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號