1/* Copyright (c) 2002, 2012, eperi GmbH.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#include <my_global.h>
17#include <typelib.h>
18#include "parser.h"
19#include <mysql/plugin_encryption.h>
20#include <string.h>
21
22static char* filename;
23static char* filekey;
24static unsigned long encryption_algorithm;
25
26static const char *encryption_algorithm_names[]=
27{
28 "aes_cbc",
29#ifdef HAVE_EncryptAes128Ctr
30 "aes_ctr",
31#endif
32 0
33};
34
35static TYPELIB encryption_algorithm_typelib=
36{
37 array_elements(encryption_algorithm_names)-1,"",
38 encryption_algorithm_names, NULL
39};
40
41
42static MYSQL_SYSVAR_STR(filename, filename,
43 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
44 "Path and name of the key file.",
45 NULL, NULL, "");
46
47static MYSQL_SYSVAR_STR(filekey, filekey,
48 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
49 "Key to encrypt / decrypt the keyfile.",
50 NULL, NULL, "");
51
52#ifdef HAVE_EncryptAes128Ctr
53#define recommendation ", aes_ctr is the recommended one"
54#else
55#define recommendation ""
56#endif
57static MYSQL_SYSVAR_ENUM(encryption_algorithm, encryption_algorithm,
58 PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
59 "Encryption algorithm to use" recommendation ".",
60 NULL, NULL, 0, &encryption_algorithm_typelib);
61
62static struct st_mysql_sys_var* settings[] = {
63 MYSQL_SYSVAR(filename),
64 MYSQL_SYSVAR(filekey),
65 MYSQL_SYSVAR(encryption_algorithm),
66 NULL
67};
68
69std::map<unsigned int,keyentry> keys;
70
71static keyentry *get_key(unsigned int key_id)
72{
73 keyentry &key= keys[key_id];
74 if (key.id == 0)
75 return 0;
76 return &key;
77}
78
79/* the version is always the same, no automatic key rotation */
80static unsigned int get_latest_version(uint key_id)
81{
82 return get_key(key_id) ? 1 : ENCRYPTION_KEY_VERSION_INVALID;
83}
84
85static unsigned int get_key_from_key_file(unsigned int key_id,
86 unsigned int key_version, unsigned char* dstbuf, unsigned *buflen)
87{
88 if (key_version != 1)
89 return ENCRYPTION_KEY_VERSION_INVALID;
90
91 keyentry* entry = get_key(key_id);
92
93 if (entry == NULL)
94 return ENCRYPTION_KEY_VERSION_INVALID;
95
96 if (*buflen < entry->length)
97 {
98 *buflen= entry->length;
99 return ENCRYPTION_KEY_BUFFER_TOO_SMALL;
100 }
101
102 *buflen= entry->length;
103 if (dstbuf)
104 memcpy(dstbuf, entry->key, entry->length);
105
106 return 0;
107}
108
109// let's simplify the condition below
110#ifndef HAVE_EncryptAes128Gcm
111#define MY_AES_GCM MY_AES_CTR
112#ifndef HAVE_EncryptAes128Ctr
113#define MY_AES_CTR MY_AES_CBC
114#endif
115#endif
116
117static inline enum my_aes_mode mode(int flags)
118{
119 /*
120 If encryption_algorithm is AES_CTR then
121 if no-padding, use AES_CTR
122 else use AES_GCM (like CTR but appends a "checksum" block)
123 else
124 use AES_CBC
125 */
126 if (encryption_algorithm)
127 if (flags & ENCRYPTION_FLAG_NOPAD)
128 return MY_AES_CTR;
129 else
130 return MY_AES_GCM;
131 else
132 return MY_AES_CBC;
133}
134
135static int ctx_init(void *ctx, const unsigned char* key, unsigned int klen,
136 const unsigned char* iv, unsigned int ivlen, int flags,
137 unsigned int key_id, unsigned int key_version)
138{
139 return my_aes_crypt_init(ctx, mode(flags), flags, key, klen, iv, ivlen);
140}
141
142static int ctx_update(void *ctx, const unsigned char *src, unsigned int slen,
143 unsigned char *dst, unsigned int *dlen)
144{
145 return my_aes_crypt_update(ctx, src, slen, dst, dlen);
146}
147
148
149static int ctx_finish(void *ctx, unsigned char *dst, unsigned int *dlen)
150{
151 return my_aes_crypt_finish(ctx, dst, dlen);
152}
153
154static unsigned int get_length(unsigned int slen, unsigned int key_id,
155 unsigned int key_version)
156{
157 return my_aes_get_size(mode(0), slen);
158}
159
160static uint ctx_size(uint, uint)
161{
162 return my_aes_ctx_size(mode(0));
163}
164
165struct st_mariadb_encryption file_key_management_plugin= {
166 MariaDB_ENCRYPTION_INTERFACE_VERSION,
167 get_latest_version,
168 get_key_from_key_file,
169 ctx_size,
170 ctx_init,
171 ctx_update,
172 ctx_finish,
173 get_length
174};
175
176static int file_key_management_plugin_init(void *p)
177{
178 Parser parser(filename, filekey);
179 return parser.parse(&keys);
180}
181
182static int file_key_management_plugin_deinit(void *p)
183{
184 keys.clear();
185 return 0;
186}
187
188/*
189 Plugin library descriptor
190*/
191maria_declare_plugin(file_key_management)
192{
193 MariaDB_ENCRYPTION_PLUGIN,
194 &file_key_management_plugin,
195 "file_key_management",
196 "Denis Endro eperi GmbH",
197 "File-based key management plugin",
198 PLUGIN_LICENSE_GPL,
199 file_key_management_plugin_init,
200 file_key_management_plugin_deinit,
201 0x0100 /* 1.0 */,
202 NULL, /* status variables */
203 settings,
204 "1.0",
205 MariaDB_PLUGIN_MATURITY_STABLE
206}
207maria_declare_plugin_end;
208