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

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

PHP7.4:OpenSSL AES-CFB 加密與 Python 不同

PHP7.4:OpenSSL AES-CFB 加密與 Python 不同

PHP
呼如林 2023-08-11 17:13:21
我正在嘗試使用 PHP7.4 復制一段使用 Pycryptodome 進行 AES-128-CFB 加密的 python 代碼。為此,我使用 PHP 的 openssl_encrypt 內置函數。我嘗試了多種配置參數和 CFB 模式,但始終得到不同的結果。我發現pycryptodomes CFB實現似乎使用8位段大小,這應該是aes-128-cfb8PHP的openssl實現中的模式。IV 故意固定為 0,所以請忽略它不安全的事實。這是我想要復制的代碼,后面是嘗試用不同方法復制結果的 PHP 代碼。有些東西告訴我這與 PHP 的“字節處理”有關,因為 python 區分字節字符串(由 返回.encode('utf-8'))和字符串。最后你可以看到兩個代碼的輸出:Python代碼:import hashlibfrom Crypto.Cipher import AESkey = 'testKey'IV = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'ENC_KEY = hashlib.md5(key.encode('utf-8')).hexdigest()print('key: "' + key + '"')print('hashedKey: ' + ENC_KEY)obj = AES.new(ENC_KEY.encode("utf8"), AES.MODE_CFB, IV.encode("utf8"))test_data = 'test'print('encrypting "' + test_data + '"')encData = obj.encrypt(test_data.encode("utf8"))print('encData: ' + encData.hex())PHP代碼:function encTest($testStr, $ENC_KEY){    $iv = hex2bin('00000000000000000000000000000000');    echo "aes-128-cfb8-1: ".bin2hex(openssl_encrypt($testStr, 'aes-128-cfb8', $ENC_KEY, OPENSSL_RAW_DATA, $iv))."\n";    echo "aes-128-cfb1-1: ".bin2hex(openssl_encrypt($testStr, 'aes-128-cfb1', $ENC_KEY, OPENSSL_RAW_DATA, $iv))."\n";    echo "aes-128-cfb-1: ".bin2hex(openssl_encrypt($testStr, 'aes-128-cfb', $ENC_KEY, OPENSSL_RAW_DATA, $iv))."\n";    echo "\n";    echo "aes-128-cfb8-2: ".bin2hex(openssl_encrypt($testStr, 'aes-128-cfb8', $ENC_KEY, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv))."\n";    echo "aes-128-cfb1-2: ".bin2hex(openssl_encrypt($testStr, 'aes-128-cfb1', $ENC_KEY, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv))."\n";    echo "aes-128-cfb-2: ".bin2hex(openssl_encrypt($testStr, 'aes-128-cfb', $ENC_KEY, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv))."\n";    echo "\n";}
查看完整描述

1 回答

?
墨色風雨

TA貢獻1853條經驗 獲得超6個贊

在 PHP 代碼中(更準確地說是openssl_encrypt),明確指定了 AES 變體,例如當前情況下的aes-128-...,即 PHP 使用 AES-128。太長的鍵會被截斷,太短的鍵會用0值填充。由于hashPHP 代碼中的方法以十六進制字符串形式返回其結果,因此 16 字節 MD5 哈希值由 32 個字符(32 字節)表示,即在當前情況下 PHP 使用密鑰的前 16 個字節 (AES-128)。

Python 代碼中的方法hexdigest也以十六進制字符串形式返回結果。然而,在Python代碼中(更準確地說是PyCryptodome),AES變體由密鑰大小指定,即Python代碼使用完整的32字節密鑰,因此使用AES-256。

不同的密鑰和 AES 變體是導致不同結果的主要原因。要解決此問題,兩個代碼中必須使用相同的密鑰和 AES 變體:

  • 選項 1 是在 Python 代碼中也使用 AES-128。這可以通過以下更改來實現:

    obj?=?AES.new(ENC_KEY[:16].encode("utf8"),?AES.MODE_CFB,?IV.encode("utf8"))

    然后輸出b0016a55是按照 PHP 代碼的結果aes-128-cfb8。

  • 選項 2 是在 PHP 代碼中也使用 AES-256。aes-128...這可以通過替換來完成aes-256...然后輸出是

    aes-256-cfb8-1:?117c1974
    aes-256-cfb1-1:?54096db1
    aes-256-cfb-1?:?11bfdaa9

正如預期的那樣, 的輸出117c1974aes-128-cfb8Python 代碼的原始值相匹配。


CFB 模式將分組密碼更改為流密碼。從而n在每個加密步驟中對位進行加密,這稱為CFBn。

PHP 中也使用術語CFBn(或),即表示 1 位、8 位(= 1 字節)和整個塊(16 字節)的加密。在 Python 中,每步的位數用 指定。cfbnCFB1CFB8CFBsegment_size

...-cfb8即PHP 中的對應項是 Python 中,?PHP 中segment_size = 8的對應項是Python 中。...-cfbsegment_size = 128

下面假設兩個代碼中使用相同的密鑰和相同的 AES 變體。

由于是默認值,Python 代碼的結果與 PHP 代碼的segment_size = 8結果相同。...-cfb8如果選擇在 Python 代碼中,則結果與在 PHP 代碼中segement_size = 128相同。...-cfb但是,在 PyCryptodome 中,該值segment_size必須是 8 的整數倍,否則錯誤消息“segment_size”必須為正數并顯示8 位的倍數。因此,CFB1PyCryptodome 不支持該模式。


另請注意:

  • 摘要的結果也可以在兩種代碼中以二進制形式返回,而不是以十六進制字符串形式返回。為此,hash必須將 PHP 方法的第三個參數設置為TRUE(默認值FALSE:)。在Python中,只需使用digest方法而不是hexdigest.

  • 在 PHP 代碼中,對于像 CFB 這樣的流密碼模式,填充會自動禁用,因此標志OPENSSL_ZERO_PADDING(可用于顯式禁用填充)沒有任何區別。

  • utf8_encode允許您從 ISO-8859-1 編碼轉換為 UTF-8,但由于它$ENC_KEY由字母數字字符(十六進制編碼)組成,因此沒有任何效果。但是,一般來說,任意二進制數據(例如摘要的結果)不得采用 UTF8 編碼,因為這會損壞數據。還有其他用于此目的的編碼,例如 Base64。如果摘要的結果以二進制形式返回(參見第一點),則不能執行 UTF8 編碼。

  • 在 CFB 模式的上下文中,舊版 PyCrypto 庫中存在一個錯誤,該錯誤要求明文的長度是段大小的整數倍。否則會出現以下錯誤:輸入字符串的長度必須是段大小 16 的倍數。


查看完整回答
反對 回復 2023-08-11
  • 1 回答
  • 0 關注
  • 260 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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