EncryptUtils.php 7.4 KB
<?php
/**
 * @note 常用的加密解密
 * @author:wlj
 * @date: 2022/6/10 14:37
 */

namespace App\Utils;


class EncryptUtils
{

    /**
     * @notes: 使用openssl密码库 传入加密算法 des对称加密
     * @param $data
     * @param $key
     * @param $iv
     * @param string $algo
     * @return string
     */
    function openssl_en($data, $key, $iv, $algo = 'DES-EDE3-CBC')
    {
        if (is_array($data) || is_object($data)) {
            $data = json_encode($data, true);
        }

//        $len = strlen($data);
//        if ($len % 8) {
//            $data = str_pad($data, $len + 8 - $len % 8, "\0");
//        }//使用空字符填充字符串的右侧,使字符串位数变为8的倍数


        return base64_encode(openssl_encrypt($data, $algo, $key, /*OPENSSL_RAW_DATA | OPENSSL_NO_PADDING*/ 0, $iv));
    }

    function openssl_de(string $data, $key, $iv, $algo = 'DES-EDE3-CBC')
    {
        $decrypt = rtrim(openssl_decrypt(base64_decode($data), $algo, $key, /*OPENSSL_RAW_DATA | OPENSSL_NO_PADDING*/ 0, $iv), "\0");
        return json_decode($decrypt, true);
    }

    // 加密
    function lock_url($txt, $key = 'blog.qsjob.top')
    {
        $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-=+";
        $nh = rand(0, 64);
        $ch = $chars[$nh];
        $mdKey = md5($key . $ch);
        $mdKey = substr($mdKey, $nh % 8, $nh % 8 + 7);
        $txt = base64_encode($txt);
        $tmp = '';
        $i = 0;
        $j = 0;
        $k = 0;
        for ($i = 0; $i < strlen($txt); $i++) {
            $k = $k == strlen($mdKey) ? 0 : $k;
            $j = ($nh + strpos($chars, $txt[$i]) + ord($mdKey[$k++])) % 64;
            $tmp .= $chars[$j];
        }
        return urlencode($ch . $tmp);
    }

    // 解密
    function unlock_url($txt, $key = 'blog.qsjob.top')
    {
        $txt = urldecode($txt);
        $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-=+";
        $ch = $txt[0];
        $nh = strpos($chars, $ch);
        $mdKey = md5($key . $ch);
        $mdKey = substr($mdKey, $nh % 8, $nh % 8 + 7);
        $txt = substr($txt, 1);
        $tmp = '';
        $i = 0;
        $j = 0;
        $k = 0;
        for ($i = 0; $i < strlen($txt); $i++) {
            $k = $k == strlen($mdKey) ? 0 : $k;
            $j = strpos($chars, $txt[$i]) - $nh - ord($mdKey[$k++]);
            while ($j < 0) {
                $j += 64;
            }
            $tmp .= $chars[$j];
        }
        return base64_decode($tmp);
    }

    // 加密
    //echo lock_url('这是第二种自定义加密解密函数');
    //解密
    //echo unlock_url(lock_url('这是第二种自定义加密解密函数'));

    //加密
    function passport_encrypt($txt, $key = 'blog.qsjob.top')
    {
        srand((double)microtime() * 1000000);
        $encrypt_key = md5(rand(0, 32000));
        $ctr = 0;
        $tmp = '';
        for ($i = 0; $i < strlen($txt); $i++) {
            $ctr = $ctr == strlen($encrypt_key) ? 0 : $ctr;
            $tmp .= $encrypt_key[$ctr] . ($txt[$i] ^ $encrypt_key[$ctr++]);
        }
        return urlencode(base64_encode($this->passport_key($tmp, $key)));
    }

    // 解密
    function passport_decrypt($txt, $key = 'blog.qsjob.top')
    {
        $txt = $this->passport_key(base64_decode(urldecode($txt)), $key);
        $tmp = '';
        for ($i = 0; $i < strlen($txt); $i++) {
            $md5 = $txt[$i];
            $tmp .= $txt[++$i] ^ $md5;
        }
        return $tmp;
    }

    // 解析算法
    function passport_key($txt, $encrypt_key)
    {
        $encrypt_key = md5($encrypt_key);
        $ctr = 0;
        $tmp = '';
        for ($i = 0; $i < strlen($txt); $i++) {
            $ctr = $ctr == strlen($encrypt_key) ? 0 : $ctr;
            $tmp .= $txt[$i] ^ $encrypt_key[$ctr++];
        }
        return $tmp;
    }
    //$txt = "1"; // 加密数据
    //$key = "testkey"; //加密密钥
    ////加密
    //$encrypt = passport_encrypt($txt,$key);
    //echo $encrypt;
    //// 解密
    //echo passport_decrypt($encrypt,$key);
    //


    //非常给力的authcode加密函数,Discuz!经典代码(带详解)
    //函数authcode($string, $operation, $key, $expiry)中的$string:字符串,明文或密文;$operation:DECODE表示解密,其它表示加密;$key:密匙;$expiry:密文有效期。
    function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0)
    {
        // 动态密匙长度,相同的明文会生成不同密文就是依靠动态密匙
        $ckey_length = 4;
        // 密匙
        $key = md5($key ? $key : $GLOBALS['discuz_auth_key']);
        // 密匙a会参与加解密
        $keya = md5(substr($key, 0, 16));
        // 密匙b会用来做数据完整性验证
        $keyb = md5(substr($key, 16, 16));
        // 密匙c用于变化生成的密文
        $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';
        // 参与运算的密匙
        $cryptkey = $keya . md5($keya . $keyc);
        $key_length = strlen($cryptkey);
        // 明文,前10位用来保存时间戳,解密时验证数据有效性,10到26位用来保存$keyb(密匙b),
        //解密时会通过这个密匙验证数据完整性
        // 如果是解码的话,会从第$ckey_length位开始,因为密文前$ckey_length位保存 动态密匙,以保证解密正确
        $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
        $string_length = strlen($string);
        $result = '';
        $box = range(0, 255);
        $rndkey = array();
        // 产生密匙簿
        for ($i = 0; $i <= 255; $i++) {
            $rndkey[$i] = ord($cryptkey[$i % $key_length]);
        }
        // 用固定的算法,打乱密匙簿,增加随机性,好像很复杂,实际上对并不会增加密文的强度
        for ($j = $i = 0; $i < 256; $i++) {
            $j = ($j + $box[$i] + $rndkey[$i]) % 256;
            $tmp = $box[$i];
            $box[$i] = $box[$j];
            $box[$j] = $tmp;
        }
        // 核心加解密部分
        for ($a = $j = $i = 0; $i < $string_length; $i++) {
            $a = ($a + 1) % 256;
            $j = ($j + $box[$a]) % 256;
            $tmp = $box[$a];
            $box[$a] = $box[$j];
            $box[$j] = $tmp;
            // 从密匙簿得出密匙进行异或,再转成字符
            $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
        }
        if ($operation == 'DECODE') {
            // 验证数据有效性,请看未加密明文的格式
            if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
                return substr($result, 26);
            } else {
                return '';
            }
        } else {
            // 把动态密匙保存在密文里,这也是为什么同样的明文,生产不同密文后能解密的原因
            // 因为加密后的密文可能是一些特殊字符,复制过程可能会丢失,所以用base64编码
            return $keyc . str_replace('=', '', base64_encode($result));
        }
    }
    //$str = 'jobhansome';
    //$key = 'blog.qsjob.top';
    //echo authcode($str,'ENCODE',$key,0); //加密
    //$str = '56f4yER1DI2WTzWMqsfPpS9hwyoJnFP2MpC8SOhRrxO7BOk';
    //echo authcode($str,'DECODE',$key,0); //解密

}