1 /***************************************************************************** 2 Copyright (C) 2013, 2015, Google Inc. All Rights Reserved. 3 Copyright (c) 2015, 2018, MariaDB Corporation. 4 5 This program is free software; you can redistribute it and/or modify it under 6 the terms of the GNU General Public License as published by the Free Software 7 Foundation; version 2 of the License. 8 9 This program is distributed in the hope that it will be useful, but WITHOUT 10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 this program; if not, write to the Free Software Foundation, Inc., 15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA 16 17 *****************************************************************************/ 18 19 /**************************************************//** 20 @file include/fil0crypt.h 21 The low-level file system encryption support functions 22 23 Created 04/01/2015 Jan Lindström 24 *******************************************************/ 25 26 #ifndef fil0crypt_h 27 #define fil0crypt_h 28 29 #ifndef UNIV_INNOCHECKSUM 30 #include "os0event.h" 31 #include "my_crypt.h" 32 #include "fil0fil.h" 33 #endif /*! UNIV_INNOCHECKSUM */ 34 35 /** 36 * Magic pattern in start of crypt data on page 0 37 */ 38 #define MAGIC_SZ 6 39 40 static const unsigned char CRYPT_MAGIC[MAGIC_SZ] = { 41 's', 0xE, 0xC, 'R', 'E', 't' }; 42 43 /* This key will be used if nothing else is given */ 44 #define FIL_DEFAULT_ENCRYPTION_KEY ENCRYPTION_KEY_SYSTEM_DATA 45 46 extern os_event_t fil_crypt_threads_event; 47 48 /** 49 * CRYPT_SCHEME_UNENCRYPTED 50 * 51 * Used as intermediate state when convering a space from unencrypted 52 * to encrypted 53 */ 54 /** 55 * CRYPT_SCHEME_1 56 * 57 * xxx is AES_CTR or AES_CBC (or another block cypher with the same key and iv lengths) 58 * L = AES_ECB(KEY, IV) 59 * CRYPT(PAGE) = xxx(KEY=L, IV=C, PAGE) 60 */ 61 62 #define CRYPT_SCHEME_1 1 63 #define CRYPT_SCHEME_1_IV_LEN 16 64 #define CRYPT_SCHEME_UNENCRYPTED 0 65 66 /* Cached L or key for given key_version */ 67 struct key_struct 68 { 69 uint key_version; /*!< Version of the key */ 70 uint key_length; /*!< Key length */ 71 unsigned char key[MY_AES_MAX_KEY_LENGTH]; /*!< Cached key 72 (that is L in CRYPT_SCHEME_1) */ 73 }; 74 75 /** is encryption enabled */ 76 extern ulong srv_encrypt_tables; 77 78 /** Mutex helper for crypt_data->scheme 79 @param[in, out] schme encryption scheme 80 @param[in] exit should we exit or enter mutex ? */ 81 void 82 crypt_data_scheme_locker( 83 st_encryption_scheme* scheme, 84 int exit); 85 86 struct fil_space_rotate_state_t 87 { 88 time_t start_time; /*!< time when rotation started */ 89 ulint active_threads; /*!< active threads in space */ 90 ulint next_offset; /*!< next "free" offset */ 91 ulint max_offset; /*!< max offset needing to be rotated */ 92 uint min_key_version_found; /*!< min key version found but not 93 rotated */ 94 lsn_t end_lsn; /*!< max lsn created when rotating this 95 space */ 96 bool starting; /*!< initial write of IV */ 97 bool flushing; /*!< space is being flushed at end of rotate */ 98 struct { 99 bool is_active; /*!< is scrubbing active in this space */ 100 time_t last_scrub_completed; /*!< when was last scrub 101 completed */ 102 } scrubbing; 103 }; 104 105 #ifndef UNIV_INNOCHECKSUM 106 107 struct fil_space_crypt_t : st_encryption_scheme 108 { 109 public: 110 /** Constructor. Does not initialize the members! 111 The object is expected to be placed in a buffer that 112 has been zero-initialized. */ fil_space_crypt_tfil_space_crypt_t113 fil_space_crypt_t( 114 uint new_type, 115 uint new_min_key_version, 116 uint new_key_id, 117 fil_encryption_t new_encryption) 118 : st_encryption_scheme(), 119 min_key_version(new_min_key_version), 120 page0_offset(0), 121 encryption(new_encryption), 122 key_found(0), 123 rotate_state() 124 { 125 key_id = new_key_id; 126 my_random_bytes(iv, sizeof(iv)); 127 mutex_create(LATCH_ID_FIL_CRYPT_DATA_MUTEX, &mutex); 128 locker = crypt_data_scheme_locker; 129 type = new_type; 130 131 if (new_encryption == FIL_ENCRYPTION_OFF || 132 (!srv_encrypt_tables && 133 new_encryption == FIL_ENCRYPTION_DEFAULT)) { 134 type = CRYPT_SCHEME_UNENCRYPTED; 135 } else { 136 type = CRYPT_SCHEME_1; 137 min_key_version = key_get_latest_version(); 138 } 139 140 key_found = min_key_version; 141 } 142 143 /** Destructor */ ~fil_space_crypt_tfil_space_crypt_t144 ~fil_space_crypt_t() 145 { 146 mutex_free(&mutex); 147 } 148 149 /** Get latest key version from encryption plugin 150 @retval key_version or 151 @retval ENCRYPTION_KEY_VERSION_INVALID if used key_id 152 is not found from encryption plugin. */ 153 uint key_get_latest_version(void); 154 155 /** Returns true if key was found from encryption plugin 156 and false if not. */ is_key_foundfil_space_crypt_t157 bool is_key_found() const { 158 return key_found != ENCRYPTION_KEY_VERSION_INVALID; 159 } 160 161 /** Returns true if tablespace should be encrypted */ should_encryptfil_space_crypt_t162 bool should_encrypt() const { 163 return ((encryption == FIL_ENCRYPTION_ON) || 164 (srv_encrypt_tables && 165 encryption == FIL_ENCRYPTION_DEFAULT)); 166 } 167 168 /** Return true if tablespace is encrypted. */ is_encryptedfil_space_crypt_t169 bool is_encrypted() const { 170 return (encryption != FIL_ENCRYPTION_OFF); 171 } 172 173 /** Return true if default tablespace encryption is used, */ is_default_encryptionfil_space_crypt_t174 bool is_default_encryption() const { 175 return (encryption == FIL_ENCRYPTION_DEFAULT); 176 } 177 178 /** Return true if tablespace is not encrypted. */ not_encryptedfil_space_crypt_t179 bool not_encrypted() const { 180 return (encryption == FIL_ENCRYPTION_OFF); 181 } 182 183 /** Fill crypt data information to the give page. 184 It should be called during ibd file creation. 185 @param[in] flags tablespace flags 186 @param[in,out] page first page of the tablespace */ 187 void fill_page0(ulint flags, byte* page); 188 189 /** Write crypt data to a page (0) 190 @param[in] space tablespace 191 @param[in,out] page0 first page of the tablespace 192 @param[in,out] mtr mini-transaction */ 193 void write_page0(const fil_space_t* space, byte* page0, mtr_t* mtr); 194 195 uint min_key_version; // min key version for this space 196 ulint page0_offset; // byte offset on page 0 for crypt data 197 fil_encryption_t encryption; // Encryption setup 198 199 ib_mutex_t mutex; // mutex protecting following variables 200 201 /** Return code from encryption_key_get_latest_version. 202 If ENCRYPTION_KEY_VERSION_INVALID encryption plugin 203 could not find the key and there is no need to call 204 get_latest_key_version again as keys are read only 205 at startup. */ 206 uint key_found; 207 208 fil_space_rotate_state_t rotate_state; 209 }; 210 211 /** Status info about encryption */ 212 struct fil_space_crypt_status_t { 213 ulint space; /*!< tablespace id */ 214 ulint scheme; /*!< encryption scheme */ 215 uint min_key_version; /*!< min key version */ 216 uint current_key_version;/*!< current key version */ 217 uint keyserver_requests;/*!< no of key requests to key server */ 218 uint key_id; /*!< current key_id */ 219 bool rotating; /*!< is key rotation ongoing */ 220 bool flushing; /*!< is flush at end of rotation ongoing */ 221 ulint rotate_next_page_number; /*!< next page if key rotating */ 222 ulint rotate_max_page_number; /*!< max page if key rotating */ 223 }; 224 225 /** Statistics about encryption key rotation */ 226 struct fil_crypt_stat_t { 227 ulint pages_read_from_cache; 228 ulint pages_read_from_disk; 229 ulint pages_modified; 230 ulint pages_flushed; 231 ulint estimated_iops; 232 }; 233 234 /** Status info about scrubbing */ 235 struct fil_space_scrub_status_t { 236 ulint space; /*!< tablespace id */ 237 bool compressed; /*!< is space compressed */ 238 time_t last_scrub_completed; /*!< when was last scrub completed */ 239 bool scrubbing; /*!< is scrubbing ongoing */ 240 time_t current_scrub_started; /*!< when started current scrubbing */ 241 ulint current_scrub_active_threads; /*!< current scrub active threads */ 242 ulint current_scrub_page_number; /*!< current scrub page no */ 243 ulint current_scrub_max_page_number; /*!< current scrub max page no */ 244 }; 245 246 /********************************************************************* 247 Init space crypt */ 248 UNIV_INTERN 249 void 250 fil_space_crypt_init(); 251 252 /********************************************************************* 253 Cleanup space crypt */ 254 UNIV_INTERN 255 void 256 fil_space_crypt_cleanup(); 257 258 /** 259 Create a fil_space_crypt_t object 260 @param[in] encrypt_mode FIL_ENCRYPTION_DEFAULT or 261 FIL_ENCRYPTION_ON or 262 FIL_ENCRYPTION_OFF 263 264 @param[in] key_id Encryption key id 265 @return crypt object */ 266 UNIV_INTERN 267 fil_space_crypt_t* 268 fil_space_create_crypt_data( 269 fil_encryption_t encrypt_mode, 270 uint key_id) 271 MY_ATTRIBUTE((warn_unused_result)); 272 273 /****************************************************************** 274 Merge fil_space_crypt_t object 275 @param[in,out] dst Destination cryp data 276 @param[in] src Source crypt data */ 277 UNIV_INTERN 278 void 279 fil_space_merge_crypt_data( 280 fil_space_crypt_t* dst, 281 const fil_space_crypt_t* src); 282 283 /** Initialize encryption parameters from a tablespace header page. 284 @param[in] page_size page size of the tablespace 285 @param[in] page first page of the tablespace 286 @return crypt data from page 0 287 @retval NULL if not present or not valid */ 288 UNIV_INTERN 289 fil_space_crypt_t* 290 fil_space_read_crypt_data(const page_size_t& page_size, const byte* page) 291 MY_ATTRIBUTE((nonnull, warn_unused_result)); 292 293 /** 294 Free a crypt data object 295 @param[in,out] crypt_data crypt data to be freed */ 296 UNIV_INTERN 297 void 298 fil_space_destroy_crypt_data( 299 fil_space_crypt_t **crypt_data); 300 301 /****************************************************************** 302 Parse a MLOG_FILE_WRITE_CRYPT_DATA log entry 303 @param[in] ptr Log entry start 304 @param[in] end_ptr Log entry end 305 @param[out] err DB_SUCCESS or DB_DECRYPTION_FAILED 306 @return position on log buffer */ 307 UNIV_INTERN 308 byte* 309 fil_parse_write_crypt_data( 310 byte* ptr, 311 const byte* end_ptr, 312 dberr_t* err) 313 MY_ATTRIBUTE((warn_unused_result)); 314 315 /** Encrypt a buffer. 316 @param[in,out] crypt_data Crypt data 317 @param[in] space space_id 318 @param[in] offset Page offset 319 @param[in] lsn Log sequence number 320 @param[in] src_frame Page to encrypt 321 @param[in] page_size Page size 322 @param[in,out] dst_frame Output buffer 323 @return encrypted buffer or NULL */ 324 byte* 325 fil_encrypt_buf( 326 fil_space_crypt_t* crypt_data, 327 ulint space, 328 ulint offset, 329 lsn_t lsn, 330 const byte* src_frame, 331 const page_size_t& page_size, 332 byte* dst_frame) 333 MY_ATTRIBUTE((warn_unused_result)); 334 335 /** 336 Encrypt a page. 337 338 @param[in] space Tablespace 339 @param[in] offset Page offset 340 @param[in] lsn Log sequence number 341 @param[in] src_frame Page to encrypt 342 @param[in,out] dst_frame Output buffer 343 @return encrypted buffer or NULL */ 344 UNIV_INTERN 345 byte* 346 fil_space_encrypt( 347 const fil_space_t* space, 348 ulint offset, 349 lsn_t lsn, 350 byte* src_frame, 351 byte* dst_frame) 352 MY_ATTRIBUTE((warn_unused_result)); 353 354 /** 355 Decrypt a page. 356 @param[in,out] crypt_data crypt_data 357 @param[in] tmp_frame Temporary buffer 358 @param[in] page_size Page size 359 @param[in,out] src_frame Page to decrypt 360 @return DB_SUCCESS or error */ 361 UNIV_INTERN 362 dberr_t 363 fil_space_decrypt( 364 fil_space_crypt_t* crypt_data, 365 byte* tmp_frame, 366 const page_size_t& page_size, 367 byte* src_frame); 368 369 /****************************************************************** 370 Decrypt a page 371 @param[in] space Tablespace 372 @param[in] tmp_frame Temporary buffer used for decrypting 373 @param[in,out] src_frame Page to decrypt 374 @return decrypted page, or original not encrypted page if decryption is 375 not needed.*/ 376 UNIV_INTERN 377 byte* 378 fil_space_decrypt( 379 const fil_space_t* space, 380 byte* tmp_frame, 381 byte* src_frame) 382 MY_ATTRIBUTE((warn_unused_result)); 383 384 /****************************************************************** 385 Calculate post encryption checksum 386 @param[in] page_size page size 387 @param[in] dst_frame Block where checksum is calculated 388 @return page checksum or BUF_NO_CHECKSUM_MAGIC 389 not needed. */ 390 UNIV_INTERN 391 uint32_t 392 fil_crypt_calculate_checksum( 393 const page_size_t& page_size, 394 const byte* dst_frame) 395 MY_ATTRIBUTE((warn_unused_result)); 396 397 /********************************************************************* 398 Adjust thread count for key rotation 399 @param[in] enw_cnt Number of threads to be used */ 400 UNIV_INTERN 401 void 402 fil_crypt_set_thread_cnt( 403 uint new_cnt); 404 405 /********************************************************************* 406 Adjust max key age 407 @param[in] val New max key age */ 408 UNIV_INTERN 409 void 410 fil_crypt_set_rotate_key_age( 411 uint val); 412 413 /********************************************************************* 414 Adjust rotation iops 415 @param[in] val New max roation iops */ 416 UNIV_INTERN 417 void 418 fil_crypt_set_rotation_iops( 419 uint val); 420 421 /********************************************************************* 422 Adjust encrypt tables 423 @param[in] val New setting for innodb-encrypt-tables */ 424 UNIV_INTERN 425 void 426 fil_crypt_set_encrypt_tables( 427 uint val); 428 429 /********************************************************************* 430 Init threads for key rotation */ 431 UNIV_INTERN 432 void 433 fil_crypt_threads_init(); 434 435 /********************************************************************* 436 Clean up key rotation threads resources */ 437 UNIV_INTERN 438 void 439 fil_crypt_threads_cleanup(); 440 441 /********************************************************************* 442 Wait for crypt threads to stop accessing space 443 @param[in] space Tablespace */ 444 UNIV_INTERN 445 void 446 fil_space_crypt_close_tablespace( 447 const fil_space_t* space); 448 449 /********************************************************************* 450 Get crypt status for a space (used by information_schema) 451 @param[in] space Tablespace 452 @param[out] status Crypt status 453 return 0 if crypt data present */ 454 UNIV_INTERN 455 void 456 fil_space_crypt_get_status( 457 const fil_space_t* space, 458 struct fil_space_crypt_status_t* status); 459 460 /********************************************************************* 461 Return crypt statistics 462 @param[out] stat Crypt statistics */ 463 UNIV_INTERN 464 void 465 fil_crypt_total_stat( 466 fil_crypt_stat_t *stat); 467 468 /** 469 Get scrub status for a space (used by information_schema) 470 471 @param[in] space Tablespace 472 @param[out] status Scrub status 473 return 0 if data found */ 474 UNIV_INTERN 475 void 476 fil_space_get_scrub_status( 477 const fil_space_t* space, 478 fil_space_scrub_status_t* status); 479 480 #include "fil0crypt.inl" 481 #endif /* !UNIV_INNOCHECKSUM */ 482 483 /** 484 Verify that post encryption checksum match calculated checksum. 485 This function should be called only if tablespace contains crypt_data 486 metadata (this is strong indication that tablespace is encrypted). 487 Function also verifies that traditional checksum does not match 488 calculated checksum as if it does page could be valid unencrypted, 489 encrypted, or corrupted. 490 491 @param[in,out] page page frame (checksum is temporarily modified) 492 @param[in] page_size page size 493 @return true if page is encrypted AND OK, false otherwise */ 494 bool 495 fil_space_verify_crypt_checksum(const byte* page, const page_size_t& page_size) 496 MY_ATTRIBUTE((warn_unused_result)); 497 498 /** Add the tablespace to the rotation list if 499 innodb_encrypt_rotate_key_age is 0 or encryption plugin does 500 not do key version rotation 501 @return whether the tablespace should be added to rotation list */ 502 bool fil_crypt_must_default_encrypt(); 503 504 #endif /* fil0crypt_h */ 505