1/*
2 Copyright (c) 2014 Google Inc.
3 Copyright (c) 2014, 2017 MariaDB Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
17
18#include <my_global.h>
19#include <string.h>
20
21#ifdef HAVE_YASSL
22#include "yassl.cc"
23#else
24#include <openssl/evp.h>
25#include <openssl/aes.h>
26#include <openssl/err.h>
27#include <openssl/rand.h>
28#endif
29
30#include <my_crypt.h>
31#include <ssl_compat.h>
32
33class MyCTX
34{
35public:
36 char ctx_buf[EVP_CIPHER_CTX_SIZE];
37 EVP_CIPHER_CTX *ctx;
38
39 MyCTX()
40 {
41 ctx= (EVP_CIPHER_CTX *)ctx_buf;
42 EVP_CIPHER_CTX_init(ctx);
43 }
44 virtual ~MyCTX()
45 {
46 EVP_CIPHER_CTX_reset(ctx);
47 ERR_remove_state(0);
48 }
49
50 virtual int init(const EVP_CIPHER *cipher, int encrypt, const uchar *key,
51 uint klen, const uchar *iv, uint ivlen)
52 {
53 compile_time_assert(MY_AES_CTX_SIZE >= sizeof(MyCTX));
54 if (unlikely(!cipher))
55 return MY_AES_BAD_KEYSIZE;
56
57 if (!EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, encrypt))
58 return MY_AES_OPENSSL_ERROR;
59
60 DBUG_ASSERT(EVP_CIPHER_CTX_key_length(ctx) == (int)klen);
61 DBUG_ASSERT(EVP_CIPHER_CTX_iv_length(ctx) <= (int)ivlen);
62
63 return MY_AES_OK;
64 }
65 virtual int update(const uchar *src, uint slen, uchar *dst, uint *dlen)
66 {
67 if (!EVP_CipherUpdate(ctx, dst, (int*)dlen, src, slen))
68 return MY_AES_OPENSSL_ERROR;
69 return MY_AES_OK;
70 }
71 virtual int finish(uchar *dst, uint *dlen)
72 {
73 if (!EVP_CipherFinal_ex(ctx, dst, (int*)dlen))
74 return MY_AES_BAD_DATA;
75 return MY_AES_OK;
76 }
77};
78
79class MyCTX_nopad : public MyCTX
80{
81public:
82 const uchar *key;
83 uint klen, buf_len;
84 uchar oiv[MY_AES_BLOCK_SIZE];
85
86 MyCTX_nopad() : MyCTX() { }
87 ~MyCTX_nopad() { }
88
89 int init(const EVP_CIPHER *cipher, int encrypt, const uchar *key, uint klen,
90 const uchar *iv, uint ivlen)
91 {
92 compile_time_assert(MY_AES_CTX_SIZE >= sizeof(MyCTX_nopad));
93 this->key= key;
94 this->klen= klen;
95 this->buf_len= 0;
96 memcpy(oiv, iv, ivlen);
97 DBUG_ASSERT(ivlen == 0 || ivlen == sizeof(oiv));
98
99 int res= MyCTX::init(cipher, encrypt, key, klen, iv, ivlen);
100
101 EVP_CIPHER_CTX_set_padding(ctx, 0);
102 return res;
103 }
104
105 int update(const uchar *src, uint slen, uchar *dst, uint *dlen)
106 {
107 buf_len+= slen;
108 return MyCTX::update(src, slen, dst, dlen);
109 }
110
111 int finish(uchar *dst, uint *dlen)
112 {
113 buf_len %= MY_AES_BLOCK_SIZE;
114 if (buf_len)
115 {
116 uchar *buf= EVP_CIPHER_CTX_buf_noconst(ctx);
117 /*
118 Not much we can do, block ciphers cannot encrypt data that aren't
119 a multiple of the block length. At least not without padding.
120 Let's do something CTR-like for the last partial block.
121
122 NOTE this assumes that there are only buf_len bytes in the buf.
123 If OpenSSL will change that, we'll need to change the implementation
124 of this class too.
125 */
126 uchar mask[MY_AES_BLOCK_SIZE];
127 uint mlen;
128
129 my_aes_crypt(MY_AES_ECB, ENCRYPTION_FLAG_ENCRYPT | ENCRYPTION_FLAG_NOPAD,
130 oiv, sizeof(mask), mask, &mlen, key, klen, 0, 0);
131 DBUG_ASSERT(mlen == sizeof(mask));
132
133 for (uint i=0; i < buf_len; i++)
134 dst[i]= buf[i] ^ mask[i];
135 }
136 *dlen= buf_len;
137 return MY_AES_OK;
138 }
139};
140
141#define make_aes_dispatcher(mode) \
142 static inline const EVP_CIPHER *aes_ ## mode(uint klen) \
143 { \
144 switch (klen) { \
145 case 16: return EVP_aes_128_ ## mode(); \
146 case 24: return EVP_aes_192_ ## mode(); \
147 case 32: return EVP_aes_256_ ## mode(); \
148 default: return 0; \
149 } \
150 }
151
152make_aes_dispatcher(ecb)
153make_aes_dispatcher(cbc)
154#ifdef HAVE_EncryptAes128Ctr
155make_aes_dispatcher(ctr)
156#endif /* HAVE_EncryptAes128Ctr */
157#ifdef HAVE_EncryptAes128Gcm
158make_aes_dispatcher(gcm)
159
160/*
161 special implementation for GCM; to fit OpenSSL AES-GCM into the
162 existing my_aes_* API it does the following:
163 - IV tail (over 12 bytes) goes to AAD
164 - the tag is appended to the ciphertext
165*/
166
167class MyCTX_gcm : public MyCTX
168{
169public:
170 const uchar *aad;
171 int aadlen;
172 MyCTX_gcm() : MyCTX() { }
173 ~MyCTX_gcm() { }
174
175 int init(const EVP_CIPHER *cipher, int encrypt, const uchar *key, uint klen,
176 const uchar *iv, uint ivlen)
177 {
178 compile_time_assert(MY_AES_CTX_SIZE >= sizeof(MyCTX_gcm));
179 int res= MyCTX::init(cipher, encrypt, key, klen, iv, ivlen);
180 int real_ivlen= EVP_CIPHER_CTX_iv_length(ctx);
181 aad= iv + real_ivlen;
182 aadlen= ivlen - real_ivlen;
183 return res;
184 }
185
186 int update(const uchar *src, uint slen, uchar *dst, uint *dlen)
187 {
188 /*
189 note that this GCM class cannot do streaming decryption, because
190 it needs the tag (which is located at the end of encrypted data)
191 before decrypting the data. it can encrypt data piecewise, like, first
192 half, then the second half, but it must decrypt all at once
193 */
194 if (!EVP_CIPHER_CTX_encrypting(ctx))
195 {
196 /* encrypted string must contain authenticaton tag (see MDEV-11174) */
197 if (slen < MY_AES_BLOCK_SIZE)
198 return MY_AES_BAD_DATA;
199 slen-= MY_AES_BLOCK_SIZE;
200 if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, MY_AES_BLOCK_SIZE,
201 (void*)(src + slen)))
202 return MY_AES_OPENSSL_ERROR;
203 }
204 int unused;
205 if (aadlen && !EVP_CipherUpdate(ctx, NULL, &unused, aad, aadlen))
206 return MY_AES_OPENSSL_ERROR;
207 aadlen= 0;
208 return MyCTX::update(src, slen, dst, dlen);
209 }
210
211 int finish(uchar *dst, uint *dlen)
212 {
213 int fin;
214 if (!EVP_CipherFinal_ex(ctx, dst, &fin))
215 return MY_AES_BAD_DATA;
216 DBUG_ASSERT(fin == 0);
217
218 if (EVP_CIPHER_CTX_encrypting(ctx))
219 {
220 if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, MY_AES_BLOCK_SIZE, dst))
221 return MY_AES_OPENSSL_ERROR;
222 *dlen= MY_AES_BLOCK_SIZE;
223 }
224 else
225 *dlen= 0;
226 return MY_AES_OK;
227 }
228};
229
230#endif
231
232const EVP_CIPHER *(*ciphers[])(uint)= {
233 aes_ecb, aes_cbc
234#ifdef HAVE_EncryptAes128Ctr
235 , aes_ctr
236#ifdef HAVE_EncryptAes128Gcm
237 , aes_gcm
238#endif
239#endif
240};
241
242extern "C" {
243
244int my_aes_crypt_init(void *ctx, enum my_aes_mode mode, int flags,
245 const unsigned char* key, unsigned int klen,
246 const unsigned char* iv, unsigned int ivlen)
247{
248#ifdef HAVE_EncryptAes128Ctr
249#ifdef HAVE_EncryptAes128Gcm
250 if (mode == MY_AES_GCM)
251 if (flags & ENCRYPTION_FLAG_NOPAD)
252 return MY_AES_OPENSSL_ERROR;
253 else
254 new (ctx) MyCTX_gcm();
255 else
256#endif
257 if (mode == MY_AES_CTR)
258 new (ctx) MyCTX();
259 else
260#endif
261 if (flags & ENCRYPTION_FLAG_NOPAD)
262 new (ctx) MyCTX_nopad();
263 else
264 new (ctx) MyCTX();
265 return ((MyCTX*)ctx)->init(ciphers[mode](klen), flags & 1,
266 key, klen, iv, ivlen);
267}
268
269int my_aes_crypt_update(void *ctx, const uchar *src, uint slen,
270 uchar *dst, uint *dlen)
271{
272 return ((MyCTX*)ctx)->update(src, slen, dst, dlen);
273}
274
275int my_aes_crypt_finish(void *ctx, uchar *dst, uint *dlen)
276{
277 int res= ((MyCTX*)ctx)->finish(dst, dlen);
278 ((MyCTX*)ctx)->~MyCTX();
279 return res;
280}
281
282int my_aes_crypt(enum my_aes_mode mode, int flags,
283 const uchar *src, uint slen, uchar *dst, uint *dlen,
284 const uchar *key, uint klen, const uchar *iv, uint ivlen)
285{
286 void *ctx= alloca(MY_AES_CTX_SIZE);
287 int res1, res2;
288 uint d1= 0, d2;
289 if ((res1= my_aes_crypt_init(ctx, mode, flags, key, klen, iv, ivlen)))
290 return res1;
291 res1= my_aes_crypt_update(ctx, src, slen, dst, &d1);
292 res2= my_aes_crypt_finish(ctx, dst + d1, &d2);
293 if (res1 || res2)
294 ERR_remove_state(0); /* in case of failure clear error queue */
295 else
296 *dlen= d1 + d2;
297 return res1 ? res1 : res2;
298}
299
300
301/*
302 calculate the length of the cyphertext from the length of the plaintext
303 for different AES encryption modes with padding enabled.
304 Without padding (ENCRYPTION_FLAG_NOPAD) cyphertext has the same length
305 as the plaintext
306*/
307unsigned int my_aes_get_size(enum my_aes_mode mode __attribute__((unused)), unsigned int source_length)
308{
309#ifdef HAVE_EncryptAes128Ctr
310 if (mode == MY_AES_CTR)
311 return source_length;
312#ifdef HAVE_EncryptAes128Gcm
313 if (mode == MY_AES_GCM)
314 return source_length + MY_AES_BLOCK_SIZE;
315#endif
316#endif
317 return (source_length / MY_AES_BLOCK_SIZE + 1) * MY_AES_BLOCK_SIZE;
318}
319
320
321unsigned int my_aes_ctx_size(enum my_aes_mode)
322{
323 return MY_AES_CTX_SIZE;
324}
325
326int my_random_bytes(uchar *buf, int num)
327{
328 if (RAND_bytes(buf, num) != 1)
329 return MY_AES_OPENSSL_ERROR;
330 return MY_AES_OK;
331}
332
333}
334