PHP RSA生成公钥和私钥对及加解密


基于PHP OpenSSL 扩展 生成RSA密钥对,和RSA加密解密,且支持长文加密和解密。


条件:

需要安装开启OpenSSL扩展。


PHP RSA 效果:
1、RSA RSA生成公钥和私钥对>> RSA 密钥生成

2、RSA加密解密,且支持长文加密和解密 >> RSA 公钥/私钥加解密


PHP RSA处理类:

<?php
/**
 * PHP RSA生成公钥和私钥对及加解密
 */

namespace rsa;


class RsaHandle
{

    /**
     * RsaHandle constructor.
     * @throws \Exception
     */
    public function __construct()
    {
        //检查 扩展是否安装
        if (extension_loaded('openssl') == false){
            $msg = "请先安装开启openssl扩展";
            throw new \Exception($msg);
        }
    }

    /**
     * 创建生成密钥 公钥私钥
     * @param int $private_key_bits 指定多少位来生成私钥 //字节数  512 1024 2048  4096 等 ,不能加引号,此处长度与加密的字符串长度有关系
     * @return array
     */
    public  function createRsaKey($private_key_bits = 1024)
    {

        //参考文章
        //https://www.cnblogs.com/guliang/p/16171260.html

        //配置信息
        $config = array(
            //'digest_alg' => 'sha512',
            'private_key_bits' => $private_key_bits,//指定多少位来生成私钥 //字节数  512 1024 2048  4096 等 ,不能加引号,此处长度与加密的字符串长度有关系
            'private_key_type' => OPENSSL_KEYTYPE_RSA //加密类型
        );

        $system_name = PHP_OS;

        if ($system_name === "WINNT"){
            //windows系统
            //报错 openssl_pkey_export(): cannot get key from parameter 1这个问题 是 没有找到 config cnf 文件路径,我这里用的是PHPstudy Apache 目录有 直接指向 就可
            //https://blog.csdn.net/jachinFang/article/details/94598969
            //将apache中的openssl.cnf复制 $config['config'] 进去,然后就可以尝试测试结果了

            $config['config'] = 'D:\phpstudy_pro\Extensions\Apache2.4.39\conf/openssl.cnf';//找到你的PHP目录下openssl配置文件
        }

        $res = openssl_pkey_new($config);
        //获取私钥
        openssl_pkey_export($res, $private_key, null, $config);
        //获取公钥
        $details = openssl_pkey_get_details($res);
        $public_key = $details['key'];

        return array('public_key' => $public_key, 'private_key' => $private_key);
    }


    /**
     * 获取密钥分段加密长度.
     * @param $keyClosure openssl_pkey_get_public($this->config['publicKey']) : openssl_pkey_get_private($this->config['privateKey']);
     * @return float|int

     * @throws \Exception
     */
    protected function getEncryptBlockLen($keyClosure)
    {
        $key_info = openssl_pkey_get_details($keyClosure);
        if (!$key_info)
        {
            $msg = '获取加密密钥信息失败' . openssl_error_string();
            throw new \Exception($msg);
        }
        // bits数除以8 减去padding长度,OPENSSL_PKCS1_PADDING 长度是11
        // php openssl 默认填充方式是 OPENSSL_PKCS1_PADDING
        return $key_info['bits'] / 8 - 11;
    }

    /**
     * 获取密钥分段解密长度.
     * @param $keyClosure openssl_pkey_get_public($this->config['publicKey']) : openssl_pkey_get_private($this->config['privateKey']);
     * @return float|int

     * @throws \Exception
     */
    protected function getDecryptBlockLen($keyClosure)
    {
        $key_info = openssl_pkey_get_details($keyClosure);
        if (!$key_info)
        {
            $msg = '获取解密密钥信息失败' . openssl_error_string();
            throw new \Exception($msg);
        }
        // bits数除以8得到字符长度
        return $key_info['bits'] / 8;
    }


    /**
     * 公钥加密
     * @param $text
     * @param string $public_key
     * @return string

     * @throws \Exception
     */
    public function rsaEncodePublic($text, $public_key = '公钥加密私钥解密')
    {
        $keyClosure = openssl_pkey_get_public($public_key);
        if (!$keyClosure) {
            $msg = '公钥不可用';
            throw new \Exception($msg);
        }
        //RSA进行加密
        $encrypt = '';
        $plainData = str_split($text, $this->getEncryptBlockLen($keyClosure));
        foreach ($plainData as $key => $encrypt_item)
        {
            $isEncrypted = openssl_public_encrypt($encrypt_item, $encrypted, $keyClosure);
            if (!$isEncrypted)
            {
                $msg = '加密数据失败,请检查密钥是否合法,' . openssl_error_string();
                throw new \Exception($msg);
            }
            $encrypt .= $encrypted;
        }
        $encrypt = base64_encode($encrypt);
        //返回
        return $encrypt;
    }

    /**
     * 私钥加密
     * @param $text
     * @param string $private_key
     * @return string
     * @throws \Exception
     */
    public function rsaEncodePrivate($text, $private_key = '私钥加密公钥解密')
    {
        $keyClosure = openssl_pkey_get_private($private_key);
        if (!$keyClosure) {
            $msg = '私钥不可用';
            throw new \Exception($msg);
        }
        //RSA进行加密
        $encrypt = '';
        $plainData = str_split($text, $this->getEncryptBlockLen($keyClosure));
        foreach ($plainData as $key => $encrypt_item)
        {
            $isEncrypted = openssl_private_encrypt($encrypt_item, $encrypted, $keyClosure);
            if (!$isEncrypted)
            {
                $msg = '加密数据失败,请检查密钥是否合法,' . openssl_error_string();
                throw new \Exception($msg);
            }
            $encrypt .= $encrypted;
        }
        $encrypt = base64_encode($encrypt);
        //返回
        return $encrypt;
    }

    /**
     * 私钥解密
     * @param $text
     * @param string $private_key
     * @return string
     * @throws \Exception
     */
    public function rsaDecodePrivate($text,$private_key = '公钥加密私钥解密')
    {
        $keyClosure = openssl_pkey_get_private($private_key);
        if (!$keyClosure) {
            $msg = '私钥不可用';
            throw new \Exception($msg);
        }
        //RSA进行解密
        $data = base64_decode($text);
        $data = str_split($data, $this->getDecryptBlockLen($keyClosure));
        $decrypt = '';
        foreach ($data as $key => $chunk)
        {
            $isDecrypted = openssl_private_decrypt($chunk, $encrypted, $keyClosure);
            if (!$isDecrypted)
            {
                $msg = '解密数据失败,请检查密钥是否合法,' . openssl_error_string();
                throw new \Exception($msg);
            }
            $decrypt .= $encrypted;
        }
        //返回
        return $decrypt;
    }

    /**
     * 公钥解密
     * @param $text
     * @param string $public_key
     * @return string
     * @throws \Exception
     */
    public function rsaDecodePublic($text,$public_key = '私钥加密公钥解密')
    {
        $keyClosure = openssl_pkey_get_public($public_key);
        if (!$keyClosure) {
            $msg = '公钥不可用';
            throw new \Exception($msg);
        }
        //RSA进行解密
        $data = base64_decode($text);
        $data = str_split($data, $this->getDecryptBlockLen($keyClosure));
        $decrypt = '';
        foreach ($data as $key => $chunk)
        {
            $isDecrypted = openssl_public_decrypt($chunk, $encrypted, $keyClosure);
            if (!$isDecrypted)
            {
                $msg = '解密数据失败,请检查密钥是否合法,' . openssl_error_string();
                throw new \Exception($msg);
            }
            $decrypt .= $encrypted;
        }
        //返回
        return $decrypt;
    }


}


参考文章:
https://php.net/manual/en/function.openssl-pkey-new.php

https://www.cnblogs.com/guliang/p/16171260.html

https://blog.csdn.net/jachinFang/article/details/94598969



云天阁
非我而当者,吾师也;是我而当者,吾友也;谄谀我者,吾贼也。
搜索