PHP中RSA非对称加密实现
1,php中RSA实现(公钥加密私钥解密)
/**
* 公钥加密数据.
* @param string $decrypted 数据明文
* @return null|string null加密失败
*/
public function encryptTxtContent(string $decrypted): ?string
{
$pubKey = openssl_get_publicKey($this->getPubKeyPem($this->txtPubKey));
return openssl_public_encrypt($decrypted, $encrypted, $pubKey) ? base64_encode($encrypted) : null;
}
/**
* 私钥解密
* @param string $encrypted 数据密文
* @return mixed
*/
public function decryptTxtContent(string $encrypted): ?string
{
$privateKey = openssl_get_privatekey($this->getPriKeyPem($this->txtPriKey));
return openssl_private_decrypt(base64_decode($encrypted), $decrypted, $privateKey) ? $decrypted : null;
}
在开发过程中,我就用了上边的加解密方式,但是在实践过程中由于加密字符串过长导致加密失败;获取一下错误信息:error:0909006C:PEM routines:get_name:no start line
;搜索了一下官方也有对应的解决方案,
https://www.php.net/manual/zh/function.openssl-public-encrypt.php#56449 。
加密出现错误的原因:
RSA对明文长度和密文长度有限制,如果要加密的明文太长则会出错。RSA 1024bit 加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块进行。
注意事项:
RSA不同的密钥长度,在分段加、解密时,分段字节数是不同的,若RSA密钥长度为M bit,分段加密字节数为(M/8-11),分段解密字节数为(M/8)。
如:
1024bit:分段加密字节数为117,分段解密字节数为128。
2048bit:分段加密字节数为245,分段解密字节数为256。
我用的是2048bit加密明文的所有代码如下:
/**
* 公钥加密数据.
* @param string $decrypted 数据明文
* @return null|string null加密失败
*/
public function encryptTxtContent(string $decrypted): ?string
{
$publicKey = openssl_get_publicKey($pubKey);
$crypted = array_reduce(str_split($decrypted, 245), function ($carry, $item) use ($publicKey) {
$subCrypted = null;
openssl_public_encrypt($item, $subCrypted, $publicKey);
$subCrypted && $carry .= $subCrypted;
return $carry;
}, '');
if (empty($crypted)) {
return '';
}
return base64_encode($crypted);
}
/**
* 私钥解密
* @param string $encrypted 数据密文
* @return mixed
*/
public function decryptTxtContent(string $encrypted): ?array
{
$privateKey = openssl_get_privatekey($this->getPriKeyPem($this->txtPriKey));
$dataArr = str_split(base64_decode($encrypted), 256);
$decrypted = array_reduce($dataArr, function ($carry, $item) use ($privateKey) {
$subDecrypted = null;
openssl_private_decrypt($item, $subDecrypted, $privateKey);
$subDecrypted && $carry .= $subDecrypted;
return $carry;
}, '');
if (! $decrypted) {
return [];
}
return json_decode($decrypted, true, 512, JSON_THROW_ON_ERROR);
}