黎昕 发表于 2023-8-22 10:37

C++对RSA加密、解密的使用

这几天也是无聊,想改一下验证的加解密来着,后来想想如果并发量起来的话,反而会影响效率,但是代码已经写完了,放出来大家一起学习吧。
代码包含C++、PHP完整的例子,没写加签、验签,这个不难。
支持中文、超大字符串加密(分段加密/解密)
期间卡了很久,发现php的base64_encode跟我C++写的base64_encode结果不一致,调试了很久才发现是被加密数据如果有中文的话,就会导致不一致。
所以放出来避免大家壁坑吧。
调用了 OpenSSL库,大家自己下载安装即可
https://static.52pojie.cn/static/image/hrline/1.gif
<?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
#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
#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;
      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;
      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;
      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;
      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::stringbb = 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::stringbb = Base64Decode(strRet);
      return U2G(bb.c_str());
}

main.cpp
#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;
}

测试结果:


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/

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


学习学习代码
页: [1]
查看完整版本: C++对RSA加密、解密的使用