diff options
Diffstat (limited to 'mysys_ssl')
-rw-r--r-- | mysys_ssl/CMakeLists.txt | 3 | ||||
-rw-r--r-- | mysys_ssl/my_aes.cc | 289 | ||||
-rw-r--r-- | mysys_ssl/my_crypt.cc | 296 | ||||
-rw-r--r-- | mysys_ssl/my_md5.cc | 132 | ||||
-rw-r--r-- | mysys_ssl/my_sha1.cc | 119 | ||||
-rw-r--r-- | mysys_ssl/yassl.cc | 194 |
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; +} + |