1 /***************************************************************************** 2 Copyright (C) 2013, 2015, Google Inc. All Rights Reserved. 3 Copyright (c) 2015, 2020, 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 uint32_t next_offset; /*!< next "free" offset */ 89 uint32_t 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 }; 97 98 #ifndef UNIV_INNOCHECKSUM 99 100 struct fil_space_crypt_t : st_encryption_scheme 101 { 102 public: 103 /** Constructor. Does not initialize the members! 104 The object is expected to be placed in a buffer that 105 has been zero-initialized. */ fil_space_crypt_tfil_space_crypt_t106 fil_space_crypt_t( 107 uint new_type, 108 uint new_min_key_version, 109 uint new_key_id, 110 fil_encryption_t new_encryption) 111 : st_encryption_scheme(), 112 min_key_version(new_min_key_version), 113 encryption(new_encryption), 114 key_found(0), 115 rotate_state() 116 { 117 key_id = new_key_id; 118 my_random_bytes(iv, sizeof(iv)); 119 mutex_create(LATCH_ID_FIL_CRYPT_DATA_MUTEX, &mutex); 120 locker = crypt_data_scheme_locker; 121 type = new_type; 122 123 if (new_encryption == FIL_ENCRYPTION_OFF || 124 (!srv_encrypt_tables && 125 new_encryption == FIL_ENCRYPTION_DEFAULT)) { 126 type = CRYPT_SCHEME_UNENCRYPTED; 127 } else { 128 type = CRYPT_SCHEME_1; 129 min_key_version = key_get_latest_version(); 130 } 131 132 key_found = min_key_version; 133 } 134 135 /** Destructor */ ~fil_space_crypt_tfil_space_crypt_t136 ~fil_space_crypt_t() 137 { 138 mutex_free(&mutex); 139 } 140 141 /** Get latest key version from encryption plugin 142 @retval key_version or 143 @retval ENCRYPTION_KEY_VERSION_INVALID if used key_id 144 is not found from encryption plugin. */ 145 uint key_get_latest_version(void); 146 147 /** Returns true if key was found from encryption plugin 148 and false if not. */ is_key_foundfil_space_crypt_t149 bool is_key_found() const { 150 return key_found != ENCRYPTION_KEY_VERSION_INVALID; 151 } 152 153 /** Returns true if tablespace should be encrypted */ should_encryptfil_space_crypt_t154 bool should_encrypt() const { 155 return ((encryption == FIL_ENCRYPTION_ON) || 156 (srv_encrypt_tables && 157 encryption == FIL_ENCRYPTION_DEFAULT)); 158 } 159 160 /** Return true if tablespace is encrypted. */ is_encryptedfil_space_crypt_t161 bool is_encrypted() const { 162 return (encryption != FIL_ENCRYPTION_OFF); 163 } 164 165 /** Return true if default tablespace encryption is used, */ is_default_encryptionfil_space_crypt_t166 bool is_default_encryption() const { 167 return (encryption == FIL_ENCRYPTION_DEFAULT); 168 } 169 170 /** Return true if tablespace is not encrypted. */ not_encryptedfil_space_crypt_t171 bool not_encrypted() const { 172 return (encryption == FIL_ENCRYPTION_OFF); 173 } 174 175 /** Fill crypt data information to the give page. 176 It should be called during ibd file creation. 177 @param[in] flags tablespace flags 178 @param[in,out] page first page of the tablespace */ 179 void fill_page0(ulint flags, byte* page); 180 181 /** Write encryption metadata to the first page. 182 @param[in,out] block first page of the tablespace 183 @param[in,out] mtr mini-transaction */ 184 void write_page0(buf_block_t* block, mtr_t* mtr); 185 186 uint min_key_version; // min key version for this space 187 fil_encryption_t encryption; // Encryption setup 188 189 ib_mutex_t mutex; // mutex protecting following variables 190 191 /** Return code from encryption_key_get_latest_version. 192 If ENCRYPTION_KEY_VERSION_INVALID encryption plugin 193 could not find the key and there is no need to call 194 get_latest_key_version again as keys are read only 195 at startup. */ 196 uint key_found; 197 198 fil_space_rotate_state_t rotate_state; 199 }; 200 201 /** Status info about encryption */ 202 struct fil_space_crypt_status_t { 203 ulint space; /*!< tablespace id */ 204 ulint scheme; /*!< encryption scheme */ 205 uint min_key_version; /*!< min key version */ 206 uint current_key_version;/*!< current key version */ 207 uint keyserver_requests;/*!< no of key requests to key server */ 208 uint key_id; /*!< current key_id */ 209 bool rotating; /*!< is key rotation ongoing */ 210 bool flushing; /*!< is flush at end of rotation ongoing */ 211 ulint rotate_next_page_number; /*!< next page if key rotating */ 212 ulint rotate_max_page_number; /*!< max page if key rotating */ 213 }; 214 215 /** Statistics about encryption key rotation */ 216 struct fil_crypt_stat_t { 217 ulint pages_read_from_cache; 218 ulint pages_read_from_disk; 219 ulint pages_modified; 220 ulint pages_flushed; 221 ulint estimated_iops; 222 }; 223 224 /********************************************************************* 225 Init space crypt */ 226 UNIV_INTERN 227 void 228 fil_space_crypt_init(); 229 230 /********************************************************************* 231 Cleanup space crypt */ 232 UNIV_INTERN 233 void 234 fil_space_crypt_cleanup(); 235 236 /** 237 Create a fil_space_crypt_t object 238 @param[in] encrypt_mode FIL_ENCRYPTION_DEFAULT or 239 FIL_ENCRYPTION_ON or 240 FIL_ENCRYPTION_OFF 241 242 @param[in] key_id Encryption key id 243 @return crypt object */ 244 UNIV_INTERN 245 fil_space_crypt_t* 246 fil_space_create_crypt_data( 247 fil_encryption_t encrypt_mode, 248 uint key_id) 249 MY_ATTRIBUTE((warn_unused_result)); 250 251 /****************************************************************** 252 Merge fil_space_crypt_t object 253 @param[in,out] dst Destination cryp data 254 @param[in] src Source crypt data */ 255 UNIV_INTERN 256 void 257 fil_space_merge_crypt_data( 258 fil_space_crypt_t* dst, 259 const fil_space_crypt_t* src); 260 261 /** Initialize encryption parameters from a tablespace header page. 262 @param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 263 @param[in] page first page of the tablespace 264 @return crypt data from page 0 265 @retval NULL if not present or not valid */ 266 fil_space_crypt_t* fil_space_read_crypt_data(ulint zip_size, const byte* page) 267 MY_ATTRIBUTE((nonnull, warn_unused_result)); 268 269 /** 270 Free a crypt data object 271 @param[in,out] crypt_data crypt data to be freed */ 272 UNIV_INTERN 273 void 274 fil_space_destroy_crypt_data( 275 fil_space_crypt_t **crypt_data); 276 277 /** Amend encryption information from redo log. 278 @param[in] space tablespace 279 @param[in] data encryption metadata */ 280 void fil_crypt_parse(fil_space_t* space, const byte* data); 281 282 /** Encrypt a buffer. 283 @param[in,out] crypt_data Crypt data 284 @param[in] space space_id 285 @param[in] offset Page offset 286 @param[in] src_frame Page to encrypt 287 @param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 288 @param[in,out] dst_frame Output buffer 289 @param[in] use_full_checksum full crc32 algo is used 290 @return encrypted buffer or NULL */ 291 UNIV_INTERN 292 byte* 293 fil_encrypt_buf( 294 fil_space_crypt_t* crypt_data, 295 ulint space, 296 ulint offset, 297 const byte* src_frame, 298 ulint zip_size, 299 byte* dst_frame, 300 bool use_full_checksum) 301 MY_ATTRIBUTE((warn_unused_result)); 302 303 /** 304 Encrypt a page. 305 306 @param[in] space Tablespace 307 @param[in] offset Page offset 308 @param[in] src_frame Page to encrypt 309 @param[in,out] dst_frame Output buffer 310 @return encrypted buffer or NULL */ 311 byte* fil_space_encrypt( 312 const fil_space_t* space, 313 ulint offset, 314 byte* src_frame, 315 byte* dst_frame) 316 MY_ATTRIBUTE((warn_unused_result)); 317 318 319 /** Decrypt a page. 320 @param]in] space_id space id 321 @param[in] crypt_data crypt_data 322 @param[in] tmp_frame Temporary buffer 323 @param[in] physical_size page size 324 @param[in] fsp_flags Tablespace flags 325 @param[in,out] src_frame Page to decrypt 326 @return DB_SUCCESS or error */ 327 UNIV_INTERN 328 dberr_t 329 fil_space_decrypt( 330 ulint space_id, 331 fil_space_crypt_t* crypt_data, 332 byte* tmp_frame, 333 ulint physical_size, 334 ulint fsp_flags, 335 byte* src_frame); 336 337 /****************************************************************** 338 Decrypt a page 339 @param[in] space Tablespace 340 @param[in] tmp_frame Temporary buffer used for decrypting 341 @param[in,out] src_frame Page to decrypt 342 @return decrypted page, or original not encrypted page if decryption is 343 not needed.*/ 344 UNIV_INTERN 345 byte* 346 fil_space_decrypt( 347 const fil_space_t* space, 348 byte* tmp_frame, 349 byte* src_frame) 350 MY_ATTRIBUTE((warn_unused_result)); 351 352 /** 353 Calculate post encryption checksum 354 @param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 355 @param[in] dst_frame Block where checksum is calculated 356 @return page checksum 357 not needed. */ 358 uint32_t 359 fil_crypt_calculate_checksum(ulint zip_size, const byte* dst_frame) 360 MY_ATTRIBUTE((warn_unused_result)); 361 362 /********************************************************************* 363 Adjust thread count for key rotation 364 @param[in] enw_cnt Number of threads to be used */ 365 UNIV_INTERN 366 void 367 fil_crypt_set_thread_cnt( 368 uint new_cnt); 369 370 /********************************************************************* 371 Adjust max key age 372 @param[in] val New max key age */ 373 UNIV_INTERN 374 void 375 fil_crypt_set_rotate_key_age( 376 uint val); 377 378 /********************************************************************* 379 Adjust rotation iops 380 @param[in] val New max roation iops */ 381 UNIV_INTERN 382 void 383 fil_crypt_set_rotation_iops( 384 uint val); 385 386 /********************************************************************* 387 Adjust encrypt tables 388 @param[in] val New setting for innodb-encrypt-tables */ 389 void fil_crypt_set_encrypt_tables(ulong val); 390 391 /********************************************************************* 392 Init threads for key rotation */ 393 UNIV_INTERN 394 void 395 fil_crypt_threads_init(); 396 397 /********************************************************************* 398 Clean up key rotation threads resources */ 399 UNIV_INTERN 400 void 401 fil_crypt_threads_cleanup(); 402 403 /********************************************************************* 404 Wait for crypt threads to stop accessing space 405 @param[in] space Tablespace */ 406 UNIV_INTERN 407 void 408 fil_space_crypt_close_tablespace( 409 const fil_space_t* space); 410 411 /********************************************************************* 412 Get crypt status for a space (used by information_schema) 413 @param[in] space Tablespace 414 @param[out] status Crypt status 415 return 0 if crypt data present */ 416 UNIV_INTERN 417 void 418 fil_space_crypt_get_status( 419 const fil_space_t* space, 420 struct fil_space_crypt_status_t* status); 421 422 /********************************************************************* 423 Return crypt statistics 424 @param[out] stat Crypt statistics */ 425 UNIV_INTERN 426 void 427 fil_crypt_total_stat( 428 fil_crypt_stat_t *stat); 429 430 #include "fil0crypt.inl" 431 #endif /* !UNIV_INNOCHECKSUM */ 432 433 /** 434 Verify that post encryption checksum match calculated checksum. 435 This function should be called only if tablespace contains crypt_data 436 metadata (this is strong indication that tablespace is encrypted). 437 Function also verifies that traditional checksum does not match 438 calculated checksum as if it does page could be valid unencrypted, 439 encrypted, or corrupted. 440 441 @param[in,out] page page frame (checksum is temporarily modified) 442 @param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 443 @return true if page is encrypted AND OK, false otherwise */ 444 bool fil_space_verify_crypt_checksum(const byte* page, ulint zip_size) 445 MY_ATTRIBUTE((warn_unused_result)); 446 447 /** Add the tablespace to the rotation list if 448 innodb_encrypt_rotate_key_age is 0 or encryption plugin does 449 not do key version rotation 450 @return whether the tablespace should be added to rotation list */ 451 bool fil_crypt_must_default_encrypt(); 452 453 #endif /* fil0crypt_h */ 454