d4fdad5a0d7fe4387937639072344078d72a4983
[awesomized/libmemcached] / src / libhashkit / aes.cc
1 /*
2 +--------------------------------------------------------------------+
3 | libmemcached-awesome - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020-2021 Michael Wallner https://awesome.co/ |
13 +--------------------------------------------------------------------+
14 */
15
16 #include "libhashkit/common.h"
17
18 #include <cstring>
19
20 #ifdef WITH_OPENSSL
21
22 #include <openssl/evp.h>
23
24 #define DIGEST_ROUNDS 5
25
26 #define AES_KEY_NBYTES 32
27 #define AES_IV_NBYTES 32
28
29 bool aes_initialize(const unsigned char *key, const size_t key_length,
30 encryption_context_t *crypto_context) {
31 unsigned char aes_key[AES_KEY_NBYTES];
32 unsigned char aes_iv[AES_IV_NBYTES];
33 if (aes_key == NULL || aes_iv == NULL) {
34 return false;
35 }
36
37 int i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha256(), NULL, key, key_length, DIGEST_ROUNDS,
38 aes_key, aes_iv);
39 if (i != AES_KEY_NBYTES) {
40 return false;
41 }
42
43 EVP_CIPHER_CTX_init(crypto_context->encryption_context);
44 EVP_CIPHER_CTX_init(crypto_context->decryption_context);
45 if (EVP_EncryptInit_ex(crypto_context->encryption_context, EVP_aes_256_cbc(), NULL, key, aes_iv)
46 != 1
47 || EVP_DecryptInit_ex(crypto_context->decryption_context, EVP_aes_256_cbc(), NULL, key,
48 aes_iv)
49 != 1)
50 {
51 return false;
52 }
53 return true;
54 }
55
56 hashkit_string_st *aes_encrypt(encryption_context_t *crypto_context, const unsigned char *source,
57 size_t source_length) {
58 EVP_CIPHER_CTX *encryption_context = crypto_context->encryption_context;
59 int cipher_length = source_length + EVP_CIPHER_CTX_block_size(encryption_context);
60 int final_length = 0;
61 unsigned char *cipher_text = (unsigned char *) malloc(cipher_length);
62 if (cipher_text == NULL) {
63 return NULL;
64 }
65 if (EVP_EncryptInit_ex(encryption_context, NULL, NULL, NULL, NULL) != 1
66 || EVP_EncryptUpdate(encryption_context, cipher_text, &cipher_length, source, source_length)
67 != 1
68 || EVP_EncryptFinal_ex(encryption_context, cipher_text + cipher_length, &final_length) != 1)
69 {
70 free(cipher_text);
71 return NULL;
72 }
73
74 hashkit_string_st *destination = hashkit_string_create(cipher_length + final_length);
75 if (destination == NULL) {
76 return NULL;
77 }
78 char *dest = hashkit_string_c_str_mutable(destination);
79 memcpy(dest, cipher_text, cipher_length + final_length);
80 hashkit_string_set_length(destination, cipher_length + final_length);
81 return destination;
82 }
83
84 hashkit_string_st *aes_decrypt(encryption_context_t *crypto_context, const unsigned char *source,
85 size_t source_length) {
86 EVP_CIPHER_CTX *decryption_context = crypto_context->decryption_context;
87 int plain_text_length = source_length;
88 int final_length = 0;
89 unsigned char *plain_text = (unsigned char *) malloc(plain_text_length);
90 if (plain_text == NULL) {
91 return NULL;
92 }
93 if (EVP_DecryptInit_ex(decryption_context, NULL, NULL, NULL, NULL) != 1
94 || EVP_DecryptUpdate(decryption_context, plain_text, &plain_text_length, source, source_length)
95 != 1
96 || EVP_DecryptFinal_ex(decryption_context, plain_text + plain_text_length, &final_length) != 1)
97 {
98 free(plain_text);
99 return NULL;
100 }
101
102 hashkit_string_st *destination = hashkit_string_create(plain_text_length + final_length);
103 if (destination == NULL) {
104 return NULL;
105 }
106 char *dest = hashkit_string_c_str_mutable(destination);
107 memcpy(dest, plain_text, plain_text_length + final_length);
108 hashkit_string_set_length(destination, plain_text_length + final_length);
109 return destination;
110 }
111
112 encryption_context_t *aes_clone_cryptographic_context(encryption_context_t *source) {
113 encryption_context_t *new_context = (encryption_context_t *) malloc(sizeof(encryption_context_t));
114 if (new_context == NULL)
115 return NULL;
116
117 new_context->encryption_context = EVP_CIPHER_CTX_new();
118 new_context->decryption_context = EVP_CIPHER_CTX_new();
119 if (new_context->encryption_context == NULL || new_context->decryption_context == NULL) {
120 free(new_context);
121 return NULL;
122 }
123 EVP_CIPHER_CTX_copy(new_context->encryption_context, source->encryption_context);
124 EVP_CIPHER_CTX_copy(new_context->decryption_context, source->decryption_context);
125 return new_context;
126 }
127
128 #else
129
130 # include "libhashkit/rijndael.hpp"
131
132 # define AES_KEY_LENGTH 256 /* 128, 192, 256 */
133 # define AES_BLOCK_SIZE 16
134
135 enum encrypt_t { AES_ENCRYPT, AES_DECRYPT };
136
137 struct _key_t {
138 int nr;
139 uint32_t rk[4 * (AES_MAXNR + 1)];
140 };
141
142 struct aes_key_t {
143 _key_t encode_key;
144 _key_t decode_key;
145 };
146
147 aes_key_t *aes_create_key(const char *key, const size_t key_length) {
148 aes_key_t *_aes_key = (aes_key_t *) (calloc(1, sizeof(aes_key_t)));
149 if (_aes_key) {
150 uint8_t rkey[AES_KEY_LENGTH / 8];
151 uint8_t *rkey_end = rkey + AES_KEY_LENGTH / 8;
152 const char *key_end = key + key_length;
153
154 memset(rkey, 0, sizeof(rkey)); /* Set initial key */
155
156 uint8_t *ptr = rkey;
157 const char *sptr = key;
158 for (; sptr < key_end; ptr++, sptr++) {
159 if (ptr == rkey_end) {
160 ptr = rkey; /* Just loop over tmp_key until we used all key */
161 }
162 *ptr ^= (uint8_t) (*sptr);
163 }
164
165 _aes_key->decode_key.nr = rijndaelKeySetupDec(_aes_key->decode_key.rk, rkey, AES_KEY_LENGTH);
166 _aes_key->encode_key.nr = rijndaelKeySetupEnc(_aes_key->encode_key.rk, rkey, AES_KEY_LENGTH);
167 }
168
169 return _aes_key;
170 }
171
172 aes_key_t *aes_clone_key(aes_key_t *_aes_key) {
173 if (_aes_key == NULL) {
174 return NULL;
175 }
176
177 aes_key_t *_aes_clone_key = (aes_key_t *) (calloc(1, sizeof(aes_key_t)));
178 if (_aes_clone_key) {
179 memcpy(_aes_clone_key, _aes_key, sizeof(aes_key_t));
180 }
181
182 return _aes_clone_key;
183 }
184
185 hashkit_string_st *aes_encrypt(aes_key_t *_aes_key, const char *source, size_t source_length) {
186 if (_aes_key == NULL) {
187 return NULL;
188 }
189
190 size_t num_blocks = source_length / AES_BLOCK_SIZE;
191
192 hashkit_string_st *destination = hashkit_string_create(source_length);
193 if (destination) {
194 char *dest = hashkit_string_c_str_mutable(destination);
195
196 for (size_t x = num_blocks; x > 0; x--) /* Encode complete blocks */ {
197 rijndaelEncrypt(_aes_key->encode_key.rk, _aes_key->encode_key.nr, (const uint8_t *) (source),
198 (uint8_t *) (dest));
199 source += AES_BLOCK_SIZE;
200 dest += AES_BLOCK_SIZE;
201 }
202
203 uint8_t block[AES_BLOCK_SIZE];
204 char pad_len = AES_BLOCK_SIZE - (source_length - AES_BLOCK_SIZE * num_blocks);
205 memcpy(block, source, 16 - pad_len);
206 memset(block + AES_BLOCK_SIZE - pad_len, pad_len, pad_len);
207 rijndaelEncrypt(_aes_key->encode_key.rk, _aes_key->encode_key.nr, block, (uint8_t *) (dest));
208 hashkit_string_set_length(destination, AES_BLOCK_SIZE * (num_blocks + 1));
209 }
210
211 return destination;
212 }
213
214 hashkit_string_st *aes_decrypt(aes_key_t *_aes_key, const char *source, size_t source_length) {
215 if (_aes_key == NULL) {
216 return NULL;
217 }
218
219 size_t num_blocks = source_length / AES_BLOCK_SIZE;
220 if ((source_length != num_blocks * AES_BLOCK_SIZE) or num_blocks == 0) {
221 return NULL;
222 }
223
224 hashkit_string_st *destination = hashkit_string_create(source_length);
225 if (destination) {
226 char *dest = hashkit_string_c_str_mutable(destination);
227
228 for (size_t x = num_blocks - 1; x > 0; x--) {
229 rijndaelDecrypt(_aes_key->decode_key.rk, _aes_key->decode_key.nr, (const uint8_t *) (source),
230 (uint8_t *) (dest));
231 source += AES_BLOCK_SIZE;
232 dest += AES_BLOCK_SIZE;
233 }
234
235 uint8_t block[AES_BLOCK_SIZE];
236 rijndaelDecrypt(_aes_key->decode_key.rk, _aes_key->decode_key.nr, (const uint8_t *) (source),
237 block);
238 /* Use last char in the block as size */
239 unsigned int pad_len = (unsigned int) (unsigned char) (block[AES_BLOCK_SIZE - 1]);
240 if (pad_len > AES_BLOCK_SIZE) {
241 hashkit_string_free(destination);
242 return NULL;
243 }
244
245 /* We could also check whole padding but we do not really need this */
246
247 memcpy(dest, block, AES_BLOCK_SIZE - pad_len);
248 hashkit_string_set_length(destination, AES_BLOCK_SIZE * num_blocks - pad_len);
249 }
250
251 return destination;
252 }
253 #endif