前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >RSA 签名/验签 (PHP为例),以及各个秘钥格式解析

RSA 签名/验签 (PHP为例),以及各个秘钥格式解析

作者头像
躺平程序员老修
发布2023-09-05 16:08:58
7100
发布2023-09-05 16:08:58
举报
文章被收录于专栏:躺平程序员老修

函数明细

  • openssl_pkey_get_details返回包含密钥详情的数组,如类型type,加密位数bits等
    • openssl_pkey_get_private获取私钥

只能打开是PEM格式的秘钥,成功返回资源类型

  • openssl_pkey_get_public获取公钥

只能打开是PEM格式的秘钥,成功返回资源类型

  • openssl_private_encrypt使用私钥加密数据

加密后的数据可以通过openssl_public_decrypt()函数来解密 该函数用来签名数据(或者哈希)让别人相信数据并不是其他人写的

  • openssl_public_decrypt解密先前由 openssl_private_encrypt() 加密的数据,并且将结果保存至第二个参数中

你可以用该函数来校验消息是否是私钥拥有者写的。

  • openssl_public_encrypt使用公钥加密数据

该函数可以用来加密数据,供该公钥匹配的私钥拥有者读取。 它也可以用来在数据库中存储安全数据。

  • openssl_private_decrypt使用私钥解密数据

openssl_private_decrypt() 解密先前通过 openssl_public_encrypt() 函数加密的 data 你可以用该函数来解密只对你可用的数据。

  • openssl_sign生成签名,通过使用与之关联的私钥生成加密数字签名来计算指定的签名
  • openssl_verify验证签名,通过使用关联的公钥验证指定数据的签名是否正确, 通过返回int 1
  • openssl_free_key从内存中释放密钥资源

用例解析

代码语言:javascript
复制
/**
 * 通用rsa认证与加密类
 *
 * @author litblc
 * User: z00455118
 * Date: 2019/7/15
 * Time: 19:20
 */

class RSA
{
    /**
     * 签名算法, 默认为 OPENSSL_ALGO_SHA1
     */
    const RSA_ALGORITHM_SIGN = OPENSSL_ALGO_SHA256;

    /**
     * 公钥
     * @var string
     */
    private static $publicKey = 'file:///D:/cert/public-key.pem';

    /**
     * 私钥
     * @var string
     */
    private static $privateKey = 'file:///D:/cert/private-key.pem';

    /**
     * 第三方公钥 交互验签使用
     * @var string
     */
    private static $thirdPublicKey = 'file:///D:/cert/third-public-key.pem';

    /**
     * 初始化秘钥信息
     * @var string
     */
    public function __construct($config)
    {
        self::$publicKey = CERT_DIR . $config['publicKey'];
        self::$privateKey = CERT_DIR . $config['privateKey'];
        self::$thirdPublicKey = CERT_DIR . $config['thirdPublicKey'];
    }
    /**
     * 是否使用安全base64需要参考第三方验签的解析方案,如果也是php推荐使用安全方式
     * @param $data
     * @return string
     */
    private static function url_safe_base64_encode($data)
    {
        return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($data));
    }

    /**
     * @param $data
     * @return string
     */
    private static function url_safe_base64_decode($data)
    {
        $base_64 = str_replace(['-', '_'], ['+', '/'], $data);

        return base64_decode($base_64);
    }

    /**
     * 获取rsa密钥加密位数
     * @param $source
     * @return mixed
     */
    private static function getKeyBitDetail($source)
    {
        return openssl_pkey_get_details($source)['bits'];
    }

    /**
     * 获取文本格式私钥 并重新格式化 为保证任何key都可以识别
     * 由于各个语言以及环境使用的证书格式不同。参考下一节: ### 秘钥格式解析
     * @return bool|resource
     */
    private static function getPrivateKey()
    {
        if (file_exists(self::$publicKey)) {
            $source =  file_get_contents(self::$privateKey);

            $search = [
                "-----BEGIN RSA PRIVATE KEY-----",
                "-----END RSA PRIVATE KEY-----",
                "\n",
                "\r",
                "\r\n"
            ];

            $private_key = str_replace($search,"",$source);
            return openssl_pkey_get_private($search[0] . PHP_EOL . wordwrap($private_key, 64, "\n", true) . PHP_EOL . $search[1]);
        }
    }

    /**
     * 获取公钥 并重新格式化
     * @return resource
     */
    private static function getPublicKey()
    {
        if (file_exists(self::$publicKey)) {
            $source = file_get_contents(self::$publicKey);

            $search = [
                "-----BEGIN PUBLIC KEY-----",
                "-----END PUBLIC KEY-----",
                "\n",
                "\r",
                "\r\n"
            ];
            $public_key = str_replace($search,"",$source);

            return openssl_pkey_get_public($search[0] . PHP_EOL . wordwrap($public_key, 64, "\n", true) . PHP_EOL . $search[1]);
        }
    }

    /**
     * 获取第三方公钥,并格式化
     * @return resource
     */
    private static function getPublicKeyThird()
    {
        if (file_exists(self::$thirdPublicKey)) {
            $source = file_get_contents(self::$thirdPublicKey);

            $search = [
                "-----BEGIN PUBLIC KEY-----",
                "-----END PUBLIC KEY-----",
                "\n",
                "\r",
                "\r\n"
            ];
            $public_key = str_replace($search, "", $source);

            return openssl_pkey_get_public($search[0] . PHP_EOL . wordwrap($public_key, 64, "\n", true) . PHP_EOL . $search[1]);
        }
    }

    /**
     * 排序数据并生成待验签字符串(类似微信支付,使用此方法,而非例子中json_encode方法)
     * @return string
     */
    private static function createLinkString($data = [])
    {
        unset($data['sign']);

        foreach ($data as $key => $val) {
            if (!$val) {
                unset($data[$key]);
            }
        }
        ksort($data);

        return urldecode(http_build_query($data));
    }

    /**
     * 排序数据并生成待验签字符串(类似微信支付,使用此方法,而非例子中json_encode方法)
     * @return string
     */
    public static function createLinkStringNew($data = [])
    {
        $mac = '';
        ksort($data);
        unset($data['sign'], $data['sign_type']);

        foreach ($data as $key => $val) {
            if ($val) {
                $mac .= "&{$key}={$val}";
            }
        }

        return ltrim($mac, '&');
    }

    /**
     * 私钥加密
     * @param $data
     * @return bool|null
     */
    public static function privEncrypt($data = '')
    {
        $privKey = self::getPrivateKey();

        $partLen = self::getKeyBitDetail($privKey) / 8 - 11;

        $parts = str_split($data, $partLen);

        $encrypted = '';

        foreach ($parts as $part) {
            openssl_private_encrypt($part, $partEncrypt, $privKey);
            $encrypted .= $partEncrypt;
        }
        openssl_free_key($privKey);

        return $encrypted ? self::url_safe_base64_encode($encrypted) : null;
    }

    /**
     * 公钥解密
     * @param string $encrypted
     * @return bool|null
     */
    public static function publicDecrypt($encrypted = '')
    {
        $pubKey = self::getPublicKey();

        $partLen = self::getKeyBitDetail($pubKey) / 8;

        $parts = str_split(self::url_safe_base64_decode($encrypted), $partLen);

        $decrypted = '';

        foreach ($parts as $part) {
            openssl_public_decrypt($part, $partDecrypt, $pubKey);
            $decrypted .= $partDecrypt;
        }

        openssl_free_key($pubKey);

        return $decrypted ?: null;
    }

    /**
     * 公钥加密
     * @param string $data
     * @return bool|null
     */
    public static function publicEncrypt($data = '')
    {
        $pubKey = self::getPublicKey();

        $partLen = self::getKeyBitDetail($pubKey) / 8 - 11;

        $parts = str_split($data, $partLen);

        $encrypted = '';

        foreach ($parts as $part) {
            openssl_public_encrypt($part, $partEncrypt, $pubKey);
            $encrypted .= $partEncrypt;
        }

        openssl_free_key($pubKey);

        return $encrypted ? self::url_safe_base64_encode($encrypted) : null;
    }

    /**

     * 私钥解密
     * @param string $encrypted
     * @return bool|null
     */
    public static function privDecrypt($encrypted = '')
    {
        $privKey = self::getPrivateKey();

        $partLen = self::getKeyBitDetail($privKey) / 8;

        $parts = str_split(self::url_safe_base64_decode($encrypted), $partLen);

        $decrypted = '';

        foreach ($parts as $part) {
            openssl_private_decrypt($part, $partDecrypt, $privKey);
            $decrypted .= $partDecrypt;
        }

        openssl_free_key($privKey);

        return $decrypted ?: null;
    }

    /**
     * 私钥签名
     * @param array $data
     * @return null|string
     */
    public static function privSign($data = [])
    {
        $privKey = self::getPrivateKey();

        openssl_sign(self::createLinkStringNew($data), $sign, $privKey, self::RSA_ALGORITHM_SIGN);

        openssl_free_key($privKey);

        return $sign ? self::url_safe_base64_encode($sign) : null;
    }

    /**
     * 公钥验签
     * @param array $data
     * @param string $sign
     * @return int
     */
    public static function publicVerifySign($data = [], $sign = '')
    {
        $pubKey = self::getPublicKey();

        $res = openssl_verify(self::createLinkStringNew($data), self::url_safe_base64_decode($sign), $pubKey, self::RSA_ALGORITHM_SIGN);

        openssl_free_key($pubKey);

        return $res;
    }

    /**
     * 公钥验签(第三方)
     * @param array $data
     * @param string $sign
     * @return int
     */
    public static function publicVerifySignThird($data = [], $sign = '')
    {
        $pubKey = self::getPublicKeyThird();

        $res = openssl_verify(self::createLinkStringNew($data), self::url_safe_base64_decode($sign), $pubKey, self::RSA_ALGORITHM_SIGN);

        openssl_free_key($pubKey);

        return $res;
    }
}

测试输出

代码语言:javascript
复制
$data['name'] = '网红';
$data['age'] = '26';
$data['title'] = '中华人民共和国公民';
$data['english'] = 'litblc.com';


// 私钥加密 公钥解密
$privSec = RSA::privEncrypt(json_encode($data));
echo '私钥加密:' . $privSec . '<br/>';
echo '公钥解密:' . RSA::publicDecrypt($privSec) . '<br/>';
echo '<hr>';

// 公钥加密 私钥解密
$pubSec = RSA::publicEncrypt(json_encode($data));
echo '公钥加密:' . $pubSec . '<br/>';
echo '私钥解密:' . RSA::privDecrypt($pubSec) . '<br/>';
echo '<hr>';

// 验签
$sign = RSA::privSign($data);
echo '私钥签名后:' . $sign . '<br/>';
echo '公钥验签后:' . RSA::publicVerifySign($data, $sign) . '<br/>';

秘钥格式解析

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 函数明细
  • 用例解析
  • 测试输出
  • 秘钥格式解析
相关产品与服务
SymantecSSL 证书
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档