一个RSA的C++封装
Posted DoubleLi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个RSA的C++封装相关的知识,希望对你有一定的参考价值。
使用RSA的难点:
- 公钥和私钥的保存与加载。
在很多的场合下,密钥是以文件的形式分开保存的,对程序员使用者来说,需要解决公钥和私钥的生成、保存、加载问题。 - 加解密过程中的分组问题。
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
通过 OpenSSL (c++) 以 XML (w3c) 格式保存 RSA 公钥和私钥
【中文标题】通过 OpenSSL (c++) 以 XML (w3c) 格式保存 RSA 公钥和私钥【英文标题】:Save RSA public and private keys in XML (w3c) format via OpenSSL (c++) 【发布时间】:2012-04-24 07:46:53 【问题描述】:我想使用 RSA 公钥和私钥的 XML 文件格式。 现在我找到了如何以 PEM 和二进制 (DER) 格式保存这些密钥(例如,PEM_write_RSAPrivateKey())
我有一个带有 xml 格式 RSA 密钥的字符串,我需要将它们加载到 EVP_PKEY 或 RSA OpenSSL 结构中。
XML格式是这样的:
<RSAKeyPair>
<Modulus>...</Modulus>
<Exponent>...</Exponent>
<P>...</P>
<Q>...</Q>
<DP>...</DP>
<DQ>...</DQ>
<InverseQ>
...
</InverseQ>
<D>...</D>
</RSAKeyPair>
谢谢!
【问题讨论】:
【参考方案1】://just a code for demo,not for actually use
int len;
RSA *rsa;
BIO *bio;
unsigned char *data;
bio = BIO_new(BIO_s_meme());
BIO *b64;
b64 = BIO_new(BIO_f_base64());
BIO_write(bio, "<RSAKeyPair>\n",strlen("<RSAKeyPair>\n"));
//write Modulus
len=BN_num_bytes(rsa->n);
data=(unsigned char *)OPENSSL_malloc(len);
if(data)
BIO_write(bio," <Modulus>",strlen(" <Modulus>"));
BN_bn2bin(rsa->n,data);
bio = BIO_push(b64, bio);
BIO_write(bio, data, len);
(void)BIO_flush(bio);
BIO_pop(bio);
BIO_reset(b64);
BIO_write(bio,"</Modulus>",strlen("</Modulus>"));
//write Exp
...
//write the bignum in rsa structure you want
BIO_write(bio, "</RSAKeyPair>\n",strlen("</RSAKeyPair>"));
【讨论】:
谢谢。我曾希望有一个简单的函数,比如 XML_write_RSAPrivateKey()...以上是关于一个RSA的C++封装的主要内容,如果未能解决你的问题,请参考以下文章