summaryrefslogtreecommitdiff
path: root/storage/innobase/log/log0crypt.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/log/log0crypt.cc')
-rw-r--r--storage/innobase/log/log0crypt.cc147
1 files changed, 94 insertions, 53 deletions
diff --git a/storage/innobase/log/log0crypt.cc b/storage/innobase/log/log0crypt.cc
index dff9661c6eb..7ad39da29ec 100644
--- a/storage/innobase/log/log0crypt.cc
+++ b/storage/innobase/log/log0crypt.cc
@@ -82,19 +82,62 @@ log_block_get_start_lsn(
return start_lsn;
}
+/** Generate crypt key from crypt msg.
+@param[in,out] info encryption key
+@param[in] upgrade whether to use the key in MariaDB 10.1 format
+@return whether the operation was successful */
+static bool init_crypt_key(crypt_info_t* info, bool upgrade = false)
+{
+ byte mysqld_key[MY_AES_MAX_KEY_LENGTH];
+ uint keylen = sizeof mysqld_key;
+
+ compile_time_assert(16 == sizeof info->crypt_key);
+
+ if (uint rc = encryption_key_get(LOG_DEFAULT_ENCRYPTION_KEY,
+ info->key_version, mysqld_key,
+ &keylen)) {
+ ib::error()
+ << "Obtaining redo log encryption key version "
+ << info->key_version << " failed (" << rc
+ << "). Maybe the key or the required encryption "
+ "key management plugin was not found.";
+ return false;
+ }
+
+ if (upgrade) {
+ while (keylen < sizeof mysqld_key) {
+ mysqld_key[keylen++] = 0;
+ }
+ }
+
+ uint dst_len;
+ int err= my_aes_crypt(MY_AES_ECB,
+ ENCRYPTION_FLAG_NOPAD | ENCRYPTION_FLAG_ENCRYPT,
+ info->crypt_msg.bytes, sizeof info->crypt_msg,
+ info->crypt_key.bytes, &dst_len,
+ mysqld_key, keylen, NULL, 0);
+
+ if (err != MY_AES_OK || dst_len != MY_AES_BLOCK_SIZE) {
+ ib::error() << "Getting redo log crypto key failed: err = "
+ << err << ", len = " << dst_len;
+ return false;
+ }
+
+ return true;
+}
+
/** Encrypt or decrypt log blocks.
@param[in,out] buf log blocks to encrypt or decrypt
@param[in] lsn log sequence number of the start of the buffer
@param[in] size size of the buffer, in bytes
-@param[in] decrypt whether to decrypt instead of encrypting */
-UNIV_INTERN
-void
-log_crypt(byte* buf, lsn_t lsn, ulint size, bool decrypt)
+@param[in] op whether to decrypt, encrypt, or rotate key and encrypt
+@return whether the operation succeeded (encrypt always does) */
+bool log_crypt(byte* buf, lsn_t lsn, ulint size, log_crypt_t op)
{
ut_ad(size % OS_FILE_LOG_BLOCK_SIZE == 0);
+ ut_ad(ulint(buf) % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_a(info.key_version);
- uint dst_len;
uint32_t aes_ctr_iv[MY_AES_BLOCK_SIZE / sizeof(uint32_t)];
compile_time_assert(sizeof(uint32_t) == 4);
@@ -103,7 +146,8 @@ log_crypt(byte* buf, lsn_t lsn, ulint size, bool decrypt)
for (const byte* const end = buf + size; buf != end;
buf += OS_FILE_LOG_BLOCK_SIZE, lsn += OS_FILE_LOG_BLOCK_SIZE) {
- uint32_t dst[(OS_FILE_LOG_BLOCK_SIZE - LOG_CRYPT_HDR_SIZE)
+ uint32_t dst[(OS_FILE_LOG_BLOCK_SIZE - LOG_CRYPT_HDR_SIZE
+ - LOG_BLOCK_CHECKSUM)
/ sizeof(uint32_t)];
/* The log block number is not encrypted. */
@@ -123,64 +167,61 @@ log_crypt(byte* buf, lsn_t lsn, ulint size, bool decrypt)
ut_ad(log_block_get_start_lsn(lsn,
log_block_get_hdr_no(buf))
== lsn);
+ byte* key_ver = &buf[OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_KEY
+ - LOG_BLOCK_CHECKSUM];
+ const uint dst_size
+ = log_sys.log.format == LOG_HEADER_FORMAT_ENC_10_4
+ ? sizeof dst - LOG_BLOCK_KEY
+ : sizeof dst;
+ if (log_sys.log.format == LOG_HEADER_FORMAT_ENC_10_4) {
+ const uint key_version = info.key_version;
+ switch (op) {
+ case LOG_ENCRYPT_ROTATE_KEY:
+ info.key_version
+ = encryption_key_get_latest_version(
+ LOG_DEFAULT_ENCRYPTION_KEY);
+ if (key_version != info.key_version
+ && !init_crypt_key(&info)) {
+ info.key_version = key_version;
+ }
+ /* fall through */
+ case LOG_ENCRYPT:
+ mach_write_to_4(key_ver, info.key_version);
+ break;
+ case LOG_DECRYPT:
+ info.key_version = mach_read_from_4(key_ver);
+ if (key_version != info.key_version
+ && !init_crypt_key(&info)) {
+ return false;
+ }
+ }
+#ifndef DBUG_OFF
+ if (key_version != info.key_version) {
+ DBUG_PRINT("ib_log", ("key_version: %x -> %x",
+ key_version,
+ info.key_version));
+ }
+#endif /* !DBUG_OFF */
+ }
+ ut_ad(LOG_CRYPT_HDR_SIZE + dst_size
+ == log_sys.trailer_offset());
+
+ uint dst_len;
int rc = encryption_crypt(
- buf + LOG_CRYPT_HDR_SIZE, sizeof dst,
+ buf + LOG_CRYPT_HDR_SIZE, dst_size,
reinterpret_cast<byte*>(dst), &dst_len,
const_cast<byte*>(info.crypt_key.bytes),
sizeof info.crypt_key,
reinterpret_cast<byte*>(aes_ctr_iv), sizeof aes_ctr_iv,
- decrypt
+ op == LOG_DECRYPT
? ENCRYPTION_FLAG_DECRYPT | ENCRYPTION_FLAG_NOPAD
: ENCRYPTION_FLAG_ENCRYPT | ENCRYPTION_FLAG_NOPAD,
LOG_DEFAULT_ENCRYPTION_KEY,
info.key_version);
-
ut_a(rc == MY_AES_OK);
- ut_a(dst_len == sizeof dst);
- memcpy(buf + LOG_CRYPT_HDR_SIZE, dst, sizeof dst);
- }
-}
-
-/** Generate crypt key from crypt msg.
-@param[in,out] info encryption key
-@param[in] upgrade whether to use the key in MariaDB 10.1 format
-@return whether the operation was successful */
-static bool init_crypt_key(crypt_info_t* info, bool upgrade = false)
-{
- byte mysqld_key[MY_AES_MAX_KEY_LENGTH];
- uint keylen = sizeof mysqld_key;
-
- compile_time_assert(16 == sizeof info->crypt_key);
-
- if (uint rc = encryption_key_get(LOG_DEFAULT_ENCRYPTION_KEY,
- info->key_version, mysqld_key,
- &keylen)) {
- ib::error()
- << "Obtaining redo log encryption key version "
- << info->key_version << " failed (" << rc
- << "). Maybe the key or the required encryption "
- "key management plugin was not found.";
- return false;
- }
-
- if (upgrade) {
- while (keylen < sizeof mysqld_key) {
- mysqld_key[keylen++] = 0;
- }
- }
-
- uint dst_len;
- int err= my_aes_crypt(MY_AES_ECB,
- ENCRYPTION_FLAG_NOPAD | ENCRYPTION_FLAG_ENCRYPT,
- info->crypt_msg.bytes, sizeof info->crypt_msg,
- info->crypt_key.bytes, &dst_len,
- mysqld_key, keylen, NULL, 0);
-
- if (err != MY_AES_OK || dst_len != MY_AES_BLOCK_SIZE) {
- ib::error() << "Getting redo log crypto key failed: err = "
- << err << ", len = " << dst_len;
- return false;
+ ut_a(dst_len == dst_size);
+ memcpy(buf + LOG_CRYPT_HDR_SIZE, dst, dst_size);
}
return true;