吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1997|回复: 7
收起左侧

[C&C++ 原创] C++对RSA加密、解密的使用

[复制链接]
黎昕 发表于 2023-8-22 10:37
这几天也是无聊,想改一下验证的加解密来着,后来想想如果并发量起来的话,反而会影响效率,但是代码已经写完了,放出来大家一起学习吧。
代码包含C++、PHP完整的例子,没写加签、验签,这个不难。
支持中文、超大字符串加密(分段加密/解密)
期间卡了很久,发现php的base64_encode跟我C++写的base64_encode结果不一致,调试了很久才发现是被加密数据如果有中文的话,就会导致不一致。
所以放出来避免大家壁坑吧。
调用了 OpenSSL库,大家自己下载安装即可

[PHP] 纯文本查看 复制代码
<?php
class Openssl
{
    /**
     * 配置信息.
     * publicKey => string.
     * privateKey => string.
     *
     * @var mixed
     */
    protected $config;
    /**
     * 初始化.
     *
     * @Param array $config
     */
    public function __construct($config)
    {
        $this->config = $config;
    }
    /**
     * 获取密钥分段加密长度.
     *
     * @param Closure $keyClosure
     *
     * @Return int
     *
     * @throws Exception
     */
    protected function getEncryptBlockLen($keyClosure)
    {
        $key_info = openssl_pkey_get_details($keyClosure);
        if (!$key_info)
        {
            throw new Exception('获取密钥信息失败' . openssl_error_string());
        }
        // bits数除以8 减去padding长度,OPENSSL_PKCS1_PADDING 长度是11
        // php openssl 默认填充方式是 OPENSSL_PKCS1_PADDING
        return $key_info['bits'] / 8 - 11;
    }
    /**
     * 获取密钥分段解密长度.
     *
     * @param Closure $keyClosure
     *
     * @return int
     *
     * @throws Exception
     */
    protected function getDecryptBlockLen($keyClosure)
    {
        $key_info = openssl_pkey_get_details($keyClosure);
        if (!$key_info)
        {
            throw new Exception('获取密钥信息失败' . openssl_error_string());
        }
        // bits数除以8得到字符长度
        return $key_info['bits'] / 8;
    }
    /**
     * 数据加密.
     *
     * @param string $text 需要加密的文本
     * @param int $type 加密方式:1.公钥加密 2.私钥加密
     *
     * @return string
     *
     * @throws Exception
     */
    public function encrypt($text, $type)
    {
        //获取密钥资源
        $keyClosure = 1 == $type ? openssl_pkey_get_public($this->config['publicKey']) : openssl_pkey_get_private($this->config['privateKey']);
        if (!$keyClosure)
        {
            throw new Exception('获取密钥失败,请检查密钥是否合法');
        }
        //RSA进行加密
        $encrypt = '';
        $plainData = str_split($text, $this->getEncryptBlockLen($keyClosure));
        foreach ($plainData as $key => $encrypt_item)
        {
            $isEncrypted = (1 == $type) ? openssl_public_encrypt($encrypt_item, $encrypted, $keyClosure) : openssl_private_encrypt($encrypt_item, $encrypted, $keyClosure);
            if (!$isEncrypted)
            {
                throw new Exception('加密数据失败,请检查密钥是否合法,' . openssl_error_string());
            }
            $encrypt .= $encrypted;
        }
        $encrypt = base64_encode($encrypt);
        //返回
        return $encrypt;
    }
    /**
     * 数据解密.
     *
     * @param string $text 需要加密的文本
     * @param int $type 加密方式:1.公钥加密 2.私钥加密
     *
     * @return string
     *
     * @throws Exception
     * @throws
     */
    public function decrypt($text, $type)
    {
        //获取密钥资源
        $keyClosure = 1 == $type ? openssl_pkey_get_public($this->config['publicKey']) : openssl_pkey_get_private($this->config['privateKey']);
        if (!$keyClosure)
        {
            throw new Exception('获取密钥失败,请检查密钥是否合法');
        }
        //RSA进行解密
        $data = base64_decode($text);
        $data = str_split($data, $this->getDecryptBlockLen($keyClosure));
        $decrypt = '';
        foreach ($data as $key => $chunk)
        {
            $isDecrypted = (1 == $type) ? openssl_public_decrypt($chunk, $encrypted, $keyClosure) : openssl_private_decrypt($chunk, $encrypted, $keyClosure);
            if (!$isDecrypted)
            {
                throw new Exception('解密数据失败,请检查密钥是否合法,' . openssl_error_string());
            }
            $decrypt .= $encrypted;
        }
        //返回
        return $decrypt;
    }
}
//01.配置公钥私钥 publicKey:公钥 privateKey:私钥
$config = [
    'publicKey' => '-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqUsK1vxiaPtlpKWrYOez
...省略..
mX1MJYsP9eP6FeGylvYIz/GtrUA7e4eHD1xriyEDwwpZ8EyNzYKTDAhktkyw55zS
nQIDAQAB
-----END PUBLIC KEY-----',
    'privateKey' => '-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCpSwrW/GJo+2Wk
...省略..
Oc8mrEYKQyozBvV7SPgYew==
-----END PRIVATE KEY-----',
];
//02.初始化
$openssl = new Openssl($config);
//03.私钥加密->公钥解密
$a = "pwsLvMjnd2i*vS$!-6Pqiw9zp%wRc5d-N*oGcJ@=I!hj8A1测&OXvjEWUr7Yi3mC3h&*WDQlW_yj6u#F!os4%rQ试3AgX99gXqn4HJ";
echo '原始数据 : '. $a .'<br/>';
$privateEnData = $openssl->encrypt(base64_encode($a) , 2);  //私钥加密
$publicDeData = $openssl->decrypt($privateEnData, 1); //公钥解密

echo '私钥加密数据 : '. $privateEnData .'<br/>';
echo '公钥解密数据 : '. base64_decode($publicDeData) .'<br/><br/><br/>';

//04.公钥加密->私钥解密
$b = "+i#JTRLN8#lOgyfGTEvrn5H@测lTk#tgu!2Zs%*+kFg2&ob_s5VkmWf试peK7Sbm!8SfPf70xyt6q7cou8Pef4RO4Sf5ad8B9D&Mfld";
echo '原始数据 : '. $b .'<br/>';
$publicEnData = $openssl->encrypt(base64_encode($b), 1); //公钥加密
$privateDeData = $openssl->decrypt($publicEnData, 2); //私钥解密

echo '公钥加密数据'. $publicEnData .'<br/>';
echo '私钥解密数据'. base64_decode($privateDeData) .'<br/>';



def.h
[C++] 纯文本查看 复制代码
#include <windows.h>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <stdio.h>
#include <string>
#include <vector>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include "rsas.h"
using namespace std;

#pragma comment(lib,"libcrypto.lib")
#pragma comment(lib,"WS2_32.lib")
#pragma comment(lib,"Crypt32.lib")


rsas.h
[C++] 纯文本查看 复制代码
#include <assert.h>
std::string Base64Encode(const unsigned char* data, size_t size)
{
        size_t base64_len = (size + 2) / 3 * 4;
        if (base64_len == 0)
        {
                return "";
        }
        std::string ret;
        ret.resize(base64_len);
        EVP_EncodeBlock((unsigned char*)ret.data(), data, size);
        return std::move(ret);
}

std::string Base64Decode(const std::string& src)
{
        size_t srcLen = src.size();
        if (srcLen % 4 != 0)
        {
                return "";
        }
        std::string ret1;
        size_t destLen = (srcLen / 4) * 3;
        ret1.resize(destLen);

        //todo: 判断返回值
        int ret = EVP_DecodeBlock((unsigned char*)ret1.data(), (const unsigned char*)src.c_str(), srcLen);
        if (ret == -1)
        {
                //base64 decode failed
                return "";
        }
        int i = 0;
        while (src.at(--srcLen) == '=')
        {
                ret--;
                if (++i > 2)
                {
                        // input maybe not base64 str;
                        return "";
                }
        }

        return std::move(ret1);
}

char* G2U(const char* gb2312)
{
        int len = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, NULL, 0);
        wchar_t* wstr = new wchar_t[len + 1];
        memset(wstr, 0, len + 1);
        MultiByteToWideChar(CP_ACP, 0, gb2312, -1, wstr, len);
        len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
        char* str = new char[len + 1];
        memset(str, 0, len + 1);
        WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
        if (wstr) delete[] wstr;
        return str;
}
//UTF-8到GB2312的转换
char* U2G(const char* utf8)
{
        int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
        wchar_t* wstr = new wchar_t[len + 1];
        memset(wstr, 0, len + 1);
        MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, len);
        len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
        char* str = new char[len + 1];
        memset(str, 0, len + 1);
        WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL);
        if (wstr) delete[] wstr;
        return str;
}
/** 公钥加密*/
std::string encrypt_RSA_by_long_str_public_key(std::string publicKey, const std::string& data)
{
        auto b = G2U(data.data());
        auto c = Base64Encode((const unsigned char*)b, strlen(b));
        std::string strRet;
        //创建RSA指针
        BIO* keybio = BIO_new_mem_buf((unsigned char*)publicKey.c_str(), -1);
        RSA* rsa = RSA_new(); 
        
        //rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);//这个失败,二脸萌壁..
        rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa, NULL, NULL);
        if (!rsa)
        {
                BIO_free_all(keybio);
                return std::string("");
        }

        int len = RSA_size(rsa);
        char* decryptedText = (char*)malloc(len + 1);
        memset(decryptedText, 0, len + 1);
        int nClearDataLen = c.length();
        int pdBlock = len - 11;
        int nCount = (nClearDataLen / pdBlock) + 1;
        //分段次数
        unsigned char* pClearData = (unsigned char*)c.c_str();
        //分段加密
        for (int i = 0; i < nCount; i++)
        {
                int nSize = 0;
                pdBlock = (nClearDataLen > pdBlock) ? pdBlock : nClearDataLen;
                nSize = RSA_public_encrypt(pdBlock, (const unsigned char*)pClearData, (unsigned char*)decryptedText, rsa, RSA_PKCS1_PADDING);
                pClearData += pdBlock;
                nClearDataLen -= pdBlock;
                if (nSize >= 0)
                {
                        strRet += std::string(decryptedText, nSize);
                }
        }
        // 释放内存
        delete decryptedText;
        BIO_free_all(keybio);
        RSA_free(rsa);
        return Base64Encode((const unsigned char*)strRet.c_str(), strRet.length());
}

/** 公钥解密*/
std::string decrypt_RSA_by_long_str_public_key(std::string publicKey, const std::string& data)
{
        auto a = Base64Decode(data);
        std::string strRet;
        //创建RSA指针
        BIO* keybio = BIO_new_mem_buf((unsigned char*)publicKey.c_str(), -1);
        RSA* rsa = RSA_new();

        //rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);//这个失败,二脸萌壁..
        rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa, NULL, NULL);
        if (!rsa)
        {
                BIO_free_all(keybio);
                return std::string("");
        }
        int len = RSA_size(rsa);
        char* decryptedText = (char*)malloc(len + 1);
        memset(decryptedText, 0, len + 1);
        int nClearDataLen = a.length();
        int pdBlock = len;
        int nCount = (nClearDataLen / pdBlock) + 1;
        //分段次数
        unsigned char* pClearData = (unsigned char*)a.c_str();
        //分段解密
        for (int i = 0; i < nCount; i++)
        {
                int nSize = 0;
                pdBlock = (nClearDataLen > pdBlock) ? pdBlock : nClearDataLen;
                nSize = RSA_public_decrypt(pdBlock, (const unsigned char*)pClearData, (unsigned char*)decryptedText, rsa, RSA_PKCS1_PADDING);
                pClearData += pdBlock;
                nClearDataLen -= pdBlock;
                if (nSize >= 0)
                {
                        strRet += std::string(decryptedText, nSize);
                }
        }
        // 释放内存
        delete decryptedText;
        BIO_free_all(keybio);
        RSA_free(rsa);
        std::string  bb = Base64Decode(strRet);
        return U2G(bb.c_str());
}

/** 私钥加密*/
std::string encrypt_RSA_by_long_str_private_key(std::string privateKey, const std::string& data)
{
        auto b = G2U(data.data());
        auto c = Base64Encode((const unsigned char*)b, strlen(b));
        std::string strRet;
        //创建RSA指针
        RSA* rsa = RSA_new();
        BIO* keybio;
        keybio = BIO_new_mem_buf((unsigned char*)privateKey.c_str(), -1);

        rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);

        int len = RSA_size(rsa);
        char* decryptedText = (char*)malloc(len + 1);
        memset(decryptedText, 0, len + 1);
        int nClearDataLen = c.length();
        int pdBlock = len - 11;
        int nCount = (nClearDataLen / pdBlock) + 1;
        //分段次数
        unsigned char* pClearData = (unsigned char*)c.c_str();
        //分段加密
        for (int i = 0; i < nCount; i++)
        {
                int nSize = 0;
                pdBlock = (nClearDataLen > pdBlock) ? pdBlock : nClearDataLen;
                nSize = RSA_private_encrypt(pdBlock, (const unsigned char*)pClearData, (unsigned char*)decryptedText, rsa, RSA_PKCS1_PADDING);
                pClearData += pdBlock;
                nClearDataLen -= pdBlock;
                if (nSize >= 0)
                {
                        strRet += std::string(decryptedText, nSize);
                }
        }
        // 释放内存
        delete decryptedText;
        RSA_free(rsa);
        
        return Base64Encode((const unsigned char*)strRet.c_str(), strRet.length());
}

/** 私钥解密*/
std::string decrypt_RSA_by_long_str_private_key(std::string privateKey, const std::string& data)
{
        auto a = Base64Decode(data);
        std::string strRet;
        //创建RSA指针
        RSA* rsa = RSA_new();
        BIO* keybio;
        keybio = BIO_new_mem_buf((unsigned char*)privateKey.c_str(), -1);

        rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);

        int len = RSA_size(rsa);
        char* decryptedText = (char*)malloc(len + 1);
        memset(decryptedText, 0, len + 1);
        int nClearDataLen = a.length();
        int pdBlock = len;
        int nCount = (nClearDataLen / pdBlock) + 1;
        //分段次数
        unsigned char* pClearData = (unsigned char*)a.c_str();
        //分段解密
        for (int i = 0; i < nCount; i++)
        {
                int nSize = 0;                
                pdBlock = (nClearDataLen > pdBlock) ? pdBlock : nClearDataLen;
                nSize = RSA_private_decrypt(pdBlock, (const unsigned char*)pClearData, (unsigned char*)decryptedText, rsa, RSA_PKCS1_PADDING);
                pClearData += pdBlock;
                nClearDataLen -= pdBlock;
                if (nSize >= 0)
                {
                        strRet += std::string(decryptedText, nSize);
                }
        }
        // 释放内存
        delete decryptedText;
        RSA_free(rsa);
        std::string  bb = Base64Decode(strRet);
        return U2G(bb.c_str());
}


main.cpp
[C++] 纯文本查看 复制代码
#include "def.h"
int main()
{
//私钥
std::string pri = "-----BEGIN PRIVATE KEY-----\n"\
                "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCpSwrW/GJo+2Wk"\
//省略
                "Oc8mrEYKQyozBvV7SPgYew==\n"\
                "-----END PRIVATE KEY-----";
//公钥
        std::string pub = "-----BEGIN PUBLIC KEY-----\n"\
                "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqUsK1vxiaPtlpKWrYOez"\
//省略
                "mX1MJYsP9eP6FeGylvYIz/GtrUA7e4eHD1xriyEDwwpZ8EyNzYKTDAhktkyw55zS"\
                "nQIDAQAB\n"\
                "-----END PUBLIC KEY-----";
        std::string a = "pwsLvMjnd2i*vS$!-6Pqiw9zp%wRc5d-N*oGcJ@=I!hj8A1测&OXvjEWUr7Yi3mC3h&*WDQlW_yj6u#F!os4%rQ试3AgX99gXqn4HJ";
        cout << "原始数据 : " << a.c_str() << endl;
        cout << endl;
        auto enc_data_pri = encrypt_RSA_by_long_str_private_key(pri, a);
        cout << "私钥加密数据 : " << enc_data_pri.c_str() << endl;
        cout << endl;
        auto dec_data_pub = decrypt_RSA_by_long_str_public_key(pub, enc_data_pri);
        cout << "公钥解密数据 : " << dec_data_pub.c_str() << endl;

        cout << endl;
        cout << endl;

        std::string b = "+i#JTRLN8#lOgyfGTEvrn5H@测lTk#tgu!2Zs%*+kFg2&ob_s5VkmWf试peK7Sbm!8SfPf70xyt6q7cou8Pef4RO4Sf5ad8B9D&Mfld";
        cout << "原始数据 : " << b.c_str() << endl;
        cout << endl;
        auto enc_data_pub = encrypt_RSA_by_long_str_public_key(pub, b);
        cout << "公钥加密 : " << enc_data_pub.c_str() << endl;
        cout << endl;
        auto dec_data_pri = decrypt_RSA_by_long_str_private_key(pri, enc_data_pub);
        cout << "私钥解密 : " << dec_data_pri.c_str() << endl;

        cout << endl;
        cout << endl;
        system("pause");
        return 0;
}


测试结果:
QQ图片20230822103523.png

Blog地址:https://3musen.com/2023/08/19/C++/C++%20%E4%BD%BF%E7%94%A8RSA%E5%8A%A0%E5%AF%86%E3%80%81%E8%A7%A3%E5%AF%86%E6%95%99%E7%A8%8B/

免费评分

参与人数 7吾爱币 +13 热心值 +6 收起 理由
hzh193536 + 1 + 1 我很赞同!
ailmail + 1 谢谢@Thanks!
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
helian147 + 1 + 1 热心回复!
shuaibi_chen + 1 + 1 用心讨论,共获提升!
zpy2 + 1 + 1 谢谢@Thanks!
gunxsword + 1 + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

L__ 发表于 2023-8-22 11:52
优秀,谢谢分享
shuaibi_chen 发表于 2023-8-22 12:35
gusong125 发表于 2023-8-22 13:17
haoxia57 发表于 2024-8-3 09:52
谢谢楼主分享
ailmail 发表于 2024-8-3 16:25
收藏学习代码
787821 发表于 2024-8-6 08:28
不错不错,谢谢分享
Anonyoung 发表于 2024-8-6 20:02

学习学习代码
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 12:34

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表