php实现RSA加解密算法

最近开发的项目中用到RSA签名算法,给数据加密解密。php端是如何实现RSA加密解密的呢?

RSA的概念

RSA是第一个比较完善的公开密钥算法,它既能用于加密,也能用于数字签名。RSA以它的三个发明者Ron Rivest, Adi Shamir, Leonard Adleman的名字首字母命名,这个算法经受住了多年深入的密码分析,虽然密码分析者既不能证明也不能否定RSA的安全性,但这恰恰说明该算法有一定的可信性,目前它已经成为最流行的公开密钥算法。

RSA的安全基于大数分解的难度。其公钥和私钥是一对大素数(100到200位十进制数或更大)的函数。从一个公钥和密文恢复出明文的难度,等价于分解两个大素数之积(这是公认的数学难题)。

RSA的公钥、私钥的组成,以及加密、解密的公式可见于下表:
lbxx

RSA为何难于破解?有什么劣势?

在RSA密码应用中,公钥KU是被公开的,即e和n的数值可以被第三方窃听者得到。破解RSA密码的问题就是从已知的e和n的数值(n等于pq),想法求出d的数值,这样就可以得到私钥来破解密文。从上文中的公式:d ≡e-1 (mod((p-1)(q-1)))或de≡1 (mod((p-1)(q-1))) 我们可以看出。密码破解的实质问题是:从Pq的数值,去求出(p-1)和(q-1)。换句话说,只要求出p和q的值,我们就能求出d的值而得到私钥。
   当p和q是一个大素数的时候,从它们的积pq去分解因子p和q,这是一个公认的数学难题。比如当pq大到1024位时,迄今为止还没有人能够利用任何计算工具去完成分解因子的任务。因此,RSA从提出到现在已近二十年,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。

  然而,虽然RSA的安全性依赖于大数的因子分解,但并没有从理论上证明破译RSA的难度与大数分解难度等价。即RSA的重大缺陷是无法从理论上把握它的保密性能如何。

  此外,RSA的缺点还有:A)产生密钥很麻烦,受到素数产生技术的限制,因而难以做到一次一密。B)分组长度太大,为保证安全性,n 至少也要 600 bits

以上,使运算代价很高,尤其是速度较慢,较对称密码算法慢几个数量级;且随着大数分解技术的发展,这个长度还在增加,不利于数据格式的标准化。因此,使用RSA只能加密少量数据,大量的数据加密还要靠对称密码算法。

简单案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?php

$private_key = "-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCpS7mxdU6svbDcs10qbq9f9t5D4yfqC1jLmZD3GDD4D/8TbNkf
vcYDvde6nyPRSxrnzl9YmZhJKlP2iCIwdwwmW6yulXZyvPurfN/1AJt4JYDxnN/q
u1bSG5DZMribLsR2dlfA5J0D6lQ7g40eSgp4D6UWy8ezLy6UWFQCrnUHEQIDAQAB
AoGAQCQeoKtvOWdNIPEb9T2mWFdx8oqXzsapx8nQ8K1LsFBvNe7hfHMsGLLOjzhI
G7223eiEm07mMaJF2XvOaEpSYX/qQ1LZRSdBrzCec1lcDbB95dcRg9NmgBuCpUxE
3SGYm3VB8rurfsrRUUYoIbjWz8qyuIGdMbaNkHG/CpnUYpkCQQDfWYDYtQ3DxCt+
JBoLfuCykk8+nIV12CIYb023naoR2s/aQQRk9BkGCkDrdOAgZAN3BGOHYseKAfTP
nARDzfiDAkEAwgtYfgCDTOfW5/kJK1lZO21CdCCZnePwGYmWDLPzNiJIn8k0U6Ig
9GmxG+0GKzY71XO8W3Nh18ilZbX9dYel2wJASQ+AJGNlc0pyZ7rrgiMo4YEWxwZw
adIfpRqTs6KxhVGseFqYU2W94cns3pjG0BGnSIF5BUp8t1pYeKkyg/OWfQJBAK1w
mq41IycQaoR5kfqPKDT32dgWc3gvDqKk2duM1KzkQ+meXAkM90u/VLDTURo6pYyK
oCdVoHTRQRUCcAQnNNUCQQCO/zDRaY+5ssjPqj77eJqWfAhtbSDRRw+NurmUSas1
FT1cD5nil+uT48bIRoC5nk/XWfvAvMg/Yw5bslGUNx7f
-----END RSA PRIVATE KEY-----";

$public_key = "-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpS7mxdU6svbDcs10qbq9f9t5D
4yfqC1jLmZD3GDD4D/8TbNkfvcYDvde6nyPRSxrnzl9YmZhJKlP2iCIwdwwmW6yu
lXZyvPurfN/1AJt4JYDxnN/qu1bSG5DZMribLsR2dlfA5J0D6lQ7g40eSgp4D6UW
y8ezLy6UWFQCrnUHEQIDAQAB
-----END PUBLIC KEY-----";

//获取所有支持算法,cipher 就是密码,算法计算的意思
$methods=openssl_get_cipher_methods();
// var_dump($methods);
$data="原始数据为: 用私钥加密origin data1";
$method="AES-128-CBC";
//通过私钥加密,生成$crypted;
openssl_private_encrypt($data, $crypted, $private_key);
// 由于php 进行openssl_public_encrypt 加密后返回的是二进制数据,需要对其返回的加密后的数据进行二进制16进制编码base64_encode才可以显示,$crypted为加密后的串
$crypted=base64_encode($crypted);
echo "私钥加密后的结果为:".$crypted."\n";
//相应的:加密后生产的16进制加密字符串需要进行base64_decode进行解密后在进行openssl_private_decrypt
$crypted=base64_decode($crypted);
openssl_public_decrypt($crypted, $decrypted , $public_key);
echo "用公钥解密的结果为".($decrypted)."\n";
echo"===================我是分割线==============\n";
$data="用公钥加密origin data2\n";
$method="AES-128-CBC";
//通过公钥加密,生成$crypted;
openssl_public_encrypt($data, $crypted, $public_key);
// 由于php 进行openssl_public_encrypt 加密后返回的是二进制数据,需要对其返回的加密后的数据进行二进制16进制编码base64_encode才可以显示,$crypted为加密后的串
$crypted=base64_encode($crypted);
echo "公钥加密后的结果为:".$crypted."\n";
//相应的:加密后生产的16进制加密字符串需要进行base64_decode进行解密后在进行openssl_private_decrypt
$crypted=base64_decode($crypted);
openssl_private_decrypt($crypted, $decrypted , $private_key);
echo "用私钥解密的结果为".($decrypted)."\n";

通用类实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
<?php
namespace ApiPub;
class Algorithm
{
const RSA_ENCRYPT_BLOCK_SIZE = 117;
const RSA_DECRYPT_BLOCK_SIZE = 128;
/**
* 利用约定数据和私钥生成数字签名
* @param $data 待签数据
* @return String 返回签名
*/
public static function sign($data='')
{
if (empty($data))
{
return False;
}
$private_key = file_get_contents(dirname(__FILE__).'/rsa_private_key.pem');
if (empty($private_key))
{
echo "私钥异常!";
return False;
}
$pkeyid = openssl_get_privatekey($private_key);
if (empty($pkeyid))
{
echo "私钥资源标识符错误!";
return False;
}
$verify = openssl_sign($data, $signature, $pkeyid, OPENSSL_ALGO_MD5);
openssl_free_key($pkeyid);
return $signature;
}
/**
* 利用公钥和数字签名以及约定数据验证合法性
* @param $data 待验证数据
* @param $signature 数字签名
* @return -1:error验证错误 1:success验证成功 0:fail验证失败
*/
public static function isValid($data='', $signature='')
{
if (empty($data) || empty($signature))
{
return False;
}
$public_key = file_get_contents(dirname(__FILE__).'/rsa_public_key.pem');
if (empty($public_key))
{
echo "公钥异常";
return False;
}
$pkeyid = openssl_get_publickey($public_key);
if (empty($pkeyid))
{
echo "公钥资源标识符错误e!";
return False;
}
$ret = openssl_verify($data, $signature, $pkeyid, OPENSSL_ALGO_MD5);
switch ($ret)
{
case -1:
echo "错误";
break;
default:
echo $ret==1 ? "success" : "fail";//0:fail
break;
}
return $ret;
}
/**
* RSA数据加密解密 私钥-加密解密
* @param type $data
* @param type $type encode加密 decode解密 $public_key 密钥
* @Description: 字符过长的话需要分段加密/解密
* @return 加密或解密后的字符
*/
public static function RAS_Do($dataStr = '测试字符',$type='encode',$public_key){
if (empty($dataStr)) {
return 'data参数不能为空';
}
if ($type=='decode') {
//私钥解密
$data=base64_decode($dataStr);
$result = '';
$data = str_split($data, self::RSA_DECRYPT_BLOCK_SIZE);
foreach ($data as $block) {
openssl_private_decrypt($block, $decrypted, $public_key,OPENSSL_PKCS1_PADDING);
$result .= $decrypted;
}
return $result;
}else{
//私钥加密
$result = '';
$data = str_split($dataStr, self::RSA_ENCRYPT_BLOCK_SIZE);
foreach ($data as $block) {
openssl_private_encrypt($block, $crypted, $public_key,OPENSSL_PKCS1_PADDING);
$result .= $crypted;
}
$result=base64_encode($result);
return $result;
}
}
}

×

谢谢客官

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. RSA的概念
  2. 2. RSA为何难于破解?有什么劣势?
  3. 3. 简单案例
  4. 4. 通用类实现
,