Browse Source

Cleanup to be able to compile with YASSL.

Temporary push as some tests still fails.
replace/d7d589dc01f6d70d1518b74d46fd3b75e76267f5
Monty 11 years ago
committed by Sergei Golubchik
parent
commit
977a87da5a
  1. 370
      mysys_ssl/my_crypt.cc
  2. 85
      mysys_ssl/my_crypt_key_management.cc
  3. 13
      mysys_ssl/my_crypt_key_management_impl.cc
  4. 3
      plugin/file_key_management_plugin/CMakeLists.txt
  5. 429
      plugin/file_key_management_plugin/EncKeys.cc
  6. 88
      plugin/file_key_management_plugin/EncKeys.h
  7. 65
      plugin/file_key_management_plugin/KeySingleton.cc
  8. 59
      plugin/file_key_management_plugin/KeySingleton.h
  9. 63
      plugin/file_key_management_plugin/file_key_management_plugin.cc

370
mysys_ssl/my_crypt.cc

@ -0,0 +1,370 @@
/*
TODO: add support for YASSL
*/
#include <my_global.h>
#include <my_crypt.h>
/* YASSL doesn't support EVP_CIPHER_CTX */
#ifdef HAVE_EncryptAes128Ctr
#include "mysql.h"
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
static const int CRYPT_ENCRYPT = 1;
static const int CRYPT_DECRYPT = 0;
class Encrypter {
public:
virtual ~Encrypter() {}
virtual Crypt_result Encrypt(const uchar* plaintext,
int plaintext_size,
uchar* ciphertext,
int* ciphertext_used) = 0;
virtual Crypt_result GetTag(uchar* tag, int tag_size) = 0;
};
class Decrypter {
public:
virtual ~Decrypter() {}
virtual Crypt_result SetTag(const uchar* tag, int tag_size) = 0;
virtual Crypt_result Decrypt(const uchar* ciphertext,
int ciphertext_size,
uchar* plaintext,
int* plaintext_used) = 0;
virtual Crypt_result CheckTag() = 0;
};
class Crypto {
public:
virtual ~Crypto();
Crypt_result Crypt(const uchar* input, int input_size,
uchar* output, int* output_used);
protected:
Crypto();
EVP_CIPHER_CTX ctx;
};
/* Various crypto implementations */
class Aes128CtrCrypto : public Crypto {
public:
virtual Crypt_result Init(const uchar* key, const uchar* iv,
int iv_size);
protected:
Aes128CtrCrypto() {}
virtual int mode() = 0;
};
class Aes128CtrEncrypter : public Aes128CtrCrypto, public Encrypter {
public:
Aes128CtrEncrypter() {}
virtual Crypt_result Encrypt(const uchar* plaintext,
int plaintext_size,
uchar* ciphertext,
int* ciphertext_used);
virtual Crypt_result GetTag(uchar* tag, int tag_size) {
DBUG_ASSERT(false);
return AES_INVALID;
}
protected:
virtual int mode() {
return CRYPT_ENCRYPT;
}
private:
Aes128CtrEncrypter(const Aes128CtrEncrypter& o);
Aes128CtrEncrypter& operator=(const Aes128CtrEncrypter& o);
};
class Aes128CtrDecrypter : public Aes128CtrCrypto, public Decrypter {
public:
Aes128CtrDecrypter() {}
virtual Crypt_result Decrypt(const uchar* ciphertext,
int ciphertext_size,
uchar* plaintext,
int* plaintext_used);
virtual Crypt_result SetTag(const uchar* tag, int tag_size) {
DBUG_ASSERT(false);
return AES_INVALID;
}
virtual Crypt_result CheckTag() {
DBUG_ASSERT(false);
return AES_INVALID;
}
protected:
virtual int mode() {
return CRYPT_DECRYPT;
}
private:
Aes128CtrDecrypter(const Aes128CtrDecrypter& o);
Aes128CtrDecrypter& operator=(const Aes128CtrDecrypter& o);
};
class Aes128EcbCrypto : public Crypto {
public:
virtual Crypt_result Init(const unsigned char* key);
protected:
Aes128EcbCrypto() {}
virtual int mode() = 0;
};
class Aes128EcbEncrypter : public Aes128EcbCrypto, public Encrypter {
public:
Aes128EcbEncrypter() {}
virtual Crypt_result Encrypt(const unsigned char* plaintext,
int plaintext_size,
unsigned char* ciphertext,
int* ciphertext_used);
virtual Crypt_result GetTag(unsigned char* tag, int tag_size) {
DBUG_ASSERT(false);
return AES_INVALID;
}
protected:
virtual int mode() {
return CRYPT_ENCRYPT;
}
private:
Aes128EcbEncrypter(const Aes128EcbEncrypter& o);
Aes128EcbEncrypter& operator=(const Aes128EcbEncrypter& o);
};
class Aes128EcbDecrypter : public Aes128EcbCrypto, public Decrypter {
public:
Aes128EcbDecrypter() {}
virtual Crypt_result Decrypt(const unsigned char* ciphertext,
int ciphertext_size,
unsigned char* plaintext,
int* plaintext_used);
virtual Crypt_result SetTag(const unsigned char* tag, int tag_size) {
DBUG_ASSERT(false);
return AES_INVALID;
}
virtual Crypt_result CheckTag() {
DBUG_ASSERT(false);
return AES_INVALID;
}
protected:
virtual int mode() {
return CRYPT_DECRYPT;
}
private:
Aes128EcbDecrypter(const Aes128EcbDecrypter& o);
Aes128EcbDecrypter& operator=(const Aes128EcbDecrypter& o);
};
Crypto::~Crypto() {
EVP_CIPHER_CTX_cleanup(&ctx);
}
Crypto::Crypto() {
EVP_CIPHER_CTX_init(&ctx);
}
/*
WARNING: It is allowed to have output == NULL, for special cases like AAD
support in AES GCM. output_used however must never be NULL.
*/
Crypt_result Crypto::Crypt(const uchar* input, int input_size,
uchar* output, int* output_used) {
DBUG_ASSERT(input != NULL);
DBUG_ASSERT(output_used != NULL);
if (!EVP_CipherUpdate(&ctx, output, output_used, input, input_size)) {
return AES_OPENSSL_ERROR;
}
return AES_OK;
}
Crypt_result Aes128CtrCrypto::Init(const uchar* key,
const uchar* iv,
int iv_size) {
if (iv_size != 16) {
DBUG_ASSERT(false);
return AES_BAD_IV;
}
if (!EVP_CipherInit_ex(&ctx, EVP_aes_128_ctr(), NULL, key, iv, mode())) {
return AES_OPENSSL_ERROR;
}
return AES_OK;
}
Crypt_result Aes128CtrEncrypter::Encrypt(const uchar* plaintext,
int plaintext_size,
uchar* ciphertext,
int* ciphertext_used) {
Crypt_result res = Crypt(plaintext, plaintext_size, ciphertext,
ciphertext_used);
DBUG_ASSERT(*ciphertext_used == plaintext_size);
return res;
}
Crypt_result Aes128CtrDecrypter::Decrypt(const uchar* ciphertext,
int ciphertext_size,
uchar* plaintext,
int* plaintext_used) {
Crypt_result res = Crypt(ciphertext, ciphertext_size, plaintext,
plaintext_used);
DBUG_ASSERT(*plaintext_used == ciphertext_size);
return res;
}
Crypt_result Aes128EcbCrypto::Init(const unsigned char* key) {
if (!EVP_CipherInit_ex(&ctx, EVP_aes_128_ecb(), NULL, key, NULL, mode())) {
return AES_OPENSSL_ERROR;
}
return AES_OK;
}
Crypt_result Aes128EcbEncrypter::Encrypt(const unsigned char* plaintext,
int plaintext_size,
unsigned char* ciphertext,
int* ciphertext_used) {
Crypt_result res = Crypt(plaintext, plaintext_size,
ciphertext, ciphertext_used);
DBUG_ASSERT(*ciphertext_used == plaintext_size);
return res;
}
Crypt_result Aes128EcbDecrypter::Decrypt(const unsigned char* ciphertext,
int ciphertext_size,
unsigned char* plaintext,
int* plaintext_used) {
Crypt_result res = Crypt(ciphertext, ciphertext_size,
plaintext, plaintext_used);
DBUG_ASSERT(*plaintext_used == ciphertext_size);
return res;
}
C_MODE_START
/* Encrypt and decrypt according to Aes128Ctr */
Crypt_result my_aes_encrypt_ctr(const uchar* source, uint32 source_length,
uchar* dest, uint32* dest_length,
const unsigned char* key, uint8 key_length,
const unsigned char* iv, uint8 iv_length,
uint noPadding)
{
Aes128CtrEncrypter encrypter;
Crypt_result res = encrypter.Init(key, iv, iv_length);
if (res != AES_OK)
return res;
return encrypter.Encrypt(source, source_length, dest, (int*)dest_length);
}
Crypt_result my_aes_decrypt_ctr(const uchar* source, uint32 source_length,
uchar* dest, uint32* dest_length,
const unsigned char* key, uint8 key_length,
const unsigned char* iv, uint8 iv_length,
uint noPadding)
{
Aes128CtrDecrypter decrypter;
Crypt_result res = decrypter.Init(key, iv, iv_length);
if (res != AES_OK)
return res;
return decrypter.Decrypt(source, source_length, dest, (int*)dest_length);
}
Crypt_result my_aes_encrypt_ecb(const uchar* source, uint32 source_length,
uchar* dest, uint32* dest_length,
const unsigned char* key, uint8 key_length,
const unsigned char* iv, uint8 iv_length,
uint noPadding)
{
Aes128EcbEncrypter encrypter;
Crypt_result res = encrypter.Init(key);
if (res != AES_OK)
return res;
return encrypter.Encrypt(source, source_length, dest, (int*)dest_length);
}
Crypt_result my_aes_decrypt_ecb(const uchar* source, uint32 source_length,
uchar* dest, uint32* dest_length,
const unsigned char* key, uint8 key_length,
const unsigned char* iv, uint8 iv_length,
uint noPadding)
{
Aes128EcbDecrypter decrypter;
Crypt_result res = decrypter.Init(key);
if (res != AES_OK)
return res;
return decrypter.Decrypt(source, source_length, dest, (int*)dest_length);
}
C_MODE_END
#endif /* HAVE_EncryptAes128Ctr */
#if defined(HAVE_YASSL)
#include <random.hpp>
C_MODE_START
Crypt_result RandomBytes(uchar* buf, int num)
{
TaoCrypt::RandomNumberGenerator rand;
rand.GenerateBlock((TaoCrypt::byte*) buf, num);
return AES_OK;
}
C_MODE_END
#else /* OpenSSL */
C_MODE_START
Crypt_result RandomBytes(uchar* buf, int num)
{
/*
Unfortunately RAND_bytes manual page does not provide any guarantees
in relation to blocking behavior. Here we explicitly use SSLeay random
instead of whatever random engine is currently set in OpenSSL. That way
we are guaranteed to have a non-blocking random.
*/
RAND_METHOD* rand = RAND_SSLeay();
if (rand == NULL || rand->bytes(buf, num) != 1)
return AES_OPENSSL_ERROR;
return AES_OK;
}
C_MODE_END
#endif /* HAVE_YASSL */

85
mysys_ssl/my_crypt_key_management.cc

@ -0,0 +1,85 @@
#include <my_global.h>
#include <my_crypt_key_management.h>
#include <cstring>
#ifdef __linux__
#include <arpa/inet.h>
#endif
#ifndef DBUG_OFF
my_bool opt_danger_danger_use_dbug_keys = 0;
#ifdef HAVE_PSI_INTERFACE
PSI_rwlock_key key_LOCK_dbug_crypto_key_version;
#endif
mysql_rwlock_t LOCK_dbug_crypto_key_version;
unsigned int opt_danger_danger_dbug_crypto_key_version = 0;
#endif
/**
* Default functions
*/
unsigned int GetLatestCryptoKeyVersionImpl();
int GetCryptoKeyImpl(unsigned int version, unsigned char* key_buffer,
unsigned int size);
/**
* Function pointers for
* - GetLatestCryptoKeyVersion
* - GetCryptoKey
*/
static
struct CryptoKeyFuncs_t cryptoKeyFuncs = {
GetLatestCryptoKeyVersionImpl,
GetCryptoKeyImpl
};
extern "C"
unsigned int GetLatestCryptoKeyVersion() {
#ifndef DBUG_OFF
if (opt_danger_danger_use_dbug_keys) {
mysql_rwlock_rdlock(&LOCK_dbug_crypto_key_version);
unsigned int res = opt_danger_danger_dbug_crypto_key_version;
mysql_rwlock_unlock(&LOCK_dbug_crypto_key_version);
return res;
}
#endif
return (* cryptoKeyFuncs.getLatestCryptoKeyVersionFunc)();
}
extern "C"
int GetCryptoKey(unsigned int version, unsigned char* key, unsigned int size) {
#ifndef DBUG_OFF
if (opt_danger_danger_use_dbug_keys) {
memset(key, 0, size);
// Just don't support tiny keys, no point anyway.
if (size < sizeof(version)) {
return 1;
}
version = htonl(version);
memcpy(key, &version, sizeof(version));
return 0;
}
#endif
return (* cryptoKeyFuncs.getCryptoKeyFunc)(version, key, size);
}
extern "C"
void
InstallCryptoKeyFunctions(const struct CryptoKeyFuncs_t* _cryptoKeyFuncs)
{
if (_cryptoKeyFuncs == NULL)
{
/* restore defaults when called with NULL argument */
cryptoKeyFuncs.getLatestCryptoKeyVersionFunc =
GetLatestCryptoKeyVersionImpl;
cryptoKeyFuncs.getCryptoKeyFunc =
GetCryptoKeyImpl;
}
else
{
cryptoKeyFuncs = *_cryptoKeyFuncs;
}
}

13
mysys_ssl/my_crypt_key_management_impl.cc

@ -0,0 +1,13 @@
#include <my_global.h>
// TODO Not yet implemented.
unsigned int GetLatestCryptoKeyVersionImpl()
{
abort();
}
int GetCryptoKeyImpl(unsigned int version, unsigned char* key,
unsigned int key_size)
{
abort();
}

3
plugin/file_key_management_plugin/CMakeLists.txt

@ -0,0 +1,3 @@
SET(FILE_KEY_MANAGEMENT_PLUGIN_SOURCES file_key_management_plugin.cc )
MYSQL_ADD_PLUGIN(FILE_KEY_MANAGEMENT_PLUGIN ${FILE_KEY_MANAGEMENT_PLUGIN_SOURCES} MANDATORY)

429
plugin/file_key_management_plugin/EncKeys.cc

@ -0,0 +1,429 @@
/* Copyright (C) 2014 eperi GmbH. All Rights Reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/******************************************************************//**
@file EncKeys.cc
A class to keep keys for encryption/decryption.
How it works...
The location and usage can be configured via the configuration file.
Example
[mysqld]
...
innodb_data_encryption_providertype = 1
innodb_data_encryption_providername = keys.enc
innodb_data_encryption_providerurl = /home/mdb/
innodb_data_encryption_filekey = secret
...
As provider type currently only value 1 is supported, which means, the keys are read from a file.
The filename is set up via the innodb_data_encryption_providername configuration value.
innodb_data_encryption_providerurl is used to configure the path to this file. This is usually
a folder name.
Examples:
innodb_data_encryption_providerurl = \\\\unc (windows share)
innodb_data_encryption_providerurl = e:/tmp/ (windows path)
innodb_data_encryption_providerurl = /tmp (linux path)
The key file contains AES keys and initialization vectors as hex-encoded Strings.
Supported are keys of size 128, 192 or 256 bits. IV consists of 16 bytes.
The key file should be encrypted and the key to decrypt the file can be given with the
innodb_data_encryption_filekey parameter.
The file key can also be located if FILE: is prepended to the key. Then the following part is interpreted
as absolut to the file containing the file key. This file can optionally be encrypted, currently with a fix key.
Example:
innodb_data_encryption_filekey = FILE:y:/secret256.enc
If the key file can not be read at server startup, for example if the file key is not present,
page_encryption feature is not availabe and access to page_encryption tables is not possible.
Example files can be found inside the unittest/eperi folder.
Open SSL command line utility can be used to create an encrypted key file.
Examples:
openssl enc aes-256-cbc md sha1 k secret in keys.txt out keys.enc
openssl enc aes-256-cbc md sha1 k <initialPwd> in secret out secret.enc
Created 09/15/2014
***********************************************************************/
#ifdef __WIN__
#define PCRE_STATIC 1
#endif
#include "EncKeys.h"
#include <my_global.h>
#include <my_aes.h>
#include <memory.h>
#include <my_sys.h>
#include <pcre.h>
#include <string.h>
#include <my_sys.h>
const char* EncKeys::strMAGIC = "Salted__";
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";
const char* EncKeys::errorNoInitializedKey = "The key could not be initialized.\n";
const char* EncKeys::errorNotImplemented = "Initializing keys through key server is not"
" yet implemented.\nYou can not read encrypted tables or columns\n\n";
const char* EncKeys::errorOpenFile = "Could not open %s for reading. You can not read encrypted tables or columns.\n\n";
const char* EncKeys::errorReadingFile = "Could not read from %s. You can not read encrypted tables or columns\n\n";
const char* EncKeys::errorFileSize = "Could not get the file size from %s. You can not read encrypted tables or columns\n\n";
const char* EncKeys::errorFalseFileKey = "Wrong encryption / decryption key for keyfile '%s'.\n";
/* read this from a secret source in some later version */
const char* EncKeys::initialPwd = "lg28s9ac5ffa537fd8798875c98e190df289da7e047c05";
EncKeys::EncKeys() {
countKeys = keyLineInKeyFile = 0;
for (int ii = 0; ii < MAX_KEYS; ii++) {
keys[ii].id = 0;
keys[ii].iv = keys[ii].key = NULL;
}
oneKey = NULL;
}
EncKeys::~EncKeys() {
for (int ii = MAX_KEYS - 1; ii >= 0 ; ii--) {
delete[] keys[ii].iv; keys[ii].iv = NULL;
delete[] keys[ii].key; keys[ii].key = NULL;
}
}
bool EncKeys::initKeys(const char *name, const char *url, const int initType, const char *filekey) {
if (KEYINITTYPE_FILE == initType)
{
int result = initKeysThroughFile(name, url, filekey);
return ERROR_FALSE_FILE_KEY != result && ERROR_OPEN_FILE != result && ERROR_READING_FILE != result;
}
else if (KEYINITTYPE_SERVER == initType)
{
return NO_ERROR_KEY_FILE_PARSE_OK == initKeysThroughServer(name, url, filekey);
}
return false;
}
int EncKeys::initKeysThroughFile(const char *name, const char *path, const char *filekey) {
if (path==NULL || name==NULL) return ERROR_OPEN_FILE;
size_t len1 = strlen(path);
size_t len2 = strlen(name);
const char *MAGIC = "FILE:";
const short MAGIC_LEN = 5;
int ret = NO_ERROR_KEY_FILE_PARSE_OK;
bool isUncPath= (len1>2) ? ((strncmp("\\\\", path, 2)==0) ? TRUE : FALSE) : FALSE;
bool isSlash = ((isUncPath? '\\':'/') == path[len1 - 1]);
char *secret = (char*) malloc(MAX_SECRET_SIZE +1 * sizeof(char));
char *filename = (char*) malloc((len1 + len2 + (isSlash ? 1 : 2)) * sizeof(char));
if(filekey != NULL)
{
//If secret starts with FILE: interpret the secret as filename.
if(memcmp(MAGIC, filekey, MAGIC_LEN) == 0) {
int fk_len = strlen(filekey);
char *secretfile = (char*)malloc( (1 + fk_len - MAGIC_LEN)* sizeof(char));
memcpy(secretfile, filekey+MAGIC_LEN, fk_len - MAGIC_LEN);
secretfile[fk_len-MAGIC_LEN] = '\0';
parseSecret(secretfile, secret);
free(secretfile);
} else
{
sprintf(secret, "%s", filekey);
}
}
sprintf(filename, "%s%s%s", path, isSlash ? "" : (isUncPath ? "\\":"/"), name);
ret = parseFile((const char *)filename, 254, secret);
free(filename);
free(secret);
return ret;
}
int EncKeys::initKeysThroughServer( const char *name, const char *path, const char *filekey)
{
//TODO
#ifdef UNIV_DEBUG
fprintf(stderr, errorNotImplemented);
#endif //UNIV_DEBUG
return ERROR_KEYINITTYPE_SERVER_NOT_IMPLEMENTED;
}
/*
* secret is limited to MAX_SECRET_SIZE characters
*/
void EncKeys::parseSecret( const char *secretfile, char *secret ) {
int maxSize = (MAX_SECRET_SIZE +16 + magicSize*2) ;
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);
int bytes_to_read = (maxSize >= file_size)? file_size:(maxSize);
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;
int res = my_aes_decrypt_cbc((const char*)buf + 2 * magicSize, bytes_to_read - 2 * magicSize,
secret, &d_size, key, keySize32, iv, ivSize16, 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];
}
#ifdef UNIV_DEBUG
else {
fprintf(stderr, errorNoKeyId, id);
return NULL;
}
#endif //UNIV_DEBUG
}
/**
* Get the keys from the key file <filename> and decrypt it with the key <secret>.
* Store the keys with id smaller then <maxKeyId> in an array of structs keyentry.
* Returns NO_ERROR_PARSE_OK or an appropriate error code.
*/
int EncKeys::parseFile(const char* filename, const ulint maxKeyId, const char *secret) {
int errorCode = 0;
char *buffer = decryptFile(filename, secret, &errorCode);
ulint id = 0;
if (NO_ERROR_PARSE_OK != errorCode) return errorCode;
else errorCode = NO_ERROR_KEY_FILE_PARSE_OK;
char *line = strtok(buffer, newLine);
while ( NULL != line) {
keyLineInKeyFile++;
switch (parseLine(line, maxKeyId)) {
case NO_ERROR_PARSE_OK:
id = oneKey->id;
keys[oneKey->id - 1] = *oneKey;
delete(oneKey);
countKeys++;
fprintf(stderr, "Line: %u --> ", keyLineInKeyFile); printKeyEntry(id);
break;
case ERROR_ID_TOO_BIG:
fprintf(stderr, errorExceedKeySize, KEY_MAX, keyLineInKeyFile);
fprintf(stderr, " --> %s\n", line);
errorCode = ERROR_KEY_FILE_EXCEEDS_MAX_NUMBERS_OF_KEYS;
break;
case ERROR_NOINITIALIZEDKEY:
fprintf(stderr, errorNoInitializedKey);
fprintf(stderr, " --> %s\n", line);
errorCode = ERROR_KEY_FILE_PARSE_NULL;
break;
case ERROR_WRONG_NUMBER_OF_MATCHES:
fprintf(stderr, errorInMatches, keyLineInKeyFile);
fprintf(stderr, " --> %s\n", line);
errorCode = ERROR_KEY_FILE_PARSE_NULL;
break;
case NO_ERROR_KEY_GREATER_THAN_ASKED:
fprintf(stderr, "No asked key in line %lu: %s\n", keyLineInKeyFile, line);
break;
case NO_ERROR_ISCOMMENT:
fprintf(stderr, "Is comment in line %lu: %s\n", keyLineInKeyFile, line);
default:
break;
}
line = strtok(NULL, newLine);
}
free(line); line = NULL;
delete[] buffer; buffer = NULL;
return errorCode;
}
int EncKeys::parseLine(const char *line, const ulint maxKeyId) {
int ret = NO_ERROR_PARSE_OK;
if (isComment(line))
ret = NO_ERROR_ISCOMMENT;
else {
const char *error_p = NULL;
int offset;
pcre *pattern = pcre_compile(
"([0-9]+);([0-9,a-f,A-F]{32});([0-9,a-f,A-F]{64}|[0-9,a-f,A-F]{48}|[0-9,a-f,A-F]{32})",
0, &error_p, &offset, NULL);
if ( NULL != error_p)
fprintf(stderr, "Error: %s\nOffset: %d\n", error_p, offset);
int m_len = (int) strlen(line), ovector[MAX_OFFSETS_IN_PCRE_PATTERNS];
int rc = pcre_exec(pattern, NULL, line, m_len, 0, 0, ovector, MAX_OFFSETS_IN_PCRE_PATTERNS);
pcre_free(pattern);
if (4 == rc) {
char lin[MAX_KEY_LINE_SIZE + 1];
strncpy( lin, line, MAX_KEY_LINE_SIZE);
lin[MAX_KEY_LINE_SIZE] = '\0';
char *substring_start = lin + ovector[2];
int substr_length = ovector[3] - ovector[2];
if (3 < substr_length)
ret = ERROR_ID_TOO_BIG;
else {
char buffer[4];
sprintf(buffer, "%.*s", substr_length, substring_start);
ulint id = atoi(buffer);
if (0 == id) ret = ERROR_NOINITIALIZEDKEY;
else if (KEY_MAX < id) ret = ERROR_ID_TOO_BIG;
else if (maxKeyId < id) ret = NO_ERROR_KEY_GREATER_THAN_ASKED;
else {
oneKey = new keyentry;
oneKey->id = id;
substring_start = lin + ovector[4];
substr_length = ovector[5] - ovector[4];
oneKey->iv = new char[substr_length + 1];
sprintf(oneKey->iv, "%.*s", substr_length, substring_start);
substring_start = lin + ovector[6];
substr_length = ovector[7] - ovector[6];
oneKey->key = new char[substr_length + 1];
sprintf(oneKey->key, "%.*s", substr_length, substring_start);
}
}
}
else
ret = ERROR_WRONG_NUMBER_OF_MATCHES;
}
return ret;
}
/**
* Decrypt the key file 'filename' if it is encrypted with the key 'secret'.
* Store the content of the decrypted file in 'buffer'. The buffer has to be freed
* in the calling function.
*/
char* EncKeys::decryptFile(const char* filename, const char *secret, int *errorCode) {
*errorCode = NO_ERROR_PARSE_OK;
fprintf(stderr, "Reading %s\n\n", filename);
FILE *fp = fopen(filename, "rb");
if (NULL == fp) {
fprintf(stderr, errorOpenFile, filename);
*errorCode = ERROR_OPEN_FILE;
return NULL;
}
if (fseek(fp, 0L, SEEK_END)) {
*errorCode = ERROR_READING_FILE;
return NULL;
}
long file_size = ftell(fp); // get the file size
if (MAX_KEY_FILE_SIZE < file_size) {
fprintf(stderr, errorExceedKeyFileSize, filename, MAX_KEY_FILE_SIZE);
*errorCode = ERROR_KEY_FILE_TOO_BIG;
fclose(fp);
return NULL;
}
else if (-1L == file_size) {
fprintf(stderr, errorFileSize, filename);
*errorCode = ERROR_READING_FILE;
return NULL;
}
rewind(fp);
//Read file into buffer
uchar *buffer = new uchar[file_size + 1];
size_t read_bytes = 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];
char *decrypted = new char[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);
if(0 != res) {
*errorCode = ERROR_FALSE_FILE_KEY;
delete[] buffer; buffer = NULL;
fprintf(stderr, errorFalseFileKey, filename);
}
else {
memcpy(buffer, decrypted, d_size);
buffer[d_size] = '\0';
}
delete[] decrypted; decrypted = NULL;
delete[] key; key = NULL;
delete[] iv; iv = NULL;
}
return (char*) buffer;
}
bool EncKeys::isComment(const char *line) {
const char *error_p;
int offset, m_len = (int) strlen(line), ovector[MAX_OFFSETS_IN_PCRE_PATTERNS];
pcre *pattern = pcre_compile("\\s*#.*", 0, &error_p, &offset, NULL);
int rc = pcre_exec( pattern, NULL, line, m_len, 0, 0, ovector, MAX_OFFSETS_IN_PCRE_PATTERNS);
pcre_free(pattern);
if (0 > rc) return false;
else return true;
}
void EncKeys::printKeyEntry( ulint id)
{
#ifdef UNIV_DEBUG
keyentry *entry = getKeys(id);
if( NULL == entry) {
fprintf(stderr, "No such keyID=%lu\n",id);
}
else {
fprintf(stderr, "Key: id:%3lu \tiv:%lu bytes\tkey:%lu bytes\n", entry->id, strlen(entry->iv)/2, strlen(entry->key)/2);
}
#endif //UNIV_DEBUG
}

88
plugin/file_key_management_plugin/EncKeys.h

@ -0,0 +1,88 @@
/* Copyright (C) 2014 eperi GmbH. All Rights Reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/******************************************************************//**
@file EncKeys.h
A structure and class to keep keys for encryption/decryption.
Created 09/15/2014
***********************************************************************/
#ifndef ENCKEYS_H_
#define ENCKEYS_H_
#include "my_global.h"
#include <sys/types.h>
#include <stdio.h>
struct keyentry {
ulint id;
char *iv;
char *key;
};
class EncKeys
{
private:
static const char *strMAGIC, *newLine;
static const int magicSize;
enum constants { MAX_OFFSETS_IN_PCRE_PATTERNS = 30};
enum keyAttributes { KEY_MIN = 1, KEY_MAX = 255, MAX_KEYS = 255,
MAX_IVLEN = 256, MAX_KEYLEN = 512, ivSize16 = 16, keySize32 = 32 };
enum keyInitType { KEYINITTYPE_FILE = 1, KEYINITTYPE_SERVER = 2 };
enum errorAttributes { MAX_KEY_LINE_SIZE = 3 * MAX_KEYLEN, MAX_KEY_FILE_SIZE = 1048576 };
enum errorCodesLine { NO_ERROR_PARSE_OK = 0, NO_ERROR_ISCOMMENT = 10, NO_ERROR_KEY_GREATER_THAN_ASKED = 20,
ERROR_NOINITIALIZEDKEY = 30, ERROR_ID_TOO_BIG = 40, ERROR_WRONG_NUMBER_OF_MATCHES = 50,
ERROR_EQUAL_DOUBLE_KEY = 60, ERROR_UNEQUAL_DOUBLE_KEY = 70 };
static const char *errorNoKeyId, *errorInMatches, *errorExceedKeyFileSize,
*errorExceedKeySize, *errorEqualDoubleKey, *errorUnequalDoubleKey,
*errorNoInitializedKey, *errorFalseFileKey,
*errorNotImplemented, *errorOpenFile, *errorReadingFile, *errorFileSize;
static const char* initialPwd;
ulint countKeys, keyLineInKeyFile;
keyentry keys[MAX_KEYS], *oneKey;
void printKeyEntry( ulint id);
int initKeysThroughFile( const char *name, const char *path, const char *filekey);
int initKeysThroughServer( const char *name, const char *path, const char *filekey);
bool isComment( const char *line);
char * decryptFile( const char* filename, const char *secret, int *errorCode);
int parseFile( const char* filename, const ulint maxKeyId, const char *secret);
int parseLine( const char *line, const ulint maxKeyId);
public:
static const size_t MAX_SECRET_SIZE = 256;
enum errorCodesFile { NO_ERROR_KEY_FILE_PARSE_OK = 0, ERROR_KEY_FILE_PARSE_NULL = 110,
ERROR_KEY_FILE_TOO_BIG = 120, ERROR_KEY_FILE_EXCEEDS_MAX_NUMBERS_OF_KEYS = 130,
ERROR_OPEN_FILE = 140, ERROR_READING_FILE = 150, ERROR_FALSE_FILE_KEY = 160,
ERROR_KEYINITTYPE_SERVER_NOT_IMPLEMENTED = 170, ERROR_ENCRYPTION_SECRET_NULL = 180 };
EncKeys();
virtual ~EncKeys();
bool initKeys( const char *name, const char *url, const int initType, const char *filekey);
keyentry *getKeys( int id);
/* made public for unit testing */
static void parseSecret( const char *filename, char *secret );
};
#endif /* ENCKEYS_H_ */

65
plugin/file_key_management_plugin/KeySingleton.cc

@ -0,0 +1,65 @@
/* Copyright (C) 2014 eperi GmbH. All Rights Reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/******************************************************************//**
@file KeySingleton.cc
Implementation of single pattern to keep keys for encrypting/decrypting pages.
Created 09/13/2014
***********************************************************************/
#include "KeySingleton.h"
#include <stdlib.h>
bool KeySingleton::instanceInited = false;
KeySingleton KeySingleton::theInstance;
EncKeys KeySingleton::encKeys;
KeySingleton & KeySingleton::getInstance() {
#ifdef UNIV_DEBUG
if( !instanceInited) {
fprintf(stderr, "Encryption / decryption keys were not initialized. "
"You can not read encrypted tables or columns\n");
}
#endif UNIV_DEBUG
return theInstance;
}
KeySingleton & KeySingleton::getInstance(const char *name, const char *url,
const int initType, const char *filekey) {
if(instanceInited) return theInstance;
instanceInited = encKeys.initKeys(name, url, initType, filekey);
if( !instanceInited) {
fprintf(stderr, "Could not initialize any of the encryption / decryption keys. "
"You can not read encrypted tables\n\n");
fflush(stderr);
}
return theInstance;
}
keyentry *KeySingleton::getKeys(int id) {
return encKeys.getKeys(id);
}
ibool KeySingleton::hasKey(int id) {
return encKeys.getKeys(id) != NULL;
}

59
plugin/file_key_management_plugin/KeySingleton.h

@ -0,0 +1,59 @@
/* Copyright (C) 2014 eperi GmbH. All Rights Reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/******************************************************************//**
@file KeySingletonPattern.h
Implementation of single pattern to keep keys for encrypting/decrypting pages.
Created 09/13/2014
***********************************************************************/
#ifndef KEYSINGLETON_H_
#define KEYSINGLETON_H_
#include "EncKeys.h"
class KeySingleton
{
private:
static bool instanceInited;
static KeySingleton theInstance;
static EncKeys encKeys;
// No new instance or object possible
KeySingleton() {}
// No new instance possible through copy constructor
KeySingleton( const KeySingleton&) {}
// No new instance possible through copy
KeySingleton & operator = (const KeySingleton&);
public:
virtual ~KeySingleton() {encKeys.~EncKeys();}
static KeySingleton& getInstance();
// Init the instance for only one time
static KeySingleton& getInstance(const char *name, const char *url,
const int initType, const char *filekey);
keyentry *getKeys(int id);
ibool hasKey(int id);
static bool isAvailable() {
return instanceInited;
}
};
#endif /* KEYSINGLETON_H_ */

63
plugin/file_key_management_plugin/file_key_management_plugin.cc

@ -0,0 +1,63 @@
/* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include <my_global.h>
#include <mysql_version.h>
#include <my_aes.h>
static int file_key_management_plugin_init(void *p)
{
/* init */
printf("TO_BE_REMOVED: Loading file_key_management_plugin_init\n");
/* Setting to MY_AES_METHOD_CBC for page encryption */
my_aes_init_dynamic_encrypt(MY_AES_ALGORITHM_CBC);
return 0;
}
static int file_key_management_plugin_deinit(void *p)
{
/**
* don't uninstall...
*/
return 0;
}
struct st_mysql_daemon file_key_management_plugin= {
MYSQL_DAEMON_INTERFACE_VERSION
};
/*
Plugin library descriptor
*/
maria_declare_plugin(file_key_management_plugin)
{
MYSQL_DAEMON_PLUGIN,
&file_key_management_plugin,
"file_key_management_plugin",
"Denis Endro eperi GmbH",
"File key management plugin",
PLUGIN_LICENSE_GPL,
file_key_management_plugin_init, /* Plugin Init */
file_key_management_plugin_deinit, /* Plugin Deinit */
0x0100 /* 1.0 */,
NULL, /* status variables */
NULL, /* system variables */
"1.0",
MariaDB_PLUGIN_MATURITY_UNKNOWN
}
maria_declare_plugin_end;
Loading…
Cancel
Save