PHP AES的加密解密-----【棄用】

mcrypt_decrypt在PHP7.*已經被棄用,取而代之的是openssl_decrypt/encrypt,請參考:

PHP7.* AES的加密解密

 

AES加密算法

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

解釋來源:http://baike.so.com/doc/6783134-6999702.htmlhtml

參考:http://www.docin.com/p-572103142.htmlgit

 

上一篇 :算法

PHP 開發API接口簽名驗證

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

是的,sign簽名咱們是能看到數據的,只是能夠防止數據的篡改。而AES能夠加密解密數據post

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

 

ECB加密模式(不推薦):加密

 

容易被攻擊url

 

 

<?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);

 

 

有沒有注意到 代碼中的註釋:spa

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

由於加密的密鑰有長度限制因此必須爲1六、2四、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加密模式 (推薦……)

 

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);
    $encrypt_str = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, SECRETKEY, $str, MCRYPT_MODE_CBC, '0000000000000000');
    return base64_encode($encrypt_str);
}

/**
 * 解密方法
 * @param string $str
 * @return string
 */
function decrypt($str) {
    //AES, 128 CBC模式加密數據
    $str = base64_decode($str);
    $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND);
    $encrypt_str = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, SECRETKEY, $str, MCRYPT_MODE_CBC, '0000000000000000');
    $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);

打印效果:

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_12八、MCRYPT_RIJNDAEL_19二、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
相關文章
相關標籤/搜索