@ -783,26 +783,6 @@ os_file_handle_error_no_exit(
const char * operation ,
bool silent ) ;
/** Decompress after a read and punch a hole in the file if it was a write
@ param [ in ] type IO context
@ param [ in ] fh Open file handle
@ param [ in , out ] buf Buffer to transform
@ param [ in , out ] scratch Scratch area for read decompression
@ param [ in ] src_len Length of the buffer before compression
@ param [ in ] len Compressed buffer length for write and size
of buf len for read
@ return DB_SUCCESS or error code */
static
dberr_t
os_file_io_complete (
const IORequest & type ,
os_file_t fh ,
byte * buf ,
byte * scratch ,
ulint src_len ,
ulint offset ,
ulint len ) ;
/** Does simulated AIO. This function should be called by an i/o-handler
thread .
@ -938,33 +918,7 @@ public:
@ return DB_SUCCESS or error code . */
static dberr_t post_io_processing ( Slot * slot ) ;
/** Decompress after a read and punch a hole in the file if
it was a write */
static dberr_t io_complete ( const Slot * slot )
{
ut_a ( slot - > offset > 0 ) ;
ut_a ( slot - > type . is_read ( ) | | ! slot - > skip_punch_hole ) ;
return ( os_file_io_complete (
slot - > type , slot - > file , slot - > buf ,
slot - > compressed_page , slot - > original_len ,
static_cast < ulint > ( slot - > offset ) ,
slot - > len ) ) ;
}
private :
/** Check whether the page was encrypted.
@ param [ in ] slot The slot that contains the IO request
@ return true if it was an encyrpted page */
static bool is_encrypted_page ( const Slot * slot )
{
# ifdef MYSQL_ENCRYPTION
return ( Encryption : : is_encrypted_page ( slot - > buf ) ) ;
# else
return ( false ) ;
# endif
}
/** Check whether the page was compressed.
@ param [ in ] slot The slot that contains the IO request
@ return true if it was a compressed page */
@ -1146,29 +1100,12 @@ AIOHandler::check_read(Slot* slot, ulint n_bytes)
# else
slot - > n_bytes = static_cast < ulint > ( n_bytes ) ;
# endif /* _WIN32 */
err = io_complete ( slot ) ;
ut_a ( err = = DB_SUCCESS ) ;
} else {
/* Read the next block in */
ut_ad ( compressed_page_size ( slot ) > = n_bytes ) ;
err = DB_FAIL ;
}
} else if ( is_encrypted_page ( slot ) ) {
ut_a ( slot - > offset > 0 ) ;
slot - > len = slot - > original_len ;
# ifdef _WIN32
slot - > n_bytes = static_cast < DWORD > ( n_bytes ) ;
# else
slot - > n_bytes = static_cast < ulint > ( n_bytes ) ;
# endif /* _WIN32 */
err = io_complete ( slot ) ;
ut_a ( err = = DB_SUCCESS ) ;
} else {
err = DB_FAIL ;
}
@ -1202,9 +1139,7 @@ AIOHandler::post_io_processing(Slot* slot)
& & slot - > len = = static_cast < ulint > ( slot - > n_bytes ) ) ) {
# ifdef MYSQL_COMPRESSION
if ( ! slot - > type . is_log ( )
& & ( is_compressed_page ( slot )
| | is_encrypted_page ( slot ) ) ) {
if ( ! slot - > type . is_log ( ) & & is_compressed_page ( slot ) ) {
ut_a ( slot - > offset > 0 ) ;
@ -1652,87 +1587,6 @@ os_file_read_string(
}
}
/** Decompress after a read and punch a hole in the file if it was a write
@ param [ in ] type IO context
@ param [ in ] fh Open file handle
@ param [ in , out ] buf Buffer to transform
@ param [ in , out ] scratch Scratch area for read decompression
@ param [ in ] src_len Length of the buffer before compression
@ param [ in ] len Used buffer length for write and output
buf len for read
@ return DB_SUCCESS or error code */
static
dberr_t
os_file_io_complete (
const IORequest & type ,
os_file_t fh ,
byte * buf ,
byte * scratch ,
ulint src_len ,
ulint offset ,
ulint len )
{
# ifdef MYSQL_ENCRYPTION
/* We never compress/decompress the first page */
ut_a ( offset > 0 ) ;
ut_ad ( type . validate ( ) ) ;
if ( ! type . is_compression_enabled ( ) ) {
return ( DB_SUCCESS ) ;
} else if ( type . is_read ( ) ) {
dberr_t ret = DB_SUCCESS ;
Encryption encryption ( type . encryption_algorithm ( ) ) ;
ut_ad ( ! type . is_log ( ) ) ;
ret = encryption . decrypt ( type , buf , src_len , scratch , len ) ;
if ( ret = = DB_SUCCESS ) {
return ( os_file_decompress_page (
type . is_dblwr_recover ( ) ,
buf , scratch , len ) ) ;
} else {
return ( ret ) ;
}
} else if ( type . punch_hole ( ) ) {
ut_ad ( len < = src_len ) ;
ut_ad ( ! type . is_log ( ) ) ;
ut_ad ( type . is_write ( ) ) ;
ut_ad ( type . is_compressed ( ) ) ;
/* Nothing to do. */
if ( len = = src_len ) {
return ( DB_SUCCESS ) ;
}
# ifdef UNIV_DEBUG
const ulint block_size = type . block_size ( ) ;
# endif /* UNIV_DEBUG */
/* We don't support multiple page sizes in the server
at the moment . */
ut_ad ( src_len = = srv_page_size ) ;
/* Must be a multiple of the compression unit size. */
ut_ad ( ( len % block_size ) = = 0 ) ;
ut_ad ( ( offset % block_size ) = = 0 ) ;
ut_ad ( len + block_size < = src_len ) ;
offset + = len ;
return ( os_file_punch_hole ( fh , offset , src_len - len ) ) ;
}
ut_ad ( ! type . is_log ( ) ) ;
# endif /* MYSQL_ENCRYPTION */
return ( DB_SUCCESS ) ;
}
/** This function returns a new path name after replacing the basename
in an old path with a new basename . The old_path is a full path
name including the extension . The tablename is in the normal
@ -2109,51 +1963,6 @@ os_file_compress_page(
}
# endif /* MYSQL_COMPRESSION */
# ifdef MYSQL_ENCRYPTION
/** Encrypt a page content when write it to disk.
@ param [ in ] type IO flags
@ param [ out ] buf buffer to read or write
@ param [ in , out ] n number of bytes to read / write , starting from
offset
@ return pointer to the encrypted page */
static
Block *
os_file_encrypt_page (
const IORequest & type ,
void * & buf ,
ulint * n )
{
byte * encrypted_page ;
ulint encrypted_len = * n ;
byte * buf_ptr ;
Encryption encryption ( type . encryption_algorithm ( ) ) ;
ut_ad ( ! type . is_log ( ) ) ;
ut_ad ( type . is_write ( ) ) ;
ut_ad ( type . is_encrypted ( ) ) ;
Block * block = os_alloc_block ( ) ;
encrypted_page = static_cast < byte * > (
ut_align ( block - > m_ptr , UNIV_SECTOR_SIZE ) ) ;
buf_ptr = encryption . encrypt ( type ,
reinterpret_cast < byte * > ( buf ) , * n ,
encrypted_page , & encrypted_len ) ;
bool encrypted = buf_ptr ! = buf ;
if ( encrypted ) {
buf = buf_ptr ;
* n = encrypted_len ;
}
return ( block ) ;
}
# endif /* MYSQL_ENCRYPTION */
# ifndef _WIN32
/** Do the read/write
@ -5501,23 +5310,6 @@ os_file_io(
}
# endif /* MYSQL_COMPRESSION */
# ifdef MYSQL_ENCRYPTION
/* We do encryption after compression, since if we do encryption
before compression , the encrypted data will cause compression fail
or low compression rate . */
if ( type . is_encrypted ( ) & & type . is_write ( ) ) {
/* We don't encrypt the first page of any file. */
Block * compressed_block = block ;
ut_ad ( offset > 0 ) ;
block = os_file_encrypt_page ( type , buf , & n ) ;
if ( compressed_block ! = NULL ) {
os_free_block ( compressed_block ) ;
}
}
# endif /* MYSQL_ENCRYPTION */
SyncFileIO sync_file_io ( file , buf , n , offset ) ;
for ( ulint i = 0 ; i < NUM_RETRIES_ON_PARTIAL_IO ; + + i ) {
@ -5532,20 +5324,7 @@ os_file_io(
} else if ( ( ulint ) n_bytes + bytes_returned = = n ) {
bytes_returned + = n_bytes ;
if ( offset > 0
& & ( type . is_compressed ( ) | | type . is_read ( ) ) ) {
* err = os_file_io_complete (
type , file ,
reinterpret_cast < byte * > ( buf ) ,
compressed_page , original_n ,
static_cast < ulint > ( offset ) , n ) ;
} else {
* err = DB_SUCCESS ;
}
* err = DB_SUCCESS ;
# ifdef MYSQL_COMPRESSION
if ( block ! = NULL ) {
os_free_block ( block ) ;
@ -7008,45 +6787,6 @@ AIO::reserve_slot(
}
# endif /* MYSQL_COMPRESSION */
# ifdef MYSQL_ENCRYPTION
/* We do encryption after compression, since if we do encryption
before compression , the encrypted data will cause compression fail
or low compression rate . */
if ( srv_use_native_aio
& & offset > 0
& & type . is_write ( )
& & type . is_encrypted ( ) ) {
ulint encrypted_len = slot - > len ;
Block * encrypted_block ;
ut_ad ( ! type . is_log ( ) ) ;
release ( ) ;
void * src_buf = slot - > buf ;
encrypted_block = os_file_encrypt_page (
type ,
src_buf ,
& encrypted_len ) ;
if ( slot - > buf_block ! = NULL ) {
os_free_block ( slot - > buf_block ) ;
}
slot - > buf_block = encrypted_block ;
slot - > buf = static_cast < byte * > ( src_buf ) ;
slot - > ptr = slot - > buf ;
# ifdef _WIN32
slot - > len = static_cast < DWORD > ( encrypted_len ) ;
# else
slot - > len = static_cast < ulint > ( encrypted_len ) ;
# endif /* _WIN32 */
acquire ( ) ;
}
# endif /* MYSQL_ENCRYPTION */
# ifdef WIN_ASYNC_IO
{
OVERLAPPED * control ;
@ -7713,13 +7453,6 @@ public:
}
}
/** Do the decompression of the pages read in */
void io_complete ( )
{
// Note: For non-compressed tables. Not required
// for correctness.
}
/** Mark the i/os done in slots */
void done ( )
{
@ -8064,8 +7797,6 @@ os_aio_simulated_handler(
srv_set_io_thread_op_info ( global_segment , " file i/o done " ) ;
handler . io_complete ( ) ;
array - > acquire ( ) ;
handler . done ( ) ;
@ -8689,634 +8420,6 @@ os_file_decompress_page(
}
# endif /* MYSQL_COMPRESSION */
# ifdef MYSQL_ENCRYPTION
/**
@ param [ in ] type The encryption type
@ return the string representation */
const char *
Encryption : : to_string ( Type type )
{
switch ( type ) {
case NONE :
return ( " N " ) ;
case AES :
return ( " Y " ) ;
}
ut_ad ( 0 ) ;
return ( " <UNKNOWN> " ) ;
}
/** Generate random encryption value for key and iv.
@ param [ in , out ] value Encryption value */
void Encryption : : random_value ( byte * value )
{
ut_ad ( value ! = NULL ) ;
my_rand_buffer ( value , ENCRYPTION_KEY_LEN ) ;
}
/** Create new master key for key rotation.
@ param [ in , out ] master_key master key */
void
Encryption : : create_master_key ( byte * * master_key )
{
# ifndef UNIV_INNOCHECKSUM
char * key_type = NULL ;
size_t key_len ;
char key_name [ ENCRYPTION_MASTER_KEY_NAME_MAX_LEN ] ;
int ret ;
/* If uuid does not match with current server uuid,
set uuid as current server uuid . */
if ( strcmp ( uuid , server_uuid ) ! = 0 ) {
memcpy ( uuid , server_uuid , ENCRYPTION_SERVER_UUID_LEN ) ;
}
memset ( key_name , 0 , ENCRYPTION_MASTER_KEY_NAME_MAX_LEN ) ;
/* Generate new master key */
ut_snprintf ( key_name , ENCRYPTION_MASTER_KEY_NAME_MAX_LEN ,
" %s-%s-%lu " , ENCRYPTION_MASTER_KEY_PRIFIX ,
uuid , master_key_id + 1 ) ;
/* We call key ring API to generate master key here. */
ret = my_key_generate ( key_name , " AES " ,
NULL , ENCRYPTION_KEY_LEN ) ;
/* We call key ring API to get master key here. */
ret = my_key_fetch ( key_name , & key_type , NULL ,
reinterpret_cast < void * * > ( master_key ) ,
& key_len ) ;
if ( ret | | * master_key = = NULL ) {
ib : : error ( ) < < " Encryption can't find master key, please check "
" the keyring plugin is loaded. " ;
* master_key = NULL ;
} else {
master_key_id + + ;
}
if ( key_type ) {
my_free ( key_type ) ;
}
# endif
}
/** Get master key by key id.
@ param [ in ] master_key_id master key id
@ param [ in ] srv_uuid uuid of server instance
@ param [ in , out ] master_key master key */
void
Encryption : : get_master_key ( ulint master_key_id ,
char * srv_uuid ,
byte * * master_key )
{
# ifndef UNIV_INNOCHECKSUM
char * key_type = NULL ;
size_t key_len ;
char key_name [ ENCRYPTION_MASTER_KEY_NAME_MAX_LEN ] ;
int ret ;
memset ( key_name , 0 , ENCRYPTION_MASTER_KEY_NAME_MAX_LEN ) ;
if ( srv_uuid ! = NULL ) {
ut_snprintf ( key_name , ENCRYPTION_MASTER_KEY_NAME_MAX_LEN ,
" %s-%s-%lu " , ENCRYPTION_MASTER_KEY_PRIFIX ,
srv_uuid , master_key_id ) ;
} else {
/* For compitable with 5.7.11, we need to get master key with
server id . */
memset ( key_name , 0 , ENCRYPTION_MASTER_KEY_NAME_MAX_LEN ) ;
ut_snprintf ( key_name , ENCRYPTION_MASTER_KEY_NAME_MAX_LEN ,
" %s-%lu-%lu " , ENCRYPTION_MASTER_KEY_PRIFIX ,
server_id , master_key_id ) ;
}
/* We call key ring API to get master key here. */
ret = my_key_fetch ( key_name , & key_type , NULL ,
reinterpret_cast < void * * > ( master_key ) , & key_len ) ;
if ( key_type ) {
my_free ( key_type ) ;
}
if ( ret ) {
* master_key = NULL ;
ib : : error ( ) < < " Encryption can't find master key, please check "
" the keyring plugin is loaded. " ;
}
# ifdef UNIV_ENCRYPT_DEBUG
if ( ! ret & & * master_key ) {
fprintf ( stderr , " Fetched master key:%lu " , master_key_id ) ;
ut_print_buf ( stderr , * master_key , key_len ) ;
fprintf ( stderr , " \n " ) ;
}
# endif /* DEBUG_TDE */
# endif
}
/** Current master key id */
ulint Encryption : : master_key_id = 0 ;
/** Current uuid of server instance */
char Encryption : : uuid [ ENCRYPTION_SERVER_UUID_LEN + 1 ] = { 0 } ;
/** Get current master key and master key id
@ param [ in , out ] master_key_id master key id
@ param [ in , out ] master_key master key
@ param [ in , out ] version encryption information version */
void
Encryption : : get_master_key ( ulint * master_key_id ,
byte * * master_key ,
Encryption : : Version * version )
{
# ifndef UNIV_INNOCHECKSUM
char * key_type = NULL ;
size_t key_len ;
char key_name [ ENCRYPTION_MASTER_KEY_NAME_MAX_LEN ] ;
int ret ;
memset ( key_name , 0 , ENCRYPTION_KEY_LEN ) ;
* version = Encryption : : ENCRYPTION_VERSION_2 ;
if ( Encryption : : master_key_id = = 0 ) {
/* If m_master_key is 0, means there's no encrypted
tablespace , we need to generate the first master key ,
and store it to key ring . */
memset ( uuid , 0 , ENCRYPTION_SERVER_UUID_LEN + 1 ) ;
memcpy ( uuid , server_uuid , ENCRYPTION_SERVER_UUID_LEN ) ;
/* Prepare the server uuid. */
ut_snprintf ( key_name , ENCRYPTION_MASTER_KEY_NAME_MAX_LEN ,
" %s-%s-1 " , ENCRYPTION_MASTER_KEY_PRIFIX ,
uuid ) ;
/* We call key ring API to generate master key here. */
ret = my_key_generate ( key_name , " AES " ,
NULL , ENCRYPTION_KEY_LEN ) ;
/* We call key ring API to get master key here. */
ret = my_key_fetch ( key_name , & key_type , NULL ,
reinterpret_cast < void * * > ( master_key ) ,
& key_len ) ;
if ( ! ret & & * master_key ! = NULL ) {
Encryption : : master_key_id + + ;
* master_key_id = Encryption : : master_key_id ;
}
# ifdef UNIV_ENCRYPT_DEBUG
if ( ! ret & & * master_key ) {
fprintf ( stderr , " Generated new master key: " ) ;
ut_print_buf ( stderr , * master_key , key_len ) ;
fprintf ( stderr , " \n " ) ;
}
# endif
} else {
* master_key_id = Encryption : : master_key_id ;
ut_snprintf ( key_name , ENCRYPTION_MASTER_KEY_NAME_MAX_LEN ,
" %s-%s-%lu " , ENCRYPTION_MASTER_KEY_PRIFIX ,
uuid , * master_key_id ) ;
/* We call key ring API to get master key here. */
ret = my_key_fetch ( key_name , & key_type , NULL ,
reinterpret_cast < void * * > ( master_key ) ,
& key_len ) ;
/* For compitable with 5.7.11, we need to try to get master key with
server id when get master key with server uuid failure . */
if ( ret | | * master_key = = NULL ) {
if ( key_type ) {
my_free ( key_type ) ;
}
memset ( key_name , 0 ,
ENCRYPTION_MASTER_KEY_NAME_MAX_LEN ) ;
ut_snprintf ( key_name , ENCRYPTION_MASTER_KEY_NAME_MAX_LEN ,
" %s-%lu-%lu " , ENCRYPTION_MASTER_KEY_PRIFIX ,
server_id , * master_key_id ) ;
ret = my_key_fetch ( key_name , & key_type , NULL ,
reinterpret_cast < void * * > ( master_key ) ,
& key_len ) ;
* version = Encryption : : ENCRYPTION_VERSION_1 ;
}
# ifdef UNIV_ENCRYPT_DEBUG
if ( ! ret & & * master_key ) {
fprintf ( stderr , " Fetched master key:%lu " ,
* master_key_id ) ;
ut_print_buf ( stderr , * master_key , key_len ) ;
fprintf ( stderr , " \n " ) ;
}
# endif
}
if ( ret ) {
* master_key = NULL ;
ib : : error ( ) < < " Encryption can't find master key, please check "
" the keyring plugin is loaded. " ;
}
if ( key_type ) {
my_free ( key_type ) ;
}
# endif
}
/** Check if page is encrypted page or not
@ param [ in ] page page which need to check
@ return true if it is a encrypted page */
bool
Encryption : : is_encrypted_page ( const byte * page )
{
ulint page_type = mach_read_from_2 ( page + FIL_PAGE_TYPE ) ;
return ( page_type = = FIL_PAGE_ENCRYPTED
| | page_type = = FIL_PAGE_COMPRESSED_AND_ENCRYPTED
| | page_type = = FIL_PAGE_ENCRYPTED_RTREE ) ;
}
/** Encrypt the page data contents. Page type can't be
FIL_PAGE_ENCRYPTED , FIL_PAGE_COMPRESSED_AND_ENCRYPTED ,
FIL_PAGE_ENCRYPTED_RTREE .
@ param [ in ] type IORequest
@ param [ in , out ] src page data which need to encrypt
@ param [ in ] src_len Size of the source in bytes
@ param [ in , out ] dst destination area
@ param [ in , out ] dst_len Size of the destination in bytes
@ return buffer data , dst_len will have the length of the data */
byte *
Encryption : : encrypt (
const IORequest & type ,
byte * src ,
ulint src_len ,
byte * dst ,
ulint * dst_len )
{
ulint len = 0 ;
ulint page_type = mach_read_from_2 ( src + FIL_PAGE_TYPE ) ;
ulint data_len ;
ulint main_len ;
ulint remain_len ;
byte remain_buf [ MY_AES_BLOCK_SIZE * 2 ] ;
# ifdef UNIV_ENCRYPT_DEBUG
ulint space_id =
mach_read_from_4 ( src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID ) ;
ulint page_no = mach_read_from_4 ( src + FIL_PAGE_OFFSET ) ;
fprintf ( stderr , " Encrypting page:%lu.%lu len:%lu \n " ,
space_id , page_no , src_len ) ;
# endif
/* Shouldn't encrypte an already encrypted page. */
ut_ad ( page_type ! = FIL_PAGE_ENCRYPTED
& & page_type ! = FIL_PAGE_COMPRESSED_AND_ENCRYPTED
& & page_type ! = FIL_PAGE_ENCRYPTED_RTREE ) ;
ut_ad ( m_type ! = Encryption : : NONE ) ;
/* This is data size which need to encrypt. */
data_len = src_len - FIL_PAGE_DATA ;
main_len = ( data_len / MY_AES_BLOCK_SIZE ) * MY_AES_BLOCK_SIZE ;
remain_len = data_len - main_len ;
/* Only encrypt the data + trailer, leave the header alone */
switch ( m_type ) {
case Encryption : : NONE :
ut_error ;
case Encryption : : AES : {
lint elen ;
ut_ad ( m_klen = = ENCRYPTION_KEY_LEN ) ;
elen = my_aes_encrypt (
src + FIL_PAGE_DATA ,
static_cast < uint32 > ( main_len ) ,
dst + FIL_PAGE_DATA ,
reinterpret_cast < unsigned char * > ( m_key ) ,
static_cast < uint32 > ( m_klen ) ,
my_aes_256_cbc ,
reinterpret_cast < unsigned char * > ( m_iv ) ,
false ) ;
if ( elen = = MY_AES_BAD_DATA ) {
ulint page_no = mach_read_from_4 (
src + FIL_PAGE_OFFSET ) ;
ulint space_id = mach_read_from_4 (
src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID ) ;
* dst_len = src_len ;
# ifndef UNIV_INNOCHECKSUM
ib : : warn ( )
< < " Can't encrypt data of page, "
< < " page no: " < < page_no
< < " space id: " < < space_id ;
# else
fprintf ( stderr , " Can't encrypt data of page, "
" page no: " ULINTPF
" space id: " ULINTPF ,
page_no , space_id ) ;
# endif /* !UNIV_INNOCHECKSUM */
return ( src ) ;
}
len = static_cast < ulint > ( elen ) ;
ut_ad ( len = = main_len ) ;
/* Copy remain bytes and page tailer. */
memcpy ( dst + FIL_PAGE_DATA + len ,
src + FIL_PAGE_DATA + len ,
src_len - FIL_PAGE_DATA - len ) ;
/* Encrypt the remain bytes. */
if ( remain_len ! = 0 ) {
remain_len = MY_AES_BLOCK_SIZE * 2 ;
elen = my_aes_encrypt (
dst + FIL_PAGE_DATA + data_len - remain_len ,
static_cast < uint32 > ( remain_len ) ,
remain_buf ,
reinterpret_cast < unsigned char * > ( m_key ) ,
static_cast < uint32 > ( m_klen ) ,
my_aes_256_cbc ,
reinterpret_cast < unsigned char * > ( m_iv ) ,
false ) ;
if ( elen = = MY_AES_BAD_DATA ) {
ulint page_no = mach_read_from_4 (
src + FIL_PAGE_OFFSET ) ;
ulint space_id = mach_read_from_4 (
src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID ) ;
# ifndef UNIV_INNOCHECKSUM
ib : : warn ( )
< < " Can't encrypt data of page, "
< < " page no: " < < page_no
< < " space id: " < < space_id ;
# else
fprintf ( stderr , " Can't encrypt data of page, "
" page no: " ULINTPF
" space id: " ULINTPF ,
page_no , space_id ) ;
# endif /* !UNIV_INNOCHECKSUM */
* dst_len = src_len ;
return ( src ) ;
}
memcpy ( dst + FIL_PAGE_DATA + data_len - remain_len ,
remain_buf , remain_len ) ;
}
break ;
}
default :
ut_error ;
}
/* Copy the header as is. */
memmove ( dst , src , FIL_PAGE_DATA ) ;
ut_ad ( memcmp ( src , dst , FIL_PAGE_DATA ) = = 0 ) ;
/* Add encryption control information. Required for decrypting. */
if ( page_type = = FIL_PAGE_COMPRESSED ) {
/* If the page is compressed, we don't need to save the
original type , since it is done in compression already . */
mach_write_to_2 ( dst + FIL_PAGE_TYPE ,
FIL_PAGE_COMPRESSED_AND_ENCRYPTED ) ;
ut_ad ( memcmp ( src + FIL_PAGE_TYPE + 2 ,
dst + FIL_PAGE_TYPE + 2 ,
FIL_PAGE_DATA - FIL_PAGE_TYPE - 2 ) = = 0 ) ;
} else if ( page_type = = FIL_PAGE_RTREE ) {
/* If the page is R-tree page, we need to save original
type . */
mach_write_to_2 ( dst + FIL_PAGE_TYPE , FIL_PAGE_ENCRYPTED_RTREE ) ;
} else {
mach_write_to_2 ( dst + FIL_PAGE_TYPE , FIL_PAGE_ENCRYPTED ) ;
mach_write_to_2 ( dst + FIL_PAGE_ORIGINAL_TYPE_V1 , page_type ) ;
}
# ifdef UNIV_ENCRYPT_DEBUG
# ifndef UNIV_INNOCHECKSUM
#if 0
byte * check_buf = static_cast < byte * > ( ut_malloc_nokey ( src_len ) ) ;
byte * buf2 = static_cast < byte * > ( ut_malloc_nokey ( src_len ) ) ;
memcpy ( check_buf , dst , src_len ) ;
dberr_t err = decrypt ( type , check_buf , src_len , buf2 , src_len ) ;
if ( err ! = DB_SUCCESS | | memcmp ( src + FIL_PAGE_DATA ,
check_buf + FIL_PAGE_DATA ,
src_len - FIL_PAGE_DATA ) ! = 0 ) {
ut_print_buf ( stderr , src , src_len ) ;
ut_print_buf ( stderr , check_buf , src_len ) ;
ut_ad ( 0 ) ;
}
ut_free ( buf2 ) ;
ut_free ( check_buf ) ;
# endif
fprintf ( stderr , " Encrypted page:%lu.%lu \n " , space_id , page_no ) ;
# endif
# endif
* dst_len = src_len ;
return ( dst ) ;
}
/** Decrypt the page data contents. Page type must be FIL_PAGE_ENCRYPTED,
if not then the source contents are left unchanged and DB_SUCCESS is returned .
@ param [ in ] type IORequest
@ param [ in , out ] src Data read from disk , decrypted data will be
copied to this page
@ param [ in ] src_len source data length
@ param [ in , out ] dst Scratch area to use for decryption
@ param [ in ] dst_len Size of the scratch area in bytes
@ return DB_SUCCESS or error code */
dberr_t
Encryption : : decrypt (
const IORequest & type ,
byte * src ,
ulint src_len ,
byte * dst ,
ulint dst_len )
{
ulint data_len ;
ulint main_len ;
ulint remain_len ;
ulint original_type ;
ulint page_type ;
byte remain_buf [ MY_AES_BLOCK_SIZE * 2 ] ;
Block * block ;
/* Do nothing if it's not an encrypted table. */
if ( ! is_encrypted_page ( src ) ) {
return ( DB_SUCCESS ) ;
}
/* For compressed page, we need to get the compressed size
for decryption */
page_type = mach_read_from_2 ( src + FIL_PAGE_TYPE ) ;
if ( page_type = = FIL_PAGE_COMPRESSED_AND_ENCRYPTED ) {
src_len = static_cast < uint16_t > (
mach_read_from_2 ( src + FIL_PAGE_COMPRESS_SIZE_V1 ) )
+ FIL_PAGE_DATA ;
# ifndef UNIV_INNOCHECKSUM
src_len = ut_calc_align ( src_len , type . block_size ( ) ) ;
# endif
}
# ifdef UNIV_ENCRYPT_DEBUG
ulint space_id =
mach_read_from_4 ( src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID ) ;
ulint page_no = mach_read_from_4 ( src + FIL_PAGE_OFFSET ) ;
fprintf ( stderr , " Decrypting page:%lu.%lu len:%lu \n " ,
space_id , page_no , src_len ) ;
# endif
original_type = static_cast < uint16_t > (
mach_read_from_2 ( src + FIL_PAGE_ORIGINAL_TYPE_V1 ) ) ;
byte * ptr = src + FIL_PAGE_DATA ;
/* The caller doesn't know what to expect */
if ( dst = = NULL ) {
block = os_alloc_block ( ) ;
# ifdef UNIV_INNOCHECKSUM
dst = block ;
# else
dst = block - > m_ptr ;
# endif /* UNIV_INNOCHECKSUM */
} else {
block = NULL ;
}
data_len = src_len - FIL_PAGE_DATA ;
main_len = ( data_len / MY_AES_BLOCK_SIZE ) * MY_AES_BLOCK_SIZE ;
remain_len = data_len - main_len ;
switch ( m_type ) {
case Encryption : : AES : {
lint elen ;
/* First decrypt the last 2 blocks data of data, since
data is no block aligned . */
if ( remain_len ! = 0 ) {
ut_ad ( m_klen = = ENCRYPTION_KEY_LEN ) ;
remain_len = MY_AES_BLOCK_SIZE * 2 ;
/* Copy the last 2 blocks. */
memcpy ( remain_buf ,
ptr + data_len - remain_len ,
remain_len ) ;
elen = my_aes_decrypt (
remain_buf ,
static_cast < uint32 > ( remain_len ) ,
dst + data_len - remain_len ,
reinterpret_cast < unsigned char * > ( m_key ) ,
static_cast < uint32 > ( m_klen ) ,
my_aes_256_cbc ,
reinterpret_cast < unsigned char * > ( m_iv ) ,
false ) ;
if ( elen = = MY_AES_BAD_DATA ) {
if ( block ! = NULL ) {
os_free_block ( block ) ;
}
return ( DB_IO_DECRYPT_FAIL ) ;
}
/* Copy the other data bytes to temp area. */
memcpy ( dst , ptr , data_len - remain_len ) ;
} else {
ut_ad ( data_len = = main_len ) ;
/* Copy the data bytes to temp area. */
memcpy ( dst , ptr , data_len ) ;
}
/* Then decrypt the main data */
elen = my_aes_decrypt (
dst ,
static_cast < uint32 > ( main_len ) ,
ptr ,
reinterpret_cast < unsigned char * > ( m_key ) ,
static_cast < uint32 > ( m_klen ) ,
my_aes_256_cbc ,
reinterpret_cast < unsigned char * > ( m_iv ) ,
false ) ;
if ( elen = = MY_AES_BAD_DATA ) {
if ( block ! = NULL ) {
os_free_block ( block ) ;
}
return ( DB_IO_DECRYPT_FAIL ) ;
}
ut_ad ( static_cast < ulint > ( elen ) = = main_len ) ;
/* Copy the remain bytes. */
memcpy ( ptr + main_len , dst + main_len , data_len - main_len ) ;
break ;
}
default :
# if !defined(UNIV_INNOCHECKSUM)
ib : : error ( )
< < " Encryption algorithm support missing: "
< < Encryption : : to_string ( m_type ) ;
# else
fprintf ( stderr , " Encryption algorithm support missing: %s \n " ,
Encryption : : to_string ( m_type ) ) ;
# endif /* !UNIV_INNOCHECKSUM */
if ( block ! = NULL ) {
os_free_block ( block ) ;
}
return ( DB_UNSUPPORTED ) ;
}
/* Restore the original page type. If it's a compressed and
encrypted page , just reset it as compressed page type , since
we will do uncompress later . */
if ( page_type = = FIL_PAGE_ENCRYPTED ) {
mach_write_to_2 ( src + FIL_PAGE_TYPE , original_type ) ;
mach_write_to_2 ( src + FIL_PAGE_ORIGINAL_TYPE_V1 , 0 ) ;
} else if ( page_type = = FIL_PAGE_ENCRYPTED_RTREE ) {
mach_write_to_2 ( src + FIL_PAGE_TYPE , FIL_PAGE_RTREE ) ;
} else {
ut_ad ( page_type = = FIL_PAGE_COMPRESSED_AND_ENCRYPTED ) ;
mach_write_to_2 ( src + FIL_PAGE_TYPE , FIL_PAGE_COMPRESSED ) ;
}
if ( block ! = NULL ) {
os_free_block ( block ) ;
}
# ifdef UNIV_ENCRYPT_DEBUG
fprintf ( stderr , " Decrypted page:%lu.%lu \n " , space_id , page_no ) ;
# endif
DBUG_EXECUTE_IF ( " ib_crash_during_decrypt_page " , DBUG_SUICIDE ( ) ; ) ;
return ( DB_SUCCESS ) ;
}
# endif /* MYSQL_ENCRYPTION */
/** Normalizes a directory path for the current OS:
On Windows , we convert ' / ' to ' \ ' , else we convert ' \ ' to ' / ' .
@ param [ in , out ] str A null - terminated directory and file path */