mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 19:06:14 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			401 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			401 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*****************************************************************************
 | |
| Copyright (C) 2013, 2015, Google Inc. All Rights Reserved.
 | |
| Copyright (c) 2015, 2021, MariaDB Corporation.
 | |
| 
 | |
| This program is free software; you can redistribute it and/or modify it under
 | |
| the terms of the GNU General Public License as published by the Free Software
 | |
| Foundation; version 2 of the License.
 | |
| 
 | |
| This program is distributed in the hope that it will be useful, but WITHOUT
 | |
| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 | |
| FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License along with
 | |
| this program; if not, write to the Free Software Foundation, Inc.,
 | |
| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
 | |
| 
 | |
| *****************************************************************************/
 | |
| 
 | |
| /**************************************************//**
 | |
| @file include/fil0crypt.h
 | |
| The low-level file system encryption support functions
 | |
| 
 | |
| Created 04/01/2015 Jan Lindström
 | |
| *******************************************************/
 | |
| 
 | |
| #ifndef fil0crypt_h
 | |
| #define fil0crypt_h
 | |
| 
 | |
| #include "my_crypt.h"
 | |
| #include "fil0fil.h"
 | |
| 
 | |
| /**
 | |
| * Magic pattern in start of crypt data on page 0
 | |
| */
 | |
| #define MAGIC_SZ 6
 | |
| 
 | |
| static const unsigned char CRYPT_MAGIC[MAGIC_SZ] = {
 | |
| 	's', 0xE, 0xC, 'R', 'E', 't' };
 | |
| 
 | |
| /* This key will be used if nothing else is given */
 | |
| #define FIL_DEFAULT_ENCRYPTION_KEY ENCRYPTION_KEY_SYSTEM_DATA
 | |
| 
 | |
| /** Wake up the encryption threads */
 | |
| void fil_crypt_threads_signal(bool broadcast= false);
 | |
| 
 | |
| /**
 | |
|  * CRYPT_SCHEME_UNENCRYPTED
 | |
|  *
 | |
|  * Used as intermediate state when convering a space from unencrypted
 | |
|  * to encrypted
 | |
|  */
 | |
| /**
 | |
|  * CRYPT_SCHEME_1
 | |
|  *
 | |
|  * xxx is AES_CTR or AES_CBC (or another block cypher with the same key and iv lengths)
 | |
|  *  L = AES_ECB(KEY, IV)
 | |
|  *  CRYPT(PAGE) = xxx(KEY=L, IV=C, PAGE)
 | |
|  */
 | |
| 
 | |
| #define CRYPT_SCHEME_1 1
 | |
| #define CRYPT_SCHEME_1_IV_LEN 16
 | |
| #define CRYPT_SCHEME_UNENCRYPTED 0
 | |
| 
 | |
| /* Cached L or key for given key_version */
 | |
| struct key_struct
 | |
| {
 | |
| 	uint key_version;			/*!< Version of the key */
 | |
| 	uint key_length;			/*!< Key length */
 | |
| 	unsigned char key[MY_AES_MAX_KEY_LENGTH]; /*!< Cached key
 | |
|                                                 (that is L in CRYPT_SCHEME_1) */
 | |
| };
 | |
| 
 | |
| /** is encryption enabled */
 | |
| extern ulong	srv_encrypt_tables;
 | |
| 
 | |
| /** Mutex helper for crypt_data->scheme
 | |
| @param[in, out]	schme	encryption scheme
 | |
| @param[in]	exit	should we exit or enter mutex ? */
 | |
| void
 | |
| crypt_data_scheme_locker(
 | |
| 	st_encryption_scheme*	scheme,
 | |
| 	int			exit);
 | |
| 
 | |
| struct fil_space_rotate_state_t
 | |
| {
 | |
| 	time_t start_time;	/*!< time when rotation started */
 | |
| 	ulint active_threads;	/*!< active threads in space */
 | |
| 	uint32_t next_offset;	/*!< next "free" offset */
 | |
| 	uint32_t max_offset;	/*!< max offset needing to be rotated */
 | |
| 	uint  min_key_version_found; /*!< min key version found but not
 | |
| 				     rotated */
 | |
| 	lsn_t end_lsn;		/*!< max lsn created when rotating this
 | |
| 				space */
 | |
| 	bool starting;		/*!< initial write of IV */
 | |
| 	bool flushing;		/*!< space is being flushed at end of rotate */
 | |
| };
 | |
| 
 | |
| #ifndef UNIV_INNOCHECKSUM
 | |
| 
 | |
| struct fil_space_crypt_t : st_encryption_scheme
 | |
| {
 | |
|  public:
 | |
| 	/** Constructor. Does not initialize the members!
 | |
| 	The object is expected to be placed in a buffer that
 | |
| 	has been zero-initialized. */
 | |
| 	fil_space_crypt_t(
 | |
| 		uint new_type,
 | |
| 		uint new_min_key_version,
 | |
| 		uint new_key_id,
 | |
| 		fil_encryption_t new_encryption)
 | |
| 		: st_encryption_scheme(),
 | |
| 		min_key_version(new_min_key_version),
 | |
| 		encryption(new_encryption),
 | |
| 		key_found(0),
 | |
| 		rotate_state()
 | |
| 	{
 | |
| 		key_id = new_key_id;
 | |
| 		my_random_bytes(iv, sizeof(iv));
 | |
| 		mysql_mutex_init(0, &mutex, nullptr);
 | |
| 		locker = crypt_data_scheme_locker;
 | |
| 		type = new_type;
 | |
| 
 | |
| 		if (new_encryption == FIL_ENCRYPTION_OFF ||
 | |
| 			(!srv_encrypt_tables &&
 | |
| 			 new_encryption == FIL_ENCRYPTION_DEFAULT)) {
 | |
| 			type = CRYPT_SCHEME_UNENCRYPTED;
 | |
| 		} else {
 | |
| 			type = CRYPT_SCHEME_1;
 | |
| 			min_key_version = key_get_latest_version();
 | |
| 		}
 | |
| 
 | |
| 		key_found = min_key_version;
 | |
| 	}
 | |
| 
 | |
| 	/** Destructor */
 | |
| 	~fil_space_crypt_t()
 | |
| 	{
 | |
| 		mysql_mutex_destroy(&mutex);
 | |
| 	}
 | |
| 
 | |
| 	/** Get latest key version from encryption plugin
 | |
| 	@retval key_version or
 | |
| 	@retval ENCRYPTION_KEY_VERSION_INVALID if used key_id
 | |
| 	is not found from encryption plugin. */
 | |
| 	uint key_get_latest_version(void);
 | |
| 
 | |
| 	/** Returns true if key was found from encryption plugin
 | |
| 	and false if not. */
 | |
| 	bool is_key_found() const {
 | |
| 		return key_found != ENCRYPTION_KEY_VERSION_INVALID;
 | |
| 	}
 | |
| 
 | |
| 	/** Returns true if tablespace should be encrypted */
 | |
| 	bool should_encrypt() const {
 | |
| 		return ((encryption == FIL_ENCRYPTION_ON) ||
 | |
| 			(srv_encrypt_tables &&
 | |
| 				encryption == FIL_ENCRYPTION_DEFAULT));
 | |
| 	}
 | |
| 
 | |
| 	/** Return true if tablespace is encrypted. */
 | |
| 	bool is_encrypted() const {
 | |
| 		return (encryption != FIL_ENCRYPTION_OFF);
 | |
| 	}
 | |
| 
 | |
| 	/** Return true if default tablespace encryption is used, */
 | |
| 	bool is_default_encryption() const {
 | |
| 		return (encryption == FIL_ENCRYPTION_DEFAULT);
 | |
| 	}
 | |
| 
 | |
| 	/** Return true if tablespace is not encrypted. */
 | |
| 	bool not_encrypted() const {
 | |
| 		return (encryption == FIL_ENCRYPTION_OFF);
 | |
| 	}
 | |
| 
 | |
| 	/** Write encryption metadata to the first page.
 | |
| 	@param[in,out]	block	first page of the tablespace
 | |
| 	@param[in,out]	mtr	mini-transaction */
 | |
| 	void write_page0(buf_block_t* block, mtr_t* mtr);
 | |
| 
 | |
| 	uint min_key_version; // min key version for this space
 | |
| 	fil_encryption_t encryption; // Encryption setup
 | |
| 
 | |
| 	mysql_mutex_t mutex;   // mutex protecting following variables
 | |
| 
 | |
| 	/** Return code from encryption_key_get_latest_version.
 | |
|         If ENCRYPTION_KEY_VERSION_INVALID encryption plugin
 | |
| 	could not find the key and there is no need to call
 | |
| 	get_latest_key_version again as keys are read only
 | |
| 	at startup. */
 | |
| 	uint key_found;
 | |
| 
 | |
| 	fil_space_rotate_state_t rotate_state;
 | |
| };
 | |
| 
 | |
| /** Status info about encryption */
 | |
| struct fil_space_crypt_status_t {
 | |
| 	ulint space;             /*!< tablespace id */
 | |
| 	ulint scheme;            /*!< encryption scheme */
 | |
| 	uint  min_key_version;   /*!< min key version */
 | |
| 	uint  current_key_version;/*!< current key version */
 | |
| 	uint  keyserver_requests;/*!< no of key requests to key server */
 | |
| 	uint key_id;            /*!< current key_id */
 | |
| 	bool rotating;           /*!< is key rotation ongoing */
 | |
| 	bool flushing;           /*!< is flush at end of rotation ongoing */
 | |
| 	ulint rotate_next_page_number; /*!< next page if key rotating */
 | |
| 	ulint rotate_max_page_number;  /*!< max page if key rotating */
 | |
| };
 | |
| 
 | |
| /** Statistics about encryption key rotation */
 | |
| struct fil_crypt_stat_t
 | |
| {
 | |
|   ulint pages_read_from_cache= 0;
 | |
|   ulint pages_read_from_disk= 0;
 | |
|   ulint pages_modified= 0;
 | |
|   ulint pages_flushed= 0;
 | |
|   ulint estimated_iops= 0;
 | |
| };
 | |
| 
 | |
| /** Init space crypt */
 | |
| void fil_space_crypt_init();
 | |
| 
 | |
| /** Cleanup space crypt */
 | |
| void fil_space_crypt_cleanup();
 | |
| 
 | |
| /**
 | |
| Create a fil_space_crypt_t object
 | |
| @param[in]	encrypt_mode	FIL_ENCRYPTION_DEFAULT or
 | |
| 				FIL_ENCRYPTION_ON or
 | |
| 				FIL_ENCRYPTION_OFF
 | |
| 
 | |
| @param[in]	key_id		Encryption key id
 | |
| @return crypt object */
 | |
| fil_space_crypt_t*
 | |
| fil_space_create_crypt_data(
 | |
| 	fil_encryption_t	encrypt_mode,
 | |
| 	uint			key_id)
 | |
| 	MY_ATTRIBUTE((warn_unused_result));
 | |
| 
 | |
| /** Initialize encryption parameters from a tablespace header page.
 | |
| @param[in]	zip_size	ROW_FORMAT=COMPRESSED page size, or 0
 | |
| @param[in]	page		first page of the tablespace
 | |
| @return crypt data from page 0
 | |
| @retval	NULL	if not present or not valid */
 | |
| fil_space_crypt_t* fil_space_read_crypt_data(ulint zip_size, const byte* page)
 | |
| 	MY_ATTRIBUTE((nonnull, warn_unused_result));
 | |
| 
 | |
| /**
 | |
| Free a crypt data object
 | |
| @param[in,out] crypt_data	crypt data to be freed */
 | |
| void fil_space_destroy_crypt_data(fil_space_crypt_t **crypt_data);
 | |
| 
 | |
| /** Amend encryption information from redo log.
 | |
| @param[in]	space	tablespace
 | |
| @param[in]	data	encryption metadata */
 | |
| void fil_crypt_parse(fil_space_t* space, const byte* data);
 | |
| 
 | |
| /** Encrypt a buffer.
 | |
| @param[in,out]		crypt_data		Crypt data
 | |
| @param[in]		space			space_id
 | |
| @param[in]		offset			Page offset
 | |
| @param[in]		src_frame		Page to encrypt
 | |
| @param[in]		zip_size		ROW_FORMAT=COMPRESSED page size, or 0
 | |
| @param[in,out]		dst_frame		Output buffer
 | |
| @param[in]		use_full_checksum	full crc32 algo is used
 | |
| @return encrypted buffer or NULL */
 | |
| byte*
 | |
| fil_encrypt_buf(
 | |
| 	fil_space_crypt_t*	crypt_data,
 | |
| 	ulint			space,
 | |
| 	ulint			offset,
 | |
| 	const byte*		src_frame,
 | |
| 	ulint			zip_size,
 | |
| 	byte*			dst_frame,
 | |
| 	bool			use_full_checksum)
 | |
| 	MY_ATTRIBUTE((warn_unused_result));
 | |
| 
 | |
| /**
 | |
| Encrypt a page.
 | |
| 
 | |
| @param[in]		space		Tablespace
 | |
| @param[in]		offset		Page offset
 | |
| @param[in]		src_frame	Page to encrypt
 | |
| @param[in,out]		dst_frame	Output buffer
 | |
| @return encrypted buffer or NULL */
 | |
| byte* fil_space_encrypt(
 | |
| 	const fil_space_t* space,
 | |
| 	ulint		offset,
 | |
| 	byte*		src_frame,
 | |
| 	byte*		dst_frame)
 | |
| 	MY_ATTRIBUTE((warn_unused_result));
 | |
| 
 | |
| /** Decrypt a page.
 | |
| @param]in]	space_id		space id
 | |
| @param[in]	fsp_flags		Tablespace flags
 | |
| @param[in]	crypt_data		crypt_data
 | |
| @param[in]	tmp_frame		Temporary buffer
 | |
| @param[in]	physical_size		page size
 | |
| @param[in,out]	src_frame		Page to decrypt
 | |
| @retval DB_SUCCESS on success
 | |
| @retval DB_DECRYPTION_FAILED on error */
 | |
| dberr_t
 | |
| fil_space_decrypt(
 | |
| 	uint32_t		space_id,
 | |
| 	uint32_t		fsp_flags,
 | |
| 	fil_space_crypt_t*	crypt_data,
 | |
| 	byte*			tmp_frame,
 | |
| 	ulint			physical_size,
 | |
| 	byte*			src_frame);
 | |
| 
 | |
| /******************************************************************
 | |
| Decrypt a page
 | |
| @param[in]	space			Tablespace
 | |
| @param[in]	tmp_frame		Temporary buffer used for decrypting
 | |
| @param[in,out]	src_frame		Page to decrypt
 | |
| @return decrypted page, or original not encrypted page if decryption is
 | |
| not needed.
 | |
| @retval nullptr on failure */
 | |
| byte*
 | |
| fil_space_decrypt(
 | |
| 	const fil_space_t* space,
 | |
| 	byte*		tmp_frame,
 | |
| 	byte*		src_frame)
 | |
| 	MY_ATTRIBUTE((warn_unused_result));
 | |
| 
 | |
| /*********************************************************************
 | |
| Adjust thread count for key rotation
 | |
| @param[in]	enw_cnt		Number of threads to be used */
 | |
| void fil_crypt_set_thread_cnt(const uint new_cnt);
 | |
| 
 | |
| /*********************************************************************
 | |
| Adjust max key age
 | |
| @param[in]	val		New max key age */
 | |
| void fil_crypt_set_rotate_key_age(uint val);
 | |
| 
 | |
| /*********************************************************************
 | |
| Adjust rotation iops
 | |
| @param[in]	val		New max roation iops */
 | |
| void fil_crypt_set_rotation_iops(uint val);
 | |
| 
 | |
| /** Add the import tablespace to default_encrypt list
 | |
| if necessary and signal fil_crypt_threads
 | |
| @param space imported tablespace */
 | |
| void fil_crypt_add_imported_space(fil_space_t *space);
 | |
| 
 | |
| /*********************************************************************
 | |
| Adjust encrypt tables
 | |
| @param[in]	val		New setting for innodb-encrypt-tables */
 | |
| void fil_crypt_set_encrypt_tables(ulong val);
 | |
| 
 | |
| /*********************************************************************
 | |
| Init threads for key rotation */
 | |
| void fil_crypt_threads_init();
 | |
| 
 | |
| /*********************************************************************
 | |
| Clean up key rotation threads resources */
 | |
| void fil_crypt_threads_cleanup();
 | |
| 
 | |
| /*********************************************************************
 | |
| Wait for crypt threads to stop accessing space
 | |
| @param[in]	space		Tablespace */
 | |
| void fil_space_crypt_close_tablespace(const fil_space_t *space);
 | |
| 
 | |
| /*********************************************************************
 | |
| Get crypt status for a space (used by information_schema)
 | |
| @param[in]	space		Tablespace
 | |
| @param[out]	status		Crypt status
 | |
| return 0 if crypt data present */
 | |
| void
 | |
| fil_space_crypt_get_status(
 | |
| 	const fil_space_t*			space,
 | |
| 	struct fil_space_crypt_status_t*	status);
 | |
| 
 | |
| /*********************************************************************
 | |
| Return crypt statistics
 | |
| @param[out]	stat		Crypt statistics */
 | |
| void fil_crypt_total_stat(fil_crypt_stat_t *stat);
 | |
| 
 | |
| #include "fil0crypt.inl"
 | |
| #endif /* !UNIV_INNOCHECKSUM */
 | |
| 
 | |
| /**
 | |
| Verify that post encryption checksum match calculated checksum.
 | |
| This function should be called only if tablespace contains crypt_data
 | |
| metadata (this is strong indication that tablespace is encrypted).
 | |
| Function also verifies that traditional checksum does not match
 | |
| calculated checksum as if it does page could be valid unencrypted,
 | |
| encrypted, or corrupted.
 | |
| 
 | |
| @param[in,out]	page		page frame (checksum is temporarily modified)
 | |
| @param[in]	zip_size	ROW_FORMAT=COMPRESSED page size, or 0
 | |
| @return true if page is encrypted AND OK, false otherwise */
 | |
| bool fil_space_verify_crypt_checksum(const byte* page, ulint zip_size)
 | |
| 	MY_ATTRIBUTE((warn_unused_result));
 | |
| 
 | |
| /** Add the tablespace to the rotation list if
 | |
| innodb_encrypt_rotate_key_age is 0 or encryption plugin does
 | |
| not do key version rotation
 | |
| @return whether the tablespace should be added to rotation list */
 | |
| bool fil_crypt_must_default_encrypt();
 | |
| 
 | |
| #endif /* fil0crypt_h */
 | 
