概要:
php從7.0升級到7.1廢棄了一個擴展,即mcrypt擴展,雖然安裝上擴展也能正常使用,但是會發出警告,告訴我們mcrypt相關方法已經被廢棄,到了7.2,已經被移除,因此不建議繼續使用。
來源:
在使用微信,淘寶第三方開發文檔的時候,很多地方還是沿用以前的加密方法,這個時候我們需要找到替換的方法,openssl就是不錯的選擇,這就需要我們清楚mcrypt和openssl之間的差異,以便保證數據加解密的一致性。
詳解mcrypt和openssl來實現AES-128/192/256-CBC加解密:
一 要點注意:
1 使用何種填充算法。mcrypt自動使用NUL("\0"),openssl自動使用PKCS7
2 是否對數據做了base64編碼處理。mcrypt默認不使用,openssl默認使用
二 算法演示
1 NUL("\0")填充算法
Mcrypt 的默認填充算法。NUL 即為 Ascii 表的編號為 0 的元素,即空元素,轉移字符是 "\0",PHP 的 pack 打包函數在 'a' 模式下就是以 NUL 字符對內容進行填充的,當然,使用 "\0" 手動拼接也是可以的。
/** * NUL("\0")填充算法 * @param string $source * @param string $cipher * @param string $mode * @return string */ public function addZeroPadding($source, $cipher = MCRYPT_RIJNDAEL_128, $mode = MCRYPT_MODE_CBC) { $source = trim($source); // openssl 並沒有提供加密cipher對應的數據塊大小的api這點比較坑 $block = mcrypt_get_block_size($cipher, $mode); $pad = $block - (strlen($source) % $block); if ($pad <= $block) { // $source .= str_repeat("\0", $pad);//KISS寫法 // pack 方法 a 模式使用 NUL("\0") 對內容進行填充 A 模式則使用空白字符填充 $source .= pack("a{$pad}", ""); //高端寫法 } return $source; } /** * NUL("\0")填充算法移除 * @param string $source * @return string */ function stripZeroPadding($source) { return rtrim($source, "\0"); }
2 PKCS7 填充算法
OpenSSL的默認填充算法。下面我們給出 PKCS7 填充算法 PHP 的實現
/** * PKCS7填充算法 * @param string $source * @param string $cipher * @param string $mode * @return string */ function addPKCS7Padding($source, $cipher = MCRYPT_RIJNDAEL_128, $mode = MCRYPT_MODE_CBC) { $source = trim($source); $block = mcrypt_get_block_size($cipher, $mode); $pad = $block - (strlen($source) % $block); if ($pad <= $block) { $char = chr($pad); $source .= str_repeat($char, $pad); } return $source; } /** * 移去PKCS7填充算法 * @param string $source * @return string */ function stripPKSC7Padding($source) { $source = trim($source); $char = substr($source, -1); $num = ord($char); if ($num == 62) { return $source; } $source = substr($source, 0, -$num); return $source; }
涉及知識講解:
1 AES詳解:
AES是當前最為常用的安全對稱加密算法
AES-128:16位密鑰key
AES-192:24位密鑰key
AES-256:32位密鑰key
即算法統一使用MCRYPT_RIJNDAEL_128,並通過key的位數來選定是以何種AES標准加密,iv固定16位(openssl的AES加密iv始終為16位),mode選用CBC模式
2 openssl講解:
openssl是一個功能強大的工具包,它集成了眾多算法,我們既可以利用它提供的命令台工具生成密鑰,證書來加解密文件,也可以利用其提供的API接口在代碼中對傳輸信息進行加密。mctypt需要將加密算法分為cipher+mode去指定,openssl則只需要直接指定method即可。並且提供了三種處理模式,即默認模式0/OPENSSL_RAW_DATA/OPENSSL_ZERO_PADDING。
openssl加解密函數中,options參數尤為重要,它是兼容mcrypt算法的關鍵:
options = 0:默認模式,自動對明文進行pkcs7 padding,且數據做base64編碼處理
options = 1:OPENSSL_RAW_DATA,自動對明文進行pkcs7 padding,數據未經base64編碼處理
options = 2:OPENSSL_ZERO_PADDING,要求待加密的數據長度已按"\0"填充與加密算法數據塊長度對齊,即同mcrypt默認填充的方式一致,且對數據做base64編碼處理(此模式下openssl要求待加密數據已按"\0"填充好,其並不會自動幫你填充數據)。
案例詳解:
mcrypt加密
private static $iv = “1122334455667788"; public static function encrypt($input, $key) { $key = base64_decode($key); $localIV = Security::$iv; $module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, $localIV); mcrypt_generic_init($module, $key, $localIV); $size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); $pad = $size - (strlen($input) % $size); $input . str_repeat(chr($pad), $pad); $data = mcrypt_generic($module, $input); mcrypt_generic_deinit($module); mcrypt_module_close($module); $data = base64_encode($data); return $data; }
openssl解密
private $hex_iv = '0102030405060708'; private $key = ''; public function decrypt_($input) { $input = base64_decode($input); $decrypted = openssl_decrypt( $input, 'AES-128-CBC', $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->hex_iv ); $dec_s = strlen($decrypted); $padding = ord($decrypted[$dec_s-1]); $decrypted = substr($decrypted, 0, -$padding); return $decrypted; }
mcrypt相關函數詳解:
mcrypt_module_open 打開加密算法和模式
參數1使用加密算法的名稱,對應mcrypt_list_algorithms()輸出的加密算法;參數3支持的加密模式,對應mcrypt_list_modes()輸出的加密模式
mcrypt_generic_init 初始化加密緩沖區
參數1為返回的加密描述符,參數2為加密密鑰,參數3為初始化向量
mcrypt_get_block_size 取得編碼方式的區塊大小
參數1為加密算法,參數3為加密模式
mcrypt_generic 數據加密
參數1為返回的加密描述符,參數2為加密錢的數據,返回加密后字符串
mcrypt_generic_deinit 結束加密,執行清理工作
mcrypt_module_close 關閉資源退出
以上就是這次的全部內容