锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

PHP 实现RSA,RSA2 加密和签名

时间:2022-11-18 01:00:00 电位器rsa0k11v901s

目录

        • 前情提要
        • 生成 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)。

加密(公钥加密,私钥解密)

 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_publicfile_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();
        }
    }
}

签名(私钥签名,公钥验签)


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的区别

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

结论

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

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

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章