diff options
author | Michael Widenius <monty@mariadb.org> | 2014-12-20 15:44:23 +0200 |
---|---|---|
committer | Michael Widenius <monty@mariadb.org> | 2014-12-20 15:44:23 +0200 |
commit | 406b31e628145f6af0fa567c0e42b8391e5173bb (patch) | |
tree | aff311e03c5bb078fe67b090bd8a0e602beed547 | |
parent | 634428b37fd039b862c8277a0c7b0b5f56e765fc (diff) | |
download | mariadb-git-bb-10.1-eperi.tar.gz |
Fixes for encryption from eperibb-10.1-eperi
45 files changed, 1193 insertions, 1468 deletions
diff --git a/include/keyfile.h b/include/keyfile.h deleted file mode 100644 index d55c79086d4..00000000000 --- a/include/keyfile.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (C) 2014 eperi GmbH. All Rights Reserved. - - 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-1301 USA */ - -/******************************************************************/ -#ifndef KEYFILE_H -#define KEYFILE_H -#include<stdio.h> - -struct keyentry { - int id; - char *iv; - char *key; -}; - -int -parseFile(FILE * fp, struct keyentry **allKeys, const int k_len, const char *secret); - -int -parseLine(const char *line, struct keyentry *entry, const int k_len); - -int -isComment(char *line); - -char* -trim(char *in); -#endif diff --git a/include/my_aes.h b/include/my_aes.h index 4c40894e116..8ec36add4d1 100644 --- a/include/my_aes.h +++ b/include/my_aes.h @@ -32,9 +32,17 @@ typedef int Crypt_result; #define AES_BAD_KEYSIZE -5 #define AES_KEY_CREATION_FAILED -10 +#define CRYPT_KEY_OK 0 +#define CRYPT_BUFFER_TO_SMALL -11; +#define CRYPT_KEY_UNKNOWN -48; + /* The max block sizes of all supported algorithms */ #define MY_AES_BLOCK_SIZE 16 +/* The max key length of all supported algorithms */ +#define MY_AES_MAX_KEY_LENGTH 32 + + #include "rijndael.h" C_MODE_START @@ -54,8 +62,7 @@ C_MODE_START @param key_length [in] Length of the key. 16, 24 or 32 @param iv [in] Iv to be used for encryption @param iv_length [in] Length of the iv. should be 16. - @param noPadding [in] if set to true, no padding is used, input data size must - be a mulitple of the AES block size + @param noPadding [in] if set, algorithm specific padding behaviour is used Method used defined by calling my_aes_init_dynamic_encrypt() at startup. @@ -85,7 +92,7 @@ extern my_aes_encrypt_dynamic_type my_aes_encrypt_dynamic; @param key_length [in] Length of the key. 16, 24 or 32 @param iv [in] Iv to be used for encryption @param iv_length [in] Length of the iv. should be 16. - @param noPadding [in] if set to true, no padding is used, input data size must be a mulitple of the AES block size + @param noPadding [in] if set, algorithm specific padding behaviour is used @return != 0 error diff --git a/include/my_crypt_key_management.h b/include/my_crypt_key_management.h index 619ac6c11fb..99643d654e1 100644 --- a/include/my_crypt_key_management.h +++ b/include/my_crypt_key_management.h @@ -21,7 +21,17 @@ C_MODE_START /** * function returning latest key version */ -typedef unsigned int (* GetLatestCryptoKeyVersionFunc_t)(); +typedef int (* GetLatestCryptoKeyVersionFunc_t)(); + +/** + * function returning if the key exists + */ +typedef unsigned int (* HasKeyVersionFunc_t)(unsigned int version); + +/** + * function returning the key size + */ +typedef int (* GetKeySizeFunc_t)(unsigned int version); /** * function returning a key for a key version @@ -30,11 +40,21 @@ typedef int (* GetCryptoKeyFunc_t)(unsigned int version, unsigned char* key, unsigned keybufsize); +/** + * function returning an iv for a key version + */ +typedef int (* GetCryptoIVFunc_t)(unsigned int version, + unsigned char* iv, + unsigned ivbufsize); + struct CryptoKeyFuncs_t { GetLatestCryptoKeyVersionFunc_t getLatestCryptoKeyVersionFunc; + HasKeyVersionFunc_t hasCryptoKeyFunc; + GetKeySizeFunc_t getCryptoKeySize; GetCryptoKeyFunc_t getCryptoKeyFunc; + GetCryptoIVFunc_t getCryptoIVFunc; }; /** @@ -47,9 +67,13 @@ InstallCryptoKeyFunctions(const struct CryptoKeyFuncs_t* cryptoKeyFuncs); * Functions to interact with key management */ -unsigned int GetLatestCryptoKeyVersion(); +int GetLatestCryptoKeyVersion(); +unsigned int HasCryptoKey(unsigned int version); +int GetCryptoKeySize(unsigned int version); int GetCryptoKey(unsigned int version, unsigned char* key_buffer, unsigned int size); +int GetCryptoIV(unsigned int version, unsigned char* key_buffer, + unsigned int size); C_MODE_END diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h index 07f3c26ba74..b610daabb06 100644 --- a/include/mysql/plugin.h +++ b/include/mysql/plugin.h @@ -89,7 +89,8 @@ typedef struct st_mysql_xid MYSQL_XID; #define MYSQL_REPLICATION_PLUGIN 6 /* The replication plugin type */ #define MYSQL_AUTHENTICATION_PLUGIN 7 /* The authentication plugin type */ #define MYSQL_VALIDATE_PASSWORD_PLUGIN 8 /* validate password plugin type */ -#define MYSQL_MAX_PLUGIN_TYPE_NUM 9 /* The number of plugin types */ +#define MYSQL_KEY_MANAGEMENT_PLUGIN 9 /* The number of plugin types */ +#define MYSQL_MAX_PLUGIN_TYPE_NUM 10 /* The number of plugin types */ /* We use the following strings to define licenses for plugins */ #define PLUGIN_LICENSE_PROPRIETARY 0 diff --git a/mysql-test/suite/innodb/t/innodb-page_encryption-32k-master.opt b/mysql-test/suite/innodb/t/innodb-page_encryption-32k-master.opt index 0c479718e27..a2d8b7ab11a 100644 --- a/mysql-test/suite/innodb/t/innodb-page_encryption-32k-master.opt +++ b/mysql-test/suite/innodb/t/innodb-page_encryption-32k-master.opt @@ -1 +1 @@ ---default_storage_engine=InnoDB --innodb-buffer-pool-size=24M --innodb_data_encryption_providertype=1 --innodb_data_encryption_providername=keys.txt --innodb_data_encryption_providerurl=$MYSQL_TEST_DIR/suite/innodb/include +--default_storage_engine=InnoDB --innodb-buffer-pool-size=24M --file_key_management_plugin_filename=$MYSQL_TEST_DIR/suite/innodb/include/keys.txt
\ No newline at end of file diff --git a/mysql-test/suite/innodb/t/innodb-page_encryption.opt b/mysql-test/suite/innodb/t/innodb-page_encryption.opt index 8f9ce8c88ed..ca1d5d1ef18 100644 --- a/mysql-test/suite/innodb/t/innodb-page_encryption.opt +++ b/mysql-test/suite/innodb/t/innodb-page_encryption.opt @@ -1 +1 @@ ---innodb_data_encryption_providertype=1 --innodb_data_encryption_providername=keys.txt --innodb_data_encryption_providerurl=$MYSQL_TEST_DIR/suite/innodb/include
\ No newline at end of file +--enable-file_key_management_plugin --file_key_management_plugin_filename=$MYSQL_TEST_DIR/suite/innodb/include/keys.txt diff --git a/mysql-test/suite/innodb/t/innodb-page_encryption_compression.opt b/mysql-test/suite/innodb/t/innodb-page_encryption_compression.opt index 8f9ce8c88ed..da28287f7a4 100644 --- a/mysql-test/suite/innodb/t/innodb-page_encryption_compression.opt +++ b/mysql-test/suite/innodb/t/innodb-page_encryption_compression.opt @@ -1 +1 @@ ---innodb_data_encryption_providertype=1 --innodb_data_encryption_providername=keys.txt --innodb_data_encryption_providerurl=$MYSQL_TEST_DIR/suite/innodb/include
\ No newline at end of file +--enable-file_key_management_plugin --file_key_management_plugin_filename=$MYSQL_TEST_DIR/suite/innodb/include/keys.txt
\ No newline at end of file diff --git a/mysys_ssl/my_aes.cc b/mysys_ssl/my_aes.cc index 22ea3d164ba..20bd03551c2 100644 --- a/mysys_ssl/my_aes.cc +++ b/mysys_ssl/my_aes.cc @@ -139,7 +139,7 @@ void my_aes_hex2uint(const char* in, unsigned char *out, int dest_length) void my_bytes_to_key(const unsigned char *salt, const char *secret, unsigned char *key, unsigned char *iv) { - #ifdef HAVE_YASSL +#ifdef HAVE_YASSL /* the yassl function has no support for SHA1. Reason unknown. */ int keyLen = 32; int ivLen = 16; @@ -188,7 +188,7 @@ void my_bytes_to_key(const unsigned char *salt, const char *secret, unsigned cha ivLeft -= store; } } -#elif HAVE_OPENSSL +#elif defined(HAVE_OPENSSL) const EVP_CIPHER *type = EVP_aes_256_cbc(); const EVP_MD *digest = EVP_sha1(); EVP_BytesToKey(type, digest, salt, (uchar*) secret, strlen(secret), 1, key, iv); @@ -208,8 +208,9 @@ void my_bytes_to_key(const unsigned char *salt, const char *secret, unsigned cha @param key_length [in] Length of the key. 16, 24 or 32 @param iv [in] Iv to be used for encryption @param iv_length [in] Length of the iv. should be 16. - @param noPadding [in] if set to true, no padding is used, input data size must - be a multiple of the AES block size + @param noPadding [in] if set to true, no padding is used. if the input length is not a + multiple of the AES block size, trailing bytes are only copied to destination buffer. + This allows currently the same interface for CBC, ECB and CTR encryption. @return != 0 error 0 no error @@ -221,8 +222,8 @@ static int my_aes_encrypt_cbc(const uchar* source, uint32 source_length, const unsigned char* iv, uint8 iv_length, uint noPadding) { - if (noPadding && (source_length % MY_AES_BLOCK_SIZE) !=0) - return AES_BAD_DATA; + uint8 remaining_bytes = (noPadding == 0) ? 0 : source_length % MY_AES_BLOCK_SIZE; + source_length = source_length - remaining_bytes; #ifdef HAVE_YASSL TaoCrypt::AES_CBC_Encryption enc; @@ -254,7 +255,10 @@ static int my_aes_encrypt_cbc(const uchar* source, uint32 source_length, } if (noPadding) { - *dest_length = MY_AES_BLOCK_SIZE * (num_blocks); + if (remaining_bytes!=0) { + memcpy(dest + source_length, source + source_length, remaining_bytes); + } + *dest_length = MY_AES_BLOCK_SIZE * (num_blocks) + remaining_bytes; return AES_OK; } @@ -305,7 +309,11 @@ static int my_aes_encrypt_cbc(const uchar* source, uint32 source_length, return AES_BAD_DATA; /* Error */ if (! EVP_EncryptFinal_ex(&ctx.ctx, (unsigned char *) dest + u_len, &f_len)) return AES_BAD_DATA; /* Error */ - *dest_length = (unsigned long int) (u_len + f_len); + + if (remaining_bytes!=0) { + memcpy(dest + source_length, source + source_length, remaining_bytes); + } + *dest_length = (unsigned long int) (u_len + f_len + remaining_bytes); return AES_OK; #else @@ -328,8 +336,9 @@ static int my_aes_encrypt_cbc(const uchar* source, uint32 source_length, @param key_length [in] Length of the key. 16, 24 or 32 @param iv [in] Iv to be used for encryption @param iv_length [in] Length of the iv. should be 16. - @param noPadding [in] if set to true, no padding is used, input data size must - be a multiple of the AES block size + @param noPadding [in] if set to true, no padding is used. if the input length is not a + multiple of the AES block size, trailing bytes are only copied to destination buffer. + This allows currently the same interface for CBC, ECB and CTR encryption. @return != 0 error 0 no error @@ -341,8 +350,8 @@ static int my_aes_encrypt_ecb(const uchar* source, uint32 source_length, const unsigned char* iv, uint8 iv_length, uint noPadding) { - if (noPadding && (source_length % MY_AES_BLOCK_SIZE) !=0) - return AES_BAD_DATA; + uint8 remaining_bytes = (noPadding == 0) ? 0 : source_length % MY_AES_BLOCK_SIZE; + source_length = source_length - remaining_bytes; #ifdef HAVE_YASSL TaoCrypt::AES_ECB_Encryption enc; @@ -374,7 +383,10 @@ static int my_aes_encrypt_ecb(const uchar* source, uint32 source_length, } if (noPadding) { - *dest_length = MY_AES_BLOCK_SIZE * (num_blocks); + if (remaining_bytes!=0) { + memcpy(dest + source_length, source + source_length, remaining_bytes); + } + *dest_length = MY_AES_BLOCK_SIZE * (num_blocks) + remaining_bytes; return AES_OK; } @@ -425,7 +437,11 @@ static int my_aes_encrypt_ecb(const uchar* source, uint32 source_length, return AES_BAD_DATA; /* Error */ if (! EVP_EncryptFinal_ex(&ctx.ctx, (unsigned char *) dest + u_len, &f_len)) return AES_BAD_DATA; /* Error */ - *dest_length = (unsigned long int) (u_len + f_len); + + if (remaining_bytes!=0) { + memcpy(dest + source_length, source + source_length, remaining_bytes); + } + *dest_length = (unsigned long int) (u_len + f_len + remaining_bytes); return AES_OK; #else @@ -449,7 +465,9 @@ static int my_aes_encrypt_ecb(const uchar* source, uint32 source_length, @param key_length [in] Length of the key. 16, 24 or 32 @param iv [in] Iv to be used for encryption @param iv_length [in] Length of the iv. should be 16. - @param noPadding [in] if set to true, no padding is used, input data size must be a mulitple of the AES block size + @param noPadding [in] if set to true, no padding is used. if the input length is not a + multiple of the AES block size, trailing bytes are only copied to destination buffer. + This allows currently the same interface for CBC, ECB and CTR encryption. @return != 0 error @@ -462,8 +480,9 @@ static int my_aes_decrypt_cbc(const uchar* source, uint32 source_length, const unsigned char* iv, uint8 iv_length, uint noPadding) { - if (noPadding && (source_length % MY_AES_BLOCK_SIZE) !=0) - return AES_BAD_DATA; + uint8 remaining_bytes = (noPadding == 0) ? 0 : source_length % MY_AES_BLOCK_SIZE; + source_length = source_length - remaining_bytes; + #ifdef HAVE_YASSL TaoCrypt::AES_CBC_Decryption dec; @@ -504,7 +523,10 @@ static int my_aes_decrypt_cbc(const uchar* source, uint32 source_length, if (noPadding) { memcpy(dest, block, MY_AES_BLOCK_SIZE); - *dest_length = MY_AES_BLOCK_SIZE * num_blocks; + if (remaining_bytes!=0) { + memcpy(dest + source_length, source + source_length, remaining_bytes); + } + *dest_length = MY_AES_BLOCK_SIZE * num_blocks + remaining_bytes; return AES_OK; } @@ -554,7 +576,10 @@ static int my_aes_decrypt_cbc(const uchar* source, uint32 source_length, *dest_length = (unsigned long int) u_len; return AES_BAD_DATA; } - *dest_length = (unsigned long int) (u_len + f_len); + if (remaining_bytes!=0) { + memcpy(dest + source_length, source + source_length, remaining_bytes); + } + *dest_length = (unsigned long int) (u_len + f_len) + remaining_bytes; #endif return AES_OK; } @@ -572,7 +597,9 @@ static int my_aes_decrypt_cbc(const uchar* source, uint32 source_length, @param key_length [in] Length of the key. 16, 24 or 32 @param iv [in] Iv to be used for encryption @param iv_length [in] Length of the iv. should be 16. - @param noPadding [in] if set to true, no padding is used, input data size must be a mulitple of the AES block size + @param noPadding [in] if set to true, no padding is used. if the input length is not a + multiple of the AES block size, trailing bytes are only copied to destination buffer. + This allows currently the same interface for CBC, ECB and CTR encryption. @return != 0 error @@ -585,8 +612,9 @@ static int my_aes_decrypt_ecb(const uchar* source, uint32 source_length, const unsigned char* iv, uint8 iv_length, uint noPadding) { - if (noPadding && (source_length % MY_AES_BLOCK_SIZE) !=0) - return AES_BAD_DATA; + uint8 remaining_bytes = (noPadding == 0) ? 0 : source_length % MY_AES_BLOCK_SIZE; + source_length = source_length - remaining_bytes; + #ifdef HAVE_YASSL TaoCrypt::AES_ECB_Decryption dec; @@ -627,7 +655,10 @@ static int my_aes_decrypt_ecb(const uchar* source, uint32 source_length, if (noPadding) { memcpy(dest, block, MY_AES_BLOCK_SIZE); - *dest_length = MY_AES_BLOCK_SIZE * num_blocks; + if (remaining_bytes!=0) { + memcpy(dest + source_length, source + source_length, remaining_bytes); + } + *dest_length = MY_AES_BLOCK_SIZE * num_blocks + remaining_bytes; return AES_OK; } @@ -677,7 +708,11 @@ static int my_aes_decrypt_ecb(const uchar* source, uint32 source_length, *dest_length = (unsigned long int) u_len; return AES_BAD_DATA; } - *dest_length = (unsigned long int) (u_len + f_len); + if (remaining_bytes!=0) { + memcpy(dest + source_length, source + source_length, remaining_bytes); + } + *dest_length = (unsigned long int) (u_len + f_len) + remaining_bytes; + #endif return AES_OK; } @@ -687,7 +722,7 @@ static int my_aes_decrypt_ecb(const uchar* source, uint32 source_length, /** - Encryption interface that doesn't do anyting (for testing) + Encryption interface that doesn't do anything (for testing) SYNOPSIS my_aes_encrypt_none() @@ -699,8 +734,7 @@ static int my_aes_decrypt_ecb(const uchar* source, uint32 source_length, @param key_length [in] Length of the key. 16, 24 or 32 @param iv [in] Iv to be used for encryption @param iv_length [in] Length of the iv. should be 16. - @param noPadding [in] if set to true, no padding is used, input data size must - be a multiple of the AES block size + @param noPadding [in] unused @return != 0 error 0 no error @@ -719,7 +753,7 @@ static int my_aes_encrypt_none(const uchar* source, uint32 source_length, /** - Decryption interface that doesn't do anyting (for testing) + Decryption interface that doesn't do anything (for testing) SYNOPSIS my_aes_decrypt_none() @@ -731,7 +765,7 @@ static int my_aes_encrypt_none(const uchar* source, uint32 source_length, @param key_length [in] Length of the key. 16, 24 or 32 @param iv [in] Iv to be used for encryption @param iv_length [in] Length of the iv. should be 16. - @param noPadding [in] if set to true, no padding is used, input data size must be a multiple of the AES block size + @param noPadding [in] unused @return != 0 error diff --git a/mysys_ssl/my_crypt_key_management.cc b/mysys_ssl/my_crypt_key_management.cc index 9e39642bcdc..94199403b4a 100644 --- a/mysys_ssl/my_crypt_key_management.cc +++ b/mysys_ssl/my_crypt_key_management.cc @@ -18,9 +18,13 @@ unsigned int opt_danger_danger_dbug_crypto_key_version = 0; /** * Default functions */ -unsigned int GetLatestCryptoKeyVersionImpl(); +int GetLatestCryptoKeyVersionImpl(); +unsigned int HasCryptoKeyImpl(unsigned int version); +int GetCryptoKeySizeImpl(unsigned int version); int GetCryptoKeyImpl(unsigned int version, unsigned char* key_buffer, unsigned int size); +int GetCryptoIVImpl(unsigned int version, unsigned char* key_buffer, + unsigned int size); /** * Function pointers for @@ -30,11 +34,14 @@ int GetCryptoKeyImpl(unsigned int version, unsigned char* key_buffer, static struct CryptoKeyFuncs_t cryptoKeyFuncs = { GetLatestCryptoKeyVersionImpl, - GetCryptoKeyImpl + HasCryptoKeyImpl, + GetCryptoKeySizeImpl, + GetCryptoKeyImpl, + GetCryptoIVImpl }; extern "C" -unsigned int GetLatestCryptoKeyVersion() { +int GetLatestCryptoKeyVersion() { #ifndef DBUG_OFF if (opt_danger_danger_use_dbug_keys) { mysql_rwlock_rdlock(&LOCK_dbug_crypto_key_version); @@ -48,6 +55,16 @@ unsigned int GetLatestCryptoKeyVersion() { } extern "C" +unsigned int HasCryptoKey(unsigned int version) { + return (* cryptoKeyFuncs.hasCryptoKeyFunc)(version); +} + +extern "C" +int GetCryptoKeySize(unsigned int version) { + return (* cryptoKeyFuncs.getCryptoKeySize)(version); +} + +extern "C" int GetCryptoKey(unsigned int version, unsigned char* key, unsigned int size) { #ifndef DBUG_OFF if (opt_danger_danger_use_dbug_keys) { @@ -67,16 +84,27 @@ int GetCryptoKey(unsigned int version, unsigned char* key, unsigned int size) { } extern "C" +int GetCryptoIV(unsigned int version, unsigned char* key, unsigned int size) { + return (* cryptoKeyFuncs.getCryptoIVFunc)(version, key, size); +} + +extern "C" void InstallCryptoKeyFunctions(const struct CryptoKeyFuncs_t* _cryptoKeyFuncs) { if (_cryptoKeyFuncs == NULL) { - /* restore defaults when called with NULL argument */ + /* restore defaults wHashhen called with NULL argument */ cryptoKeyFuncs.getLatestCryptoKeyVersionFunc = GetLatestCryptoKeyVersionImpl; + cryptoKeyFuncs.hasCryptoKeyFunc = + HasCryptoKeyImpl; + cryptoKeyFuncs.getCryptoKeySize = + GetCryptoKeySizeImpl; cryptoKeyFuncs.getCryptoKeyFunc = GetCryptoKeyImpl; + cryptoKeyFuncs.getCryptoIVFunc = + GetCryptoIVImpl; } else { diff --git a/mysys_ssl/my_crypt_key_management_impl.cc b/mysys_ssl/my_crypt_key_management_impl.cc index 23c87c9208a..ece4b72c372 100644 --- a/mysys_ssl/my_crypt_key_management_impl.cc +++ b/mysys_ssl/my_crypt_key_management_impl.cc @@ -1,7 +1,17 @@ #include <my_global.h> // TODO Not yet implemented. -unsigned int GetLatestCryptoKeyVersionImpl() +int GetLatestCryptoKeyVersionImpl() +{ + abort(); +} + +unsigned int HasCryptoKeyImpl(unsigned int version) +{ + abort(); +} + +int GetCryptoKeySizeImpl(unsigned int version) { abort(); } @@ -11,3 +21,9 @@ int GetCryptoKeyImpl(unsigned int version, unsigned char* key, { abort(); } + +int GetCryptoIVImpl(unsigned int version, unsigned char* key, + unsigned int key_size) +{ + abort(); +} diff --git a/plugin/example_key_management_plugin/example_key_management_plugin.cc b/plugin/example_key_management_plugin/example_key_management_plugin.cc index 19fac2ca38c..5785d264c60 100644 --- a/plugin/example_key_management_plugin/example_key_management_plugin.cc +++ b/plugin/example_key_management_plugin/example_key_management_plugin.cc @@ -2,6 +2,7 @@ #include <mysql_version.h> #include <my_global.h> +#include <my_aes.h> #include <my_crypt_key_management.h> #include <my_md5.h> @@ -15,7 +16,7 @@ static unsigned int next_key_version = 0; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static -unsigned int +int get_latest_key_version() { uint now = time(0); @@ -50,15 +51,44 @@ get_key(unsigned int version, unsigned char* dstbuf, unsigned buflen) return 0; } +static unsigned int has_key_func(unsigned int keyID) +{ + return true; +} + +static int get_key_size(unsigned int keyID) +{ + return 16; +} + +static int get_iv(unsigned int keyID, unsigned char* dstbuf, unsigned buflen) +{ + if (buflen < 16) + { + return CRYPT_BUFFER_TO_SMALL; + } + + for (int i=0; i<16; i++) + dstbuf[i] = 0; + + return CRYPT_KEY_OK; +} + + static int example_key_management_plugin_init(void *p) { /* init */ seed = time(0); get_latest_key_version(); + my_aes_init_dynamic_encrypt(MY_AES_ALGORITHM_CTR); + struct CryptoKeyFuncs_t func; func.getLatestCryptoKeyVersionFunc = get_latest_key_version; + func.hasCryptoKeyFunc = has_key_func; + func.getCryptoKeySize = get_key_size; func.getCryptoKeyFunc = get_key; + func.getCryptoIVFunc = get_iv; InstallCryptoKeyFunctions(&func); return 0; } diff --git a/plugin/file_key_management_plugin/CMakeLists.txt b/plugin/file_key_management_plugin/CMakeLists.txt index a4eb490c9a7..49196448e2b 100644 --- a/plugin/file_key_management_plugin/CMakeLists.txt +++ b/plugin/file_key_management_plugin/CMakeLists.txt @@ -1,3 +1,3 @@ -SET(FILE_KEY_MANAGEMENT_PLUGIN_SOURCES file_key_management_plugin.cc ) +SET(FILE_KEY_MANAGEMENT_PLUGIN_SOURCES file_key_management_plugin.cc EncKeys.cc KeySingleton.cc) -MYSQL_ADD_PLUGIN(FILE_KEY_MANAGEMENT_PLUGIN ${FILE_KEY_MANAGEMENT_PLUGIN_SOURCES} MANDATORY) +MYSQL_ADD_PLUGIN(FILE_KEY_MANAGEMENT_PLUGIN ${FILE_KEY_MANAGEMENT_PLUGIN_SOURCES} DEFAULT) diff --git a/plugin/file_key_management_plugin/EncKeys.cc b/plugin/file_key_management_plugin/EncKeys.cc index cabdf7911a0..c43d261926a 100644 --- a/plugin/file_key_management_plugin/EncKeys.cc +++ b/plugin/file_key_management_plugin/EncKeys.cc @@ -23,37 +23,43 @@ Example [mysqld] ... -innodb_data_encryption_providertype = 1 -innodb_data_encryption_providername = keys.enc -innodb_data_encryption_providerurl = /home/mdb/ -innodb_data_encryption_filekey = secret +file_key_management_plugin_filename = /home/mdb/keys.enc +file_key_management_plugin_filekey = secret +file_key_management_plugin_encryption_method = aes_cbc + ... +Optional configuration value file_key_management_plugin_encryption_method determines the method used for encryption. +Supported are aes_cbc, aes_ecb or aes_ctr. aes_cbc is default. +The plug-in sets the default aes encryption/decryption method to the given method. + +The keys are read from a file. +The filename is set up via the file_key_management_plugin_filename configuration value. +file_key_management_plugin_filename is used to configure the absolute path to this file. -As provider type currently only value 1 is supported, which means, the keys are read from a file. -The filename is set up via the innodb_data_encryption_providername configuration value. -innodb_data_encryption_providerurl is used to configure the path to this file. This is usually -a folder name. Examples: -innodb_data_encryption_providerurl = \\\\unc (windows share) -innodb_data_encryption_providerurl = e:/tmp/ (windows path) -innodb_data_encryption_providerurl = /tmp (linux path) +file_key_management_plugin_filename = \\\\unc\\keys.enc (windows share) +file_key_management_plugin_filename = e:/tmp/keys.enc (windows path) +file_key_management_plugin_filename = /tmp/keys.enc (linux path) The key file contains AES keys and initialization vectors as hex-encoded Strings. Supported are keys of size 128, 192 or 256 bits. IV consists of 16 bytes. +Example: +1;F5502320F8429037B8DAEF761B189D12;770A8A65DA156D24EE2A093277530142 + +1 is the key identifier which can be used for table creation, a 16 byte IV follows, and finally a 16 byte AES key. +255 entries are supported. The key file should be encrypted and the key to decrypt the file can be given with the -innodb_data_encryption_filekey parameter. +optional file_key_management_plugin_filekey parameter. The file key can also be located if FILE: is prepended to the key. Then the following part is interpreted -as absolut to the file containing the file key. This file can optionally be encrypted, currently with a fix key. +as absolute path to the file containing the file key. This file can optionally be encrypted, currently with a fix key. Example: -innodb_data_encryption_filekey = FILE:y:/secret256.enc +file_key_management_plugin_filekey = FILE:y:/secret256.enc If the key file can not be read at server startup, for example if the file key is not present, page_encryption feature is not availabe and access to page_encryption tables is not possible. -Example files can be found inside the unittest/eperi folder. - Open SSL command line utility can be used to create an encrypted key file. Examples: openssl enc –aes-256-cbc –md sha1 –k secret –in keys.txt –out keys.enc @@ -67,6 +73,7 @@ openssl enc –aes-256-cbc –md sha1 –k <initialPwd> –in secret –out secr #include "EncKeys.h" #include <my_global.h> + #include <my_aes.h> #include <memory.h> #include <my_sys.h> @@ -119,59 +126,34 @@ EncKeys::~EncKeys() { } } -bool EncKeys::initKeys(const char *name, const char *url, const int initType, const char *filekey) { - if (KEYINITTYPE_FILE == initType) - { - int result = initKeysThroughFile(name, url, filekey); - return ERROR_FALSE_FILE_KEY != result && ERROR_OPEN_FILE != result && ERROR_READING_FILE != result; - } - else if (KEYINITTYPE_SERVER == initType) - { - return NO_ERROR_KEY_FILE_PARSE_OK == initKeysThroughServer(name, url, filekey); - } - return false; -} +bool EncKeys::initKeys(const char *filename, const char *filekey) { + if (filename==NULL) + return ERROR_OPEN_FILE; -int EncKeys::initKeysThroughFile(const char *name, const char *path, const char *filekey) { - if (path==NULL || name==NULL) return ERROR_OPEN_FILE; - size_t len1 = strlen(path); - size_t len2 = strlen(name); const char *MAGIC = "FILE:"; const short MAGIC_LEN = 5; - int ret = NO_ERROR_KEY_FILE_PARSE_OK; - bool isUncPath= (len1>2) ? ((strncmp("\\\\", path, 2)==0) ? TRUE : FALSE) : FALSE; - bool isSlash = ((isUncPath? '\\':'/') == path[len1 - 1]); - char *secret = (char*) malloc(MAX_SECRET_SIZE +1 * sizeof(char)); - char *filename = (char*) malloc((len1 + len2 + (isSlash ? 1 : 2)) * sizeof(char)); - if(filekey != NULL) + + char *secret = (char*) malloc(MAX_SECRET_SIZE +1 * sizeof(char)); + + if(filekey != NULL) + { + //If secret starts with FILE: interpret the secret as filename. + if(memcmp(MAGIC, filekey, MAGIC_LEN) == 0) { + int fk_len = strlen(filekey); + char *secretfile = (char*)malloc( (1 + fk_len - MAGIC_LEN)* sizeof(char)); + memcpy(secretfile, filekey+MAGIC_LEN, fk_len - MAGIC_LEN); + secretfile[fk_len-MAGIC_LEN] = '\0'; + parseSecret(secretfile, secret); + free(secretfile); + } else { - //If secret starts with FILE: interpret the secret as filename. - if(memcmp(MAGIC, filekey, MAGIC_LEN) == 0) { - int fk_len = strlen(filekey); - char *secretfile = (char*)malloc( (1 + fk_len - MAGIC_LEN)* sizeof(char)); - memcpy(secretfile, filekey+MAGIC_LEN, fk_len - MAGIC_LEN); - secretfile[fk_len-MAGIC_LEN] = '\0'; - parseSecret(secretfile, secret); - free(secretfile); - } else - { - sprintf(secret, "%s", filekey); - } + sprintf(secret, "%s", filekey); } - sprintf(filename, "%s%s%s", path, isSlash ? "" : (isUncPath ? "\\":"/"), name); - ret = parseFile((const char *)filename, 254, secret); - free(filename); - free(secret); - return ret; -} + } -int EncKeys::initKeysThroughServer( const char *name, const char *path, const char *filekey) -{ - //TODO -#ifdef UNIV_DEBUG - fprintf(stderr, errorNotImplemented); -#endif //UNIV_DEBUG - return ERROR_KEYINITTYPE_SERVER_NOT_IMPLEMENTED; + int ret = parseFile((const char *)filename, 254, secret); + free(secret); + return (ret==NO_ERROR_KEY_FILE_PARSE_OK); } /* @@ -181,7 +163,6 @@ void EncKeys::parseSecret( const char *secretfile, char *secret ) { int maxSize = (MAX_SECRET_SIZE +16 + magicSize*2) ; char* buf = (char*)malloc((maxSize) * sizeof(char)); char* _initPwd = (char*)malloc((strlen(initialPwd)+1) * sizeof(char)); - FILE *fp = fopen(secretfile, "rb"); fseek(fp, 0L, SEEK_END); long file_size = ftell(fp); @@ -201,8 +182,9 @@ void EncKeys::parseSecret( const char *secretfile, char *secret ) { _initPwd[strlen(initialPwd)]= '\0'; my_bytes_to_key((unsigned char *) salt, _initPwd, key, iv); uint32 d_size = 0; - int res = my_aes_decrypt_cbc((const char*)buf + 2 * magicSize, bytes_to_read - 2 * magicSize, - secret, &d_size, key, keySize32, iv, ivSize16, 0); + my_aes_decrypt_dynamic_type func = get_aes_decrypt_func(MY_AES_ALGORITHM_CBC); + int res = (* func)((const uchar*)buf + 2 * magicSize, bytes_to_read - 2 * magicSize, + (uchar*)secret, &d_size, (const uchar*)key, keySize32, iv, ivSize16, 0); if (d_size>EncKeys::MAX_SECRET_SIZE) { d_size = EncKeys::MAX_SECRET_SIZE; } @@ -237,10 +219,10 @@ keyentry *EncKeys::getKeys(int id) { * Store the keys with id smaller then <maxKeyId> in an array of structs keyentry. * Returns NO_ERROR_PARSE_OK or an appropriate error code. */ -int EncKeys::parseFile(const char* filename, const ulint maxKeyId, const char *secret) { +int EncKeys::parseFile(const char* filename, const uint32 maxKeyId, const char *secret) { int errorCode = 0; char *buffer = decryptFile(filename, secret, &errorCode); - ulint id = 0; + uint32 id = 0; if (NO_ERROR_PARSE_OK != errorCode) return errorCode; else errorCode = NO_ERROR_KEY_FILE_PARSE_OK; @@ -258,17 +240,17 @@ int EncKeys::parseFile(const char* filename, const ulint maxKeyId, const char *s break; case ERROR_ID_TOO_BIG: fprintf(stderr, errorExceedKeySize, KEY_MAX, keyLineInKeyFile); - fprintf(stderr, " --> %s\n", line); + fprintf(stderr, " ---> %s\n", line); errorCode = ERROR_KEY_FILE_EXCEEDS_MAX_NUMBERS_OF_KEYS; break; case ERROR_NOINITIALIZEDKEY: fprintf(stderr, errorNoInitializedKey); - fprintf(stderr, " --> %s\n", line); + fprintf(stderr, " ----> %s\n", line); errorCode = ERROR_KEY_FILE_PARSE_NULL; break; case ERROR_WRONG_NUMBER_OF_MATCHES: fprintf(stderr, errorInMatches, keyLineInKeyFile); - fprintf(stderr, " --> %s\n", line); + fprintf(stderr, " -----> %s\n", line); errorCode = ERROR_KEY_FILE_PARSE_NULL; break; case NO_ERROR_KEY_GREATER_THAN_ASKED: @@ -287,7 +269,7 @@ int EncKeys::parseFile(const char* filename, const ulint maxKeyId, const char *s return errorCode; } -int EncKeys::parseLine(const char *line, const ulint maxKeyId) { +int EncKeys::parseLine(const char *line, const uint32 maxKeyId) { int ret = NO_ERROR_PARSE_OK; if (isComment(line)) ret = NO_ERROR_ISCOMMENT; @@ -314,7 +296,7 @@ int EncKeys::parseLine(const char *line, const ulint maxKeyId) { else { char buffer[4]; sprintf(buffer, "%.*s", substr_length, substring_start); - ulint id = atoi(buffer); + uint32 id = atoi(buffer); if (0 == id) ret = ERROR_NOINITIALIZEDKEY; else if (KEY_MAX < id) ret = ERROR_ID_TOO_BIG; else if (maxKeyId < id) ret = NO_ERROR_KEY_GREATER_THAN_ASKED; @@ -381,12 +363,13 @@ char* EncKeys::decryptFile(const char* filename, const char *secret, int *errorC unsigned char salt[magicSize]; unsigned char *key = new unsigned char[keySize32]; unsigned char *iv = new unsigned char[ivSize16]; - char *decrypted = new char[file_size]; + uchar *decrypted = new uchar[file_size]; memcpy(&salt, buffer + magicSize, magicSize); my_bytes_to_key((unsigned char *) salt, secret, key, iv); uint32 d_size = 0; - int res = my_aes_decrypt_cbc((const char*)buffer + 2 * magicSize, file_size - 2 * magicSize, - decrypted, &d_size, key, keySize32, iv, ivSize16, 0); + my_aes_decrypt_dynamic_type func = get_aes_decrypt_func(MY_AES_ALGORITHM_CBC); + int res = (* func)((const uchar*)buffer + 2 * magicSize, file_size - 2 * magicSize, + decrypted, &d_size, (const uchar*) key, keySize32, iv, ivSize16, 0); if(0 != res) { *errorCode = ERROR_FALSE_FILE_KEY; delete[] buffer; buffer = NULL; @@ -415,7 +398,7 @@ bool EncKeys::isComment(const char *line) { } -void EncKeys::printKeyEntry( ulint id) +void EncKeys::printKeyEntry( uint32 id) { #ifdef UNIV_DEBUG keyentry *entry = getKeys(id); diff --git a/plugin/file_key_management_plugin/EncKeys.h b/plugin/file_key_management_plugin/EncKeys.h index ec05c8667df..c2b56047a6e 100644 --- a/plugin/file_key_management_plugin/EncKeys.h +++ b/plugin/file_key_management_plugin/EncKeys.h @@ -23,15 +23,16 @@ Created 09/15/2014 #ifndef ENCKEYS_H_ #define ENCKEYS_H_ -#include "my_global.h" +#include <my_global.h> #include <sys/types.h> #include <stdio.h> + struct keyentry { - ulint id; + uint32 id; char *iv; char *key; }; @@ -58,16 +59,14 @@ private: *errorNotImplemented, *errorOpenFile, *errorReadingFile, *errorFileSize; static const char* initialPwd; - ulint countKeys, keyLineInKeyFile; + uint32 countKeys, keyLineInKeyFile; keyentry keys[MAX_KEYS], *oneKey; - void printKeyEntry( ulint id); - int initKeysThroughFile( const char *name, const char *path, const char *filekey); - int initKeysThroughServer( const char *name, const char *path, const char *filekey); + void printKeyEntry( uint32 id); bool isComment( const char *line); char * decryptFile( const char* filename, const char *secret, int *errorCode); - int parseFile( const char* filename, const ulint maxKeyId, const char *secret); - int parseLine( const char *line, const ulint maxKeyId); + int parseFile( const char* filename, const uint32 maxKeyId, const char *secret); + int parseLine( const char *line, const uint32 maxKeyId); public: static const size_t MAX_SECRET_SIZE = 256; @@ -78,7 +77,7 @@ public: ERROR_KEYINITTYPE_SERVER_NOT_IMPLEMENTED = 170, ERROR_ENCRYPTION_SECRET_NULL = 180 }; EncKeys(); virtual ~EncKeys(); - bool initKeys( const char *name, const char *url, const int initType, const char *filekey); + bool initKeys( const char *filename, const char *filekey); keyentry *getKeys( int id); /* made public for unit testing */ static void parseSecret( const char *filename, char *secret ); diff --git a/plugin/file_key_management_plugin/KeySingleton.cc b/plugin/file_key_management_plugin/KeySingleton.cc index fc633b4f63c..891fe4335f9 100644 --- a/plugin/file_key_management_plugin/KeySingleton.cc +++ b/plugin/file_key_management_plugin/KeySingleton.cc @@ -41,11 +41,10 @@ KeySingleton & KeySingleton::getInstance() { return theInstance; } -KeySingleton & KeySingleton::getInstance(const char *name, const char *url, - const int initType, const char *filekey) { +KeySingleton & KeySingleton::getInstance(const char *filename, const char *filekey) { if(instanceInited) return theInstance; - instanceInited = encKeys.initKeys(name, url, initType, filekey); + instanceInited = encKeys.initKeys(filename, filekey); if( !instanceInited) { fprintf(stderr, "Could not initialize any of the encryption / decryption keys. " "You can not read encrypted tables\n\n"); @@ -59,7 +58,7 @@ keyentry *KeySingleton::getKeys(int id) { return encKeys.getKeys(id); } -ibool KeySingleton::hasKey(int id) { +bool KeySingleton::hasKey(int id) { return encKeys.getKeys(id) != NULL; } diff --git a/plugin/file_key_management_plugin/KeySingleton.h b/plugin/file_key_management_plugin/KeySingleton.h index 2b2f3991998..d66ff44df27 100644 --- a/plugin/file_key_management_plugin/KeySingleton.h +++ b/plugin/file_key_management_plugin/KeySingleton.h @@ -47,10 +47,9 @@ public: virtual ~KeySingleton() {encKeys.~EncKeys();} static KeySingleton& getInstance(); // Init the instance for only one time - static KeySingleton& getInstance(const char *name, const char *url, - const int initType, const char *filekey); + static KeySingleton& getInstance(const char *filename, const char *filekey); keyentry *getKeys(int id); - ibool hasKey(int id); + bool hasKey(int id); static bool isAvailable() { return instanceInited; } diff --git a/plugin/file_key_management_plugin/file_key_management_plugin.cc b/plugin/file_key_management_plugin/file_key_management_plugin.cc index 4fc853d172c..ce0d3aea208 100644 --- a/plugin/file_key_management_plugin/file_key_management_plugin.cc +++ b/plugin/file_key_management_plugin/file_key_management_plugin.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2002, 2012, eperi GmbH. 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 @@ -17,23 +17,176 @@ #include <my_global.h> #include <mysql_version.h> #include <my_aes.h> +#include <my_crypt_key_management.h> +#include <string.h> +#include "sql_class.h" + +//#include "file_key_management_plugin.h" +#include "KeySingleton.h" +#include "EncKeys.h" + + +/* Encryption for tables and columns */ +static char* filename = NULL; +static char* filekey = NULL; +static char* encryption_method = NULL; + +static MYSQL_SYSVAR_STR(encryption_method, encryption_method, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, + "Name of the encryption method. This can be aes_cbc (default) or aes_ctr (requires OpenSSL on Linux).", + NULL, NULL, "aes_cbc"); + +static MYSQL_SYSVAR_STR(filename, filename, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, + "Path and name of the key file.", + NULL, NULL, NULL); + +static MYSQL_SYSVAR_STR(filekey, filekey, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, + "Key to encrypt / decrypt the keyfile.", + NULL, NULL, NULL); + +static struct st_mysql_sys_var* settings[] = { + MYSQL_SYSVAR(encryption_method), + MYSQL_SYSVAR(filename), + MYSQL_SYSVAR(filekey), + NULL +}; + + + +/** + * This method is using with the id 0 if exists. This method is used by innobase/xtradb for the key + * rotation feature of encrypting log files. + */ +static int get_highest_key_used_in_key_file() +{ + if (KeySingleton::getInstance().hasKey(0)) + { + return 0; + } + else + return CRYPT_KEY_UNKNOWN; +} + +static unsigned int has_key_from_key_file(unsigned int keyID) +{ + keyentry* entry = KeySingleton::getInstance().getKeys(keyID); + + return entry != NULL; +} + +static int get_key_size_from_key_file(unsigned int keyID) +{ + keyentry* entry = KeySingleton::getInstance().getKeys(keyID); + + if (entry != NULL) + { + char* keyString = entry->key; + size_t key_len = strlen(keyString)/2; + + return key_len; + } + else + { + return CRYPT_KEY_UNKNOWN; + } +} + +static int get_key_from_key_file(unsigned int keyID, unsigned char* dstbuf, unsigned buflen) +{ + keyentry* entry = KeySingleton::getInstance().getKeys((int)keyID); + + if (entry != NULL) + { + char* keyString = entry->key; + size_t key_len = strlen(keyString)/2; + + if (buflen < key_len) + { + return CRYPT_BUFFER_TO_SMALL; + } + + my_aes_hex2uint(keyString, (unsigned char*)dstbuf, key_len); + + return CRYPT_KEY_OK; + } + else + { + return CRYPT_KEY_UNKNOWN; + } +} + +static int get_iv_from_key_file(unsigned int keyID, unsigned char* dstbuf, unsigned buflen) +{ + keyentry* entry = KeySingleton::getInstance().getKeys((int)keyID); + + if (entry != NULL) + { + char* ivString = entry->iv; + size_t iv_len = strlen(ivString)/2; + + if (buflen < iv_len) + { + return CRYPT_BUFFER_TO_SMALL; + } + + my_aes_hex2uint(ivString, (unsigned char*)dstbuf, iv_len); + + return CRYPT_KEY_OK; + } + else + { + return CRYPT_KEY_UNKNOWN; + } +} + static int file_key_management_plugin_init(void *p) { /* init */ - printf("TO_BE_REMOVED: Loading file_key_management_plugin_init\n"); + printf("@DE: Loading file_key_management_plugin_init \n"); + + /* Setting encryption method */ + if (encryption_method != NULL && strcmp("aes_ctr", encryption_method) == 0) + { + my_aes_init_dynamic_encrypt(MY_AES_ALGORITHM_CTR); + } else if (encryption_method != NULL && strcmp("aes_ecb", encryption_method) == 0) + { + my_aes_init_dynamic_encrypt(MY_AES_ALGORITHM_ECB); + } + else + { + my_aes_init_dynamic_encrypt(MY_AES_ALGORITHM_CBC); + } + - /* Setting to MY_AES_METHOD_CBC for page encryption */ - my_aes_init_dynamic_encrypt(MY_AES_ALGORITHM_CBC); + /* Initializing the key provider */ + struct CryptoKeyFuncs_t func; + func.getLatestCryptoKeyVersionFunc = get_highest_key_used_in_key_file; + func.hasCryptoKeyFunc = has_key_from_key_file; + func.getCryptoKeySize = get_key_size_from_key_file; + func.getCryptoKeyFunc = get_key_from_key_file; + func.getCryptoIVFunc = get_iv_from_key_file; + + InstallCryptoKeyFunctions(&func); + + if (filename == NULL || strcmp("", filename) == 0) + { + sql_print_error("Parameter file_key_management_plugin_filename is required"); + + return 1; + } + + KeySingleton::getInstance(filename, filekey); return 0; } static int file_key_management_plugin_deinit(void *p) { - /** - * don't uninstall... - */ + KeySingleton::getInstance().~KeySingleton(); + return 0; } @@ -46,7 +199,7 @@ struct st_mysql_daemon file_key_management_plugin= { */ maria_declare_plugin(file_key_management_plugin) { - MYSQL_DAEMON_PLUGIN, + MYSQL_KEY_MANAGEMENT_PLUGIN, &file_key_management_plugin, "file_key_management_plugin", "Denis Endro eperi GmbH", @@ -56,7 +209,7 @@ maria_declare_plugin(file_key_management_plugin) file_key_management_plugin_deinit, /* Plugin Deinit */ 0x0100 /* 1.0 */, NULL, /* status variables */ - NULL, /* system variables */ + settings, "1.0", MariaDB_PLUGIN_MATURITY_UNKNOWN } diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 66b0b810717..874e3943e10 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1229,7 +1229,17 @@ static void reap_plugins(void) list= reap; while ((plugin= *(--list))) - plugin_deinitialize(plugin, true); + { + if (plugin->plugin->type != MYSQL_KEY_MANAGEMENT_PLUGIN) + plugin_deinitialize(plugin, true); + } + + list= reap; + while ((plugin= *(--list))) + { + if (plugin->plugin->type == MYSQL_KEY_MANAGEMENT_PLUGIN) + plugin_deinitialize(plugin, true); + } mysql_mutex_lock(&LOCK_plugin); @@ -1529,6 +1539,65 @@ int plugin_init(int *argc, char **argv, int flags) /* First we register builtin plugins */ + mandatory = false; + for (builtins= mysql_optional_plugins; *builtins; builtins++) + { + for (plugin= *builtins; plugin->info; plugin++) + { + if (opt_ignore_builtin_innodb && + !my_strnncoll(&my_charset_latin1, (const uchar*) plugin->name, + 6, (const uchar*) "InnoDB", 6)) + continue; + + if (plugin->type != MYSQL_KEY_MANAGEMENT_PLUGIN) + continue; + + bzero(&tmp, sizeof(tmp)); + tmp.plugin= plugin; + tmp.name.str= (char *)plugin->name; + tmp.name.length= strlen(plugin->name); + tmp.state= 0; + tmp.load_option= mandatory ? PLUGIN_FORCE : PLUGIN_ON; + + for (i=0; i < array_elements(override_plugin_load_policy); i++) + { + if (!my_strcasecmp(&my_charset_latin1, plugin->name, + override_plugin_load_policy[i].plugin_name)) + { + tmp.load_option= override_plugin_load_policy[i].override; + break; + } + } + + free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE)); + tmp.state= PLUGIN_IS_UNINITIALIZED; + if (register_builtin(plugin, &tmp, &plugin_ptr)) + goto err_unlock; + + is_myisam= !my_strcasecmp(&my_charset_latin1, plugin->name, "MyISAM"); + + if (plugin_initialize(&tmp_root, plugin_ptr, argc, argv, !is_myisam && + (flags & PLUGIN_INIT_SKIP_INITIALIZATION))) + { + if (plugin_ptr->load_option == PLUGIN_FORCE) + goto err_unlock; + plugin_ptr->state= PLUGIN_IS_DISABLED; + } + + if (is_myisam) + { + DBUG_ASSERT(!global_system_variables.table_plugin); + global_system_variables.table_plugin= + intern_plugin_lock(NULL, plugin_int_to_ref(plugin_ptr)); + DBUG_ASSERT(plugin_ptr->ref_count == 1); + } + } + } + + /* + First we register builtin plugins + */ + mandatory = true; for (builtins= mysql_mandatory_plugins; *builtins || mandatory; builtins++) { if (!*builtins) @@ -1545,6 +1614,9 @@ int plugin_init(int *argc, char **argv, int flags) 6, (const uchar*) "InnoDB", 6)) continue; + if (plugin->type == MYSQL_KEY_MANAGEMENT_PLUGIN) + continue; + bzero(&tmp, sizeof(tmp)); tmp.plugin= plugin; tmp.name.str= (char *)plugin->name; diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index 5fcd30cfa18..3693620d394 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -359,8 +359,6 @@ SET(INNOBASE_SOURCES dict/dict0stats.cc dict/dict0stats_bg.cc dyn/dyn0dyn.cc - enc/EncKeys.cc - enc/KeySingleton.cc eval/eval0eval.cc eval/eval0proc.cc fil/fil0fil.cc diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index dbc6db8b4b8..49eef1c5f7a 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -16,7 +16,6 @@ #include <my_crypt_key_management.h> #include <my_aes.h> -#include <KeySingleton.h> #include <math.h> @@ -180,18 +179,14 @@ fil_space_crypt_cleanup() Get key bytes for a space/key-version */ static void -fil_crypt_get_key(byte *dst, uint dstlen, +fil_crypt_get_key(byte *dst, uint* key_length, fil_space_crypt_t* crypt_data, uint version, bool page_encrypted) { - /* TODO: Find a better way to do this */ - unsigned char keybuf[CRYPT_SCHEME_1_IV_LEN]; - byte key[CRYPT_SCHEME_1_IV_LEN]; - uint8 key_len = sizeof(keybuf); + unsigned char keybuf[MY_AES_MAX_KEY_LENGTH]; unsigned char iv[CRYPT_SCHEME_1_IV_LEN]; ulint iv_len = sizeof(iv); - bool key_error = false; - if (!page_encrypted) { + if (!page_encrypted) { mutex_enter(&crypt_data->mutex); // Check if we already have key @@ -210,77 +205,82 @@ fil_crypt_get_key(byte *dst, uint dstlen, for (uint i = 1; i < array_elements(crypt_data->keys); i++) { crypt_data->keys[i] = crypt_data->keys[i - 1]; } + } + else + { + // load iv - // TODO(jonaso): Integrate with real key server - int rc = GetCryptoKey(version, keybuf, key_len); - if (rc != 0) { - ib_logf(IB_LOG_LEVEL_FATAL, - "Unable to retrieve key with" - " version %u return-code: %d. Can't continue!\n", - version, rc); - ut_error; - } - } else { - /* For page encrypted tables we need to get the L */ - - /* Get key and IV */ - KeySingleton& keys = KeySingleton::getInstance(); - - if (keys.isAvailable() && keys.getKeys(version) != NULL) { - char* keyString = keys.getKeys(version)->key; - char* ivString = keys.getKeys(version)->iv; + int rc = GetCryptoIV(version, (unsigned char*)iv, iv_len); - if (keyString == NULL || ivString == NULL) { - key_error=true; - } else { - my_aes_hex2uint(keyString, (unsigned char*)&keybuf, key_len); - my_aes_hex2uint(ivString, (unsigned char*)&iv, iv_len); - } - } else { - key_error = true; - } - - if (key_error == true) { - ib_logf(IB_LOG_LEVEL_FATAL, - "Key file not found"); - ut_error; - } - } + if (rc != CRYPT_KEY_OK) { + ib_logf(IB_LOG_LEVEL_FATAL, + "IV %d can not be found. Reason=%d", version, rc); + ut_error; + } + } - // Now compute L by encrypting IV using this key - const unsigned char* src = page_encrypted ? iv : crypt_data->iv; - const int srclen = page_encrypted ? iv_len : crypt_data->iv_length; - unsigned char* buf = page_encrypted ? key : crypt_data->keys[0].key; - uint32 buflen = page_encrypted ? key_len : sizeof(crypt_data->keys[0].key); + if (HasCryptoKey(version)) { + *key_length = GetCryptoKeySize(version); - // call ecb explicit - my_aes_encrypt_dynamic_type func= get_aes_encrypt_func(MY_AES_ALGORITHM_ECB); - int rc = (*func)(src, srclen, - buf, &buflen, - (unsigned char*)&keybuf, key_len, - NULL, 0, - 1); + int rc = GetCryptoKey(version, (unsigned char*)keybuf, *key_length); - if (rc != AES_OK) { + if (rc != CRYPT_KEY_OK) { ib_logf(IB_LOG_LEVEL_FATAL, - "Unable to encrypt key-block " - " src: %p srclen: %d buf: %p buflen: %d." - " return-code: %d. Can't continue!\n", - src, srclen, buf, buflen, rc); + "Key %d can not be found. Reason=%d", version, rc); + ut_error; + } + } else { + ib_logf(IB_LOG_LEVEL_FATAL, + "Key %d not found", version); ut_error; } - if (!page_encrypted) { - crypt_data->keys[0].key_version = version; - crypt_data->key_count++; - if (crypt_data->key_count > array_elements(crypt_data->keys)) { - crypt_data->key_count = array_elements(crypt_data->keys); - } + // do ctr key initialization + if (current_aes_dynamic_method == MY_AES_ALGORITHM_CTR) + { + // Now compute L by encrypting IV using this key + const unsigned char* src = page_encrypted ? iv : crypt_data->iv; + const int srclen = page_encrypted ? iv_len : crypt_data->iv_length; + unsigned char* buf = page_encrypted ? keybuf : crypt_data->keys[0].key; + uint32 buflen = page_encrypted ? *key_length : sizeof(crypt_data->keys[0].key); + + // call ecb explicit + my_aes_encrypt_dynamic_type func = get_aes_encrypt_func(MY_AES_ALGORITHM_ECB); + int rc = (*func)(src, srclen, + buf, &buflen, + (unsigned char*)keybuf, *key_length, + NULL, 0, + 1); + + if (rc != AES_OK) { + ib_logf(IB_LOG_LEVEL_FATAL, + "Unable to encrypt key-block " + " src: %p srclen: %d buf: %p buflen: %d." + " return-code: %d. Can't continue!\n", + src, srclen, buf, buflen, rc); + ut_error; + } + + if (!page_encrypted) { + crypt_data->keys[0].key_version = version; + crypt_data->key_count++; + + if (crypt_data->key_count > array_elements(crypt_data->keys)) { + crypt_data->key_count = array_elements(crypt_data->keys); + } + } + + // set the key size to the aes block size because this encrypted data is the key + *key_length = MY_AES_BLOCK_SIZE; + memcpy(dst, buf, buflen); + } + else + { + // otherwise keybuf contains the right key + memcpy(dst, keybuf, *key_length); } - memcpy(dst, buf, buflen); - if (!page_encrypted) { mutex_exit(&crypt_data->mutex); } @@ -290,14 +290,22 @@ fil_crypt_get_key(byte *dst, uint dstlen, Get key bytes for a space/latest(key-version) */ static inline void -fil_crypt_get_latest_key(byte *dst, uint dstlen, +fil_crypt_get_latest_key(byte *dst, uint* key_length, fil_space_crypt_t* crypt_data, uint *version) { if (srv_encrypt_tables) { - *version = GetLatestCryptoKeyVersion(); - return fil_crypt_get_key(dst, dstlen, crypt_data, *version, false); + // used for key rotation - get the next key id from the key provider + int rc = GetLatestCryptoKeyVersion(); + + // if no new key was created use the last one + if (rc >= 0) + { + *version = rc; + } + + return fil_crypt_get_key(dst, key_length, crypt_data, *version, false); } else { - return fil_crypt_get_key(dst, dstlen, NULL, *version, true); + return fil_crypt_get_key(dst, key_length, NULL, *version, true); } } @@ -614,7 +622,8 @@ fil_space_encrypt(ulint space, ulint offset, lsn_t lsn, // get key (L) uint key_version; - byte key[CRYPT_SCHEME_1_IV_LEN]; + byte key[MY_AES_MAX_KEY_LENGTH]; + uint key_length; if (srv_encrypt_tables) { crypt_data = fil_space_get_crypt_data(space); @@ -623,12 +632,45 @@ fil_space_encrypt(ulint space, ulint offset, lsn_t lsn, memcpy(dst_frame, src_frame, page_size); return; } - fil_crypt_get_latest_key(key, sizeof(key), crypt_data, &key_version); + fil_crypt_get_latest_key(key, &key_length, crypt_data, &key_version); } else { key_version = encryption_key; - fil_crypt_get_latest_key(key, sizeof(key), NULL, (uint*)&key_version); + fil_crypt_get_latest_key(key, &key_length, NULL, (uint*)&key_version); } + + /* Load the iv or counter (depending to the encryption algorithm used) */ + unsigned char iv[MY_AES_BLOCK_SIZE]; + + if (current_aes_dynamic_method == MY_AES_ALGORITHM_CTR) + { + // create counter block (C) + mach_write_to_4(iv + 0, space); + ulint space_offset = mach_read_from_4( + src_frame + FIL_PAGE_OFFSET); + mach_write_to_4(iv + 4, space_offset); + mach_write_to_8(iv + 8, lsn); + } + else + { + // take the iv from the key provider + + int load_iv_rc = GetCryptoIV(key_version, (uchar *) iv, sizeof(iv)); + + // if the iv can not be loaded the whole page can not be encrypted + if (load_iv_rc != CRYPT_KEY_OK) + { + ib_logf(IB_LOG_LEVEL_FATAL, + "Unable to decrypt data-block. " + " Can not load iv for key %d" + " return-code: %d. Can't continue!\n", + key_version, load_iv_rc); + + ut_error; + } + } + + ibool page_compressed = (mach_read_from_2(src_frame+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED); ibool page_encrypted = fil_space_is_page_encrypted(space); @@ -662,14 +704,6 @@ fil_space_encrypt(ulint space, ulint offset, lsn_t lsn, key_version); } - // create counter block (C) - unsigned char counter[MY_AES_BLOCK_SIZE]; - mach_write_to_4(counter + 0, space); - ulint space_offset = mach_read_from_4( - src_frame + FIL_PAGE_OFFSET); - mach_write_to_4(counter + 4, space_offset); - mach_write_to_8(counter + 8, lsn); - // encrypt page data ulint unencrypted_bytes = FIL_PAGE_DATA + FIL_PAGE_DATA_END; ulint srclen = page_size - unencrypted_bytes; @@ -683,10 +717,10 @@ fil_space_encrypt(ulint space, ulint offset, lsn_t lsn, int rc = (* my_aes_encrypt_dynamic)(src, srclen, - dst, &dstlen, - (unsigned char*)&key, sizeof(key), - (unsigned char*)&counter, sizeof(counter), - 1); + dst, &dstlen, + (unsigned char*)key, key_length, + (unsigned char*)iv, sizeof(iv), + 1); if (! ((rc == AES_OK) && ((ulint) dstlen == srclen))) { ib_logf(IB_LOG_LEVEL_FATAL, @@ -776,6 +810,7 @@ bool fil_space_decrypt(fil_space_crypt_t* crypt_data, const byte* src_frame, ulint page_size, byte* dst_frame) { + ulint space_id = mach_read_from_4(src_frame + FIL_PAGE_SPACE_ID); ulint page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE); // key version uint key_version; @@ -791,7 +826,7 @@ fil_space_decrypt(fil_space_crypt_t* crypt_data, if (page_type == FIL_PAGE_PAGE_ENCRYPTED) { key_version = mach_read_from_2( src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION); - fprintf(stderr, "JAN: key_version %u\n", key_version); + fprintf(stderr, "JAN: key_version %lu\n", key_version); orig_page_type = mach_read_from_2( src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + 2); fprintf(stderr, "JAN: decrypt: orig_page_type %lu\n", orig_page_type); @@ -816,10 +851,6 @@ fil_space_decrypt(fil_space_crypt_t* crypt_data, fprintf(stderr, "JAN: space %lu, offset %lu lsn %lu\n", space, offset, lsn); - // get key (L) - byte key[CRYPT_SCHEME_1_IV_LEN]; - fil_crypt_get_key(key, sizeof(key), crypt_data, key_version, page_encrypted); - // copy page header memcpy(dst_frame, src_frame, FIL_PAGE_DATA); @@ -828,11 +859,41 @@ fil_space_decrypt(fil_space_crypt_t* crypt_data, mach_write_to_2(dst_frame+FIL_PAGE_TYPE, orig_page_type); } - // create counter block - unsigned char counter[MY_AES_BLOCK_SIZE]; - mach_write_to_4(counter + 0, space); - mach_write_to_4(counter + 4, offset); - mach_write_to_8(counter + 8, lsn); + + // get key + byte key[MY_AES_MAX_KEY_LENGTH]; + uint key_length; + fil_crypt_get_key(key, &key_length, crypt_data, key_version, page_encrypted); + + // get the iv + unsigned char iv[MY_AES_BLOCK_SIZE]; + + if (current_aes_dynamic_method == MY_AES_ALGORITHM_CTR) + { + // create counter block + + mach_write_to_4(iv + 0, space); + mach_write_to_4(iv + 4, offset); + mach_write_to_8(iv + 8, lsn); + } + else + { + // take the iv from the key provider + + int load_iv_rc = GetCryptoIV(key_version, (uchar *) iv, sizeof(iv)); + + // if the iv can not be loaded the whole page can not be decrypted + if (load_iv_rc != CRYPT_KEY_OK) + { + ib_logf(IB_LOG_LEVEL_FATAL, + "Unable to decrypt data-block. " + " Can not load iv for key %d" + " return-code: %d. Can't continue!\n", + key_version, load_iv_rc); + + return AES_KEY_CREATION_FAILED; + } + } // decrypt page data ulint unencrypted_bytes = FIL_PAGE_DATA + FIL_PAGE_DATA_END; @@ -857,10 +918,10 @@ fil_space_decrypt(fil_space_crypt_t* crypt_data, srclen = pow((double)2, (double)((int)compressed_len)); } int rc = (* my_aes_decrypt_dynamic)(src, srclen, - dst, &dstlen, - (unsigned char*)&key, sizeof(key), - (unsigned char*)&counter, sizeof(counter), - 1); + dst, &dstlen, + (unsigned char*)key, key_length, + (unsigned char*)iv, sizeof(iv), + 1); if (! ((rc == AES_OK) && ((ulint) dstlen == srclen))) { ib_logf(IB_LOG_LEVEL_FATAL, diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 18b65c83949..30b021cb319 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -30,7 +30,6 @@ Created 10/25/1995 Heikki Tuuri #include "fil0pageencryption.h" #include "fsp0pageencryption.h" -#include "KeySingleton.h" #include <debug_sync.h> #include <my_dbug.h> @@ -824,7 +823,7 @@ fil_node_open_file( success = os_file_read(node->handle, page, 0, UNIV_PAGE_SIZE, space->flags); - if (fil_page_can_not_decrypt(page)) { + if (fil_page_encryption_status(page)) { /* if page is (still) encrypted, write an error and return. * Otherwise the server would crash if decrypting is not possible. * This may be the case, if the key file could not be @@ -1329,8 +1328,7 @@ fil_space_create( ut_a(fil_system); if (fsp_flags_is_page_encrypted(flags)) { - if (!KeySingleton::getInstance().isAvailable() - || KeySingleton::getInstance().getKeys(fsp_flags_get_page_encryption_key(flags))==NULL) { + if (!HasCryptoKey(fsp_flags_get_page_encryption_key(flags))) { /* by returning here it should be avoided that * the server crashes, if someone tries to access an * encrypted table and the encryption key is not available. @@ -2099,7 +2097,7 @@ fil_check_first_page( or the encryption key is not available, the check for reading the first page should intentionally fail with "can not decrypt" message. */ - page_is_encrypted = fil_page_can_not_decrypt(page); + page_is_encrypted = fil_page_encryption_status(page); if ((page_is_encrypted == PAGE_ENCRYPTION_KEY_MISSING) && page_is_encrypted) { page_is_encrypted = 1; } else { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 0f0ab32c7f5..99d619092d4 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -104,8 +104,6 @@ this program; if not, write to the Free Software Foundation, Inc., #include "page0zip.h" #include "fil0pagecompress.h" -#include "KeySingleton.h" - #define thd_get_trx_isolation(X) ((enum_tx_isolation)thd_tx_isolation(X)) @@ -203,12 +201,6 @@ static char* innobase_disable_monitor_counter = NULL; static char* innobase_reset_monitor_counter = NULL; static char* innobase_reset_all_monitor_counter = NULL; -/* Encryption for tables and columns */ -static char* innobase_data_encryption_providername = NULL; -static char* innobase_data_encryption_providerurl = NULL; -static uint innobase_data_encryption_providertype = 0; // 1 == file, 2 == server -static char* innobase_data_encryption_filekey = NULL; - /* The highest file format being used in the database. The value can be set by user, however, it will be adjusted to the newer file format if a table of such format is created/opened. */ @@ -3131,10 +3123,6 @@ innobase_init( ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR); - KeySingleton::getInstance( - innobase_data_encryption_providername, innobase_data_encryption_providerurl, - innobase_data_encryption_providertype, innobase_data_encryption_filekey); - #ifndef DBUG_OFF static const char test_filename[] = "-@"; char test_tablename[sizeof test_filename @@ -3760,8 +3748,6 @@ innobase_end( mysql_mutex_destroy(&pending_checkpoint_mutex); } - KeySingleton::getInstance().~KeySingleton(); - DBUG_RETURN(err); } @@ -11254,15 +11240,6 @@ ha_innobase::check_table_options( " innodb_file_per_table."); return "PAGE_ENCRYPTION"; } - - if (!KeySingleton::getInstance().isAvailable()) { - push_warning( - thd, Sql_condition::WARN_LEVEL_WARN, - HA_WRONG_CREATE_OPTION, - "InnoDB: PAGE_ENCRYPTION needs a key provider" - ); - return "PAGE_ENCRYPTION"; - } } /* Check page compression requirements */ @@ -11352,7 +11329,7 @@ ha_innobase::check_table_options( return "PAGE_ENCRYPTION_KEY"; } - if (!KeySingleton::getInstance().isAvailable() || KeySingleton::getInstance().getKeys(options->page_encryption_key)==NULL) { + if (!HasCryptoKey(options->page_encryption_key)) { push_warning_printf( thd, Sql_condition::WARN_LEVEL_WARN, HA_WRONG_CREATE_OPTION, @@ -19044,26 +19021,6 @@ static MYSQL_SYSVAR_ULONG(fatal_semaphore_wait_threshold, srv_fatal_semaphore_wa UINT_MAX32, /* Maximum setting */ 0); -static MYSQL_SYSVAR_UINT(data_encryption_providertype, innobase_data_encryption_providertype, - PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, - "Use table or column encryption / decryption. Default is 0 for no use, 1 for keyfile and 2 for keyserver.", - NULL, NULL, 1, 0, 2, 0); - -static MYSQL_SYSVAR_STR(data_encryption_providername, innobase_data_encryption_providername, - PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, - "Name of keyfile or keyserver.", - NULL, NULL, NULL); - -static MYSQL_SYSVAR_STR(data_encryption_providerurl, innobase_data_encryption_providerurl, - PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, - "Path or URL for keyfile or keyserver.", - NULL, NULL, NULL); - -static MYSQL_SYSVAR_STR(data_encryption_filekey, innobase_data_encryption_filekey, - PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, - "Key to encrypt / decrypt the keyfile.", - NULL, NULL, NULL); - static MYSQL_SYSVAR_BOOL(encrypt_tables, srv_encrypt_tables, 0, "Encrypt tables", 0, 0, 0); @@ -19342,11 +19299,6 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(compression_algorithm), MYSQL_SYSVAR(mtflush_threads), MYSQL_SYSVAR(use_mtflush), - /* Table encryption feature */ - MYSQL_SYSVAR(data_encryption_providertype), - MYSQL_SYSVAR(data_encryption_providername), - MYSQL_SYSVAR(data_encryption_providerurl), - MYSQL_SYSVAR(data_encryption_filekey), /* Encryption feature */ MYSQL_SYSVAR(encrypt_tables), MYSQL_SYSVAR(encryption_threads), diff --git a/storage/innobase/include/EncKeys.h b/storage/innobase/include/EncKeys.h deleted file mode 100644 index 43f2920fd7f..00000000000 --- a/storage/innobase/include/EncKeys.h +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright (C) 2014 eperi GmbH. All Rights Reserved. - - 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-1301 USA */ - -/******************************************************************//** -@file EncKeys.h -A structure and class to keep keys for encryption/decryption. - -Created 09/15/2014 -***********************************************************************/ - -#ifndef ENCKEYS_H_ -#define ENCKEYS_H_ - -#include "univ.i" -#include <sys/types.h> -#include <stdio.h> - - - - -struct keyentry { - ulint id; - char *iv; - char *key; -}; - - -class EncKeys -{ -private: - static const char *strMAGIC, *newLine; - static const int magicSize; - - enum constants { MAX_OFFSETS_IN_PCRE_PATTERNS = 30}; - enum keyAttributes { KEY_MIN = 1, KEY_MAX = 255, MAX_KEYS = 255, - MAX_IVLEN = 256, MAX_KEYLEN = 512, ivSize16 = 16, keySize32 = 32 }; - enum keyInitType { KEYINITTYPE_FILE = 1, KEYINITTYPE_SERVER = 2 }; - enum errorAttributes { MAX_KEY_LINE_SIZE = 3 * MAX_KEYLEN, MAX_KEY_FILE_SIZE = 1048576 }; - enum errorCodesLine { NO_ERROR_PARSE_OK = 0, NO_ERROR_ISCOMMENT = 10, NO_ERROR_KEY_GREATER_THAN_ASKED = 20, - ERROR_NOINITIALIZEDKEY = 30, ERROR_ID_TOO_BIG = 40, ERROR_WRONG_NUMBER_OF_MATCHES = 50, - ERROR_EQUAL_DOUBLE_KEY = 60, ERROR_UNEQUAL_DOUBLE_KEY = 70 }; - - static const char *errorNoKeyId, *errorInMatches, *errorExceedKeyFileSize, - *errorExceedKeySize, *errorEqualDoubleKey, *errorUnequalDoubleKey, - *errorNoInitializedKey, *errorFalseFileKey, - *errorNotImplemented, *errorOpenFile, *errorReadingFile, *errorFileSize; - - static const char* initialPwd; - ulint countKeys, keyLineInKeyFile; - keyentry keys[MAX_KEYS], *oneKey; - - void printKeyEntry( ulint id); - int initKeysThroughFile( const char *name, const char *path, const char *filekey); - int initKeysThroughServer( const char *name, const char *path, const char *filekey); - bool isComment( const char *line); - char * decryptFile( const char* filename, const char *secret, int *errorCode); - int parseFile( const char* filename, const ulint maxKeyId, const char *secret); - int parseLine( const char *line, const ulint maxKeyId); - -public: - static const size_t MAX_SECRET_SIZE = 256; - - enum errorCodesFile { NO_ERROR_KEY_FILE_PARSE_OK = 0, ERROR_KEY_FILE_PARSE_NULL = 110, - ERROR_KEY_FILE_TOO_BIG = 120, ERROR_KEY_FILE_EXCEEDS_MAX_NUMBERS_OF_KEYS = 130, - ERROR_OPEN_FILE = 140, ERROR_READING_FILE = 150, ERROR_FALSE_FILE_KEY = 160, - ERROR_KEYINITTYPE_SERVER_NOT_IMPLEMENTED = 170, ERROR_ENCRYPTION_SECRET_NULL = 180 }; - EncKeys(); - virtual ~EncKeys(); - bool initKeys( const char *name, const char *url, const int initType, const char *filekey); - keyentry *getKeys( int id); - /* made public for unit testing */ - static void parseSecret( const char *filename, char *secret ); - -}; - -#endif /* ENCKEYS_H_ */ diff --git a/storage/innobase/include/KeySingleton.h b/storage/innobase/include/KeySingleton.h deleted file mode 100644 index 2b2f3991998..00000000000 --- a/storage/innobase/include/KeySingleton.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright (C) 2014 eperi GmbH. All Rights Reserved. - - 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-1301 USA */ - -/******************************************************************//** -@file KeySingletonPattern.h -Implementation of single pattern to keep keys for encrypting/decrypting pages. - -Created 09/13/2014 -***********************************************************************/ - - -#ifndef KEYSINGLETON_H_ -#define KEYSINGLETON_H_ - -#include "EncKeys.h" - - -class KeySingleton -{ -private: - static bool instanceInited; - static KeySingleton theInstance; - static EncKeys encKeys; - - // No new instance or object possible - KeySingleton() {} - - // No new instance possible through copy constructor - KeySingleton( const KeySingleton&) {} - - // No new instance possible through copy - KeySingleton & operator = (const KeySingleton&); - -public: - virtual ~KeySingleton() {encKeys.~EncKeys();} - static KeySingleton& getInstance(); - // Init the instance for only one time - static KeySingleton& getInstance(const char *name, const char *url, - const int initType, const char *filekey); - keyentry *getKeys(int id); - ibool hasKey(int id); - static bool isAvailable() { - return instanceInited; - } -}; - -#endif /* KEYSINGLETON_H_ */ diff --git a/storage/innobase/include/fil0pageencryption.h b/storage/innobase/include/fil0pageencryption.h index 395361bcd04..9769f8c1912 100644 --- a/storage/innobase/include/fil0pageencryption.h +++ b/storage/innobase/include/fil0pageencryption.h @@ -69,7 +69,7 @@ Find out whether the page can be decrypted @return true if page can be decrypted, false if not. */ UNIV_INLINE ulint -fil_page_can_not_decrypt( +fil_page_encryption_status( /*===================*/ const byte *buf); /*!< in: page */ diff --git a/storage/innobase/include/fsp0pageencryption.ic b/storage/innobase/include/fsp0pageencryption.ic index ad016c46fdb..42c980b0430 100644 --- a/storage/innobase/include/fsp0pageencryption.ic +++ b/storage/innobase/include/fsp0pageencryption.ic @@ -24,8 +24,8 @@ Created 08/28/2014 ***********************************************************************/ #include "fsp0fsp.h" -#include "KeySingleton.h" #include "fil0pageencryption.h" +#include <my_crypt_key_management.h> /********************************************************************//** @@ -138,7 +138,7 @@ The function for decrypting the page should already be executed before this. */ UNIV_INLINE ulint -fil_page_can_not_decrypt( +fil_page_encryption_status( /*=====================*/ const byte *buf) /*!< in: page */ { @@ -147,11 +147,9 @@ fil_page_can_not_decrypt( if (page_type == FIL_PAGE_TYPE_FSP_HDR) { ulint flags = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + buf); if (fsp_flags_is_page_encrypted(flags)) { - if (!KeySingleton::getInstance().isAvailable() || - !KeySingleton::getInstance().hasKey(fsp_flags_get_page_encryption_key(flags))) { + if (!HasCryptoKey(fsp_flags_get_page_encryption_key(flags))) { /* accessing table would surely fail, because no key or no key provider available */ - if (KeySingleton::getInstance().isAvailable() && - !KeySingleton::getInstance().hasKey(fsp_flags_get_page_encryption_key(flags))) { + if (!HasCryptoKey(fsp_flags_get_page_encryption_key(flags))) { return PAGE_ENCRYPTION_KEY_MISSING; } return PAGE_ENCRYPTION_ERROR; @@ -161,8 +159,7 @@ fil_page_can_not_decrypt( if(page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED) { ulint key = mach_read_from_4(buf + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION); - if (KeySingleton::getInstance().isAvailable() && - !KeySingleton::getInstance().hasKey(key)) { + if (!HasCryptoKey(key)) { return PAGE_ENCRYPTION_KEY_MISSING; } return PAGE_ENCRYPTION_ERROR; diff --git a/storage/innobase/log/log0crypt.cc b/storage/innobase/log/log0crypt.cc index f902df61484..d7dd6b38459 100644 --- a/storage/innobase/log/log0crypt.cc +++ b/storage/innobase/log/log0crypt.cc @@ -4,11 +4,13 @@ Innodb log encrypt/decrypt Created 11/25/2013 Minli Zhu *******************************************************/ +#include "m_string.h" #include "log0crypt.h" +#include <my_crypt.h> + #include "log0log.h" #include "srv0start.h" // for srv_start_lsn #include "log0recv.h" // for recv_sys -#include <my_crypt.h> /* If true, enable redo log encryption. */ UNIV_INTERN my_bool srv_encrypt_log = FALSE; diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 20f6d4d1db0..0bcbe01c0f6 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -4703,9 +4703,9 @@ found: } - if (srv_encrypt_tables) { - page_encryption = TRUE; - } +// if (srv_encrypt_tables) { + //page_encryption = TRUE; +// } /* If the space is page encryption and this is write operation then we encrypt the page */ diff --git a/storage/tokudb/ft-index/ft/ftverify b/storage/tokudb/ft-index/ft/ftverify Binary files differnew file mode 100755 index 00000000000..96b86bfe250 --- /dev/null +++ b/storage/tokudb/ft-index/ft/ftverify diff --git a/storage/tokudb/ft-index/ft/tdb-recover b/storage/tokudb/ft-index/ft/tdb-recover Binary files differnew file mode 100755 index 00000000000..8df5480b705 --- /dev/null +++ b/storage/tokudb/ft-index/ft/tdb-recover diff --git a/storage/tokudb/ft-index/ft/tdb_logprint b/storage/tokudb/ft-index/ft/tdb_logprint Binary files differnew file mode 100755 index 00000000000..3055805b767 --- /dev/null +++ b/storage/tokudb/ft-index/ft/tdb_logprint diff --git a/storage/tokudb/ft-index/ft/tokuftdump b/storage/tokudb/ft-index/ft/tokuftdump Binary files differnew file mode 100755 index 00000000000..5b0b4c3b78a --- /dev/null +++ b/storage/tokudb/ft-index/ft/tokuftdump diff --git a/storage/xtradb/CMakeLists.txt b/storage/xtradb/CMakeLists.txt index d0a8b137791..121d7914083 100644 --- a/storage/xtradb/CMakeLists.txt +++ b/storage/xtradb/CMakeLists.txt @@ -359,8 +359,6 @@ SET(INNOBASE_SOURCES dict/dict0stats.cc dict/dict0stats_bg.cc dyn/dyn0dyn.cc - enc/EncKeys.cc - enc/KeySingleton.cc eval/eval0eval.cc eval/eval0proc.cc fil/fil0fil.cc diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc index 227570626ca..d32c5fb138f 100644 --- a/storage/xtradb/buf/buf0buf.cc +++ b/storage/xtradb/buf/buf0buf.cc @@ -5807,7 +5807,7 @@ buf_page_encrypt_before_write( // encrypt page content fil_space_encrypt(bpage->space, bpage->offset, bpage->newest_modification, - src_frame, zip_size, dst_frame); + src_frame, zip_size, dst_frame, 0); unsigned key_version = mach_read_from_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION); diff --git a/storage/xtradb/enc/EncKeys.cc b/storage/xtradb/enc/EncKeys.cc deleted file mode 100644 index 3b5e9f4121c..00000000000 --- a/storage/xtradb/enc/EncKeys.cc +++ /dev/null @@ -1,458 +0,0 @@ -/* Copyright (C) 2014 eperi GmbH. All Rights Reserved. - - 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-1301 USA */ - -/******************************************************************//** - @file EncKeys.cc - A class to keep keys for encryption/decryption. - -How it works... -The location and usage can be configured via the configuration file. -Example - -[mysqld] -... -innodb_data_encryption_providertype = 1 -innodb_data_encryption_providername = keys.enc -innodb_data_encryption_providerurl = /home/mdb/ -innodb_data_encryption_filekey = secret -... - -As provider type currently only value 1 is supported, which means, the keys are read from a file. -The filename is set up via the innodb_data_encryption_providername configuration value. -innodb_data_encryption_providerurl is used to configure the path to this file. This is usually -a folder name. -Examples: -innodb_data_encryption_providerurl = \\\\unc (windows share) -innodb_data_encryption_providerurl = e:/tmp/ (windows path) -innodb_data_encryption_providerurl = /tmp (linux path) - -The key file contains AES keys and initialization vectors as hex-encoded Strings. -Supported are keys of size 128, 192 or 256 bits. IV consists of 16 bytes. - -The key file should be encrypted and the key to decrypt the file can be given with the -innodb_data_encryption_filekey parameter. - -The file key can also be located if FILE: is prepended to the key. Then the following part is interpreted -as absolut to the file containing the file key. This file can optionally be encrypted, currently with a fix key. -Example: -innodb_data_encryption_filekey = FILE:y:/secret256.enc - -If the key file can not be read at server startup, for example if the file key is not present, -page_encryption feature is not availabe and access to page_encryption tables is not possible. - -Example files can be found inside the unittest/eperi folder. - -Open SSL command line utility can be used to create an encrypted key file. -Examples: -openssl enc –aes-256-cbc –md sha1 –k secret –in keys.txt –out keys.enc -openssl enc –aes-256-cbc –md sha1 –k <initialPwd> –in secret –out secret.enc - - Created 09/15/2014 - ***********************************************************************/ -#ifdef __WIN__ -#define PCRE_STATIC 1 -#endif - -#include "EncKeys.h" -#include <my_global.h> -#include <my_aes.h> -#include <memory.h> -#include <my_sys.h> -#include <pcre.h> -#include <string.h> -#include <my_sys.h> - - - - -const char* EncKeys::strMAGIC = "Salted__"; -#define magicSize 8 //strlen(strMAGIC); // 8 byte -const char* EncKeys::newLine = "\n"; - -const char* EncKeys::errorNoKeyId = "KeyID = %u not found or with error. Check the key and the log file.\n"; -const char* EncKeys::errorInMatches = "Wrong match of the keyID in line %u, see the template.\n"; -const char* EncKeys::errorExceedKeyFileSize = "The size of the key file %s exceeds " - "the maximum allowed of %u bytes.\n"; -const char* EncKeys::errorExceedKeySize = "The key size exceeds the maximum allowed size of %u in line %u.\n"; -const char* EncKeys::errorEqualDoubleKey = "More than one identical key with keyID = %u found" - " in lines %u and %u.\nDelete one of them in the key file.\n"; -const char* EncKeys::errorUnequalDoubleKey = "More than one not identical key with keyID = %u found" - " in lines %u and %u.\nChoose the right one and delete the other in the key file.\n" - "I'll take the key from line %u\n"; -const char* EncKeys::errorNoInitializedKey = "The key could not be initialized.\n"; -const char* EncKeys::errorNotImplemented = "Initializing keys through key server is not" - " yet implemented.\nYou can not read encrypted tables or columns\n\n"; -const char* EncKeys::errorOpenFile = "Could not open %s for reading. You can not read encrypted tables or columns.\n\n"; -const char* EncKeys::errorReadingFile = "Could not read from %s. You can not read encrypted tables or columns\n\n"; -const char* EncKeys::errorFileSize = "Could not get the file size from %s. You can not read encrypted tables or columns\n\n"; -const char* EncKeys::errorFalseFileKey = "Wrong encryption / decryption key for keyfile '%s'.\n"; - -/* read this from a secret source in some later version */ -const char* EncKeys::initialPwd = "lg28s9ac5ffa537fd8798875c98e190df289da7e047c05"; - -EncKeys::EncKeys() { - countKeys = keyLineInKeyFile = 0; - for (int ii = 0; ii < MAX_KEYS; ii++) { - keys[ii].id = 0; - keys[ii].iv = keys[ii].key = NULL; - } - oneKey = NULL; -} - -EncKeys::~EncKeys() { - for (int ii = MAX_KEYS - 1; ii >= 0 ; ii--) { - delete[] keys[ii].iv; keys[ii].iv = NULL; - delete[] keys[ii].key; keys[ii].key = NULL; - - } -} - -bool EncKeys::initKeys(const char *name, const char *url, const int initType, const char *filekey) { - if (KEYINITTYPE_FILE == initType) - { - int result = initKeysThroughFile(name, url, filekey); - return ERROR_FALSE_FILE_KEY != result && ERROR_OPEN_FILE != result && ERROR_READING_FILE != result; - } - else if (KEYINITTYPE_SERVER == initType) - { - return NO_ERROR_KEY_FILE_PARSE_OK == initKeysThroughServer(name, url, filekey); - } - return false; -} - -int EncKeys::initKeysThroughFile(const char *name, const char *path, const char *filekey) { - if (path==NULL || name==NULL) return ERROR_OPEN_FILE; - size_t len1 = strlen(path); - size_t len2 = strlen(name); - const char *MAGIC = "FILE:"; - const short MAGIC_LEN = 5; - int ret = NO_ERROR_KEY_FILE_PARSE_OK; - bool isUncPath= (len1>2) ? ((strncmp("\\\\", path, 2)==0) ? TRUE : FALSE) : FALSE; - bool isSlash = ((isUncPath? '\\':'/') == path[len1 - 1]); - char *secret = (char*) malloc(MAX_SECRET_SIZE +1 * sizeof(char)); - char *filename = (char*) malloc((len1 + len2 + (isSlash ? 1 : 2)) * sizeof(char)); - if(filekey != NULL) - { - //If secret starts with FILE: interpret the secret as filename. - if(memcmp(MAGIC, filekey, MAGIC_LEN) == 0) { - int fk_len = strlen(filekey); - char *secretfile = (char*)malloc( (1 + fk_len - MAGIC_LEN)* sizeof(char)); - memcpy(secretfile, filekey+MAGIC_LEN, fk_len - MAGIC_LEN); - secretfile[fk_len-MAGIC_LEN] = '\0'; - parseSecret(secretfile, secret); - free(secretfile); - } else - { - sprintf(secret, "%s", filekey); - } - } - sprintf(filename, "%s%s%s", path, isSlash ? "" : (isUncPath ? "\\":"/"), name); - ret = parseFile((const char *)filename, 254, secret); - free(filename); - free(secret); - return ret; -} - -int EncKeys::initKeysThroughServer( const char *name, const char *path, const char *filekey) -{ - //TODO -#ifdef UNIV_DEBUG - fprintf(stderr, errorNotImplemented); -#endif //UNIV_DEBUG - return ERROR_KEYINITTYPE_SERVER_NOT_IMPLEMENTED; -} - - -/* - secret is limited to MAX_SECRET_SIZE characters -*/ - -void EncKeys::parseSecret(const char *secretfile, char *secret) -{ - int maxSize = (MAX_SECRET_SIZE +16 + magicSize*2) ; - uchar* buf = (uchar*)malloc((maxSize) * sizeof(uchar)); - char* _initPwd = (char*)malloc((strlen(initialPwd)+1) * sizeof(char)); - - FILE *fp = fopen(secretfile, "rb"); - fseek(fp, 0L, SEEK_END); - long file_size = ftell(fp); - rewind(fp); - int bytes_to_read = MY_MIN(maxSize, file_size); - if ((fread(buf, 1, bytes_to_read, fp)) != bytes_to_read) - { - secret[0]=0; - goto err; - } - - if (memcmp(buf, strMAGIC, magicSize)) - { - bytes_to_read = ((unsigned int) bytes_to_read>MAX_SECRET_SIZE) ? MAX_SECRET_SIZE : bytes_to_read; - memcpy(secret, buf, bytes_to_read); - secret[bytes_to_read] = '\0'; - } - else - { - unsigned char salt[magicSize]; - unsigned char *key = new unsigned char[keySize32]; - unsigned char *iv = new unsigned char[ivSize16]; - memcpy(&salt, buf + magicSize, magicSize); - memcpy(_initPwd, initialPwd, strlen(initialPwd)); - _initPwd[strlen(initialPwd)]= '\0'; - my_bytes_to_key((unsigned char *) salt, _initPwd, key, iv); - uint32 d_size = 0; - - /* This file is always encoded with cbc */ - enum_my_aes_encryption_algorithm org_method= current_aes_dynamic_method; - my_aes_init_dynamic_encrypt(MY_AES_ALGORITHM_CBC); - int res = my_aes_decrypt_dynamic((const uchar*)buf + 2 * magicSize, - bytes_to_read - 2 * magicSize, - (uchar*)secret, &d_size, (const uchar*)key, keySize32, - iv, ivSize16, 0); - my_aes_init_dynamic_encrypt(org_method); - /* We would prefer a better error handling, but this will due for now */ - if (res != 0) - d_size= 0; - if (d_size>EncKeys::MAX_SECRET_SIZE) - d_size = EncKeys::MAX_SECRET_SIZE; - secret[d_size] = '\0'; - delete[] key; - delete[] iv; - } - -err: - free(buf); - free(_initPwd); - fclose(fp); -} - -/** - * Returns a struct keyentry with the asked 'id' or NULL. - */ - -keyentry *EncKeys::getKeys(int id) -{ - if (KEY_MIN <= id && KEY_MAX >= id && (&keys[id - 1])->iv) - { - return &keys[id - 1]; - } - DBUG_PRINT("error", (errorNoKeyId, id)); - return NULL; -} - -/** - * Get the keys from the key file <filename> and decrypt it with the key <secret>. - * Store the keys with id smaller then <maxKeyId> in an array of structs keyentry. - * Returns NO_ERROR_PARSE_OK or an appropriate error code. - */ -int EncKeys::parseFile(const char* filename, const ulint maxKeyId, const char *secret) { - int errorCode = 0; - char *buffer = decryptFile(filename, secret, &errorCode); - ulint id = 0; - - if (NO_ERROR_PARSE_OK != errorCode) return errorCode; - else errorCode = NO_ERROR_KEY_FILE_PARSE_OK; - - char *line = strtok(buffer, newLine); - while ( NULL != line) { - keyLineInKeyFile++; - switch (parseLine(line, maxKeyId)) { - case NO_ERROR_PARSE_OK: - id = oneKey->id; - keys[oneKey->id - 1] = *oneKey; - delete(oneKey); - countKeys++; - fprintf(stderr, "Line: %u --> ", (uint) keyLineInKeyFile); printKeyEntry(id); - break; - case ERROR_ID_TOO_BIG: - fprintf(stderr, errorExceedKeySize, KEY_MAX, keyLineInKeyFile); - fprintf(stderr, " --> %s\n", line); - errorCode = ERROR_KEY_FILE_EXCEEDS_MAX_NUMBERS_OF_KEYS; - break; - case ERROR_NOINITIALIZEDKEY: - fprintf(stderr, errorNoInitializedKey); - fprintf(stderr, " --> %s\n", line); - errorCode = ERROR_KEY_FILE_PARSE_NULL; - break; - case ERROR_WRONG_NUMBER_OF_MATCHES: - fprintf(stderr, errorInMatches, keyLineInKeyFile); - fprintf(stderr, " --> %s\n", line); - errorCode = ERROR_KEY_FILE_PARSE_NULL; - break; - case NO_ERROR_KEY_GREATER_THAN_ASKED: - fprintf(stderr, "No asked key in line %lu: %s\n", keyLineInKeyFile, line); - break; - case NO_ERROR_ISCOMMENT: - fprintf(stderr, "Is comment in line %lu: %s\n", keyLineInKeyFile, line); - default: - break; - } - line = strtok(NULL, newLine); - } - - free(line); line = NULL; - delete[] buffer; buffer = NULL; - return errorCode; -} - -int EncKeys::parseLine(const char *line, const ulint maxKeyId) { - int ret = NO_ERROR_PARSE_OK; - if (isComment(line)) - ret = NO_ERROR_ISCOMMENT; - else { - const char *error_p = NULL; - int offset; - pcre *pattern = pcre_compile( - "([0-9]+);([0-9,a-f,A-F]{32});([0-9,a-f,A-F]{64}|[0-9,a-f,A-F]{48}|[0-9,a-f,A-F]{32})", - 0, &error_p, &offset, NULL); - if ( NULL != error_p) - fprintf(stderr, "Error: %s\nOffset: %d\n", error_p, offset); - - int m_len = (int) strlen(line), ovector[MAX_OFFSETS_IN_PCRE_PATTERNS]; - int rc = pcre_exec(pattern, NULL, line, m_len, 0, 0, ovector, MAX_OFFSETS_IN_PCRE_PATTERNS); - pcre_free(pattern); - if (4 == rc) { - char lin[MAX_KEY_LINE_SIZE + 1]; - strncpy( lin, line, MAX_KEY_LINE_SIZE); - lin[MAX_KEY_LINE_SIZE] = '\0'; - char *substring_start = lin + ovector[2]; - int substr_length = ovector[3] - ovector[2]; - if (3 < substr_length) - ret = ERROR_ID_TOO_BIG; - else { - char buffer[4]; - sprintf(buffer, "%.*s", substr_length, substring_start); - ulint id = atoi(buffer); - if (0 == id) ret = ERROR_NOINITIALIZEDKEY; - else if (KEY_MAX < id) ret = ERROR_ID_TOO_BIG; - else if (maxKeyId < id) ret = NO_ERROR_KEY_GREATER_THAN_ASKED; - else { - oneKey = new keyentry; - oneKey->id = id; - substring_start = lin + ovector[4]; - substr_length = ovector[5] - ovector[4]; - oneKey->iv = new char[substr_length + 1]; - sprintf(oneKey->iv, "%.*s", substr_length, substring_start); - substring_start = lin + ovector[6]; - substr_length = ovector[7] - ovector[6]; - oneKey->key = new char[substr_length + 1]; - sprintf(oneKey->key, "%.*s", substr_length, substring_start); - } - } - } - else - ret = ERROR_WRONG_NUMBER_OF_MATCHES; - } - return ret; -} - -/** - Decrypt the key file 'filename' if it is encrypted with the key 'secret'. - Store the content of the decrypted file in 'buffer'. The buffer has to be freed - in the calling function. -*/ - -char* EncKeys::decryptFile(const char* filename, const char *secret, int *errorCode) { - *errorCode = NO_ERROR_PARSE_OK; - fprintf(stderr, "Reading %s\n\n", filename); - FILE *fp = fopen(filename, "rb"); - if (NULL == fp) { - fprintf(stderr, errorOpenFile, filename); - *errorCode = ERROR_OPEN_FILE; - return NULL; - } - - if (fseek(fp, 0L, SEEK_END)) { - *errorCode = ERROR_READING_FILE; - return NULL; - } - long file_size = ftell(fp); // get the file size - if (MAX_KEY_FILE_SIZE < file_size) { - fprintf(stderr, errorExceedKeyFileSize, filename, MAX_KEY_FILE_SIZE); - *errorCode = ERROR_KEY_FILE_TOO_BIG; - fclose(fp); - return NULL; - } - else if (-1L == file_size) { - fprintf(stderr, errorFileSize, filename); - *errorCode = ERROR_READING_FILE; - return NULL; - } - - rewind(fp); - //Read file into buffer - uchar *buffer = new uchar[file_size + 1]; - file_size= fread(buffer, 1, file_size, fp); - buffer[file_size] = '\0'; - fclose(fp); - //Check for file encryption - if (0 == memcmp(buffer, strMAGIC, magicSize)) - { //If file is encrypted, decrypt it first. - unsigned char salt[magicSize]; - unsigned char *key = new unsigned char[keySize32]; - unsigned char *iv = new unsigned char[ivSize16]; - uchar *decrypted = new uchar[file_size]; - memcpy(&salt, buffer + magicSize, magicSize); - my_bytes_to_key((unsigned char *) salt, secret, key, iv); - uint32 d_size = 0; - - /* This file is always encoded with cbc */ - enum_my_aes_encryption_algorithm org_method= current_aes_dynamic_method; - my_aes_init_dynamic_encrypt(MY_AES_ALGORITHM_CBC); - int res = my_aes_decrypt_dynamic((const uchar*)buffer + 2 * magicSize, - file_size - 2 * magicSize, - decrypted, &d_size, - (const uchar*) key, keySize32, - iv, ivSize16, 0); - my_aes_init_dynamic_encrypt(org_method); - if(0 != res) { - *errorCode = ERROR_FALSE_FILE_KEY; - delete[] buffer; buffer = NULL; - fprintf(stderr, errorFalseFileKey, filename); - } - else { - memcpy(buffer, decrypted, d_size); - buffer[d_size] = '\0'; - } - - delete[] decrypted; decrypted = NULL; - delete[] key; key = NULL; - delete[] iv; iv = NULL; - } - return (char*) buffer; -} - -bool EncKeys::isComment(const char *line) { - const char *error_p; - int offset, m_len = (int) strlen(line), ovector[MAX_OFFSETS_IN_PCRE_PATTERNS]; - pcre *pattern = pcre_compile("\\s*#.*", 0, &error_p, &offset, NULL); - int rc = pcre_exec( pattern, NULL, line, m_len, 0, 0, ovector, MAX_OFFSETS_IN_PCRE_PATTERNS); - pcre_free(pattern); - if (0 > rc) return false; - else return true; -} - - -void EncKeys::printKeyEntry( ulint id) -{ -#ifdef UNIV_DEBUG - keyentry *entry = getKeys(id); - if( NULL == entry) { - fprintf(stderr, "No such keyID=%lu\n",id); - } - else { - fprintf(stderr, "Key: id:%3lu \tiv:%lu bytes\tkey:%lu bytes\n", entry->id, strlen(entry->iv)/2, strlen(entry->key)/2); - } -#endif //UNIV_DEBUG -} diff --git a/storage/xtradb/enc/KeySingleton.cc b/storage/xtradb/enc/KeySingleton.cc deleted file mode 100644 index b751bd79fe2..00000000000 --- a/storage/xtradb/enc/KeySingleton.cc +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright (C) 2014 eperi GmbH. All Rights Reserved. - - 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-1301 USA */ - -/******************************************************************//** -@file KeySingleton.cc -Implementation of single pattern to keep keys for encrypting/decrypting pages. - -Created 09/13/2014 -***********************************************************************/ - - -#include "KeySingleton.h" -#include <stdlib.h> - - -bool KeySingleton::instanceInited = false; -KeySingleton KeySingleton::theInstance; -EncKeys KeySingleton::encKeys; - - - -KeySingleton & KeySingleton::getInstance() { -#ifdef UNIV_DEBUG - if( !instanceInited) { - fprintf(stderr, "Encryption / decryption keys were not initialized. " - "You can not read encrypted tables or columns\n"); - } -#endif /* UNIV_DEBUG */ - return theInstance; -} - -KeySingleton & KeySingleton::getInstance(const char *name, const char *url, - const int initType, const char *filekey) { - - if(instanceInited) return theInstance; - instanceInited = encKeys.initKeys(name, url, initType, filekey); - if( !instanceInited) { - fprintf(stderr, "Could not initialize any of the encryption / decryption keys. " - "You can not read encrypted tables\n\n"); - fflush(stderr); - } - - return theInstance; -} - -keyentry *KeySingleton::getKeys(int id) { - return encKeys.getKeys(id); -} - -ibool KeySingleton::hasKey(int id) { - return encKeys.getKeys(id) != NULL; -} - diff --git a/storage/xtradb/fil/fil0crypt.cc b/storage/xtradb/fil/fil0crypt.cc index 5024db0d0fb..0b61b31f7f5 100644 --- a/storage/xtradb/fil/fil0crypt.cc +++ b/storage/xtradb/fil/fil0crypt.cc @@ -9,10 +9,16 @@ #include "ut0ut.h" #include "btr0scrub.h" #include "fsp0fsp.h" +#include "fil0pagecompress.h" +#include "fil0pageencryption.h" #include <my_crypt.h> #include <my_crypt_key_management.h> +#include <my_aes.h> +#include <math.h> + + /** Mutex for keys */ UNIV_INTERN ib_mutex_t fil_crypt_key_mutex; @@ -173,85 +179,136 @@ fil_space_crypt_cleanup() Get key bytes for a space/key-version */ static void -fil_crypt_get_key(uchar *dst, uint dstlen, - fil_space_crypt_t* crypt_data, uint version) +fil_crypt_get_key(byte *dst, uint* key_length, + fil_space_crypt_t* crypt_data, uint version, bool page_encrypted) { -#ifndef HAVE_EncryptAes128Ctr - return; -#else - mutex_enter(&crypt_data->mutex); + unsigned char keybuf[MY_AES_MAX_KEY_LENGTH]; + unsigned char iv[CRYPT_SCHEME_1_IV_LEN]; + ulint iv_len = sizeof(iv); - // Check if we already have key - for (uint i = 0; i < crypt_data->key_count; i++) { - if (crypt_data->keys[i].key_version == version) { - memcpy(dst, crypt_data->keys[i].key, - sizeof(crypt_data->keys[i].key)); - mutex_exit(&crypt_data->mutex); - return; + if (!page_encrypted) { + mutex_enter(&crypt_data->mutex); + + // Check if we already have key + for (uint i = 0; i < crypt_data->key_count; i++) { + if (crypt_data->keys[i].key_version == version) { + memcpy(dst, crypt_data->keys[i].key, + sizeof(crypt_data->keys[i].key)); + mutex_exit(&crypt_data->mutex); + return; + } } - } - // Not found! - crypt_data->keyserver_requests++; + // Not found! + crypt_data->keyserver_requests++; - // Rotate keys to make room for a new - for (uint i = 1; i < array_elements(crypt_data->keys); i++) { - crypt_data->keys[i] = crypt_data->keys[i - 1]; - } + // Rotate keys to make room for a new + for (uint i = 1; i < array_elements(crypt_data->keys); i++) { + crypt_data->keys[i] = crypt_data->keys[i - 1]; + } + } + else + { + // load iv + fprintf(stderr, "%d... %d\n",iv_len, version); - // TODO(jonaso): Integrate with real key server + int rc = GetCryptoIV(version, (unsigned char*)iv, iv_len); + fprintf(stderr, " %d\n",rc); - // Get new key from key server - unsigned char keybuf[CRYPT_SCHEME_1_IV_LEN]; - unsigned keylen = sizeof(keybuf); - int rc = GetCryptoKey(version, keybuf, keylen); - if (rc != 0) { + if (rc != CRYPT_KEY_OK) { ib_logf(IB_LOG_LEVEL_FATAL, - "Unable to retrieve key with" - " version %u return-code: %d. Can't continue!\n", - version, rc); + "IV %d can not be found. Reason=%d", version, rc); ut_error; - } + } + } + + if (HasCryptoKey(version)) { + *key_length = GetCryptoKeySize(version); + + int rc = GetCryptoKey(version, (unsigned char*)keybuf, *key_length); - // Now compute L by encrypting IV using this key - const unsigned char* src = crypt_data->iv; - const int srclen = crypt_data->iv_length; - unsigned char* buf = crypt_data->keys[0].key; - int buflen = sizeof(crypt_data->keys[0].key); - rc = my_aes_encrypt_ecb(src, srclen, - buf, &buflen, - keybuf, sizeof(keybuf), - 0,0,0); - if (rc != CRYPT_OK) { + if (rc != CRYPT_KEY_OK) { ib_logf(IB_LOG_LEVEL_FATAL, - "Unable to encrypt key-block " - " src: %p srclen: %d buf: %p buflen: %d." - " return-code: %d. Can't continue!\n", - src, srclen, buf, buflen, rc); + "Key %d can not be found. Reason=%d", version, rc); + ut_error; + } + } else { + ib_logf(IB_LOG_LEVEL_FATAL, + "Key %d not found", version); ut_error; } - crypt_data->keys[0].key_version = version; - crypt_data->key_count++; - if (crypt_data->key_count > array_elements(crypt_data->keys)) { - crypt_data->key_count = array_elements(crypt_data->keys); + // do ctr key initialization + if (current_aes_dynamic_method == MY_AES_ALGORITHM_CTR) + { + // Now compute L by encrypting IV using this key + const unsigned char* src = page_encrypted ? iv : crypt_data->iv; + const int srclen = page_encrypted ? iv_len : crypt_data->iv_length; + unsigned char* buf = page_encrypted ? keybuf : crypt_data->keys[0].key; + uint32 buflen = page_encrypted ? *key_length : sizeof(crypt_data->keys[0].key); + + // call ecb explicit + my_aes_encrypt_dynamic_type func = get_aes_encrypt_func(MY_AES_ALGORITHM_ECB); + int rc = (*func)(src, srclen, + buf, &buflen, + (unsigned char*)keybuf, *key_length, + NULL, 0, + 1); + + if (rc != AES_OK) { + ib_logf(IB_LOG_LEVEL_FATAL, + "Unable to encrypt key-block " + " src: %p srclen: %d buf: %p buflen: %d." + " return-code: %d. Can't continue!\n", + src, srclen, buf, buflen, rc); + ut_error; + } + + if (!page_encrypted) { + crypt_data->keys[0].key_version = version; + crypt_data->key_count++; + + if (crypt_data->key_count > array_elements(crypt_data->keys)) { + crypt_data->key_count = array_elements(crypt_data->keys); + } + } + + // set the key size to the aes block size because this encrypted data is the key + *key_length = MY_AES_BLOCK_SIZE; + memcpy(dst, buf, buflen); + } + else + { + // otherwise keybuf contains the right key + memcpy(dst, keybuf, *key_length); } - memcpy(dst, crypt_data->keys[0].key, - sizeof(crypt_data->keys[0].key)); - mutex_exit(&crypt_data->mutex); -#endif + if (!page_encrypted) { + mutex_exit(&crypt_data->mutex); + } } /****************************************************************** Get key bytes for a space/latest(key-version) */ static inline void -fil_crypt_get_latest_key(uchar *dst, uint dstlen, +fil_crypt_get_latest_key(byte *dst, uint* key_length, fil_space_crypt_t* crypt_data, uint *version) { - *version = GetLatestCryptoKeyVersion(); - return fil_crypt_get_key(dst, dstlen, crypt_data, *version); + if (srv_encrypt_tables) { + // used for key rotation - get the next key id from the key provider + int rc = GetLatestCryptoKeyVersion(); + + // if no new key was created use the last one + if (rc >= 0) + { + *version = rc; + } + + return fil_crypt_get_key(dst, key_length, crypt_data, *version, false); + } else { + return fil_crypt_get_key(dst, key_length, NULL, *version, true); + } } /****************************************************************** @@ -260,9 +317,6 @@ UNIV_INTERN fil_space_crypt_t* fil_space_create_crypt_data() { -#ifndef HAVE_EncryptAes128Ctr - return 0; -#else const uint iv_length = CRYPT_SCHEME_1_IV_LEN; const uint sz = sizeof(fil_space_crypt_t) + iv_length; fil_space_crypt_t* crypt_data = @@ -282,7 +336,6 @@ fil_space_create_crypt_data() crypt_data->iv_length = iv_length; my_random_bytes(crypt_data->iv, iv_length); return crypt_data; -#endif } /****************************************************************** @@ -558,52 +611,120 @@ fil_space_check_encryption_write( } /****************************************************************** - Encrypt a page */ UNIV_INTERN void fil_space_encrypt(ulint space, ulint offset, lsn_t lsn, - const byte* src_frame, ulint zip_size, byte* dst_frame) + const byte* src_frame, ulint zip_size, byte* dst_frame, ulint encryption_key) { - fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space); + fil_space_crypt_t* crypt_data; ulint page_size = (zip_size) ? zip_size : UNIV_PAGE_SIZE; - if (crypt_data == NULL || srv_encrypt_tables == FALSE) { - memcpy(dst_frame, src_frame, page_size); - return; - } + + fprintf(stderr, "JAN: page_size %lu\n", page_size); // get key (L) uint key_version; - uchar key[CRYPT_SCHEME_1_IV_LEN]; - fil_crypt_get_latest_key(key, sizeof(key), crypt_data, &key_version); + byte key[MY_AES_MAX_KEY_LENGTH]; + uint key_length; + + if (srv_encrypt_tables) { + crypt_data = fil_space_get_crypt_data(space); + if (crypt_data == NULL) { + //TODO: Is this really needed ? + memcpy(dst_frame, src_frame, page_size); + return; + } + fil_crypt_get_latest_key(key, &key_length, crypt_data, &key_version); + } else { + key_version = encryption_key; + fil_crypt_get_latest_key(key, &key_length, NULL, (uint*)&key_version); + } + + + /* Load the iv or counter (depending to the encryption algorithm used) */ + unsigned char iv[MY_AES_BLOCK_SIZE]; + + if (current_aes_dynamic_method == MY_AES_ALGORITHM_CTR) + { + // create counter block (C) + mach_write_to_4(iv + 0, space); + ulint space_offset = mach_read_from_4( + src_frame + FIL_PAGE_OFFSET); + mach_write_to_4(iv + 4, space_offset); + mach_write_to_8(iv + 8, lsn); + } + else + { + // take the iv from the key provider + + int load_iv_rc = GetCryptoIV(key_version, (uchar *) iv, sizeof(iv)); + + // if the iv can not be loaded the whole page can not be encrypted + if (load_iv_rc != CRYPT_KEY_OK) + { + ib_logf(IB_LOG_LEVEL_FATAL, + "Unable to decrypt data-block. " + " Can not load iv for key %d" + " return-code: %d. Can't continue!\n", + key_version, load_iv_rc); + + ut_error; + } + } + + + ibool page_compressed = (mach_read_from_2(src_frame+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED); + ibool page_encrypted = fil_space_is_page_encrypted(space); + + ulint compression_alg = mach_read_from_8(src_frame+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION); + + ulint orig_page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE); + if (orig_page_type==FIL_PAGE_TYPE_FSP_HDR + || orig_page_type==FIL_PAGE_TYPE_XDES + || orig_page_type== FIL_PAGE_PAGE_ENCRYPTED + || orig_page_type== FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED) { + memcpy(dst_frame, src_frame, page_size); + return; + } // copy page header memcpy(dst_frame, src_frame, FIL_PAGE_DATA); - // store key version - mach_write_to_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, - key_version); - // create counter block (C) - unsigned char counter[MY_AES_BLOCK_SIZE]; - mach_write_to_4(counter + 0, space); - mach_write_to_4(counter + 4, offset); - mach_write_to_8(counter + 8, lsn); + if (page_encrypted && !page_compressed) { + // key id + mach_write_to_2(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, + key_version); + // original page type + mach_write_to_2(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + 2, + orig_page_type); + // new page type + mach_write_to_2(dst_frame+FIL_PAGE_TYPE, FIL_PAGE_PAGE_ENCRYPTED); + } else { + // store key version + mach_write_to_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, + key_version); + } // encrypt page data ulint unencrypted_bytes = FIL_PAGE_DATA + FIL_PAGE_DATA_END; - - const uchar* src = (uchar*) src_frame + FIL_PAGE_DATA; - uchar* dst = (uchar*) dst_frame + FIL_PAGE_DATA; + ulint srclen = page_size - unencrypted_bytes; + const byte* src = src_frame + FIL_PAGE_DATA; + byte* dst = dst_frame + FIL_PAGE_DATA; uint32 dstlen; - int rc = my_aes_encrypt_dynamic(src, (page_size - unencrypted_bytes), - dst, &dstlen, - key, sizeof(key), - counter, sizeof(counter), - 0); - if (! ((rc == AES_OK) && - ((ulint) dstlen == (page_size - unencrypted_bytes)))) - { + + if (page_compressed) { + srclen = page_size; + } + + + int rc = (* my_aes_encrypt_dynamic)(src, srclen, + dst, &dstlen, + (unsigned char*)key, key_length, + (unsigned char*)iv, sizeof(iv), + 1); + + if (! ((rc == AES_OK) && ((ulint) dstlen == srclen))) { ib_logf(IB_LOG_LEVEL_FATAL, "Unable to encrypt data-block " " src: %p srclen: %ld buf: %p buflen: %d." @@ -613,42 +734,57 @@ fil_space_encrypt(ulint space, ulint offset, lsn_t lsn, ut_error; } - // copy page trailer - memcpy(dst_frame + page_size - FIL_PAGE_DATA_END, - src_frame + page_size - FIL_PAGE_DATA_END, - FIL_PAGE_DATA_END); + if (!page_compressed) { + // copy page trailer + memcpy(dst_frame + page_size - FIL_PAGE_DATA_END, + src_frame + page_size - FIL_PAGE_DATA_END, + FIL_PAGE_DATA_END); - /* handle post encryption checksum */ - ib_uint32_t checksum = 0; - srv_checksum_algorithm_t algorithm = - static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm); + /* handle post encryption checksum */ + ib_uint32_t checksum = 0; + srv_checksum_algorithm_t algorithm = + static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm); - if (zip_size == 0) { - switch (algorithm) { - case SRV_CHECKSUM_ALGORITHM_CRC32: - case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32: - checksum = buf_calc_page_crc32(dst_frame); - break; - case SRV_CHECKSUM_ALGORITHM_INNODB: - case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB: - checksum = (ib_uint32_t) buf_calc_page_new_checksum( - dst_frame); - break; - case SRV_CHECKSUM_ALGORITHM_NONE: - case SRV_CHECKSUM_ALGORITHM_STRICT_NONE: - checksum = BUF_NO_CHECKSUM_MAGIC; - break; - /* no default so the compiler will emit a warning - * if new enum is added and not handled here */ + if (zip_size == 0) { + switch (algorithm) { + case SRV_CHECKSUM_ALGORITHM_CRC32: + case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32: + checksum = buf_calc_page_crc32(dst_frame); + break; + case SRV_CHECKSUM_ALGORITHM_INNODB: + case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB: + checksum = (ib_uint32_t) buf_calc_page_new_checksum( + dst_frame); + break; + case SRV_CHECKSUM_ALGORITHM_NONE: + case SRV_CHECKSUM_ALGORITHM_STRICT_NONE: + checksum = BUF_NO_CHECKSUM_MAGIC; + break; + /* no default so the compiler will emit a warning + * if new enum is added and not handled here */ + } + } else { + checksum = page_zip_calc_checksum(dst_frame, zip_size, + algorithm); } + + // store the post-encryption checksum after the key-version + mach_write_to_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + 4, + checksum); } else { - checksum = page_zip_calc_checksum(dst_frame, zip_size, - algorithm); + /* Page compressed and encrypted tables have different + FIL_HEADER */ + ulint page_len = log10((double)srclen)/log10((double)2); + /* Set up the correct page type */ + mach_write_to_2(dst_frame+FIL_PAGE_TYPE, FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED); + /* Set up the compression algorithm */ + mach_write_to_2(dst_frame+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION+4, orig_page_type); + /* Set up the compressed size */ + mach_write_to_1(dst_frame+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION+6, page_len); + /* Set up the compression method */ + mach_write_to_1(dst_frame+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION+7, compression_alg); } - // store the post-encryption checksum after the key-version - mach_write_to_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + 4, - checksum); } /********************************************************************* @@ -676,21 +812,38 @@ bool fil_space_decrypt(fil_space_crypt_t* crypt_data, const byte* src_frame, ulint page_size, byte* dst_frame) { + ulint space_id = mach_read_from_4(src_frame + FIL_PAGE_SPACE_ID); + ulint page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE); // key version - uint key_version = mach_read_from_4( - src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION); + uint key_version; + bool page_encrypted = (page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED + || page_type == FIL_PAGE_PAGE_ENCRYPTED); + + bool page_compressed = (page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED + || page_type == FIL_PAGE_PAGE_COMPRESSED); + + ulint orig_page_type=0; + fprintf(stderr, "JAN: page type %lu\n", page_type); + + if (page_type == FIL_PAGE_PAGE_ENCRYPTED) { + key_version = mach_read_from_2( + src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION); + fprintf(stderr, "JAN: key_version %lu\n", key_version); + orig_page_type = mach_read_from_2( + src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + 2); + fprintf(stderr, "JAN: decrypt: orig_page_type %lu\n", orig_page_type); + } else { + key_version = mach_read_from_4( + src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION); + } - if (key_version == 0) { + if (key_version == 0 && !page_encrypted) { + fprintf(stderr, "JAN: unencrypted\n"); + //TODO: is this really needed ? memcpy(dst_frame, src_frame, page_size); return false; /* page not decrypted */ } -#ifndef HAVE_EncryptAes128Ctr - ib_logf(IB_LOG_LEVEL_FATAL, - "Unable to decrypt data-block as server not compiled with CTR encyption"); - ut_error; - return false; -#else // read space & offset & lsn ulint space = mach_read_from_4( src_frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); @@ -698,32 +851,81 @@ fil_space_decrypt(fil_space_crypt_t* crypt_data, src_frame + FIL_PAGE_OFFSET); ib_uint64_t lsn = mach_read_from_8(src_frame + FIL_PAGE_LSN); - ut_a(crypt_data != NULL); - - // get key (L) - byte key[CRYPT_SCHEME_1_IV_LEN]; - fil_crypt_get_key(key, sizeof(key), crypt_data, key_version); + fprintf(stderr, "JAN: space %lu, offset %lu lsn %lu\n", space, offset, lsn); // copy page header memcpy(dst_frame, src_frame, FIL_PAGE_DATA); - // create counter block - unsigned char counter[MY_AES_BLOCK_SIZE]; - mach_write_to_4(counter + 0, space); - mach_write_to_4(counter + 4, offset); - mach_write_to_8(counter + 8, lsn); + if (page_type == FIL_PAGE_PAGE_ENCRYPTED) { + // orig page type + mach_write_to_2(dst_frame+FIL_PAGE_TYPE, orig_page_type); + } + + + // get key + byte key[MY_AES_MAX_KEY_LENGTH]; + uint key_length; + fil_crypt_get_key(key, &key_length, crypt_data, key_version, page_encrypted); + + // get the iv + unsigned char iv[MY_AES_BLOCK_SIZE]; + + if (current_aes_dynamic_method == MY_AES_ALGORITHM_CTR) + { + // create counter block + + mach_write_to_4(iv + 0, space); + mach_write_to_4(iv + 4, offset); + mach_write_to_8(iv + 8, lsn); + } + else + { + // take the iv from the key provider + + int load_iv_rc = GetCryptoIV(key_version, (uchar *) iv, sizeof(iv)); + + // if the iv can not be loaded the whole page can not be decrypted + if (load_iv_rc != CRYPT_KEY_OK) + { + ib_logf(IB_LOG_LEVEL_FATAL, + "Unable to decrypt data-block. " + " Can not load iv for key %d" + " return-code: %d. Can't continue!\n", + key_version, load_iv_rc); + + return AES_KEY_CREATION_FAILED; + } + } // decrypt page data ulint unencrypted_bytes = FIL_PAGE_DATA + FIL_PAGE_DATA_END; const byte* src = src_frame + FIL_PAGE_DATA; byte* dst = dst_frame + FIL_PAGE_DATA; - int dstlen; - int rc = my_aes_decrypt_ctr(src, (page_size - unencrypted_bytes), - dst, &dstlen, key, sizeof(key), - counter, sizeof(counter), 0); - if (! ((rc == AES_OK) && - ((ulint) dstlen == (page_size - unencrypted_bytes)))) { + uint32 dstlen; + ulint srclen = page_size - (FIL_PAGE_DATA + FIL_PAGE_DATA_END); + + ulint compressed_len; + ulint compression_method; + if (page_compressed) { + orig_page_type = mach_read_from_2(src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION+4); + compressed_len = mach_read_from_1(src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION+6); + compression_method = mach_read_from_1(src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION+7); + } + if (page_encrypted && !page_compressed) { + orig_page_type = mach_read_from_2(src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION+2); + } + + if (page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED) { + srclen = pow((double)2, (double)((int)compressed_len)); + } + int rc = (* my_aes_decrypt_dynamic)(src, srclen, + dst, &dstlen, + (unsigned char*)key, key_length, + (unsigned char*)iv, sizeof(iv), + 1); + + if (! ((rc == AES_OK) && ((ulint) dstlen == srclen))) { ib_logf(IB_LOG_LEVEL_FATAL, "Unable to decrypt data-block " " src: %p srclen: %ld buf: %p buflen: %d." @@ -733,16 +935,26 @@ fil_space_decrypt(fil_space_crypt_t* crypt_data, ut_error; } - // copy page trailer - memcpy(dst_frame + page_size - FIL_PAGE_DATA_END, - src_frame + page_size - FIL_PAGE_DATA_END, - FIL_PAGE_DATA_END); + if (page_type != FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED) { + fprintf(stderr, "JAN: trailer...\n"); + // copy page trailer + memcpy(dst_frame + page_size - FIL_PAGE_DATA_END, + src_frame + page_size - FIL_PAGE_DATA_END, + FIL_PAGE_DATA_END); - // clear key-version & crypt-checksum from dst - memset(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0, 8); + // clear key-version & crypt-checksum from dst + memset(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, 0, 8); + } else { + /* For page compressed tables we set up the FIL_HEADER again */ + /* setting original page type */ + mach_write_to_2(dst_frame + FIL_PAGE_TYPE, orig_page_type); + /* page_compression uses BUF_NO_CHECKSUM_MAGIC as checksum */ + mach_write_to_4(dst_frame + FIL_PAGE_SPACE_OR_CHKSUM, BUF_NO_CHECKSUM_MAGIC); + /* Set up the flush lsn to be compression algorithm */ + mach_write_to_8(dst_frame+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, compression_method); + } return true; /* page was decrypted */ -#endif } /****************************************************************** diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc index e45a4b5bbf8..0799e9921bf 100644 --- a/storage/xtradb/fil/fil0fil.cc +++ b/storage/xtradb/fil/fil0fil.cc @@ -26,7 +26,6 @@ Created 10/25/1995 Heikki Tuuri #include "fil0fil.h" -#include "KeySingleton.h" #include <debug_sync.h> #include <my_dbug.h> @@ -1361,8 +1360,7 @@ fil_space_create( ut_a(fil_system); if (fsp_flags_is_page_encrypted(flags)) { - if (!KeySingleton::getInstance().isAvailable() - || KeySingleton::getInstance().getKeys(fsp_flags_get_page_encryption_key(flags))==NULL) { + if (!HasCryptoKey(fsp_flags_get_page_encryption_key(flags))) { /* by returning here it should be avoided that * the server crashes, if someone tries to access an * encrypted table and the encryption key is not available. diff --git a/storage/xtradb/fil/fil0pageencryption.cc b/storage/xtradb/fil/fil0pageencryption.cc index 114064984e3..49c42615e19 100644 --- a/storage/xtradb/fil/fil0pageencryption.cc +++ b/storage/xtradb/fil/fil0pageencryption.cc @@ -33,7 +33,6 @@ this program; if not, write to the Free Software Foundation, Inc., #include "buf0checksum.h" #include <my_global.h> #include <my_aes.h> -#include <KeySingleton.h> #include <math.h> /* @@ -217,35 +216,28 @@ fil_encrypt_page( data_size = ((len - FIL_PAGE_DATA - FIL_PAGE_DATA_END) / MY_AES_BLOCK_SIZE) * MY_AES_BLOCK_SIZE; - const unsigned char rkey[] = {0xbd, 0xe4, 0x72, 0xa2, 0x95, 0x67, 0x5c, 0xa9, - 0x2e, 0x04, 0x67, 0xea, 0xdb, 0xc0, 0xe0, 0x23, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8 key_len = 16; + unsigned char rkey[GetCryptoKeySize(encryption_key)]; + uint key_len = sizeof(rkey); - const unsigned char iv[] = {0x2d, 0x1a, 0xf8, 0xd3, 0x97, 0x4e, 0x0b, 0xd3, 0xef, 0xed, - 0x5a, 0x6f, 0x82, 0x59, 0x4f,0x5e}; + unsigned char iv[16]; + uint iv_len = sizeof(iv); - ulint iv_len = 16; - - KeySingleton& keys = KeySingleton::getInstance(); - - if (!keys.isAvailable()) { - err = AES_KEY_CREATION_FAILED; - } else if (keys.getKeys(encryption_key) == NULL) { + if (!HasCryptoKey(encryption_key)) { err = PAGE_ENCRYPTION_KEY_MISSING; } else { - char* keyString = keys.getKeys(encryption_key)->key; - char* ivString = keys.getKeys(encryption_key)->iv; + int rc; + + rc = GetCryptoKey(encryption_key, rkey, key_len); + if (rc != AES_OK) + { + err = PAGE_ENCRYPTION_KEY_MISSING; + } - if (keyString == NULL || ivString == NULL) { - *errorCode = PAGE_ENCRYPTION_WILL_NOT_ENCRYPT; - *out_len = len; - return (buf); + rc = GetCryptoIV(encryption_key, iv, iv_len); + if (rc != AES_OK) + { + err = PAGE_ENCRYPTION_KEY_MISSING; } - key_len = strlen(keyString)/2; - my_aes_hex2uint(keyString, (unsigned char*)&rkey, key_len); - my_aes_hex2uint(ivString, (unsigned char*)&iv, 16); } /* 1st encryption: data_size bytes starting from FIL_PAGE_DATA */ @@ -255,9 +247,9 @@ fil_encrypt_page( data_size, (uchar *) out_buf + FIL_PAGE_DATA, &write_size, - (const unsigned char *) &rkey, + (const unsigned char *) rkey, key_len, - (const unsigned char *) &iv, + (const unsigned char *) iv, iv_len, 1); @@ -285,9 +277,9 @@ fil_encrypt_page( 64, (uchar*)tmp_buf, &write_size, - (const unsigned char *)&rkey, + (const unsigned char *)rkey, key_len, - (const unsigned char *)&iv, + (const unsigned char *)iv, iv_len, 1); ut_ad(write_size == 64); @@ -449,34 +441,32 @@ fil_decrypt_page( data_size = ((len - FIL_PAGE_DATA - FIL_PAGE_DATA_END) / MY_AES_BLOCK_SIZE) * MY_AES_BLOCK_SIZE; - const unsigned char rkey[] = {0xbd, 0xe4, 0x72, 0xa2, 0x95, 0x67, 0x5c, 0xa9, - 0x2e, 0x04, 0x67, 0xea, 0xdb, 0xc0,0xe0, 0x23, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - uint8 key_len = 16; - const unsigned char iv[] = {0x2d, 0x1a, 0xf8, 0xd3, 0x97, 0x4e, 0x0b, 0xd3, 0xef, 0xed, - 0x5a, 0x6f, 0x82, 0x59, 0x4f,0x5e}; - uint8 iv_len = 16; + unsigned char rkey[GetCryptoKeySize(page_decryption_key)]; + uint key_len = sizeof(rkey); - KeySingleton& keys = KeySingleton::getInstance(); + unsigned char iv[16]; + uint iv_len = sizeof(iv); - if (!keys.isAvailable()) { - err = PAGE_ENCRYPTION_ERROR; - } else if (keys.getKeys(page_decryption_key) == NULL) { + if (!HasCryptoKey(page_decryption_key)) { err = PAGE_ENCRYPTION_KEY_MISSING; } else { - char* keyString = keys.getKeys(page_decryption_key)->key; - char* ivString = keys.getKeys(page_decryption_key)->iv; - key_len = strlen(keyString)/2; - if (keyString == NULL || ivString == NULL) { - return err; + int rc; + + rc = GetCryptoKey(page_decryption_key, rkey, key_len); + if (rc != AES_OK) + { + err = PAGE_ENCRYPTION_KEY_MISSING; } - my_aes_hex2uint(keyString, (unsigned char*)&rkey, key_len); - my_aes_hex2uint(ivString, (unsigned char*)&iv, 16); + rc = GetCryptoIV(page_decryption_key, iv, iv_len); + if (rc != AES_OK) + { + err = PAGE_ENCRYPTION_KEY_MISSING; + } } + if (err != AES_OK) { /* surely key could not be determined. */ fprintf(stderr, "InnoDB: Corruption: Page is marked as encrypted\n" @@ -514,9 +504,9 @@ fil_decrypt_page( 64, (uchar *) in_buf + len - offset - 64, &tmp_write_size, - (const unsigned char *) &rkey, + (const unsigned char *) rkey, key_len, - (const unsigned char *) &iv, + (const unsigned char *) iv, iv_len, 1); diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index c319f1a1d84..21d7cee0fba 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -107,8 +107,6 @@ this program; if not, write to the Free Software Foundation, Inc., #include "page0zip.h" #include "fil0pagecompress.h" -#include "KeySingleton.h" - #define thd_get_trx_isolation(X) ((enum_tx_isolation)thd_tx_isolation(X)) @@ -213,12 +211,6 @@ static char* innobase_disable_monitor_counter = NULL; static char* innobase_reset_monitor_counter = NULL; static char* innobase_reset_all_monitor_counter = NULL; -/* Encryption for tables and columns */ -static char* innobase_data_encryption_providername = NULL; -static char* innobase_data_encryption_providerurl = NULL; -static uint innobase_data_encryption_providertype = 0; // 1 == file, 2 == server -static char* innobase_data_encryption_filekey = NULL; - /* The highest file format being used in the database. The value can be set by user, however, it will be adjusted to the newer file format if a table of such format is created/opened. */ @@ -3505,10 +3497,6 @@ innobase_init( ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR); - KeySingleton::getInstance( - innobase_data_encryption_providername, innobase_data_encryption_providerurl, - innobase_data_encryption_providertype, innobase_data_encryption_filekey); - #ifndef DBUG_OFF static const char test_filename[] = "-@"; char test_tablename[sizeof test_filename @@ -4173,8 +4161,6 @@ innobase_end( mysql_mutex_destroy(&pending_checkpoint_mutex); } - KeySingleton::getInstance().~KeySingleton(); - DBUG_RETURN(err); } @@ -11883,15 +11869,6 @@ ha_innobase::check_table_options( " innodb_file_per_table."); return "PAGE_ENCRYPTION"; } - - if (!KeySingleton::getInstance().isAvailable()) { - push_warning( - thd, Sql_condition::WARN_LEVEL_WARN, - HA_WRONG_CREATE_OPTION, - "InnoDB: PAGE_ENCRYPTION needs a key provider" - ); - return "PAGE_ENCRYPTION"; - } } /* Check page compression requirements */ @@ -11981,7 +11958,7 @@ ha_innobase::check_table_options( return "PAGE_ENCRYPTION_KEY"; } - if (KeySingleton::getInstance().getKeys(options->page_encryption_key)==NULL) { + if (!HasCryptoKey(options->page_encryption_key)) { push_warning_printf( thd, Sql_condition::WARN_LEVEL_WARN, HA_WRONG_CREATE_OPTION, @@ -20333,26 +20310,6 @@ static MYSQL_SYSVAR_ULONG(fatal_semaphore_wait_threshold, srv_fatal_semaphore_wa UINT_MAX32, /* Maximum setting */ 0); -static MYSQL_SYSVAR_UINT(data_encryption_providertype, innobase_data_encryption_providertype, - PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, - "Use table or column encryption / decryption. Default is 0 for no use, 1 for keyfile and 2 for keyserver.", - NULL, NULL, 1, 0, 2, 0); - -static MYSQL_SYSVAR_STR(data_encryption_providername, innobase_data_encryption_providername, - PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, - "Name of keyfile or keyserver.", - NULL, NULL, NULL); - -static MYSQL_SYSVAR_STR(data_encryption_providerurl, innobase_data_encryption_providerurl, - PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, - "Path or URL for keyfile or keyserver.", - NULL, NULL, NULL); - -static MYSQL_SYSVAR_STR(data_encryption_filekey, innobase_data_encryption_filekey, - PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, - "Key to encrypt / decrypt the keyfile.", - NULL, NULL, NULL); - static MYSQL_SYSVAR_BOOL(encrypt_tables, srv_encrypt_tables, 0, "Encrypt tables", 0, 0, 0); @@ -20669,11 +20626,6 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(compression_algorithm), MYSQL_SYSVAR(mtflush_threads), MYSQL_SYSVAR(use_mtflush), - /* Table encryption feature */ - MYSQL_SYSVAR(data_encryption_providertype), - MYSQL_SYSVAR(data_encryption_providername), - MYSQL_SYSVAR(data_encryption_providerurl), - MYSQL_SYSVAR(data_encryption_filekey), /* Encryption feature */ MYSQL_SYSVAR(encrypt_tables), MYSQL_SYSVAR(encryption_threads), diff --git a/storage/xtradb/include/EncKeys.h b/storage/xtradb/include/EncKeys.h deleted file mode 100644 index 43f2920fd7f..00000000000 --- a/storage/xtradb/include/EncKeys.h +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright (C) 2014 eperi GmbH. All Rights Reserved. - - 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-1301 USA */ - -/******************************************************************//** -@file EncKeys.h -A structure and class to keep keys for encryption/decryption. - -Created 09/15/2014 -***********************************************************************/ - -#ifndef ENCKEYS_H_ -#define ENCKEYS_H_ - -#include "univ.i" -#include <sys/types.h> -#include <stdio.h> - - - - -struct keyentry { - ulint id; - char *iv; - char *key; -}; - - -class EncKeys -{ -private: - static const char *strMAGIC, *newLine; - static const int magicSize; - - enum constants { MAX_OFFSETS_IN_PCRE_PATTERNS = 30}; - enum keyAttributes { KEY_MIN = 1, KEY_MAX = 255, MAX_KEYS = 255, - MAX_IVLEN = 256, MAX_KEYLEN = 512, ivSize16 = 16, keySize32 = 32 }; - enum keyInitType { KEYINITTYPE_FILE = 1, KEYINITTYPE_SERVER = 2 }; - enum errorAttributes { MAX_KEY_LINE_SIZE = 3 * MAX_KEYLEN, MAX_KEY_FILE_SIZE = 1048576 }; - enum errorCodesLine { NO_ERROR_PARSE_OK = 0, NO_ERROR_ISCOMMENT = 10, NO_ERROR_KEY_GREATER_THAN_ASKED = 20, - ERROR_NOINITIALIZEDKEY = 30, ERROR_ID_TOO_BIG = 40, ERROR_WRONG_NUMBER_OF_MATCHES = 50, - ERROR_EQUAL_DOUBLE_KEY = 60, ERROR_UNEQUAL_DOUBLE_KEY = 70 }; - - static const char *errorNoKeyId, *errorInMatches, *errorExceedKeyFileSize, - *errorExceedKeySize, *errorEqualDoubleKey, *errorUnequalDoubleKey, - *errorNoInitializedKey, *errorFalseFileKey, - *errorNotImplemented, *errorOpenFile, *errorReadingFile, *errorFileSize; - - static const char* initialPwd; - ulint countKeys, keyLineInKeyFile; - keyentry keys[MAX_KEYS], *oneKey; - - void printKeyEntry( ulint id); - int initKeysThroughFile( const char *name, const char *path, const char *filekey); - int initKeysThroughServer( const char *name, const char *path, const char *filekey); - bool isComment( const char *line); - char * decryptFile( const char* filename, const char *secret, int *errorCode); - int parseFile( const char* filename, const ulint maxKeyId, const char *secret); - int parseLine( const char *line, const ulint maxKeyId); - -public: - static const size_t MAX_SECRET_SIZE = 256; - - enum errorCodesFile { NO_ERROR_KEY_FILE_PARSE_OK = 0, ERROR_KEY_FILE_PARSE_NULL = 110, - ERROR_KEY_FILE_TOO_BIG = 120, ERROR_KEY_FILE_EXCEEDS_MAX_NUMBERS_OF_KEYS = 130, - ERROR_OPEN_FILE = 140, ERROR_READING_FILE = 150, ERROR_FALSE_FILE_KEY = 160, - ERROR_KEYINITTYPE_SERVER_NOT_IMPLEMENTED = 170, ERROR_ENCRYPTION_SECRET_NULL = 180 }; - EncKeys(); - virtual ~EncKeys(); - bool initKeys( const char *name, const char *url, const int initType, const char *filekey); - keyentry *getKeys( int id); - /* made public for unit testing */ - static void parseSecret( const char *filename, char *secret ); - -}; - -#endif /* ENCKEYS_H_ */ diff --git a/storage/xtradb/include/KeySingleton.h b/storage/xtradb/include/KeySingleton.h deleted file mode 100644 index 2b2f3991998..00000000000 --- a/storage/xtradb/include/KeySingleton.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright (C) 2014 eperi GmbH. All Rights Reserved. - - 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-1301 USA */ - -/******************************************************************//** -@file KeySingletonPattern.h -Implementation of single pattern to keep keys for encrypting/decrypting pages. - -Created 09/13/2014 -***********************************************************************/ - - -#ifndef KEYSINGLETON_H_ -#define KEYSINGLETON_H_ - -#include "EncKeys.h" - - -class KeySingleton -{ -private: - static bool instanceInited; - static KeySingleton theInstance; - static EncKeys encKeys; - - // No new instance or object possible - KeySingleton() {} - - // No new instance possible through copy constructor - KeySingleton( const KeySingleton&) {} - - // No new instance possible through copy - KeySingleton & operator = (const KeySingleton&); - -public: - virtual ~KeySingleton() {encKeys.~EncKeys();} - static KeySingleton& getInstance(); - // Init the instance for only one time - static KeySingleton& getInstance(const char *name, const char *url, - const int initType, const char *filekey); - keyentry *getKeys(int id); - ibool hasKey(int id); - static bool isAvailable() { - return instanceInited; - } -}; - -#endif /* KEYSINGLETON_H_ */ diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h index e0004311404..6d9c2d0404e 100644 --- a/storage/xtradb/include/fil0fil.h +++ b/storage/xtradb/include/fil0fil.h @@ -168,6 +168,8 @@ static const ulint FIL_PAGE_COMPRESS_SIZE_V1 = FIL_PAGE_ORIGINAL_SIZE_V1 + 2; /* @} */ /** File page types (values of FIL_PAGE_TYPE) @{ */ +#define FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED 35631 /* page compressed + + encrypted page */ #define FIL_PAGE_PAGE_COMPRESSED 34354 /*!< Page compressed page */ #define FIL_PAGE_PAGE_ENCRYPTED 34355 /*!< Page encrypted page */ #define FIL_PAGE_INDEX 17855 /*!< B-tree node */ @@ -1236,7 +1238,9 @@ fil_space_encrypt( lsn_t lsn, /*!< in: page lsn */ const byte* src_frame,/*!< in: page frame */ ulint size, /*!< in: size of data to encrypt */ - byte* dst_frame); /*!< in: where to encrypt to */ + byte* dst_frame, /*!< in: where to encrypt to */ + ulint page_encryption_key); /*!< in: page encryption key id if page + encrypted */ /********************************************************************* Decrypt buffer page */ diff --git a/storage/xtradb/include/fsp0pageencryption.ic b/storage/xtradb/include/fsp0pageencryption.ic index c78ed40bcc6..7ff002b203e 100644 --- a/storage/xtradb/include/fsp0pageencryption.ic +++ b/storage/xtradb/include/fsp0pageencryption.ic @@ -24,7 +24,6 @@ Created 08/28/2014 ***********************************************************************/ #include "fsp0fsp.h" -#include "KeySingleton.h" #include "fil0pageencryption.h" @@ -116,6 +115,17 @@ fil_page_is_encrypted( return(mach_read_from_2(buf+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_ENCRYPTED); } +/*******************************************************************//** +Find out whether the page is page is first compressed and then encrypted +@return true if page is page compressed+encrypted, false if not */ +UNIV_INLINE +ibool +fil_page_is_compressed_encrypted( +/*=============================*/ + const byte *buf) /*!< in: page */ +{ + return(mach_read_from_2(buf+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED); +} /*******************************************************************//** Find out whether the page can be decrypted. @@ -139,22 +149,16 @@ fil_page_encryption_status( if (page_type == FIL_PAGE_TYPE_FSP_HDR) { ulint flags = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + buf); if (fsp_flags_is_page_encrypted(flags)) { - if (!KeySingleton::getInstance().isAvailable() || - !KeySingleton::getInstance().hasKey(fsp_flags_get_page_encryption_key(flags))) { + if (!HasCryptoKey(fsp_flags_get_page_encryption_key(flags))) { /* accessing table would surely fail, because no key or no key provider available */ - if (KeySingleton::getInstance().isAvailable() && - !KeySingleton::getInstance().hasKey(fsp_flags_get_page_encryption_key(flags))) { - return PAGE_ENCRYPTION_KEY_MISSING; - } - return PAGE_ENCRYPTION_ERROR; + return PAGE_ENCRYPTION_KEY_MISSING; } } } if(page_type == FIL_PAGE_PAGE_ENCRYPTED) { ulint key = mach_read_from_1(buf + FIL_PAGE_SPACE_OR_CHKSUM); - if (KeySingleton::getInstance().isAvailable() && - !KeySingleton::getInstance().hasKey(key)) { - return PAGE_ENCRYPTION_KEY_MISSING; + if (!HasCryptoKey(key)) { + return PAGE_ENCRYPTION_KEY_MISSING; } return PAGE_ENCRYPTION_ERROR; } diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc index e2a409011b2..9cb1bd8d7f9 100644 --- a/storage/xtradb/os/os0file.cc +++ b/storage/xtradb/os/os0file.cc @@ -3152,6 +3152,7 @@ try_again: if (ret && len == n) { /* If page is encrypted we need to decrypt it first */ + /* if (fil_page_is_encrypted((byte *)buf)) { if (fil_decrypt_page( NULL, @@ -3163,6 +3164,22 @@ try_again: return FALSE; } } + */ + + if (fil_page_is_compressed_encrypted((byte *)buf) || + fil_page_is_encrypted((byte *)buf)) { + + byte * dst_frm = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE)); + // Decrypt the data + fil_space_decrypt( + (fil_space_crypt_t* ) NULL, + (byte *)buf, + n, + dst_frm); + // Copy decrypted buffer back to buf + memcpy(buf, dst_frm, n); + ut_free(dst_frm); + } /* Note that InnoDB writes files that are not formated as file spaces and they do not have FIL_PAGE_TYPE @@ -3185,6 +3202,7 @@ try_again: if ((ulint) ret == n) { /* If page is encrypted we need to decrypt it first */ + /* if (fil_page_is_encrypted((byte *)buf)) { if (fil_decrypt_page( NULL, @@ -3196,6 +3214,21 @@ try_again: return FALSE; } } + */ + if (fil_page_is_compressed_encrypted((byte *)buf) || + fil_page_is_encrypted((byte *)buf)) { + + byte * dst_frm = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE)); + // Decrypt the data + fil_space_decrypt( + (fil_space_crypt_t*) NULL, + (byte *)buf, + n, + dst_frm); + // Copy decrypted buffer back to buf + memcpy(buf, dst_frm, n); + ut_free(dst_frm); + } /* Note that InnoDB writes files that are not formated as file spaces and they do not have FIL_PAGE_TYPE @@ -3296,6 +3329,7 @@ try_again: if (ret && len == n) { /* If page is encrypted we need to decrypt it first */ + /* if (fil_page_is_encrypted((byte *)buf)) { if (fil_decrypt_page( NULL, @@ -3307,6 +3341,20 @@ try_again: return (FALSE); } } + */ + if (fil_page_is_compressed_encrypted((byte *)buf) || + fil_page_is_encrypted((byte *)buf)) { + byte * dst_frm = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE)); + // Decrypt the data + fil_space_decrypt( + (fil_space_crypt_t* ) NULL, + (byte *)buf, + n, + dst_frm); + // Copy decrypted buffer back to buf + memcpy(buf, dst_frm, n); + ut_free(dst_frm); + } /* Note that InnoDB writes files that are not formated as file spaces and they do not have FIL_PAGE_TYPE @@ -3330,6 +3378,7 @@ try_again: if ((ulint) ret == n) { /* If the page is encrypted we need to decrypt it first */ + /* if (fil_page_is_encrypted((byte *)buf)) { if (fil_decrypt_page( NULL, @@ -3341,6 +3390,23 @@ try_again: return (FALSE); } } + */ + + if (fil_page_is_compressed_encrypted((byte *)buf) || + fil_page_is_encrypted((byte *)buf)) { + + byte * dst_frm = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE)); + // Decrypt the data + fil_space_decrypt( + (fil_space_crypt_t* ) NULL, + (byte *)buf, + n, + dst_frm); + // Copy decrypted buffer back to buf + memcpy(buf, dst_frm, n); + ut_free(dst_frm); + } + /* Note that InnoDB writes files that are not formated as file spaces and they do not have FIL_PAGE_TYPE @@ -4901,6 +4967,10 @@ found: os_mutex_enter(array->mutex); } +// if (srv_encrypt_tables) { +// page_encryption = TRUE; +// } + /* If the space is page encryption and this is write operation then we encrypt the page */ if (message1 && type == OS_FILE_WRITE && page_encryption ) { @@ -4915,28 +4985,18 @@ found: // if it is not yet allocated. os_slot_alloc_page_buf2(slot); os_slot_alloc_tmp_encryption_buf(slot); - - tmp = fil_encrypt_page( + /* ctr not yet supported in xtradb, lsn is null*/ + fil_space_encrypt( fil_node_get_space_id(slot->message1), + slot->offset, + NULL, (byte *)buf, + slot->len, slot->page_buf2, - len, - page_encryption_key, - &real_len, - &ec, - slot->tmp_encryption_buf); + slot->page_encryption_key); - /* If encryption succeeded, set up the length and buffer */ - if (tmp != buf) { - len = real_len; - buf = slot->page_buf2; - slot->len = real_len; - slot->page_encryption_success = TRUE; - } else { - /* Use original not encrypted page */ - slot->page_encryption_success = FALSE; - buf = slot->buf; - } + slot->page_encryption_success = TRUE; + buf = slot->page_buf2; /* Take array mutex back */ os_mutex_enter(array->mutex); @@ -5575,16 +5635,20 @@ os_aio_windows_handle( } if (slot->type == OS_FILE_READ) { - if (fil_page_is_encrypted(slot->buf)) { + if (fil_page_is_compressed_encrypted(slot->buf) || + fil_page_is_encrypted(slot->buf)) { + ut_ad(slot->message1 != NULL); os_slot_alloc_page_buf2(slot); os_slot_alloc_tmp_encryption_buf(slot); - fil_decrypt_page( - slot->page_buf2, + + // Decrypt the data + fil_space_decrypt( + fil_node_get_space_id(slot->message1), slot->buf, slot->len, - slot->write_size, - NULL, - slot->tmp_encryption_buf); + slot->page_buf2); + // Copy decrypted buffer back to buf + memcpy(slot->buf, slot->page_buf2, slot->len); } if (fil_page_is_compressed(slot->buf)) { @@ -5702,16 +5766,21 @@ retry: ut_a(slot->pos < end_pos); if (slot->type == OS_FILE_READ) { - if (fil_page_is_encrypted(slot->buf)) { + /* If the page is page encrypted we decrypt */ + if (fil_page_is_compressed_encrypted(slot->buf) || + fil_page_is_encrypted(slot->buf)) { os_slot_alloc_page_buf2(slot); os_slot_alloc_tmp_encryption_buf(slot); - fil_decrypt_page( - slot->page_buf2, + ut_ad(slot->message1 != NULL); + + // Decrypt the data + fil_space_decrypt( + fil_node_get_space_id(slot->message1), slot->buf, slot->len, - slot->write_size, - NULL, - slot->tmp_encryption_buf); + slot->page_buf2); + // Copy decrypted buffer back to buf + memcpy(slot->buf, slot->page_buf2, slot->len); } /* If the page is page compressed and this is read, |