clang-format: no single-line case
[awesomized/libmemcached] / src / libhashkit / aes.cc
1 /*
2 +--------------------------------------------------------------------+
3 | libmemcached - 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 Michael Wallner <mike@php.net> |
13 +--------------------------------------------------------------------+
14 */
15
16 #include "libhashkit/common.h"
17
18 #include "libhashkit/rijndael.hpp"
19
20 #include <cstring>
21
22 #define AES_KEY_LENGTH 256 /* 128, 192, 256 */
23 #define AES_BLOCK_SIZE 16
24
25 enum encrypt_t { AES_ENCRYPT, AES_DECRYPT };
26
27 struct _key_t {
28 int nr;
29 uint32_t rk[4 * (AES_MAXNR + 1)];
30 };
31
32 struct aes_key_t {
33 _key_t encode_key;
34 _key_t decode_key;
35 };
36
37 aes_key_t *aes_create_key(const char *key, const size_t key_length) {
38 aes_key_t *_aes_key = (aes_key_t *) (calloc(1, sizeof(aes_key_t)));
39 if (_aes_key) {
40 uint8_t rkey[AES_KEY_LENGTH / 8];
41 uint8_t *rkey_end = rkey + AES_KEY_LENGTH / 8;
42 const char *key_end = key + key_length;
43
44 memset(rkey, 0, sizeof(rkey)); /* Set initial key */
45
46 uint8_t *ptr = rkey;
47 const char *sptr = key;
48 for (; sptr < key_end; ptr++, sptr++) {
49 if (ptr == rkey_end) {
50 ptr = rkey; /* Just loop over tmp_key until we used all key */
51 }
52 *ptr ^= (uint8_t)(*sptr);
53 }
54
55 _aes_key->decode_key.nr = rijndaelKeySetupDec(_aes_key->decode_key.rk, rkey, AES_KEY_LENGTH);
56 _aes_key->encode_key.nr = rijndaelKeySetupEnc(_aes_key->encode_key.rk, rkey, AES_KEY_LENGTH);
57 }
58
59 return _aes_key;
60 }
61
62 aes_key_t *aes_clone_key(aes_key_t *_aes_key) {
63 if (_aes_key == NULL) {
64 return NULL;
65 }
66
67 aes_key_t *_aes_clone_key = (aes_key_t *) (calloc(1, sizeof(aes_key_t)));
68 if (_aes_clone_key) {
69 memcpy(_aes_clone_key, _aes_key, sizeof(aes_key_t));
70 }
71
72 return _aes_clone_key;
73 }
74
75 hashkit_string_st *aes_encrypt(aes_key_t *_aes_key, const char *source, size_t source_length) {
76 if (_aes_key == NULL) {
77 return NULL;
78 }
79
80 size_t num_blocks = source_length / AES_BLOCK_SIZE;
81
82 hashkit_string_st *destination = hashkit_string_create(source_length);
83 if (destination) {
84 char *dest = hashkit_string_c_str_mutable(destination);
85
86 for (size_t x = num_blocks; x > 0; x--) /* Encode complete blocks */ {
87 rijndaelEncrypt(_aes_key->encode_key.rk, _aes_key->encode_key.nr, (const uint8_t *) (source),
88 (uint8_t *) (dest));
89 source += AES_BLOCK_SIZE;
90 dest += AES_BLOCK_SIZE;
91 }
92
93 uint8_t block[AES_BLOCK_SIZE];
94 char pad_len = AES_BLOCK_SIZE - (source_length - AES_BLOCK_SIZE * num_blocks);
95 memcpy(block, source, 16 - pad_len);
96 memset(block + AES_BLOCK_SIZE - pad_len, pad_len, pad_len);
97 rijndaelEncrypt(_aes_key->encode_key.rk, _aes_key->encode_key.nr, block, (uint8_t *) (dest));
98 hashkit_string_set_length(destination, AES_BLOCK_SIZE * (num_blocks + 1));
99 }
100
101 return destination;
102 }
103
104 hashkit_string_st *aes_decrypt(aes_key_t *_aes_key, const char *source, size_t source_length) {
105 if (_aes_key == NULL) {
106 return NULL;
107 }
108
109 size_t num_blocks = source_length / AES_BLOCK_SIZE;
110 if ((source_length != num_blocks * AES_BLOCK_SIZE) or num_blocks == 0) {
111 return NULL;
112 }
113
114 hashkit_string_st *destination = hashkit_string_create(source_length);
115 if (destination) {
116 char *dest = hashkit_string_c_str_mutable(destination);
117
118 for (size_t x = num_blocks - 1; x > 0; x--) {
119 rijndaelDecrypt(_aes_key->decode_key.rk, _aes_key->decode_key.nr, (const uint8_t *) (source),
120 (uint8_t *) (dest));
121 source += AES_BLOCK_SIZE;
122 dest += AES_BLOCK_SIZE;
123 }
124
125 uint8_t block[AES_BLOCK_SIZE];
126 rijndaelDecrypt(_aes_key->decode_key.rk, _aes_key->decode_key.nr, (const uint8_t *) (source),
127 block);
128 /* Use last char in the block as size */
129 unsigned int pad_len = (unsigned int) (unsigned char) (block[AES_BLOCK_SIZE - 1]);
130 if (pad_len > AES_BLOCK_SIZE) {
131 hashkit_string_free(destination);
132 return NULL;
133 }
134
135 /* We could also check whole padding but we do not really need this */
136
137 memcpy(dest, block, AES_BLOCK_SIZE - pad_len);
138 hashkit_string_set_length(destination, AES_BLOCK_SIZE * num_blocks - pad_len);
139 }
140
141 return destination;
142 }