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 加密:仅解密第一个块
是否可以在 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 加密/解密