Commit e02749aa authored by Sergei Golubchik's avatar Sergei Golubchik

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
parent 9bda4bc5
1;F5502320F8429037B8DAEF761B189D12;770A8A65DA156D24EE2A093277530142
2;35B2FF0795FB84BBD666DB8430CA214E;4D92199549E0F2EF009B4160F3582E5528A11A45017F3EF8
3;7E892875A52C59A3B588306B13C31FBD;B374A26A71490437AA024E4FADD5B497FDFF1A8EA6FF12F6FB65AF2720B59CCF
4;021B0663D4DD7B54E2EBC852677E40BD;18420B5CBA31CCDFFE9716E91EB61374D05914F3ADE23E03
5;9BF92CEA026CE732DA80821122A8CE97;966050D7777350B6FD5CCB3E5F648DA45C63BEFB6DEDDFA13443F156B7D35C84
6;BC44D4AFD2D9FCD82A679E4DC6700D06;B5EA210C8C09EF20DB95EC584714A89F
1;770A8A65DA156D24EE2A093277530142
2;4D92199549E0F2EF009B4160F3582E5528A11A45017F3EF8
3;B374A26A71490437AA024E4FADD5B497FDFF1A8EA6FF12F6FB65AF2720B59CCF
4;18420B5CBA31CCDFFE9716E91EB61374D05914F3ADE23E03
5;966050D7777350B6FD5CCB3E5F648DA45C63BEFB6DEDDFA13443F156B7D35C84
6;B5EA210C8C09EF20DB95EC584714A89F
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})
This diff is collapsed.
/* 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_ */
/* 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;
}
......@@ -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;
/* 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;
}
......@@ -14,45 +14,41 @@
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.
@file Parser.h
A structure and class to keep keys for encryption/decryption.
Created 09/13/2014
Created 09/15/2014
***********************************************************************/
#include <my_crypt.h>
#include <ctype.h>
#include <sql_array.h>
#ifndef KEYSINGLETON_H_
#define KEYSINGLETON_H_
#include "EncKeys.h"
struct keyentry {
unsigned int id;
unsigned char key[MY_AES_MAX_KEY_LENGTH];
unsigned int length;
};
class KeySingleton
class Parser
{
private:
static bool instanceInited;
static KeySingleton theInstance;
static EncKeys encKeys;
const char *filename;
const char *filekey;
unsigned int line_number;
// No new instance or object possible
KeySingleton() {}
unsigned int from_hex(char c)
{ return c <= '9' ? c - '0' : tolower(c) - 'a' + 10; }
// No new instance possible through copy constructor
KeySingleton( const KeySingleton&) {}
// No new instance possible through copy
KeySingleton & operator = (const KeySingleton&);
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:
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;
}
Parser(const char* fn, const char *fk) :
filename(fn), filekey(fk), line_number(0) { }
bool parse(Dynamic_array<keyentry> *keys);
};
#endif /* KEYSINGLETON_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment