php AES加密解密
來自專欄 php 學習
隨筆 - 165 文章 - 0 評論 - 20
PHP AES的加密解密
AES加密演算法 密碼學中的高級加密標準(Advanced Encryption Standard,AES),又稱Rijndael加密法,是美國聯邦政府採用的一種區塊加密標準。這個標準用來替代原先的DES,已經被多方分析且廣為全世界所使用。 解釋來源:http://baike.so.com/doc/6783134-6999702.html 參考:http://www.docin.com/p-572103142.html 上一篇 : PHP 開發API介面簽名驗證 中我們說到了sign簽名,sign其實是防篡改的一種方法,它將約定好的排序、位置、數組進行密鑰加密生成sign對比。 是的,sign簽名我們是能看到數據的,只是可以防止數據的篡改。而AES可以加密解密數據
AES通過約定好的密鑰進行加密,通過約定好的密鑰解密。
ECB加密模式(不推薦): 容易被攻擊function encrypt($input, $key) {
$size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$input = pkcs5_pad($input, $size);
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, , MCRYPT_MODE_ECB, );
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, hextobin($key), $iv);
$data = mcrypt_generic($td, $input);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
$data = base64_encode($data);
return $data;
}
function pkcs5_pad($text, $blocksize) {
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
/* * 解密 */
function decrypt($sStr, $sKey) {
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, hextobin($sKey), base64_decode($sStr), MCRYPT_MODE_ECB);
$dec_s = strlen($decrypted);
$padding = ord($decrypted[$dec_s - 1]);
$decrypted = substr($decrypted, 0, -$padding);
return $decrypted;
}
function hextobin($hexstr) {
$n = strlen($hexstr);
$sbin = "";
$i = 0;
while ($i < $n) {
$a = substr($hexstr, $i, 2);
$c = pack("H*", $a);
if ($i == 0) {
$sbin = $c;
} else {
$sbin.=$c;
}
$i+=2;
}
return $sbin;
}
define(SECRETKEY, 3163213543213543052abc43edfedus);
//Warning: mcrypt_decrypt(): Key of size 9 not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported
//Warning: pack(): Type H: illegal hex digit s
//Warning: pack(): Type H: illegal hex digit u
# 加密
echo $endata= encrypt(Hello, world! , SECRETKEY);
# 解密
echo $dedata= decrypt($endata, SECRETKEY);
有沒有注意到 代碼中的注釋: Warning: mcrypt_decrypt(): Key of size 9 not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported Warning: pack(): Type H: illegal hex digit s Warning: pack(): Type H: illegal hex digit u
因為加密的密鑰有長度限制所以必須為16、24、32的長度才可以
pack() 16進位轉換為二進位的時候,發現了key密鑰中包含了「s,u」 字元,想想看,16進位最多到F,F以後的字元都是扯蛋 1111 = 8 + 4 + 2 + 1 = 15 =F 1110 = 8 + 4 + 2 + 0 = 14= E 1101 = 8 + 4 + 0 + 1 = 13= D 1100 = 8 + 4 + 0 + 0 = 12 =C 1011 = 8 + 0 + 2 + 1 = 11= B 1010 = 8 + 0 + 2 + 0 = 10 =A 所以生成使用密鑰的時候,我們應該預先生成好16進位的密鑰。 加密後: 4ihVrJk0acwmAF6td5emIkV9T6VnRHYZcW2BUw4CSUQ= 解密後: Hello, world! CBC加密模式 (推薦……): 按 Ctrl+C 複製代碼按 Ctrl+C 複製代碼 列印效果: tZOYOkwxFdkqP6chub5Q8SsH9igXPIKlCNmWxVBjFkM= Hello, world! 使用PKCS5Padding/PKCS7Padding填充可以兼容多平台語言之間AES加密解密(PHP、Java、C……) 注意這裡每次產生的密文是相同的,因為設置了初試向量iv為16位個數的「0」。要產生不同的密文就要使用變化的初試向量iv define(SECRETKEY, 12f862d21d3ceafba1b88e5f22960d55);/** * 加密方法 * @param string $str * @return string */
function encrypt($str) {
//AES, 128 ECB模式加密數據 $str = addPKCS7Padding($str);
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND);
define(A, $iv);
$encrypt_str = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, SECRETKEY, $str, MCRYPT_MODE_CBC, $iv);
return base64_encode($encrypt_str); }
/** * 解密方法 * @param string $str * @return string */
function decrypt($str) {
//AES, 128 ECB模式加密數據 $str = base64_decode($str);
$encrypt_str = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, SECRETKEY, $str, MCRYPT_MODE_CBC,A);
$encrypt_str = stripPKSC7Padding($encrypt_str);
return $encrypt_str; }
/** * 填充演算法 * @param string $source * @return string */
function addPKCS7Padding($source) {
$source = trim($source);
$block = mcrypt_get_block_size(rijndael-128, cbc);
$pad = $block - (strlen($source) % $block);
if ($pad <= $block) {
$char = chr($pad);
$source .= str_repeat($char, $pad);
}
return $source;
}
/** * 移去填充演算法 * @param string $source * @return string */
function stripPKSC7Padding($source) {
$char = substr($source, -1);
$num = ord($char);
$source = substr($source, 0, -$num);
return $source;
}
/** * 加密 */
$string =encrypt(Hello, world!);
print_r($string); echo <hr>;
/** * 解密 */
$string=decrypt($string);
print_r($string);
列印效果: faxcY9iEj4Q+67l2Fd+k+URMp8Y4VVih/JeUSQbYuwKw3u8holL0mdG3Jg51mbPxDFlj76M3dU8jYt2nhtUhxA== tVWCmXvNuOeuWYI6VoSplUtdq+yV66vDr22Bdja2uNVpaftNNU6jwQWth2DD4JxgaL1d3Atv8jZGsoSV6XLJWA== PTjgu8kJ1B7LTm40IXEl6fPVTbQYuETPvjg2miQVVs1i/r+07pjGAfsL5JpSQKOROMX8B3mSiSu/YjubHffkYA== Cb5WjMwb3wOpqCmUWEErPc9sfUEYYiMzvoosYoHdCFq1vh78batnXLbpjOavnCT0Y6y+4jq+fviTmY3plOAK8g== 結果都是: Hello, world! 注意: 這裡面的密鑰define(SECRETKEY, 12f862d21d3ceafba1b88e5f22960d55); 長度為32位,但在嚴格的AES中,加密的密鑰必須與字元串演算法長度一至,(MCRYPT_RIJNDAEL_128、MCRYPT_RIJNDAEL_192、MCRYPT_RIJNDAEL_256) 1 bit 位 = 1 二進位數據 1 byte 位元組 = 8 bit 1 字母 = 1 byte = 8 bit 也就是128位/8=16位元組=16字元 192位/8=24位元組=24字元 256位/8=32位元組=32字元 所以,上面的代碼為了兼容其他Java、C等,密鑰應該改為16位: define(SECRETKEY, 12f862d21d3ceafb) 也可以直接生成一個32位的16進位密鑰用於其他功能的加密(sign簽名),通過hex2bin可以將32位的16進位字元串轉換為16位二進位字元串 生成16進位隨機碼 $num="";for($i=0;$i<32;$i++){
$num .=dechex(rand(0,15));
}
echo $num;
echo $screct_key = hex2bin($num);
echo strlen($screct_key);
列印: 9957a20d097485d608d9f090efe34b9a ?W? t???????K? 16推薦閱讀:
※TLS的密碼學套件
※加密空投,你了解嗎?
※比特幣一度失守8000美元.加密貨幣市值1天蒸發4377億
※BitLocker驅動器加密疑難雜症大曝光
※LS-DYNA種如何對K文件進行部分或者全部加密,而求解器依然能計算?