1 /***************************************************************************** 2 Copyright (C) 2013, 2015, Google Inc. All Rights Reserved. 3 Copyright (c) 2015, 2019, 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 #include "os0event.h" 30 #include "my_crypt.h" 31 #include "fil0fil.h" 32 33 /** 34 * Magic pattern in start of crypt data on page 0 35 */ 36 #define MAGIC_SZ 6 37 38 static const unsigned char CRYPT_MAGIC[MAGIC_SZ] = { 39 's', 0xE, 0xC, 'R', 'E', 't' }; 40 41 /* This key will be used if nothing else is given */ 42 #define FIL_DEFAULT_ENCRYPTION_KEY ENCRYPTION_KEY_SYSTEM_DATA 43 44 extern os_event_t fil_crypt_threads_event; 45 46 /** 47 * CRYPT_SCHEME_UNENCRYPTED 48 * 49 * Used as intermediate state when convering a space from unencrypted 50 * to encrypted 51 */ 52 /** 53 * CRYPT_SCHEME_1 54 * 55 * xxx is AES_CTR or AES_CBC (or another block cypher with the same key and iv lengths) 56 * L = AES_ECB(KEY, IV) 57 * CRYPT(PAGE) = xxx(KEY=L, IV=C, PAGE) 58 */ 59 60 #define CRYPT_SCHEME_1 1 61 #define CRYPT_SCHEME_1_IV_LEN 16 62 #define CRYPT_SCHEME_UNENCRYPTED 0 63 64 /* Cached L or key for given key_version */ 65 struct key_struct 66 { 67 uint key_version; /*!< Version of the key */ 68 uint key_length; /*!< Key length */ 69 unsigned char key[MY_AES_MAX_KEY_LENGTH]; /*!< Cached key 70 (that is L in CRYPT_SCHEME_1) */ 71 }; 72 73 /** is encryption enabled */ 74 extern ulong srv_encrypt_tables; 75 76 /** Mutex helper for crypt_data->scheme 77 @param[in, out] schme encryption scheme 78 @param[in] exit should we exit or enter mutex ? */ 79 void 80 crypt_data_scheme_locker( 81 st_encryption_scheme* scheme, 82 int exit); 83 84 struct fil_space_rotate_state_t 85 { 86 time_t start_time; /*!< time when rotation started */ 87 ulint active_threads; /*!< active threads in space */ 88 ulint next_offset; /*!< next "free" offset */ 89 ulint max_offset; /*!< max offset needing to be rotated */ 90 uint min_key_version_found; /*!< min key version found but not 91 rotated */ 92 lsn_t end_lsn; /*!< max lsn created when rotating this 93 space */ 94 bool starting; /*!< initial write of IV */ 95 bool flushing; /*!< space is being flushed at end of rotate */ 96 struct { 97 bool is_active; /*!< is scrubbing active in this space */ 98 time_t last_scrub_completed; /*!< when was last scrub 99 completed */ 100 } scrubbing; 101 }; 102 103 #ifndef UNIV_INNOCHECKSUM 104 105 struct fil_space_crypt_t : st_encryption_scheme 106 { 107 public: 108 /** Constructor. Does not initialize the members! 109 The object is expected to be placed in a buffer that 110 has been zero-initialized. */ fil_space_crypt_tfil_space_crypt_t111 fil_space_crypt_t( 112 uint new_type, 113 uint new_min_key_version, 114 uint new_key_id, 115 fil_encryption_t new_encryption) 116 : st_encryption_scheme(), 117 min_key_version(new_min_key_version), 118 page0_offset(0), 119 encryption(new_encryption), 120 key_found(0), 121 rotate_state() 122 { 123 key_id = new_key_id; 124 my_random_bytes(iv, sizeof(iv)); 125 mutex_create(LATCH_ID_FIL_CRYPT_DATA_MUTEX, &mutex); 126 locker = crypt_data_scheme_locker; 127 type = new_type; 128 129 if (new_encryption == FIL_ENCRYPTION_OFF || 130 (!srv_encrypt_tables && 131 new_encryption == FIL_ENCRYPTION_DEFAULT)) { 132 type = CRYPT_SCHEME_UNENCRYPTED; 133 } else { 134 type = CRYPT_SCHEME_1; 135 min_key_version = key_get_latest_version(); 136 } 137 138 key_found = min_key_version; 139 } 140 141 /** Destructor */ ~fil_space_crypt_tfil_space_crypt_t142 ~fil_space_crypt_t() 143 { 144 mutex_free(&mutex); 145 } 146 147 /** Get latest key version from encryption plugin 148 @retval key_version or 149 @retval ENCRYPTION_KEY_VERSION_INVALID if used key_id 150 is not found from encryption plugin. */ 151 uint key_get_latest_version(void); 152 153 /** Returns true if key was found from encryption plugin 154 and false if not. */ is_key_foundfil_space_crypt_t155 bool is_key_found() const { 156 return key_found != ENCRYPTION_KEY_VERSION_INVALID; 157 } 158 159 /** Returns true if tablespace should be encrypted */ should_encryptfil_space_crypt_t160 bool should_encrypt() const { 161 return ((encryption == FIL_ENCRYPTION_ON) || 162 (srv_encrypt_tables && 163 encryption == FIL_ENCRYPTION_DEFAULT)); 164 } 165 166 /** Return true if tablespace is encrypted. */ is_encryptedfil_space_crypt_t167 bool is_encrypted() const { 168 return (encryption != FIL_ENCRYPTION_OFF); 169 } 170 171 /** Return true if default tablespace encryption is used, */ is_default_encryptionfil_space_crypt_t172 bool is_default_encryption() const { 173 return (encryption == FIL_ENCRYPTION_DEFAULT); 174 } 175 176 /** Return true if tablespace is not encrypted. */ not_encryptedfil_space_crypt_t177 bool not_encrypted() const { 178 return (encryption == FIL_ENCRYPTION_OFF); 179 } 180 181 /** Fill crypt data information to the give page. 182 It should be called during ibd file creation. 183 @param[in] flags tablespace flags 184 @param[in,out] page first page of the tablespace */ 185 void fill_page0(ulint flags, byte* page); 186 187 /** Write crypt data to a page (0) 188 @param[in] space tablespace 189 @param[in,out] page0 first page of the tablespace 190 @param[in,out] mtr mini-transaction */ 191 void write_page0(const fil_space_t* space, byte* page0, mtr_t* mtr); 192 193 uint min_key_version; // min key version for this space 194 ulint page0_offset; // byte offset on page 0 for crypt data 195 fil_encryption_t encryption; // Encryption setup 196 197 ib_mutex_t mutex; // mutex protecting following variables 198 199 /** Return code from encryption_key_get_latest_version. 200 If ENCRYPTION_KEY_VERSION_INVALID encryption plugin 201 could not find the key and there is no need to call 202 get_latest_key_version again as keys are read only 203 at startup. */ 204 uint key_found; 205 206 fil_space_rotate_state_t rotate_state; 207 }; 208 209 /** Status info about encryption */ 210 struct fil_space_crypt_status_t { 211 ulint space; /*!< tablespace id */ 212 ulint scheme; /*!< encryption scheme */ 213 uint min_key_version; /*!< min key version */ 214 uint current_key_version;/*!< current key version */ 215 uint keyserver_requests;/*!< no of key requests to key server */ 216 uint key_id; /*!< current key_id */ 217 bool rotating; /*!< is key rotation ongoing */ 218 bool flushing; /*!< is flush at end of rotation ongoing */ 219 ulint rotate_next_page_number; /*!< next page if key rotating */ 220 ulint rotate_max_page_number; /*!< max page if key rotating */ 221 }; 222 223 /** Statistics about encryption key rotation */ 224 struct fil_crypt_stat_t { 225 ulint pages_read_from_cache; 226 ulint pages_read_from_disk; 227 ulint pages_modified; 228 ulint pages_flushed; 229 ulint estimated_iops; 230 }; 231 232 /** Status info about scrubbing */ 233 struct fil_space_scrub_status_t { 234 ulint space; /*!< tablespace id */ 235 bool compressed; /*!< is space compressed */ 236 time_t last_scrub_completed; /*!< when was last scrub completed */ 237 bool scrubbing; /*!< is scrubbing ongoing */ 238 time_t current_scrub_started; /*!< when started current scrubbing */ 239 ulint current_scrub_active_threads; /*!< current scrub active threads */ 240 ulint current_scrub_page_number; /*!< current scrub page no */ 241 ulint current_scrub_max_page_number; /*!< current scrub max page no */ 242 }; 243 244 /********************************************************************* 245 Init space crypt */ 246 UNIV_INTERN 247 void 248 fil_space_crypt_init(); 249 250 /********************************************************************* 251 Cleanup space crypt */ 252 UNIV_INTERN 253 void 254 fil_space_crypt_cleanup(); 255 256 /** 257 Create a fil_space_crypt_t object 258 @param[in] encrypt_mode FIL_ENCRYPTION_DEFAULT or 259 FIL_ENCRYPTION_ON or 260 FIL_ENCRYPTION_OFF 261 262 @param[in] key_id Encryption key id 263 @return crypt object */ 264 UNIV_INTERN 265 fil_space_crypt_t* 266 fil_space_create_crypt_data( 267 fil_encryption_t encrypt_mode, 268 uint key_id) 269 MY_ATTRIBUTE((warn_unused_result)); 270 271 /****************************************************************** 272 Merge fil_space_crypt_t object 273 @param[in,out] dst Destination cryp data 274 @param[in] src Source crypt data */ 275 UNIV_INTERN 276 void 277 fil_space_merge_crypt_data( 278 fil_space_crypt_t* dst, 279 const fil_space_crypt_t* src); 280 281 /** Initialize encryption parameters from a tablespace header page. 282 @param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 283 @param[in] page first page of the tablespace 284 @return crypt data from page 0 285 @retval NULL if not present or not valid */ 286 fil_space_crypt_t* fil_space_read_crypt_data(ulint zip_size, const byte* page) 287 MY_ATTRIBUTE((nonnull, warn_unused_result)); 288 289 /** 290 Free a crypt data object 291 @param[in,out] crypt_data crypt data to be freed */ 292 UNIV_INTERN 293 void 294 fil_space_destroy_crypt_data( 295 fil_space_crypt_t **crypt_data); 296 297 /****************************************************************** 298 Parse a MLOG_FILE_WRITE_CRYPT_DATA log entry 299 @param[in] ptr Log entry start 300 @param[in] end_ptr Log entry end 301 @param[out] err DB_SUCCESS or DB_DECRYPTION_FAILED 302 @return position on log buffer */ 303 UNIV_INTERN 304 byte* 305 fil_parse_write_crypt_data( 306 byte* ptr, 307 const byte* end_ptr, 308 dberr_t* err) 309 MY_ATTRIBUTE((warn_unused_result)); 310 311 /** Encrypt a buffer. 312 @param[in,out] crypt_data Crypt data 313 @param[in] space space_id 314 @param[in] offset Page offset 315 @param[in] lsn Log sequence number 316 @param[in] src_frame Page to encrypt 317 @param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 318 @param[in,out] dst_frame Output buffer 319 @param[in] use_full_checksum full crc32 algo is used 320 @return encrypted buffer or NULL */ 321 UNIV_INTERN 322 byte* 323 fil_encrypt_buf( 324 fil_space_crypt_t* crypt_data, 325 ulint space, 326 ulint offset, 327 lsn_t lsn, 328 const byte* src_frame, 329 ulint zip_size, 330 byte* dst_frame, 331 bool use_full_checksum) 332 MY_ATTRIBUTE((warn_unused_result)); 333 334 /** 335 Encrypt a page. 336 337 @param[in] space Tablespace 338 @param[in] offset Page offset 339 @param[in] lsn Log sequence number 340 @param[in] src_frame Page to encrypt 341 @param[in,out] dst_frame Output buffer 342 @return encrypted buffer or NULL */ 343 UNIV_INTERN 344 byte* 345 fil_space_encrypt( 346 const fil_space_t* space, 347 ulint offset, 348 lsn_t lsn, 349 byte* src_frame, 350 byte* dst_frame) 351 MY_ATTRIBUTE((warn_unused_result)); 352 353 354 /** Decrypt a page. 355 @param]in] space_id space id 356 @param[in] crypt_data crypt_data 357 @param[in] tmp_frame Temporary buffer 358 @param[in] physical_size page size 359 @param[in] fsp_flags Tablespace flags 360 @param[in,out] src_frame Page to decrypt 361 @return DB_SUCCESS or error */ 362 UNIV_INTERN 363 dberr_t 364 fil_space_decrypt( 365 ulint space_id, 366 fil_space_crypt_t* crypt_data, 367 byte* tmp_frame, 368 ulint physical_size, 369 ulint fsp_flags, 370 byte* src_frame); 371 372 /****************************************************************** 373 Decrypt a page 374 @param[in] space Tablespace 375 @param[in] tmp_frame Temporary buffer used for decrypting 376 @param[in,out] src_frame Page to decrypt 377 @return decrypted page, or original not encrypted page if decryption is 378 not needed.*/ 379 UNIV_INTERN 380 byte* 381 fil_space_decrypt( 382 const fil_space_t* space, 383 byte* tmp_frame, 384 byte* src_frame) 385 MY_ATTRIBUTE((warn_unused_result)); 386 387 /** 388 Calculate post encryption checksum 389 @param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 390 @param[in] dst_frame Block where checksum is calculated 391 @return page checksum 392 not needed. */ 393 uint32_t 394 fil_crypt_calculate_checksum(ulint zip_size, 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] zip_size ROW_FORMAT=COMPRESSED page size, or 0 493 @return true if page is encrypted AND OK, false otherwise */ 494 bool fil_space_verify_crypt_checksum(const byte* page, ulint zip_size) 495 MY_ATTRIBUTE((warn_unused_result)); 496 497 /** Add the tablespace to the rotation list if 498 innodb_encrypt_rotate_key_age is 0 or encryption plugin does 499 not do key version rotation 500 @return whether the tablespace should be added to rotation list */ 501 bool fil_crypt_must_default_encrypt(); 502 503 #endif /* fil0crypt_h */ 504