首页 > 编程语言 >一个RSA的C++封装

一个RSA的C++封装

时间:2023-06-08 14:55:06浏览次数:62  
标签:std CRSA 封装 string RSA C++ ret const

使用RSA的难点:

  1. 公钥和私钥的保存与加载。
    在很多的场合下,密钥是以文件的形式分开保存的,对程序员使用者来说,需要解决公钥和私钥的生成、保存、加载问题。
  2. 加解密过程中的分组问题。
    RSA加解密的开销很大,比DES和AES高2个数量级,一般情况下不适合用来对较长的数据进行加解密。但是,RSA本身也是一种分组加密算法,即使再短的数据加密需求,从程序的健状性考虑,我们也必须搞清楚和实现分组的加解密支持。

下面的C++可复用代码,解决了上面的这两个问题,有需要的朋友可以借鉴。代码如下:

头文件RSA.h:

#ifndef __DAKUANG_RSA_H__
#define __DAKUANG_RSA_H__

#include <string>

namespace dakuang
{

    class CRSA
    {
    public:

        // 生成密钥对,输出为PEM文件
        static bool genKeyFiles(const std::string& strPrivateKeyPEMFile, const std::string& strPublicKeyPEMFile);

        // 生成密钥对,输出为PEM字符串
        static bool genKeyStrings(std::string& strPrivateKeyPEMString, std::string& strPublicKeyPEMString);


        // 使用PEM私钥文件加密
        static bool encryptByPrivatePEMFile(const std::string& strIn, std::string& strOut, const std::string& strKeyPEMFile);

        // 使用PEM私钥文件解密
        static bool decryptByPrivatePEMFile(const std::string& strIn, std::string& strOut, const std::string& strKeyPEMFile);

        // 使用PEM公钥文件加密
        static bool encryptByPublicPEMFile(const std::string& strIn, std::string& strOut, const std::string& strKeyPEMFile);

        // 使用PEM公钥文件解密
        static bool decryptByPublicPEMFile(const std::string& strIn, std::string& strOut, const std::string& strKeyPEMFile);


        // 使用PEM私钥字符串加密
        static bool encryptByPrivatePEMString(const std::string& strIn, std::string& strOut, const std::string& strKeyPEMString);

        // 使用PEM私钥字符串解密
        static bool decryptByPrivatePEMString(const std::string& strIn, std::string& strOut, const std::string& strKeyPEMString);

        // 使用PEM公钥字符串加密
        static bool encryptByPublicPEMString(const std::string& strIn, std::string& strOut, const std::string& strKeyPEMString);

        // 使用PEM公钥字符串解密
        static bool decryptByPublicPEMString(const std::string& strIn, std::string& strOut, const std::string& strKeyPEMString);

    private:

        // 生成RSA密钥结构
        static void* __genKey(int nBits);

        // 使用RSA执行加密或解密
        static bool __encryptOrDecrypt(const std::string& strIn, std::string& strOut, const void* pRSA, const void* pFunc, bool bEncrypt);
    };

}

#endif

实现文件RSA.cpp:

#include "RSA.h"

#include <openssl/rsa.h>
#include <openssl/pem.h>

using namespace dakuang;

// 加解密函数签名
typedef int (*RSA_encryptOrDecrypt)(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding);

// 生成密钥对,输出为PEM文件
bool CRSA::genKeyFiles(const std::string& strPrivateKeyPEMFile, const std::string& strPublicKeyPEMFile)
{
    // 生成RSA
    RSA* rsa = (RSA*)__genKey(1024);
    if (rsa == NULL)
        return false;

    // 输出私钥
    {
        BIO* bio = BIO_new_file(strPrivateKeyPEMFile.data(), "w");
        int ret = PEM_write_bio_RSAPrivateKey(bio, rsa, NULL, NULL, 0, NULL, NULL);
        if (ret != 1)
        {
            BIO_free(bio);
            RSA_free(rsa);
            return false;
        }

        BIO_free(bio);
    }

    // 输出公钥
    {
        BIO* bio = BIO_new_file(strPublicKeyPEMFile.data(), "w");
        int ret = PEM_write_bio_RSAPublicKey(bio, rsa);
        if (ret != 1)
        {
            BIO_free(bio);
            RSA_free(rsa);
            return false;
        }

        BIO_free(bio);
    }

    RSA_free(rsa);
    return true;
}

// 生成密钥对,输出为PEM字符串
bool CRSA::genKeyStrings(std::string& strPrivateKeyPEMString, std::string& strPublicKeyPEMString)
{
    // 生成RSA
    RSA* rsa = (RSA*)__genKey(1024);
    if (rsa == NULL)
        return false;

    // 输出私钥
    {
        BIO* bio = BIO_new(BIO_s_mem());
        int ret = PEM_write_bio_RSAPrivateKey(bio, rsa, NULL, NULL, 0, NULL, NULL);
        if (ret != 1)
        {
            BIO_free(bio);
            RSA_free(rsa);
            return false;
        }

        char sBuf[1024] = {0};
        int bytes = BIO_read(bio, sBuf, 1024);
        if (bytes <= 0)
        {
            BIO_free(bio);
            RSA_free(rsa);
            return false;
        }

        BIO_free(bio);
        strPrivateKeyPEMString.assign(sBuf, bytes);
    }

    // 输出公钥
    {
        BIO* bio = BIO_new(BIO_s_mem());
        int ret = PEM_write_bio_RSAPublicKey(bio, rsa);
        if (ret != 1)
        {
            BIO_free(bio);
            RSA_free(rsa);
            return false;
        }

        char sBuf[1024] = {0};
        int bytes = BIO_read(bio, sBuf, 1024);
        if (bytes <= 0)
        {
            BIO_free(bio);
            RSA_free(rsa);
            return false;
        }

        BIO_free(bio);
        strPublicKeyPEMString.assign(sBuf, bytes);
    }

    RSA_free(rsa);
    return true;
}


// 使用PEM私钥文件加密
bool CRSA::encryptByPrivatePEMFile(const std::string& strIn, std::string& strOut, const std::string& strKeyPEMFile)
{
    // 加载私钥
    BIO* bio = BIO_new_file(strKeyPEMFile.data(), "r");
    RSA* rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
    BIO_free(bio);

    if (rsa == NULL)
        return false;

    // 使用私钥加密
    bool b = __encryptOrDecrypt(strIn, strOut, rsa, (const void*)RSA_private_encrypt, true);
    RSA_free(rsa);
    return b;
}

// 使用PEM私钥文件解密
bool CRSA::decryptByPrivatePEMFile(const std::string& strIn, std::string& strOut, const std::string& strKeyPEMFile)
{
    // 加载私钥
    BIO* bio = BIO_new_file(strKeyPEMFile.data(), "r");
    RSA* rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
    BIO_free(bio);

    if (rsa == NULL)
        return false;

    // 检查密文大小是否为分组的整数倍
    int keySize = RSA_size(rsa);
    int blockSize = keySize;
    if ( (strIn.size() % blockSize) != 0 )
        return false;

    // 使用私钥解密
    bool b = __encryptOrDecrypt(strIn, strOut, rsa, (const void*)RSA_private_decrypt, false);
    RSA_free(rsa);
    return b;
}

// 使用PEM公钥文件加密
bool CRSA::encryptByPublicPEMFile(const std::string& strIn, std::string& strOut, const std::string& strKeyPEMFile)
{
    // 加载公钥
    BIO* bio = BIO_new_file(strKeyPEMFile.data(), "r");
    RSA* rsa = PEM_read_bio_RSAPublicKey(bio, NULL, NULL, NULL);
    BIO_free(bio);

    if (rsa == NULL)
        return false;

    // 使用公钥加密
    bool b = __encryptOrDecrypt(strIn, strOut, rsa, (const void*)RSA_public_encrypt, true);
    RSA_free(rsa);
    return b;
}

// 使用PEM公钥文件解密
bool CRSA::decryptByPublicPEMFile(const std::string& strIn, std::string& strOut, const std::string& strKeyPEMFile)
{
    // 加载公钥
    BIO* bio = BIO_new_file(strKeyPEMFile.data(), "r");
    RSA* rsa = PEM_read_bio_RSAPublicKey(bio, NULL, NULL, NULL);
    BIO_free(bio);

    if (rsa == NULL)
        return false;

    // 检查密文大小是否为分组的整数倍
    int keySize = RSA_size(rsa);
    int blockSize = keySize;
    if ( (strIn.size() % blockSize) != 0 )
        return false;

    // 使用公钥解密
    bool b = __encryptOrDecrypt(strIn, strOut, rsa, (const void*)RSA_public_decrypt, false);
    RSA_free(rsa);
    return b;
}


// 使用PEM私钥字符串加密
bool CRSA::encryptByPrivatePEMString(const std::string& strIn, std::string& strOut, const std::string& strKeyPEMString)
{
    // 加载私钥
    BIO* bio = BIO_new_mem_buf((const void*)strKeyPEMString.data(), strKeyPEMString.size());
    RSA* rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
    BIO_free(bio);

    if (rsa == NULL)
        return false;

    // 使用私钥加密
    bool b = __encryptOrDecrypt(strIn, strOut, rsa, (const void*)RSA_private_encrypt, true);
    RSA_free(rsa);
    return b;
}

// 使用PEM私钥字符串解密
bool CRSA::decryptByPrivatePEMString(const std::string& strIn, std::string& strOut, const std::string& strKeyPEMString)
{
    // 加载私钥
    BIO* bio = BIO_new_mem_buf((const void*)strKeyPEMString.data(), strKeyPEMString.size());
    RSA* rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
    BIO_free(bio);

    if (rsa == NULL)
        return false;

    // 检查密文大小是否为分组的整数倍
    int keySize = RSA_size(rsa);
    int blockSize = keySize;
    if ( (strIn.size() % blockSize) != 0 )
        return false;

    // 使用私钥解密
    bool b = __encryptOrDecrypt(strIn, strOut, rsa, (const void*)RSA_private_decrypt, false);
    RSA_free(rsa);
    return b;
}

// 使用PEM公钥字符串加密
bool CRSA::encryptByPublicPEMString(const std::string& strIn, std::string& strOut, const std::string& strKeyPEMString)
{
    // 加载公钥
    BIO* bio = BIO_new_mem_buf((const void*)strKeyPEMString.data(), strKeyPEMString.size());
    RSA* rsa = PEM_read_bio_RSAPublicKey(bio, NULL, NULL, NULL);
    BIO_free(bio);

    if (rsa == NULL)
        return false;

    // 使用公钥加密
    bool b = __encryptOrDecrypt(strIn, strOut, rsa, (const void*)RSA_public_encrypt, true);
    RSA_free(rsa);
    return b;
}

// 使用PEM公钥字符串解密
bool CRSA::decryptByPublicPEMString(const std::string& strIn, std::string& strOut, const std::string& strKeyPEMString)
{
    // 加载公钥
    BIO* bio = BIO_new_mem_buf((const void*)strKeyPEMString.data(), strKeyPEMString.size());
    RSA* rsa = PEM_read_bio_RSAPublicKey(bio, NULL, NULL, NULL);
    BIO_free(bio);

    if (rsa == NULL)
        return false;

    // 检查密文大小是否为分组的整数倍
    int keySize = RSA_size(rsa);
    int blockSize = keySize;
    if ( (strIn.size() % blockSize) != 0 )
        return false;

    // 使用公钥解密
    bool b = __encryptOrDecrypt(strIn, strOut, rsa, (const void*)RSA_public_decrypt, false);
    RSA_free(rsa);
    return b;
}

// 生成RSA密钥结构
void* CRSA::__genKey(int nBits)
{
    RSA* rsa = RSA_new();

    BIGNUM* bne = BN_new();
    BN_set_word(bne, RSA_F4);

    int ret = RSA_generate_key_ex(rsa, nBits, bne, NULL);

    BN_free(bne);

    if (ret != 1)
    {
        RSA_free(rsa);
        return NULL;
    }

    return (void*)rsa;
}

// 使用RSA执行加密或解密
bool CRSA::__encryptOrDecrypt(const std::string& strIn, std::string& strOut, const void* pRSA, const void* pFunc, bool bEncrypt)
{
    const RSA_encryptOrDecrypt encryptOrDecrypt = (const RSA_encryptOrDecrypt)pFunc;

    // 计算加密块大小
    int nKeySize = RSA_size((RSA*)pRSA);
    int nBlockSize = bEncrypt ? (nKeySize - RSA_PKCS1_PADDING_SIZE) : nKeySize;

    const unsigned char* pIn = (const unsigned char*)strIn.data();
    int nInSize = strIn.size();

    unsigned char* pBuf = new unsigned char[nKeySize];

    // 分组迭代加密
    for (int i = 0; i < nInSize; )
    {
        int nBlockLen = (nInSize - i > nBlockSize ? nBlockSize : nInSize - i);

        int ret = encryptOrDecrypt(nBlockLen, pIn + i, pBuf, (RSA*)pRSA, RSA_PKCS1_PADDING);
        if (ret <= 0)
        {
            delete[] pBuf;
            return false;
        }

        strOut.append((char*)pBuf, ret);
        i += nBlockLen;
    }

    delete[] pBuf;
    return true;
}

使用举例:

下面的代码完整地演示了RSA封装的所有功能,包括PEM文件的生成与加载、字符串密钥的生成与加载,以及两种密钥方法的加解密。

#include <stdio.h>
#include <stdlib.h>

#include "RSA.h"

int main(int argc, char* argv[])
{
    using namespace dakuang;

    std::string strText = "abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567
890abcdefghijklmnopqrstuvwxyz1234567890";

    {
        bool b = CRSA::genKeyFiles("test.key", "test.pub");
        printf("CRSA::genKeyFiles() ret:[%d] \n", b);

        std::string strCipher = "";
        b = CRSA::encryptByPrivatePEMFile(strText, strCipher, "test.key");
        printf("CRSA::encryptByPrivatePEMFile() ret:[%d] cipher len:[%d] \n", b, strCipher.size());

        std::string strText2 = "";
        b = CRSA::decryptByPublicPEMFile(strCipher, strText2, "test.pub");
        printf("CRSA::decryptByPublicPEMFile() ret:[%d] text len:[%d] body:[%s] \n", b, strText2.size(), strText2.data());

        strCipher = "";
        b = CRSA::encryptByPublicPEMFile(strText, strCipher, "test.pub");
        printf("CRSA::encryptByPublicPEMFile() ret:[%d] cipher len:[%d] \n", b, strCipher.size());

        strText2 = "";
        b = CRSA::decryptByPrivatePEMFile(strCipher, strText2, "test.key");
        printf("CRSA::decryptByPrivatePEMFile() ret:[%d] text len:[%d] body:[%s] \n", b, strText2.size(), strText2.data());
    }

    {
        std::string strPrivateKey = "", strPublicKey = "";
        bool b = CRSA::genKeyStrings(strPrivateKey, strPublicKey);
        printf("CRSA::genKeyStrings() ret:[%d] \n", b);

        std::string strCipher = "";
        b = CRSA::encryptByPrivatePEMString(strText, strCipher, strPrivateKey);
        printf("CRSA::encryptByPrivatePEMString() ret:[%d] cipher len:[%d] \n", b, strCipher.size());

        std::string strText2 = "";
        b = CRSA::decryptByPublicPEMString(strCipher, strText2, strPublicKey);
        printf("CRSA::decryptByPublicPEMString() ret:[%d] text len:[%d] body:[%s] \n", b, strText2.size(), strText2.data());

        strCipher = "";
        b = CRSA::encryptByPublicPEMString(strText, strCipher, strPublicKey);
        printf("CRSA::encryptByPublicPEMString() ret:[%d] cipher len:[%d] \n", b, strCipher.size());

        strText2 = "";
        b = CRSA::decryptByPrivatePEMString(strCipher, strText2, strPrivateKey);
        printf("CRSA::decryptByPrivatePEMString() ret:[%d] text len:[%d] body:[%s] \n", b, strText2.size(), strText2.data());
    }

    return 0;
}

生成私钥内容如下:
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDqpNkFqAdedWhOc+lukwCKFNamFr0HMSGgjONUE7dYL5wxk2Pe
5QsLIjqgA7dE14AFCQgF5WOyyUdP94xRGZdstH7CCWz2KhG7nX6ZupKwc5mMO+d3
8tpSp98TTx+CWLL/ntpZNB0cwU/Cx9TbkW+Ysto3LyPkjmlh4othcRMbJwIDAQAB
AoGAUV+qA9Qp+hAthEeehMJmRXzElAT+uSfIya0SiW3s/6BDQs4irIIyOkI8opGn
VTCHLTfcmG7dDHvRR2JKPzXo1RgQW7CgBK3/G5u7CCjF43XtdBd7F4f04yE+bOnY
3oGiXyv2N8okL3MtjSbQwsMX//v+M+fcQtVOO1iUtZPcnQECQQD8t1Dl1isvkaET
ZA+kdnzcF50Y0UQ3lIeTZKNhBH27jzs9tg172s/opS0Ef5c99gFx72Wt9QJfZKLu
4ZDHhJzxAkEA7bFpvS7tbCzqNYGrp3pocWGP7R7dGjKnxzy7tXOucPnyiLqlSL/N
48iWb0jneGN6u+/GiHrnwLaGGzh6gvcZlwJAJS4rPsVVsTfxxNKR4pZ0JEVtHXuc
V7kIgUzrJJjujquyAZBJR5GXyRiUGPdUnw8Ug1i/UuqbIMHDnvWcwV3nYQJAe1lo
QC8MMukUGfRS+jTB4qT4pdswbpn/C5vu5XlE+4gaXu5NO/WdiSndN58j0Av/82u5
IbZ2ckHGUnX6zeAhvQJBAJQs5GMT2MCQ8n5cFP/1eT0fiGPeP6qLO0UZ1BTFfGIq
mXz1ITOTo+PbE93uHDf3u299I70zF8v5R3ifFsGmAus=
-----END RSA PRIVATE KEY-----

生成公钥内容如下:
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAOqk2QWoB151aE5z6W6TAIoU1qYWvQcxIaCM41QTt1gvnDGTY97lCwsi
OqADt0TXgAUJCAXlY7LJR0/3jFEZl2y0fsIJbPYqEbudfpm6krBzmYw753fy2lKn
3xNPH4JYsv+e2lk0HRzBT8LH1NuRb5iy2jcvI+SOaWHii2FxExsnAgMBAAE=
-----END RSA PUBLIC KEY-----

输出:
CRSA::genKeyFiles() ret:[1]
CRSA::encryptByPrivatePEMFile() ret:[1] cipher len:[256]
CRSA::decryptByPublicPEMFile() ret:[1] text len:[144] body:[abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890]
CRSA::encryptByPublicPEMFile() ret:[1] cipher len:[256]
CRSA::decryptByPrivatePEMFile() ret:[1] text len:[144] body:[abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890]
CRSA::genKeyStrings() ret:[1]
CRSA::encryptByPrivatePEMString() ret:[1] cipher len:[256]
CRSA::decryptByPublicPEMString() ret:[1] text len:[144] body:[abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890]
CRSA::encryptByPublicPEMString() ret:[1] cipher len:[256]
CRSA::decryptByPrivatePEMString() ret:[1] text len:[144] body:[abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890]



ref:https://www.jianshu.com/p/947630b33df1

标签:std,CRSA,封装,string,RSA,C++,ret,const
From: https://www.cnblogs.com/lidabo/p/17466488.html

相关文章

  • 基于springmvc+spring+mybatis+hibernate 封装的框架
    基于maven  freemarker2.3.20  spirngmvc3.2.9.RELEASE  spring3.2.9.RELEASE  Hiberante3.6.9.Final(自动建表)  mybatis3.2.7数据交互  druid连接池   cxf3.0.0发布webservice  quartz2.2.1定时任务  jquery   jquery-datata......
  • C++ 时钟;多角星;花环实现。
     最近在回顾C++,写了几个小玩意儿练习一下,该找工作了,十分焦虑。好了,开始正文首先如何画多角星?比如五角星,六角星等等?这里以五角星为例,r1需要被指定,r2可以通过正弦定理得到。然后通过每一步增加360/2n的角度,依次通过短半径和长半径循环计算每个顶点的坐标。如果需要绘制的图形......
  • C++ this 指针
    第一部分this指针的类型可理解为Box*。此时得到两个地址分别为box1和box2对象的地址。实例:#include<iostream>usingnamespacestd;classBox{public:Box(){;}~Box(){;}Box*get_address()//得到this的地址{......
  • C++ 指向类的指针
    C++指向类的指针一个指向C++类的指针与指向结构的指针类似,访问指向类的指针的成员,需要使用成员访问运算符->,就像访问指向结构的指针一样。与所有的指针一样,您必须在使用指针之前,对指针进行初始化。下面的实例有助于更好地理解指向类的指针的概念:#include<iostream>usin......
  • 驱动开发:内核封装WFP防火墙入门
    WFP框架是微软推出来替代TDIHOOK传输层驱动接口网络通信的方案,其默认被设计为分层结构,该框架分别提供了用户态与内核态相同的AIP函数,在两种模式下均可以开发防火墙产品,以下代码我实现了一个简单的驱动过滤防火墙。WFP框架分为两大层次模块,用户态基础过滤引擎BFE(BaseFiltering......
  • C++面试八股文:C和C++有哪些区别
    C++面试八股文:C和C++有哪些区别某日小二参加XXX科技公司的C++高级工程师开发岗位1面:面试官:请问C和C++的区别有哪些?小二:C++是C的超集。面试官:还有吗?小二:...面试官:面试结束,回去等消息吧。小二:淦。小二的答案对吗?实际上这句话是有问题的,严格的说,C语言和C++有很......
  • C++面试八股文:C++中,函数的参数应该传值还是传引用?
    某日二师兄参加XXX科技公司的C++工程师开发岗位第8面:面试官:C++中,函数的参数应该传值还是传引用?二师兄:要看参数的用途。如果是出参,必须传引用。如果是入参,主要考虑参数类型的大小,来决定传值还是传引用。面试官:为什么不使用指针?二师兄:传指针也称之为传引用(passbyrefereence)。......
  • 混合编程python与C++
    上个版本:只是用到ctypes进行传输,这次将python服务端更改为C++服务端,方便后续维护.本文实现功能:python传输图片给C++,C++接受图片后对图片进行处理,并将结果返回给python客户端,passimagefrompythontoC++C++服务端.h文件注意文中的model//.h#pragmaonce#in......
  • 浅谈: C++中*&的含义
    指针引用int*&A;该类型要从右往左读:变量A,是一个引用&;谁的引用呢?指针*的引用。为什么有些函数形参要用*&而不直接用*呢?......
  • C++哈希算法(一)
    哈希设计思想:试想如果我们对一个数组进行查询,这个数组里,每一个元素都是一个字符串。我们知道数组最快的检索办法是通过数组的下标进行检索,但是对于这种场景,我们无能为力,只能从头查到尾,从而查询出目标元素。如果我们要根据名字找到其中的任何一个元素,就需要遍历整个数组。最坏情......