summaryrefslogtreecommitdiff
path: root/mysys_ssl/my_crypt.cc
diff options
context:
space:
mode:
authorMonty <monty@mariadb.org>2014-12-22 16:53:17 +0200
committerSergei Golubchik <serg@mariadb.org>2015-02-10 10:21:17 +0100
commitd7d589dc01f6d70d1518b74d46fd3b75e76267f5 (patch)
treef9df59951453660f0038ed78cf5ceadc852bf74c /mysys_ssl/my_crypt.cc
parent3a3ec744b5a31318a00821dc0ed6da8af49fda25 (diff)
downloadmariadb-git-d7d589dc01f6d70d1518b74d46fd3b75e76267f5.tar.gz
Push for testing of encryption
Diffstat (limited to 'mysys_ssl/my_crypt.cc')
-rw-r--r--mysys_ssl/my_crypt.cc370
1 files changed, 370 insertions, 0 deletions
diff --git a/mysys_ssl/my_crypt.cc b/mysys_ssl/my_crypt.cc
new file mode 100644
index 00000000000..0d49999fdfa
--- /dev/null
+++ b/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 my_random_bytes(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 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 AES_OPENSSL_ERROR;
+ return AES_OK;
+}
+
+C_MODE_END
+#endif /* HAVE_YASSL */