1. 程式人生 > >使用PHP實現RSA演算法的加密和解密

使用PHP實現RSA演算法的加密和解密

本文提供使用RSA演算法加密解密資料的PHP程式類(簽名和驗籤的實現方式可以檢視使用PHP實現RSA演算法的簽名和驗籤 這篇文章),封裝了格式化公鑰和私鑰檔案的方法,這樣無論使用什麼格式的公鑰或者私鑰都可以正常執行,公鑰加密後使用私鑰解密或者私鑰加密後用公鑰解密都可以實現。下面是程式碼:

class RSA{

    private $public_key_resource = ''; //公鑰資源
    private $private_key_resource = ''; //私鑰資源
    /**
     * 建構函式
     * @param [string] $public_key  [公鑰資料字串]
     * @param [string] $private_key [私鑰資料字串]
     */
    public function __construct($public_key,$private_key) {
           $this->public_key_resource = !empty($public_key) ? openssl_pkey_get_public($this->get_public_key($public_key)) : false;
		   $this->private_key_resource = !empty($private_key) ? openssl_pkey_get_private($this->get_private_key($private_key)) : false;
    }

	/**
		獲取私有key字串 重新格式化  為保證任何key都可以識別
	*/
	public function get_private_key($private_key){
		$search = [
			"-----BEGIN RSA PRIVATE KEY-----",
			"-----END RSA PRIVATE KEY-----",
			"\n",
			"\r",
			"\r\n"
		];

		$private_key=str_replace($search,"",$private_key);
		return $search[0] . PHP_EOL . wordwrap($private_key, 64, "\n", true) . PHP_EOL . $search[1];
	}


	/**

		獲取公共key字串  重新格式化 為保證任何key都可以識別
	*/

	public function get_public_key($public_key){
		$search = [
			"-----BEGIN PUBLIC KEY-----",
			"-----END PUBLIC KEY-----",
			"\n",
			"\r",
			"\r\n"
		];
		$public_key=str_replace($search,"",$public_key);
		return $search[0] . PHP_EOL . wordwrap($public_key, 64, "\n", true) . PHP_EOL . $search[1];
	}

    /**
     * 生成一對公私鑰 成功返回 公私鑰陣列 失敗 返回 false
     */
    public function create_key() {
        $res = openssl_pkey_new();
        if($res == false) return false;
        openssl_pkey_export($res, $private_key);
        $public_key = openssl_pkey_get_details($res);
        return array('public_key'=>$public_key["key"],'private_key'=>$private_key);
    }
    /**
     * 用私鑰加密
     */
    public function private_encrypt($input) {
        openssl_private_encrypt($input,$output,$this->private_key_resource);
        return base64_encode($output);
    }
    /**
     * 解密 私鑰加密後的密文
     */
    public function public_decrypt($input) {
        openssl_public_decrypt(base64_decode($input),$output,$this->public_key_resource);
        return $output;
    }
    /**
     * 用公鑰加密
     */
    public function public_encrypt($input) {
        openssl_public_encrypt($input,$output,$this->public_key_resource,OPENSSL_PKCS1_OAEP_PADDING);
        return base64_encode($output);
    }
    /**
     * 解密 公鑰加密後的密文
     */
    public function private_decrypt($input) {
        openssl_private_decrypt(base64_decode($input),$output,$this->private_key_resource,OPENSSL_PKCS1_OAEP_PADDING);
        return $output;
    }
}

$rsa = new RSA(file_get_contents('public.txt'),file_get_contents('private.txt'));
//
$str = '這裡是待加密的資料';
echo '<hr>公鑰加密私鑰解密如下:<hr>';
echo '原始資料:',$str,'<br>';
$tmpstr = $rsa->public_encrypt($str); //用公鑰加密
echo '加密後的資料:' . $tmpstr,'</br>';
$tmpstr = $rsa->private_decrypt($tmpstr); //用私鑰解密
echo '解密結果:' . $tmpstr,'<hr>私鑰加密公鑰解密如下:<hr>';
////=============================================================

echo '原始資料:',$str,'<br>';
$tmpstr = $rsa->private_encrypt($str); //用私鑰加密
echo '加密後的資料' . $tmpstr,'</br>';
$tmpstr = $rsa->public_decrypt($tmpstr); //用公密解密
echo '解密結果:' . $tmpstr,'</br>';

提醒:在對接某些介面的時候一定要注意加密解密的填充模式,在上述程式碼中私鑰加密公鑰解密的程式碼使用了預設的填充模式,如果需要更改填充模式只需要增加一個可選引數就可以。為了通用在公鑰加密私鑰解密的程式碼中使用了非預設的OPENSSL_PKCS1_OAEP_PADDING填充模式,這在微信介面中可以正常使用,否則會出現如下錯誤:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xml>
    <err_code>SYSTEMERROR</err_code>
    <err_code_des>解密真實姓名或銀行卡號出錯</err_code_des>
    <result_code>FAIL</result_code>
    <return_code>SUCCESS</return_code>
    <return_msg>引數錯誤,請檢查引數</return_msg>
    <mch_id>1444739402</mch_id>
</xml>