diff options
Diffstat (limited to 'storage/innobase/log/log0crypt.cc')
-rw-r--r-- | storage/innobase/log/log0crypt.cc | 147 |
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; |