基於openssl的AES加解密

對於加解密,企業常用的有AES和RSA,它們分別是對稱加解密算法和非對稱加解密算法的代表,這裏主要封裝了php的一套基於openssl的AES加解密實現類

<?php
/**
 * Created by PhpStorm.
 * User: 小小徐
 * Date: 2019/4/21
 * Time: 18:11
 */
class BaseAES{
    /**
     * 初始化向量長度|隨機向量長度
     */
    const INIT_VECTOR_LENGTH = 16;
    /**
     * 常見的的兩種AES加密128|256
     */
    const CIPHER128 = 'AES-128-CBC';
    const CIPHER256 = 'AES-256-CBC';
    /**
     * @var string 加解密方式
     */
    protected static $method ;
    /**
     * 加密|解密字符
     * @var null|string
     */
    protected $data;
    /**
     * 隨機偏移量
     * @var string
     */
    protected $initVector;
    /**
     * 錯誤信息
     * @var null|string
     */
    protected $errorMessage;

    /**
     * 構造函數
     * @param string $initVector 偏移量
     * @param string|null $data 加解密數據
     * @param string|null $errorMessage 錯誤信息
     */
    public function __construct($initVector, $data = null, $errorMessage = null)
    {
        $this->initVector = $initVector;
        $this->data = $data;
        $this->errorMessage = $errorMessage;
    }

    /**
     * 校驗密鑰長度
     * @param string $secretKey 16/24/32 -characters secret password
     * @return bool
     */
    protected static function isKeyLengthValid($secretKey)
    {
        $length = strlen($secretKey);
        return $length == 16 || $length == 24 || $length == 32;
    }

    /**
     * 獲取加解密的字符串
     * @return string|null
     */
    public function getData()
    {
        return $this->data;
    }

    /**
     * 獲取隨機偏移量
     * @return string|null
     */
    public function getInitVector()
    {
        return $this->initVector;
    }

    /**
     * 獲取錯誤信息
     * @return string|null
     */
    public function getErrorMessage()
    {
        return $this->errorMessage;
    }

    /**
     * 判斷是否有錯誤
     * @return bool
     */
    public function hasError()
    {
        return $this->errorMessage !== null;
    }

    /**
     * @return null|string
     */
    public function __toString()
    {
        return $this->getData();
    }

    /**
     * 基於openssl的解密方法
     * @param string  $plainText  需要解密的字符串
     * @param string  $secretKey  密鑰長度16|24|32
     * @param string  $initVector 偏移量
     * @param string  $method  解密方式
     * @return static
     */
    public static function decrypt($cipherText, $secretKey,$initVector=null, $method= null)
    {
        try {
            // 校驗密鑰長度
            if (!static::isKeyLengthValid($secretKey)) {
                throw new \InvalidArgumentException("Secret key's length must be 128, 192 or 256 bits");
            }
            // 獲取原加密後的字符串
            $encoded = base64_decode($cipherText);
            //獲取解密方式
            if(null === $method){
                $method = self::CIPHER128;
            }
            
            // 獲取真正加密後的原始串
            $data = static ::decryptCallBack($initVector,$encoded);
            //  解密
            $decoded = openssl_decrypt(
                $data,
                $method,
                $secretKey,
                OPENSSL_RAW_DATA,
                $initVector
            );
            if ($decoded === false) {
                // Operation failed
                return new static(isset($initVector), null, openssl_error_string());
            }
            // 返回一個自己的對象 可以再進行進一步操作
            return new static($initVector, $decoded);
        } catch (\Exception $e) {
            // Operation failed
            return new static(isset($initVector), null, $e->getMessage());
        }
    }

    /**
     * 基於openssl的加密方法
     * @param string  $plainText  需要加密的字符串
     * @param string  $secretKey  密鑰長度16|24|32
     * @param string  $initVector 偏移量
     * @param string  $method  加密方式
     * @return static
     */
    protected static function encrypt($plainText, $secretKey,$initVector=null, $method= null)
    {
        try {
            //校驗密鑰長度
            if (!static::isKeyLengthValid($secretKey)) {
                throw new \InvalidArgumentException("Secret key's length must be 128, 192 or 256 bits");
            }
            //設置加密方式
            if(null === $method){
                $method = self::CIPHER128;
            }
            // 生成隨機向量 即偏移量
            if(null === $initVector){
                $initVector = bin2hex(openssl_random_pseudo_bytes(static::INIT_VECTOR_LENGTH / 2));
            }
            //加密
            $raw = openssl_encrypt(
                $plainText,
                $method,
                $secretKey,
                OPENSSL_RAW_DATA,
                $initVector
            );
            //對加密後的原始數據和偏移量進行操作
            $callBackResult = static ::encryptCallBack($initVector,$raw);
            // Return base64-encoded string:  $callBackResult result |將數據進行base64_encode
            $result = base64_encode($callBackResult);
            if ($result === false) {
                // Operation failed
                return new static($initVector, null, openssl_error_string());
            }
            // 返回自己的對象方便進一步操作
            return new static($initVector, $result);
        } catch (\Exception $e) {
            // Operation failed
            return new static(isset($initVector), null, $e->getMessage());
        }
    }

    /**
     * 與decryptCallBack相對應
     * 在加密後和base64_encode之前 對 加密後的原始數據與偏移量進行操作
     * @param $initVector string 偏移量
     * @param $raw  string 加密後的原始串[非utf8]
     * @return string
     */
    protected static function encryptCallBack($initVector,$raw){
        return $initVector.$raw;
    }

    /**
     * 與encryptCallBack相對應
     * 在base64_decode之後和解密之前 對 需要解密的字符串進行base64_decode之後的原始數據與偏移量進行操作
     * @param $initVector  string 偏移量
     * @param $encoded  string 解密後的原始串[非utf8]
     * @return bool|string
     */
    protected static function decryptCallBack(&$initVector,$encoded){
        // 獲取偏移量
        if( null === $initVector){
            $initVector = substr($encoded, 0, static::INIT_VECTOR_LENGTH);
        }
        return substr($encoded, static::INIT_VECTOR_LENGTH);
    }


    /**
     * AES128加密
     * @param $plainText string 需要加密的字符串
     * @param $secretKey string 密鑰
     * @param $initVector string 偏移量
     * @return BaseAES
     */
    public static function encryptWith128CBC($plainText, $secretKey,$initVector=null)
    {
           return self::encrypt($plainText,$secretKey,$initVector);
    }

    /**
     * AES128解密
     * @param $cipherText string  需要解密的字符串
     * @param $secretKey  string  密鑰
     * @param $initVector string 偏移量
     */
    public static function decryptWith128CBC($cipherText, $secretKey,$initVector=null)
    {
        return self::decrypt($cipherText, $secretKey,$initVector);
    }

    /**
     * AES256加密
     * @param $plainText string 需要加密的字符串
     * @param $secretKey string 密鑰
     * @param $initVector string 偏移量
     * @return BaseAES
     */
    public static function encryptWith256CBC($plainText, $secretKey,$initVector=null)
    {
        return self::encrypt($plainText,$secretKey,$initVector,self::CIPHER256);
    }

    /**
     * AES256解密
     * @param $cipherText string  需要解密的字符串
     * @param $secretKey  string  密鑰
     * @param $initVector string 偏移量
     */
    public static function decryptWith256CBC($cipherText, $secretKey,$initVector=null)
    {
        return self::decrypt($cipherText, $secretKey,$initVector,self::CIPHER256);
    }

}

使用方式

$key = 'zxcvbnmasdfghjkl';
$data = "who are you!";
$res1 = BaseAES::encryptWith256CBC($data,$key);
$res2 = BaseAES::decryptWith256CBC($res1,$key);
var_dump($res1);
var_dump($res2);

爲了滿足更特殊的需求,返回的是一個對象,包含加密|解密的數據及隨機生成的偏移量以滿足特殊的使用場景

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章