基于openssl1.1.1d库的RSA加密解密验证签名(C++版)
1.下载openssl-1.1.1d库以及相关编译依赖
openssl的1.0.x版本和1.1.x版本有细微的不同,本文方法适用于1.1.x版本
openssl库下载路径:https://www.openssl.org/source/
下载其中的openssl-1.1.1d.tar.gz
perl用于配置编译环境,下载路径:https://www.perl.org/get.html#win32
下载其中的:Strawberry Perl
如果在linux上使用,需要注意1.1.x版本中使用函数:secure_getenv 该函数需要glibc版本2.17以上
可以修改源代码使用getenv,该函数说明:http://www.man7.org/linux/man-pages/man3/getenv.3.html
glibc版本下载:http://www.gnu.org/software/libc/
2.安装好perl,解压好openssl后
其中生成makefile的编译选项有:perl Configure { VC-WIN32 | VC-WIN64A | VC-WIN64I | VC-CE } [no-shared][no-asm][no-tests][--debug]
如果编译32位版本:perl Configure VC-WIN32 no-asm no-tests 即可,如果不加no-asm需要安装NASM并且添加路径到Path中
生成makefile后只需要nmake即可。
perl Configure VC-WIN32 no-asm no-tests
nmake
将openssl目录下的include和[libcrypto.lib libssl.lib libssl-1_1.dll libcrypto-1_1.dll]或者[libcrypto_static.lib libssl_static.lib]
添加到自己的工程,注意还需要额外链接ws2_32.lib。
3.代码及其说明如下:
#include "openssl/pem.h"
#include "openssl/ssl.h"
#include "openssl/evp.h"
#include "openssl/sha.h"
#include "openssl/bio.h"
#include "openssl/rsa.h"
#include "openssl/err.h"
#include <string>
#include <iostream>
#include <cstdlib>
#include <atlenc.h> //用于调用 Base64Encode
using namespace std;
int main(int argc, char *argv[])
{
string strPrivateKey =
"-----BEGIN RSA PRIVATE KEY-----
"
"MIICXgIBAAKBgQDIOkm7kTU6m8ALDqPE2nn049vOHSKkekpdzwcOmfYiAwg+sbli"
"2ToVTlUwM51SDNdOfbvogbH4KeDqwYnb0bjMhk4wxfZPD1wHXotRc/ERN2iaZ6Km"
"0ImJjlW41zDFicNoj9qre3NpFkAAjXyJEDEdQrVCGYRYvcAYwUtpNVhavwIDAQAB"
"AoGBAMWSnobyte9rGIjQnVD1tDmtTYuIvFJISXFfg7souPK+wzf57tBXQTUc4np5"
"s9buzNWqw+ydbZtO151N9FZwD0Qij7YtfvoxNrEzMRd1SzaFMxKOZqNSV8uW6v7o"
"8ISS7E7YIrnGvJIXTRAOiehu3Zy3maQc6wVLJVDDf0kqHPRhAkEA6VShkeUXxJ9t"
"08O+YEX+CV3KHXBfmXBIMKaKBAShnVUyx2+TW0C0ZyGTJMwjPhpVIhWDlNwQ1mVT"
"sMjc+CBWlQJBANuuU2ABCLyyG423PQmOHSuAm+80kUEoPkBpWDOHa+kR7yR1mdaK"
"ne4Yzv/7aTC9qmKQ+LdtSassGu7YWoM3OwMCQAm+mBTQvYJfqiWK6jt5ENfxS8yY"
"8dUlpE4r1l2+l8VLVpiPp1bLR/16oHuL7vjb/qwyu9EOs8FQcANVEC1opFUCQQDT"
"ajZk+znMV2A7B3CfZHxgJFptX9q2qSMX3An9NUO9vvu1y9OsbCTHQmrcYbj/Jlj2"
"mOwzouK18DFPUTnyc9G/AkEAwyVQYY6tQNUJ6srRA1MrS8K0iwS7PRyt/u+ziBS8"
"Va/rzRJe9s30pXsiRubUhCCKUvuCWWwOrxhPQB+VGx7EXQ==
"
"-----END RSA PRIVATE KEY-----
";
string strPublicKey =
"-----BEGIN PUBLIC KEY-----
"
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIOkm7kTU6m8ALDqPE2nn049vO"
"HSKkekpdzwcOmfYiAwg+sbli2ToVTlUwM51SDNdOfbvogbH4KeDqwYnb0bjMhk4w"
"xfZPD1wHXotRc/ERN2iaZ6Km0ImJjlW41zDFicNoj9qre3NpFkAAjXyJEDEdQrVC"
"GYRYvcAYwUtpNVhavwIDAQAB
"
"-----END PUBLIC KEY-----
";
//用于测试的明文
string strText = "Hello,World! p1=3344&p2=12.03&p3=ssaabb";
//先测试一个错误输出!,这里使用PublicKey去生成PrivateRSA,会生成失败产生一个错误!
//错误字符串:error:0909006C:PEM routines:get_name:no start line
//这个一般都是函数用错了,或者Key的格式有问题
RSA *err_rsa = 0;
BIO *err_bio = 0;
err_bio = BIO_new_mem_buf(strPublicKey.c_str(), strPublicKey.size());
err_rsa = PEM_read_bio_RSAPrivateKey(err_bio, &err_rsa, 0, 0);
if (!err_rsa)
{
int ierr = ERR_get_error();
char szErr[2048];
memset(szErr, 0, sizeof(szErr));
ERR_error_string_n(ierr, szErr, 2048);
cout << "Test-Error" << endl;
cout << "err-id:" << ierr << endl;
cout << "errstr:" << szErr << endl << endl;
BIO_free(err_bio);
}
//这里先生成正确的公钥RSA对象,私钥RSA对象
RSA *pri_rsa = 0;
BIO *pri_bio = 0;
pri_bio = BIO_new_mem_buf(strPrivateKey.c_str(), strPrivateKey.size());
pri_rsa = PEM_read_bio_RSAPrivateKey(pri_bio, &pri_rsa, 0, 0);
RSA *pub_rsa = 0;
BIO *pub_bio = 0;
pub_bio = BIO_new_mem_buf(strPublicKey.c_str(), strPublicKey.size());
//pub_rsa = PEM_read_bio_RSAPublicKey(pub_bio, &pub_rsa, 0, 0); //这里不知道为什么不能使用该函数
pub_rsa = PEM_read_bio_RSA_PUBKEY(pub_bio, &pub_rsa, 0, 0);
char szCipher[4096]; //密文缓存
char szPlain[4096]; //明文缓存
int iLenCipher = 0;
int iLenPlain = 0;
char szB64Temp[4096]; //用于base64缓存
int iLenB64 = 0;
//输出未加密前的明文,用于对比
cout << "Test-Plain:
" << strText << endl << endl;
//测试:私钥加密,公钥解密
memset(szCipher, 0, sizeof(szCipher));
memset(szPlain, 0, sizeof(szPlain));
iLenCipher = RSA_private_encrypt(strText.size(), (const unsigned char*)strText.c_str(), (unsigned char*)szCipher, pri_rsa, RSA_PKCS1_PADDING);
iLenPlain = RSA_public_decrypt(iLenCipher, (const unsigned char*)szCipher, (unsigned char*)szPlain, pub_rsa, RSA_PKCS1_PADDING);
//注意,一般加密后都是乱码,实际应用程序中传送的都是base64之后的数据,这里直接输出乱码!
cout << "private-encrypt:
" << szCipher << endl;
cout << "public-decrypt:
" << szPlain << endl;
//输出base64之后的密文
memset(szB64Temp, 0, sizeof(szB64Temp));
iLenB64 = 4096;
Base64Encode((const BYTE*)szCipher, iLenCipher, szB64Temp, &iLenB64);
cout << "b64-cipher:
" << szB64Temp << endl << endl;
//测试:公钥加密,私钥解密
memset(szCipher, 0, sizeof(szCipher));
memset(szPlain, 0, sizeof(szPlain));
iLenCipher = RSA_public_encrypt(strText.size(), (const unsigned char*)strText.c_str(), (unsigned char*)szCipher, pub_rsa, RSA_PKCS1_PADDING);
iLenPlain = RSA_private_decrypt(iLenCipher, (const unsigned char*)szCipher, (unsigned char*)szPlain, pri_rsa, RSA_PKCS1_PADDING);
//注意RSA算法,公钥加密相同的文本每次密文都会改变,这是正确的,说明RSA难以破解
cout << "public-encrypt:
" << szCipher << endl;
cout << "private-decrypt:
" << szPlain << endl;
memset(szB64Temp, 0, sizeof(szB64Temp));
iLenB64 = 4096;
Base64Encode((const BYTE*)szCipher, iLenCipher, szB64Temp, &iLenB64);
cout << "b64-cipher:
" << szB64Temp << endl << endl;
//测试:私钥签名,公钥验签
char szSigned[4096];
memset(szSigned, 0, sizeof(szSigned));
int iLenSign = 0;
RSA_sign(NID_sha1, (const unsigned char*)strText.c_str(), strText.size(), (unsigned char*)szSigned, (unsigned int*)&iLenSign, pri_rsa);
cout << "private-signed:
" << szSigned << endl;
int iRet = RSA_verify(NID_sha1, (const unsigned char*)strText.c_str(), strText.size(), (const unsigned char*)szSigned, iLenSign, pub_rsa);
cout << "public-verify:" << iRet << endl; //1-验签成功,0-验签失败
RSA_free(pub_rsa);
BIO_free(pub_bio);
RSA_free(pri_rsa);
BIO_free(pri_bio);
cout << endl << endl;
system("pause");
return 0;
}
4.运行结果如下:
以上是 基于openssl1.1.1d库的RSA加密解密验证签名(C++版) 的全部内容, 来源链接: utcz.com/z/512344.html