-
Notifications
You must be signed in to change notification settings - Fork 2
/
openssl_aes.cc
158 lines (126 loc) · 3.87 KB
/
openssl_aes.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include "openssl_utils.hpp"
#include <gtest/gtest.h>
#include <openssl/evp.h>
#include <random>
// AES generate key and iv
void aes_generate_key_iv(std::string &key, std::string &iv)
{
key.resize(32);
iv.resize(16);
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 255);
for (auto &c : key) {
c = static_cast<char>(dis(gen));
}
for (auto &c : iv) {
c = static_cast<char>(dis(gen));
}
}
// AES encrypt
auto aes_encrypt(const std::string &key, const std::string &iv, const std::string &plain)
-> std::string
{
std::string cipher;
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (ctx == nullptr) {
openssl_error();
return cipher;
}
if (EVP_EncryptInit_ex(ctx,
EVP_aes_256_cbc(), // AES-256-CBC
nullptr,
reinterpret_cast<const unsigned char *>(key.c_str()),
reinterpret_cast<const unsigned char *>(iv.c_str()))
!= 1) {
openssl_error();
EVP_CIPHER_CTX_free(ctx);
return cipher;
}
int len = 0;
int plain_len = static_cast<int>(plain.size());
int max_cipher_len = plain_len + EVP_CIPHER_CTX_block_size(ctx);
cipher.resize(max_cipher_len);
if (EVP_EncryptUpdate(ctx,
reinterpret_cast<unsigned char *>(cipher.data()),
&len,
reinterpret_cast<const unsigned char *>(plain.c_str()),
plain_len)
!= 1) {
openssl_error();
EVP_CIPHER_CTX_free(ctx);
return cipher;
}
int cipher_len = len;
if (EVP_EncryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(cipher.data()) + len, &len)
!= 1) {
openssl_error();
EVP_CIPHER_CTX_free(ctx);
return cipher;
}
cipher_len += len;
cipher.resize(cipher_len);
EVP_CIPHER_CTX_free(ctx);
return cipher;
}
// AES decrypt
auto aes_decrypt(const std::string &key, const std::string &iv, const std::string &cipher)
-> std::string
{
std::string plain;
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (ctx == nullptr) {
openssl_error();
return plain;
}
if (EVP_DecryptInit_ex(ctx,
EVP_aes_256_cbc(), // AES-256-CBC
nullptr,
reinterpret_cast<const unsigned char *>(key.c_str()),
reinterpret_cast<const unsigned char *>(iv.c_str()))
!= 1) {
openssl_error();
EVP_CIPHER_CTX_free(ctx);
return plain;
}
int len = 0;
int cipher_len = static_cast<int>(cipher.size());
int max_plain_len = cipher_len + EVP_CIPHER_CTX_block_size(ctx);
plain.resize(max_plain_len);
if (EVP_DecryptUpdate(ctx,
reinterpret_cast<unsigned char *>(plain.data()),
&len,
reinterpret_cast<const unsigned char *>(cipher.c_str()),
cipher_len)
!= 1) {
openssl_error();
EVP_CIPHER_CTX_free(ctx);
return plain;
}
int plain_len = len;
if (EVP_DecryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(plain.data()) + len, &len) != 1) {
openssl_error();
EVP_CIPHER_CTX_free(ctx);
return plain;
}
plain_len += len;
plain.resize(plain_len);
EVP_CIPHER_CTX_free(ctx);
return plain;
}
TEST(openssl_aes, openssl_aes)
{
std::string plain = "hello world";
std::string key;
std::string iv;
aes_generate_key_iv(key, iv);
std::string cipher = aes_encrypt(key, iv, plain);
std::string result = aes_decrypt(key, iv, cipher);
EXPECT_EQ(plain, result);
}
auto main() -> int
{
openssl_version();
testing::InitGoogleTest();
return RUN_ALL_TESTS();
}