C++ Openssl AES GCM 128bits代码示例,可wins10的visual studio 2017 中直接运行

Posted 链巨人

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ Openssl AES GCM 128bits代码示例,可wins10的visual studio 2017 中直接运行相关的知识,希望对你有一定的参考价值。

C++ Openssl AES GCM 128bits代码示例,可wins直接运行

使用vcpkg安装64bits的openssl,本人当前的openssl为openssl-1.1.1d版本,wins10系统,使用visual studio2017编辑器

注意事项:如果使用Openssl 1.0的版本,需要使用EVP_CIPHER_CTX ctx;来定义ctx对象。具体看下面链接:https://github.com/openssl/openssl/issues/962

执行结果:

下面代码有两个版本,第一个是基础的没经过速度优化的但比较适合阅读的。第二个是为了性能特意优化了。

代码:



//g++ main.cpp -lcrypto

#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <string>
#include <sstream>
#include <vector>
#include <iostream>

using std::string;
using std::vector;
using std::cout;
using std::endl;



void aes_init()

	static int init = 0;
	if (init == 0)
	
		EVP_CIPHER_CTX * e_ctx = EVP_CIPHER_CTX_new();
		EVP_CIPHER_CTX *d_ctx = EVP_CIPHER_CTX_new();

		//initialize openssl ciphers
		OpenSSL_add_all_ciphers();

		//initialize random number generator (for IVs)
		int rv = RAND_load_file("/dev/urandom", 32);

		EVP_CIPHER_CTX_free(e_ctx);
		EVP_CIPHER_CTX_free(d_ctx);

	


std::vector<unsigned char> aes_128_gcm_encrypt(std::string plaintext, std::string key)

	aes_init();

	size_t enc_length = plaintext.length() * 3;
	std::vector<unsigned char> output;
	output.resize(enc_length, '\\0');

	unsigned char tag[AES_BLOCK_SIZE];
	unsigned char iv[AES_BLOCK_SIZE];
	RAND_bytes(iv, sizeof(iv));
	std::copy(iv, iv + 16, output.begin() + 16);

	int actual_size = 0, final_size = 0;
	EVP_CIPHER_CTX* e_ctx = EVP_CIPHER_CTX_new();
	//EVP_CIPHER_CTX_ctrl(e_ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL);
	EVP_EncryptInit(e_ctx, EVP_aes_128_gcm(), (const unsigned char*)key.c_str(), iv);
	EVP_EncryptUpdate(e_ctx, &output[32], &actual_size, (const unsigned char*)plaintext.data(), plaintext.length());
	EVP_EncryptFinal(e_ctx, &output[32 + actual_size], &final_size);
	EVP_CIPHER_CTX_ctrl(e_ctx, EVP_CTRL_GCM_GET_TAG, 16, tag);
	std::copy(tag, tag + 16, output.begin());
	std::copy(iv, iv + 16, output.begin() + 16);
	output.resize(32 + actual_size + final_size);
	EVP_CIPHER_CTX_free(e_ctx);
	return output;


std::string aes_128_gcm_decrypt(std::vector<unsigned char> ciphertext, std::string key)

	aes_init();

	unsigned char tag[AES_BLOCK_SIZE];
	unsigned char iv[AES_BLOCK_SIZE];
	std::copy(ciphertext.begin(), ciphertext.begin() + 16, tag);
	std::copy(ciphertext.begin() + 16, ciphertext.begin() + 32, iv);
	std::vector<unsigned char> plaintext; plaintext.resize(ciphertext.size(), '\\0');

	int actual_size = 0, final_size = 0;
	EVP_CIPHER_CTX *d_ctx = EVP_CIPHER_CTX_new();
	EVP_DecryptInit(d_ctx, EVP_aes_128_gcm(), (const unsigned char*)key.c_str(), iv);
	EVP_DecryptUpdate(d_ctx, &plaintext[0], &actual_size, &ciphertext[32], ciphertext.size() - 32);
	EVP_CIPHER_CTX_ctrl(d_ctx, EVP_CTRL_GCM_SET_TAG, 16, tag);
	EVP_DecryptFinal(d_ctx, &plaintext[actual_size], &final_size);
	EVP_CIPHER_CTX_free(d_ctx);
	plaintext.resize(actual_size + final_size, '\\0');

	return string(plaintext.begin(), plaintext.end());


int main(int argc, char **argv)

	aes_init();

	//create a sample key
	unsigned char key_bytes[16];
	RAND_bytes(key_bytes, sizeof(key_bytes));
	string key = string((char *)key_bytes, sizeof(key_bytes));

	//text to encrypt
	string plaintext = "elephants in space";
	cout << plaintext << endl;

	//encrypt
	vector<unsigned char> ciphertext = aes_128_gcm_encrypt(plaintext, key);

	//output
	static const char *chars = "0123456789ABCDEF";
	for (int i = 0; i < ciphertext.size(); i++)
	
		cout << chars[ciphertext[i] / 16];
		cout << chars[ciphertext[i] % 16];
	
	cout << endl;

	//decrypt
	string out = aes_128_gcm_decrypt(ciphertext, key);
	cout << out << endl;

	system("pause");


第二个代码:

//http://www.zedwood.com/article/cpp-openssl-aes-gcm-code-sample

//http://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption

//g++ main.cpp -lcrypto

#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <string>
#include <sstream>
#include <vector>
#include <iostream>

#include <chrono>

using std::string;
using std::vector;
using std::cout;
using std::endl;
using namespace std;
using namespace chrono;


EVP_CIPHER_CTX * e_ctx = nullptr;
EVP_CIPHER_CTX *d_ctx = nullptr;

void aes_init()

	static int init = 0;
	if (init == 0)
	
		e_ctx = EVP_CIPHER_CTX_new();
		d_ctx = EVP_CIPHER_CTX_new();

		//initialize openssl ciphers
		OpenSSL_add_all_ciphers();

		//initialize random number generator (for IVs)
		int rv = RAND_load_file("/dev/urandom", 32);

		init++;
	
	


//需要在函数外面使用free()释放参数out的内容
void aes_128_gcm_encrypt0(const char* plaintext, size_t plaintext_len,
				const char * key,
				unsigned char ** out, size_t & out_len) 

	size_t output_length = AES_BLOCK_SIZE + AES_BLOCK_SIZE + plaintext_len;
	unsigned char * output = (unsigned char*)malloc(output_length);

	RAND_bytes(output+16, 16);

	int actual_size = 0, final_size = 0;
	
	EVP_EncryptInit(e_ctx, EVP_aes_128_gcm(), (const unsigned char*)key, output + 16);
	EVP_EncryptUpdate(e_ctx, &output[32], &actual_size, (const unsigned char*)plaintext, plaintext_len);
	EVP_EncryptFinal(e_ctx, &output[32 + actual_size], &final_size);
	EVP_CIPHER_CTX_ctrl(e_ctx, EVP_CTRL_GCM_GET_TAG, 16, output);
	
	*out = output;
	out_len = output_length;


std::vector<unsigned char> aes_128_gcm_encrypt(std::string plaintext, std::string key)
	size_t enc_length = plaintext.length() * 3;
	std::vector<unsigned char> output;
	output.resize(enc_length, '\\0');

	unsigned char tag[AES_BLOCK_SIZE];
	unsigned char iv[AES_BLOCK_SIZE];
	RAND_bytes(iv, sizeof(iv));
	std::copy(iv, iv + 16, output.begin() + 16);

	int actual_size = 0, final_size = 0;
	EVP_CIPHER_CTX* e_ctx = EVP_CIPHER_CTX_new();
	//EVP_CIPHER_CTX_ctrl(e_ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL);
	EVP_EncryptInit(e_ctx, EVP_aes_128_gcm(), (const unsigned char*)key.c_str(), iv);
	EVP_EncryptUpdate(e_ctx, &output[32], &actual_size, (const unsigned char*)plaintext.data(), plaintext.length());
	EVP_EncryptFinal(e_ctx, &output[32 + actual_size], &final_size);
	EVP_CIPHER_CTX_ctrl(e_ctx, EVP_CTRL_GCM_GET_TAG, 16, tag);
	std::copy(tag, tag + 16, output.begin());
	std::copy(iv, iv + 16, output.begin() + 16);
	output.resize(32 + actual_size + final_size);
	EVP_CIPHER_CTX_free(e_ctx);
	return output;


//需要在函数外面使用free()释放参数out的内容
void aes_128_gcm_decrypt0(const char* ciphertext, size_t ciphertext_len,
				const char * key,
				unsigned char ** out, size_t & out_len) 

	unsigned char *plaintext = (unsigned char*)malloc(ciphertext_len - 32);

	int actual_size = 0, final_size = 0;
	EVP_DecryptInit(d_ctx, EVP_aes_128_gcm(), (const unsigned char*)key, (unsigned char*)ciphertext+16);
	EVP_DecryptUpdate(d_ctx, plaintext, &actual_size, (const unsigned char*)&ciphertext[32], ciphertext_len - 32);
	EVP_CIPHER_CTX_ctrl(d_ctx, EVP_CTRL_GCM_SET_TAG, 16, (char*)ciphertext);
	EVP_DecryptFinal(d_ctx, &plaintext[actual_size], &final_size);

	*out = plaintext;
	out_len = ciphertext_len - 32;


std::string aes_128_gcm_decrypt(std::vector<unsigned char> ciphertext, std::string key)


	unsigned char tag[AES_BLOCK_SIZE];
	unsigned char iv[AES_BLOCK_SIZE];
	std::copy(ciphertext.begin(), ciphertext.begin() + 16, tag);
	std::copy(ciphertext.begin() + 16, ciphertext.begin() + 32, iv);
	std::vector<unsigned char> plaintext; 
	plaintext.resize(ciphertext.size(), '\\0');

	int actual_size = 0, final_size = 0;
	EVP_CIPHER_CTX *d_ctx = EVP_CIPHER_CTX_new();
	EVP_DecryptInit(d_ctx, EVP_aes_128_gcm(), (const unsigned char*)key.c_str(), iv);
	EVP_DecryptUpdate(d_ctx, &plaintext[0], &actual_size, &ciphertext[32], ciphertext.size() - 32);
	EVP_CIPHER_CTX_ctrl(d_ctx, EVP_CTRL_GCM_SET_TAG, 16, tag);
	EVP_DecryptFinal(d_ctx, &plaintext[actual_size], &final_size);
	EVP_CIPHER_CTX_free(d_ctx);
	plaintext.resize(actual_size + final_size, '\\0');

	return string(plaintext.begin(), plaintext.end());


void test() 
	aes_init();

	//create a sample key
	unsigned char key_bytes[16];
	RAND_bytes(key_bytes, sizeof(key_bytes));
	string key = string((char *)key_bytes, sizeof(key_bytes));

	//text to encrypt
	string plaintext = "elephants in space dsfsdfgdgdliangyihuaifgf";
	cout << plaintext << endl;

	//encrypt
	//vector<unsigned char> ciphertext = aes_128_gcm_encrypt(plaintext, key);
	unsigned char * enc_msg = nullptr;
	size_t enc_msg_len = -1;
	aes_128_gcm_encrypt0(plaintext.c_str(), plaintext.length(), key.c_str(), &enc_msg, enc_msg_len);

	vector<unsigned char> ciphertext;
	ciphertext.resize(enc_msg_len, '\\0');
	std::copy(enc_msg, enc_msg + enc_msg_len, ciphertext.begin());

	//output
	static const char *chars = "0123456789ABCDEF";
	for (int i = 0; i < ciphertext.size(); i++)
	
		cout << chars[ciphertext[i] / 16];
		cout << chars[ciphertext[i] % 16];
	
	cout << endl;

	//decrypt
	//string out = aes_128_gcm_decrypt(ciphertext, key);
	//cout << out << endl;
	unsigned char * dec_msg = nullptr;
	size_t len_dec_msg = -1;
	aes_128_gcm_decrypt0((char*)enc_msg, enc_msg_len, key.c_str(), &dec_msg, len_dec_msg);

	vector<unsigned char> ciphertext_final;
	ciphertext_final.resize(len_dec_msg, '\\0');
	std::copy(dec_msg, dec_msg + len_dec_msg, ciphertext_final.begin());

	for (int i = 0; i < len_dec_msg; i++) 
		cout << dec_msg[i];
	
	cout << endl;


	free(enc_msg);
	free(dec_msg);


void performanceTest() 
	aes_init();

	//create a sample key
	unsigned char key_bytes[16];
	RAND_bytes(key_bytes, sizeof(key_bytes));
	string key = string((char *)key_bytes, sizeof(key_bytes));

	//text to encrypt
	string plaintext = "elephants in space dsfsdfgdgdliangyihuaifgf";
	cout << plaintext << endl;

	const int round = 10000;
	auto begin = std::chrono::high_resolution_clock::now();
	for (int i = 0; i < round; i++) 
		//encrypt
		unsigned char * enc_msg = nullptr;
		size_t enc_msg_len = -1;
		aes_128_gcm_encrypt0(plaintext.c_str(), plaintext.length(), key.c_str(), &enc_msg, enc_msg_len);

		/*vector<unsigned char> ciphertext;
		ciphertext.resize(enc_msg_len, '\\0');
		std::copy(enc_msg, enc_msg + enc_msg_len, ciphertext.begin());*/

		//output
		/*static const char *chars = "0123456789ABCDEF";
		for (int i = 0; i < ciphertext.size(); i++)
		
			cout << chars[ciphertext[i] / 16];
			cout << chars[ciphertext[i] % 16];
		
		cout << endl;*/

		//decrypt
		unsigned char * dec_msg = nullptr;
		size_t len_dec_msg = -1;
		aes_128_gcm_decrypt0((char*)enc_msg, enc_msg_len, key.c_str(), &dec_msg, len_dec_msg);

		/*vector<unsigned char> ciphertext_final;
		ciphertext_final.resize(len_dec_msg, '\\0');
		std::copy(dec_msg, dec_msg + len_dec_msg, ciphertext_final.begin());

		for (int i = 0; i < len_dec_msg; i++) 
			cout << dec_msg[i];
		
		cout << endl;*/


		free(enc_msg);
		free(dec_msg);
	
	
	auto end = std::chrono::high_resolution_clock::now();
	double elapsedTime = ((duration<double, std::milli>)(end - begin)).count();
	cout << "\\ntotal elapsed time: " << elapsedTime << ", ave = " << (elapsedTime / round) << endl;

	


int main(int argc, char **argv)

	test();
	performanceTest();


	EVP_CIPHER_CTX_free(e_ctx);
	EVP_CIPHER_CTX_free(d_ctx);
	system("pause");


http://www.zedwood.com/article/cpp-openssl-aes-gcm-code-sample

http://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption

以上是关于C++ Openssl AES GCM 128bits代码示例,可wins10的visual studio 2017 中直接运行的主要内容,如果未能解决你的问题,请参考以下文章

使用 OpenSSL/C++ 和 PHP/Mcrypt 的 AES-128-CBC 加密:仅解密第一个块

是否可以在TLSv1.2会话中使用TLSv1.3密码?

是否可以在 iOS 上使用 AES128 和 GCM 模式?

php openssl aes-256-cbc key长度自动匹配了128的长度,为啥

不支持 OpenSSL 密码 PSK-AES128-CCM8?

AES (aes-cbc-128, aes-cbc-192, aes-cbc-256) 使用 openssl C 加密/解密