summaryrefslogtreecommitdiffstats
path: root/storage/innobase/include/fil0crypt.h
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/include/fil0crypt.h')
-rw-r--r--storage/innobase/include/fil0crypt.h455
1 files changed, 455 insertions, 0 deletions
diff --git a/storage/innobase/include/fil0crypt.h b/storage/innobase/include/fil0crypt.h
new file mode 100644
index 00000000..872053dc
--- /dev/null
+++ b/storage/innobase/include/fil0crypt.h
@@ -0,0 +1,455 @@
+/*****************************************************************************
+Copyright (C) 2013, 2015, Google Inc. All Rights Reserved.
+Copyright (c) 2015, 2020, 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 "os0event.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
+
+extern os_event_t fil_crypt_threads_event;
+
+/**
+ * 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));
+ mutex_create(LATCH_ID_FIL_CRYPT_DATA_MUTEX, &mutex);
+ 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()
+ {
+ mutex_free(&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);
+ }
+
+ /** Fill crypt data information to the give page.
+ It should be called during ibd file creation.
+ @param[in] flags tablespace flags
+ @param[in,out] page first page of the tablespace */
+ void fill_page0(ulint flags, byte* page);
+
+ /** 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
+
+ ib_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;
+ ulint pages_read_from_disk;
+ ulint pages_modified;
+ ulint pages_flushed;
+ ulint estimated_iops;
+};
+
+/*********************************************************************
+Init space crypt */
+UNIV_INTERN
+void
+fil_space_crypt_init();
+
+/*********************************************************************
+Cleanup space crypt */
+UNIV_INTERN
+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 */
+UNIV_INTERN
+fil_space_crypt_t*
+fil_space_create_crypt_data(
+ fil_encryption_t encrypt_mode,
+ uint key_id)
+ MY_ATTRIBUTE((warn_unused_result));
+
+/******************************************************************
+Merge fil_space_crypt_t object
+@param[in,out] dst Destination cryp data
+@param[in] src Source crypt data */
+UNIV_INTERN
+void
+fil_space_merge_crypt_data(
+ fil_space_crypt_t* dst,
+ const fil_space_crypt_t* src);
+
+/** 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 */
+UNIV_INTERN
+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 */
+UNIV_INTERN
+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] crypt_data crypt_data
+@param[in] tmp_frame Temporary buffer
+@param[in] physical_size page size
+@param[in] fsp_flags Tablespace flags
+@param[in,out] src_frame Page to decrypt
+@param[out] err DB_SUCCESS or DB_DECRYPTION_FAILED
+@return true if page decrypted, false if not.*/
+UNIV_INTERN
+bool
+fil_space_decrypt(
+ ulint space_id,
+ fil_space_crypt_t* crypt_data,
+ byte* tmp_frame,
+ ulint physical_size,
+ ulint fsp_flags,
+ byte* src_frame,
+ dberr_t* err);
+
+/******************************************************************
+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.*/
+UNIV_INTERN
+byte*
+fil_space_decrypt(
+ const fil_space_t* space,
+ byte* tmp_frame,
+ byte* src_frame)
+ MY_ATTRIBUTE((warn_unused_result));
+
+/**
+Calculate post encryption checksum
+@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
+@param[in] dst_frame Block where checksum is calculated
+@return page checksum
+not needed. */
+uint32_t
+fil_crypt_calculate_checksum(ulint zip_size, const byte* dst_frame)
+ MY_ATTRIBUTE((warn_unused_result));
+
+/*********************************************************************
+Adjust thread count for key rotation
+@param[in] enw_cnt Number of threads to be used */
+UNIV_INTERN
+void
+fil_crypt_set_thread_cnt(
+ uint new_cnt);
+
+/*********************************************************************
+Adjust max key age
+@param[in] val New max key age */
+UNIV_INTERN
+void
+fil_crypt_set_rotate_key_age(
+ uint val);
+
+/*********************************************************************
+Adjust rotation iops
+@param[in] val New max roation iops */
+UNIV_INTERN
+void
+fil_crypt_set_rotation_iops(
+ uint val);
+
+/*********************************************************************
+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 */
+UNIV_INTERN
+void
+fil_crypt_threads_init();
+
+/*********************************************************************
+Clean up key rotation threads resources */
+UNIV_INTERN
+void
+fil_crypt_threads_cleanup();
+
+/*********************************************************************
+Wait for crypt threads to stop accessing space
+@param[in] space Tablespace */
+UNIV_INTERN
+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 */
+UNIV_INTERN
+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 */
+UNIV_INTERN
+void
+fil_crypt_total_stat(
+ fil_crypt_stat_t *stat);
+
+#include "fil0crypt.ic"
+#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 */