<?php

/**
* Ras非对称加解密算法
* 功能:1、生成公钥和私钥
* 2、公钥和私钥的加密和解密
* eg:
* $generatePriAndPub = RsaAlg::generatePriAndPub();
* $rsaAlg = new RsaAlg($generatePriAndPub['pubKey'], $generatePriAndPub['privKey']);//传入秘钥
* //$rsaAlg = new RsaAlg("E:/rsa/rsa_public_key.pem", "E:/rsa/rsa_private_key.pem",true);//传入秘钥文件
* $str = json_encode(['id'=>1,'name'=>"zhuangshan"],true);
* $keyCode = $rsaAlg->public_encrypt($str); //用公密钥加密
* echo $keyCode, '</br>';
* $str = $rsaAlg->private_decrypt($keyCode); //用私密钥解密
* echo $str, '</br>';
* //=============================================================
* $keyCode = $rsaAlg->private_encrypt($str); //用私密钥加密
* echo $keyCode, '</br>';
* $str = $rsaAlg->public_decrypt($keyCode); //用公密钥解密
* echo $str, '</br>';
*/
class RsaAlg
{
private $public_key = ''; //公密钥,可以外部传入 也可以自己生成
private $private_key = ''; //私密钥
private $public_key_resource = ''; //公密钥资源
private $private_key_resource = ''; //私密钥资源

public static $config = array(
"digest_alg" => "sha512",
"private_key_bits" => 2048, //字节数 512 1024 2048 4096 等
"private_key_type" => OPENSSL_KEYTYPE_RSA, //加密类型
);

/**
* 该静态方法用于生成公钥和私钥
*
* 注意 1、window中注意生成非对称秘钥,需要在openssl 的Openssl default config路径中指定正确的默认openssl.cnf
*/
public static function generatePriAndPub()
{
$res = openssl_pkey_new(self::$config);
$privKey = "";
//从得到的资源中获取私钥 并把私钥赋给$privKey
openssl_pkey_export($res, $privKey);
//从得到的资源中获取公钥 并把公钥赋给$pubKey
$pubKey = openssl_pkey_get_details($res);
$pubKey = $pubKey["key"];
return array('privKey' => $privKey, 'pubKey' => $pubKey);
}

/**
* 架构函数
* @param [string] $public_key [公密钥]
* @param [string] $private_key [私密钥]
* @Param isFile true表示文件地址 false 表示内容
*/
public function __construct($public_key, $private_key, $isFile = false)
{
if ($isFile) {
$this->public_key = file_get_contents($public_key);
$this->private_key = file_get_contents($private_key);
} else {
$this->public_key = $public_key;
$this->private_key = $private_key;
}
if (false == ($this->public_key_resource = $this->is_bad_public_key($this->public_key)) || false == ($this->private_key_resource = $this->is_bad_private_key($this->private_key))) {
throw new Exception('public key or private key no usable');
}
}

private function is_bad_public_key($public_key)
{
return openssl_pkey_get_public($public_key);
}

private function is_bad_private_key($private_key)
{
return openssl_pkey_get_private($private_key);
}

/**
* 生成一对公私密钥 成功返回 公私密钥数组 失败 返回 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);
return base64_encode($output);
}

/**
* 解密 公密钥加密后的密文
*/
public function private_decrypt($input)
{
openssl_private_decrypt(base64_decode($input), $output, $this->private_key_resource);
return $output;
}
}

//$generatePriAndPub = RsaAlg::generatePriAndPub();
//$rsaAlg = new RsaAlg($generatePriAndPub['pubKey'], $generatePriAndPub['privKey']);//传入秘钥
//$rsaAlg = new RsaAlg("E:/rsa/rsa_public_key.pem", "E:/rsa/rsa_private_key.pem",true);
//$str = json_encode(['id' => 1, 'name' => "zhuangshan"], true);
//$keyCode = $rsaAlg->public_encrypt($str); //用公密钥加密
//echo $keyCode, '</br>';
//$str = $rsaAlg->private_decrypt($keyCode); //用私密钥解密
//echo $str, '</br>';
////=============================================================
//$keyCode = $rsaAlg->private_encrypt($str); //用私密钥加密
//echo $keyCode, '</br>';
//$str = $rsaAlg->public_decrypt($keyCode); //用公密钥解密
//echo $str, '</br>';