您的位置 首页 php

在PHP里实现AES的加密解密功能(包括mcrypt版本和openssl版本)

1. 介绍

1.1 介绍

福哥需要在php里使用AES加密解密功能,今天整理出来和大家分享一下。

早期的PHP实现AES借助的是mcrypt扩展,后来在PHP7之后就换成了openssl扩展来实现了。mcrypt版本代码比较复杂且需要自己实现PKCS7补位的逻辑,而openssl版本则默认使用了PKCS7补位不需要自己来编写代码实现了。

2. 通过openssl实现

2.1 安装openssl扩展

需要安装php扩展openssl,具体方法就不提供了,php的扩展的安装方式都一样,php7.1以上的版本支持了openssl模块。

2.2 加密解密对象

加密解密对象,默认 AES-256-CBC 方法。

 class AES_Encrypt{
    const BLOCK_SIZE = 32;

    private string $method;

    public function __construct(string $method = null){
        if($method == null){
            $method = "AES-256-CBC";
        }
        $this->method = $method;
    }

    public function pkcs7Pad($str){
        $len = mb_strlen($str, '8bit');
        $c = 16 - ($len % 16);
        $str .= str_repeat(chr($c), $c);

        return $str;
    }

    private function pkcs7Encode($text){
        $text_length = strlen($text);

        $amount_to_pad = AES_Encrypt::BLOCK_SIZE - ($text_length % AES_Encrypt::BLOCK_SIZE);
        if ($amount_to_pad == 0) {
            $amount_to_pad = AES_Encrypt::BLOCK_SIZE;
        }

        $pad_chr = chr($amount_to_pad);
        $tmp = "";
        for ($index = 0; $index < $amount_to_pad; $index++) {
            $tmp .= $pad_chr;
        }

        return $text . $tmp;
    }

    private function pkcs7Decode($text){
        $pad = ord(substr($text, -1));
        if ($pad < 1 || $pad > 32) {
            $pad = 0;
        }

        return substr($text, 0, (strlen($text) - $pad));
    }

    public function encrypt(string $data, string $key, string $iv):string {
        $data = $this->pkcs7Encode($data);
        $encrypted = openssl_encrypt($data, $this->method, $key,OPENSSL_ZERO_PADDING, $iv);

        return $encrypted;
    }

    public function decrypt(string $data, string $key, string $iv):string {
        $decrypted = openssl_decrypt($data, $this->method, $key,OPENSSL_ZERO_PADDING, $iv);
        $data = $this->pkcs7Decode($decrypted);

        return $data;
    }
}  

2.3 options

openssl_encrypt和openssl_decrypt的第三个参数是options,它有着很重要的作用,我们来了解一下。

  • 0:默认模式,自动进行 pkcs7 补位,同时自动进行 base64 编码
  • 1:OPENSSL_RAW_DATA,自动进行 pkcs7 补位, 但是不自动进行 base64 编码
  • 2:OPENSSL_ZERO_PADDING,需要自己进行 pkcs7 补位,同时自动进行 base64 编码

3. 通过mcrypt实现

3.1 安装mcrypt扩展

需要安装php扩展mcrypt,具体方法就不提供了,php的扩展的安装方式都一样,php7.1以下的版本支持mcrypt模块。

3.2 加密解密对象

加密解密对象,默认 AES-128-CBC 方法。

 class AES_Encrypt{
    const BLOCK_SIZE = 32;

    private $RIJNDAEL;
    private $MODE;

    public function __construct($method = null){
        if($method == null){
            $method = "AES-128-CBC";
        }
        $this->RIJNDAEL = null;
        $this->MODE = null;
        $this->methodArr = explode("-", $method);
        switch($this->methodArr[1]){
            case "128":
                $this->RIJNDAEL = MCRYPT_RIJNDAEL_128;
                break;
            case "192":
                $this->RIJNDAEL = MCRYPT_RIJNDAEL_192;
                break;
            case "256":
                $this->RIJNDAEL = MCRYPT_RIJNDAEL_256;
                break;
        }
        switch($this->methodArr[2]){
            case "CBC":
                $this->MODE = MCRYPT_MODE_CBC;
                break;
            case "CFB":
                $this->MODE = MCRYPT_MODE_CFB;
                break;
            case "ECB":
                $this->MODE = MCRYPT_MODE_ECB;
                break;
            case "NOFB":
                $this->MODE = MCRYPT_MODE_NOFB;
                break;
            case "OFB":
                $this->MODE = MCRYPT_MODE_OFB;
                break;
            case "STREAM":
                $this->MODE = MCRYPT_MODE_STREAM;
                break;
        }
        if($this->RIJNDAEL == null || $this->MODE == null){

            throw new Exception("invalid RIJNDAEL or MODE about '". $method. "'", 2000100);
        }
    }

    public function pkcs7Pad($str){
        $len = mb_strlen($str, '8bit');
        $c = 16 - ($len % 16);
        $str .= str_repeat(chr($c), $c);

        return $str;
    }

    private function pkcs7Encode($text){
        $text_length = strlen($text);

        $amount_to_pad = AES_Encrypt::BLOCK_SIZE - ($text_length % AES_Encrypt::BLOCK_SIZE);
        if ($amount_to_pad == 0) {
            $amount_to_pad = AES_Encrypt::BLOCK_SIZE;
        }

        $pad_chr = chr($amount_to_pad);
        $tmp = "";
        for ($index = 0; $index < $amount_to_pad; $index++) {
            $tmp .= $pad_chr;
        }

        return $text . $tmp;
    }

    private function pkcs7Decode($text){
        $pad = ord(substr($text, -1));
        if ($pad < 1 || $pad > 32) {
            $pad = 0;
        }

        return substr($text, 0, (strlen($text) - $pad));
    }

    public function encrypt($data, $key, $iv){
        $data = $this->pkcs7Encode($data);
        $encrypted = mcrypt_encrypt($this->RIJNDAEL, $key, $data, $this->MODE, $iv);
        $based_encrypted = base64_encode($encrypted);

        return $based_encrypted;
    }

    public function decrypt($data, $key, $iv){
        $data = base64_decode($data);
        $encrypted = mcrypt_decrypt($this->RIJNDAEL, $key, $data, $this->MODE, $iv);
        $encrypted = $this->pkcs7Decode($encrypted);

        return $encrypted;
    }
}  

4. 使用

使用AES加密需要原数据、AES私钥、令牌,下面给出一个例子。

注意:在openssl版本里的AES-256-CBC方法对应mcrypt版本里的AES-128-CBC,也是微信公众号服务器接口使用的AES算法的方法

4.1 示例

准备一个字符串,加密后再解密,最后如果和原字符串相同,证明函数工作正常。

 $dataOrg = "我是福哥,I like coding!!!";
$AESKey = "rN6LfP9qbILPabc938IixdFds3s5ksIqjcPyYxOPx4v";
$iv = "";

// 初始化
$myAES_Encrypt = new AES_Encrypt();

// 加密字符串
$dataEncrypted = $myAES_Encrypt->encrypt($dataOrg, $AESKey, $iv);

// 解密字符串
$dataDecrypted = $myAES_Encrypt->decrypt($dataEncrypted, $AESKey, $iv);

// 比较
var_dump($dataOrg == $dataDecrypted);  

5. 总结

福哥今天给出了两个使用PHP实现AES的加密算法功能的方法,新版本的openssl效率更高、代码更简单,福哥推荐这种方法~~

文章来源:智云一二三科技

文章标题:在PHP里实现AES的加密解密功能(包括mcrypt版本和openssl版本)

文章地址:https://www.zhihuclub.com/76676.shtml

关于作者: 智云科技

热门文章

网站地图