天天看點

ThinkPHP rsa非對稱加密類

公鑰加密後的字元串是一直變化的,但是用私鑰解密後的内容仍然是相同的,這是為了加密資料使用的。

私鑰加密的字元串是不會變化的,即使暴露在外網上别人截取時如果沒有公鑰也是看不出來内容的,僅允許給予公鑰的第三方來解密并看到内容,實際作用相當于簽名功能,如果能拿到未加密的内容,說明一定是信任方的資料,因為有他的簽名啊。

其實這種非對稱加密技術可以用于單點登入中去,安全級别高,能解密擷取到内容應該就是信任方的資料。

<?php

namespace Common\Org;
class RsaCrypt {

    const CERPATH ='../Application/Runtime/Data/server.cer';  //生成證書路徑
    const PFXPATH = '../Application/Runtime/Data/server.pfx';  //秘鑰檔案路徑


    const FILEDIR =  '../Application/Runtime/Data/';
    
     /**
      * 生成公鑰私鑰
      */
     public static function generateCertKey()
     {
        $dn = array('countryName'=>'CN', 'stateOrProvinceName'=>'beijing', 'localityName'=>'beijing','organizationName'=>'clcw',
             'organizationalUnitName'=>'clcw', 'commonName'=>'clcw', 'emailAddress'=>'[email protected]');

        $privkeypass = 'secret';       //私鑰密碼
        $numberOfDays = 365;           //有效時長,機關為天

        //生成證書
        $privkey = openssl_pkey_new();
        $csr = openssl_csr_new($dn, $privkey);
        $sscert = openssl_csr_sign($csr, null, $privkey, $numberOfDays);

        openssl_x509_export_to_file($sscert, self::CERPATH);
        openssl_pkcs12_export_to_file($sscert, self::PFXPATH, $privkey, $privkeypass);

        (file_exists(self::CERPATH)) or die('公鑰的檔案路徑錯誤');
        (file_exists(self::PFXPATH)) or die('密鑰的檔案路徑錯誤');
     }

     public static function verifyData($originData, $decryptData)
     {
        $cer_key = file_get_contents(self::$cerpath);
        $cer = openssl_x509_read($cer_key);
        $res = openssl_verify($originData, $decryptData, $cer);
        var_dump($res);
     }

     /**
      * 生成公鑰私鑰檔案
      * @param $appName string 應用名稱
      */
     public static function generateKey($appName='')
     {
        $result = ['status'=>0, 'msg'=>''];
        if (!extension_loaded('openssl') ) {
            $result['msg'] = 'php需要openssl支援';
        }
        //建立公鑰
        $res = openssl_pkey_new();//array('private_key_bits'=>512) 這一串參數不加,否則隻能加密54個長度的字元串
        //提取私鑰
        openssl_pkey_export($res, $privatekey);
        //生成公鑰
        $public_key = openssl_pkey_get_details($res);
        $publickey = $public_key['key'];

        // $path = self::FILEDIR.$appName;


        try{
            // file_put_contents($path.'_public.pem', $publickey);
            // file_put_contents($path.'_private.pem', $privatekey);
            $result['status'] = 1;
            $result['publickey']  = $publickey;
            $result['privatekey'] = $privatekey;
        }catch(\Exception $e) {
            // throw new \Exception($e->getMessage());
            $result['msg'] = $e->getMessage();
        }
        return $result; 
     }

     /**
      * 用私鑰加密資料
      * @param $data string 需要加密的字元串(最好不要超過200個字元)
      * @param $appName string 應用名稱
      */
     public static function privateEncrypt($data, $appName)
     {
        $result = ['status'=>0, 'msg'=>''];
        $privatekey = C($appName.'.PRIVATE_KEY');

        $myinfo = 'In '.__METHOD__.',privatekey:'.$privatekey."\n";
        file_put_contents('/tmp/shiyf.log', $myinfo, FILE_APPEND);

        //生成resource類型的密鑰,如果密鑰檔案内容被破壞,openssl_pkey_get_private函數傳回false
        $privatekey = openssl_pkey_get_private($privatekey);
        if (empty($privatekey)) {
            $result['msg'] = '密鑰不可用';
        }
        $encryptData = '';
        //用私鑰加密
        if (openssl_private_encrypt($data, $encryptData, $privatekey)) {
            $result['msg'] = base64_encode($encryptData);
            $result['status'] = 1;
        } else {
            $result['msg'] = '加密失敗!';
        }
        return $result;
     }

     /**
      * 用公鑰解密資料
      * @param $data string 需要解密的字元串(最好不要超過200個字元)
      * @param $appName string 應用名稱
      */
     public static function publicDecrypt($data, $appName)
     {
        $result = ['status'=>0, 'msg'=>''];
        $data = base64_decode($data);
        $publickey = C($appName.'.PUBLIC_KEY');
        //生成resource類型的公鑰,如果公鑰檔案内容被破壞,openssl_pkey_get_public函數傳回false
        $publickey = openssl_pkey_get_public($publickey);
        if (empty($publickey)) {
            $result['msg'] = '公鑰不可用';
        }
        //解密資料
        $decryptData = '';
        if (openssl_public_decrypt($data, $decryptData, $publickey)) {
            $result['msg'] =  $decryptData;
            $result['status'] = 1;
        } else {
            $result['msg'] = '解密失敗';
        }
        return $result;
     }


     /**
      * 用公鑰加密資料
      * @param $data string 需要加密的字元串(最好不要超過200個字元)
      * @param $appName string 應用名稱
      */
     public static function publicEncrypt($data, $publickey)
     {
        $result = ['status'=>0, 'msg'=>''];
        //生成resource類型的公鑰,如果公鑰檔案内容被破壞,openssl_pkey_get_private函數傳回false
        $publickey = openssl_pkey_get_public($publickey);
        if (empty($publickey)) {
            $result['msg'] = '公鑰不可用';
        }
        $encryptData = '';
        //用私鑰加密
        if (openssl_public_encrypt($data, $encryptData, $publickey)) {
            $result['msg'] = base64_encode($encryptData);
            $result['status'] = 1;
        } else {
            $result['msg'] = '加密失敗!';
        }
        return $result;
     }

     /**
      * 用私鑰加密資料
      * @param $data string 需要解密的字元串(最好不要超過200個字元)
      * @param $appName string 應用名稱
      */
     public static function privateDecrypt($data, $appName)
     {
        $result = ['status'=>0, 'msg'=>''];
        $data = base64_decode($data);
        $privatekey = C($appName.'.PRIVATE_KEY');
        //生成resource類型的私鑰,如果私鑰檔案内容被破壞,openssl_pkey_get_public函數傳回false
        $privatekey = openssl_pkey_get_private($privatekey);
        if (empty($privatekey)) {
            $result['msg'] = '私鑰不可用';
        }
        //解密資料
        $decryptData = '';
        if (openssl_private_decrypt($data, $decryptData, $privatekey)) {
            $result['msg'] =  $decryptData;
            $result['status'] = 1;
        } else {
            $result['msg'] = '解密失敗';
        }
        return $result;
     }
}