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