获取私钥资源
$config = [
"digest_alg" => "sha512",//摘要算法或签名哈希算法
"private_key_bits" => 1024,//字节数 512 1024 2048 4096 等
"private_key_type" => OPENSSL_KEYTYPE_RSA, //加密类型
"config" => "D:\phpstudy_pro\Extensions\Apache2.4.39\conf\openssl.cnf",//openssl.cnf配置路径
];
//生成一个私钥资源
$opensslPkey = openssl_pkey_new($config);
最后一个配置可以不要,但是在windows环境下如果没有配置环境变量也不传当前参数的话是获取不到私钥资源的。
下面这个是在百度上搜索到openssl_pkey_new返回false时的解决方案,如果你配置了最后一个config配置的话一般不会出现以下错误
导出私钥
//导出私钥
$res = openssl_pkey_export($opensslPkey,$private_key,null,$config);
//第一个参数是私钥资源
//第二个参数是私钥存储变量
//第三个参数 密钥可以通过值为passphrase的密码来保护
//第四个参数是配置数组
导出公钥
//导出公钥 传入的值是私钥资源
$public_key = openssl_pkey_get_details($opensslPkey);
公钥加密
openssl_public_encrypt($data,$key,$public_key);
// 第一个参数 需要加密的数据
//第二个参数 接收加密字符串
//第三个参数 公钥
私钥解密
openssl_private_decrypt($key,$data,$private_key);
// 第一个参数 加密的字符串
//第二个参数 接收解密的数据
//第三个参数 私钥
贴上一段自己写的公钥私钥自签证书等代码
//openssl公私钥配置
"openssl" => [
//生成openssl公私钥资源配置
"config" =>[
"digest_alg" => "sha512",//摘要算法或签名哈希算法
"private_key_bits" => 1024,//字节数 512 1024 2048 4096 等
"private_key_type" => OPENSSL_KEYTYPE_RSA, //加密类型
"config" => "D:\phpstudy_pro\Extensions\Apache2.4.39\conf\openssl.cnf",//openssl.cnf配置路径
],
//私钥密码
"privkey_passwd" => "123123",
//证书有效时间
"valid_day" => 365,
//证书路径
"cer_path" => ".././certificate/openssl_cert.cer",
//密钥文件路径
"pfx_path" => ".././certificate/openssl_cert.pfx",
//生成自签证书配置
"dn" => [
"countryName" => "CN", //所在国家
"stateOrProvinceName" => "Guizhou", //所在省份
"localityName" => "Guiyang", //所在城市
"organizationName" => "Shen zengxuan", //注册人姓名
"organizationalUnitName" => "Guiyang Youjie Technology", //组织名称
"commonName" => "Youjie Technology", //公共名称
"emailAddress" => "522717820@qq.com" //邮箱
],
],
class OpenSSL
{
//获取私钥公钥自签证书等配置
public $openssl = [];
//私钥
public $private_key = "";
//公钥
public $public_key = "";
public function __construct()
{
//获取配置
$this->openssl = config("ywds.openssl");
//获取私钥公钥
$this->getCert(false);
}
/**
* @Notes 获取公钥和私钥
* @Author shenzx
* @Date 2020-10-13 17:36
* @return array|bool
*/
public function getCert($is_reset){
//判断配置是否为空
if(empty($this->openssl)){
return false;
}
//判断两个文件是否存在
if($is_reset || !file_exists($this->openssl["cer_path"]) || !file_exists($this->openssl["pfx_path"]) ){
//生成一个私钥资源
$opensslPkey = openssl_pkey_new($this->openssl["config"]);
//判断获取结果
if($opensslPkey == false){
return false;
}
//导出私钥并处理密钥 不处理过的密钥导不出公钥
$res = openssl_pkey_export($opensslPkey,$private_key,null,$this->openssl["config"]);
//判断处理结果
if($res == false){
return false;
}
//导出公钥
$public_key = openssl_pkey_get_details($opensslPkey);
$public_key = $public_key["key"];
//生成CSR文件 基于$dn生成新的 CSR (证书签名请求)
$csr = openssl_csr_new($this->openssl["dn"], $private_key,$this->openssl["config"]);
//根据配置自己对证书进行签名
$sscert = openssl_csr_sign($csr, null, $private_key, $this->openssl["valid_day"],$this->openssl["config"]);
//将公钥证书存储到一个变量,由 PEM 编码格式命名。
openssl_x509_export($sscert, $public_cert_key);
//将私钥存储到名为的出 PKCS12 文件格式的字符串。 导出密钥
openssl_pkcs12_export($sscert, $private_cert_key, $private_key, $this->openssl["privkey_passwd"]);
//生成证书文件
$fp = fopen($this->openssl["cer_path"], "w");
fwrite($fp, $public_cert_key);
fclose($fp);
//生成密钥文件
$fp = fopen($this->openssl["pfx_path"], "w");
fwrite($fp, $private_cert_key);
fclose($fp);
//组装返回数据
$keys = [
"public_key" => $public_key,
"private_key" => $private_key,
];
}else{
//获取密钥文件内容
$pfx_cert = file_get_contents($this->openssl["pfx_path"]);
//读取公钥私钥
$read = openssl_pkcs12_read($pfx_cert, $cert_keys, $this->openssl["privkey_passwd"]);
//判断读取结果
if($read == false){
$this->getCert(true);
}
//组装返回数据
$keys = [
"public_key" => $cert_keys["cert"],
"private_key" => $cert_keys["pkey"],
];
}
//赋值变量
$this->public_key = $keys["public_key"];
$this->private_key = $keys["private_key"];
//返回私钥和公钥
return $keys;
}
/**
* @Notes 公钥加密
* @Author shenzx
* @Date 2020-10-14 10:10
* @param $data 需要加密的数据
* @return bool|String 返回失败或密钥
*/
public function encryptionData($data){
//判断公钥是否为空
if(empty($this->public_key)){
return false;
}
//判断数据是否为空
if(empty($data)){
return false;
}
//数据序列化
$data = serialize($data);
//数据加密
$result = openssl_public_encrypt($data,$key,$this->public_key);
//判断加密结果
if($result == false){
return false;
}
//base64转码并返回加密密钥
return base64_encode($key);
}
/**
* @Notes 数据解密
* @Author shenzx
* @Date 2020-10-14 10:15
* @param string $key 公钥加密的密钥
* @return bool|array|String 失败返回false 成功返回解密后的数据
*/
public function decipheringData(string $key){
//判断私钥是否为空
if(empty($this->private_key)){
return false;
}
//判断密钥是否为空
if(empty($key)){
return false;
}
//base64解码
$key = base64_decode($key);
//数据解密
$result = openssl_private_decrypt($key,$data,$this->private_key);
//判断加密结果
if($result == false){
return false;
}
//数据反序列化
$data = unserialize($data);
//返回加密密钥
return $data;
}
/**
* @Notes 获取一段数据的签名
* @Author shenzx
* @Date 2020-10-14 10:35
* @param $data 获取签名的数据
* @return bool|string 失败返回false 成功返回签名
*/
public function getSign($data){
//判断私钥是否为空
if(empty($this->private_key)){
return false;
}
//判断数据是否为空
if(empty($data)){
return false;
}
//数据序列化
$data = serialize($data);
//申城签名
$result = openssl_sign($data,$sign,$this->private_key);
//判断加密结果
if($result == false){
return false;
}
//base64转码并返回签名
return base64_encode($sign);
}
/**
* @Notes 验签
* @Author shenzx
* @Date 2020-10-14 10:39
* @param $data 需要验签的数据
* @param string $sign 签名
* @return bool 失败false 成功true
*/
public function checkSign($data,string $sign){
//判断公钥是否为空
if(empty($this->public_key)){
return false;
}
//判断数据是否为空
if(empty($data)){
return false;
}
//判断签名是否为空
if(empty($sign)){
return false;
}
//base64解码
$sign = base64_decode($sign);
//数据序列化
$data = serialize($data);
//验签
$checkSign = openssl_verify($data,$sign,$this->public_key);
//返回验签结果
return boolval($checkSign);
}
}