php AES加密解密

php AES加密解密

來自專欄 php 學習

隨筆 - 165 文章 - 0 評論 - 20

PHP AES的加密解密

AES加密演算法

密碼學中的高級加密標準(Advanced Encryption Standard,AES),又稱Rijndael加密法,是美國聯邦政府採用的一種區塊加密標準。這個標準用來替代原先的DES,已經被多方分析且廣為全世界所使用。

解釋來源:baike.so.com/doc/678313

參考:docin.com/p-572103142.h

上一篇 :

PHP 開發API介面簽名驗證

中我們說到了sign簽名,sign其實是防篡改的一種方法,它將約定好的排序、位置、數組進行密鑰加密生成sign對比。

是的,sign簽名我們是能看到數據的,只是可以防止數據的篡改。而AES可以加密解密數據

AES通過約定好的密鑰進行加密,通過約定好的密鑰解密。

ECB加密模式(不推薦):

容易被攻擊

<?php /* * 加密 */

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文件進行部分或者全部加密,而求解器依然能計算?

TAG:加密 | AES加密 | 密碼加密 |