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 +--------------------------------------------------------------------+
16 #include "libhashkit/common.h"
20 #ifdef HAVE_OPENSSL_CRYPTO
22 #include <openssl/evp.h>
24 #define DIGEST_ROUNDS 5
26 #define AES_KEY_NBYTES 32
27 #define AES_IV_NBYTES 32
30 EVP_CIPHER_CTX
*encryption_context
;
31 EVP_CIPHER_CTX
*decryption_context
;
35 aes_key_t
*aes_create_key(const char *key
, const size_t key_length
) {
36 unsigned char aes_key
[AES_KEY_NBYTES
];
37 unsigned char aes_iv
[AES_IV_NBYTES
];
38 const unsigned char *ukey
= (const unsigned char *) key
;
44 int i
= EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha256(), NULL
, ukey
, key_length
, DIGEST_ROUNDS
,
46 if (i
!= AES_KEY_NBYTES
) {
50 aes_key_t
*aes_ctx
= (aes_key_t
*) malloc(sizeof(aes_key_t
));
52 if (!(aes_ctx
->encryption_context
= EVP_CIPHER_CTX_new())) {
55 if (!(aes_ctx
->decryption_context
= EVP_CIPHER_CTX_new())) {
56 EVP_CIPHER_CTX_free(aes_ctx
->encryption_context
);
60 EVP_CIPHER_CTX_init(aes_ctx
->encryption_context
);
61 EVP_CIPHER_CTX_init(aes_ctx
->decryption_context
);
62 if (EVP_EncryptInit_ex(aes_ctx
->encryption_context
, EVP_aes_256_cbc(), NULL
, ukey
, aes_iv
) != 1
63 || EVP_DecryptInit_ex(aes_ctx
->decryption_context
, EVP_aes_256_cbc(), NULL
, ukey
, aes_iv
) != 1)
65 aes_free_key(aes_ctx
);
72 hashkit_string_st
*aes_encrypt(aes_key_t
*ctx
, const char *source
, size_t source_length
) {
73 EVP_CIPHER_CTX
*encryption_context
= ctx
->encryption_context
;
74 int cipher_length
= source_length
+ EVP_CIPHER_CTX_block_size(encryption_context
);
76 const unsigned char *usource
= (const unsigned char *) source
;
77 unsigned char *cipher_text
= (unsigned char *) malloc(cipher_length
);
81 if (EVP_EncryptInit_ex(encryption_context
, NULL
, NULL
, NULL
, NULL
) != 1
82 || EVP_EncryptUpdate(encryption_context
, cipher_text
, &cipher_length
, usource
, source_length
) != 1
83 || EVP_EncryptFinal_ex(encryption_context
, cipher_text
+ cipher_length
, &final_length
) != 1)
89 hashkit_string_st
*destination
= hashkit_string_create(cipher_length
+ final_length
);
93 char *dest
= hashkit_string_c_str_mutable(destination
);
94 memcpy(dest
, cipher_text
, cipher_length
+ final_length
);
95 hashkit_string_set_length(destination
, cipher_length
+ final_length
);
99 hashkit_string_st
*aes_decrypt(aes_key_t
*ctx
, const char *source
, size_t source_length
) {
100 EVP_CIPHER_CTX
*decryption_context
= ctx
->decryption_context
;
101 int plain_text_length
= source_length
;
102 int final_length
= 0;
103 const unsigned char *usource
= (const unsigned char *) source
;
104 unsigned char *plain_text
= (unsigned char *) malloc(plain_text_length
);
108 if (EVP_DecryptInit_ex(decryption_context
, NULL
, NULL
, NULL
, NULL
) != 1
109 || EVP_DecryptUpdate(decryption_context
, plain_text
, &plain_text_length
, usource
, source_length
) != 1
110 || EVP_DecryptFinal_ex(decryption_context
, plain_text
+ plain_text_length
, &final_length
) != 1)
116 hashkit_string_st
*destination
= hashkit_string_create(plain_text_length
+ final_length
);
120 char *dest
= hashkit_string_c_str_mutable(destination
);
121 memcpy(dest
, plain_text
, plain_text_length
+ final_length
);
122 hashkit_string_set_length(destination
, plain_text_length
+ final_length
);
126 aes_key_t
*aes_clone_key(aes_key_t
*old_context
) {
131 aes_key_t
*new_context
= (aes_key_t
*) malloc(sizeof(aes_key_t
));
133 new_context
->encryption_context
= EVP_CIPHER_CTX_new();
134 new_context
->decryption_context
= EVP_CIPHER_CTX_new();
135 if (!new_context
->encryption_context
|| !new_context
->decryption_context
) {
136 aes_free_key(new_context
);
139 EVP_CIPHER_CTX_copy(new_context
->encryption_context
, old_context
->encryption_context
);
140 EVP_CIPHER_CTX_copy(new_context
->decryption_context
, old_context
->decryption_context
);
146 void aes_free_key(aes_key_t
*context
) {
148 if (context
->encryption_context
) {
149 EVP_CIPHER_CTX_free(context
->encryption_context
);
150 context
->encryption_context
= NULL
;
152 if (context
->decryption_context
) {
153 EVP_CIPHER_CTX_free(context
->decryption_context
);
154 context
->decryption_context
= NULL
;
162 # include "libhashkit/rijndael.hpp"
164 # define AES_KEY_LENGTH 256 /* 128, 192, 256 */
165 # define AES_BLOCK_SIZE 16
167 enum encrypt_t
{ AES_ENCRYPT
, AES_DECRYPT
};
171 uint32_t rk
[4 * (AES_MAXNR
+ 1)];
179 aes_key_t
*aes_create_key(const char *key
, const size_t key_length
) {
180 aes_key_t
*_aes_key
= (aes_key_t
*) (calloc(1, sizeof(aes_key_t
)));
182 uint8_t rkey
[AES_KEY_LENGTH
/ 8];
183 uint8_t *rkey_end
= rkey
+ AES_KEY_LENGTH
/ 8;
184 const char *key_end
= key
+ key_length
;
186 memset(rkey
, 0, sizeof(rkey
)); /* Set initial key */
189 const char *sptr
= key
;
190 for (; sptr
< key_end
; ptr
++, sptr
++) {
191 if (ptr
== rkey_end
) {
192 ptr
= rkey
; /* Just loop over tmp_key until we used all key */
194 *ptr
^= (uint8_t) (*sptr
);
197 _aes_key
->decode_key
.nr
= rijndaelKeySetupDec(_aes_key
->decode_key
.rk
, rkey
, AES_KEY_LENGTH
);
198 _aes_key
->encode_key
.nr
= rijndaelKeySetupEnc(_aes_key
->encode_key
.rk
, rkey
, AES_KEY_LENGTH
);
204 aes_key_t
*aes_clone_key(aes_key_t
*_aes_key
) {
209 aes_key_t
*_aes_clone_key
= (aes_key_t
*) (calloc(1, sizeof(aes_key_t
)));
210 if (_aes_clone_key
) {
211 memcpy(_aes_clone_key
, _aes_key
, sizeof(aes_key_t
));
214 return _aes_clone_key
;
217 hashkit_string_st
*aes_encrypt(aes_key_t
*_aes_key
, const char *source
, size_t source_length
) {
222 size_t num_blocks
= source_length
/ AES_BLOCK_SIZE
;
224 hashkit_string_st
*destination
= hashkit_string_create(source_length
);
226 char *dest
= hashkit_string_c_str_mutable(destination
);
228 for (size_t x
= num_blocks
; x
> 0; x
--) /* Encode complete blocks */ {
229 rijndaelEncrypt(_aes_key
->encode_key
.rk
, _aes_key
->encode_key
.nr
, (const uint8_t *) (source
),
231 source
+= AES_BLOCK_SIZE
;
232 dest
+= AES_BLOCK_SIZE
;
235 uint8_t block
[AES_BLOCK_SIZE
];
236 char pad_len
= AES_BLOCK_SIZE
- (source_length
- AES_BLOCK_SIZE
* num_blocks
);
237 memcpy(block
, source
, 16 - pad_len
);
238 memset(block
+ AES_BLOCK_SIZE
- pad_len
, pad_len
, pad_len
);
239 rijndaelEncrypt(_aes_key
->encode_key
.rk
, _aes_key
->encode_key
.nr
, block
, (uint8_t *) (dest
));
240 hashkit_string_set_length(destination
, AES_BLOCK_SIZE
* (num_blocks
+ 1));
246 hashkit_string_st
*aes_decrypt(aes_key_t
*_aes_key
, const char *source
, size_t source_length
) {
251 size_t num_blocks
= source_length
/ AES_BLOCK_SIZE
;
252 if ((source_length
!= num_blocks
* AES_BLOCK_SIZE
) or num_blocks
== 0) {
256 hashkit_string_st
*destination
= hashkit_string_create(source_length
);
258 char *dest
= hashkit_string_c_str_mutable(destination
);
260 for (size_t x
= num_blocks
- 1; x
> 0; x
--) {
261 rijndaelDecrypt(_aes_key
->decode_key
.rk
, _aes_key
->decode_key
.nr
, (const uint8_t *) (source
),
263 source
+= AES_BLOCK_SIZE
;
264 dest
+= AES_BLOCK_SIZE
;
267 uint8_t block
[AES_BLOCK_SIZE
];
268 rijndaelDecrypt(_aes_key
->decode_key
.rk
, _aes_key
->decode_key
.nr
, (const uint8_t *) (source
),
270 /* Use last char in the block as size */
271 unsigned int pad_len
= (unsigned int) (unsigned char) (block
[AES_BLOCK_SIZE
- 1]);
272 if (pad_len
> AES_BLOCK_SIZE
) {
273 hashkit_string_free(destination
);
277 /* We could also check whole padding but we do not really need this */
279 memcpy(dest
, block
, AES_BLOCK_SIZE
- pad_len
);
280 hashkit_string_set_length(destination
, AES_BLOCK_SIZE
* num_blocks
- pad_len
);
286 void aes_free_key(aes_key_t
*key
) {