diff options
author | Sergei Golubchik <serg@mariadb.org> | 2015-05-13 21:57:24 +0200 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2015-05-15 18:12:01 +0200 |
commit | 2300fe2e0ed59e36046bb867cc7499bf4c3d7c27 (patch) | |
tree | 9adab44a30ef40e5cf1e1661220a9cf8079cb5b5 | |
parent | 632f2307f775d255bab948de2178feb85fcac970 (diff) | |
download | mariadb-git-2300fe2e0ed59e36046bb867cc7499bf4c3d7c27.tar.gz |
Identical key derivation code in XtraDB/InnoDB/Aria
* Extract it into the "encryption_scheme" service.
* Make these engines to use the service, remove duplicate code.
* Change MY_AES_xxx error codes, to return them safely
from encryption_scheme_encrypt/decrypt without conflicting
with ENCRYPTION_SCHEME_KEY_INVALID error
26 files changed, 612 insertions, 466 deletions
diff --git a/include/my_crypt.h b/include/my_crypt.h index bfde4d3c0f7..655d1641136 100644 --- a/include/my_crypt.h +++ b/include/my_crypt.h @@ -25,10 +25,10 @@ extern "C" { #endif /* return values from my_aes_encrypt/my_aes_decrypt functions */ -#define MY_AES_OK 0 -#define MY_AES_BAD_DATA -1 -#define MY_AES_OPENSSL_ERROR -2 -#define MY_AES_BAD_KEYSIZE -3 +#define MY_AES_OK 0 +#define MY_AES_BAD_DATA -100 +#define MY_AES_OPENSSL_ERROR -101 +#define MY_AES_BAD_KEYSIZE -102 /* The block size for all supported algorithms */ #define MY_AES_BLOCK_SIZE 16 diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h index 09026514a88..cfa4b13a7ef 100644 --- a/include/mysql/plugin.h +++ b/include/mysql/plugin.h @@ -75,7 +75,7 @@ typedef struct st_mysql_xid MYSQL_XID; #define MYSQL_PLUGIN_INTERFACE_VERSION 0x0104 /* MariaDB plugin interface version */ -#define MARIA_PLUGIN_INTERFACE_VERSION 0x010a +#define MARIA_PLUGIN_INTERFACE_VERSION 0x010b /* The allowable types of plugins diff --git a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp index 7346c4f29b0..669be094542 100644 --- a/include/mysql/plugin_audit.h.pp +++ b/include/mysql/plugin_audit.h.pp @@ -213,6 +213,43 @@ struct encryption_service_st { encrypt_decrypt_func encryption_decrypt_func; }; extern struct encryption_service_st encryption_handler; +#include <mysql/service_encryption_scheme.h> +struct st_encryption_scheme_key { + unsigned int version; + unsigned char key[16]; +}; +struct st_encryption_scheme { + unsigned char iv[16]; + struct st_encryption_scheme_key key[3]; + unsigned int keyserver_requests; + unsigned int key_id; + unsigned int type; + void (*locker)(struct st_encryption_scheme *self, int release); +}; +extern struct encryption_scheme_service_st { + int (*encryption_scheme_encrypt_func) + (const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); + int (*encryption_scheme_decrypt_func) + (const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); +} *encryption_scheme_service; +int encryption_scheme_encrypt(const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); +int encryption_scheme_decrypt(const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); struct st_mysql_xid { long formatID; long gtrid_length; diff --git a/include/mysql/plugin_auth.h.pp b/include/mysql/plugin_auth.h.pp index 1df73b0a41e..1b795079c22 100644 --- a/include/mysql/plugin_auth.h.pp +++ b/include/mysql/plugin_auth.h.pp @@ -213,6 +213,43 @@ struct encryption_service_st { encrypt_decrypt_func encryption_decrypt_func; }; extern struct encryption_service_st encryption_handler; +#include <mysql/service_encryption_scheme.h> +struct st_encryption_scheme_key { + unsigned int version; + unsigned char key[16]; +}; +struct st_encryption_scheme { + unsigned char iv[16]; + struct st_encryption_scheme_key key[3]; + unsigned int keyserver_requests; + unsigned int key_id; + unsigned int type; + void (*locker)(struct st_encryption_scheme *self, int release); +}; +extern struct encryption_scheme_service_st { + int (*encryption_scheme_encrypt_func) + (const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); + int (*encryption_scheme_decrypt_func) + (const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); +} *encryption_scheme_service; +int encryption_scheme_encrypt(const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); +int encryption_scheme_decrypt(const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); struct st_mysql_xid { long formatID; long gtrid_length; diff --git a/include/mysql/plugin_encryption.h.pp b/include/mysql/plugin_encryption.h.pp index 2cf344864e4..56cad7ab716 100644 --- a/include/mysql/plugin_encryption.h.pp +++ b/include/mysql/plugin_encryption.h.pp @@ -213,6 +213,43 @@ struct encryption_service_st { encrypt_decrypt_func encryption_decrypt_func; }; extern struct encryption_service_st encryption_handler; +#include <mysql/service_encryption_scheme.h> +struct st_encryption_scheme_key { + unsigned int version; + unsigned char key[16]; +}; +struct st_encryption_scheme { + unsigned char iv[16]; + struct st_encryption_scheme_key key[3]; + unsigned int keyserver_requests; + unsigned int key_id; + unsigned int type; + void (*locker)(struct st_encryption_scheme *self, int release); +}; +extern struct encryption_scheme_service_st { + int (*encryption_scheme_encrypt_func) + (const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); + int (*encryption_scheme_decrypt_func) + (const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); +} *encryption_scheme_service; +int encryption_scheme_encrypt(const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); +int encryption_scheme_decrypt(const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); struct st_mysql_xid { long formatID; long gtrid_length; diff --git a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp index ee8ebc4299c..3c07800a656 100644 --- a/include/mysql/plugin_ftparser.h.pp +++ b/include/mysql/plugin_ftparser.h.pp @@ -213,6 +213,43 @@ struct encryption_service_st { encrypt_decrypt_func encryption_decrypt_func; }; extern struct encryption_service_st encryption_handler; +#include <mysql/service_encryption_scheme.h> +struct st_encryption_scheme_key { + unsigned int version; + unsigned char key[16]; +}; +struct st_encryption_scheme { + unsigned char iv[16]; + struct st_encryption_scheme_key key[3]; + unsigned int keyserver_requests; + unsigned int key_id; + unsigned int type; + void (*locker)(struct st_encryption_scheme *self, int release); +}; +extern struct encryption_scheme_service_st { + int (*encryption_scheme_encrypt_func) + (const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); + int (*encryption_scheme_decrypt_func) + (const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); +} *encryption_scheme_service; +int encryption_scheme_encrypt(const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); +int encryption_scheme_decrypt(const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); struct st_mysql_xid { long formatID; long gtrid_length; diff --git a/include/mysql/plugin_password_validation.h.pp b/include/mysql/plugin_password_validation.h.pp index e7dcc44f07a..6b8a886dc25 100644 --- a/include/mysql/plugin_password_validation.h.pp +++ b/include/mysql/plugin_password_validation.h.pp @@ -213,6 +213,43 @@ struct encryption_service_st { encrypt_decrypt_func encryption_decrypt_func; }; extern struct encryption_service_st encryption_handler; +#include <mysql/service_encryption_scheme.h> +struct st_encryption_scheme_key { + unsigned int version; + unsigned char key[16]; +}; +struct st_encryption_scheme { + unsigned char iv[16]; + struct st_encryption_scheme_key key[3]; + unsigned int keyserver_requests; + unsigned int key_id; + unsigned int type; + void (*locker)(struct st_encryption_scheme *self, int release); +}; +extern struct encryption_scheme_service_st { + int (*encryption_scheme_encrypt_func) + (const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); + int (*encryption_scheme_decrypt_func) + (const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); +} *encryption_scheme_service; +int encryption_scheme_encrypt(const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); +int encryption_scheme_decrypt(const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); struct st_mysql_xid { long formatID; long gtrid_length; diff --git a/include/mysql/service_encryption_scheme.h b/include/mysql/service_encryption_scheme.h new file mode 100644 index 00000000000..195c7aa4a5c --- /dev/null +++ b/include/mysql/service_encryption_scheme.h @@ -0,0 +1,133 @@ +#ifndef MYSQL_SERVICE_ENCRYPTION_SCHEME_INCLUDED +/* Copyright (c) 2015, MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file + encryption scheme service + + A higher-level access to encryption service. + + This is a helper service that storage engines use to encrypt tables on disk. + It requests keys from the plugin, generates temporary or local keys + from the global (as returned by the plugin) keys, etc. + + To use the service: + + * st_encryption_scheme object is created per space. A "space" can be + a table space in XtraDB/InnoDB, a file in Aria, etc. The whole + space is encrypted with the one key id. + + * The service does not take the key and the IV as parameters for + encryption or decryption. Instead it takes two 32-bit integers and + one 64-bit integer (and requests the key from an encryption + plugin, if needed). + + * The service requests the global key from the encryption plugin + automatically as needed. Three last keys are cached in the + st_encryption_scheme. Number of key requests (number of cache + misses) are counted in st_encryption_scheme::keyserver_requests + + * If an st_encryption_scheme can be used concurrently by different + threads, it needs to be able to lock itself when accessing the key + cache. Set the st_encryption_scheme::locker appropriately. If + non-zero, it will be invoked by encrypt/decrypt functions to lock + and unlock the scheme when needed. + + * Implementation details (in particular, key derivation) are defined + by the scheme type. Currently only schema type 1 is supported. + + In the schema type 1, every "space" (table space in XtraDB/InnoDB, + file in Aria) is encrypted with a different space-local key: + + * Every space has a 16-byte unique identifier (typically it's + generated randomly and stored in the space). The caller should + put it into st_encryption_scheme::iv. + + * Space-local key is generated by encrypting this identifier with + the global encryption key (of the given id and version) using AES_ECB. + + * Encryption/decryption parameters for a page are typically the + 4-byte space id, 4-byte page position (offset, page number, etc), + and the 8-byte LSN. This guarantees that they'll be different for + any two pages (of the same or different tablespaces) and also that + they'll change for the same page when it's modified. They don't need + to be secret (they create the IV, not the encryption key). +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#define ENCRYPTION_SCHEME_KEY_INVALID -1 +#define ENCRYPTION_SCHEME_BLOCK_LENGTH 16 + +struct st_encryption_scheme_key { + unsigned int version; + unsigned char key[ENCRYPTION_SCHEME_BLOCK_LENGTH]; +}; + +struct st_encryption_scheme { + unsigned char iv[ENCRYPTION_SCHEME_BLOCK_LENGTH]; + struct st_encryption_scheme_key key[3]; + unsigned int keyserver_requests; + unsigned int key_id; + unsigned int type; + + void (*locker)(struct st_encryption_scheme *self, int release); +}; + +extern struct encryption_scheme_service_st { + int (*encryption_scheme_encrypt_func) + (const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); + int (*encryption_scheme_decrypt_func) + (const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); +} *encryption_scheme_service; + +#ifdef MYSQL_DYNAMIC_PLUGIN + +#define encryption_scheme_encrypt(S,SL,D,DL,SCH,KV,I32,J32,I64) encryption_scheme_service->encryption_scheme_encrypt_func(S,SL,D,DL,SCH,KV,I32,J32,I64) +#define encryption_scheme_decrypt(S,SL,D,DL,SCH,KV,I32,J32,I64) encryption_scheme_service->encryption_scheme_decrypt_func(S,SL,D,DL,SCH,KV,I32,J32,I64) + +#else + +int encryption_scheme_encrypt(const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); +int encryption_scheme_decrypt(const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64); + +#endif + + +#ifdef __cplusplus +} +#endif + +#define MYSQL_SERVICE_ENCRYPTION_SCHEME_INCLUDED +#endif diff --git a/include/mysql/services.h b/include/mysql/services.h index f8f41b19bd9..9d031a9b094 100644 --- a/include/mysql/services.h +++ b/include/mysql/services.h @@ -33,6 +33,7 @@ extern "C" { #include <mysql/service_thd_error_context.h> #include <mysql/service_thd_specifics.h> #include <mysql/service_encryption.h> +#include <mysql/service_encryption_scheme.h> /*#include <mysql/service_wsrep.h>*/ #ifdef __cplusplus diff --git a/include/service_versions.h b/include/service_versions.h index 0f3d8af5723..79b36092a0d 100644 --- a/include/service_versions.h +++ b/include/service_versions.h @@ -36,4 +36,5 @@ #define VERSION_thd_error_context 0x0100 #define VERSION_thd_specifics 0x0100 #define VERSION_encryption 0x0200 +#define VERSION_encryption_scheme 0x0100 diff --git a/libservices/CMakeLists.txt b/libservices/CMakeLists.txt index 1dc472612e6..62181a00aa2 100644 --- a/libservices/CMakeLists.txt +++ b/libservices/CMakeLists.txt @@ -29,6 +29,7 @@ SET(MYSQLSERVICES_SOURCES my_md5_service.c wsrep_service.c encryption_service.c + encryption_scheme_service.c kill_statement_service.c logger_service.c) diff --git a/libservices/encryption_scheme_service.c b/libservices/encryption_scheme_service.c new file mode 100644 index 00000000000..87d85df16b4 --- /dev/null +++ b/libservices/encryption_scheme_service.c @@ -0,0 +1,17 @@ +/* Copyright (c) 2015 MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include <service_versions.h> +SERVICE_VERSION encryption_scheme_service= (void*)VERSION_encryption_scheme; diff --git a/mysql-test/r/handlersocket.result b/mysql-test/r/handlersocket.result index 2332a8b2c7f..e38de6bf5c2 100644 --- a/mysql-test/r/handlersocket.result +++ b/mysql-test/r/handlersocket.result @@ -5,7 +5,7 @@ plugin_version 1.0 plugin_status ACTIVE plugin_type DAEMON plugin_library handlersocket.so -plugin_library_version 1.10 +plugin_library_version 1.11 plugin_author higuchi dot akira at dena dot jp plugin_description Direct access into InnoDB plugin_license BSD diff --git a/mysql-test/r/plugin.result b/mysql-test/r/plugin.result index 9f4aff6bae9..42a29f25432 100644 --- a/mysql-test/r/plugin.result +++ b/mysql-test/r/plugin.result @@ -15,7 +15,7 @@ PLUGIN_STATUS ACTIVE PLUGIN_TYPE STORAGE ENGINE PLUGIN_TYPE_VERSION # PLUGIN_LIBRARY ha_example.so -PLUGIN_LIBRARY_VERSION 1.10 +PLUGIN_LIBRARY_VERSION 1.11 PLUGIN_AUTHOR Brian Aker, MySQL AB PLUGIN_DESCRIPTION Example storage engine PLUGIN_LICENSE GPL @@ -28,7 +28,7 @@ PLUGIN_STATUS ACTIVE PLUGIN_TYPE DAEMON PLUGIN_TYPE_VERSION # PLUGIN_LIBRARY ha_example.so -PLUGIN_LIBRARY_VERSION 1.10 +PLUGIN_LIBRARY_VERSION 1.11 PLUGIN_AUTHOR Sergei Golubchik PLUGIN_DESCRIPTION Unusable Daemon PLUGIN_LICENSE GPL @@ -67,7 +67,7 @@ PLUGIN_STATUS DELETED PLUGIN_TYPE STORAGE ENGINE PLUGIN_TYPE_VERSION # PLUGIN_LIBRARY ha_example.so -PLUGIN_LIBRARY_VERSION 1.10 +PLUGIN_LIBRARY_VERSION 1.11 PLUGIN_AUTHOR Brian Aker, MySQL AB PLUGIN_DESCRIPTION Example storage engine PLUGIN_LICENSE GPL diff --git a/mysql-test/suite/plugins/r/show_all_plugins.result b/mysql-test/suite/plugins/r/show_all_plugins.result index f07bafe3536..623e8e9314b 100644 --- a/mysql-test/suite/plugins/r/show_all_plugins.result +++ b/mysql-test/suite/plugins/r/show_all_plugins.result @@ -4,8 +4,8 @@ Variable_name Value Opened_plugin_libraries 0 select * from information_schema.all_plugins where plugin_library='ha_example.so'; PLUGIN_NAME PLUGIN_VERSION PLUGIN_STATUS PLUGIN_TYPE PLUGIN_TYPE_VERSION PLUGIN_LIBRARY PLUGIN_LIBRARY_VERSION PLUGIN_AUTHOR PLUGIN_DESCRIPTION PLUGIN_LICENSE LOAD_OPTION PLUGIN_MATURITY PLUGIN_AUTH_VERSION -EXAMPLE 0.1 NOT INSTALLED STORAGE ENGINE MYSQL_VERSION_ID ha_example.so 1.10 Brian Aker, MySQL AB Example storage engine GPL OFF Experimental 0.1 -UNUSABLE 3.14 NOT INSTALLED DAEMON MYSQL_VERSION_ID ha_example.so 1.10 Sergei Golubchik Unusable Daemon GPL OFF Experimental 3.14.15.926 +EXAMPLE 0.1 NOT INSTALLED STORAGE ENGINE MYSQL_VERSION_ID ha_example.so 1.11 Brian Aker, MySQL AB Example storage engine GPL OFF Experimental 0.1 +UNUSABLE 3.14 NOT INSTALLED DAEMON MYSQL_VERSION_ID ha_example.so 1.11 Sergei Golubchik Unusable Daemon GPL OFF Experimental 3.14.15.926 show status like '%libraries%'; Variable_name Value Opened_plugin_libraries 1 diff --git a/mysql-test/suite/plugins/r/simple_password_check.result b/mysql-test/suite/plugins/r/simple_password_check.result index b6906fc923a..c74471a651a 100644 --- a/mysql-test/suite/plugins/r/simple_password_check.result +++ b/mysql-test/suite/plugins/r/simple_password_check.result @@ -6,7 +6,7 @@ PLUGIN_STATUS ACTIVE PLUGIN_TYPE PASSWORD VALIDATION PLUGIN_TYPE_VERSION 1.0 PLUGIN_LIBRARY simple_password_check.so -PLUGIN_LIBRARY_VERSION 1.10 +PLUGIN_LIBRARY_VERSION 1.11 PLUGIN_AUTHOR Sergei Golubchik PLUGIN_DESCRIPTION Simple password strength checks PLUGIN_LICENSE GPL diff --git a/sql/encryption.cc b/sql/encryption.cc index 44208baf8b3..ab551e00d07 100644 --- a/sql/encryption.cc +++ b/sql/encryption.cc @@ -103,3 +103,110 @@ int finalize_encryption_plugin(st_plugin_int *plugin) return 0; } +/****************************************************************** + Encryption Scheme service +******************************************************************/ +static uint scheme_get_key(st_encryption_scheme *scheme, + st_encryption_scheme_key *key) +{ + if (scheme->locker) + scheme->locker(scheme, 0); + + // Check if we already have key + for (uint i = 0; i < array_elements(scheme->key); i++) + { + if (scheme->key[i].version == 0) // no more keys + break; + + if (scheme->key[i].version == key->version) + { + *key= scheme->key[i]; + if (scheme->locker) + scheme->locker(scheme, 1); + return 0; + } + } + + // Not found! + scheme->keyserver_requests++; + + uchar global_key[MY_AES_MAX_KEY_LENGTH]; + uint global_key_len= sizeof(global_key), key_len; + + uint rc = encryption_key_get(scheme->key_id, key->version, + global_key, & global_key_len); + if (rc) + goto ret; + + /* Now generate the local key by encrypting IV using the global key */ + rc = my_aes_encrypt_ecb(scheme->iv, sizeof(scheme->iv), key->key, &key_len, + global_key, global_key_len, NULL, 0, 1); + + DBUG_ASSERT(key_len == sizeof(key->key)); + + if (rc) + goto ret; + + // Rotate keys to make room for a new + for (uint i = array_elements(scheme->key) - 1; i; i--) + scheme->key[i] = scheme->key[i - 1]; + + scheme->key[0]= *key; + +ret: + if (scheme->locker) + scheme->locker(scheme, 1); + return rc; +} + +int do_crypt(const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64, + encrypt_decrypt_func crypt) +{ + compile_time_assert(ENCRYPTION_SCHEME_KEY_INVALID == + (int)ENCRYPTION_KEY_VERSION_INVALID); + + DBUG_ASSERT(scheme->type == 1); + + if (key_version == ENCRYPTION_KEY_VERSION_INVALID || + key_version == ENCRYPTION_KEY_NOT_ENCRYPTED) + return ENCRYPTION_SCHEME_KEY_INVALID; + + st_encryption_scheme_key key; + key.version= key_version; + uint rc= scheme_get_key(scheme, &key); + if (rc) + return (int)rc; + + unsigned char iv[4 + 4 + 8]; + int4store(iv + 0, i32_1); + int4store(iv + 4, i32_2); + int8store(iv + 8, i64); + + return crypt(src, slen, dst, dlen, key.key, sizeof(key.key), + iv, sizeof(iv), 1, scheme->key_id, key_version); +} + +int encryption_scheme_encrypt(const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64) +{ + return do_crypt(src, slen, dst, dlen, scheme, key_version, i32_1, + i32_2, i64, encryption_handler.encryption_encrypt_func); +} + + +int encryption_scheme_decrypt(const unsigned char* src, unsigned int slen, + unsigned char* dst, unsigned int* dlen, + struct st_encryption_scheme *scheme, + unsigned int key_version, unsigned int i32_1, + unsigned int i32_2, unsigned long long i64) +{ + return do_crypt(src, slen, dst, dlen, scheme, key_version, i32_1, + i32_2, i64, encryption_handler.encryption_decrypt_func); +} diff --git a/sql/sql_plugin_services.h b/sql/sql_plugin_services.h index b848dfb8f6b..4bb1861281e 100644 --- a/sql/sql_plugin_services.h +++ b/sql/sql_plugin_services.h @@ -147,6 +147,12 @@ static struct thd_specifics_service_st thd_specifics_handler= thd_setspecific }; +static struct encryption_scheme_service_st encryption_scheme_handler= +{ + encryption_scheme_encrypt, + encryption_scheme_decrypt +}; + static struct st_service_ref list_of_services[]= { { "my_snprintf_service", VERSION_my_snprintf, &my_snprintf_handler }, @@ -162,6 +168,7 @@ static struct st_service_ref list_of_services[]= { "thd_autoinc_service", VERSION_thd_autoinc, &thd_autoinc_handler }, { "wsrep_service", VERSION_wsrep, &wsrep_handler }, { "encryption_service", VERSION_encryption, &encryption_handler }, + { "encryption_scheme_service", VERSION_encryption_scheme, &encryption_scheme_handler }, { "thd_specifics_service", VERSION_thd_specifics, &thd_specifics_handler }, { "thd_error_context_service", VERSION_thd_error_context, &thd_error_conext_handler }, }; diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 513bdf594e9..7d7755efdf9 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -150,82 +150,6 @@ fil_space_crypt_cleanup() } /****************************************************************** -Get key bytes for a space/key-version */ -static -void -fil_crypt_get_key( -/*==============*/ - byte* dst, /*<! out: Key */ - uint* key_length, /*<! out: Key length */ - fil_space_crypt_t* crypt_data, /*<! in: crypt data */ - uint version) /*<! in: Key version */ -{ - unsigned char keybuf[MY_AES_MAX_KEY_LENGTH]; - - 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, - crypt_data->keys[i].key_length); - *key_length = crypt_data->keys[i].key_length; - mutex_exit(&crypt_data->mutex); - return; - } - } - - // 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]; - } - - *key_length = sizeof(keybuf); - uint rc = encryption_key_get(crypt_data->key_id, version, keybuf, key_length); - if (rc) { - ib_logf(IB_LOG_LEVEL_FATAL, - "Key id %u version %u can not be found. Reason=%u", - crypt_data->key_id, version, rc); - ut_error; - } - - /* Now compute L by encrypting IV using this key. Note - that we use random IV from crypt data. */ - const unsigned char* src = crypt_data->iv; - const int srclen = crypt_data->iv_length; - unsigned char* buf = crypt_data->keys[0].key; - uint32 buflen = CRYPT_SCHEME_1_IV_LEN; - - /* We use AES_ECB to encrypt IV */ - rc = my_aes_encrypt_ecb(src, srclen, buf, &buflen, - keybuf, *key_length, NULL, 0, 1); - - if (rc != MY_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; - } - - crypt_data->keys[0].key_version = version; - crypt_data->key_count++; - *key_length = buflen; - crypt_data->keys[0].key_length = buflen; - - if (crypt_data->key_count > array_elements(crypt_data->keys)) { - crypt_data->key_count = array_elements(crypt_data->keys); - } - - memcpy(dst, buf, buflen); - mutex_exit(&crypt_data->mutex); -} - -/****************************************************************** Get the latest(key-version), waking the encrypt thread, if needed */ static inline uint @@ -244,27 +168,17 @@ fil_crypt_get_latest_key_version( } /****************************************************************** -Get key bytes for a space/latest(key-version) */ -static inline -void -fil_crypt_get_latest_key( -/*=====================*/ - byte* dst, /*!< out: Key */ - uint* key_length, /*!< out: Key length */ - fil_space_crypt_t* crypt_data, /*!< in: crypt data */ - uint* version) /*!< in: Key version */ +Mutex helper for crypt_data->scheme */ +static void crypt_data_scheme_locker(st_encryption_scheme *scheme, int exit) { - // used for key rotation - get the next key id from the key provider - uint rc = *version = fil_crypt_get_latest_key_version(crypt_data); + fil_space_crypt_t* crypt_data = + static_cast<fil_space_crypt_t*>(scheme); - if (rc == ENCRYPTION_KEY_VERSION_INVALID) { - ib_logf(IB_LOG_LEVEL_FATAL, - "Unknown key id %u. Can't continue!\n", - crypt_data->key_id); - ut_error; + if (exit) { + mutex_exit(&crypt_data->mutex); + } else { + mutex_enter(&crypt_data->mutex); } - - return fil_crypt_get_key(dst, key_length, crypt_data, *version); } /****************************************************************** @@ -277,8 +191,7 @@ fil_space_create_crypt_data( fil_encryption_t encrypt_mode, /*!< in: encryption mode */ uint key_id) /*!< in: encryption key id */ { - const uint iv_length = CRYPT_SCHEME_1_IV_LEN; - const uint sz = sizeof(fil_space_crypt_t) + iv_length; + const uint sz = sizeof(fil_space_crypt_t); fil_space_crypt_t* crypt_data = static_cast<fil_space_crypt_t*>(malloc(sz)); @@ -290,14 +203,14 @@ fil_space_create_crypt_data( crypt_data->min_key_version = 0; } else { crypt_data->type = CRYPT_SCHEME_1; - crypt_data->key_id = key_id; + crypt_data->key_id = key_id; crypt_data->min_key_version = encryption_key_get_latest_version(key_id); } mutex_create(fil_crypt_data_mutex_key, &crypt_data->mutex, SYNC_NO_ORDER_CHECK); - crypt_data->iv_length = iv_length; - my_random_bytes(crypt_data->iv, iv_length); + crypt_data->locker = crypt_data_scheme_locker; + my_random_bytes(crypt_data->iv, sizeof(crypt_data->iv)); crypt_data->encryption = FIL_SPACE_ENCRYPTION_DEFAULT; return crypt_data; } @@ -317,12 +230,9 @@ fil_space_crypt_compare( ut_a(crypt_data2->type == CRYPT_SCHEME_UNENCRYPTED || crypt_data2->type == CRYPT_SCHEME_1); - ut_a(crypt_data1->iv_length == CRYPT_SCHEME_1_IV_LEN); - ut_a(crypt_data2->iv_length == CRYPT_SCHEME_1_IV_LEN); - /* no support for changing iv (yet?) */ ut_a(memcmp(crypt_data1->iv, crypt_data2->iv, - crypt_data1->iv_length) == 0); + sizeof(crypt_data1->iv)) == 0); return 0; } @@ -378,9 +288,10 @@ fil_space_read_crypt_data( ut_error; } + fil_space_crypt_t* crypt_data; ulint iv_length = mach_read_from_1(page + offset + MAGIC_SZ + 1); - if (! (iv_length == CRYPT_SCHEME_1_IV_LEN)) { + if (! (iv_length == sizeof(crypt_data->iv))) { ib_logf(IB_LOG_LEVEL_ERROR, "Found non sensible iv length: %lu for space %lu " " offset: %lu type: %lu bytes: " @@ -405,8 +316,7 @@ fil_space_read_crypt_data( page + offset + MAGIC_SZ + 2 + iv_length + 8); const uint sz = sizeof(fil_space_crypt_t) + iv_length; - fil_space_crypt_t* crypt_data = static_cast<fil_space_crypt_t*>( - malloc(sz)); + crypt_data = static_cast<fil_space_crypt_t*>(malloc(sz)); memset(crypt_data, 0, sz); crypt_data->type = type; @@ -416,7 +326,7 @@ fil_space_read_crypt_data( crypt_data->encryption = encryption; mutex_create(fil_crypt_data_mutex_key, &crypt_data->mutex, SYNC_NO_ORDER_CHECK); - crypt_data->iv_length = iv_length; + crypt_data->locker = crypt_data_scheme_locker; memcpy(crypt_data->iv, page + offset + MAGIC_SZ + 2, iv_length); return crypt_data; @@ -453,7 +363,7 @@ fil_space_write_crypt_data_low( ut_a(offset > 0 && offset < UNIV_PAGE_SIZE); ulint space_id = mach_read_from_4( page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); - const uint len = crypt_data->iv_length; + const uint len = sizeof(crypt_data->iv); const uint min_key_version = crypt_data->min_key_version; const uint key_id = crypt_data->key_id; const fil_encryption_t encryption = crypt_data->encryption; @@ -662,9 +572,6 @@ fil_space_encrypt( fil_space_crypt_t* crypt_data = NULL; ulint page_size = (zip_size) ? zip_size : UNIV_PAGE_SIZE; uint key_version; - unsigned char key[MY_AES_MAX_KEY_LENGTH]; - uint key_length = MY_AES_MAX_KEY_LENGTH; - unsigned char iv[MY_AES_BLOCK_SIZE]; ulint orig_page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE); @@ -686,12 +593,14 @@ fil_space_encrypt( return; } - fil_crypt_get_latest_key(key, &key_length, crypt_data, &key_version); + key_version = fil_crypt_get_latest_key_version(crypt_data); - /* create iv/counter */ - mach_write_to_4(iv + 0, space); - mach_write_to_4(iv + 4, offset); - mach_write_to_8(iv + 8, lsn); + if (key_version == ENCRYPTION_KEY_VERSION_INVALID) { + ib_logf(IB_LOG_LEVEL_FATAL, + "Unknown key id %u. Can't continue!\n", + crypt_data->key_id); + ut_error; + } ibool page_compressed = (mach_read_from_2(src_frame+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED); @@ -719,9 +628,9 @@ fil_space_encrypt( dst+=2; } - int rc = encryption_encrypt(src, srclen, dst, &dstlen, - key, key_length, iv, sizeof(iv), 1, - crypt_data->key_id, key_version); + int rc = encryption_scheme_encrypt(src, srclen, dst, &dstlen, + crypt_data, key_version, + space, offset, lsn); if (! ((rc == MY_AES_OK) && ((ulint) dstlen == srclen))) { ib_logf(IB_LOG_LEVEL_FATAL, @@ -837,17 +746,6 @@ fil_space_decrypt( /* Copy FIL page header, it is not encrypted */ memcpy(dst_frame, src_frame, FIL_PAGE_DATA); - /* Get key */ - byte key[MY_AES_MAX_KEY_LENGTH]; - uint key_length; - unsigned char iv[MY_AES_BLOCK_SIZE]; - fil_crypt_get_key(key, &key_length, crypt_data, key_version); - - /* create iv/counter */ - mach_write_to_4(iv + 0, space); - mach_write_to_4(iv + 4, offset); - mach_write_to_8(iv + 8, lsn); - /* Calculate the offset where decryption starts */ const byte* src = src_frame + FIL_PAGE_DATA; byte* dst = dst_frame + FIL_PAGE_DATA; @@ -865,9 +763,9 @@ fil_space_decrypt( srclen = compressed_len; } - int rc = encryption_decrypt(src, srclen, dst, &dstlen, key, key_length, - iv, sizeof(iv), 1, - crypt_data->key_id, key_version); + int rc = encryption_scheme_decrypt(src, srclen, dst, &dstlen, + crypt_data, key_version, + space, offset, lsn); if (! ((rc == MY_AES_OK) && ((ulint) dstlen == srclen))) { ib_logf(IB_LOG_LEVEL_FATAL, diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ded1680bfb2..b837ac43909 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -11729,8 +11729,7 @@ ha_innobase::create( /* If there is old crypt data, copy IV */ if (old_crypt_data) { - memcpy(crypt_data->iv, old_crypt_data->iv, old_crypt_data->iv_length); - crypt_data->iv_length = old_crypt_data->iv_length; + memcpy(crypt_data->iv, old_crypt_data->iv, sizeof(crypt_data->iv)); } mtr_t mtr; diff --git a/storage/innobase/include/fil0crypt.h b/storage/innobase/include/fil0crypt.h index 12f0946f28c..32d3c46585f 100644 --- a/storage/innobase/include/fil0crypt.h +++ b/storage/innobase/include/fil0crypt.h @@ -80,13 +80,8 @@ struct fil_space_rotate_state_t } scrubbing; }; -struct fil_space_crypt_struct +struct fil_space_crypt_struct : st_encryption_scheme { - ulint type; // CRYPT_SCHEME - uint keyserver_requests; // no of key requests to key server - uint key_count; // No of initalized key-structs - uint key_id; // Key id for this space - key_struct keys[3]; // cached L = AES_ECB(KEY, IV) uint min_key_version; // min key version for this space ulint page0_offset; // byte offset on page 0 for crypt data fil_encryption_t encryption; // Encryption setup @@ -94,9 +89,6 @@ struct fil_space_crypt_struct ib_mutex_t mutex; // mutex protecting following variables bool closing; // is tablespace being closed fil_space_rotate_state_t rotate_state; - - uint iv_length; // length of IV - byte iv[1]; // IV-data }; /* structure containing encryption specification */ diff --git a/storage/maria/ma_check_standalone.h b/storage/maria/ma_check_standalone.h index 693de8a8a56..c240ca056e7 100644 --- a/storage/maria/ma_check_standalone.h +++ b/storage/maria/ma_check_standalone.h @@ -33,6 +33,33 @@ struct encryption_service_st encryption_handler= no_key, 0, 0, 0, 0, 0 }; +int encryption_scheme_encrypt(const unsigned char* src __attribute__((unused)), + unsigned int slen __attribute__((unused)), + unsigned char* dst __attribute__((unused)), + unsigned int* dlen __attribute__((unused)), + struct st_encryption_scheme *scheme __attribute__((unused)), + unsigned int key_version __attribute__((unused)), + unsigned int i32_1 __attribute__((unused)), + unsigned int i32_2 __attribute__((unused)), + unsigned long long i64 __attribute__((unused))) +{ + return -1; +} + + +int encryption_scheme_decrypt(const unsigned char* src __attribute__((unused)), + unsigned int slen __attribute__((unused)), + unsigned char* dst __attribute__((unused)), + unsigned int* dlen __attribute__((unused)), + struct st_encryption_scheme *scheme __attribute__((unused)), + unsigned int key_version __attribute__((unused)), + unsigned int i32_1 __attribute__((unused)), + unsigned int i32_2 __attribute__((unused)), + unsigned long long i64 __attribute__((unused))) +{ + return -1; +} + /* only those that included myisamchk.h may need and can use the below */ #ifdef _myisamchk_h /* diff --git a/storage/maria/ma_crypt.c b/storage/maria/ma_crypt.c index c0a260c405f..b327d528678 100644 --- a/storage/maria/ma_crypt.c +++ b/storage/maria/ma_crypt.c @@ -39,14 +39,9 @@ struct st_crypt_key struct st_maria_crypt_data { - uchar type; - uint keyid; + struct st_encryption_scheme scheme; + uint space; mysql_mutex_t lock; /* protecting keys */ - uint keyserver_requests; /* # of key requests to key server */ - uint key_count; /* # of initalized key-structs */ - struct st_crypt_key keys[3]; /* cached L = AES_ECB(KEY, IV) */ - uchar iv_length; - uchar iv[1]; /* variable size */ }; uint @@ -77,19 +72,27 @@ ma_crypt_get_file_length() return 2 + CRYPT_SCHEME_1_IV_LEN + CRYPT_SCHEME_1_ID_LEN; } +static void crypt_data_scheme_locker(struct st_encryption_scheme *scheme, + int unlock) +{ + MARIA_CRYPT_DATA *crypt_data = (MARIA_CRYPT_DATA*)scheme; + if (unlock) + mysql_mutex_unlock(&crypt_data->lock); + else + mysql_mutex_lock(&crypt_data->lock); +} + int ma_crypt_create(MARIA_SHARE* share) { - const uint iv_length= CRYPT_SCHEME_1_IV_LEN + CRYPT_SCHEME_1_ID_LEN; - const uint sz= sizeof(MARIA_CRYPT_DATA) + iv_length; - MARIA_CRYPT_DATA *crypt_data= (MARIA_CRYPT_DATA*)my_malloc(sz, MYF(0)); - bzero(crypt_data, sz); - crypt_data->type= CRYPT_SCHEME_1; - crypt_data->key_count= 0; + MARIA_CRYPT_DATA *crypt_data= + (MARIA_CRYPT_DATA*)my_malloc(sizeof(MARIA_CRYPT_DATA), MYF(MY_ZEROFILL)); + crypt_data->scheme.type= CRYPT_SCHEME_1; + crypt_data->scheme.locker= crypt_data_scheme_locker; mysql_mutex_init(key_CRYPT_DATA_lock, &crypt_data->lock, MY_MUTEX_INIT_FAST); - crypt_data->keyid= HARD_CODED_ENCRYPTION_KEY_ID; - crypt_data->iv_length= iv_length; - my_random_bytes(crypt_data->iv, iv_length); + crypt_data->scheme.key_id= HARD_CODED_ENCRYPTION_KEY_ID; + my_random_bytes(crypt_data->scheme.iv, sizeof(crypt_data->scheme.iv)); + my_random_bytes((uchar*)&crypt_data->space, sizeof(crypt_data->space)); share->crypt_data= crypt_data; share->crypt_page_header_space= CRYPT_SCHEME_1_KEY_VERSION_SIZE; return 0; @@ -109,19 +112,18 @@ ma_crypt_free(MARIA_SHARE* share) int ma_crypt_write(MARIA_SHARE* share, File file) { - uchar buff[2]; MARIA_CRYPT_DATA *crypt_data= share->crypt_data; + uchar buff[2 + 4 + sizeof(crypt_data->scheme.iv)]; if (crypt_data == 0) return 0; - buff[0]= crypt_data->type; - buff[1]= crypt_data->iv_length; + buff[0]= crypt_data->scheme.type; + buff[1]= sizeof(buff) - 2; - if (mysql_file_write(file, buff, 2, MYF(MY_NABP))) - return 1; + int4store(buff + 2, crypt_data->space); + memcpy(buff + 6, crypt_data->scheme.iv, sizeof(crypt_data->scheme.iv)); - if (mysql_file_write(file, crypt_data->iv, crypt_data->iv_length, - MYF(MY_NABP))) + if (mysql_file_write(file, buff, sizeof(buff), MYF(MY_NABP))) return 1; return 0; @@ -132,29 +134,10 @@ ma_crypt_read(MARIA_SHARE* share, uchar *buff) { uchar type= buff[0]; uchar iv_length= buff[1]; - if (share->crypt_data == NULL) - { - /* opening a table */ - const uint sz= sizeof(MARIA_CRYPT_DATA) + iv_length; - MARIA_CRYPT_DATA *crypt_data= (MARIA_CRYPT_DATA*)my_malloc(sz, MYF(0)); - crypt_data->type= type; - crypt_data->key_count= 0; - mysql_mutex_init(key_CRYPT_DATA_lock, &crypt_data->lock, - MY_MUTEX_INIT_FAST); - crypt_data->keyid= HARD_CODED_ENCRYPTION_KEY_ID; - crypt_data->iv_length= iv_length; - memcpy(crypt_data->iv, buff + 2, iv_length); - share->crypt_data= crypt_data; - } - else - { - /* creating a table */ - assert(type == share->crypt_data->type); - assert(iv_length == share->crypt_data->iv_length); - } /* currently only supported type */ - if (type != CRYPT_SCHEME_1) + if (type != CRYPT_SCHEME_1 || + iv_length != sizeof(((MARIA_CRYPT_DATA*)1)->scheme.iv) + 4) { my_printf_error(HA_ERR_UNSUPPORTED, "Unsupported crypt scheme! type: %d iv_length: %d\n", @@ -163,6 +146,22 @@ ma_crypt_read(MARIA_SHARE* share, uchar *buff) return 0; } + if (share->crypt_data == NULL) + { + /* opening a table */ + MARIA_CRYPT_DATA *crypt_data= + (MARIA_CRYPT_DATA*)my_malloc(sizeof(MARIA_CRYPT_DATA), MYF(MY_ZEROFILL)); + + crypt_data->scheme.type= type; + mysql_mutex_init(key_CRYPT_DATA_lock, &crypt_data->lock, + MY_MUTEX_INIT_FAST); + crypt_data->scheme.locker= crypt_data_scheme_locker; + crypt_data->scheme.key_id= HARD_CODED_ENCRYPTION_KEY_ID; + crypt_data->space= uint4korr(buff + 2); + memcpy(crypt_data->scheme.iv, buff + 6, sizeof(crypt_data->scheme.iv)); + share->crypt_data= crypt_data; + } + share->crypt_page_header_space= CRYPT_SCHEME_1_KEY_VERSION_SIZE; return buff + 2 + iv_length; } @@ -425,100 +424,6 @@ void ma_crypt_set_index_pagecache_callbacks(PAGECACHE_FILE *file, file->post_write_hook= ma_crypt_post_write_hook; } -/** - get key bytes for a table and key-version -*/ -static int ma_crypt_get_key(uchar *dst, uint dstlen, - MARIA_CRYPT_DATA *crypt_data, uint version) -{ - int rc; - uint i; - uchar keybuf[CRYPT_SCHEME_1_IV_LEN]; - uint keylen= sizeof(keybuf); - - DBUG_ASSERT(dstlen == sizeof(crypt_data->keys[0].key)); - - mysql_mutex_lock(&crypt_data->lock); - - /* Check if we already have key */ - for (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)); - mysql_mutex_unlock(&crypt_data->lock); - return 0; - } - } - - /* Not found! */ - crypt_data->keyserver_requests++; - - /* Rotate keys to make room for a new */ - for (i= 1; i < array_elements(crypt_data->keys); i++) - crypt_data->keys[i]= crypt_data->keys[i - 1]; - - /* Get new key from key server */ - rc= encryption_key_get(crypt_data->keyid, version, keybuf, &keylen); - if (rc != 0) - { - my_printf_error(HA_ERR_GENERIC, - "Key id %u version %u can not be found. Reason=%u", - MYF(ME_FATALERROR|ME_NOREFRESH), - crypt_data->keyid, version, rc ); - return 1; - } - - /* Now compute L by encrypting IV using this key */ - { - const uchar* src= crypt_data->iv; - const int srclen= CRYPT_SCHEME_1_IV_LEN; - uchar* buf= crypt_data->keys[0].key; - uint buflen= sizeof(crypt_data->keys[0].key); - rc = my_aes_encrypt_ecb(src, srclen, buf, &buflen, - keybuf, keylen, NULL, 0, 1); - if (rc != MY_AES_OK) - { - my_printf_error(HA_ERR_GENERIC, - "Unable to encrypt key-block " - " src: %p srclen: %d buf: %p buflen: %d." - " return-code: %d. Can't continue!", - MYF(ME_FATALERROR|ME_NOREFRESH), - src, srclen, buf, buflen, rc); - return 1; - } - } - - 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); - - memcpy(dst, crypt_data->keys[0].key, sizeof(crypt_data->keys[0].key)); - mysql_mutex_unlock(&crypt_data->lock); - return 0; -} - -/****************************************************************** -Get key bytes for a table and latest key-version */ -static int ma_crypt_get_latest_key(uchar *dst, uint dstlen, - MARIA_CRYPT_DATA* crypt_data, uint *version) -{ - uint rc = *version = encryption_key_get_latest_version(crypt_data->keyid); - if (rc == ENCRYPTION_KEY_VERSION_INVALID) - { - my_printf_error(HA_ERR_GENERIC, - "Unknown key id %u. Can't continue!", - MYF(ME_FATALERROR|ME_NOREFRESH), - crypt_data->keyid); - return 1; - } - return ma_crypt_get_key(dst, dstlen, crypt_data, *version); -} - -#define COUNTER_LEN MY_AES_BLOCK_SIZE - static int ma_encrypt(MARIA_CRYPT_DATA *crypt_data, const uchar *src, uchar *dst, uint size, uint pageno, LSN lsn, @@ -526,22 +431,18 @@ static int ma_encrypt(MARIA_CRYPT_DATA *crypt_data, { int rc; uint32 dstlen; - uchar counter[COUNTER_LEN]; - uchar key[CRYPT_SCHEME_1_IV_LEN]; - // get key (L) and key_version - if (ma_crypt_get_latest_key(key, sizeof(key), crypt_data, key_version)) + *key_version = encryption_key_get_latest_version(crypt_data->scheme.key_id); + if (*key_version == ENCRYPTION_KEY_VERSION_INVALID) + { + my_printf_error(HA_ERR_GENERIC, "Unknown key id %u. Can't continue!", + MYF(ME_FATALERROR|ME_NOREFRESH), crypt_data->scheme.key_id); return 1; + } - /* create counter block */ - memcpy(counter + 0, crypt_data->iv + CRYPT_SCHEME_1_IV_LEN, 4); - int4store(counter + 4, pageno); - int8store(counter + 8, lsn); - - rc= encryption_encrypt(src, size, dst, &dstlen, - crypt_data->iv, CRYPT_SCHEME_1_IV_LEN, - counter, sizeof(counter), 1, - crypt_data->keyid, *key_version); + rc= encryption_scheme_encrypt(src, size, dst, &dstlen, + &crypt_data->scheme, *key_version, + crypt_data->space, pageno, lsn); DBUG_ASSERT(rc == MY_AES_OK); DBUG_ASSERT(dstlen == size); @@ -564,22 +465,10 @@ static int ma_decrypt(MARIA_CRYPT_DATA *crypt_data, { int rc; uint32 dstlen; - uchar counter[COUNTER_LEN]; - uchar key[CRYPT_SCHEME_1_IV_LEN]; - - // get key (L) and key_version - if (ma_crypt_get_key(key, sizeof(key), crypt_data, key_version)) - return 1; - - /* create counter block */ - memcpy(counter + 0, crypt_data->iv + CRYPT_SCHEME_1_IV_LEN, 4); - int4store(counter + 4, pageno); - int8store(counter + 8, lsn); - rc =encryption_decrypt(src, size, dst, &dstlen, - crypt_data->iv, CRYPT_SCHEME_1_IV_LEN, - counter, sizeof(counter), 1, crypt_data->keyid, - key_version); + rc= encryption_scheme_decrypt(src, size, dst, &dstlen, + &crypt_data->scheme, key_version, + crypt_data->space, pageno, lsn); DBUG_ASSERT(rc == MY_AES_OK); DBUG_ASSERT(dstlen == size); diff --git a/storage/xtradb/fil/fil0crypt.cc b/storage/xtradb/fil/fil0crypt.cc index 2d8ac3cef39..878c34a5091 100644 --- a/storage/xtradb/fil/fil0crypt.cc +++ b/storage/xtradb/fil/fil0crypt.cc @@ -150,82 +150,6 @@ fil_space_crypt_cleanup() } /****************************************************************** -Get key bytes for a space/key-version */ -static -void -fil_crypt_get_key( -/*==============*/ - byte* dst, /*<! out: Key */ - uint* key_length, /*<! out: Key length */ - fil_space_crypt_t* crypt_data, /*<! in: crypt data */ - uint version) /*<! in: Key version */ -{ - unsigned char keybuf[MY_AES_MAX_KEY_LENGTH]; - - 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, - crypt_data->keys[i].key_length); - *key_length = crypt_data->keys[i].key_length; - mutex_exit(&crypt_data->mutex); - return; - } - } - - // 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]; - } - - *key_length = sizeof(keybuf); - uint rc = encryption_key_get(crypt_data->key_id, version, keybuf, key_length); - if (rc) { - ib_logf(IB_LOG_LEVEL_FATAL, - "Key id %u version %u can not be found. Reason=%u", - crypt_data->key_id, version, rc); - ut_error; - } - - /* Now compute L by encrypting IV using this key. Note - that we use random IV from crypt data. */ - const unsigned char* src = crypt_data->iv; - const int srclen = crypt_data->iv_length; - unsigned char* buf = crypt_data->keys[0].key; - uint32 buflen = CRYPT_SCHEME_1_IV_LEN; - - /* We use AES_ECB to encrypt IV */ - rc = my_aes_encrypt_ecb(src, srclen, buf, &buflen, - keybuf, *key_length, NULL, 0, 1); - - if (rc != MY_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; - } - - crypt_data->keys[0].key_version = version; - crypt_data->key_count++; - *key_length = buflen; - crypt_data->keys[0].key_length = buflen; - - if (crypt_data->key_count > array_elements(crypt_data->keys)) { - crypt_data->key_count = array_elements(crypt_data->keys); - } - - memcpy(dst, buf, buflen); - mutex_exit(&crypt_data->mutex); -} - -/****************************************************************** Get the latest(key-version), waking the encrypt thread, if needed */ static inline uint @@ -244,27 +168,17 @@ fil_crypt_get_latest_key_version( } /****************************************************************** -Get key bytes for a space/latest(key-version) */ -static inline -void -fil_crypt_get_latest_key( -/*=====================*/ - byte* dst, /*!< out: Key */ - uint* key_length, /*!< out: Key length */ - fil_space_crypt_t* crypt_data, /*!< in: crypt data */ - uint* version) /*!< in: Key version */ +Mutex helper for crypt_data->scheme */ +static void crypt_data_scheme_locker(st_encryption_scheme *scheme, int exit) { - // used for key rotation - get the next key id from the key provider - uint rc = *version = fil_crypt_get_latest_key_version(crypt_data); + fil_space_crypt_t* crypt_data = + static_cast<fil_space_crypt_t*>(scheme); - if (rc == ENCRYPTION_KEY_VERSION_INVALID) { - ib_logf(IB_LOG_LEVEL_FATAL, - "Unknown key id %u. Can't continue!\n", - crypt_data->key_id); - ut_error; + if (exit) { + mutex_exit(&crypt_data->mutex); + } else { + mutex_enter(&crypt_data->mutex); } - - return fil_crypt_get_key(dst, key_length, crypt_data, *version); } /****************************************************************** @@ -277,8 +191,7 @@ fil_space_create_crypt_data( fil_encryption_t encrypt_mode, /*!< in: encryption mode */ uint key_id) /*!< in: encryption key id */ { - const uint iv_length = CRYPT_SCHEME_1_IV_LEN; - const uint sz = sizeof(fil_space_crypt_t) + iv_length; + const uint sz = sizeof(fil_space_crypt_t); fil_space_crypt_t* crypt_data = static_cast<fil_space_crypt_t*>(malloc(sz)); @@ -290,14 +203,14 @@ fil_space_create_crypt_data( crypt_data->min_key_version = 0; } else { crypt_data->type = CRYPT_SCHEME_1; - crypt_data->key_id = key_id; + crypt_data->key_id = key_id; crypt_data->min_key_version = encryption_key_get_latest_version(key_id); } mutex_create(fil_crypt_data_mutex_key, &crypt_data->mutex, SYNC_NO_ORDER_CHECK); - crypt_data->iv_length = iv_length; - my_random_bytes(crypt_data->iv, iv_length); + crypt_data->locker = crypt_data_scheme_locker; + my_random_bytes(crypt_data->iv, sizeof(crypt_data->iv)); crypt_data->encryption = FIL_SPACE_ENCRYPTION_DEFAULT; return crypt_data; } @@ -317,12 +230,9 @@ fil_space_crypt_compare( ut_a(crypt_data2->type == CRYPT_SCHEME_UNENCRYPTED || crypt_data2->type == CRYPT_SCHEME_1); - ut_a(crypt_data1->iv_length == CRYPT_SCHEME_1_IV_LEN); - ut_a(crypt_data2->iv_length == CRYPT_SCHEME_1_IV_LEN); - /* no support for changing iv (yet?) */ ut_a(memcmp(crypt_data1->iv, crypt_data2->iv, - crypt_data1->iv_length) == 0); + sizeof(crypt_data1->iv)) == 0); return 0; } @@ -378,9 +288,10 @@ fil_space_read_crypt_data( ut_error; } + fil_space_crypt_t* crypt_data; ulint iv_length = mach_read_from_1(page + offset + MAGIC_SZ + 1); - if (! (iv_length == CRYPT_SCHEME_1_IV_LEN)) { + if (! (iv_length == sizeof(crypt_data->iv))) { ib_logf(IB_LOG_LEVEL_ERROR, "Found non sensible iv length: %lu for space %lu " " offset: %lu type: %lu bytes: " @@ -405,8 +316,7 @@ fil_space_read_crypt_data( page + offset + MAGIC_SZ + 2 + iv_length + 8); const uint sz = sizeof(fil_space_crypt_t) + iv_length; - fil_space_crypt_t* crypt_data = static_cast<fil_space_crypt_t*>( - malloc(sz)); + crypt_data = static_cast<fil_space_crypt_t*>(malloc(sz)); memset(crypt_data, 0, sz); crypt_data->type = type; @@ -416,7 +326,7 @@ fil_space_read_crypt_data( crypt_data->encryption = encryption; mutex_create(fil_crypt_data_mutex_key, &crypt_data->mutex, SYNC_NO_ORDER_CHECK); - crypt_data->iv_length = iv_length; + crypt_data->locker = crypt_data_scheme_locker; memcpy(crypt_data->iv, page + offset + MAGIC_SZ + 2, iv_length); return crypt_data; @@ -453,7 +363,7 @@ fil_space_write_crypt_data_low( ut_a(offset > 0 && offset < UNIV_PAGE_SIZE); ulint space_id = mach_read_from_4( page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); - const uint len = crypt_data->iv_length; + const uint len = sizeof(crypt_data->iv); const uint min_key_version = crypt_data->min_key_version; const uint key_id = crypt_data->key_id; const fil_encryption_t encryption = crypt_data->encryption; @@ -662,9 +572,6 @@ fil_space_encrypt( fil_space_crypt_t* crypt_data = NULL; ulint page_size = (zip_size) ? zip_size : UNIV_PAGE_SIZE; uint key_version; - unsigned char key[MY_AES_MAX_KEY_LENGTH]; - uint key_length = MY_AES_MAX_KEY_LENGTH; - unsigned char iv[MY_AES_BLOCK_SIZE]; ulint orig_page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE); @@ -686,12 +593,14 @@ fil_space_encrypt( return; } - fil_crypt_get_latest_key(key, &key_length, crypt_data, &key_version); + key_version = fil_crypt_get_latest_key_version(crypt_data); - /* create iv/counter */ - mach_write_to_4(iv + 0, space); - mach_write_to_4(iv + 4, offset); - mach_write_to_8(iv + 8, lsn); + if (key_version == ENCRYPTION_KEY_VERSION_INVALID) { + ib_logf(IB_LOG_LEVEL_FATAL, + "Unknown key id %u. Can't continue!\n", + crypt_data->key_id); + ut_error; + } ibool page_compressed = (mach_read_from_2(src_frame+FIL_PAGE_TYPE) == FIL_PAGE_PAGE_COMPRESSED); @@ -719,9 +628,9 @@ fil_space_encrypt( dst+=2; } - int rc = encryption_encrypt(src, srclen, dst, &dstlen, - key, key_length, iv, sizeof(iv), 1, - crypt_data->key_id, key_version); + int rc = encryption_scheme_encrypt(src, srclen, dst, &dstlen, + crypt_data, key_version, + space, offset, lsn); if (! ((rc == MY_AES_OK) && ((ulint) dstlen == srclen))) { ib_logf(IB_LOG_LEVEL_FATAL, @@ -837,17 +746,6 @@ fil_space_decrypt( /* Copy FIL page header, it is not encrypted */ memcpy(dst_frame, src_frame, FIL_PAGE_DATA); - /* Get key */ - byte key[MY_AES_MAX_KEY_LENGTH]; - uint key_length; - unsigned char iv[MY_AES_BLOCK_SIZE]; - fil_crypt_get_key(key, &key_length, crypt_data, key_version); - - /* create iv/counter */ - mach_write_to_4(iv + 0, space); - mach_write_to_4(iv + 4, offset); - mach_write_to_8(iv + 8, lsn); - /* Calculate the offset where decryption starts */ const byte* src = src_frame + FIL_PAGE_DATA; byte* dst = dst_frame + FIL_PAGE_DATA; @@ -865,9 +763,9 @@ fil_space_decrypt( srclen = compressed_len; } - int rc = encryption_decrypt(src, srclen, dst, &dstlen, key, key_length, - iv, sizeof(iv), 1, - crypt_data->key_id, key_version); + int rc = encryption_scheme_decrypt(src, srclen, dst, &dstlen, + crypt_data, key_version, + space, offset, lsn); if (! ((rc == MY_AES_OK) && ((ulint) dstlen == srclen))) { ib_logf(IB_LOG_LEVEL_FATAL, diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 7097c72a721..ddcbc3f591d 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -12242,8 +12242,7 @@ ha_innobase::create( /* If there is old crypt data, copy IV */ if (old_crypt_data) { - memcpy(crypt_data->iv, old_crypt_data->iv, old_crypt_data->iv_length); - crypt_data->iv_length = old_crypt_data->iv_length; + memcpy(crypt_data->iv, old_crypt_data->iv, sizeof(crypt_data->iv)); } mtr_t mtr; diff --git a/storage/xtradb/include/fil0crypt.h b/storage/xtradb/include/fil0crypt.h index 12f0946f28c..32d3c46585f 100644 --- a/storage/xtradb/include/fil0crypt.h +++ b/storage/xtradb/include/fil0crypt.h @@ -80,13 +80,8 @@ struct fil_space_rotate_state_t } scrubbing; }; -struct fil_space_crypt_struct +struct fil_space_crypt_struct : st_encryption_scheme { - ulint type; // CRYPT_SCHEME - uint keyserver_requests; // no of key requests to key server - uint key_count; // No of initalized key-structs - uint key_id; // Key id for this space - key_struct keys[3]; // cached L = AES_ECB(KEY, IV) uint min_key_version; // min key version for this space ulint page0_offset; // byte offset on page 0 for crypt data fil_encryption_t encryption; // Encryption setup @@ -94,9 +89,6 @@ struct fil_space_crypt_struct ib_mutex_t mutex; // mutex protecting following variables bool closing; // is tablespace being closed fil_space_rotate_state_t rotate_state; - - uint iv_length; // length of IV - byte iv[1]; // IV-data }; /* structure containing encryption specification */ |