模組和演算法
Mcrypt 主要是使用的Mcrypt 工具來進行加密操作的,所以在CentOS 或其它作業系統中,我們需要安裝libmcrypt-devel 來使用這個擴展。如果 yum 中無法安裝的話,直接更新 yum 來源即可。
Mcrypt 包含很多的模組和演算法。演算法就不用多解釋了,就是用來加密資料的方式。而模組,包括CBC, OFB,CFB 和ECB 這幾種,是一系列的分組、流式加密的模式,有推薦的模組,也有安全的模組,具體的區分大家可以自行查閱相關的資料,這裡我們先看一下我們的環境中所支援的模組和演算法。
$algorithms = @mcrypt_list_algorithms(); print_r($algorithms); // Array // ( // [0] => cast-128 // [1] => gost // [2] => rijndael-128 // [3] => twofish // [4] => arcfour // [5] => cast-256 // [6] => loki97 // [7] => rijndael-192 // [8] => saferplus // [9] => wake // [10] => blowfish-compat // [11] => des // [12] => rijndael-256 // [13] => serpent // [14] => xtea // [15] => blowfish // [16] => enigma // [17] => rc2 // [18] => tripledes // ) $modes = @mcrypt_list_modes(); print_r($modes); // Array // ( // [0] => cbc // [1] => cfb // [2] => ctr // [3] => ecb // [4] => ncfb // [5] => nofb // [6] => ofb // [7] => stream // )
mcrypt_list_algorithms() 函數可以獲得目前環境下所有支援的 Mcrypt 演算法。而 mcrypt_list_modes() 則列印出了目前環境下所有可支援的模組。注意在某些版本的 PHP 或某些系統中,這些內容會有所不同,在使用 Mcrypt 相關的加密能力的時候,這兩項都是相互配合使用的。因此,我們有必要在需要運行 Mcrypt 的環境中預先確定好當前環境下所支援的模組和演算法。
加密解密資料
$key = hash('sha256', 'secret key', true); $input = json_encode(['id'=>1, 'data'=>'Test mcrypt!']); $td = @mcrypt_module_open('rijndael-128', '', 'cbc', ''); $iv = @mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_DEV_URANDOM); @mcrypt_generic_init($td, $key, $iv); $encrypted_data = @mcrypt_generic($td, $input); @mcrypt_generic_deinit($td); @mcrypt_module_close($td); echo $encrypted_data, PHP_EOL; // ��I $�3���gE�ǣu(�9n����� // p�>P $td = @mcrypt_module_open('rijndael-128', '', 'cbc', ''); @mcrypt_generic_init($td, $key, $iv); $data = @mdecrypt_generic($td, $encrypted_data); echo $data, PHP_EOL; // {"id":1,"data":"Test mcrypt!"} @mcrypt_generic_deinit($td); @mcrypt_module_close($td);
程式碼比較多也較亂,我們一塊一塊來看。
首先是我們確定一個加密的 key ,然後 input 就是我們要加密的資料。例如我們要加密一個 json 資料。這個 key 其實字串就可以,但我們這裡也對 key 進行了一次 hash 處理,這個 hash 相關的內容在上一篇文章我們已經詳細的講解過了。
接下來就是使用 mcrypt_module_open() 開啟一個加密模組句柄,這裡我們使用 rijndael-128 演算法和 cbc 模組。然後使用 mcrypt_create_iv() 建立一個 iv ,這個 iv 就是一個初始化向量。初始化向量的值依密碼演算法而不同。最基本的要求是“唯一性”,也就是說同一把金鑰不重複使用同一個初始化向量。這個特性無論在分組加密或流加密中都非常重要。相信大家要是做過微信或支付寶相關的介面通信,在解密驗證資料的時候一定會看過這個 iv 屬性。
使用 mcrypt_generic() 產生加密結果,使用 mcrypt_generic_deinit() 結束產生初始化,最後透過 mcrypt_module_close() 關閉加密模組句柄。這樣,一套 Mcrypt 加密流程就完成了。
同樣的,解密流程和加密流程也是類似的,只是我們使用 mdecrypt_generic() 這個函數來進行解密就可以了。
另一種加密解密資料方式
上面的加密流程非常麻煩且複雜,其實在 Mcrypt 中也提供了更簡單的加密函數。
$string = 'Test MCrypt2'; $algorithm = 'rijndael-128'; $key = md5( "mypassword", true); $iv_length = @mcrypt_get_iv_size( $algorithm, MCRYPT_MODE_CBC ); $iv = @mcrypt_create_iv( $iv_length, MCRYPT_RAND ); $encrypted = @mcrypt_encrypt( $algorithm, $key, $string, MCRYPT_MODE_CBC, $iv ); $result = @mcrypt_decrypt( $algorithm, $key, $encrypted, MCRYPT_MODE_CBC, $iv ); echo $encrypted, PHP_EOL; // \<�`�U��Uf)�Y echo $result, PHP_EOL; // Test MCrypt2
我們仍然要準備好要加密的數據,演算法,key ,以及 iv 向量。然後直接使用 mcrypt_encrypt() 和 mcrypt_decrypt() 來進行加/解密就可以了,是不是方便很多。
總結
相對於 Hash 來說,Mcrypt 是可解密的對稱加密形式。關於什麼是對稱和非對稱加密,我們將在 OpenSSL 擴展的學習中詳細地講解,而 Hash 加密則是單向的加密形式,是無法透過加密後的資料反向計算獲得原始資料的。它們都有不同的應用場景,不過就像PHP 提示的那樣,Mcrypt 已經是不推薦使用的擴展了,所以我們在這裡只是簡單的進行了加/解密的測試而已,如果有用到的小伙伴,可以根據手冊進行更深入地學習。
測試程式碼:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202007/source/PHP%E7%9A%84Mcrypt%E5%8A%A0%E5%AF%86%E6%89%A9%E5%B1%95%E7%9F%A5%E8%AF%86%E4%BA%86%E8%A7%A3.php