什么是RSA加密?
RSA
(详见维基百科)算法是现今使用最广泛的公钥密码算法,也是号称地球上最安全的加密算法,与 md5
和 sha1
不同,到目前为止,也只有极短的RSA加密被破解。
使用场景
为移动端(IOS,安卓)编写 API 接口
进行支付、真实信息验证等安全性需求较高的通信
与其他第三方或合作伙伴进行重要的数据传输,用于外部商户系统和本系统之间报文的安全性验证。
<?php
class Rsa
{
/**
* 生成证书
* @return array
*/
public static function exportOpenSSLFile($bits = 1024)
{
$config = array(
"digest_alg" => "sha512",
"private_key_bits" => $bits, //字节数 512 1024 2048 4096 等
"private_key_type" => OPENSSL_KEYTYPE_RSA, //加密类型
);
$res = openssl_pkey_new($config);
if ($res == false) return [];
openssl_pkey_export($res, $private_key);
$public_key = openssl_pkey_get_details($res);
$public_key = $public_key["key"];
openssl_free_key($res);
return [$private_key, $public_key];
}
/**
* 生成签名
* @param array $params 待签名的所有参数
* @return string 生成的签名
*/
public static function getSignGenerator($params, $ssl_private)
{
//生成待验签的字符串
$data = self::getSignStr($params);
$pem = "-----BEGIN RSA PRIVATE KEY-----\n" .
wordwrap($ssl_private, 64, "\n", true) .
"\n-----END RSA PRIVATE KEY-----";
//openssl_private_encrypt($data, $crypted, $pem);
openssl_sign($data, $sign, $pem, OPENSSL_ALGO_SHA256);
return base64_encode($sign);
}
/**
* 验证签名 公钥验证签名
* @param array $params 待签名的所有参数
* @param string $sign 生成的签名
* @return boolean 校验的结果
*/
public static function signCheck($data, $sign, $ssl_public)
{
//对方的公钥内容 一行的形式
$pem = "-----BEGIN PUBLIC KEY-----\n" .
wordwrap($ssl_public, 64, "\n", true) .
"\n-----END PUBLIC KEY-----";
return (bool)openssl_verify($data, base64_decode($sign), $pem, OPENSSL_ALGO_SHA256);
}
/**
* 我们自己的加密
* @param $string
* @param $pubKey
* @return string
*/
function encrypt($string, $ssl_public)
{
$res = "-----BEGIN PUBLIC KEY-----\n" .
wordwrap($ssl_public, 64, "\n", true) .
"\n-----END PUBLIC KEY-----";
openssl_public_encrypt($string, $encrypt, $res);
return base64_encode($encrypt);
}
/**
* 私钥加密 (使用公钥解密)
* @param string $data
* @param $privateKey
* @param int $padding
* @return null|string
*/
public static function privateEncrypt(string $data, $privateKey, $padding = OPENSSL_PKCS1_PADDING)
{
$encrypted = '';
$chunks = str_split($data, 117);
foreach ($chunks as $chunk) {
$partialEncrypted = '';
$encryptionOk = openssl_private_encrypt($chunk, $partialEncrypted, $privateKey, $padding);
if ($encryptionOk === false) {
return null;
}
$encrypted .= $partialEncrypted;
}
return base64_encode($encrypted);
}
/**
* 公钥加密(使用私钥解密)
* @param string $data 加密字符串
* @param int $padding
* @return null|string
*/
public static function publicEncrypt(string $data, $publicKey, $padding = OPENSSL_PKCS1_PADDING)
{
$encrypted = '';
$chunks = str_split($data, 117);
foreach ($chunks as $chunk) {
$partialEncrypted = '';
$encryptionOk = openssl_public_encrypt($chunk, $partialEncrypted, $publicKey, $padding);
if ($encryptionOk === false) {
return null;
}
$encrypted .= $partialEncrypted;
}
return base64_encode($encrypted);
}
/**
* @param string $encrypted
* @param $privateKey
* @return null
* @uses 私钥解密 (使用公钥加密)
*/
public static function privateDecrypt(string $encrypted, $privateKey)
{
$decrypted = '';
$chunks = str_split(base64_decode($encrypted), 128);
foreach ($chunks as $chunk) {
$partial = '';
$decryptIsTrue = openssl_private_decrypt($chunk, $partial, $privateKey);
if ($decryptIsTrue === false) {
return null;
}
$decrypted .= $partial;
}
return $decrypted;
}
/**
* 公钥解密 (使用私钥解密)
* @param string $encrypted 被解密字符串
* @return null
*/
public static function publicDecrypt(string $encrypted, $publicKey)
{
$decrypted = '';
$chunks = str_split(base64_decode($encrypted), 128);
foreach ($chunks as $chunk) {
$partial = '';
$decryptIsTrue = openssl_public_decrypt($chunk, $partial, $publicKey);
if ($decryptIsTrue === false) {
return null;
}
$decrypted .= $partial;
}
return $decrypted;
}
/**
* 私钥签名
* @param $data string 验签内容
* @param $signature string 签名字符串
* @param int $signature_alg
* @return string
*/
public static function privateSign($data, $privateKey, $signature_alg = OPENSSL_ALGO_SHA1)
{
$signature = '';
openssl_sign($data, $signature, $privateKey, $signature_alg);
openssl_free_key($privateKey);
return base64_encode($signature);
}
/**
* 公钥验签
* @param $data string 验签内容
* @param $signature string 签名字符串
* @param int $signature_alg
* @return bool
*/
public static function publicSign($data, $signature, $publicKey, $signature_alg = OPENSSL_ALGO_SHA1)
{
$result = openssl_verify($data, base64_decode($signature), $publicKey, $signature_alg);
openssl_free_key($publicKey);
return $result === 1;
}
/**
* 生成待签名的字符串
* @param array $data 参与签名的参数数组
* @return string 待签名的字符串
*/
public static function getSignStr(array $data)
{
//排序
ksort($data);
//剔除sign 如果对方的签名叫sign 或者可以在调用方法的时候剔除
//unset($data['sign']);
$stringToBeSigned = '';
$i = 0;
foreach ($data as $k => $v) {
if ($i == 0) {
$stringToBeSigned .= "$k" . "=" . "$v";
} else {
$stringToBeSigned .= "&" . "$k" . "=" . "$v";
}
$i++;
}
return $stringToBeSigned;
}
}
使用Demo
<?php
$public_key = '-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbtLA7lMfUvpBgfgzouiPgcnbL
DnEcuCK0gMub/EAEqmr82sl+9tH1iQb1w/hgQLptVRxAuUOa03XqlnG3wkAegtQt
4Q5ZtHSSomE8/5FXJvQfGTCz5RARyM0MiLTMZJGhLdVT6O8uCYIrPRQq7u6NVLs9
6YDmtzX2do/sTsWCAwIDAQAB
-----END PUBLIC KEY-----';
$private_key = '-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCbtLA7lMfUvpBgfgzouiPgcnbLDnEcuCK0gMub/EAEqmr82sl+
9tH1iQb1w/hgQLptVRxAuUOa03XqlnG3wkAegtQt4Q5ZtHSSomE8/5FXJvQfGTCz
5RARyM0MiLTMZJGhLdVT6O8uCYIrPRQq7u6NVLs96YDmtzX2do/sTsWCAwIDAQAB
AoGAfnO3zCuAPp6k0jiMc1T4XgeXwkDwS8qfJMiUkxHBTAi66q8khSAeU7H9HQsS
Y9ktji1YzJeo98xULzgPEpWHS/uhA8VZa16TLy9Yfadn2t+wpWpEJ9ZA4jjEqfQj
DDxcUc/pEv5siaE/bU8uls4o2nAiuWnI2n5FGrQa2OziGUECQQDPOh3KD2AOZtEF
p7i0yxYXe4dCKwenfw5q7l933RgqMXsVR1EAGzAUdIs71hTye6ibhva+eJRfndoV
Jq2IHjOdAkEAwFpOZR8j3Cl4zEk/9D9WEnSa8VWLe76vb7DfgfwkSAhs/f2MNF1I
zy9W5tPHRiMzaHNgPBFX9tw2u5QzsgOqHwJAPl3zUTjHZA41okoUIPVuNKsMzjE9
IH/wyuXq/ZwhBbHWpVTNYAbOtZlNvjh0HXZyDDzWTgTkQtKzK+J0H59XUQJARukD
vYOdVKx1O9pFGWW/9U3HUPCYWyYQxrwNqX2qYmO4ymmOJj+9d6OcBbxM2i5f5UGj
WIGMTBUimEQqSpXPQQJAIkHC2GknUv8HaBRLXxYTIAjj78a0pQT2bYlI6R04AwUZ
ljBaUGvvdYJ3CGZ32Xk12Te2fMJj5h/yLyEr8uzpzw==
-----END RSA PRIVATE KEY-----',
# 公钥加密、私钥解密
// 加密明文
$crypt_text = '公钥加密、私钥解密';
echo '加密明文:' . $crypt_text.PHP_EOL;
$public_encrypt_data = Rsa::publicEncrypt($crypt_text, $publicKey);
echo '公钥加密后数据:' . $public_encrypt_data.PHP_EOL; // 一直在变化
$private_decrypt_data = Rsa::privateDecrypt($public_encrypt_data, $privateKey);
echo '私钥解密数据: ' . $private_decrypt_data.PHP_EOL;
加密明文:公钥加密、私钥解密
公钥加密后数据:QHdj15P6l1gJbjNlD7spKT7KjCJJ0Qg5c8JjLBAS9hvhkq8eRuaNY/dDrboD3t40NvyPI8SBFBkDTjJ5IDyqTTSfthUROvasMD7wCPRYGaOt5to+ygfvV5t4CyYQEvSSflqimWvffRs0L8fs3pqE2kLD/AHOC94+ZBNFfzTTtVA=
私钥解密数据: 公钥加密、私钥解密
# 私钥加密、公钥解密
// 加密明文
$crypt_text = '私钥加密、公钥解密';
echo '加密明文:' . $crypt_text.PHP_EOL;
$private_encrypt_data = Rsa::privateEncrypt($crypt_text, $privateKey);
echo '私钥加密后数据:' . $private_encrypt_data..PHP_EOL; // 不变
$public_decrypt_data = Rsa::publicDecrypt($private_encrypt_data, $publicKey);
echo '公钥解密数据: ' . $public_decrypt_data..PHP_EOL;
加密明文:私钥加密、公钥解密
私钥加密后数据:dDzAs7kj9z7kS7Zbcz6sNLP+sIOnXp2qFGr4RepZcZp9XzCt8Tt+Kd/NIo4S20hjAvBiurvSHaR6LLL5ur5dc4vkFGkV+bGaT2SlhC4JkvYt4N2T9EiQupwcCtlk+dcENLexWiCvZtuzk3peK+H7AUWqFeOlmGRZb3De7bP+heY=
公钥解密数据: 私钥加密、公钥解密