IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> PHP 实现RSA,RSA2 加密和签名 -> 正文阅读

[PHP知识库]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 的。

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 15:58:20  更:2022-04-06 15:59:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 6:02:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码