C++实现基于openssl的AES加密,支持文件和字节数组的加密,linux和windows通用

基于openssl使用C++实现的AES加密功能,支持文件加密,字节数组加密。linux和windows都可使用(PS:使用此方式需要先安装openssl)。linux发行版一般自带openssl,window版可以在可以点击此处下载windows版openssl

源文件

aes.h


#ifndef __AES_H__
#define __AES_H__

#define OS_LINUX	0x00
#define	OS_WINDOWS	0x01

#define TYPE_OS		OS_WINDOWS	//windows下使用

#if TYPE_OS == OS_WINDOWS
//去掉编译警告
#define _CRT_NONSTDC_NO_DEPRECATE 
#define _CRT_SECURE_NO_WARNINGS

#pragma comment(lib,"libssl.lib")
#pragma comment(lib,"libcrypto.lib")
#endif

#define AES_BIT		256//192//256
#define AES_KEYLEN  AES_BIT/8

 //错误码定义
enum SysErrCode {
	ErrNone = 0,
	ErrSrcNotExist,
	ErrSrcOpenFail,
	ErrDstOpenFail,
	ErrWriteFail,
	ErrAesFileFormat
};

class aes {
public:
	enum AESBIT {
		AES_256 = 256,
		AES_192 = 192,
		AES_128 = 128,
	};

	int aesBit;
	int aesKeyLen;
	unsigned char *myKey;

	/**
	  * @brief aes构造函数
	  */
	aes();

	/**
	  * @brief aes析构函数
	  */
	~aes();

	/**
	  * @brief 设置加密key
	  */
	int setKey(unsigned char *key, AESBIT bit);

	/**
	  * @brief 加密输入缓冲内容
	  */
	int encryptBuf(unsigned char *inbuf, int inbuflen, unsigned char *outbuf);

	/**
	  * @brief 解密输入缓冲内容
	  */
	int decryptBuf(unsigned char *inbuf, int inbuflen, unsigned char *outbuf);

	/**
	  * @brief AES文件加密
	  */
	int encryptFile(const char *src_path, const char *dst_path);

	/**
	  * @brief AES文件解密
	  */
	int decryptFile(const char *src_path, const char *dst_path);

};

#endif

aes.cpp

#include "aes.h"
#include <stdio.h>
#include <stdarg.h>
#include <sys/types.h> 
#include <fcntl.h>
#include <sys/stat.h>
#include <memory.h>
#include <stdlib.h>
#include <openssl/aes.h>

#if TYPE_OS == OS_WINDOWS
#include <io.h>
#define lstat		_stati64
#define	stat		_stati64
#else
#include <sys/vfs.h>
#endif // TYPE_OS == OS_WINDOWS

using namespace std;

static const unsigned int READ_BUF_LEN = 1024 * 1024;
#if AES_BIT == 256
unsigned char gAESKEY[AES_KEYLEN] = { 0x45,0x4d,0x5e,0xdf,0x8c,0xae,0x53,0x23,
								   0xc4,0xed,0xac,0x99,0xaa,0x78,0x29,0x45,
								   0x11,0x54,0x36,0x65,0x45,0x88,0xac,0xea,
								   0xde,0xdd,0xea,0xeb,0xbd,0x8b,0x9a,0xb5 };
#elif AES_BIT == 192
unsigned char gAESKEY[AES_KEYLEN] = { 0x85,0x4d,0x55,0xdf,0x8c,0xae,0x53,0x23,
								   0xca,0xed,0xac,0x99,0xaa,0x76,0x29,0x45,
								   0x11,0x54,0x31,0x65,0x45,0x28,0xac,0xea };

#elif AES_BIT == 128
unsigned char gAESKEY[AES_KEYLEN] = { 0x85,0x4d,0x5e,0xdf,0x8c,0x5e,0x53,0x23,
								   0xca,0xed,0xac,0x97s,0xaa,0x78,0x29,0x45 };
#endif

/**
  * @brief 构造函数
  */
aes::aes()
{
	aesBit = AES_BIT;
	aesKeyLen = AES_KEYLEN;
	myKey = new unsigned char[aesKeyLen];
	memcpy(myKey, gAESKEY, aesKeyLen);
}

/**
  * @brief 析构函数
  */
aes::~aes()
{
	delete[] myKey;
}

/**
  * @brief 设置密钥和加密位数
  * @para1 key 密钥
  * @para2 bit 加密位数
  * @expl
  * @return 0:成功 -1:失败
  */
int aes::setKey(unsigned char * key, AESBIT bit)
{
	aesBit = bit;
	aesKeyLen = bit / 8;
	delete[] myKey;
	myKey = new unsigned char[aesKeyLen];
	memcpy(myKey, key, aesKeyLen);
	return 0;
}


/**
  * @brief 加密输入缓冲内容
  * @para1 inbuf 输入缓冲
  * @para2 inbuflen 输入缓冲大小
  * @para3 outbuf 输出缓冲
  * @expl
  * @return 加密后的字节数
  */
int aes::encryptBuf(unsigned char *inbuf, int inbuflen, unsigned char *outbuf)
{
	AES_KEY aeskey;
	int read_size, remain;
	int block, block_remain;
	unsigned char *mInbuf = new unsigned char[inbuflen+32];
	memcpy(mInbuf,inbuf,inbuflen);

	read_size = inbuflen;
	block = read_size / 16;
	block_remain = read_size % 16;

	AES_set_encrypt_key(myKey, aesBit, &aeskey);

	for (int i = 0; i < block; i++) {
		AES_encrypt(&mInbuf[i * 16], &outbuf[i * 16], &aeskey);
	}
	remain = 32 - block_remain;
	for (int i = block_remain; i < 16; i++) 
		mInbuf[i + block * 16] = remain;
	AES_encrypt(&mInbuf[block * 16], &outbuf[block * 16], &aeskey);
	block++;
	for (int i =0; i < 16; i++)
		mInbuf[i + block * 16] = remain;
	AES_encrypt(&mInbuf[block * 16], &outbuf[block * 16], &aeskey);
	block++;

	delete [] mInbuf;
	return block * 16;
}

/**
  * @brief 解密输入缓冲内容
  * @para1 inbuf 输入缓冲
  * @para2 inbuflen 输入缓冲大小
  * @para3 outbuf 输出缓冲
  * @expl
  * @return 加密后的字节数
  */
int aes::decryptBuf(unsigned char *inbuf, int inbuflen, unsigned char *outbuf)
{
	AES_KEY aeskey;
	int same = 0, write_len;
	int read_size, block;
	unsigned char data;

	AES_set_decrypt_key(myKey, aesBit, &aeskey);

	read_size = inbuflen;

	block = read_size / 16;

	for (int i = 0; i < block; i++)
		AES_decrypt(&inbuf[i * 16], &outbuf[i * 16], &aeskey);

	write_len = read_size;

	data = outbuf[read_size - 1];
	for (int i = 0; i < 32; i++) {
		if (data == outbuf[read_size - 1 - i]) {
			same++;
		}
		else {
			break;
		}
	}
	if (same > 0 && same >= data) {
		write_len = read_size - same;
	}

	return write_len;
}

/**
  * @brief AES文件加密
  * @para1 src_path 源文件,未加密的文件
  * @para2 dst_path 目的文件,加密文件
  * @expl
  * @return 0:成功 其他:失败
  */
int aes::encryptFile(const char *src_path, const char *dst_path)
{

	AES_KEY aeskey;
	struct stat src_stat;
	int read_fd, write_fd, ret, add_tail = 0;
	long long read_file_size;
	int read_size, remain;
	int block, block_remain;
	unsigned char *inbuf=new unsigned char[READ_BUF_LEN+32];
	unsigned char *outbuf=new unsigned char[READ_BUF_LEN+32];

	/* 获取文件属性 */
	if (lstat(src_path, &src_stat) != 0)
		return ErrSrcNotExist;

	read_file_size = src_stat.st_size;

	if (read_file_size % 16 == 0 || read_file_size == 0)
		add_tail = 1;


	read_fd = open(src_path, O_RDONLY | O_BINARY);
	if (read_fd < 0)
		return ErrSrcOpenFail;


	write_fd = open(dst_path, O_CREAT | O_WRONLY | O_BINARY);
	if (write_fd < 0) {
		close(read_fd);
		return ErrDstOpenFail;
	}

	AES_set_encrypt_key(myKey, aesBit, &aeskey);

	while (read_file_size > 0) {
		read_size = read(read_fd, inbuf, READ_BUF_LEN);
		block = read_size / 16;
		block_remain = read_size % 16;
		for (int i = 0; i < block; i++) {
			AES_encrypt(&inbuf[i * 16], &outbuf[i * 16], &aeskey);
		}
		if (block_remain != 0) {
			remain = 32 - block_remain;
			for (int i = block_remain; i < 16; i++)
				inbuf[i + block * 16] = remain;
			AES_encrypt(&inbuf[block * 16], &outbuf[block * 16], &aeskey);
			block++;
			for (int i = 0; i < 16; i++)
				inbuf[i + block * 16] = remain;
			AES_encrypt(&inbuf[block * 16], &outbuf[block * 16], &aeskey);
			block++;
		}
		ret = write(write_fd, outbuf, block * 16);
		if (ret < 0)
			goto END;
		read_file_size -= read_size;
	}

	if (add_tail == 1) {
		for (int k = 0; k < 2; k++) {
			memset(inbuf, 32, 16);
			AES_encrypt(inbuf, outbuf, &aeskey);
			ret = write(write_fd, outbuf, 16);
			if (ret < 0)
				goto END;
		}
	}

END:
	close(read_fd);
	close(write_fd);

	delete[] inbuf;
	delete[] outbuf;
	if (ret < 0)
		return ErrWriteFail;

	return ErrNone;
}

/**
  * @brief AES文件解密
  * @para1 src_path 源文件,解密前的密文
  * @para2 dst_path 目的文件,解密后的明文
  * @expl
  * @return 0:成功 其他:失败
  */
int aes::decryptFile(const char *src_path, const char *dst_path)
{
	AES_KEY aeskey;
	struct stat src_stat;
	int read_fd, write_fd, ret, same = 0, write_len;
	long long read_file_size;
	int read_size, block;
	unsigned char *inbuf= new unsigned char[READ_BUF_LEN+32];
	unsigned char *outbuf=new unsigned char[READ_BUF_LEN+32];
	unsigned char data;
	char *dstfileDir = NULL;

	/* 获取文件属性 */
	if (lstat(src_path, &src_stat) != 0)
		return ErrSrcNotExist;

	read_file_size = src_stat.st_size;

	/* 判断加密文件长度是否合法,正常为16的倍数 */
	if (read_file_size % 16 != 0 || read_file_size == 0)
		return ErrAesFileFormat;

	read_fd = open(src_path, O_RDONLY | O_BINARY);
	if (read_fd < 0)
		return ErrSrcOpenFail;

	/* 删除已存在的目的文件 */
	unlink(dst_path);

	write_fd = open(dst_path, O_CREAT | O_WRONLY | O_BINARY);
	if (write_fd < 0) {
		close(read_fd);
		return ErrDstOpenFail;
	}

	AES_set_decrypt_key(myKey, aesBit, &aeskey);

	while (read_file_size > 0) {
		read_size = read(read_fd, inbuf, READ_BUF_LEN);

		block = read_size / 16;

		for (int i = 0; i < block; i++)
			AES_decrypt(&inbuf[i * 16], &outbuf[i * 16], &aeskey);

		write_len = read_size;

		if (read_size == read_file_size) {
			data = outbuf[read_size - 1];
			for (int i = 0; i < 32; i++) {
				if (data == outbuf[read_size - 1 - i]) {
					same++;
				}
				else {
					break;
				}
			}
			if (same > 0 && same >= data) {
				write_len = read_size - data;
			}
		}
		ret = write(write_fd, outbuf, write_len);
		if (ret < 0)
			goto END;
		read_file_size -= read_size;
	}
END:
	close(read_fd);
	close(write_fd);

	delete[] inbuf;
	delete[] outbuf;

	if (ret < 0)
		return ErrWriteFail;
	return ErrNone;
}

使用方式及测试示例:

//文件加解密
aes Aes;
Aes.encryptFile("F:/src_9.txt", "F:/src_9.aes");
Aes.decryptFile("F:/src_9.aes", "F:/src_9_new.txt");
Aes.encryptFile("F:/src_16.txt", "F:/src_16.aes");
Aes.decryptFile("F:/src_16.aes", "F:/src_16_new.txt");
Aes.encryptFile("F:/src_20.txt", "F:/src_20.aes");
Aes.decryptFile("F:/src_20.aes", "F:/src_20_new.txt");
Aes.encryptFile("F:/src_32.txt", "F:/src_32.aes");
Aes.decryptFile("F:/src_32.aes", "F:/src_32_new.txt");

//字节数组加解密(PS:加密后的输出数组长度至少为输入数组的大小加上32字节)
unsigned char buf_7[] = { 0x13,0x24,0x35,0x42,0x78,0x9,0xad };
unsigned char buf_16[] = { 0x13,0x24,0x35,0x42,0x78,0x9,0xad,0xed,0xac,0xcb,0x87,0x34,0x76,0x23,0x13,0x1 };
unsigned char buf_31[] = { 0x13,0x24,0x35,0x42,0x78,0x9,0xad,0xed,0xac,0xcb,0x87,0x34,0x76,0x23,0x13,0x3 , 0x13,0x24,0x35,0x42,0x78,0x9,0xad,0xed,0xac,0xcb,0x87,0x34,0x76,0x23,0x1 };
unsigned char buf_64[] = { 0x13,0x24,0x35,0x42,0x78,0x9,0xad,0xed,0xac,0xcb,0x87,0x34,0x76,0x23,0x13,0x3 , 0x13,0x24,0x35,0x42,0x78,0x9,0xad,0xed,0xac,0xcb,0x87,0x34,0x76,0x23,0x13,0x3 ,
				0x13,0x24,0x35,0x42,0x78,0x9,0xad,0xed,0xac,0xcb,0x87,0x34,0x76,0x23,0x13,0x3 , 0x13,0x24,0x35,0x42,0x78,0x9,0xad,0xed,0xac,0xcb,0x87,0x34,0x76,0x23,0x13,0x3 };

unsigned char buf_7_aes[128] = { 0 };
unsigned char buf_16_aes[128] = { 0 };
unsigned char buf_31_aes[128] = { 0 };
unsigned char buf_64_aes[128] = { 0 };

unsigned char buf_7_out[128] = { 0 };
unsigned char buf_16_out[128] = { 0 };
unsigned char buf_31_out[128] = { 0 };
unsigned char buf_64_out[128] = { 0 };

int aeslen, srclen,i;
aeslen = Aes.encryptBuf(buf_7, sizeof(buf_7), buf_7_aes);
srclen = Aes.decryptBuf(buf_7_aes,aeslen,buf_7_out);
if (srclen == sizeof(buf_7)) {
	for (i = 0; i < srclen; i++) {
		if (buf_7[i] != buf_7_out[i]) {
			printf("buf_7 not equal\n");
			break;
		}
	}
}
else
	printf("buf_7 not equal len=%d\n",srclen);

aeslen = Aes.encryptBuf(buf_16, sizeof(buf_16), buf_16_aes);
srclen = Aes.decryptBuf(buf_16_aes, aeslen, buf_16_out);
if (srclen == sizeof(buf_16)) {
	for (i = 0; i < srclen; i++) {
		if (buf_16[i] != buf_16_out[i]) {
			printf("buf_16 not equal\n");
			break;
		}
	}
}
else
	printf("buf_16 not equal len=%d\n", srclen);

aeslen = Aes.encryptBuf(buf_31, sizeof(buf_31), buf_31_aes);
srclen = Aes.decryptBuf(buf_31_aes, aeslen, buf_31_out);
if (srclen == sizeof(buf_31)) {
	for (i = 0; i < srclen; i++) {
		if (buf_31[i] != buf_31_out[i]) {
			printf("buf_31 not equal\n");
			break;
		}
	}
}
else
	printf("buf_31 not equal len=%d\n", srclen);

aeslen = Aes.encryptBuf(buf_64, sizeof(buf_64), buf_64_aes);
srclen = Aes.decryptBuf(buf_64_aes, aeslen, buf_64_out);
if (srclen == sizeof(buf_64)) {
	for (i = 0; i < srclen; i++) {
		if (buf_64[i] != buf_64_out[i]) {
			printf("buf_64 not equal\n");
			break;
		}
	}
}
else
	printf("buf_64 not equal len=%d\n", srclen);
下面是一个简单的C++示例代码,用于基于OpenSSL实现文件的对称加密和密钥管理: ```c++ #include <iostream> #include <fstream> #include <cstring> #include <openssl/evp.h> #include <openssl/rand.h> #include <openssl/err.h> #define KEY_LEN 32 using namespace std; int main(int argc, char *argv[]) { if (argc != 3) { cout << "Usage: " << argv[0] << " <input_file> <output_file>" << endl; return -1; } // Generate a random key unsigned char key[KEY_LEN]; if (RAND_bytes(key, KEY_LEN) != 1) { cerr << "Error: failed to generate random key" << endl; ERR_print_errors_fp(stderr); return -1; } // Open input file for reading ifstream in(argv[1], ios::binary); if (!in.is_open()) { cerr << "Error: failed to open input file" << endl; return -1; } // Open output file for writing ofstream out(argv[2], ios::binary); if (!out.is_open()) { cerr << "Error: failed to open output file" << endl; return -1; } // Initialize encryption context EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) { cerr << "Error: failed to initialize encryption context" << endl; return -1; } // Set up encryption algorithm if (EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, NULL) != 1) { cerr << "Error: failed to set up encryption algorithm" << endl; EVP_CIPHER_CTX_free(ctx); return -1; } // Read input file and encrypt data unsigned char inbuf[1024]; unsigned char outbuf[1024 + EVP_CIPHER_block_size(EVP_aes_256_cbc())]; int outlen; while (in.good()) { in.read(reinterpret_cast<char *>(inbuf), sizeof(inbuf)); int inlen = in.gcount(); if (EVP_EncryptUpdate(ctx, outbuf, &outlen, inbuf, inlen) != 1) { cerr << "Error: failed to encrypt data" << endl; EVP_CIPHER_CTX_free(ctx); return -1; } out.write(reinterpret_cast<char *>(outbuf), outlen); } // Finalize encryption process if (EVP_EncryptFinal_ex(ctx, outbuf, &outlen) != 1) { cerr << "Error: failed to finalize encryption process" << endl; EVP_CIPHER_CTX_free(ctx); return -1; } out.write(reinterpret_cast<char *>(outbuf), outlen); // Clean up EVP_CIPHER_CTX_free(ctx); in.close(); out.close(); return 0; } ``` 这个示例程序使用了AES-256-CBC算法来加密数据,生成了一个32字节长度的随机密钥,并将其保存到一个数组中。然后,它打开一个输入文件和一个输出文件,并使用EVP_EncryptUpdate函数来逐块读取输入文件加密数据,最后使用EVP_EncryptFinal_ex函数来完成加密过程。在加密过程中,程序还会进行错误检查,以确保加密过程能够正确执行。 对于密钥管理,一种常见的方法是使用另一个密钥对主密钥进行加密,然后将加密后的主密钥存储在文件中。这样,只有持有加密主密钥的人才能够解密主密钥,并使用它来解密文件。这个过程可以使用相同的OpenSSL函数来完成。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值