Commit acd992d4 authored by Sergei Golubchik's avatar Sergei Golubchik

MDEV-8022 Assertion `rc == 0' failed in ma_encrypt on dropping an encrypted Aria table

fix encryption of the last partial block

* now really encrypt it, using key and iv
* support the case of very short plaintext (less than one block)
* recommend aes_ctr over aes_cbc, because the former
  doesn't have problems with partial blocks
parent bea3f30d
set global aria_encrypt_tables = 1;
create table t1 (i int, key(i)) engine=aria;
insert into t1 values (1);
drop table t1;
set global aria_encrypt_tables = 0;
#
# MDEV-8022 Assertion `rc == 0' failed in ma_encrypt on dropping an encrypted Aria table
#
--source include/have_file_key_management_plugin.inc
set global aria_encrypt_tables = 1;
create table t1 (i int, key(i)) engine=aria;
insert into t1 values (1);
drop table t1;
set global aria_encrypt_tables = 0;
...@@ -71,84 +71,94 @@ static int block_crypt(CipherMode cipher, Dir dir, ...@@ -71,84 +71,94 @@ static int block_crypt(CipherMode cipher, Dir dir,
{ {
int tail= source_length % MY_AES_BLOCK_SIZE; int tail= source_length % MY_AES_BLOCK_SIZE;
#ifdef HAVE_YASSL DBUG_ASSERT(source_length);
TaoCrypt::AES ctx(dir, cipher);
if (unlikely(key_length != 16 && key_length != 24 && key_length != 32))
return MY_AES_BAD_KEYSIZE;
ctx.SetKey(key, key_length); if (likely(source_length >= MY_AES_BLOCK_SIZE || !no_padding))
if (iv)
{ {
ctx.SetIV(iv); #ifdef HAVE_YASSL
DBUG_ASSERT(TaoCrypt::AES::BLOCK_SIZE == iv_length); TaoCrypt::AES ctx(dir, cipher);
}
DBUG_ASSERT(TaoCrypt::AES::BLOCK_SIZE == MY_AES_BLOCK_SIZE);
ctx.Process(dest, source, source_length - tail); if (unlikely(key_length != 16 && key_length != 24 && key_length != 32))
*dest_length= source_length - tail; return MY_AES_BAD_KEYSIZE;
/* unlike OpenSSL, YaSSL doesn't support PKCS#7 padding */ ctx.SetKey(key, key_length);
if (!no_padding) if (iv)
{
if (dir == CRYPT_ENCRYPT)
{ {
uchar buf[MY_AES_BLOCK_SIZE]; ctx.SetIV(iv);
memcpy(buf, source + source_length - tail, tail); DBUG_ASSERT(TaoCrypt::AES::BLOCK_SIZE <= iv_length);
memset(buf + tail, MY_AES_BLOCK_SIZE - tail, MY_AES_BLOCK_SIZE - tail);
ctx.Process(dest + *dest_length, buf, MY_AES_BLOCK_SIZE);
*dest_length+= MY_AES_BLOCK_SIZE;
} }
else DBUG_ASSERT(TaoCrypt::AES::BLOCK_SIZE == MY_AES_BLOCK_SIZE);
ctx.Process(dest, source, source_length - tail);
*dest_length= source_length - tail;
/* unlike OpenSSL, YaSSL doesn't support PKCS#7 padding */
if (!no_padding)
{ {
int n= dest[source_length - 1]; if (dir == CRYPT_ENCRYPT)
if (tail || n == 0 || n > MY_AES_BLOCK_SIZE) {
return MY_AES_BAD_DATA; uchar buf[MY_AES_BLOCK_SIZE];
*dest_length-= n; memcpy(buf, source + source_length - tail, tail);
memset(buf + tail, MY_AES_BLOCK_SIZE - tail, MY_AES_BLOCK_SIZE - tail);
ctx.Process(dest + *dest_length, buf, MY_AES_BLOCK_SIZE);
*dest_length+= MY_AES_BLOCK_SIZE;
}
else
{
int n= dest[source_length - 1];
if (tail || n == 0 || n > MY_AES_BLOCK_SIZE)
return MY_AES_BAD_DATA;
*dest_length-= n;
}
} }
}
#else // HAVE_OPENSSL #else // HAVE_OPENSSL
int fin; int fin;
struct MyCTX ctx; struct MyCTX ctx;
if (unlikely(!cipher)) if (unlikely(!cipher))
return MY_AES_BAD_KEYSIZE; return MY_AES_BAD_KEYSIZE;
if (!EVP_CipherInit_ex(&ctx, cipher, NULL, key, iv, dir)) if (!EVP_CipherInit_ex(&ctx, cipher, NULL, key, iv, dir))
return MY_AES_OPENSSL_ERROR; return MY_AES_OPENSSL_ERROR;
EVP_CIPHER_CTX_set_padding(&ctx, !no_padding); EVP_CIPHER_CTX_set_padding(&ctx, !no_padding);
DBUG_ASSERT(EVP_CIPHER_CTX_key_length(&ctx) == (int)key_length); DBUG_ASSERT(EVP_CIPHER_CTX_key_length(&ctx) == (int)key_length);
DBUG_ASSERT(EVP_CIPHER_CTX_iv_length(&ctx) == (int)iv_length); DBUG_ASSERT(EVP_CIPHER_CTX_iv_length(&ctx) <= (int)iv_length);
DBUG_ASSERT(EVP_CIPHER_CTX_block_size(&ctx) == MY_AES_BLOCK_SIZE); DBUG_ASSERT(EVP_CIPHER_CTX_block_size(&ctx) == MY_AES_BLOCK_SIZE);
/* use built-in OpenSSL padding, if possible */ /* use built-in OpenSSL padding, if possible */
if (!EVP_CipherUpdate(&ctx, dest, (int*)dest_length, if (!EVP_CipherUpdate(&ctx, dest, (int*)dest_length,
source, source_length - (no_padding ? tail : 0))) source, source_length - (no_padding ? tail : 0)))
return MY_AES_OPENSSL_ERROR; return MY_AES_OPENSSL_ERROR;
if (!EVP_CipherFinal_ex(&ctx, dest + *dest_length, &fin)) if (!EVP_CipherFinal_ex(&ctx, dest + *dest_length, &fin))
return MY_AES_BAD_DATA; return MY_AES_BAD_DATA;
*dest_length += fin; *dest_length += fin;
#endif #endif
}
if (no_padding && tail) if (no_padding && tail)
{ {
/* /*
Not much we can do, block ciphers cannot encrypt data that aren't Not much we can do, block ciphers cannot encrypt data that aren't
a multiple of the block length. At least not without padding. a multiple of the block length. At least not without padding.
What we do here, we XOR the tail with the previous encrypted block. Let's do something CTR-like for the last partial block.
*/ */
if (unlikely(source_length < MY_AES_BLOCK_SIZE)) uchar mask[MY_AES_BLOCK_SIZE];
return MY_AES_BAD_DATA; uint mlen;
DBUG_ASSERT(iv_length >= sizeof(mask));
my_aes_encrypt_ecb(iv, sizeof(mask), mask, &mlen,
key, key_length, 0, 0, 1);
DBUG_ASSERT(mlen == sizeof(mask));
const uchar *s= source + source_length - tail; const uchar *s= source + source_length - tail;
const uchar *e= source + source_length; const uchar *e= source + source_length;
uchar *d= dest + source_length - tail; uchar *d= dest + source_length - tail;
const uchar *m= (dir == CRYPT_ENCRYPT ? d : s) - MY_AES_BLOCK_SIZE; const uchar *m= mask;
while (s < e) while (s < e)
*d++ = *s++ ^ *m++; *d++ = *s++ ^ *m++;
*dest_length= source_length; *dest_length= source_length;
...@@ -204,7 +214,7 @@ int my_aes_encrypt_ecb(const uchar* source, uint source_length, ...@@ -204,7 +214,7 @@ int my_aes_encrypt_ecb(const uchar* source, uint source_length,
int no_padding) int no_padding)
{ {
return block_crypt(aes_ecb(key_length), CRYPT_ENCRYPT, source, source_length, return block_crypt(aes_ecb(key_length), CRYPT_ENCRYPT, source, source_length,
dest, dest_length, key, key_length, 0, 0, no_padding); dest, dest_length, key, key_length, iv, iv_length, no_padding);
} }
int my_aes_decrypt_ecb(const uchar* source, uint source_length, int my_aes_decrypt_ecb(const uchar* source, uint source_length,
...@@ -214,7 +224,7 @@ int my_aes_decrypt_ecb(const uchar* source, uint source_length, ...@@ -214,7 +224,7 @@ int my_aes_decrypt_ecb(const uchar* source, uint source_length,
int no_padding) int no_padding)
{ {
return block_crypt(aes_ecb(key_length), CRYPT_DECRYPT, source, source_length, return block_crypt(aes_ecb(key_length), CRYPT_DECRYPT, source, source_length,
dest, dest_length, key, key_length, 0, 0, no_padding); dest, dest_length, key, key_length, iv, iv_length, no_padding);
} }
int my_aes_encrypt_cbc(const uchar* source, uint source_length, int my_aes_encrypt_cbc(const uchar* source, uint source_length,
......
...@@ -50,7 +50,7 @@ static MYSQL_SYSVAR_STR(filekey, filekey, ...@@ -50,7 +50,7 @@ static MYSQL_SYSVAR_STR(filekey, filekey,
static MYSQL_SYSVAR_ENUM(encryption_algorithm, encryption_algorithm, static MYSQL_SYSVAR_ENUM(encryption_algorithm, encryption_algorithm,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Encryption algorithm to use.", "Encryption algorithm to use, aes_ctr is the recommended one.",
NULL, NULL, 0, &encryption_algorithm_typelib); NULL, NULL, 0, &encryption_algorithm_typelib);
static struct st_mysql_sys_var* settings[] = { static struct st_mysql_sys_var* settings[] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment