mariadb/storage/innobase/include/log0crypt.h
Marko Mäkelä cc277a7d24 MDEV-36024: Redesign innodb_encrypt_log=ON
The innodb_encrypt_log=ON subformat of FORMAT_10_8 is inefficient,
because a new encryption or decryption context is being set up for
every log record payload snippet.

An in-place conversion between the old and new innodb_encrypt_log=ON
format is technically possible. No such conversion has been
implemented, though. There is some overhead with respect to the
unencrypted format (innodb_encrypt_log=OFF): At the end of each
mini-transaction, right before the CRC-32C, additional 8 bytes will be
reserved for a nonce (really, log_sys.get_flushed_lsn()), which forms
a part of an initialization vector.

log_t::FORMAT_ENC_11: The new format identifier, a UTF-8 encoding of
🗝 U+1F5DD OLD KEY (encryption). In this format, everything except the
types and lengths of log records will be encrypted. Thus, unlike in
FORMAT_10_8, also page identifiers and FILE_ records will be encrypted.
The initialization vector (IV) consists of the 8-byte nonce as well as
the type and length byte(s) of the first record of the mini-transaction.
Page identifiers will no longer form any part of the IV.

The old log_t::FORMAT_ENC_10_8 (innodb_encrypt_log=ON) will be supported
both by mariadb-backup and by crash recovery. Downgrade from the new
format will only be possible if the new server has been running or
restarted with innodb_encrypt_log=OFF. If innodb_encrypt_log=ON,
only the new log_t::FORMAT_ENC_11 will be written.

log_t::is_recoverable(): A new predicate, which holds for all 3
formats.

recv_sys_t::tmp_buf: A heap-allocated buffer for decrypting a
mini-transaction, or for making the wrap-around of a memory-mapped
log file contiguous.

recv_sys_t::start_lsn: The start of the mini-transaction.
Updated at the start of parse_tail().

log_decrypt_mtr(): Decrypt a mini-transaction in recv_sys.tmp_buf.
Theoretically, when reading the log via pread() rather than a read-only
memory mapping, we could modify the contents of log_sys.buf in place.
If we did that, we would have to re-read the last log block into
log_sys.buf before resuming writes, because otherwise that block could be
re-written as a mix of old decrypted data and new encrypted data, which
would cause a subsequent recovery failure unless the log checkpoint had
been advanced beyond this point.

log_decrypt_legacy(): Decrypt a log_t::FORMAT_ENC_10_8 record snippet
on stack. Replaces recv_buf::copy_if_needed().

recv_sys_t::get_backup_parser(): Return a recv_sys_t::parser, that is,
a pointer to an instantiation of parse_mmap or parse_mtr for the current
log format.

recv_sys_t::parse_mtr(), recv_sys_t::parse_mmap(): Add a parameter
template<uint32_t> for the current log_sys.format.

log_parse_start(): Validate the CRC-32C of a mini-transaction.
This has been split from the recv_sys_t::parse() template to
reduce code duplication. These two are the lowest-level functions
that will be instantiated for both recv_buf and recv_ring.

recv_sys_t::parse(): Split into ::log_parse_start() and parse_tail().
Add a parameter template<uint32_t format> to specialize for
log_sys.format at compilation time.

recv_sys_t::parse_tail(): Operate on pointers to contiguous
mini-transaction data. Use a parameter template<bool ENC_10_8>
for special handling of the old innodb_encrypt_log=ON format.
The former recv_buf::get_buf() is being inlined here.
Much of the logic is split into non-inline functions, to avoid
duplicating a lot of code for every template expansion.

log_crypt: Encrypt or decrypt a mini-transaction in place in the
new innodb_encrypt_log=ON format. We will use temporary buffers
so that encryption_ctx_update() can be invoked on integer multiples
of MY_AES_BLOCK_SIZE, except for the last bytes of the encrypted
payload, which will be encrypted or decrypted in place thanks to
ENCRYPTION_FLAG_NOPAD.

log_crypt::append(): Invoke encryption_ctx_update() in MY_AES_BLOCK_SIZE
(16-byte) blocks and scatter/gather shorter data blocks as needed.

log_crypt::finish(), Handle the last (possibly incomplete) block as a
special case, with ENCRYPTION_FLAG_NOPAD.

mtr_t::parse_length(): Parse the length of a log record.

mtr_t::encrypt(): Use log_crypt instead of the old log_encrypt_buf().

recv_buf::crc32c(): Add a parameter for the initial CRC-32C value.

recv_sys_t::rewind(): Operate on pointers to the start of the
mini-transaction and to the first skipped record.

recv_sys_t::trim(): Declare as ATTRIBUTE_COLD so that this rarely
invoked function will not be expanded inline in parse_tail().

recv_sys_t::parse_init(): Handle INIT_PAGE or FREE_PAGE while scanning
to the end of the log.

recv_sys_t::parse_page0(): Handle WRITE to FSP_SPACE_SIZE and
FSP_SPACE_FLAGS.

recv_sys_t::parse_store_if_exists(), recv_sys_t::parse_store(),
recv_sys_t::parse_oom(): Handle page-level log records.

mlog_decode_varint_length(): Make use of __builtin_clz() to avoid a loop
when possible.

mlog_decode_varint(): Define only on const byte*, as
ATTRIBUTE_NOINLINE static because it is a rather large function.

recv_buf::decode_varint(): Trivial wrapper for mlog_decode_varint().

recv_ring::decode_varint(): Special implementation.

log_page_modify(): Note that a page will be modified in recovery.
Split from recv_sys_t::parse_tail().

log_parse_file(): Handle non-page log records.

log_record_corrupted(), log_unknown(), log_page_id_corrupted():
Common error reporting functions.
2025-09-02 13:28:34 +03:00

117 lines
4.2 KiB
C

/*****************************************************************************
Copyright (C) 2013, 2015, Google Inc. All Rights Reserved.
Copyright (C) 2014, 2022, 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 St, Fifth Floor, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file include/log0crypt.h
Innodb log encrypt/decrypt
Created 11/25/2013 Minli Zhu
Modified Jan Lindström jan.lindstrom@mariadb.com
MDEV-11782: Rewritten for MariaDB 10.2 by Marko Mäkelä, MariaDB Corporation.
*******************************************************/
#pragma once
#include "log0log.h"
/** innodb_encrypt_log: whether to encrypt the redo log */
extern my_bool srv_encrypt_log;
/** Initialize the redo log encryption key and random parameters
when creating a new redo log.
The random parameters will be persisted in the log header.
@see log_crypt_write_header()
@see log_crypt_read_header()
@return whether the operation succeeded */
bool log_crypt_init();
/** Add the encryption information to the log header buffer.
@param buf part of log header buffer */
void log_crypt_write_header(byte *buf);
/** Read the encryption information from a redo log checkpoint buffer.
@param buf part of checkpoint buffer
@return whether the operation was successful */
bool log_crypt_read_header(const byte *buf);
/** Read the MariaDB 10.1 checkpoint crypto (version, msg and iv) info.
@param[in] buf checkpoint buffer
@return whether the operation was successful */
ATTRIBUTE_COLD bool log_crypt_101_read_checkpoint(const byte* buf);
/** Decrypt a MariaDB 10.1 redo log block.
@param[in,out] buf log block
@param[in] start_lsn server start LSN
@return whether the decryption was successful */
ATTRIBUTE_COLD bool log_crypt_101_read_block(byte* buf, lsn_t start_lsn);
/** Read the checkpoint crypto (version, msg and iv) info.
@param[in] buf checkpoint buffer
@return whether the operation was successful */
ATTRIBUTE_COLD bool log_crypt_read_checkpoint_buf(const byte* buf);
/** Decrypt log blocks.
@param[in,out] buf log blocks to decrypt
@param[in] lsn log sequence number of the start of the buffer
@param[in] size size of the buffer, in bytes
@return whether the operation succeeded */
ATTRIBUTE_COLD bool log_decrypt(byte* buf, lsn_t lsn, ulint size);
/** Decrypt part of a log record.
@param iv initialization vector
@param buf buffer for the decrypted data
@param data the encrypted data
@param len length of the data, in bytes
@return buf */
byte *log_decrypt_buf(const byte *iv, byte *buf, const byte *data, uint len);
/** Decrypt a mini-transaction in place.
@param buf start of the mini-transaction
@param end end of data (followed by sequence byte and the 8-byte nonce) */
void log_decrypt_mtr(byte *buf, const byte *end) noexcept;
/** Encrypt or decrypt a temporary file block.
@param[in] src block to encrypt or decrypt
@param[in] size size of the block
@param[out] dst destination block
@param[in] offs offset to block
@param[in] encrypt true=encrypt; false=decrypt
@return whether the operation succeeded */
bool log_tmp_block_encrypt(
const byte* src,
ulint size,
byte* dst,
uint64_t offs,
bool encrypt = true)
MY_ATTRIBUTE((warn_unused_result, nonnull));
/** Decrypt a temporary file block.
@param[in] src block to decrypt
@param[in] size size of the block
@param[out] dst destination block
@param[in] offs offset to block
@return whether the operation succeeded */
inline
bool
log_tmp_block_decrypt(
const byte* src,
ulint size,
byte* dst,
uint64_t offs)
{
return(log_tmp_block_encrypt(src, size, dst, offs, false));
}