summaryrefslogtreecommitdiff
path: root/plugin
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2015-03-28 13:25:25 +0100
committerSergei Golubchik <serg@mariadb.org>2015-04-08 10:58:50 +0200
commite02749aaf5559384ef130e53aaaf02a33e5bcac3 (patch)
tree8a55d98b53ef46545e54949696c2c6340c4ff5bf /plugin
parent9bda4bc52a1c36ec61589e9006edc3f8ac5fec0b (diff)
downloadmariadb-git-e02749aaf5559384ef130e53aaaf02a33e5bcac3.tar.gz
completely rewrote file_key_management plugin
numerous issues fixed: * buffer overflows * error conditions aren't checked (crash if file doesn't exist) * accessing random unallocated memory * hard-coded password * arbitrary hard-coded key id limit * incomprehensible error messages (for key_id == 0 it reported "The key could not be initialized", for syntax errors the message was "Wrong match of the keyID, see the template", for a key id larger than hard-coded limit the message was "No asked key", and there was an error "Is comment" for a comment). * tons of small mallocs, many are freed few lines down in the code * malloc(N) and new char[N] are used both, even in the same function * redundant memory copies * pcre - "I can solve it with regular expressions" - with incorrect regexes * parser context stored in a singleton * keys are stored as strings and are strlen-ed and hex2bin-ed on every get_key() request * lots of useless code (e.g. sprintf instead of a pointer assignment, checking of the file length to read a part of it in a fixed buffer, multiplying by sizeof(char) in many places, etc) * this list is not exhaustive
Diffstat (limited to 'plugin')
-rw-r--r--plugin/file_key_management/CMakeLists.txt8
-rw-r--r--plugin/file_key_management/EncKeys.cc477
-rw-r--r--plugin/file_key_management/EncKeys.h112
-rw-r--r--plugin/file_key_management/KeySingleton.cc64
-rw-r--r--plugin/file_key_management/KeySingleton.h58
-rw-r--r--plugin/file_key_management/file_key_management_plugin.cc195
-rw-r--r--plugin/file_key_management/parser.cc365
-rw-r--r--plugin/file_key_management/parser.h54
8 files changed, 455 insertions, 878 deletions
diff --git a/plugin/file_key_management/CMakeLists.txt b/plugin/file_key_management/CMakeLists.txt
index 15c0357f47b..c2f13fb9f63 100644
--- a/plugin/file_key_management/CMakeLists.txt
+++ b/plugin/file_key_management/CMakeLists.txt
@@ -1,6 +1,4 @@
-SET(FILE_KEY_MANAGEMENT_PLUGIN_SOURCES file_key_management_plugin.cc EncKeys.cc KeySingleton.cc)
+SET(FILE_KEY_MANAGEMENT_PLUGIN_SOURCES file_key_management_plugin.cc parser.cc)
-IF(NOT SSL_SOURCES)
- MYSQL_ADD_PLUGIN(FILE_KEY_MANAGEMENT ${FILE_KEY_MANAGEMENT_PLUGIN_SOURCES}
- LINK_LIBRARIES pcre)
-ENDIF()
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql)
+MYSQL_ADD_PLUGIN(FILE_KEY_MANAGEMENT ${FILE_KEY_MANAGEMENT_PLUGIN_SOURCES})
diff --git a/plugin/file_key_management/EncKeys.cc b/plugin/file_key_management/EncKeys.cc
deleted file mode 100644
index 77e28878832..00000000000
--- a/plugin/file_key_management/EncKeys.cc
+++ /dev/null
@@ -1,477 +0,0 @@
-/* Copyright (C) 2014 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
- 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]
-...
-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.
-
-Examples:
-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 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 absolute path to the
-file containing the file key. This file can optionally be encrypted,
-currently with a fix key.
-
-Example:
-
-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.
-
-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 <my_global.h>
-#include <sql_class.h> /* For sql_print_error */
-#include "EncKeys.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__";
-const int EncKeys::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";
-#define 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 *filename, const char *filekey)
-{
- if (filename==NULL)
- return false;
-
- const char *MAGIC= "FILE:";
- const short MAGIC_LEN= 5;
-
- 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
- {
- sprintf(secret, "%s", filekey);
- }
- }
-
- int ret= parseFile((const char *)filename, 254, secret);
- free(secret);
- return (ret==NO_ERROR_KEY_FILE_PARSE_OK);
-}
-
-
-/*
- secret is limited to MAX_SECRET_SIZE characters
-*/
-
-void EncKeys::parseSecret(const char *secretfile, char *secret)
-{
- size_t 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);
- rewind(fp);
- size_t bytes_to_read= ((maxSize >= (size_t) file_size) ? (size_t) file_size :
- maxSize);
- bytes_to_read= fread(buf, 1, bytes_to_read, fp);
- if (memcmp(buf, strMAGIC, magicSize))
- {
- bytes_to_read= (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;
- my_aes_decrypt_dynamic_type func= get_aes_decrypt_func(MY_AES_ALGORITHM_CBC);
- int re= (* func)((const uchar*)buf + 2 * magicSize,
- bytes_to_read - 2 * magicSize,
- (uchar*)secret, &d_size, (const uchar*)key, keySize32,
- iv, ivSize16, 0);
- if (re)
- d_size= 0;
- if (d_size>EncKeys::MAX_SECRET_SIZE)
- {
- d_size= EncKeys::MAX_SECRET_SIZE;
- }
- secret[d_size]= '\0';
- delete[] key;
- delete[] iv;
- }
- 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];
- }
-#ifndef DBUG_OFF
- else
- {
- sql_print_error(errorNoKeyId, id);
- }
-#endif
- 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 uint32 maxKeyId,
- const char *secret)
-{
- int errorCode= 0;
- char *buffer= decryptFile(filename, secret, &errorCode);
-
- if (errorCode != NO_ERROR_PARSE_OK)
- return errorCode;
- 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:
- keys[oneKey->id - 1]= *oneKey;
- delete(oneKey);
- countKeys++;
- break;
- case ERROR_ID_TOO_BIG:
- sql_print_error(errorExceedKeySize, KEY_MAX,
- keyLineInKeyFile);
- sql_print_error(" ---> %s\n", line);
- errorCode= ERROR_KEY_FILE_EXCEEDS_MAX_NUMBERS_OF_KEYS;
- break;
- case ERROR_NOINITIALIZEDKEY:
- sql_print_error(errorNoInitializedKey);
- sql_print_error(" ----> %s\n", line);
- errorCode= ERROR_KEY_FILE_PARSE_NULL;
- break;
- case ERROR_WRONG_NUMBER_OF_MATCHES:
- sql_print_error(errorInMatches, keyLineInKeyFile);
- sql_print_error(" -----> %s\n", line);
- errorCode= ERROR_KEY_FILE_PARSE_NULL;
- break;
- case NO_ERROR_KEY_GREATER_THAN_ASKED:
- sql_print_error("No asked key in line %u: %s\n",
- keyLineInKeyFile, line);
- break;
- case NO_ERROR_ISCOMMENT:
- sql_print_error("Is comment in line %u: %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 uint32 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)
- sql_print_error("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);
- 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;
- 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;
- FILE *fp= fopen(filename, "rb");
- if (NULL == fp)
- {
- sql_print_error(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)
- {
- sql_print_error(errorExceedKeyFileSize, filename, MAX_KEY_FILE_SIZE);
- *errorCode= ERROR_KEY_FILE_TOO_BIG;
- fclose(fp);
- return NULL;
- }
- else if (-1L == file_size)
- {
- sql_print_error(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;
- 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;
- sql_print_error(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);
- return (rc >= 0);
-}
-
-
-void EncKeys::printKeyEntry(uint32 id)
-{
-#ifndef DBUG_OFF
- keyentry *entry= getKeys(id);
- if (NULL == entry)
- {
- sql_print_error("No such keyID: %u\n",id);
- }
- else
- {
- sql_print_error("Key: id: %3u\tiv:%lu bytes\tkey:%lu bytes\n",
- entry->id, strlen(entry->iv)/2, strlen(entry->key)/2);
- }
-#endif /* DBUG_OFF */
-}
diff --git a/plugin/file_key_management/EncKeys.h b/plugin/file_key_management/EncKeys.h
deleted file mode 100644
index 8d57237f375..00000000000
--- a/plugin/file_key_management/EncKeys.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* Copyright (C) 2014 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
- 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 <my_global.h>
-#include <sys/types.h>
-#include <stdio.h>
-
-/**
- Calculate key and iv from a given salt and secret as it is handled in openssl
- encrypted files via console
-
- SYNOPSIS
- my_bytes_to_key()
-
- @param salt [in] the given salt as extracted from the encrypted file
- @param secret [in] the given secret as String, provided by the user
- @param key [out] 32 Bytes of key are written to this pointer
- @param iv [out] 16 Bytes of iv are written to this pointer
- */
-
-void my_bytes_to_key(const uchar *salt,
- const char *secret, uchar *key,
- uchar *iv);
-
-/**
- Decode Hexencoded String to uint8[].
-
- SYNOPSIS
- my_aes_hex2uint()
- @param iv [in] Pointer to hexadecimal encoded IV String
- @param dest [out] Pointer to output uint8 array. Memory needs to be
- allocated by caller
- @param iv_length [in] Size of destination array.
- */
-
-void my_aes_hex2uint(const char *in, uchar *out, int dest_length);
-
-struct keyentry {
- uint32 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;
- uint32 countKeys, keyLineInKeyFile;
- keyentry keys[MAX_KEYS], *oneKey;
-
- 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 uint32 maxKeyId, const char *secret);
- int parseLine( const char *line, const uint32 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 *filename, 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/plugin/file_key_management/KeySingleton.cc b/plugin/file_key_management/KeySingleton.cc
deleted file mode 100644
index 936a7cf71a9..00000000000
--- a/plugin/file_key_management/KeySingleton.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Copyright (C) 2014 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
- 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 <my_global.h>
-#include <sql_class.h>
-#include "KeySingleton.h"
-
-bool KeySingleton::instanceInited = false;
-KeySingleton KeySingleton::theInstance;
-EncKeys KeySingleton::encKeys;
-
-KeySingleton & KeySingleton::getInstance()
-{
-#ifndef DBUG_OFF
- if( !instanceInited)
- {
- sql_print_error("Encryption / decryption keys were not initialized. "
- "You can not read encrypted tables or columns\n");
- }
-#endif /* DBUG_OFF */
- return theInstance;
-}
-
-KeySingleton & KeySingleton::getInstance(const char *filename,
- const char *filekey)
-{
- if (!instanceInited)
- {
- if (!(instanceInited = encKeys.initKeys(filename, filekey)))
- sql_print_error("Could not initialize any of the encryption / "
- "decryption keys. You can not read encrypted tables");
- }
- return theInstance;
-}
-
-keyentry *KeySingleton::getKeys(int id)
-{
- return encKeys.getKeys(id);
-}
-
-bool KeySingleton::hasKey(int id)
-{
- return encKeys.getKeys(id) != NULL;
-}
diff --git a/plugin/file_key_management/KeySingleton.h b/plugin/file_key_management/KeySingleton.h
deleted file mode 100644
index 37246c1b802..00000000000
--- a/plugin/file_key_management/KeySingleton.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright (C) 2014 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
- 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 *filename, const char *filekey);
- keyentry *getKeys(int id);
- bool hasKey(int id);
- static bool isAvailable() {
- return instanceInited;
- }
-};
-
-#endif /* KEYSINGLETON_H_ */
diff --git a/plugin/file_key_management/file_key_management_plugin.cc b/plugin/file_key_management/file_key_management_plugin.cc
index 806d50938dd..125f5b6e91d 100644
--- a/plugin/file_key_management/file_key_management_plugin.cc
+++ b/plugin/file_key_management/file_key_management_plugin.cc
@@ -14,27 +14,23 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
-#include <my_global.h>
+#include "parser.h"
#include <mysql_version.h>
#include <mysql/plugin_encryption_key_management.h>
-#include <my_aes.h>
-#include "sql_class.h"
-#include "KeySingleton.h"
-#include "EncKeys.h"
+#include <string.h>
-/* Encryption for tables and columns */
-static char* filename = NULL;
-static char* filekey = NULL;
+static char* filename;
+static char* filekey;
static MYSQL_SYSVAR_STR(filename, filename,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Path and name of the key file.",
- NULL, NULL, NULL);
+ NULL, NULL, "");
static MYSQL_SYSVAR_STR(filekey, filekey,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Key to encrypt / decrypt the keyfile.",
- NULL, NULL, NULL);
+ NULL, NULL, "");
static struct st_mysql_sys_var* settings[] = {
MYSQL_SYSVAR(filename),
@@ -42,103 +38,24 @@ static struct st_mysql_sys_var* settings[] = {
NULL
};
-/**
- Decode Hexencoded String to uint8[].
-
- SYNOPSIS
- my_aes_hex2uint()
- @param iv [in] Pointer to hexadecimal encoded IV String
- @param dest [out] Pointer to output uint8 array. Memory allocated by caller
- @param iv_length [in] Size of destination array.
- */
+Dynamic_array<keyentry> keys(static_cast<uint>(0));
-void my_aes_hex2uint(const char* in, unsigned char *out, int dest_length)
+static keyentry *get_key(unsigned int key_id)
{
- const char *pos= in;
- int count;
- for (count = 0; count < dest_length; count++)
+ keyentry *a= keys.front(), *b= keys.back() + 1, *c;
+ while (b - a > 1)
{
- uchar res;
- sscanf(pos, "%2hhx", &res);
- out[count] = res;
- pos += 2 * sizeof(char);
+ c= a + (b - a)/2;
+ if (c->id == key_id)
+ return c;
+ else if (c->id < key_id)
+ a= c;
+ else
+ b= c;
}
+ return a->id == key_id ? a : 0;
}
-
-/**
- Calculate key and iv from a given salt and secret as it is handled
- in openssl encrypted files via console
-
- SYNOPSIS
- my_bytes_to_key()
- @param salt [in] the given salt as extracted from the encrypted file
- @param secret [in] the given secret as String, provided by the user
- @param key [out] 32 Bytes of key are written to this pointer
- @param iv [out] 16 Bytes of iv are written to this pointer
-*/
-
-void my_bytes_to_key(const unsigned char *salt, const char *secret, unsigned char *key,
- unsigned char *iv)
-{
-#ifdef HAVE_YASSL
- /* the yassl function has no support for SHA1. Reason unknown. */
- int keyLen = 32;
- int ivLen = 16;
- int EVP_SALT_SZ = 8;
- const int SHA_LEN = 20;
- yaSSL::SHA myMD;
- uint digestSz = myMD.get_digestSize();
- unsigned char digest[SHA_LEN]; // max size
- int sz = strlen(secret);
- int count = 1;
- int keyLeft = keyLen;
- int ivLeft = ivLen;
- int keyOutput = 0;
-
- while (keyOutput < (keyLen + ivLen))
- {
- int digestLeft = digestSz;
- if (keyOutput) // first time D_0 is empty
- myMD.update(digest, digestSz);
- myMD.update((yaSSL::byte* )secret, sz);
- if (salt)
- myMD.update(salt, EVP_SALT_SZ);
- myMD.get_digest(digest);
- for (int j = 1; j < count; j++)
- {
- myMD.update(digest, digestSz);
- myMD.get_digest(digest);
- }
-
- if (keyLeft)
- {
- int store = MY_MIN(keyLeft, static_cast<int>(digestSz));
- memcpy(&key[keyLen - keyLeft], digest, store);
-
- keyOutput += store;
- keyLeft -= store;
- digestLeft -= store;
- }
-
- if (ivLeft && digestLeft)
- {
- int store = MY_MIN(ivLeft, digestLeft);
- memcpy(&iv[ivLen - ivLeft], &digest[digestSz - digestLeft], store);
-
- keyOutput += store;
- ivLeft -= store;
- }
- }
-#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);
-#endif
-}
-
-
-
/**
This method is using with the id 0 if exists.
This method is used by innobase/xtradb for the key
@@ -147,91 +64,45 @@ void my_bytes_to_key(const unsigned char *salt, const char *secret, unsigned cha
static unsigned int get_highest_key_used_in_key_file()
{
- if (KeySingleton::getInstance().hasKey(0))
- {
- return 0;
- }
- else
- return CRYPT_KEY_UNKNOWN;
+ return 0;
}
-static unsigned int has_key_from_key_file(unsigned int keyID)
+static unsigned int has_key_from_key_file(unsigned int key_id)
{
- keyentry* entry = KeySingleton::getInstance().getKeys(keyID);
+ keyentry* entry = get_key(key_id);
return entry != NULL;
}
-static unsigned int get_key_size_from_key_file(unsigned int keyID)
+static unsigned int get_key_size_from_key_file(unsigned int key_id)
{
- keyentry* entry = KeySingleton::getInstance().getKeys(keyID);
+ keyentry* entry = get_key(key_id);
- if (entry != NULL)
- {
- char* keyString = entry->key;
- size_t key_len = strlen(keyString)/2;
-
- return key_len;
- }
- else
- {
- return CRYPT_KEY_UNKNOWN;
- }
+ return entry ? entry->length : CRYPT_KEY_UNKNOWN;
}
-static int get_key_from_key_file(unsigned int keyID, unsigned char* dstbuf,
+static int get_key_from_key_file(unsigned int key_id, unsigned char* dstbuf,
unsigned buflen)
{
- keyentry* entry = KeySingleton::getInstance().getKeys((int)keyID);
+ keyentry* entry = get_key(key_id);
if (entry != NULL)
{
- char* keyString = entry->key;
- size_t key_len = strlen(keyString)/2;
-
- if (buflen < key_len)
- {
+ if (buflen < entry->length)
return CRYPT_BUFFER_TO_SMALL;
- }
- my_aes_hex2uint(keyString, (unsigned char*)dstbuf, key_len);
+ memcpy(dstbuf, entry->key, entry->length);
return CRYPT_KEY_OK;
}
else
- {
return CRYPT_KEY_UNKNOWN;
- }
}
static int file_key_management_plugin_init(void *p)
{
- /* init */
-
- if (current_aes_dynamic_method == MY_AES_ALGORITHM_NONE)
- {
- sql_print_error("No encryption method choosen with --encryption-algorithm. "
- "file_key_management disabled");
- return 1;
- }
-
- if (filename == NULL || strcmp("", filename) == 0)
- {
- sql_print_error("Parameter file_key_management_filename is required");
-
- return 1;
- }
-
- KeySingleton::getInstance(filename, filekey);
-
- return 0;
-}
-
-static int file_key_management_plugin_deinit(void *p)
-{
- KeySingleton::getInstance().~KeySingleton();
-
- return 0;
+ Parser parser(filename, filekey);
+ return parser.parse(&keys);
}
struct st_mariadb_encryption_key_management file_key_management_plugin= {
@@ -253,12 +124,12 @@ maria_declare_plugin(file_key_management)
"Denis Endro eperi GmbH",
"File-based key management plugin",
PLUGIN_LICENSE_GPL,
- file_key_management_plugin_init, /* Plugin Init */
- file_key_management_plugin_deinit, /* Plugin Deinit */
+ file_key_management_plugin_init,
+ NULL,
0x0100 /* 1.0 */,
NULL, /* status variables */
settings,
"1.0",
- MariaDB_PLUGIN_MATURITY_UNKNOWN
+ MariaDB_PLUGIN_MATURITY_ALPHA
}
maria_declare_plugin_end;
diff --git a/plugin/file_key_management/parser.cc b/plugin/file_key_management/parser.cc
new file mode 100644
index 00000000000..1a2d48c2471
--- /dev/null
+++ b/plugin/file_key_management/parser.cc
@@ -0,0 +1,365 @@
+/* Copyright (C) 2014 eperi GmbH.
+ Copyright (C) 2015 MariaDB Corporation
+
+ 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 Parser.cc
+ A class to parse the key file
+
+How it works...
+The location and usage can be configured via the configuration file.
+Example
+
+[mysqld]
+...
+file_key_management_filename = /home/mdb/keys.enc
+file_key_management_filekey = secret
+...
+
+The keys are read from a file.
+The filename is set up via the file_key_management_filename
+configuration value.
+file_key_management_filename is used to configure the absolute
+path to this file.
+
+Examples:
+file_key_management_filename = \\\\unc\\keys.enc (windows share)
+file_key_management_filename = e:/tmp/keys.enc (windows path)
+file_key_management_filename = /tmp/keys.enc (linux path)
+
+The key file contains AES keys as hex-encoded strings.
+Supported are keys of size 128, 192 or 256 bits.
+Example:
+1;F5502320F8429037B8DAEF761B189D12
+2;770A8A65DA156D24EE2A093277530142770A8A65DA156D24EE2A093277530142
+
+1 is the key identifier which can be used for table creation,
+it is followed by a AES key
+
+The key file could be encrypted and the key to decrypt the file can
+be given with the optional file_key_management_filekey
+parameter.
+
+The file key can also be located if FILE: is prepended to the
+key. Then the following part is interpreted as absolute path to the
+file containing the file key (which must be a text - not binary - string).
+
+Example:
+
+file_key_management_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, the plugin will not start
+access to encrypted tables will not be possible.
+
+Open SSL command line utility can be used to create an encrypted key file.
+Example:
+openssl enc -aes-256-cbc -md sha1 -k "secret" -in keys.txt -out keys.enc
+***********************************************************************/
+
+#include "parser.h"
+#include <m_string.h>
+#include <mysys_err.h>
+
+#define FILE_PREFIX "FILE:"
+#define MAX_KEY_FILE_SIZE 1024*1024
+#define MAX_SECRET_SIZE 256
+
+/*
+ The values below are what one gets after
+ openssl enc -aes-256-cbc -md sha1 -k "secret" -in keys.txt -out keys.enc
+*/
+#define OpenSSL_prefix "Salted__"
+#define OpenSSL_prefix_len (sizeof(OpenSSL_prefix) - 1)
+#define OpenSSL_salt_len 8
+#define OpenSSL_key_len 32
+#define OpenSSL_iv_len 16
+
+/**
+ Calculate key and iv from a given salt and secret as in the
+ openssl command-line tool
+
+ @param salt [in] the given salt as extracted from the encrypted file
+ @param secret [in] the given secret as String, provided by the user
+ @param key [out] 32 Bytes of key are written to this pointer
+ @param iv [out] 16 Bytes of iv are written to this pointer
+
+ Note, that in openssl this whole function can be reduced to
+
+ #include <openssl/evp.h>
+ EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt,
+ secret, strlen(secret), 1, key, iv);
+
+ but alas! we want to support yassl too
+*/
+
+void Parser::bytes_to_key(const unsigned char *salt, const char *input,
+ unsigned char *key, unsigned char *iv)
+{
+ unsigned char digest[MY_SHA1_HASH_SIZE];
+ int key_left = OpenSSL_key_len;
+ int iv_left = OpenSSL_iv_len;
+ const size_t ilen= strlen(input);
+ const size_t slen= OpenSSL_salt_len; // either this or explicit (size_t) casts below
+
+ my_sha1_multi(digest, input, ilen, salt, slen, NullS);
+
+ while (iv_left)
+ {
+ int left= MY_SHA1_HASH_SIZE;
+ if (key_left)
+ {
+ int store = MY_MIN(key_left, MY_SHA1_HASH_SIZE);
+ memcpy(&key[OpenSSL_key_len - key_left], digest, store);
+
+ key_left -= store;
+ left -= store;
+ }
+
+ if (iv_left && left)
+ {
+ int store= MY_MIN(iv_left, left);
+ memcpy(&iv[OpenSSL_iv_len - iv_left], &digest[MY_SHA1_HASH_SIZE - left], store);
+
+ iv_left -= store;
+ }
+
+ if (iv_left)
+ my_sha1_multi(digest, digest, MY_SHA1_HASH_SIZE,
+ input, ilen, salt, slen, NullS);
+ }
+}
+
+
+bool Parser::parse(Dynamic_array<keyentry> *keys)
+{
+ const char *secret= filekey;
+ char buf[MAX_SECRET_SIZE + 1];
+
+ //If secret starts with FILE: interpret the secret as a filename.
+ if (is_prefix(filekey, FILE_PREFIX))
+ {
+ if (read_filekey(filekey + sizeof(FILE_PREFIX) - 1, buf))
+ return 1;
+ secret= buf;
+ }
+
+ return parse_file(keys, secret);
+}
+
+
+/*
+ secret is limited to MAX_SECRET_SIZE characters
+*/
+
+bool Parser::read_filekey(const char *filekey, char *secret)
+{
+ int f= my_open(filekey, O_RDONLY, MYF(MY_WME));
+ if (f == -1)
+ return 1;
+ int len= my_read(f, (uchar*)secret, MAX_SECRET_SIZE, MYF(MY_WME));
+ my_close(f, MYF(MY_WME));
+ if (len <= 0)
+ return 1;
+ secret[len]= '\0';
+ return 0;
+}
+
+static int sort_keys(const keyentry *k1, const keyentry *k2)
+{
+ return k1->id < k2->id ? -1 : k1->id > k2->id;
+}
+
+/**
+ 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.
+
+ @return 0 when ok, 1 for an error
+ */
+
+bool Parser::parse_file(Dynamic_array<keyentry> *keys, const char *secret)
+{
+ char *buffer= read_and_decrypt_file(secret);
+
+ if (!buffer)
+ return 1;
+
+ keyentry key;
+ char *line=buffer;
+
+ while (*line)
+ {
+ line_number++;
+ switch (parse_line(&line, &key)) {
+ case 1: // comment
+ break;
+ case -1: // error
+ my_free(buffer);
+ return 1;
+ case 0:
+ if (keys->push(key))
+ return 1;
+ break;
+ }
+ }
+
+ keys->sort(sort_keys);
+
+ my_free(buffer);
+ return 0;
+}
+
+void Parser::report_error(const char *reason, uint position)
+{
+ my_printf_error(EE_READ, "%s at %s line %u, column %u",
+ MYF(ME_NOREFRESH), reason, filename, line_number, position + 1);
+}
+
+/*
+ return 0 - new key
+ 1 - comment
+ -1 - error
+*/
+int Parser::parse_line(char **line_ptr, keyentry *key)
+{
+ int res= 1;
+ char *p= *line_ptr;
+ while (isspace(*p) && *p != '\n') p++;
+ if (*p != '#' && *p != '\n')
+ {
+ int error;
+ p+= 100; // the number will surely end here (on a non-digit or with an overflow)
+ longlong id= my_strtoll10(p - 100, &p, &error);
+ if (error)
+ {
+ report_error("Syntax error", p - *line_ptr);
+ return -1;
+ }
+
+ if (id < 1 || id > UINT_MAX32)
+ {
+ report_error("Invalid key id", p - *line_ptr);
+ return -1;
+ }
+
+ if (*p != ';')
+ {
+ report_error("Syntax error", p - *line_ptr);
+ return -1;
+ }
+
+ p++;
+ key->id= id;
+ key->length=0;
+ while (isxdigit(p[0]) && isxdigit(p[1]) && key->length < sizeof(key->key))
+ {
+ key->key[key->length++] = from_hex(p[0]) * 16 + from_hex(p[1]);
+ p+=2;
+ }
+ if (isxdigit(*p) ||
+ (key->length != 16 && key->length != 24 && key->length != 32))
+ {
+ report_error("Invalid key", p - *line_ptr);
+ return -1;
+ }
+
+ res= 0;
+ }
+ while (*p && *p != '\n') p++;
+ *line_ptr= *p == '\n' ? p + 1 : p;
+ return res;
+}
+
+/**
+ 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* Parser::read_and_decrypt_file(const char *secret)
+{
+ int f= my_open(filename, O_RDONLY, MYF(MY_WME));
+ if (f < 0)
+ goto err0;
+
+ my_off_t file_size;
+ file_size= my_seek(f, 0, SEEK_END, MYF(MY_WME));
+
+ if (file_size == MY_FILEPOS_ERROR)
+ goto err1;
+
+ if (file_size > MAX_KEY_FILE_SIZE)
+ {
+ my_error(EE_READ, MYF(0), filename, EFBIG);
+ goto err1;
+ }
+
+ //Read file into buffer
+ uchar *buffer;
+ buffer= (uchar*)my_malloc(file_size + 1, MYF(MY_WME));
+ if (!buffer)
+ goto err1;
+
+ if (my_pread(f, buffer, file_size, 0, MYF(MY_WME)) != file_size)
+ goto err2;
+
+// Check for file encryption
+ uchar *decrypted;
+ if (is_prefix((char*)buffer, OpenSSL_prefix))
+ {
+ uchar key[OpenSSL_key_len];
+ uchar iv[OpenSSL_iv_len];
+
+ decrypted= (uchar*)my_malloc(file_size, MYF(MY_WME));
+ if (!decrypted)
+ goto err2;
+
+ bytes_to_key(buffer + OpenSSL_prefix_len, secret, key, iv);
+ uint32 d_size;
+ if (my_aes_decrypt_cbc(buffer + OpenSSL_prefix_len + OpenSSL_salt_len,
+ file_size - OpenSSL_prefix_len - OpenSSL_salt_len,
+ decrypted, &d_size, key, OpenSSL_key_len,
+ iv, OpenSSL_iv_len, 0))
+
+ {
+ my_printf_error(EE_READ, "Cannot decrypt %s. Wrong key?", MYF(ME_NOREFRESH), filename);
+ goto err3;
+ }
+
+ my_free(buffer);
+ buffer= decrypted;
+ file_size= d_size;
+ }
+ else if (*secret)
+ {
+ my_printf_error(EE_READ, "Cannot decrypt %s. Not encrypted", MYF(ME_NOREFRESH), filename);
+ goto err2;
+ }
+
+ buffer[file_size]= '\0';
+ my_close(f, MYF(MY_WME));
+ return (char*) buffer;
+
+err3:
+ my_free(decrypted);
+err2:
+ my_free(buffer);
+err1:
+ my_close(f, MYF(MY_WME));
+err0:
+ return NULL;
+}
+
diff --git a/plugin/file_key_management/parser.h b/plugin/file_key_management/parser.h
new file mode 100644
index 00000000000..c8349db70a0
--- /dev/null
+++ b/plugin/file_key_management/parser.h
@@ -0,0 +1,54 @@
+/* Copyright (C) 2014 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
+ 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 Parser.h
+A structure and class to keep keys for encryption/decryption.
+
+Created 09/15/2014
+***********************************************************************/
+
+#include <my_crypt.h>
+#include <ctype.h>
+#include <sql_array.h>
+
+struct keyentry {
+ unsigned int id;
+ unsigned char key[MY_AES_MAX_KEY_LENGTH];
+ unsigned int length;
+};
+
+class Parser
+{
+ const char *filename;
+ const char *filekey;
+ unsigned int line_number;
+
+ unsigned int from_hex(char c)
+ { return c <= '9' ? c - '0' : tolower(c) - 'a' + 10; }
+
+ void bytes_to_key(const unsigned char *salt, const char *secret,
+ unsigned char *key, unsigned char *iv);
+ bool read_filekey(const char *filekey, char *secret);
+ bool parse_file(Dynamic_array<keyentry> *keys, const char *secret);
+ void report_error(const char *reason, unsigned int position);
+ int parse_line(char **line_ptr, keyentry *key);
+ char* read_and_decrypt_file(const char *secret);
+
+public:
+ Parser(const char* fn, const char *fk) :
+ filename(fn), filekey(fk), line_number(0) { }
+ bool parse(Dynamic_array<keyentry> *keys);
+};