最新优化的版本,不受长度限制
<?php
namespace app\common\lib\pay\tppay;
class Rsa
{
private $privateKey;
private $publicKey;
public function __construct(?string $privateKeyPath = null, ?string $publicKeyPath = null, ?string $privateKeyContent = null, ?string $publicKeyContent = null)
{
if ($privateKeyContent !== null) {
$this->privateKey = openssl_pkey_get_private($privateKeyContent);
} else {
$this->privateKey = openssl_pkey_get_private(file_get_contents($privateKeyPath ?? __DIR__ . '/rsa_private_key.pem'));
}
if ($publicKeyContent !== null) {
$this->publicKey = openssl_pkey_get_public($publicKeyContent);
} else {
$this->publicKey = openssl_pkey_get_public(file_get_contents($publicKeyPath ?? __DIR__ . '/rsa_public_key.pem'));
}
}
/**
* 生成数据的SHA1withRSA签名
* @param string $data 需要签名的数据
* @return string 返回base64编码的签名
*/
public function sign(string $data): string
{
if (!openssl_sign($data, $signature, $this->privateKey, OPENSSL_ALGO_SHA1)) {
throw new \RuntimeException('签名失败');
}
return base64_encode($signature);
}
/**
* 验证数据的SHA1withRSA签名
* @param string $data 原始数据
* @param string $signature 要验证的base64编码的签名
* @return bool 返回签名是否有效
*/
public function verify(string $data, string $signature): bool
{
$signature = base64_decode($signature);
$result = openssl_verify($data, $signature, $this->publicKey, OPENSSL_ALGO_SHA1);
if ($result === -1) {
throw new \RuntimeException('验证签名失败: ' . openssl_error_string());
}
return $result === 1;
}
private function getBlockSize($type = 'private')
{
$keyDetail = openssl_pkey_get_details($type === 'private' ? $this->privateKey : $this->publicKey);
$modulusSize = strlen($keyDetail['rsa']['n']) * 8; // 获取模数的位数
return floor(($modulusSize / 8) - 11); // RSA PKCS#1 v1.5 padding
}
public function privEncrypt(string $data)
{
$blockSize = $this->getBlockSize('private');
$encryptedData = '';
while ($data) {
$input = substr($data, 0, $blockSize);
$data = substr($data, $blockSize);
if (!openssl_private_encrypt($input, $encryptedPart, $this->privateKey)) {
throw new \RuntimeException('私钥加密失败');
}
$encryptedData .= $encryptedPart;
}
return base64_encode($encryptedData);
}
public function publicEncrypt(string $data)
{
$blockSize = $this->getBlockSize('public');
$encryptedData = '';
while ($data) {
$input = substr($data, 0, $blockSize);
$data = substr($data, $blockSize);
if (!openssl_public_encrypt($input, $encryptedPart, $this->publicKey)) {
throw new \RuntimeException('公钥加密失败');
}
$encryptedData .= $encryptedPart;
}
return base64_encode($encryptedData);
}
public function privDecrypt(string $encrypted)
{
$blockSize = $this->getBlockSize('private');
$decryptedData = '';
$encrypted = base64_decode($encrypted);
while ($encrypted) {
$input = substr($encrypted, 0, $blockSize + 11); // 加上padding长度
$encrypted = substr($encrypted, $blockSize + 11);
if (!openssl_private_decrypt($input, $decryptedPart, $this->privateKey)) {
throw new \RuntimeException('私钥解密失败');
}
$decryptedData .= $decryptedPart;
}
return $decryptedData;
}
public function publicDecrypt(string $encrypted)
{
$blockSize = $this->getBlockSize('public');
$decryptedData = '';
$encrypted = base64_decode($encrypted);
while ($encrypted) {
$input = substr($encrypted, 0, $blockSize + 11);
$encrypted = substr($encrypted, $blockSize + 11);
if (!openssl_public_decrypt($input, $decryptedPart, $this->publicKey)) {
throw new \RuntimeException('公钥解密失败');
}
$decryptedData .= $decryptedPart;
}
return $decryptedData;
}
public function __destruct()
{
if ($this->privateKey !== null) {
openssl_free_key($this->privateKey);
}
if ($this->publicKey !== null) {
openssl_free_key($this->publicKey);
}
}
/**
* 创建RSA密钥对
* @param int $bits 密钥位数,默认为2048位
* @param bool $saveToFile 是否将密钥保存到文件,默认为true
* @param string|null $privateKeyPath 私钥保存路径,如果$saveToFile为false,则忽略此参数
* @param string|null $publicKeyPath 公钥保存路径,如果$saveToFile为false,则忽略此参数
* @return array 返回包含私钥和公钥的数组
*/
public static function createKeyPair($bits = 2048, $saveToFile = true, $privateKeyPath = null, $publicKeyPath = null)
{
// 创建一个新的私钥和公钥资源
$res = openssl_pkey_new([
"private_key_bits" => $bits,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
]);
if ($res === false) {
throw new \RuntimeException('无法创建RSA密钥对');
}
// 提取私钥和公钥
openssl_pkey_export($res, $privateKey);
$publicKey = openssl_pkey_get_details($res)['key'];
// 如果需要保存到文件
if ($saveToFile) {
// 确保目录存在
if ($privateKeyPath !== null && !is_dir(dirname($privateKeyPath))) {
mkdir(dirname($privateKeyPath), 0755, true);
}
if ($publicKeyPath !== null && !is_dir(dirname($publicKeyPath))) {
mkdir(dirname($publicKeyPath), 0755, true);
}
// 保存私钥和公钥到文件
file_put_contents($privateKeyPath ?? __DIR__ . '/rsa_private_key.pem', $privateKey);
file_put_contents($publicKeyPath ?? __DIR__ . '/rsa_public_key.pem', $publicKey);
}
return [
'privateKey' => $privateKey,
'publicKey' => $publicKey,
];
}
}
// $rsa = new Rsa('/path/to/private_key.pem', '/path/to/public_key.pem');
// $rsa = new Rsa(null, null, '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----');
//直接获取密钥对(不保存)
//$keyPair = Rsa::createKeyPair(2048, false);
//echo "Private Key:\n" . $keyPair['privateKey'];
//echo "Public Key:\n" . $keyPair['publicKey'];
//将密钥对保存到指定位置
//$keyPair = Rsa::createKeyPair(2048, true, '/path/to/rsa_private_key.pem', '/path/to/rsa_public_key.pem');
下载开源RSA密钥生成工具openssl(通常Linux系统都自带该程序),解压缩至独立的文件夹,进入其中的bin目录,执行以下命令:
a、openssl genrsa -out rsa_private_key.pem 1024
b、openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt -out private_key.pem
c、openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
第一条命令生成原始 RSA私钥文件 rsa_private_key.pem
第二条命令将原始 RSA私钥转换为 pkcs8格式
第三条生成RSA公钥 rsa_public_key.pem
上面几个就可以看出:通过私钥能生成对应的公钥
RSA类:
<?php
class Rsa {
/**
* 获取私钥
* @return bool|resource
*/
private static function getPrivateKey()
{
$abs_path = dirname(__FILE__) . '/rsa_private_key.pem';
$content = file_get_contents($abs_path);
return openssl_pkey_get_private($content);
}
/**
* 获取公钥
* @return bool|resource
*/
private static function getPublicKey()
{
$abs_path = dirname(__FILE__) . '/rsa_public_key.pem';
$content = file_get_contents($abs_path);
return openssl_pkey_get_public($content);
}
/**
* 私钥加密
* @param string $data
* @return null|string
*/
public static function privEncrypt($data = '')
{
if (!is_string($data)) {
return null;
}
return openssl_private_encrypt($data,$encrypted,self::getPrivateKey()) ? base64_encode($encrypted) : null;
}
/**
* 公钥加密
* @param string $data
* @return null|string
*/
public static function publicEncrypt($data = '')
{
if (!is_string($data)) {
return null;
}
return openssl_public_encrypt($data,$encrypted,self::getPublicKey()) ? base64_encode($encrypted) : null;
}
/**
* 私钥解密
* @param string $encrypted
* @return null
*/
public static function privDecrypt($encrypted = '')
{
if (!is_string($encrypted)) {
return null;
}
return (openssl_private_decrypt(base64_decode($encrypted), $decrypted, self::getPrivateKey())) ? $decrypted : null;
}
/**
* 公钥解密
* @param string $encrypted
* @return null
*/
public static function publicDecrypt($encrypted = '')
{
if (!is_string($encrypted)) {
return null;
}
return (openssl_public_decrypt(base64_decode($encrypted), $decrypted, self::getPublicKey())) ? $decrypted : null;
}
}
**demo:**
<?php
require_once "Rsa.php";
$rsa = new Rsa();
$data['name'] = 'Tom';
$data['age'] = '20';
$privEncrypt = $rsa->privEncrypt(json_encode($data));
echo '私钥加密后:'.$privEncrypt.'<br>';
$publicDecrypt = $rsa->publicDecrypt($privEncrypt);
echo '公钥解密后:'.$publicDecrypt.'<br>';
$publicEncrypt = $rsa->publicEncrypt(json_encode($data));
echo '公钥加密后:'.$publicEncrypt.'<br>';
$privDecrypt = $rsa->privDecrypt($publicEncrypt);
echo '私钥解密后:'.$privDecrypt.'<br>';
也有一些网站提供生成rsa公钥私钥的服务:http://www.bm8.com.cn/webtool/rsa/
文章参考:https://www.cnblogs.com/xuweiqiang/p/9784584.html
评论