php 生成非对称密钥,PHP使用非对称加密算法(RSA)签名及验签、加密及解密示例...

两个密钥:公开密钥(public_key)(以下简称公钥)和私有密钥(private_key)(以下简称私钥)。

公钥与私钥是一对,如果用公钥对数据进行签名(或加密),只有用对应的私钥才能验签(或解密);如果用私钥对数据进行签名(或加密),那么只有用对应的公钥才能验签(或解密)。

因为签名(或加密)和验签(或解密)使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

两种应用场景:一种是签名与验签,这个只保证了数据来源的合法性,也就是你收到的数据是由你预期的对方发过来的;另一种是加密与解密,这个可以保证你的数据不会在网上裸奔,即便被劫持了也没关系。(注:传统的MD5只能对数据进行签名和验签,因为MD5是不可逆的,加密了就无法解密)

一般的应用场景都是用私钥签名、用公钥验签,或者用公钥加密、用私钥解密。

以支付宝的支付场景为例,在支付订单的时候,我们把订单交易数据通过我们自己的私钥(rsa_private_key)进行签名然后传给支付宝的服务器,支付宝的服务器接收到数据后会用我们自己的公钥(rsa_public_key)进行验签,这就是为什么要把我们自己的公钥(rsa_public_key)通过支付宝控制台传上去的原因了;而在订单异步通知的时候,支付宝会用他们自己的私钥(alipay_private_key)对订单通知数据进行签名然后传给我们的服务器,我们的服务器在接收到数据后只能用支付宝的公钥(alipay_public_key)进行验签,这就是为什么我们要去支付宝控制台获取到支付宝公钥的原因了。

如果要对传输的数据进行加密,那么我们在发送数据之前要用支付宝的公钥对数据加密,而支付宝那边收到数据后则用他们自己的私钥进行解密;而支付宝那边在发送数据之前就会用我们的公钥对数据进行加密,而我们在收到数据后则用我们自己的私钥进行解密。

PHP的RSA签名与验签及加密与解密代码示例如下:

/**

* RSA操作类库

* @author Ken(QQ:2480990710)

* @blog http://ken.01h.net/

* @date 2020-3-12

*/

class Rsa{

//RSA or RSA2

public $signType = 'RSA';

//私钥文件路径(与私钥值二选一)

public $rsaPrivateKeyFilePath;

//私钥值

public $rsaPrivateKey;

//公钥文件路径(与公钥值二选一)

public $rsaPublicKeyFilePath;

//公钥值

public $rsaPublicKey;

/**

* 校验$value是否非空

* if not set ,return true;

* if is null , return true;

*/

private function checkEmpty($value) {

if (!isset($value))

return true;

if ($value === null)

return true;

if (trim($value) === "")

return true;

return false;

}

/**

* 获取私钥

* @return bool|resource

*/

private function getPrivateKey()

{

if($this->checkEmpty($this->rsaPrivateKeyFilePath)){

$priKey = $this->rsaPrivateKey;

$res = "-----BEGIN RSA PRIVATE KEY-----\n" .

wordwrap($priKey, 64, "\n", true) .

"\n-----END RSA PRIVATE KEY-----";

}else {

$priKey = file_get_contents($this->rsaPrivateKeyFilePath);

$res = openssl_pkey_get_private($priKey);

}

return $res;

}

/**

* 获取公钥

* @return bool|resource

*/

private function getPublicKey()

{

if($this->checkEmpty($this->rsaPublicKeyFilePath)){

$pubKey = $this->rsaPublicKey;

$res = "-----BEGIN PUBLIC KEY-----\n" .

wordwrap($pubKey, 64, "\n", true) .

"\n-----END PUBLIC KEY-----";

}else {

$pubKey = file_get_contents($this->rsaPublicKeyFilePath);

$res = openssl_pkey_get_public($pubKey);

}

return $res;

}

/**

* 私钥签名

* @param string $data

* @return null|string

*/

public function sign($data) {

$res = $this->getPrivateKey();

if ("RSA2" == $this->signType) {

openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);

} else {

openssl_sign($data, $sign, $res);

}

if(!$this->checkEmpty($this->rsaPrivateKeyFilePath)){

openssl_free_key($res);

}

$sign = base64_encode($sign);

return $sign;

}

/**

* 公钥验签

* @param string $data

* @param string $sign

* @return bool

*/

public function verify($data, $sign) {

$res = $this->getPublicKey();

if ("RSA2" == $this->signType) {

$result = (bool)openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256);

} else {

$result = (bool)openssl_verify($data, base64_decode($sign), $res);

}

if(!$this->checkEmpty($this->rsaPublicKeyFilePath)) {

openssl_free_key($res);

}

return $result;

}

/**

* 公钥加密

* @param string $data

* @return null|string

*/

public function publicEncrypt($data)

{

if (!is_string($data)) {

return null;

}

$res = $this->getPublicKey();

if ("RSA2" == $this->signType) {

$max_encrypt_block = 245;

} else {

$max_encrypt_block = 117;

}

$result = '';

while($data){

$input = substr($data, 0, $max_encrypt_block);

$data = substr($data, $max_encrypt_block);

openssl_public_encrypt($input, $encrypted, $res);

$result .= $encrypted;

}

if(!$this->checkEmpty($this->rsaPublicKeyFilePath)) {

openssl_free_key($res);

}

$result = base64_encode($result);

return $result;

}

/**

* 私钥解密

* @param string $encrypted

* @return null|string

*/

public function privDecrypt($encrypted)

{

if (!is_string($encrypted)) {

return null;

}

$res = $this->getPrivateKey();

if ("RSA2" == $this->signType) {

$max_decrypt_block = 256;

} else {

$max_decrypt_block = 128;

}

$content = base64_decode($encrypted);

$result = '';

for($i = 0; $i < strlen($content)/$max_decrypt_block; $i++ ) {

$data = substr($content, $i * $max_decrypt_block, $max_decrypt_block);

openssl_private_decrypt($data, $decrypt, $res);

$result .= $decrypt;

}

if(!$this->checkEmpty($this->rsaPrivateKeyFilePath)){

openssl_free_key($res);

}

return $result;

}

}

$data = 'version=1.0&service=orderPay&mch_id=1000000000001';

$rsa = new Rsa();

//设置公钥

$rsa->rsaPublicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCIaDx0DMC0NxLssTPZg3VZOX8xnW1hu74AK4Kwzv+fpZT9JiliIU/gTBwTJQNCnR2LbFR0DOMRnWUafrbI0IcbA2VA3sO+z/WwfGYTy9/fZnNOXr91Jgg7Hln+7qM7aWy2MoGY4M1s8NvtHbtMc+FZFQwVzgjipGDReEaK3ahGCQIDAQAB';

//设置私钥

$rsa->rsaPrivateKey = 'MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIhoPHQMwLQ3EuyxM9mDdVk5fzGdbWG7vgArgrDO/5+llP0mKWIhT+BMHBMlA0KdHYtsVHQM4xGdZRp+tsjQhxsDZUDew77P9bB8ZhPL399mc05ev3UmCDseWf7uoztpbLYygZjgzWzw2+0du0xz4VkVDBXOCOKkYNF4RordqEYJAgMBAAECgYAxXbfzL+JV1lCtBHyFTcQcZGiZ5iV951od6aFEp8VvW5eN/k+fyfqEbEcEzrJdW0sj+DKgRUGwUEwUyKMSDhW2r8mFr0wlWDvOJDpVl1VYjSxp2yhwjg0H1uTjGZhf9G1GcWwJHnD3U54ZrzgtqGiEvqK64qIl1koGXG5ww5mu4QJBAO4CZfw8lF+wD2+YlT1x4e4ku4NyI9awihadV4LN3NiHs1Ubm2RuW4ca/hcH5oToRrRmypmOT8bxyWMMkrj5CIUCQQCSt8itnsDfxyWdhEX1ecyn+25bkZQo1fn+ujFxc6ZmGI0vym22HZji/ghKUAug+i6Owtn896/O80m5V/ZZ5EC1AkEAiWAjA2Ln9Q8G6c+1HEEWOcFD5gvEec9t9L2eXCZ8eRJiRRZpK5+y/plq3Vo3CLGU1d2axOTqURcPuTbxnQhIjQJAUpQ80HQVTR7S7iigE719UmMzRzjWMnHVZuk3oQqd8sMI3IhMXf+kqMagter90JpgEBxeA4MJoirPKRH4Z7oQLQJAJm5Fol7pjrCAVin5P1yxpD5ZZqPU4vzyk4tOomFYShtjV+6GQrNQNS6jmCZ2ARz4k0b0LrMnk+Iv9JQXFsDKiw==';

//签名

$sign = $rsa->sign($data);

echo "\r\n------------------sign--------------------\r\n";

echo $sign;

//验签

$verify = $rsa->verify($data, $sign);

echo "\r\n------------------verify--------------------\r\n";

var_dump($verify);

//公钥加密

$result = $rsa->publicEncrypt($data);

echo "\r\n------------------publicEncrypt--------------------\r\n";

echo $result;

//私钥解密

$data2 = $rsa->privDecrypt($result);

echo "\r\n------------------privDecrypt--------------------\r\n";

echo $data2;

?>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值