diff options
Diffstat (limited to 'plugin/file_key_management_plugin')
-rw-r--r-- | plugin/file_key_management_plugin/CMakeLists.txt | 4 | ||||
-rw-r--r-- | plugin/file_key_management_plugin/EncKeys.cc | 137 | ||||
-rw-r--r-- | plugin/file_key_management_plugin/EncKeys.h | 17 | ||||
-rw-r--r-- | plugin/file_key_management_plugin/KeySingleton.cc | 7 | ||||
-rw-r--r-- | plugin/file_key_management_plugin/KeySingleton.h | 5 | ||||
-rw-r--r-- | plugin/file_key_management_plugin/file_key_management_plugin.cc | 171 |
6 files changed, 237 insertions, 104 deletions
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 } |