利用openssl的AES和RSA完成对数据的加密解密

时间:2021-10-11 13:12:28
#include<windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/aes.h>
#include<iostream>
using namespace std;
#pragma comment(lib,"libssl.lib")
#pragma comment(lib,"libcrypto.lib")

#define AES_BITS 128
#define MSG_LEN 128

#define INTERFACE "eth0"
#define PAD_SIZE 32

#define TxtBufLen 3200
#define code1024 117
#define code512 53
char g_pPubFile[30] = { 0 };
char g_pPriFile[30] = { 0 };
//maxCodeByte = g_nBits/8-11这里设置了2048,意味着RSA最多可以 编、解码 2048/8-11=117个字节
const int g_nBits = 1024;

bool ReadTxt( char(&buf)[TxtBufLen])
{
FILE *fp;
if ((fp = fopen("1.txt", "r")) == NULL)
{
return false;
}
fseek(fp, 0, SEEK_END);
int fileLen = ftell(fp);
char *tmp = new char[fileLen+1];
memset(tmp, 0, fileLen + 1);
fseek(fp, 0, SEEK_SET);
fread(tmp, fileLen, sizeof(char), fp);
fclose(fp);

memcpy(buf, tmp, fileLen);
delete tmp;
return true;
}

bool WriteTxt(char* Decbuf)
{
FILE *fp;
if ((fp = fopen("2.txt", "w+")) == NULL)
{
return false;
}
rewind(fp);
int fileLen = strlen((char*)Decbuf);
fwrite(Decbuf, fileLen, sizeof(char), fp);
fclose(fp);
}

int MakeKey(const char* publicName, const char* privateName)
{
//产生一个模为bits位的 密钥对,e为公开的加密指数,一般为65537(0x10001即 RSA_F4)
//其它两个参数可以设置为NULL
char* g_pPub = "public.pem";
char* g_pPri = "private.pem";
sprintf(g_pPubFile, "%s%s", publicName, g_pPub);
sprintf(g_pPriFile, "%s%s", privateName, g_pPri);

RSA *pRsa = RSA_generate_key(g_nBits, RSA_F4, NULL, NULL);
if (pRsa == NULL)
{
cout << "rsa_generate_key error" << endl;
return -1;
}

////////////////////////////////
//1.开始生成公钥pem文件
BIO *pBio = BIO_new_file(g_pPubFile, "wb");//该函数根据给定的mode类型创建了一个文件BIO,mode参数跟fopen函数中mode参数的含义是一样的
if (pBio == NULL)
{
cout << "BIO_new_file " << g_pPubFile << " error" << endl;
return -2;
}
if (PEM_write_bio_RSAPublicKey(pBio, pRsa) == 0)//输出RSAPublicKey公钥到pem文件中
{
cout << "write public key error" << endl;
return -3;
}
BIO_free_all(pBio);// 公钥文件生成成功,释放资源

////////////////////////////////
//2.开始生成私钥pem文件
pBio = BIO_new_file(g_pPriFile, "w");
if (pBio == NULL)
{
cout << "BIO_new_file " << g_pPriFile << " error" << endl;
return -4;
}
if (PEM_write_bio_RSAPrivateKey(pBio, pRsa, NULL, NULL, 0, NULL, NULL) == 0)////输出RSAPrivateKey私钥到pem文件中
{
cout << "write private key error" << endl;
return -5;
}
BIO_free_all(pBio);


RSA_free(pRsa);
return 0;
}

//************************************
// function: 使用公钥对字符串进行加密
//************************************
int Enc(unsigned char *infile, int inLen, unsigned char *out, int &outLen)
{
BIO *pBio = BIO_new_file(g_pPubFile, "r");
RSA *pRsa = PEM_read_bio_RSAPublicKey(pBio, NULL, NULL, NULL);
BIO_free_all(pBio);
outLen = RSA_public_encrypt(
(RSA_size(pRsa) - 11) > inLen ? inLen : RSA_size(pRsa) - 11,
infile,
out,
pRsa,
RSA_PKCS1_PADDING);
RSA_free(pRsa);
if (outLen >= 0) { return 0; }
return -1;
}

//************************************
// function: 用私钥解密
//************************************
int Dec(unsigned char *infile, int inLen, unsigned char *out, int &outLen)
{
BIO *pBio = BIO_new_file(g_pPriFile, "r");
RSA *pRsa = PEM_read_bio_RSAPrivateKey(pBio, NULL, NULL, NULL);
BIO_free_all(pBio);
outLen = RSA_private_decrypt(
inLen,
infile,
out,
pRsa,
RSA_PKCS1_PADDING);
RSA_free(pRsa);
if (outLen >= 0)
return 0;
return -1;
}





void HextoASCll(unsigned char *bytes, int byteNum, char *strAsii)
{
int i = 0;
for (i = 0; i < byteNum; i++)
{
sprintf(strAsii, "%02X", bytes[i]);
strAsii += 2;
}
*strAsii = '\n';
}

void CBC_Encrpt(unsigned char* key, char* pt1, char* ct, int ilen, int ctLen, unsigned char* iv1)
{
AES_KEY k;
AES_set_encrypt_key(key, 256, &k);
/*
 void AES_cbc_encrypt(
 const unsigned char *in,
 unsigned char *out,
 const unsigned long length, //in 的长度
 const AES_KEY *key, //it will be changed during the encrypt&decrypt process, so it required to be reset each time
 unsigned char *ivec, //向量
 const int enc);
 */

AES_cbc_encrypt((unsigned char*)pt1, (unsigned char*)ct, ctLen, &k, (unsigned char*)iv1, AES_ENCRYPT);


//把加密后的内容显示出来
//printf("encrypt:%s\n", ct);

//把加密后的内容二进制显示出来
/*char strAsLL[3200] = { 0 };
HextoASCll((unsigned char*)ct, ctLen, strAsLL);
printf("\n%s\n", strAsLL);*/
}

void CBC_Decrpt(unsigned char* key, char* pt2,char* ct, int ctLen, unsigned char* iv2)
{
AES_KEY k;
AES_set_decrypt_key(key, 256, &k);
int len = strlen(ct);
//下面用了ctLen是因为加密后的秘文中可能夹杂‘\0’,这样解密就只会解一段出来
//AES_cbc_encrypt((unsigned char*)ct, (unsigned char*)pt2,strlen(ct), &k, (unsigned char*)iv2, AES_DECRYPT);//解密内容不全
AES_cbc_encrypt((unsigned char*)ct, (unsigned char*)pt2, ctLen, &k, (unsigned char*)iv2, AES_DECRYPT);

}

int main()
{

unsigned char key[32+1] = ")*^&$*kdjfkdjfjdsjfska!*&^%$#@ab"; // 256bits key (应该是真正的随机数才好)
cout << "原key" << "(" << strlen((char*)key) << ")"<<endl ;

unsigned char rsaEnc[500] = { 0 };//rsa处理后的加密key
int nEncLen = 0;
unsigned char rsaDec[500] = { 0 };//rsa处理后的解密key
int nDecLen = 0;

/////////////////////////////////////////////////////////
/////利用RSA对设置的key进行非对称加密处理

MakeKey("2", "2");
Enc(key,strlen((char*)key), rsaEnc, nEncLen);
//cout << "RSA加密之后"<<"("<<nEncLen<<")" <<endl<<rsaEnc << endl<<endl;

Dec(rsaEnc, strlen((char*)rsaEnc), rsaDec, nDecLen);
cout << "RSA解密之后"<<"("<< nDecLen <<")"<<endl <<rsaDec << endl << endl;
unsigned char rsa_keybuf[32 + 1] = { 0 };

memcpy(rsa_keybuf, rsaDec, strlen((char*)rsaDec));

char ptSource[TxtBufLen] = {0};//原数据明文
char ct[TxtBufLen] = { 0 }; // 加密文
char ptResult[TxtBufLen] = { 0 };// 解密后的明文

ReadTxt(ptSource);
int ilen = strlen(ptSource);
int ctLen = (ilen % 16 == 0) ? ilen : (ilen / 16 + 1) * 16;//这是aes加密之后的长度[可能需要自己加密时补充的东西]

unsigned char iv1[16 + 1] = { "|bc~!f947j*$m_op" }; // 16+1,加密用
unsigned char iv2[16 + 1] = { "|bc~!f947j*$m_op" }; // 16+1,解密用


CBC_Encrpt(key, ptSource,ct,ilen,ctLen,iv1);//CBC方式加密数据明文

//将加密处理后的结果存放文本
FILE *fp1 = fopen("aes_CBCencrypt.txt", "w");
fwrite(ct, sizeof(unsigned char), ctLen, fp1);
fflush(fp1);

CBC_Decrpt(rsa_keybuf, ptResult,ct,ctLen,iv2);//CBC方式解密数据明文

//从加密后的字符中截取出属于原数据的长度部分(之前加密时按数据块整数倍加密,可能会有填充的部分)
int Relen = strlen(ptResult);
char* pSource = new char[ilen+1];
memset(pSource, 0, ilen + 1);
memcpy(pSource,ptResult,ilen);

WriteTxt(pSource);

//判断CBC是否成功
if (memcmp(ptSource, pSource, ilen) == 0)
puts("AES CBC mode ok");
else puts("AES CBC mode err");
system("pause");
return 0;
}