PHP RSA加密解密

PHP服务端与客户端交互或者提供开放API时,通常需要对敏感的数据进行加密,这时候rsa非对称加密就能派上用处了。


举个通俗易懂的例子,假设我们再登录一个网站,发送账号和密码,请求被拦截了。



  • 密码没加密,那攻击者就直接拿到了密码,这是最搓的。

  • 密码加密了,是不可逆加密,那攻击者只需要模拟那个请求即可登录。

  • 密码加密了,是可逆加密,其中携带有时间等参数,后台可以根据时间等参数来判断是否有效,但因为是在前端加密,其加密方式也能在代码中找到,找到加密方式就可以得出解密方式。


但是如果我们使用非对称加密就可以避免以上问题。


非对称加密算法需要两个密钥来进行加密和解密,这两个秘钥是公开密钥(public key,简称公钥)和私有密钥(private key,简称私钥)。


工作过程如下,甲乙之间使用非对称加密的方式完成了重要信息的安全传输。


PHP RSA加密解密



  • 乙方生成一对密钥(公钥和私钥)并将公钥向其它方公开。

  • 得到该公钥的甲方使用该密钥对机密信息进行加密后再发送给乙方。

  • 乙方再用自己保存的另一把专用密钥(私钥)对加密后的信息进行解密。乙方只能用其专用密钥(私钥)解密由对应的公钥加密后的信息。


在传输过程中,即使攻击者截获了传输的密文,并得到了乙的公钥,也无法破解密文,因为只有乙的私钥才能解密密文。

同样,如果乙要回复加密信息给甲,那么需要甲先公布甲的公钥给乙用于加密,甲自己保存甲的私钥用于解密。


在非对称加密中使用的主要算法有:RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)等。


下面我们通过一个例子来说明如何用PHP来实现RSA的加密解密。



class Rsa
{
public $privateKey = '';

public $publicKey = '';

public function __construct()
{
$resource = openssl_pkey_new();
openssl_pkey_export($resource, $this->privateKey);
$detail = openssl_pkey_get_details($resource);
$this->publicKey = $detail['key'];
}

public function publicEncrypt($data, $publicKey)
{
openssl_public_encrypt($data, $encrypted, $publicKey);
return $encrypted;
}

public function publicDecrypt($data, $publicKey)
{
openssl_public_decrypt($data, $decrypted, $publicKey);
return $decrypted;
}

public function privateEncrypt($data, $privateKey)
{
openssl_private_encrypt($data, $encrypted, $privateKey);
return $encrypted;
}

public function privateDecrypt($data, $privateKey)
{
openssl_private_decrypt($data, $decrypted, $privateKey);
return $decrypted;
}
}


$rsa = new Rsa();
echo "公钥:n", $rsa->publicKey, "n";
echo "私钥:n", $rsa->privateKey, "n";

// 使用公钥加密
$str = $rsa->publicEncrypt('hello', $rsa->publicKey);
// 这里使用base64是为了不出现乱码,默认加密出来的值有乱码
$str = base64_encode($str);
echo "公钥加密(base64处理过):n", $str, "n";
$str = base64_decode($str);
$pubstr = $rsa->publicDecrypt($str, $rsa->publicKey);
echo "公钥解密:n", $pubstr, "n";
$privstr = $rsa->privateDecrypt($str, $rsa->privateKey);
echo "私钥解密:n", $privstr, "n";

// 使用私钥加密
$str = $rsa->privateEncrypt('world', $rsa->privateKey);
// 这里使用base64是为了不出现乱码,默认加密出来的值有乱码
$str = base64_encode($str);
echo "私钥加密(base64处理过):n", $str, "n";
$str = base64_decode($str);
$pubstr = $rsa->publicDecrypt($str, $rsa->publicKey);
echo "公钥解密:n", $pubstr, "n";
$privstr = $rsa->privateDecrypt($str, $rsa->privateKey);
echo "私钥解密:n", $privstr, "n";

大家执行一下可以看到公钥加密的数据,只有私钥能解密,反之亦然,私钥加密的数据只有公钥能解码。


执行结果如下:



这是PHP端的实现,可用在第三方跟平台之间的数据传输,但如果是前端传到后端该怎么办呢,搜索了一下,发现了这个库
jsencrypt


使用jsencrypt加密解密的例子如下:


html>


</span>JSEncrypt Example<span class="kw">
id="basetag" href="/jsencrypt-2.3.0/">
http-equiv="Content-Type" content="text/html; charset=UTF-8">
name="viewport" content="width=device-width, initial-scale=1.0">
src="jquery.js">
type="text/javascript" src="bin/jsencrypt.js">



class="container">
type="text/javascript">

// Call this code when the page is done loading.
$(function() {

// Run a quick encryption/decryption when they click.
$('#testme').click(function() {

// Encrypt with the public key...
var encrypt = new JSEncrypt();
encrypt.setPublicKey($('#pubkey').val());
var encrypted = encrypt.encrypt($('#input').val());
console.log(encrypted)

// Decrypt with the private key...
var decrypt = new JSEncrypt();
decrypt.setPrivateKey($('#privkey').val());
var uncrypted = decrypt.decrypt(encrypted);
console.log(uncrypted)

// Now a simple check to see if the round-trip worked.
if (uncrypted == $('#input').val()) {
alert('It works!!!');
} else {
alert('Something went wrong....');
}
});
});
</script>


其中的公钥和私钥都是上面PHP代码中生成的,这边好像只有公钥加密,私钥解密。


拿到其中打印出的加密后的数据,尝试在PHP中进行解密,可以看到也能解密成功。代码如下:



class Rsa
{
public $privateKey = '-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDkaTKbAERvJGE0
jGsdPXUI1FpO1uDkBkuuQU4LRv0Quw9r8j+fVNkN9rZVXMV7MiGOgb80Z0k9zRxZ
5KWOqMnSlrpyO3WjhFpDJeSmqZ4wLMFwmxrr31AjabD5Nkf9dQ7RiEIuM49g27+M
3OFvdIPcLgCyXnkl8FwBceBs38QbCXY5MrwlZr13yWZnyj6fbbG8t4atAzJ6bnj3
FZuvynC3QnMaVi6YnTIlBOUOHtqt/jsUTOCWkwKqkZh+RZF2fx3IFkSpJAOMgT5p
jSnfEJkK5E4JJHobLo/dFO0J7Gve+qb/lfJ9UpnZe78N1TAvbJiNZoN22ghbuIAW
M5qqIqOzAgMBAAECggEBAItUJFtqoVQOpADy+s/+UirNpjzbVJmjwXyNN3cnmW0g
PjsBrY+aqUCcUwLlMU2B+fg86w6jRokdWgL3t4m7Kkl8SkUuQgc5z/mP3tdPNkB6
vJDc/GIPeYnwidSrKOTSB/UGoiAesYJK6aCaiCV9tIWVxjUH7eyXnvf+qAChyrUW
PG/FirLyYmz1yRG99VKKE+iEIzemGSswU0DI0bwTFQ0MunLeJf0EdT20XppNwnl4
uoRgOBpMkW02vxDDWke2YIpk128KFRtPE3zF7W+Prb3ifMuQHSqDdqTgZA5+G3A9
D+lwczy95+0mIBpJ8rKQGjJ51ZT5WVMET9+Hb9+nUIECgYEA9NluRzIi9tZxwQa2
KdU8WAtWZZQZfG18mSFg8/QYrAGF2TyLAW0mEIe7nQXxPzm50HdpxTJCkUrXGm3u
hfPayx18H4oVVYRepSSfV+xe7wdogJWV6i5h/LaZsiTk1O8vF9Cwc3yUyVoMtKsg
yVcsONOzo/Kg/vwejQJb1C8dNvMCgYEA7tAewjA25vDmfiWZ0lrWKlwGQZ97+pMU
X+N12DWxL1Lvi6jBKXlK+Eiz19Qm/mBz9RxrDDY4/o0IjtTxdOh5thDaiqIcnqQn
PiBpm7zbheZOlPBGjFJ1vwueIWvqbx9vcqHik/4xHwuFNwQ+YCSpVpVoqrgoN/h/
fX5+hKm1kEECgYEAzn69UZAICtLKNveZE+jBLqPJJnvjjpur1F1hLfzz/cR/BLnZ
pcdOrew7Hu+PCTp+6kB7VJLRr0VF6gVCf3gsUta4AsVqvqeXRoF/XSB84+wEh0Ug
nNKnUwEQ2DvjPW3G8rfOyGcN+E5YntogGY3KPtbUDvWmL8WjYlrV5Toi0l8CgYAQ
Ujr37JGkAOzPzEQSA1FFvdpTm9G+U1T+JK6GI01DvbhPZC4nZnnAND/OTVqI4hCq
vNF4GTCV/Q+Lq3QBGG5RCh/Vf7TTBscD0PVGxoZ+RTozpaQ8rNoNP38EK7ru80gL
npK8qI+03nWxR+H3cin8l+N6X3GoOZyE+CMvb+XPwQKBgEeDjwTWxVhH/uksO3pw
MgbHjauD6AjuW9jc2a7ngFCWSQxQ3+xK1Spn6pbVdLPiBgInxCIl8d6S1yFU0Uan
iZHgy4fs1hdJRSuJ6qydqSwlS2C+gDpyY8ye0i+jq5VYYhKcpJCrCgaQGbleuaUd
ldp7v1FD8uyeemknGA35f6Id
-----END PRIVATE KEY-----';

public $publicKey = '-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5GkymwBEbyRhNIxrHT11
CNRaTtbg5AZLrkFOC0b9ELsPa/I/n1TZDfa2VVzFezIhjoG/NGdJPc0cWeSljqjJ
0pa6cjt1o4RaQyXkpqmeMCzBcJsa699QI2mw+TZH/XUO0YhCLjOPYNu/jNzhb3SD
3C4Asl55JfBcAXHgbN/EGwl2OTK8JWa9d8lmZ8o+n22xvLeGrQMyem549xWbr8pw
t0JzGlYumJ0yJQTlDh7arf47FEzglpMCqpGYfkWRdn8dyBZEqSQDjIE+aY0p3xCZ
CuROCSR6Gy6P3RTtCexr3vqm/5XyfVKZ2Xu/DdUwL2yYjWaDdtoIW7iAFjOaqiKj
swIDAQAB
-----END PUBLIC KEY-----';

public function __construct()
{
}

public function publicEncrypt($data, $publicKey)
{
openssl_public_encrypt($data, $encrypted, $publicKey);
return $encrypted;
}

public function publicDecrypt($data, $publicKey)
{
openssl_public_decrypt($data, $decrypted, $publicKey);
return $decrypted;
}

public function privateEncrypt($data, $privateKey)
{
openssl_private_encrypt($data, $encrypted, $privateKey);
return $encrypted;
}

public function privateDecrypt($data, $privateKey)
{
openssl_private_decrypt($data, $decrypted, $privateKey);
return $decrypted;
}
}

$rsa = new Rsa();

// 使用公钥加密的内容
$str = 'IUMBGcLwJECdxUu3LMbeEhGQdoRjCLqFwfZQBO/Odh3tClbq76Tva7yYqTVxexXLmZ3uY8DrOk/XwcVVRr6g9rBnv/zxBxUShCdN0CwkoguvI+6Oju2aUBlM4FhUp+gmasa5YfqylEp1RpsVAp67GMGlxZvp0ekfhFXkjSqAguPd7dKq5YjftP12xOyuJHAzzg7U+eHxffxnneKqXkK7QrfQD6VrLpbYmayPSjMza/RbjXF+d85UeUZUaF25PZ7Y7kD4Yo7/hY/L6peeOkI5//tpl6U4QY9VsFsjAbIpNMsZuNjE/cZ57Kc5WScPsmy0o9wsp5DUEJmu+YYmr6adoA==';
$str = base64_decode($str);
$pubstr = $rsa->publicDecrypt($str, $rsa->publicKey);
echo "公钥解密:n", $pubstr, "n";
$privstr = $rsa->privateDecrypt($str, $rsa->privateKey);
echo "私钥解密:n", $privstr, "n";

解码结果如下:



0 个评论

要回复文章请先登录注册