zoukankan      html  css  js  c++  java
  • PHP AES的加密解密-----【弃用】

    mcrypt_decrypt在PHP7.*已经被弃用,取而代之的是openssl_decrypt/encrypt,请参考:

    PHP7.* 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加密模式(不推荐):

    容易被攻击

    <?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加密模式 (推荐……)

    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_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
  • 相关阅读:
    数据结构之链表
    非常好的Java反射例子
    return和finally的执行和联系
    struts2中的OGNL详解
    解耦与耦合的你我他
    struts2案例
    《使用Hibernate开发租房系统》内部测试笔试题
    一对多双向关联关系
    Oracle基本数据类型
    transactionManager的type与dataSource的type
  • 原文地址:https://www.cnblogs.com/dcb3688/p/4608007.html
Copyright © 2011-2022 走看看