1. 程式人生 > >PHP用openssl_encrypt代替mcrypt_encrypt

PHP用openssl_encrypt代替mcrypt_encrypt

每個人都應該已經停止使用PHP Mcrypt擴充套件程式進行新的工作,並且應該計劃將其現有的應用程式關閉,因為libmcrypt在2003年被放棄,並且不被保護。
我認為最好的選擇是OpenSSL。近年來熱度很高,但我認為對稱塊加密是一個很好的選擇。 (我可能會解釋為什麼我這麼想呢)
PHP中的 openssl_encrypt()和openssl_decrypt()的文件有點缺乏。本文旨在填補一些空白。這是兩者的簽名。

string openssl_encrypt ( string $data , string $method , string $key [, int $

options = 0 [, string $iv = “” ]] )

string openssl_decrypt ( string $data , string $method , string $key [, int $options = 0 [, string $iv = “” ]] )

我們將始終使用一個初始化向量,結果是$options有很大的不同,所以我們可以簡化:

string openssl_encrypt ( string $data , string $method , string $key , int $options, string $iv )

string openssl_decrypt ( string $data , string $method , string $password , int $options, string $iv )

其中$opention將是OPENSSL_RAW_DATAOPENSSL_ZERO_PADDING

它們還需要為您使用的密碼演算法準備好金鑰。我只使用金鑰大小為16位元組的AES-128。如果您通過openssl_en/decrypt()一個金鑰(在$ password引數中)長於密碼的本質金鑰大小,則會將該餘數丟棄。如果通過一個短於預期的鍵,則填充為零,即\x00位元組。

所以你需要仔細準備你的鑰匙。如果使用者提供密碼,請使用類似PBKDF2的特殊鹽。如果您有輸入加密金鑰,則可以使用HKDF匯出openssl_en/decrypt()的金鑰。

所以讓我們再簡化一下:

string openssl_encrypt ( string $data , string $method , string $key , int $options, string $iv )

string openssl_decrypt ( string $data , string $method , string $key , int $options, string $iv )

如果您正在生成金鑰,而不是從使用者輸入金鑰或密碼中匯出金鑰,則應使用從加密安全偽隨機數生成器或CSPRNG中提取的隨機位元組的二進位制字串.(我也許會部落格介紹如何在PHP中獲取這樣的字串,實際上並不像呼叫openssl_random_pseudo_bytes()一樣簡單。)

初始化向量 $iv

初始化向量$iv的要求類似於$password的要求。它應該是與密碼塊大小相同長度的二進位制字串。過多的位元組被丟棄,並且太短的$iv被填充到零位元組的塊大小。

初始化向量應該是來自CSPRNG的隨機位元組的二進位制串。不要重複使用IV。

密碼規範 $method

$method允許值由PHP平臺上的openssl_get_cipher_methods()函式列出,並在openssl enc文件中更詳細地列出。
我不打算討論這些的相對優點。我唯一使用的是CBC模式的AES。除了RC5(由RAS獲得專利但未被廣泛使用)外,OpenSSL提供的所有其他對稱塊密碼都具有64位或更小的塊。
我總是使用AES-128,它有一個16位元組的鍵。所以這意味著我會選擇“AES-128-CBC”。我想你可以安全地選擇’AES-192-CBC’或’AES-256-CBC’,但是我不會被引用到最好的論點。
在任何情況下,$method都必須是openssl_get_cipher_methods()返回的字串之一,您必須使用適當長度的$iv$key才能使用該密碼。

編碼、填充和OPENSSL_RAW_DATAOPENSSL_ZERO_PADDING

在Mcrypt中,加密和解密的輸入和輸出編碼是原始的二進位制字串。 Paintext和ciphertext都是二進位制字串。

在CBC或ECB模式下使用塊密碼加密之前,Mcrypt會自動將零位元組填充新增到明文中,並在解密之後返回零位元組填充的明文(即,Mcrypt在解密之後不刪除填充)。

注意:以下是錯誤,請參閱下面My1的註釋。選項表示兩個標誌:將OPENSSL_RAW_DATA位設定為使用二進位制字串,並將其設定為base64。設定OPENSSL_ZERO_PADDING位來進行自己的填充或取消設定,openssl_en/decrypt()做PKCS7填充。

OpenSSL有兩種模式:
$options = OPENSSL_RAW_DATA

– openssl_encrypt()和openssl_decrypt()的輸入和輸出編碼都是二進位制字串,即plaintext和cipertext都是二進位制字串。
– openssl_encrypt()在CBC或ECB模式下使用塊密碼加密之前,將PKCS7填充新增到明文中。 –
– openssl_decrypt()解密之後剝離填充。

$ options = OPENSSL_ZERO_PADDING

– openssl_encrypt()的輸入編碼和openssl_decrypt()的輸出編碼是原始的二進位制字串,即明文是原始的二進位制字串。
– 輸出編碼fron openssl_encrypt()和對openssl_decrypt()的輸入編碼是base64,即密文是base64編碼的。
– openssl_encrypt()的輸入大小必須是塊大小的整數倍,否則返回錯誤程式碼。 –
– openssl_encrypt()不新增填充,或者由openssl_decrypt()刪除,

可以做任何工作,但我更喜歡OPENSSL_RAW_DATA。如果我需要密文的特定編碼,那我寧願自己做。而PKCS7將是我的填充選擇,實際上這是我用於Mcrypt的。

總結

已經弄清了這兩個功能的所有這些未記錄的功能,結果是我打算使用OpenSSL進行對稱加密的唯一方法是這樣的:

$ciphertext = openssl_encrypt($plaintext, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
$plaintext = openssl_decrypt($ciphertext, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);

其中:

$plaintext是任何字串,任何長度。
– $key16位元組長的二進位制字串形式的加密金鑰(因為AES-128的金鑰大小為16位元組)
– $iv是一個16位位元組長的加密安全隨機二進位制字串(因為AES具有16個位元組的塊大小),我將只使用一次
– $ciphertext是一個比$plaintext116個位元組之間的二進位制字串(因為PKCS7填充到16位元組塊大小)

並記住加密金鑰必須從輸入金鑰材料或密碼中正確派生或由CSPRNG生成。

結語

記住,如果您需要加密資料,那麼您幾乎肯定也需要進行身份驗證。為此,您可以使用HMAC簽名。使用SHA-2演算法之一。 還要記住最後簽名並進行認證,即HMAC需要覆蓋包含加密資料的整個訊息

原文:https://coderlife.cn/1624.html

http://www.lilinjian.com/web/2018/01/18/php72-AES.html