近期对接一项目,对方是Java,用到了rsa的加解密以及签名。熬了一天才解决。。。
rsa的加解密需要用到OpenSSL的公钥私钥,在我上一篇的文章又说到,不懂得可以去看。
先上代码,然后再说这次开发中踩的坑::
一、RSA 加解密类
<?php
namespace util;
use Exception;
class RSA
{
const PKCS1 = 'PKCS#1';
const PKCS8 = 'PKCS#8';
private $rsa_public;
private $rsa_private;
private $key_format;
private $padding;
public function __construct($rsa_public, $rsa_private, $key_format = self::PKCS8, $padding = OPENSSL_PKCS1_PADDING)
{
$this->rsa_public = $rsa_public;
$this->rsa_private = $rsa_private;
$this->key_format = $key_format;
$this->padding = $padding;
}
public function sign($str)
{
openssl_sign($str, $sign, $this->getPrivateKey());
return base64_encode($sign);
}
// 加密
public function encrypt($content)
{
$crypto = '';
$pu_key = $this->getPublicKey();
foreach (str_split($content, 117) as $chunk) {
openssl_public_encrypt($chunk, $encryptData, $pu_key,$this->padding);
$crypto .= $encryptData;
}
return base64_encode($crypto);
}
// 解密
public function decrypt($content)
{
if (!is_string($content)) return null;
$decrypted = '';
$chunks = str_split(base64_decode($content), 128);
foreach ($chunks as $chunk) {
$partial = '';
$decryptIsTrue = openssl_private_decrypt($chunk, $partial, $this->getPrivateKey());
if ($decryptIsTrue === false) {
return null;
}
$decrypted .= $partial;
}
return $decrypted;
}
public function getPublicKey()
{
if ($this->key_format == self::PKCS1) {
$search = [
"-----BEGIN PUBLIC KEY-----",
"-----END PUBLIC KEY-----",
"\n",
"\r",
"\r\n"
];
$public_key = str_replace($search, "", $this->rsa_public);
$public_key = $search[0] . PHP_EOL . wordwrap($public_key, 64, "\n", true) . PHP_EOL . $search[1];
} else {
$public_key = $this->rsa_public;
}
$key = openssl_pkey_get_public($public_key);//这个函数可用来判断公钥是否是可用的
if (!$key) {
$this->throwError('公钥不可用');
}
return $key;
}
public function getPrivateKey()
{
if ($this->key_format == self::PKCS1) {
$search = [
"-----BEGIN PRIVATE KEY-----",
"-----END PRIVATE KEY-----",
"\n",
"\r",
"\r\n"
];
$private_key = str_replace($search, "", $this->rsa_private);
$private_key = $search[0] . PHP_EOL . wordwrap($private_key, 64, "\n", true) . PHP_EOL . $search[1];
} else {
$private_key = $this->rsa_private;
}
$pi_key = openssl_pkey_get_private($private_key);
if (!$pi_key) {
$this->throwError('私钥不可用');
}
return $pi_key;
}
public function throwError($msg)
{
throw new Exception($msg);
}
}
二、调用方法
rsa加解密,普遍的是把自己的公钥给对方,使用彼此的公钥进行加密,然后使用
私钥进行解密的操作。这里只提供加解密以及签名案例
//我自己的私钥
private $private_key = '-----BEGIN RSA PRIVATE KEY-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----END RSA PRIVATE KEY-----';
//对方的公钥
private $public_key = '-----BEGIN PUBLIC KEY-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----END PUBLIC KEY-----';
//定义需要加密的测试数据
$bizContent=array(
"supplierCode"=>"202372000142021000064",
"type"=>"1",
"surrenderTime"=>"2021-09-10 15:30:00"
);
//TODO 对数据进行签名以及加密
????$bizContent=json_encode($bizContent);
? $utilRsa = new RSA($this->public_key , '');
$bizContent_k = $utilRsa->encrypt($bizContent);
//需要进行签名的数据串
$sign='appKey=123123&bizContent='.$bizContent_k.'&charset=UTF-8&format=JSON&serviceName=serviceName&signType=RSA×tamp=111111&version=1.0.0';
//对sign进行私钥加密
$sign_k= (new RSA('',$this->private_key))->sign($sign);
????//数据解密
$res_bizContent = '需要解密的密文';
$res = (new RSA('',$this->private_key))->decrypt($res_bizContent);
$bizContent = json_decode($res,true);
三、注意细节
1、加密用的是对方的公钥,解密使用自己的私钥。
2、加解密的时候,会受到密文长度的限制报错,这时需要将密文分段加解密然后把结果在拼接起来
3、PHP的rsa加解密方法和Java还是有区别的,需要进行详细的沟通,了解具体的加密方法才可以匹配成功
4、第三方提供的java rsa秘钥(pkcs8格式),PHP不能直接使用;只能将rsa秘钥转成pkcs1格式,然后再按照PHP rsa秘钥格式处理。上面的加解密类有类似的方法
|