summaryrefslogtreecommitdiff
path: root/mysys_ssl
diff options
context:
space:
mode:
Diffstat (limited to 'mysys_ssl')
-rw-r--r--mysys_ssl/CMakeLists.txt3
-rw-r--r--mysys_ssl/my_aes.cc289
-rw-r--r--mysys_ssl/my_crypt.cc296
-rw-r--r--mysys_ssl/my_md5.cc132
-rw-r--r--mysys_ssl/my_sha1.cc119
-rw-r--r--mysys_ssl/yassl.cc194
6 files changed, 656 insertions, 377 deletions
diff --git a/mysys_ssl/CMakeLists.txt b/mysys_ssl/CMakeLists.txt
index 45867095e4a..8a8f81d70ae 100644
--- a/mysys_ssl/CMakeLists.txt
+++ b/mysys_ssl/CMakeLists.txt
@@ -26,7 +26,6 @@ ENDIF()
# must be compiled with "-fvisibility=hidden"
IF(WITH_SSL STREQUAL "bundled" AND HAVE_VISIBILITY_HIDDEN)
SET_SOURCE_FILES_PROPERTIES(
- my_aes.cc
my_md5.cc
my_sha1.cc
my_sha2.cc
@@ -34,11 +33,11 @@ IF(WITH_SSL STREQUAL "bundled" AND HAVE_VISIBILITY_HIDDEN)
ENDIF()
SET(MYSYS_SSL_SOURCES
- my_aes.cc
my_sha1.cc
my_sha2.cc
my_md5.cc
my_rnd.cc
+ my_crypt.cc
)
ADD_CONVENIENCE_LIBRARY(mysys_ssl ${MYSYS_SSL_SOURCES})
diff --git a/mysys_ssl/my_aes.cc b/mysys_ssl/my_aes.cc
deleted file mode 100644
index 2bc54d68848..00000000000
--- a/mysys_ssl/my_aes.cc
+++ /dev/null
@@ -1,289 +0,0 @@
-/* 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 <m_string.h>
-#include <my_aes.h>
-
-#if defined(HAVE_YASSL)
-#include "aes.hpp"
-#include "openssl/ssl.h"
-#elif defined(HAVE_OPENSSL)
-#include <openssl/aes.h>
-#include <openssl/evp.h>
-#include <openssl/err.h>
-
-#ifdef HAVE_ERR_remove_thread_state
-#define ERR_remove_state(X) ERR_remove_thread_state(NULL)
-#endif
-
-// Wrap C struct, to ensure resources are released.
-struct MyCipherCtx
-{
- MyCipherCtx() { memset(&ctx, 0, sizeof(ctx)); }
- ~MyCipherCtx() { EVP_CIPHER_CTX_cleanup(&ctx); }
-
- EVP_CIPHER_CTX ctx;
-};
-#endif
-
-enum encrypt_dir { MY_AES_ENCRYPT, MY_AES_DECRYPT };
-
-#define MY_AES_BLOCK_SIZE 16 /* Block size in bytes */
-
-/* If bad data discovered during decoding */
-#define AES_BAD_DATA -1
-
-/**
- This is internal function just keeps joint code of Key generation
-
- SYNOPSIS
- my_aes_create_key()
- @param key [in] Key to use for real key creation
- @param key_length [in] Length of the key
- @param rkey [out] Real key (used by OpenSSL/YaSSL)
-
- @return
- 0 Ok
- -1 Error; Note: The current impementation never returns this
-*/
-
-static int my_aes_create_key(const char *key, int key_length, uint8 *rkey)
-{
- uint8 *rkey_end= rkey + AES_KEY_LENGTH / 8; /* Real key boundary */
- uint8 *ptr; /* Start of the real key*/
- const char *sptr; /* Start of the working key */
- const char *key_end= key + key_length; /* Working key boundary*/
-
- memset(rkey, 0, AES_KEY_LENGTH / 8); /* Set initial key */
-
- for (ptr= rkey, sptr= key; sptr < key_end; ptr ++, sptr ++)
- {
- if (ptr == rkey_end)
- /* Just loop over tmp_key until we used all key */
- ptr= rkey;
- *ptr ^= (uint8) *sptr;
- }
-#ifdef AES_USE_KEY_BITS
- /*
- This block is intended to allow more weak encryption if application
- build with libmysqld needs to correspond to export regulations
- It should be never used in normal distribution as does not give
- any speed improvement.
- To get worse security define AES_USE_KEY_BITS to number of bits
- you want key to be. It should be divisible by 8
-
- WARNING: Changing this value results in changing of enryption for
- all key lengths so altering this value will result in impossibility
- to decrypt data encrypted with previous value
- */
-#define AES_USE_KEY_BYTES (AES_USE_KEY_BITS/8)
- /*
- To get weaker key we use first AES_USE_KEY_BYTES bytes of created key
- and cyclically copy them until we created all required key length
- */
- for (ptr= rkey+AES_USE_KEY_BYTES, sptr=rkey ; ptr < rkey_end;
- ptr ++, sptr ++)
- {
- if (sptr == rkey + AES_USE_KEY_BYTES)
- sptr= rkey;
- *ptr= *sptr;
- }
-#endif
- return 0;
-}
-
-
-/**
- Crypt buffer with AES encryption algorithm.
-
- SYNOPSIS
- my_aes_encrypt()
- @param source [in] Pointer to data for encryption
- @param source_length [in] Size of encryption data
- @param dest [out] Buffer to place encrypted data (must be large enough)
- @param key [in] Key to be used for encryption
- @param key_length [in] Length of the key. Will handle keys of any length
-
- @return
- >= 0 Size of encrypted data
- < 0 Error
-*/
-
-int my_aes_encrypt(const char* source, int source_length, char* dest,
- const char* key, int key_length)
-{
-#if defined(HAVE_YASSL)
- TaoCrypt::AES_ECB_Encryption enc;
- /* 128 bit block used for padding */
- uint8 block[MY_AES_BLOCK_SIZE];
- int num_blocks; /* number of complete blocks */
- int i;
-#elif defined(HAVE_OPENSSL)
- MyCipherCtx ctx;
- int u_len, f_len;
-#endif
-
- /* The real key to be used for encryption */
- uint8 rkey[AES_KEY_LENGTH / 8];
- int rc; /* result codes */
-
- if ((rc= my_aes_create_key(key, key_length, rkey)))
- return rc;
-
-#if defined(HAVE_YASSL)
- enc.SetKey((const TaoCrypt::byte *) rkey, MY_AES_BLOCK_SIZE);
-
- num_blocks = source_length / MY_AES_BLOCK_SIZE;
-
- for (i = num_blocks; i > 0; i--) /* Encode complete blocks */
- {
- enc.Process((TaoCrypt::byte *) dest, (const TaoCrypt::byte *) source,
- MY_AES_BLOCK_SIZE);
- source += MY_AES_BLOCK_SIZE;
- dest += MY_AES_BLOCK_SIZE;
- }
-
- /* Encode the rest. We always have incomplete block */
- char pad_len = MY_AES_BLOCK_SIZE - (source_length -
- MY_AES_BLOCK_SIZE * num_blocks);
- memcpy(block, source, 16 - pad_len);
- memset(block + MY_AES_BLOCK_SIZE - pad_len, pad_len, pad_len);
-
- enc.Process((TaoCrypt::byte *) dest, (const TaoCrypt::byte *) block,
- MY_AES_BLOCK_SIZE);
-
- return MY_AES_BLOCK_SIZE * (num_blocks + 1);
-#elif defined(HAVE_OPENSSL)
- if (! EVP_EncryptInit(&ctx.ctx, EVP_aes_128_ecb(),
- (const unsigned char *) rkey, NULL))
- goto err;
- if (! EVP_EncryptUpdate(&ctx.ctx, (unsigned char *) dest, &u_len,
- (unsigned const char *) source, source_length))
- goto err;
- if (! EVP_EncryptFinal(&ctx.ctx, (unsigned char *) dest + u_len, &f_len))
- goto err;
-
- return u_len + f_len;
-err:
- ERR_remove_state(0);
- return AES_BAD_DATA;
-#endif
-}
-
-
-/**
- DeCrypt buffer with AES encryption algorithm.
-
- SYNOPSIS
- my_aes_decrypt()
- @param source [in] Pointer to data for decryption
- @param source_length [in] Size of encrypted data
- @param dest [out] Buffer to place decrypted data (must
- be large enough)
- @param key [in] Key to be used for decryption
- @param key_length [in] Length of the key. Will handle keys of any length
-
- @return
- >= 0 Size of encrypted data
- < 0 Error
-*/
-
-int my_aes_decrypt(const char *source, int source_length, char *dest,
- const char *key, int key_length)
-{
-#if defined(HAVE_YASSL)
- TaoCrypt::AES_ECB_Decryption dec;
- /* 128 bit block used for padding */
- uint8 block[MY_AES_BLOCK_SIZE];
- int num_blocks; /* Number of complete blocks */
- int i;
-#elif defined(HAVE_OPENSSL)
- MyCipherCtx ctx;
- int u_len, f_len;
-#endif
-
- /* The real key to be used for decryption */
- uint8 rkey[AES_KEY_LENGTH / 8];
- int rc; /* Result codes */
-
- if ((rc= my_aes_create_key(key, key_length, rkey)))
- return rc;
-
-#if defined(HAVE_YASSL)
- dec.SetKey((const TaoCrypt::byte *) rkey, MY_AES_BLOCK_SIZE);
-
- num_blocks = source_length / MY_AES_BLOCK_SIZE;
-
- if ((source_length != num_blocks * MY_AES_BLOCK_SIZE) || num_blocks == 0 )
- /* Input size has to be even and at least one block */
- return AES_BAD_DATA;
-
- /* Decode all but last blocks */
- for (i = num_blocks - 1; i > 0; i--)
- {
- dec.Process((TaoCrypt::byte *) dest, (const TaoCrypt::byte *) source,
- MY_AES_BLOCK_SIZE);
- source += MY_AES_BLOCK_SIZE;
- dest += MY_AES_BLOCK_SIZE;
- }
-
- dec.Process((TaoCrypt::byte *) block, (const TaoCrypt::byte *) source,
- MY_AES_BLOCK_SIZE);
-
- /* Use last char in the block as size */
- uint pad_len = (uint) (uchar) block[MY_AES_BLOCK_SIZE - 1];
-
- if (pad_len > MY_AES_BLOCK_SIZE)
- return AES_BAD_DATA;
- /* We could also check whole padding but we do not really need this */
-
- memcpy(dest, block, MY_AES_BLOCK_SIZE - pad_len);
- return MY_AES_BLOCK_SIZE * num_blocks - pad_len;
-#elif defined(HAVE_OPENSSL)
- if (! EVP_DecryptInit(&ctx.ctx, EVP_aes_128_ecb(),
- (const unsigned char *) rkey, NULL))
- goto err;
- if (! EVP_DecryptUpdate(&ctx.ctx, (unsigned char *) dest, &u_len,
- (unsigned const char *) source, source_length))
- goto err;
- if (! EVP_DecryptFinal(&ctx.ctx, (unsigned char *) dest + u_len, &f_len))
- goto err;
- return u_len + f_len;
-err:
- ERR_remove_state(0);
- return AES_BAD_DATA;
-#endif
-}
-
-
-/**
- Get size of buffer which will be large enough for encrypted data
-
- SYNOPSIS
- my_aes_get_size()
- @param source_length [in] Length of data to be encrypted
-
- @return
- Size of buffer required to store encrypted data
-*/
-
-int my_aes_get_size(int source_length)
-{
- return MY_AES_BLOCK_SIZE * (source_length / MY_AES_BLOCK_SIZE)
- + MY_AES_BLOCK_SIZE;
-}
-
diff --git a/mysys_ssl/my_crypt.cc b/mysys_ssl/my_crypt.cc
new file mode 100644
index 00000000000..49bd9af3f60
--- /dev/null
+++ b/mysys_ssl/my_crypt.cc
@@ -0,0 +1,296 @@
+/*
+ Copyright (c) 2014 Google Inc.
+ Copyright (c) 2014, 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 */
+
+#include <my_global.h>
+#include <string.h>
+#include <my_crypt.h>
+
+#ifdef HAVE_YASSL
+#include "yassl.cc"
+#else
+
+#include <openssl/evp.h>
+#include <openssl/aes.h>
+#include <openssl/err.h>
+
+#ifdef HAVE_ERR_remove_thread_state
+#define ERR_remove_state(X) ERR_remove_thread_state(NULL)
+#endif
+
+#endif
+
+class MyCTX
+{
+public:
+ EVP_CIPHER_CTX ctx;
+ MyCTX() { EVP_CIPHER_CTX_init(&ctx); }
+ virtual ~MyCTX() { EVP_CIPHER_CTX_cleanup(&ctx); ERR_remove_state(0); }
+
+ virtual int init(const EVP_CIPHER *cipher, int encrypt, const uchar *key,
+ uint klen, const uchar *iv, uint ivlen)
+ {
+ if (unlikely(!cipher))
+ return MY_AES_BAD_KEYSIZE;
+
+ if (!EVP_CipherInit_ex(&ctx, cipher, NULL, key, iv, encrypt))
+ return MY_AES_OPENSSL_ERROR;
+
+ DBUG_ASSERT(EVP_CIPHER_CTX_key_length(&ctx) == (int)klen);
+ DBUG_ASSERT(EVP_CIPHER_CTX_iv_length(&ctx) <= (int)ivlen);
+
+ return MY_AES_OK;
+ }
+ virtual int update(const uchar *src, uint slen, uchar *dst, uint *dlen)
+ {
+ if (!EVP_CipherUpdate(&ctx, dst, (int*)dlen, src, slen))
+ return MY_AES_OPENSSL_ERROR;
+ return MY_AES_OK;
+ }
+ virtual int finish(uchar *dst, uint *dlen)
+ {
+ if (!EVP_CipherFinal_ex(&ctx, dst, (int*)dlen))
+ return MY_AES_BAD_DATA;
+ return MY_AES_OK;
+ }
+};
+
+class MyCTX_nopad : public MyCTX
+{
+public:
+ const uchar *key;
+ int klen;
+
+ MyCTX_nopad() : MyCTX() { }
+ ~MyCTX_nopad() { }
+
+ int init(const EVP_CIPHER *cipher, int encrypt, const uchar *key, uint klen,
+ const uchar *iv, uint ivlen)
+ {
+ compile_time_assert(MY_AES_CTX_SIZE >= sizeof(MyCTX_nopad));
+ this->key= key;
+ this->klen= klen;
+ int res= MyCTX::init(cipher, encrypt, key, klen, iv, ivlen);
+ memcpy(ctx.oiv, iv, ivlen); // in ECB mode OpenSSL doesn't do that itself
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+ return res;
+ }
+
+ int finish(uchar *dst, uint *dlen)
+ {
+ if (ctx.buf_len)
+ {
+ /*
+ Not much we can do, block ciphers cannot encrypt data that aren't
+ a multiple of the block length. At least not without padding.
+ Let's do something CTR-like for the last partial block.
+ */
+ uchar mask[MY_AES_BLOCK_SIZE];
+ uint mlen;
+
+ my_aes_crypt(MY_AES_ECB, ENCRYPTION_FLAG_ENCRYPT | ENCRYPTION_FLAG_NOPAD,
+ ctx.oiv, sizeof(mask), mask, &mlen, key, klen, 0, 0);
+ DBUG_ASSERT(mlen == sizeof(mask));
+
+ for (int i=0; i < ctx.buf_len; i++)
+ dst[i]= ctx.buf[i] ^ mask[i];
+ }
+ *dlen= ctx.buf_len;
+ return MY_AES_OK;
+ }
+};
+
+#define make_aes_dispatcher(mode) \
+ static inline const EVP_CIPHER *aes_ ## mode(uint klen) \
+ { \
+ switch (klen) { \
+ case 16: return EVP_aes_128_ ## mode(); \
+ case 24: return EVP_aes_192_ ## mode(); \
+ case 32: return EVP_aes_256_ ## mode(); \
+ default: return 0; \
+ } \
+ }
+
+make_aes_dispatcher(ecb)
+make_aes_dispatcher(cbc)
+#ifdef HAVE_EncryptAes128Ctr
+make_aes_dispatcher(ctr)
+#endif /* HAVE_EncryptAes128Ctr */
+#ifdef HAVE_EncryptAes128Gcm
+make_aes_dispatcher(gcm)
+
+/*
+ special implementation for GCM; to fit OpenSSL AES-GCM into the
+ existing my_aes_* API it does the following:
+ - IV tail (over 12 bytes) goes to AAD
+ - the tag is appended to the ciphertext
+*/
+
+class MyCTX_gcm : public MyCTX
+{
+public:
+ const uchar *aad;
+ int aadlen;
+ MyCTX_gcm() : MyCTX() { }
+ ~MyCTX_gcm() { }
+
+ int init(const EVP_CIPHER *cipher, int encrypt, const uchar *key, uint klen,
+ const uchar *iv, uint ivlen)
+ {
+ compile_time_assert(MY_AES_CTX_SIZE >= sizeof(MyCTX_gcm));
+ int res= MyCTX::init(cipher, encrypt, key, klen, iv, ivlen);
+ int real_ivlen= EVP_CIPHER_CTX_iv_length(&ctx);
+ aad= iv + real_ivlen;
+ aadlen= ivlen - real_ivlen;
+ return res;
+ }
+
+ int update(const uchar *src, uint slen, uchar *dst, uint *dlen)
+ {
+ /*
+ note that this GCM class cannot do streaming decryption, because
+ it needs the tag (which is located at the end of encrypted data)
+ before decrypting the data. it can encrypt data piecewise, like, first
+ half, then the second half, but it must decrypt all at once
+ */
+ if (!ctx.encrypt)
+ {
+ slen-= MY_AES_BLOCK_SIZE;
+ if(!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_TAG, MY_AES_BLOCK_SIZE,
+ (void*)(src + slen)))
+ return MY_AES_OPENSSL_ERROR;
+ }
+ int unused;
+ if (aadlen && !EVP_CipherUpdate(&ctx, NULL, &unused, aad, aadlen))
+ return MY_AES_OPENSSL_ERROR;
+ aadlen= 0;
+ return MyCTX::update(src, slen, dst, dlen);
+ }
+
+ int finish(uchar *dst, uint *dlen)
+ {
+ int fin;
+ if (!EVP_CipherFinal_ex(&ctx, dst, &fin))
+ return MY_AES_BAD_DATA;
+ DBUG_ASSERT(fin == 0);
+
+ if (ctx.encrypt)
+ {
+ if(!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_GET_TAG, MY_AES_BLOCK_SIZE, dst))
+ return MY_AES_OPENSSL_ERROR;
+ *dlen= MY_AES_BLOCK_SIZE;
+ }
+ else
+ *dlen= 0;
+ return MY_AES_OK;
+ }
+};
+
+#endif
+
+const EVP_CIPHER *(*ciphers[])(uint)= {
+ aes_ecb, aes_cbc
+#ifdef HAVE_EncryptAes128Ctr
+ , aes_ctr
+#ifdef HAVE_EncryptAes128Gcm
+ , aes_gcm
+#endif
+#endif
+};
+
+extern "C" {
+
+int my_aes_crypt_init(void *ctx, enum my_aes_mode mode, int flags,
+ const unsigned char* key, unsigned int klen,
+ const unsigned char* iv, unsigned int ivlen)
+{
+#ifdef HAVE_EncryptAes128Ctr
+#ifdef HAVE_EncryptAes128Gcm
+ if (mode == MY_AES_GCM)
+ if (flags & ENCRYPTION_FLAG_NOPAD)
+ return MY_AES_OPENSSL_ERROR;
+ else
+ new (ctx) MyCTX_gcm();
+ else
+#endif
+ if (mode == MY_AES_CTR)
+ new (ctx) MyCTX();
+ else
+#endif
+ if (flags & ENCRYPTION_FLAG_NOPAD)
+ new (ctx) MyCTX_nopad();
+ else
+ new (ctx) MyCTX();
+ return ((MyCTX*)ctx)->init(ciphers[mode](klen), flags & 1,
+ key, klen, iv, ivlen);
+}
+
+int my_aes_crypt_update(void *ctx, const uchar *src, uint slen,
+ uchar *dst, uint *dlen)
+{
+ return ((MyCTX*)ctx)->update(src, slen, dst, dlen);
+}
+
+int my_aes_crypt_finish(void *ctx, uchar *dst, uint *dlen)
+{
+ int res= ((MyCTX*)ctx)->finish(dst, dlen);
+ ((MyCTX*)ctx)->~MyCTX();
+ return res;
+}
+
+int my_aes_crypt(enum my_aes_mode mode, int flags,
+ const uchar *src, uint slen, uchar *dst, uint *dlen,
+ const uchar *key, uint klen, const uchar *iv, uint ivlen)
+{
+ void *ctx= alloca(MY_AES_CTX_SIZE);
+ int res1, res2;
+ uint d1, d2;
+ if ((res1= my_aes_crypt_init(ctx, mode, flags, key, klen, iv, ivlen)))
+ return res1;
+ res1= my_aes_crypt_update(ctx, src, slen, dst, &d1);
+ res2= my_aes_crypt_finish(ctx, dst + d1, &d2);
+ *dlen= d1 + d2;
+ return res1 ? res1 : res2;
+}
+
+#ifdef HAVE_YASSL
+#include <random.hpp>
+int my_random_bytes(uchar* buf, int num)
+{
+ TaoCrypt::RandomNumberGenerator rand;
+ rand.GenerateBlock((TaoCrypt::byte*) buf, num);
+ return MY_AES_OK;
+}
+#else
+#include <openssl/rand.h>
+
+int my_random_bytes(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 MY_AES_OPENSSL_ERROR;
+ return MY_AES_OK;
+}
+#endif
+
+}
+
diff --git a/mysys_ssl/my_md5.cc b/mysys_ssl/my_md5.cc
index 4e362e647a1..7139ea9b6ff 100644
--- a/mysys_ssl/my_md5.cc
+++ b/mysys_ssl/my_md5.cc
@@ -1,4 +1,5 @@
-/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2012, Oracle and/or its affiliates.
+ Copyright (c) 2014, SkySQL Ab.
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
@@ -24,51 +25,132 @@
#include <my_global.h>
#include <my_md5.h>
+#include <stdarg.h>
#if defined(HAVE_YASSL)
-#include "my_config.h"
#include "md5.hpp"
-static void my_md5_hash(char *digest, const char *buf, int len)
+typedef TaoCrypt::MD5 MD5_CONTEXT;
+
+static void md5_init(MD5_CONTEXT *context)
+{
+ context= new(context) MD5_CONTEXT;
+ context->Init();
+}
+
+/*
+ this is a variant of md5_init to be used in this file only.
+ does nothing for yassl, because the context's constructor was called automatically.
+*/
+static void md5_init_fast(MD5_CONTEXT *context)
+{
+}
+
+static void md5_input(MD5_CONTEXT *context, const uchar *buf, unsigned len)
+{
+ context->Update((const TaoCrypt::byte *) buf, len);
+}
+
+static void md5_result(MD5_CONTEXT *context, uchar digest[MD5_HASH_SIZE])
{
- TaoCrypt::MD5 hasher;
- hasher.Update((TaoCrypt::byte *) buf, len);
- hasher.Final((TaoCrypt::byte *) digest);
+ context->Final((TaoCrypt::byte *) digest);
}
#elif defined(HAVE_OPENSSL)
#include <openssl/evp.h>
+typedef EVP_MD_CTX MD5_CONTEXT;
-static void my_md5_hash(uchar* digest, const uchar *buf, uint len)
+static void md5_init(MD5_CONTEXT *context)
{
- EVP_MD_CTX ctx;
- EVP_MD_CTX_init(&ctx);
+ EVP_MD_CTX_init(context);
#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
/* Ok to ignore FIPS: MD5 is not used for crypto here */
- EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+ EVP_MD_CTX_set_flags(context, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
#endif
- EVP_DigestInit_ex(&ctx, EVP_md5(), NULL);
- EVP_DigestUpdate(&ctx, buf, len);
- EVP_DigestFinal(&ctx, digest, &len);
- EVP_MD_CTX_cleanup(&ctx);
+ EVP_DigestInit_ex(context, EVP_md5(), NULL);
+}
+
+static void md5_init_fast(MD5_CONTEXT *context)
+{
+ md5_init(context);
+}
+
+static void md5_input(MD5_CONTEXT *context, const uchar *buf, unsigned len)
+{
+ EVP_DigestUpdate(context, buf, len);
+}
+
+static void md5_result(MD5_CONTEXT *context, uchar digest[MD5_HASH_SIZE])
+{
+ EVP_DigestFinal_ex(context, digest, NULL);
+ EVP_MD_CTX_cleanup(context);
}
#endif /* HAVE_YASSL */
/**
- Wrapper function to compute MD5 message digest.
+ Wrapper function to compute MD5 message digest.
- @param digest [out] Computed MD5 digest
- @param buf [in] Message to be computed
- @param len [in] Length of the message
+ @param digest [out] Computed MD5 digest
+ @param buf [in] Message to be computed
+ @param len [in] Length of the message
- @return void
+ @return void
*/
-void compute_md5_hash(char *digest, const char *buf, int len)
+void my_md5(uchar *digest, const char *buf, size_t len)
{
-#if defined(HAVE_YASSL)
- my_md5_hash(digest, buf, len);
-#elif defined(HAVE_OPENSSL)
- my_md5_hash((unsigned char*)digest, (unsigned const char*)buf, len);
-#endif /* HAVE_YASSL */
+ MD5_CONTEXT md5_context;
+
+ md5_init_fast(&md5_context);
+ md5_input(&md5_context, (const uchar *)buf, len);
+ md5_result(&md5_context, digest);
+}
+
+
+/**
+ Wrapper function to compute MD5 message digest for
+ two messages in order to emulate md5(msg1, msg2).
+
+ @param digest [out] Computed MD5 digest
+ @param buf1 [in] First message
+ @param len1 [in] Length of first message
+ @param buf2 [in] Second message
+ @param len2 [in] Length of second message
+
+ @return void
+*/
+void my_md5_multi(uchar *digest, ...)
+{
+ va_list args;
+ va_start(args, digest);
+
+ MD5_CONTEXT md5_context;
+ const uchar *str;
+
+ md5_init_fast(&md5_context);
+ for (str= va_arg(args, const uchar*); str; str= va_arg(args, const uchar*))
+ md5_input(&md5_context, str, va_arg(args, size_t));
+
+ md5_result(&md5_context, digest);
+ va_end(args);
+}
+
+size_t my_md5_context_size()
+{
+ return sizeof(MD5_CONTEXT);
+}
+
+void my_md5_init(void *context)
+{
+ md5_init((MD5_CONTEXT *)context);
+}
+
+void my_md5_input(void *context, const uchar *buf, size_t len)
+{
+ md5_input((MD5_CONTEXT *)context, buf, len);
+}
+
+void my_md5_result(void *context, uchar *digest)
+{
+ md5_result((MD5_CONTEXT *)context, digest);
}
diff --git a/mysys_ssl/my_sha1.cc b/mysys_ssl/my_sha1.cc
index fc8f88856bb..9b12d1f1ae8 100644
--- a/mysys_ssl/my_sha1.cc
+++ b/mysys_ssl/my_sha1.cc
@@ -1,4 +1,5 @@
-/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2012, Oracle and/or its affiliates.
+ Copyright (c) 2014, SkySQL Ab.
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
@@ -29,66 +30,52 @@
#if defined(HAVE_YASSL)
#include "sha.hpp"
-/**
- Compute SHA1 message digest using YaSSL.
+typedef TaoCrypt::SHA SHA_CTX;
- @param digest [out] Computed SHA1 digest
- @param buf [in] Message to be computed
- @param len [in] Length of the message
+static void sha1_init(SHA_CTX *context)
+{
+ context->Init();
+}
- @return void
+/*
+ this is a variant of sha1_init to be used in this file only.
+ does nothing for yassl, because the context's constructor was called automatically.
*/
-void mysql_sha1_yassl(uint8 *digest, const char *buf, int len)
+static void sha1_init_fast(SHA_CTX *context)
{
- TaoCrypt::SHA hasher;
- hasher.Update((const TaoCrypt::byte *) buf, len);
- hasher.Final ((TaoCrypt::byte *) digest);
}
-/**
- Compute SHA1 message digest for two messages in order to
- emulate sha1(msg1, msg2) using YaSSL.
-
- @param digest [out] Computed SHA1 digest
- @param buf1 [in] First message
- @param len1 [in] Length of first message
- @param buf2 [in] Second message
- @param len2 [in] Length of second message
+static void sha1_input(SHA_CTX *context, const uchar *buf, unsigned len)
+{
+ context->Update((const TaoCrypt::byte *) buf, len);
+}
- @return void
-*/
-void mysql_sha1_multi_yassl(uint8 *digest, va_list args)
+static void sha1_result(SHA_CTX *context, uchar digest[SHA1_HASH_SIZE])
{
- const char *str;
- TaoCrypt::SHA hasher;
-
- for (str= va_arg(args, const char*); str; str= va_arg(args, const char*))
- {
- hasher.Update((const TaoCrypt::byte *) str, va_arg(args, size_t));
- }
- hasher.Final((TaoCrypt::byte *) digest);
+ context->Final((TaoCrypt::byte *) digest);
}
#elif defined(HAVE_OPENSSL)
#include <openssl/sha.h>
-int mysql_sha1_reset(SHA_CTX *context)
+static void sha1_init(SHA_CTX *context)
{
- return SHA1_Init(context);
+ SHA1_Init(context);
}
-
-int mysql_sha1_input(SHA_CTX *context, const uint8 *message_array,
- unsigned length)
+static void sha1_init_fast(SHA_CTX *context)
{
- return SHA1_Update(context, message_array, length);
+ sha1_init(context);
}
+static void sha1_input(SHA_CTX *context, const uchar *buf, unsigned len)
+{
+ SHA1_Update(context, buf, len);
+}
-int mysql_sha1_result(SHA_CTX *context,
- uint8 Message_Digest[SHA1_HASH_SIZE])
+static void sha1_result(SHA_CTX *context, uchar digest[SHA1_HASH_SIZE])
{
- return SHA1_Final(Message_Digest, context);
+ SHA1_Final(digest, context);
}
#endif /* HAVE_YASSL */
@@ -102,17 +89,13 @@ int mysql_sha1_result(SHA_CTX *context,
@return void
*/
-void my_sha1(uint8 *digest, const char *buf, size_t len)
+void my_sha1(uchar *digest, const char *buf, size_t len)
{
-#if defined(HAVE_YASSL)
- mysql_sha1_yassl(digest, buf, len);
-#elif defined(HAVE_OPENSSL)
SHA_CTX sha1_context;
- mysql_sha1_reset(&sha1_context);
- mysql_sha1_input(&sha1_context, (const uint8 *) buf, len);
- mysql_sha1_result(&sha1_context, digest);
-#endif /* HAVE_YASSL */
+ sha1_init_fast(&sha1_context);
+ sha1_input(&sha1_context, (const uchar *)buf, len);
+ sha1_result(&sha1_context, digest);
}
@@ -128,24 +111,38 @@ void my_sha1(uint8 *digest, const char *buf, size_t len)
@return void
*/
-void my_sha1_multi(uint8 *digest, ...)
+void my_sha1_multi(uchar *digest, ...)
{
va_list args;
va_start(args, digest);
-#if defined(HAVE_YASSL)
- mysql_sha1_multi_yassl(digest, args);
-#elif defined(HAVE_OPENSSL)
SHA_CTX sha1_context;
- const char *str;
-
- mysql_sha1_reset(&sha1_context);
- for (str= va_arg(args, const char*); str; str= va_arg(args, const char*))
- {
- mysql_sha1_input(&sha1_context, (const uint8 *) str, va_arg(args, size_t));
- }
- mysql_sha1_result(&sha1_context, digest);
-#endif /* HAVE_YASSL */
+ const uchar *str;
+
+ sha1_init_fast(&sha1_context);
+ for (str= va_arg(args, const uchar*); str; str= va_arg(args, const uchar*))
+ sha1_input(&sha1_context, str, va_arg(args, size_t));
+
+ sha1_result(&sha1_context, digest);
va_end(args);
}
+size_t my_sha1_context_size()
+{
+ return sizeof(SHA_CTX);
+}
+
+void my_sha1_init(void *context)
+{
+ sha1_init((SHA_CTX *)context);
+}
+
+void my_sha1_input(void *context, const uchar *buf, size_t len)
+{
+ sha1_input((SHA_CTX *)context, buf, len);
+}
+
+void my_sha1_result(void *context, uchar *digest)
+{
+ sha1_result((SHA_CTX *)context, digest);
+}
diff --git a/mysys_ssl/yassl.cc b/mysys_ssl/yassl.cc
new file mode 100644
index 00000000000..9717870fe26
--- /dev/null
+++ b/mysys_ssl/yassl.cc
@@ -0,0 +1,194 @@
+/*
+ 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 */
+
+/*
+ The very minimal subset of OpenSSL's EVP* functions.
+ Just enough for my_crypt.cc to work.
+
+ On the other hand, where it has to implement OpenSSL functionality,
+ it tries to be compatible (e.g. same flags and struct member names).
+*/
+
+#include <openssl/ssl.h>
+#include "aes.hpp"
+
+using yaSSL::yaERR_remove_state;
+
+#define EVP_CIPH_ECB_MODE 0x1
+#define EVP_CIPH_CBC_MODE 0x2
+#define EVP_CIPH_NO_PADDING 0x100
+
+/*
+ note that TaoCrypt::AES object is not explicitly put into EVP_CIPHER_CTX.
+ That's because we need to control when TaoCrypt::AES constructor and
+ destructor are called.
+*/
+typedef struct
+{
+ ulong flags;
+ int encrypt;
+ int key_len;
+ int buf_len;
+ int final_used;
+ uchar tao_buf[sizeof(TaoCrypt::AES)]; // TaoCrypt::AES object
+ uchar oiv[TaoCrypt::AES::BLOCK_SIZE]; // original IV
+ uchar buf[TaoCrypt::AES::BLOCK_SIZE]; // last partial input block
+ uchar final[TaoCrypt::AES::BLOCK_SIZE]; // last decrypted (output) block
+} EVP_CIPHER_CTX;
+
+typedef struct {
+ TaoCrypt::Mode mode;
+ TaoCrypt::word32 key_len;
+} EVP_CIPHER;
+
+#define gen_cipher(mode, MODE, len) \
+ static const EVP_CIPHER *EVP_aes_ ## len ## _ ## mode() \
+ { static const EVP_CIPHER c={TaoCrypt::MODE, len/8}; return &c; }
+
+gen_cipher(ecb,ECB,128)
+gen_cipher(ecb,ECB,192)
+gen_cipher(ecb,ECB,256)
+gen_cipher(cbc,CBC,128)
+gen_cipher(cbc,CBC,192)
+gen_cipher(cbc,CBC,256)
+
+static inline TaoCrypt::AES *TAO(EVP_CIPHER_CTX *ctx)
+{
+ return (TaoCrypt::AES *)(ctx->tao_buf);
+}
+
+static void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx)
+{
+ ctx->final_used= ctx->buf_len= ctx->flags= 0;
+}
+
+static int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *ctx)
+{
+ TAO(ctx)->~AES();
+ return 1;
+}
+
+static int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad)
+{
+ if (pad)
+ ctx->flags&= ~EVP_CIPH_NO_PADDING;
+ else
+ ctx->flags|= EVP_CIPH_NO_PADDING;
+ return 1;
+}
+
+static int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ void *, const uchar *key, const uchar *iv, int enc)
+{
+ new (ctx->tao_buf) TaoCrypt::AES(enc ? TaoCrypt::ENCRYPTION
+ : TaoCrypt::DECRYPTION, cipher->mode);
+ TAO(ctx)->SetKey(key, cipher->key_len);
+ if (iv)
+ {
+ TAO(ctx)->SetIV(iv);
+ memcpy(ctx->oiv, iv, TaoCrypt::AES::BLOCK_SIZE);
+ }
+ ctx->encrypt= enc;
+ ctx->key_len= cipher->key_len;
+ ctx->flags|= cipher->mode == TaoCrypt::CBC ? EVP_CIPH_CBC_MODE : EVP_CIPH_ECB_MODE;
+ return 1;
+}
+
+static int EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx)
+{
+ return ctx->key_len;
+}
+
+static int EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx)
+{
+ return ctx->flags & EVP_CIPH_ECB_MODE ? 0 : TaoCrypt::AES::BLOCK_SIZE;
+}
+
+static void do_whole_blocks(EVP_CIPHER_CTX *ctx, uchar *out, int *outl,
+ const uchar *in, int inl)
+{
+ DBUG_ASSERT(inl);
+ DBUG_ASSERT(inl % TaoCrypt::AES::BLOCK_SIZE == 0);
+ if (ctx->encrypt || (ctx->flags & EVP_CIPH_NO_PADDING))
+ {
+ TAO(ctx)->Process(out, in, inl);
+ *outl+= inl;
+ return;
+ }
+ /* 'final' is only needed when decrypting with padding */
+ if (ctx->final_used)
+ {
+ memcpy(out, ctx->final, TaoCrypt::AES::BLOCK_SIZE);
+ *outl+= TaoCrypt::AES::BLOCK_SIZE;
+ out+= TaoCrypt::AES::BLOCK_SIZE;
+ }
+ inl-= TaoCrypt::AES::BLOCK_SIZE;
+ TAO(ctx)->Process(out, in, inl);
+ *outl+= inl;
+ TAO(ctx)->Process(ctx->final, in + inl, TaoCrypt::AES::BLOCK_SIZE);
+ ctx->final_used= 1;
+}
+
+static int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, uchar *out, int *outl,
+ const uchar *in, int inl)
+{
+ *outl= 0;
+ if (ctx->buf_len)
+ {
+ int prefixl= TaoCrypt::AES::BLOCK_SIZE - ctx->buf_len;
+ if (prefixl > inl)
+ {
+ memcpy(ctx->buf + ctx->buf_len, in, inl);
+ ctx->buf_len+= inl;
+ return 1;
+ }
+ memcpy(ctx->buf + ctx->buf_len, in, prefixl);
+ do_whole_blocks(ctx, out, outl, ctx->buf, TaoCrypt::AES::BLOCK_SIZE);
+ in+= prefixl;
+ inl-= prefixl;
+ out+= *outl;
+ }
+ ctx->buf_len= inl % TaoCrypt::AES::BLOCK_SIZE;
+ inl-= ctx->buf_len;
+ memcpy(ctx->buf, in + inl, ctx->buf_len);
+ if (inl)
+ do_whole_blocks(ctx, out, outl, in, inl);
+ return 1;
+}
+
+static int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, uchar *out, int *outl)
+{
+ if (ctx->flags & EVP_CIPH_NO_PADDING)
+ return ctx->buf_len == 0;
+
+ // PKCS#7 padding
+ *outl= 0;
+ if (ctx->encrypt)
+ {
+ int v= TaoCrypt::AES::BLOCK_SIZE - ctx->buf_len;
+ memset(ctx->buf + ctx->buf_len, v, v);
+ do_whole_blocks(ctx, out, outl, ctx->buf, TaoCrypt::AES::BLOCK_SIZE);
+ return 1;
+ }
+ int n= ctx->final[TaoCrypt::AES::BLOCK_SIZE - 1];
+ if (ctx->buf_len || !ctx->final_used ||
+ n < 1 || n > TaoCrypt::AES::BLOCK_SIZE)
+ return 0;
+ *outl= TaoCrypt::AES::BLOCK_SIZE - n;
+ memcpy(out, ctx->final, *outl);
+ return 1;
+}
+