@ -1,7 +1,7 @@
/*****************************************************************************
Copyright ( C ) 2013 , 2015 , Google Inc . All Rights Reserved .
Copyright ( C ) 2014 , 2019 , MariaDB Corporation .
Copyright ( C ) 2014 , 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
@ -37,22 +37,15 @@ my_bool srv_encrypt_log;
/** Redo log encryption key ID */
# define LOG_DEFAULT_ENCRYPTION_KEY 1
struct aes_block_t {
byte bytes [ MY_AES_BLOCK_SIZE ] ;
} ;
struct crypt_info_t {
ulint checkpoint_no ; /*!< checkpoint no; 32 bits */
uint key_version ; /*!< mysqld key version */
/** random string for encrypting the key */
aes_block_t crypt_msg ;
alignas ( 8 ) byte crypt_msg [ MY_AES_BLOCK_SIZE ] ;
/** the secret key */
aes_block_t crypt_key ;
alignas ( 8 ) byte crypt_key [ MY_AES_BLOCK_SIZE ] ;
/** a random string for the per-block initialization vector */
union {
uint32_t word ;
byte bytes [ 4 ] ;
} crypt_nonce ;
alignas ( 4 ) byte crypt_nonce [ 4 ] ;
} ;
/** The crypt info */
@ -91,7 +84,7 @@ 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 . bytes ) ;
compile_time_assert ( 16 = = sizeof info - > crypt_key ) ;
compile_time_assert ( 16 = = MY_AES_BLOCK_SIZE ) ;
if ( uint rc = encryption_key_get ( LOG_DEFAULT_ENCRYPTION_KEY ,
@ -114,8 +107,8 @@ static bool init_crypt_key(crypt_info_t* info, bool upgrade = false)
uint dst_len ;
int err = my_aes_crypt ( MY_AES_ECB ,
ENCRYPTION_FLAG_NOPAD | ENCRYPTION_FLAG_ENCRYPT ,
info - > crypt_msg . bytes , MY_AES_BLOCK_SIZE ,
info - > crypt_key . bytes , & dst_len ,
info - > crypt_msg , MY_AES_BLOCK_SIZE ,
info - > crypt_key , & dst_len ,
mysqld_key , keylen , NULL , 0 ) ;
if ( err ! = MY_AES_OK | | dst_len ! = MY_AES_BLOCK_SIZE ) {
@ -139,32 +132,24 @@ bool log_crypt(byte* buf, lsn_t lsn, ulint size, log_crypt_t op)
ut_ad ( ulint ( buf ) % OS_FILE_LOG_BLOCK_SIZE = = 0 ) ;
ut_a ( info . key_version ) ;
uint32_t aes_ctr_iv [ MY_AES_BLOCK_SIZE / sizeof ( uint32_t ) ] ;
compile_time_assert ( sizeof ( uint32_t ) = = 4 ) ;
alignas ( 8 ) byte aes_ctr_iv [ MY_AES_BLOCK_SIZE ] ;
# define LOG_CRYPT_HDR_SIZE 4
lsn & = ~ lsn_t ( OS_FILE_LOG_BLOCK_SIZE - 1 ) ;
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
- LOG_BLOCK_CHECKSUM )
/ sizeof ( uint32_t ) ] ;
alignas ( 4 ) byte dst [ OS_FILE_LOG_BLOCK_SIZE - LOG_CRYPT_HDR_SIZE
- LOG_BLOCK_CHECKSUM ] ;
/* The log block number is not encrypted. */
* aes_ctr_iv =
# ifdef WORDS_BIGENDIAN
~ LOG_BLOCK_FLUSH_BIT_MASK
# else
~ ( LOG_BLOCK_FLUSH_BIT_MASK > > 24 )
# endif
& ( * dst = * reinterpret_cast < const uint32_t * > (
buf + LOG_BLOCK_HDR_NO ) ) ;
# if LOG_BLOCK_HDR_NO + 4 != LOG_CRYPT_HDR_SIZE
# error "LOG_BLOCK_HDR_NO has been moved; redo log format affected!"
# endif
aes_ctr_iv [ 1 ] = info . crypt_nonce . word ;
mach_write_to_8 ( reinterpret_cast < byte * > ( aes_ctr_iv + 2 ) , lsn ) ;
memcpy_aligned < 4 > ( dst , buf + LOG_BLOCK_HDR_NO , 4 ) ;
memcpy_aligned < 4 > ( aes_ctr_iv , buf + LOG_BLOCK_HDR_NO , 4 ) ;
* aes_ctr_iv & = ~ ( LOG_BLOCK_FLUSH_BIT_MASK > > 24 ) ;
static_assert ( LOG_BLOCK_HDR_NO + 4 = = LOG_CRYPT_HDR_SIZE ,
" compatibility " ) ;
memcpy_aligned < 4 > ( aes_ctr_iv + 4 , info . crypt_nonce , 4 ) ;
mach_write_to_8 ( my_assume_aligned < 8 > ( aes_ctr_iv + 8 ) , lsn ) ;
ut_ad ( log_block_get_start_lsn ( lsn ,
log_block_get_hdr_no ( buf ) )
= = lsn ) ;
@ -212,9 +197,9 @@ bool log_crypt(byte* buf, lsn_t lsn, ulint size, log_crypt_t op)
int rc = encryption_crypt (
buf + LOG_CRYPT_HDR_SIZE , dst_size ,
reinterpret_cast < byte * > ( dst ) , & dst_len ,
const_cast < byte * > ( info . crypt_key . bytes ) ,
const_cast < byte * > ( info . crypt_key ) ,
MY_AES_BLOCK_SIZE ,
reinterpret_cast < byte * > ( aes_ctr_iv ) , sizeof aes_ctr_iv ,
aes_ctr_iv , sizeof aes_ctr_iv ,
op = = LOG_DECRYPT
? ENCRYPTION_FLAG_DECRYPT | ENCRYPTION_FLAG_NOPAD
: ENCRYPTION_FLAG_ENCRYPT | ENCRYPTION_FLAG_NOPAD ,
@ -234,37 +219,31 @@ The random parameters will be persisted in the log checkpoint pages.
@ see log_crypt_write_checkpoint_buf ( )
@ see log_crypt_read_checkpoint_buf ( )
@ return whether the operation succeeded */
UNIV_INTERN
bool
log_crypt_init ( )
bool log_crypt_init ( )
{
info . key_version = encryption_key_get_latest_version (
LOG_DEFAULT_ENCRYPTION_KEY ) ;
if ( info . key_version = = ENCRYPTION_KEY_VERSION_INVALID ) {
ib : : error ( ) < < " innodb_encrypt_log: cannot get key version " ;
info . key_version = 0 ;
return false ;
}
if ( my_random_bytes ( tmp_iv , MY_AES_BLOCK_SIZE ) ! = MY_AES_OK
| | my_random_bytes ( info . crypt_msg . bytes , sizeof info . crypt_msg )
! = MY_AES_OK
| | my_random_bytes ( info . crypt_nonce . bytes , sizeof info . crypt_nonce )
! = MY_AES_OK ) {
ib : : error ( ) < < " innodb_encrypt_log: my_random_bytes() failed " ;
return false ;
}
return init_crypt_key ( & info ) ;
info . key_version =
encryption_key_get_latest_version ( LOG_DEFAULT_ENCRYPTION_KEY ) ;
if ( info . key_version = = ENCRYPTION_KEY_VERSION_INVALID )
ib : : error ( ) < < " log_crypt_init(): cannot get key version " ;
else if ( my_random_bytes ( tmp_iv , MY_AES_BLOCK_SIZE ) ! = MY_AES_OK | |
my_random_bytes ( info . crypt_msg , sizeof info . crypt_msg ) ! =
MY_AES_OK | |
my_random_bytes ( info . crypt_nonce , sizeof info . crypt_nonce ) ! =
MY_AES_OK )
ib : : error ( ) < < " log_crypt_init(): my_random_bytes() failed " ;
else if ( init_crypt_key ( & info ) )
goto func_exit ;
info . key_version = 0 ;
func_exit :
return info . key_version ! = 0 ;
}
/** Read the MariaDB 10.1 checkpoint crypto (version, msg and iv) info.
@ param [ in ] buf checkpoint buffer
@ return whether the operation was successful */
UNIV_INTERN
bool
log_crypt_101_read_checkpoint ( const byte * buf )
ATTRIBUTE_COLD bool log_crypt_101_read_checkpoint ( const byte * buf )
{
buf + = 20 + 32 * 9 ;
@ -286,9 +265,8 @@ log_crypt_101_read_checkpoint(const byte* buf)
infos_used + + ;
info . checkpoint_no = checkpoint_no ;
info . key_version = mach_read_from_4 ( buf + 4 ) ;
memcpy ( info . crypt_msg . bytes , buf + 8 , MY_AES_BLOCK_SIZE ) ;
memcpy ( info . crypt_nonce . bytes , buf + 24 ,
sizeof info . crypt_nonce ) ;
memcpy ( info . crypt_msg , buf + 8 , MY_AES_BLOCK_SIZE ) ;
memcpy ( info . crypt_nonce , buf + 24 , sizeof info . crypt_nonce ) ;
if ( ! init_crypt_key ( & info , true ) ) {
return false ;
@ -304,10 +282,8 @@ next_slot:
@ param [ in , out ] buf log block
@ param [ in ] start_lsn server start LSN
@ return whether the decryption was successful */
bool log_crypt_101_read_block ( byte * buf , lsn_t start_lsn )
ATTRIBUTE_COLD bool log_crypt_101_read_block ( byte * buf , lsn_t start_lsn )
{
ut_ad ( log_block_calc_checksum_format_0 ( buf )
! = log_block_get_checksum ( buf ) ) ;
const uint32_t checkpoint_no
= uint32_t ( log_block_get_checkpoint_no ( buf ) ) ;
const crypt_info_t * info = infos ;
@ -337,7 +313,7 @@ found:
/* The log block header is not encrypted. */
memcpy ( dst , buf , LOG_BLOCK_HDR_SIZE ) ;
memcpy ( aes_ctr_iv , info - > crypt_nonce . bytes , 3 ) ;
memcpy ( aes_ctr_iv , info - > crypt_nonce , 3 ) ;
mach_write_to_8 ( aes_ctr_iv + 3 ,
log_block_get_start_lsn ( start_lsn , log_block_no ) ) ;
memcpy ( aes_ctr_iv + 11 , buf , 4 ) ;
@ -346,7 +322,7 @@ found:
int rc = encryption_crypt ( buf + LOG_BLOCK_HDR_SIZE , src_len ,
dst + LOG_BLOCK_HDR_SIZE , & dst_len ,
const_cast < byte * > ( info - > crypt_key . bytes ) ,
const_cast < byte * > ( info - > crypt_key ) ,
MY_AES_BLOCK_SIZE ,
aes_ctr_iv , MY_AES_BLOCK_SIZE ,
ENCRYPTION_FLAG_DECRYPT
@ -369,15 +345,15 @@ void
log_crypt_write_checkpoint_buf ( byte * buf )
{
ut_ad ( info . key_version ) ;
compile_time_assert ( 16 = = sizeof info . crypt_msg . bytes ) ;
compile_time_assert ( 16 = = sizeof info . crypt_msg ) ;
compile_time_assert ( 16 = = MY_AES_BLOCK_SIZE ) ;
compile_time_assert ( LOG_CHECKPOINT_CRYPT_MESSAGE
- LOG_CHECKPOINT_CRYPT_NONCE
= = sizeof info . crypt_nonce ) ;
memcpy ( buf + LOG_CHECKPOINT_CRYPT_MESSAGE , info . crypt_msg . bytes ,
memcpy ( buf + LOG_CHECKPOINT_CRYPT_MESSAGE , info . crypt_msg ,
MY_AES_BLOCK_SIZE ) ;
memcpy ( buf + LOG_CHECKPOINT_CRYPT_NONCE , info . crypt_nonce . bytes ,
memcpy ( buf + LOG_CHECKPOINT_CRYPT_NONCE , info . crypt_nonce ,
sizeof info . crypt_nonce ) ;
mach_write_to_4 ( buf + LOG_CHECKPOINT_CRYPT_KEY , info . key_version ) ;
}
@ -385,9 +361,7 @@ log_crypt_write_checkpoint_buf(byte* buf)
/** Read the checkpoint crypto (version, msg and iv) info.
@ param [ in ] buf checkpoint buffer
@ return whether the operation was successful */
UNIV_INTERN
bool
log_crypt_read_checkpoint_buf ( const byte * buf )
bool log_crypt_read_checkpoint_buf ( const byte * buf )
{
info . checkpoint_no = mach_read_from_4 ( buf + ( LOG_CHECKPOINT_NO + 4 ) ) ;
info . key_version = mach_read_from_4 ( buf + LOG_CHECKPOINT_CRYPT_KEY ) ;
@ -395,15 +369,15 @@ log_crypt_read_checkpoint_buf(const byte* buf)
# if MY_AES_BLOCK_SIZE != 16
# error "MY_AES_BLOCK_SIZE != 16; redo log checkpoint format affected"
# endif
compile_time_assert ( 16 = = sizeof info . crypt_msg . bytes ) ;
compile_time_assert ( 16 = = sizeof info . crypt_msg ) ;
compile_time_assert ( 16 = = MY_AES_BLOCK_SIZE ) ;
compile_time_assert ( LOG_CHECKPOINT_CRYPT_MESSAGE
- LOG_CHECKPOINT_CRYPT_NONCE
= = sizeof info . crypt_nonce ) ;
memcpy ( info . crypt_msg . bytes , buf + LOG_CHECKPOINT_CRYPT_MESSAGE ,
memcpy ( info . crypt_msg , buf + LOG_CHECKPOINT_CRYPT_MESSAGE ,
MY_AES_BLOCK_SIZE ) ;
memcpy ( info . crypt_nonce . bytes , buf + LOG_CHECKPOINT_CRYPT_NONCE ,
memcpy ( info . crypt_nonce , buf + LOG_CHECKPOINT_CRYPT_NONCE ,
sizeof info . crypt_nonce ) ;
return init_crypt_key ( & info ) ;
@ -432,7 +406,7 @@ log_tmp_block_encrypt(
int rc = encryption_crypt (
src , uint ( size ) , dst , & dst_len ,
const_cast < byte * > ( info . crypt_key . bytes ) , MY_AES_BLOCK_SIZE ,
const_cast < byte * > ( info . crypt_key ) , MY_AES_BLOCK_SIZE ,
reinterpret_cast < byte * > ( iv ) , uint ( sizeof iv ) ,
encrypt
? ENCRYPTION_FLAG_ENCRYPT | ENCRYPTION_FLAG_NOPAD