/*
Copyright ( c ) 2015 , 2020 , MariaDB
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 */
/*************************************************************************
Limitation of encrypted IO_CACHEs
1 . Designed to support temporary files only ( open_cached_file , fd = - 1 )
2 . Created with WRITE_CACHE , later can be reinit_io_cache ' ed to
READ_CACHE and WRITE_CACHE in any order arbitrary number of times .
3 . no seeks for writes , but reinit_io_cache ( WRITE_CACHE , seek_offset )
is allowed ( there ' s a special hack in reinit_io_cache ( ) for that )
*/
#include "../mysys/mysys_priv.h"
#include "log.h"
#include "mysqld.h"
#include "sql_class.h"
static uint keyid, keyver;
#define set_iv(IV, N1, N2) \
do { \
compile_time_assert(sizeof (IV) >= sizeof (N1) + sizeof (N2)); \
memcpy(IV, &(N1), sizeof (N1)); \
memcpy(IV + sizeof (N1), &(N2), sizeof (N2)); \
} while (0 )
static int my_b_encr_read(IO_CACHE *info, uchar *Buffer, size_t Count)
{
my_off_t pos_in_file= info->pos_in_file + (info->read_end - info->buffer);
my_off_t old_pos_in_file= pos_in_file, pos_offset= 0 ;
IO_CACHE_CRYPT *crypt_data=
(IO_CACHE_CRYPT *)(info->buffer + info->buffer_length + MY_AES_BLOCK_SIZE);
uchar *wbuffer= (uchar*)&(crypt_data->inbuf_counter);
uchar *ebuffer= (uchar*)(crypt_data + 1 );
DBUG_ENTER("my_b_encr_read" );
if (pos_in_file == info->end_of_file)
{
/* reading past EOF should not empty the cache */
info->read_pos= info->read_end;
info->error= 0 ;
DBUG_RETURN(MY_TEST(Count));
}
if (info->seek_not_done)
{
my_off_t wpos;
pos_offset= pos_in_file % info->buffer_length;
pos_in_file-= pos_offset;
wpos= pos_in_file / info->buffer_length * crypt_data->block_length;
if ((mysql_file_seek(info->file, wpos, MY_SEEK_SET, MYF(0 ))
== MY_FILEPOS_ERROR))
{
info->error= -1 ;
DBUG_RETURN(1 );
}
info->seek_not_done= 0 ;
if (info->next_file_user)
{
IO_CACHE *c;
for (c= info->next_file_user;
c!= info;
c= c->next_file_user)
{
c->seek_not_done= 1 ;
}
}
}
do
{
uint elength, wlength;
uint length= static_cast <uint>(info->buffer_length);
uchar iv[MY_AES_BLOCK_SIZE]= {0 };
DBUG_ASSERT(pos_in_file % info->buffer_length == 0 );
if (info->end_of_file - pos_in_file >= info->buffer_length)
wlength= crypt_data->block_length;
else
wlength= crypt_data->last_block_length;
if (mysql_file_read(info->file, wbuffer, wlength, info->myflags | MY_NABP))
{
info->error= -1 ;
DBUG_RETURN(1 );
}
elength= wlength - (uint)(ebuffer - wbuffer);
length= elength;
set_iv(iv, pos_in_file, crypt_data->inbuf_counter);
if (encryption_crypt(ebuffer, elength, info->buffer, &length,
crypt_data->key, sizeof (crypt_data->key),
iv, sizeof (iv), ENCRYPTION_FLAG_DECRYPT,
keyid, keyver))
{
my_errno= 1 ;
DBUG_RETURN(info->error= -1 );
}
DBUG_ASSERT(length <= info->buffer_length);
size_t copied= MY_MIN(Count, (size_t)(length - pos_offset));
if (copied)
{
memcpy(Buffer, info->buffer + pos_offset, copied);
Count-= copied;
Buffer+= copied;
}
info->read_pos= info->buffer + pos_offset + copied;
info->read_end= info->buffer + length;
info->pos_in_file= pos_in_file;
pos_in_file+= length;
pos_offset= 0 ;
if (wlength < crypt_data->block_length && pos_in_file < info->end_of_file)
{
info->error= (int )(pos_in_file - old_pos_in_file);
DBUG_RETURN(1 );
}
} while (Count);
DBUG_RETURN(0 );
}
static int my_b_encr_write(IO_CACHE *info, const uchar *Buffer, size_t Count)
{
IO_CACHE_CRYPT *crypt_data=
(IO_CACHE_CRYPT *)(info->buffer + info->buffer_length + MY_AES_BLOCK_SIZE);
uchar *wbuffer= (uchar*)&(crypt_data->inbuf_counter);
uchar *ebuffer= (uchar*)(crypt_data + 1 );
DBUG_ENTER("my_b_encr_write" );
if (Buffer != info->write_buffer)
{
Count-= Count % info->buffer_length;
if (!Count)
DBUG_RETURN(0 );
}
if (info->seek_not_done)
{
DBUG_ASSERT(info->pos_in_file % info->buffer_length == 0 );
my_off_t wpos= info->pos_in_file / info->buffer_length * crypt_data->block_length;
if ((mysql_file_seek(info->file, wpos, MY_SEEK_SET, MYF(0 )) == MY_FILEPOS_ERROR))
{
info->error= -1 ;
DBUG_RETURN(1 );
}
info->seek_not_done= 0 ;
}
if (info->pos_in_file == 0 )
{
if (my_random_bytes(crypt_data->key, sizeof (crypt_data->key)))
{
my_errno= 1 ;
DBUG_RETURN(info->error= -1 );
}
crypt_data->counter= 0 ;
crypt_data->block_length= 0 ;
crypt_data->last_block_length= 0 ;
}
do
{
uint wlength;
size_t length= MY_MIN(info->buffer_length, Count);
uint elength= static_cast <uint>(length);
uchar iv[MY_AES_BLOCK_SIZE]= {0 };
crypt_data->inbuf_counter= crypt_data->counter;
set_iv(iv, info->pos_in_file, crypt_data->inbuf_counter);
if (encryption_crypt(Buffer, (uint)length, ebuffer, &elength,
crypt_data->key, (uint) sizeof (crypt_data->key),
iv, (uint) sizeof (iv), ENCRYPTION_FLAG_ENCRYPT,
keyid, keyver))
{
my_errno= 1 ;
DBUG_RETURN(info->error= -1 );
}
wlength= elength + (uint)(ebuffer - wbuffer);
if (length == info->buffer_length)
{
/*
block_length should be always the same . that is , encrypting
buffer_length bytes should * always * produce block_length bytes
*/
DBUG_ASSERT(crypt_data->block_length == 0 || crypt_data->block_length == wlength);
DBUG_ASSERT(elength <= encryption_encrypted_length((uint)length, keyid, keyver));
crypt_data->block_length= wlength;
}
else
{
/* if we write a partial block, it *must* be the last write */
IF_DBUG(info->write_function= 0 ,);
crypt_data->last_block_length= wlength;
}
if (io_cache_tmp_file_track(info, info->pos_in_file + wlength) ||
mysql_file_write(info->file, wbuffer, wlength, info->myflags | MY_NABP))
DBUG_RETURN(info->error= -1 );
Buffer+= length;
Count-= length;
info->pos_in_file+= length;
crypt_data->counter++;
} while (Count);
DBUG_RETURN(0 );
}
/**
determine what key id and key version to use for IO_CACHE temp files
First , try key id 2 , if it doesn ' t exist , use key id 1 .
( key id 1 is the default system key id , used pretty much everywhere , it must
exist . key id 2 is for tempfiles , it can be used , for example , to set a
faster encryption algorithm for temporary files )
This looks like it might have a bug : if an encryption plugin is unloaded when
there ' s an open IO_CACHE , that IO_CACHE will become unreadable after reinit .
But in fact it is safe , as an encryption plugin can only be unloaded on
server shutdown .
Note that encrypt_tmp_files variable is read - only .
*/
int init_io_cache_encryption()
{
if (encrypt_tmp_files)
{
keyid= ENCRYPTION_KEY_TEMPORARY_DATA;
keyver= encryption_key_get_latest_version(keyid);
if (keyver == ENCRYPTION_KEY_VERSION_INVALID)
{
keyid= ENCRYPTION_KEY_SYSTEM_DATA;
keyver= encryption_key_get_latest_version(keyid);
}
if (keyver == ENCRYPTION_KEY_VERSION_INVALID)
{
sql_print_error("Failed to enable encryption of temporary files" );
return 1 ;
}
if (keyver != ENCRYPTION_KEY_NOT_ENCRYPTED)
{
sql_print_information("Using encryption key id %d for temporary files" , keyid);
_my_b_encr_read= my_b_encr_read;
_my_b_encr_write= my_b_encr_write;
return 0 ;
}
}
_my_b_encr_read= 0 ;
_my_b_encr_write= 0 ;
return 0 ;
}
Messung V0.5 in Prozent C=98 H=75 G=87
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet am 2026-10-08)
¤
*© Formatika GbR, Deutschland