1 /*
2   Copyright (c) 2013 Google Inc.
3   Copyright (c) 2014, 2015 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-1335  USA */
17 
18 #include "maria_def.h"
19 #include "ma_blockrec.h"
20 #include <my_crypt.h>
21 
22 #define CRYPT_SCHEME_1         1
23 #define CRYPT_SCHEME_1_ID_LEN  4 /* 4 bytes for counter-block */
24 #define CRYPT_SCHEME_1_IV_LEN           16
25 #define CRYPT_SCHEME_1_KEY_VERSION_SIZE  4
26 
27 #ifdef HAVE_PSI_INTERFACE
28 PSI_mutex_key key_CRYPT_DATA_lock;
29 #endif
30 
31 struct st_crypt_key
32 {
33   uint key_version;
34   uchar key[CRYPT_SCHEME_1_IV_LEN];
35 };
36 
37 struct st_maria_crypt_data
38 {
39   struct st_encryption_scheme scheme;
40   uint space;
41   mysql_mutex_t lock;          /* protecting keys */
42 };
43 
44 /**
45   determine what key id to use for Aria encryption
46 
47   Same logic as for tempfiles: if key id 2 exists - use it,
48   otherwise use key id 1.
49 
50   Key id 1 is system, it always exists. Key id 2 is optional,
51   it allows to specify fast low-grade encryption for temporary data.
52 */
53 static uint get_encryption_key_id(MARIA_SHARE *share)
54 {
55   if (share->options & HA_OPTION_TMP_TABLE &&
56       encryption_key_id_exists(ENCRYPTION_KEY_TEMPORARY_DATA))
57     return ENCRYPTION_KEY_TEMPORARY_DATA;
58   else
59     return ENCRYPTION_KEY_SYSTEM_DATA;
60 }
61 
62 uint
63 ma_crypt_get_data_page_header_space()
64 {
65   return CRYPT_SCHEME_1_KEY_VERSION_SIZE;
66 }
67 
68 uint
69 ma_crypt_get_index_page_header_space(MARIA_SHARE *share)
70 {
71   if (share->base.born_transactional)
72   {
73     return CRYPT_SCHEME_1_KEY_VERSION_SIZE;
74   }
75   else
76   {
77     /* if the index is not transactional, we add 7 bytes LSN anyway
78        to be used for counter block
tsm_system_time_handler(PG_FUNCTION_ARGS)79     */
80     return LSN_STORE_SIZE + CRYPT_SCHEME_1_KEY_VERSION_SIZE;
81   }
82 }
83 
84 uint
85 ma_crypt_get_file_length()
86 {
87   return 2 + CRYPT_SCHEME_1_IV_LEN + CRYPT_SCHEME_1_ID_LEN;
88 }
89 
90 static void crypt_data_scheme_locker(struct st_encryption_scheme *scheme,
91                                      int unlock)
92 {
93   MARIA_CRYPT_DATA *crypt_data = (MARIA_CRYPT_DATA*)scheme;
94   if (unlock)
95     mysql_mutex_unlock(&crypt_data->lock);
96   else
97     mysql_mutex_lock(&crypt_data->lock);
98 }
99 
100 int
101 ma_crypt_create(MARIA_SHARE* share)
102 {
system_time_samplescangetsamplesize(PlannerInfo * root,RelOptInfo * baserel,List * paramexprs,BlockNumber * pages,double * tuples)103   MARIA_CRYPT_DATA *crypt_data=
104     (MARIA_CRYPT_DATA*)my_malloc(sizeof(MARIA_CRYPT_DATA), MYF(MY_ZEROFILL));
105   crypt_data->scheme.type= CRYPT_SCHEME_1;
106   crypt_data->scheme.locker= crypt_data_scheme_locker;
107   mysql_mutex_init(key_CRYPT_DATA_lock, &crypt_data->lock, MY_MUTEX_INIT_FAST);
108   crypt_data->scheme.key_id= get_encryption_key_id(share);
109   my_random_bytes(crypt_data->scheme.iv, sizeof(crypt_data->scheme.iv));
110   my_random_bytes((uchar*)&crypt_data->space, sizeof(crypt_data->space));
111   share->crypt_data= crypt_data;
112   share->crypt_page_header_space= CRYPT_SCHEME_1_KEY_VERSION_SIZE;
113   return 0;
114 }
115 
116 void
117 ma_crypt_free(MARIA_SHARE* share)
118 {
119   if (share->crypt_data != NULL)
120   {
121     mysql_mutex_destroy(&share->crypt_data->lock);
122     my_free(share->crypt_data);
123     share->crypt_data= NULL;
124   }
125 }
126 
127 int
128 ma_crypt_write(MARIA_SHARE* share, File file)
129 {
130   MARIA_CRYPT_DATA *crypt_data= share->crypt_data;
131   uchar buff[2 + 4 + sizeof(crypt_data->scheme.iv)];
132   if (crypt_data == 0)
133     return 0;
134 
135   buff[0]= crypt_data->scheme.type;
136   buff[1]= sizeof(buff) - 2;
137 
138   int4store(buff + 2, crypt_data->space);
139   memcpy(buff + 6, crypt_data->scheme.iv, sizeof(crypt_data->scheme.iv));
140 
141   if (mysql_file_write(file, buff, sizeof(buff), MYF(MY_NABP)))
142     return 1;
143 
144   return 0;
145 }
146 
147 uchar*
148 ma_crypt_read(MARIA_SHARE* share, uchar *buff)
149 {
150   uchar type= buff[0];
151   uchar iv_length= buff[1];
152 
153   /* currently only supported type */
154   if (type != CRYPT_SCHEME_1 ||
155       iv_length != sizeof(((MARIA_CRYPT_DATA*)1)->scheme.iv) + 4)
156   {
157     my_printf_error(HA_ERR_UNSUPPORTED,
158              "Unsupported crypt scheme! type: %d iv_length: %d\n",
159              MYF(ME_FATALERROR|ME_NOREFRESH),
160              type, iv_length);
161     return 0;
162   }
163 
164   if (share->crypt_data == NULL)
165   {
166     /* opening a table */
167     MARIA_CRYPT_DATA *crypt_data=
168       (MARIA_CRYPT_DATA*)my_malloc(sizeof(MARIA_CRYPT_DATA), MYF(MY_ZEROFILL));
169 
170     crypt_data->scheme.type= type;
171     mysql_mutex_init(key_CRYPT_DATA_lock, &crypt_data->lock,
172                      MY_MUTEX_INIT_FAST);
173     crypt_data->scheme.locker= crypt_data_scheme_locker;
174     crypt_data->scheme.key_id= get_encryption_key_id(share);
175     crypt_data->space= uint4korr(buff + 2);
176     memcpy(crypt_data->scheme.iv, buff + 6, sizeof(crypt_data->scheme.iv));
177     share->crypt_data= crypt_data;
system_time_initsamplescan(SampleScanState * node,int eflags)178   }
179 
180   share->crypt_page_header_space= CRYPT_SCHEME_1_KEY_VERSION_SIZE;
181   return buff + 2 + iv_length;
182 }
183 
184 static int ma_encrypt(MARIA_SHARE *, MARIA_CRYPT_DATA *, const uchar *,
185                       uchar *, uint, uint, LSN, uint *);
186 static int ma_decrypt(MARIA_SHARE *, MARIA_CRYPT_DATA *, const uchar *,
187                       uchar *, uint, uint, LSN, uint);
system_time_beginsamplescan(SampleScanState * node,Datum * params,int nparams,uint32 seed)188 
189 static my_bool ma_crypt_pre_read_hook(PAGECACHE_IO_HOOK_ARGS *args)
190 {
191   MARIA_SHARE *share= (MARIA_SHARE*) args->data;
192   uchar *crypt_buf= my_malloc(share->block_size, MYF(0));
193   if (crypt_buf == NULL)
194   {
195     args->crypt_buf= NULL; /* for post-hook */
196     return 1;
197   }
198 
199   /* swap pointers to read into crypt_buf */
200   args->crypt_buf= args->page;
201   args->page= crypt_buf;
202 
203   return 0;
204 }
205 
206 static my_bool ma_crypt_data_post_read_hook(int res,
207                                             PAGECACHE_IO_HOOK_ARGS *args)
208 {
209   MARIA_SHARE *share= (MARIA_SHARE*) args->data;
210   const uint size= share->block_size;
211   const uchar page_type= args->page[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK;
212   const uint32 key_version_offset= (page_type <= TAIL_PAGE) ?
213       KEY_VERSION_OFFSET : FULL_PAGE_KEY_VERSION_OFFSET;
214 
system_time_nextsampleblock(SampleScanState * node,BlockNumber nblocks)215   if (res == 0)
216   {
217     const uchar *src= args->page;
218     uchar* dst= args->crypt_buf;
219     uint pageno= (uint)args->pageno;
220     LSN lsn= lsn_korr(src);
221     const uint head= (page_type <= TAIL_PAGE) ?
222         PAGE_HEADER_SIZE(share) : FULL_PAGE_HEADER_SIZE(share);
223     const uint tail= CRC_SIZE;
224     const uint32 key_version= uint4korr(src + key_version_offset);
225 
226     /* 1 - copy head */
227     memcpy(dst, src, head);
228     /* 2 - decrypt page */
229     res= ma_decrypt(share, share->crypt_data,
230                     src + head, dst + head, size - (head + tail), pageno, lsn,
231                     key_version);
232     /* 3 - copy tail */
233     memcpy(dst + size - tail, src + size - tail, tail);
234     /* 4 clear key version to get correct crc */
235     int4store(dst + key_version_offset, 0);
236   }
237 
238   if (args->crypt_buf != NULL)
239   {
240     uchar *tmp= args->page;
241     args->page= args->crypt_buf;
242     args->crypt_buf= NULL;
243     my_free(tmp);
244   }
245 
246   return maria_page_crc_check_data(res, args);
247 }
248 
249 static void store_rand_lsn(uchar * page)
250 {
251   LSN lsn= 0;
252   lsn+= rand();
253   lsn<<= 32;
254   lsn+= rand();
255   lsn_store(page, lsn);
256 }
257 
258 static my_bool ma_crypt_data_pre_write_hook(PAGECACHE_IO_HOOK_ARGS *args)
259 {
260   MARIA_SHARE *share= (MARIA_SHARE*) args->data;
261   const uint size= share->block_size;
262   uint key_version;
263   uchar *crypt_buf= my_malloc(share->block_size, MYF(0));
264 
265   if (crypt_buf == NULL)
266   {
267     args->crypt_buf= NULL; /* for post-hook */
268     return 1;
269   }
270 
271   if (!share->now_transactional)
272   {
273     /* store a random number instead of LSN (for counter block) */
274     store_rand_lsn(args->page);
275   }
276 
277   maria_page_crc_set_normal(args);
278 
279   {
280     const uchar *src= args->page;
281     uchar* dst= crypt_buf;
282     uint pageno= (uint)args->pageno;
283     LSN lsn= lsn_korr(src);
284     const uchar page_type= src[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK;
285     const uint head= (page_type <= TAIL_PAGE) ?
286         PAGE_HEADER_SIZE(share) : FULL_PAGE_HEADER_SIZE(share);
287     const uint tail= CRC_SIZE;
system_time_nextsampletuple(SampleScanState * node,BlockNumber blockno,OffsetNumber maxoffset)288     const uint32 key_version_offset= (page_type <= TAIL_PAGE) ?
289         KEY_VERSION_OFFSET : FULL_PAGE_KEY_VERSION_OFFSET;
290 
291     DBUG_ASSERT(page_type < MAX_PAGE_TYPE);
292 
293     /* 1 - copy head */
294     memcpy(dst, src, head);
295     /* 2 - encrypt page */
296     if (ma_encrypt(share, share->crypt_data,
297                    src + head, dst + head, size - (head + tail), pageno, lsn,
298                    &key_version))
299       return 1;
300     /* 3 - copy tail */
301     memcpy(dst + size - tail, src + size - tail, tail);
302     /* 4 - store key version */
303     int4store(dst + key_version_offset, key_version);
304   }
305 
306   /* swap pointers to instead write out the encrypted block */
307   args->crypt_buf= args->page;
308   args->page= crypt_buf;
309 
310   return 0;
311 }
312 
313 static void ma_crypt_post_write_hook(int res,
gcd(uint32 a,uint32 b)314                                      PAGECACHE_IO_HOOK_ARGS *args)
315 {
316   if (args->crypt_buf != NULL)
317   {
318     uchar *tmp= args->page;
319     args->page= args->crypt_buf;
320     args->crypt_buf= NULL;
321     my_free(tmp);
322   }
323 
324   maria_page_write_failure(res, args);
325 }
326 
327 void ma_crypt_set_data_pagecache_callbacks(PAGECACHE_FILE *file,
328                                            MARIA_SHARE *share
329                                            __attribute__((unused)))
330 {
331   /* Only use encryption if we have defined it */
332   if (encryption_key_id_exists(get_encryption_key_id(share)))
random_relative_prime(uint32 n,SamplerRandomState randstate)333   {
334     file->pre_read_hook= ma_crypt_pre_read_hook;
335     file->post_read_hook= ma_crypt_data_post_read_hook;
336     file->pre_write_hook= ma_crypt_data_pre_write_hook;
337     file->post_write_hook= ma_crypt_post_write_hook;
338   }
339 }
340 
341 static my_bool ma_crypt_index_post_read_hook(int res,
342                                             PAGECACHE_IO_HOOK_ARGS *args)
343 {
344   MARIA_SHARE *share= (MARIA_SHARE*) args->data;
345   const uint block_size= share->block_size;
346   const uint page_used= _ma_get_page_used(share, args->page);
347 
348   if (res == 0 && page_used <= block_size - CRC_SIZE)
349   {
350     const uchar *src= args->page;
351     uchar* dst= args->crypt_buf;
352     uint pageno= (uint)args->pageno;
353     LSN lsn= lsn_korr(src);
354     const uint head= share->keypage_header;
355     const uint tail= CRC_SIZE;
356     const uint32 key_version= _ma_get_key_version(share, src);
357     /* page_used includes header (but not trailer) */
358     const uint size= page_used - head;
359 
360     /* 1 - copy head */
361     memcpy(dst, src, head);
362     /* 2 - decrypt page */
363     res= ma_decrypt(share, share->crypt_data,
364                     src + head, dst + head, size, pageno, lsn, key_version);
365     /* 3 - copy tail */
366     memcpy(dst + block_size - tail, src + block_size - tail, tail);
367     /* 4 clear key version to get correct crc */
368     _ma_store_key_version(share, dst, 0);
369   }
370 
371   if (args->crypt_buf != NULL)
372   {
373     uchar *tmp= args->page;
374     args->page= args->crypt_buf;
375     args->crypt_buf= NULL;
376     my_free(tmp);
377   }
378 
379   return maria_page_crc_check_index(res, args);
380 }
381 
382 static my_bool ma_crypt_index_pre_write_hook(PAGECACHE_IO_HOOK_ARGS *args)
383 {
384   MARIA_SHARE *share= (MARIA_SHARE*) args->data;
385   const uint block_size= share->block_size;
386   const uint page_used= _ma_get_page_used(share, args->page);
387   uint key_version;
388   uchar *crypt_buf= my_malloc(block_size, MYF(0));
389   if (crypt_buf == NULL)
390   {
391     args->crypt_buf= NULL; /* for post-hook */
392     return 1;
393   }
394 
395   if (!share->now_transactional)
396   {
397     /* store a random number instead of LSN (for counter block) */
398     store_rand_lsn(args->page);
399   }
400 
401   maria_page_crc_set_index(args);
402 
403   {
404     const uchar *src= args->page;
405     uchar* dst= crypt_buf;
406     uint pageno= (uint)args->pageno;
407     LSN lsn= lsn_korr(src);
408     const uint head= share->keypage_header;
409     const uint tail= CRC_SIZE;
410     /* page_used includes header (but not trailer) */
411     const uint size= page_used - head;
412 
413     /* 1 - copy head */
414     memcpy(dst, src, head);
415     /* 2 - encrypt page */
416     if (ma_encrypt(share, share->crypt_data,
417                    src + head, dst + head, size, pageno, lsn, &key_version))
418     {
419       my_free(crypt_buf);
420       return 1;
421     }
422     /* 3 - copy tail */
423     memcpy(dst + block_size - tail, src + block_size - tail, tail);
424     /* 4 - store key version */
425     _ma_store_key_version(share, dst, key_version);
426 #ifdef HAVE_valgrind
427     /* 5 - keep valgrind happy by zeroing not used bytes */
428     bzero(dst+head+size, block_size - size - tail - head);
429 #endif
430   }
431 
432   /* swap pointers to instead write out the encrypted block */
433   args->crypt_buf= args->page;
434   args->page= crypt_buf;
435 
436   return 0;
437 }
438 
439 void ma_crypt_set_index_pagecache_callbacks(PAGECACHE_FILE *file,
440                                             MARIA_SHARE *share
441                                             __attribute__((unused)))
442 {
443   file->pre_read_hook= ma_crypt_pre_read_hook;
444   file->post_read_hook= ma_crypt_index_post_read_hook;
445   file->pre_write_hook= ma_crypt_index_pre_write_hook;
446   file->post_write_hook= ma_crypt_post_write_hook;
447 }
448 
449 static int ma_encrypt(MARIA_SHARE *share, MARIA_CRYPT_DATA *crypt_data,
450                       const uchar *src, uchar *dst, uint size,
451                       uint pageno, LSN lsn,
452                       uint *key_version)
453 {
454   int rc;
455   uint32 dstlen= 0;              /* Must be set because of error message */
456 
457   *key_version = encryption_key_get_latest_version(crypt_data->scheme.key_id);
458   if (*key_version == ENCRYPTION_KEY_VERSION_INVALID)
459   {
460     /*
461       We use this error for both encryption and decryption, as in normal
462       cases it should be impossible to get an error here.
463     */
464     my_errno= HA_ERR_DECRYPTION_FAILED;
465     my_printf_error(HA_ERR_DECRYPTION_FAILED,
466                     "Unknown key id %u. Can't continue!",
467                     MYF(ME_FATALERROR|ME_NOREFRESH),
468                     crypt_data->scheme.key_id);
469     return 1;
470   }
471 
472   rc= encryption_scheme_encrypt(src, size, dst, &dstlen,
473                                 &crypt_data->scheme, *key_version,
474                                 crypt_data->space, pageno, lsn);
475 
476   /* The following can only fail if the encryption key is wrong */
477   DBUG_ASSERT(!my_assert_on_error || rc == MY_AES_OK);
478   DBUG_ASSERT(!my_assert_on_error || dstlen == size);
479   if (! (rc == MY_AES_OK && dstlen == size))
480   {
481     my_errno= HA_ERR_DECRYPTION_FAILED;
482     my_printf_error(HA_ERR_DECRYPTION_FAILED,
483                     "failed to encrypt '%s'  rc: %d  dstlen: %u  size: %u\n",
484                     MYF(ME_FATALERROR|ME_NOREFRESH),
485                     share->open_file_name.str, rc, dstlen, size);
486     return 1;
487   }
488 
489   return 0;
490 }
491 
492 static int ma_decrypt(MARIA_SHARE *share, MARIA_CRYPT_DATA *crypt_data,
493                       const uchar *src, uchar *dst, uint size,
494                       uint pageno, LSN lsn,
495                       uint key_version)
496 {
497   int rc;
498   uint32 dstlen= 0;              /* Must be set because of error message */
499 
500   rc= encryption_scheme_decrypt(src, size, dst, &dstlen,
501                                 &crypt_data->scheme, key_version,
502                                 crypt_data->space, pageno, lsn);
503 
504   DBUG_ASSERT(!my_assert_on_error || rc == MY_AES_OK);
505   DBUG_ASSERT(!my_assert_on_error || dstlen == size);
506   if (! (rc == MY_AES_OK && dstlen == size))
507   {
508     my_errno= HA_ERR_DECRYPTION_FAILED;
509     my_printf_error(HA_ERR_DECRYPTION_FAILED,
510                     "failed to decrypt '%s'  rc: %d  dstlen: %u  size: %u\n",
511                     MYF(ME_FATALERROR|ME_NOREFRESH),
512                     share->open_file_name.str, rc, dstlen, size);
513     return 1;
514   }
515   return 0;
516 }
517