PHP 实现RSA,RSA2 加密和签名

前情提要

在网站或应用的业务开发中,往往会使用一些加密逻辑或者与第三方对接 API 时的签名逻辑,在当下繁杂的加密/签名算法中我相信 RSA 相对来说是比较适用的算法。

那这里又有一个问题,很多人其实分不清楚 RSA 所属的公钥和私钥,到底哪个用来加密,哪个用来解密;或者说哪个用来签名,哪个用来验签。其实这个问题也是很好理解的。

如果是用来加密,那么我作为开发者肯定是不希望别人知道我的消息,所以也就是说只有我才能解密,所以可以得出公钥负责加密,私钥负责解密

如果是用来签名,那么我作为开发者肯定不希望有人能冒充我的消息,只能由我去生成这个签名,也就可以得出私钥负责签名,公钥负责验证

那好,有了上述的结论,我们接下来去实现这个加密方法。

生成 RSA 私钥和公钥

RSA是非对称加密,对加密内容长度有限制,生成 1024 位私钥的最多只能加密 127 位数据,如果加密字符串过长请生成 2048 位的秘钥

# 生成私钥,长度参数可不加,目前默认生成的就是2048 bit的秘钥
 openssl genrsa -out private_key.pem 2048
 
# 如果是Java开发者需要将私钥转换成PKCS8格式
openssl pkcs8 -topk8 -inform PEM -in private_key.pem -outform PEM -nocrypt -out private_key.pem

# 生成对应的公钥
openssl rsa -in private_key.pem -pubout -out public_key.pem 

通过上述操作命令,将生成的公钥与秘钥拷贝到自己的项目目录,即可继续进行下面的开发工作(使用 Laravel8)。

加密(公钥加密,私钥解密)
<?php
namespace App\Http\Controllers;

use Illuminate\Support\Str;

class RsaController extends Controller
{
    // 这里应直接从配置文件获取,为方便大家查阅直接定义在这里,
    // 公钥和私钥可以直接复制出来以字符串形式配置,也可以配置存放公钥秘钥文件的目录路径
    private $private_key = 'MIIEowIBAAKCAQEAyZGgkPRWyeGIlY';
    private $public_key = storage_path('public_key.pem');
    
    // 公钥加密
    public function encrypt()
    {
        // 待加密字符串
       	$str = 123456789;
        
       //验证公钥 拼装公钥,可以读文件也可以自行将字符串按64位长度分组拼装
        if (Str::endsWith($this->public_key, '.pem')) {
            $public_key = openssl_pkey_get_public( file_get_contents($this->public_key) );;
        } else {
            $public_key = "-----BEGIN PUBLIC KEY-----\n".
                wordwrap($this->public_key, 64, "\n", true).
                "\n-----END PUBLIC KEY-----";
        }
        
        // 加密
        try {
            openssl_public_encrypt($str,$encrypted, $public_key);

            // base64_encode转码后的内容通常含有特殊字符,在浏览器通过url传输时要注意base64编码是否是url安全的,所以进行url转码
            $encrypted = urlencode(base64_encode($encrypted));

			!is_resource($public_key) ?: openssl_free_key($public_key);

            return $encrypted;

        } catch (\Exception $exception) {
            return $exception->getMessage();
        }
    }
    
    // 私钥解密
    public function decrypt()
    {
        // 公钥加密后的字符串
        $str = 'lj73ktX7FJWb534rbiE...';

        // 验证私钥 拼装私钥
        if (Str::endsWith($this->private_key, '.pem')) {
            $private_key = openssl_pkey_get_private($this->private_key);
        } else {
            $private_key = "-----BEGIN RSA PRIVATE KEY-----\n".
                wordwrap($this->private_key, 64, "\n", true).
                "\n-----END RSA PRIVATE KEY-----";
        }
        
        // 解密
        try {
            openssl_private_decrypt(base64_decode(urldecode($str)), $decrypted, $private_key);

			!is_resource($private_key) ?: openssl_free_key($private_key);
			
            return $decrypted;

        } catch (\Exception $exception) {
            return $exception->getMessage();
        }
    }
}
签名(私钥签名,公钥验签)
<?php
namespace App\Http\Controllers;

use Illuminate\Support\Str;

class RsaController extends Controller
{
    // 这里应直接从配置文件获取,为方便大家查阅直接定义在这里,
    // 公钥和私钥可以直接复制出来以字符串形式配置,也可以配置存放公钥秘钥文件的目录路径
    private $private_key = 'MIIEowIBAAKCAQEAyZGgkPRWyeGIlY';
    private $public_key = storage_path('public_key.pem');
    
    // 私钥签名
    public function genSign()
    {
        // 待生成签名的字符串
        $str = 'a=1&b=2&c=3&d=5';

        // 验证私钥 拼装私钥
        if (Str::endsWith($this->private_key, '.pem')) {
            $private_key = openssl_pkey_get_private($this->private_key);
        } else {
            $private_key = "-----BEGIN RSA PRIVATE KEY-----\n".
                wordwrap($this->private_key, 64, "\n", true).
                "\n-----END RSA PRIVATE KEY-----";
        }

        try {
            openssl_sign($str, $signature, $private_key);

			$sign = base64_encode($signature);
			
			!is_resource($private_key) ?: openssl_free_key($private_key);

            return $sign;

        } catch (\Exception $exception) {
            return $exception->getMessage();
        }
    }

    // 公钥验签
    public function verifySign()
    {
        // 获取到参与签名的字符串
        $str = 'a=1&b=2&c=3&d=5';
        // 私钥生成的签名
        $sign = 'ZSMivQqMFZ1s36NFE9kcB83BcltwII...';

        // 验证公钥 拼装公钥
        if (Str::endsWith($this->public_key, '.pem')) {
            $public_key = openssl_pkey_get_public($this->public_key);
        } else {
            $public_key = "-----BEGIN PUBLIC KEY-----\n".
                wordwrap($this->public_key, 64, "\n", true).
                "\n-----END PUBLIC KEY-----";
        }

        // 验签
        try {
            // 如果签名正确返回 1, 签名错误返回 0, 内部发生错误则返回-1
            $result = openssl_verify($str, base64_decode($sign), $public_key );

			!is_resource($public_key) ?: openssl_free_key($public_key);
			
            return $result === 1

        } catch (\Exception $exception) {
            return $exception->getMessage();
        }
    }
}
使用 RSA2 的签名和验签说明

RSA 默认签名方式为 OPENSSL_ALGO_SHA1 如果使用RSA2的话需要在签名和验签方法中增加参数 OPENSSL_ALGO_SHA256 ,示例如下:

// 签名
openssl_sign($str, $signature, $private_key, OPENSSL_ALGO_SHA256);

// 验签
openssl_verify($str, base64_decode($sign), $public_key, OPENSSL_ALGO_SHA256);

RSA 和 RSA2的区别

签名算法标准签名算法描述
RSA2SHA256WithRSA强制要求 RSA 密钥的长度至少为 2048。
RSASHA1WithRSA对 RSA 密钥的长度不限制,推荐使用 2048 位以上。
结论

以上就是使用 RSA 进行加解密以及签名验签的全部实现了,并不是很复杂,代码稍作修改即可应用在你自己的业务中了。

另外建议在使用 RSA 做签名验证的时候建议使用 RSA2 的方式,相对而言 RSA2 的安全能力是高于 RSA 的。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: PHP RSA 加密是一种非对称加密算法,它使用一对公钥和私钥对数据进行加密和解密。公钥用来加密数据,私钥用来解密数据。使用 PHP 实现 RSA 加密可以使用 openssl 扩展库,该库提供了多种 RSA 算法实现,并可以方便地生成公钥和私钥。例如下面这段代码可以生成一对公钥和私钥 ``` <?php // 生成公钥和私钥 $res = openssl_pkey_new(); // 提取私钥 openssl_pkey_export($res, $privKey); // 提取公钥 $pubKey = openssl_pkey_get_details($res); $pubKey = $pubKey["key"]; // 使用公钥加密数据 $data = "hello world"; openssl_public_encrypt($data, $encrypted, $pubKey); // 使用私钥解密数据 openssl_private_decrypt($encrypted, $decrypted, $privKey); echo $decrypted; ``` ### 回答2: PHP中的RSA加密是一种非对称加密算法,它支持公钥加密和私钥解密的过程。RSA加密的主要步骤如下: 1. 生成密钥对:首先,通过调用PHP的openssl扩展库中的函数生成RSA密钥对,包括公钥和私钥。通常,公钥用于加密数据,私钥用于解密数据。 2. 加密数据:在使用RSA加密之前,需要将待加密数据转换为字节流,并且需要使用公钥进行加密。可通过`openssl_public_encrypt`函数来实现数据的加密。 3. 解密数据:在使用RSA解密之前,需要将密文转换为字节流,并且需要使用私钥进行解密。可通过`openssl_private_decrypt`函数来实现数据的解密。 需要注意的是,RSA加密算法对输入数据的长度有限制,通常能够处理的最大数据长度受到密钥长度的限制。因此,对于需要加密的数据较大的情况,可以使用对称加密算法(如AES)对数据进行加密,再使用RSA加密对称加密的密钥。 此外,为了确保数据的安全性,我们还可以对RSA密钥进行保护,如设置密钥密码、存储密钥的文件权限等。 总之,PHP中的RSA加密提供了一种可靠的非对称加密方式,可以用于保护敏感数据的安全传输。 ### 回答3: RSA(Rivest-Shamir-Adleman)是一种非对称加密算法,常用于数据加密和数字签名PHP中有一些库和函数可以用来实现RSA加密。 首先,我们需要生成一对RSA密钥。可以使用openssl库中的openssl_pkey_new()函数来生成一个新的密钥对,并使用openssl_pkey_export()函数将其导出为字符串格式。这样我们就得到了一个私钥和一个公钥。 然后,我们可以使用openssl_public_encrypt()函数使用公钥对要加密的数据进行加密。这个函数将返回一个加密后的字符串,在解密时需要使用私钥进行解密。 最后,我们可以使用openssl_private_decrypt()函数使用私钥对加密后的数据进行解密。这个函数将返回解密后的原始数据。 下面是一个使用RSA加密的简单示例: ```php // 生成RSA密钥对 $res = openssl_pkey_new(); openssl_pkey_export($res, $private_key); $public_key = openssl_pkey_get_details($res)['key']; // 要加密的数据 $data = 'Hello, World!'; // 使用公钥加密数据 openssl_public_encrypt($data, $encrypted, $public_key); // 使用私钥解密数据 openssl_private_decrypt($encrypted, $decrypted, $private_key); // 输出解密后的数据 echo $decrypted; // Hello, World! ``` 这是一个简单的示例,实际使用中可能需要更复杂的逻辑来处理数据的加密和解密。此外,还应该注意保护好私钥,确保只有授权的人才能访问私钥,以防止数据被非法解密。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吹落的树叶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值