PHP加密解密 第8.2章 AES代码 PHP加密解密 第8.2章 AES代码

2023-06-15

一、介绍

早期的 PHP 实现 AES 借助的是 mcrypt 扩展,后来在 PHP7 之后就换成了 openssl 扩展来实现了。

mcrypt 版本代码比较复杂且需要自己实现 PKCS7 补位的逻辑,而 openssl 版本则默认使用了 PKCS7 补位不需要自己来编写代码实现了。

二、openssl

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

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

class aesHelper extends baseHelper
{
   const BLOCK_SIZE = 32;

   private $method;

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


   private function pkcs7Encode($text): string
   {
       $text_length = strlen($text);
       $amount_to_pad = self::BLOCK_SIZE - ($text_length % self::BLOCK_SIZE);
       if ($amount_to_pad == 0) {
           $amount_to_pad = self::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);
       return openssl_encrypt($data, $this->method, $key,OPENSSL_ZERO_PADDING, $iv);
   }

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

测试

$aesKey = 'lulublog';
$iv = 'L2gZjtlri1KB4hGn';
$aesHelper = new aesHelper('AES-256-CBC');
$encrypt = $aesHelper->encrypt('lulublog欢迎您', $aesKey, $iv);
var_dump($encrypt);
$decrypt = $aesHelper->decrypt($encrypt, $aesKey, $iv);
var_dump($decrypt);

注意

  • 初始化向量 IV 是 16 位的字符串

  • ECB 不需要初始化向量 IV,即 $iv=''

  • 新版本的 openssl 效率更高、代码更简单

三、mcrypt

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

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

class aesMcryptHelper extends baseHelper
{
   const BLOCK_SIZE = 32;

   private $RIJNDAEL;
   private $MODE;
   private $methodArr;

   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 = self::BLOCK_SIZE - ($text_length % self::BLOCK_SIZE);
       if ($amount_to_pad == 0) {
           $amount_to_pad = self::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);
       return base64_encode($encrypted);
   }

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

测试

$aesKey = 'lulubloglulublog';
$iv = 'L2gZjtlri1KB4hGn';
$aesMcryptHelper = new aesMcryptHelper('AES-128-CBC');
$encrypt = $aesMcryptHelper->encrypt('lulublog欢迎您', $aesKey, $iv);
var_dump($encrypt);
$decrypt = $aesMcryptHelper->decrypt($encrypt, $aesKey, $iv);
var_dump($decrypt);

注意

  • aesKey 的长度为:16、24、32

打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开微信扫一扫,即可进行扫码打赏哦

阅读 264