293 lines
8.4 KiB
PHP
293 lines
8.4 KiB
PHP
<?php
|
||
|
||
namespace encryption;
|
||
|
||
class Rsa
|
||
{
|
||
const SIGN_CERT_PWD = '123456'; // 签名证书密码
|
||
private $public_key; // 公钥
|
||
private $private_key; // 私钥
|
||
private $cert_save_path = ''; // 证书文件保存目录
|
||
private $openssl_cnf_path = '/etc/ssl/openssl.cnf';
|
||
protected static $rsa;
|
||
|
||
/**
|
||
* 设私有构造方法防止对象被new
|
||
*/
|
||
private function __construct($config)
|
||
{
|
||
if ($config['public'] && $config['private']) {
|
||
if (is_file($config['public'])) {
|
||
$this->public_key = $this->getPublicKey($config['public']);
|
||
} else {
|
||
$this->public_key = openssl_pkey_get_public($config['public']);
|
||
if (!$this->public_key) {
|
||
die('请检查公钥是否正确');
|
||
}
|
||
}
|
||
|
||
if (is_file($config['private'])) {
|
||
$this->private_key = $this->getPrivateKey($config['private']);
|
||
} else {
|
||
$this->private_key = openssl_pkey_get_private($config['private']);
|
||
if (!$this->private_key) {
|
||
die('请检查私钥是否正确');
|
||
}
|
||
}
|
||
}
|
||
if ($config['cert_save_path']) $this->cert_save_path = $config['cert_save_path'];
|
||
}
|
||
|
||
/**
|
||
* 单例获取对象实例
|
||
*/
|
||
public static function instance($config=array())
|
||
{
|
||
if (!self::$rsa) {
|
||
if (empty($config)) {
|
||
$config = [
|
||
'public' => '',
|
||
'private' => '',
|
||
'cert_save_path' => ''
|
||
];
|
||
}
|
||
self::$rsa = new self($config);
|
||
}
|
||
return self::$rsa;
|
||
}
|
||
|
||
/**
|
||
* 读取文件
|
||
*/
|
||
private function fileGet($file)
|
||
{
|
||
if (!file_exists($file)) {
|
||
die($file . "不是文件");
|
||
}
|
||
return file_get_contents($file);
|
||
}
|
||
|
||
/**
|
||
* 获取公钥
|
||
*/
|
||
private function getPublicKey($path)
|
||
{
|
||
$pubKey = $this->fileGet($path);
|
||
if (!$pubKey) {
|
||
die('请检查公钥路径是否正确');
|
||
}
|
||
return openssl_pkey_get_public($pubKey);
|
||
}
|
||
|
||
/**
|
||
* 获取私钥
|
||
*/
|
||
private function getPrivateKey($path)
|
||
{
|
||
$priKey = $this->fileGet($path);
|
||
if (!$priKey) {
|
||
die('请检查私钥路径是否正确');
|
||
}
|
||
return openssl_pkey_get_private($priKey);
|
||
}
|
||
|
||
/**
|
||
* 使用私钥生成签名
|
||
* @param string 用于生成签名的字符串
|
||
* @return string 签名后的值
|
||
*/
|
||
public function signPrivate($data)
|
||
{
|
||
$signature = false;
|
||
if (openssl_sign($data, $signature, $this->private_key)) {
|
||
$signature = base64_encode($signature);
|
||
}
|
||
return $signature;
|
||
}
|
||
|
||
/**
|
||
* 使用公钥验签
|
||
* @param $data = array('data'='','signature'='')
|
||
* @return bool
|
||
*/
|
||
public function verifyPublic($data)
|
||
{
|
||
$bool = false;
|
||
if (!$data['data'] || !$data['signature']) {
|
||
die('数据源或签名值为出错!');
|
||
}
|
||
$result = base64_decode($data['signature']);
|
||
switch (openssl_verify($data['data'], $result, $this->public_key)) {
|
||
case 1:
|
||
$bool = true;
|
||
break;
|
||
case 0:
|
||
case -1:
|
||
$bool = false;
|
||
break;
|
||
default:
|
||
$bool = false;
|
||
}
|
||
return $bool;
|
||
}
|
||
|
||
/**
|
||
* 使用公钥加密
|
||
*/
|
||
public function encryptPublic($data)
|
||
{
|
||
$crypted = false;
|
||
if (is_array($data)) {
|
||
$data = json_encode($data);
|
||
}
|
||
$cryp = strrev($data); // 将数据前后反转再加密
|
||
if (openssl_public_encrypt($cryp, $crypted, $this->public_key, OPENSSL_PKCS1_PADDING)) {
|
||
$crypted = base64_encode($crypted);
|
||
}
|
||
return $crypted;
|
||
}
|
||
|
||
/**
|
||
* 使用公钥分块加密
|
||
*/
|
||
public function chunkEncryptPublic($data, $limit = 117)
|
||
{
|
||
if (is_array($data)) {
|
||
$data = json_encode($data);
|
||
}
|
||
$datas = str_split($data, $limit);
|
||
|
||
$crypteds = [];
|
||
foreach ($datas as $key => $val) {
|
||
$crypteds[$key] = $this->encryptPublic($val);
|
||
}
|
||
return $crypteds;
|
||
}
|
||
|
||
/**
|
||
* 使用私钥解密
|
||
*/
|
||
public function decryptPrivate($encrypted)
|
||
{
|
||
$decrypted = '';
|
||
$data = base64_decode($encrypted);
|
||
if (openssl_private_decrypt($data, $decrypted, $this->private_key, OPENSSL_PKCS1_PADDING)) {
|
||
$decrypted = rtrim(strrev($decrypted), '\0');
|
||
}
|
||
return $decrypted;
|
||
}
|
||
|
||
/**
|
||
* 使用私钥分块解密
|
||
*/
|
||
public function chunkDecryptPrivate($encrypteds)
|
||
{
|
||
$decrypted = '';
|
||
$encrypteds = htmlspecialchars_decode($encrypteds);
|
||
if (!is_array($encrypteds)) {
|
||
$arr = explode(',', $encrypteds);
|
||
if ($arr) {
|
||
$encrypteds = $arr;
|
||
} else {
|
||
return json_decode($this->decryptPrivate($encrypteds));
|
||
}
|
||
}
|
||
|
||
foreach ($encrypteds as $key => $val) {
|
||
$decrypted .= $this->decryptPrivate($val);
|
||
}
|
||
|
||
$res = json_decode($decrypted, true);
|
||
if (is_array($res)) return $res;
|
||
return json_decode($res, true);
|
||
}
|
||
|
||
/**
|
||
* 生成公私钥
|
||
*/
|
||
public function createRsa($writeFile=false)
|
||
{
|
||
$config = array("config" => $this->openssl_cnf_path);
|
||
|
||
// 生成公私钥
|
||
$privkey = openssl_pkey_new($config);
|
||
openssl_pkey_export($privkey, $private_key, null, $config); // 导出私钥$private_key
|
||
$public_key = openssl_pkey_get_details($privkey); // 导出公钥$public_key
|
||
|
||
if (!$writeFile) {
|
||
return array('private_key' => $private_key, 'public_key' => $public_key['key']);
|
||
}
|
||
|
||
$publicPath = $this->cert_save_path . "rsa_public_key.pem"; // 生成公钥路径
|
||
$privatePath = $this->cert_save_path . "rsa_private_key.pem"; // 私钥文件路径
|
||
|
||
// 生成公钥文件
|
||
if (!is_writeable($publicPath)) {
|
||
chmod($publicPath, 0755);
|
||
}
|
||
$fp = fopen($publicPath, "w");
|
||
fwrite($fp, $public_key['key']);
|
||
fclose($fp);
|
||
// 生成私钥文件
|
||
if (!is_writeable($privatePath)) {
|
||
chmod($privatePath, 0755);
|
||
}
|
||
$fp = fopen($privatePath, "w");
|
||
fwrite($fp, $private_key);
|
||
fclose($fp);
|
||
}
|
||
|
||
/**
|
||
* 生成证书和密钥
|
||
*/
|
||
public function createCsr($writeFile=false)
|
||
{
|
||
$dn = array(
|
||
"countryName" => 'CN', // 所在国家名称
|
||
"stateOrProvinceName" => 'Hunan', // 所在省份名称
|
||
"localityName" => 'Changsha', // 所在城市名称
|
||
"organizationName" => 'opd', // 注册人姓名
|
||
"organizationalUnitName" => 'orico_opd', // 组织名称
|
||
"commonName" => 'orico_opd', // 公共名称
|
||
"emailAddress" => '735273025@qq.com' // 邮箱
|
||
);
|
||
|
||
$privkeypass = self::SIGN_CERT_PWD; //私钥密码
|
||
$config = array(
|
||
"config" => $this->openssl_cnf_path,
|
||
"digest_alg" => "sha1",
|
||
"private_key_bits" => 2048,
|
||
"private_key_type" => OPENSSL_KEYTYPE_DSA,
|
||
"encrypt_key" => false
|
||
);
|
||
|
||
$privkey = openssl_pkey_new($config);
|
||
$csr = openssl_csr_new($dn, $privkey, $config);
|
||
$sscert = openssl_csr_sign($csr, null, $privkey, 365, $config);
|
||
openssl_x509_export($sscert, $csrkey); // 导出证书$csrkey
|
||
openssl_pkcs12_export($sscert, $private_key, $privkey, $privkeypass); // 导出密钥$private_key
|
||
|
||
if (!$writeFile) {
|
||
return array('csrkey' => $csrkey, 'private_key_pfx' => $private_key);
|
||
}
|
||
|
||
$cerpath = $this->cert_save_path . "csrkey.cer"; // 生成证书路径
|
||
$pfxpath = $this->cert_save_path . "private_key.pfx"; // 密钥文件路径
|
||
|
||
// 生成证书文件
|
||
if (!is_writeable($cerpath)) {
|
||
chmod($cerpath, 0755);
|
||
}
|
||
$fp = fopen($cerpath, "w");
|
||
fwrite($fp, $csrkey);
|
||
fclose($fp);
|
||
// 生成密钥文件
|
||
if (!is_writeable($pfxpath)) {
|
||
chmod($pfxpath, 0755);
|
||
}
|
||
$fp = fopen($pfxpath, "w");
|
||
fwrite($fp, $private_key);
|
||
fclose($fp);
|
||
}
|
||
}
|