AES_CBC is now supported for binlog encryption
AES_CBC can be used for binlog files encryption The AES_CBC could leaves some not handled bytes in the buffer and those need a special encoding (ECB and XOR) This way the output buffer of the whole encoding with AES_CBC will have same size as the input (AES_CTR does it without any other step)
This commit is contained in:
@ -83,7 +83,8 @@ MXS_BEGIN_DECLS
|
|||||||
enum blr_aes_mode
|
enum blr_aes_mode
|
||||||
{
|
{
|
||||||
BLR_AES_CBC,
|
BLR_AES_CBC,
|
||||||
BLR_AES_CTR
|
BLR_AES_CTR,
|
||||||
|
BLR_AES_ECB
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Default encryption alogorithm is AES_CTR */
|
/* Default encryption alogorithm is AES_CTR */
|
||||||
|
|||||||
@ -44,6 +44,7 @@
|
|||||||
* Events are decrypted before being sent to slaves.
|
* Events are decrypted before being sent to slaves.
|
||||||
* Events larger than 16MBytes are currently not suitable
|
* Events larger than 16MBytes are currently not suitable
|
||||||
* for ecryption/decryption.
|
* for ecryption/decryption.
|
||||||
|
* 29/11/2016 Massimiliano Pinto Binlog files can be encrypted with AES_CBC
|
||||||
*
|
*
|
||||||
* @endverbatim
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
@ -104,13 +105,31 @@ static inline const EVP_CIPHER *aes_cbc(uint klen)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AES_ECB handling
|
||||||
|
*
|
||||||
|
* @param klen The AES Key len
|
||||||
|
* @return The EVP_AES_ECB routine for key len
|
||||||
|
*/
|
||||||
|
static inline const EVP_CIPHER *aes_ecb(uint klen)
|
||||||
|
{
|
||||||
|
switch (klen)
|
||||||
|
{
|
||||||
|
case 16: return EVP_aes_128_ecb();
|
||||||
|
case 24: return EVP_aes_192_ecb();
|
||||||
|
case 32: return EVP_aes_256_ecb();
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array of functions for supported algorithms
|
* Array of functions for supported algorithms
|
||||||
*/
|
*/
|
||||||
const EVP_CIPHER *(*ciphers[])(unsigned int) =
|
const EVP_CIPHER *(*ciphers[])(unsigned int) =
|
||||||
{
|
{
|
||||||
aes_cbc,
|
aes_cbc,
|
||||||
aes_ctr
|
aes_ctr,
|
||||||
|
aes_ecb
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *blr_encryption_algorithm_names[BINLOG_MAX_CRYPTO_SCHEME] = {"aes_cbc", "aes_ctr"};
|
static const char *blr_encryption_algorithm_names[BINLOG_MAX_CRYPTO_SCHEME] = {"aes_cbc", "aes_ctr"};
|
||||||
@ -161,6 +180,12 @@ GWBUF *blr_aes_crypt(ROUTER_INSTANCE *router,
|
|||||||
uint32_t event_size,
|
uint32_t event_size,
|
||||||
uint8_t *iv,
|
uint8_t *iv,
|
||||||
int action);
|
int action);
|
||||||
|
int blr_aes_create_tail_for_cbc(uint8_t *output,
|
||||||
|
uint8_t *input,
|
||||||
|
uint32_t in_size,
|
||||||
|
uint8_t *iv,
|
||||||
|
uint8_t *key,
|
||||||
|
unsigned int key_len);
|
||||||
|
|
||||||
/** MaxScale generated events */
|
/** MaxScale generated events */
|
||||||
typedef enum
|
typedef enum
|
||||||
@ -2744,62 +2769,103 @@ blr_create_start_encryption_event(ROUTER_INSTANCE *router, uint32_t event_pos, b
|
|||||||
*/
|
*/
|
||||||
GWBUF *blr_aes_crypt(ROUTER_INSTANCE *router, uint8_t *buffer, uint32_t size, uint8_t *iv, int action)
|
GWBUF *blr_aes_crypt(ROUTER_INSTANCE *router, uint8_t *buffer, uint32_t size, uint8_t *iv, int action)
|
||||||
{
|
{
|
||||||
EVP_CIPHER_CTX *ctx;
|
EVP_CIPHER_CTX ctx;
|
||||||
ctx = EVP_CIPHER_CTX_new();
|
uint8_t *key = router->encryption.key_value;
|
||||||
uint8_t key[BINLOG_AES_MAX_KEY_LEN];
|
unsigned int key_len = router->encryption.key_len;
|
||||||
int outlen;
|
int outlen;
|
||||||
int flen;
|
int flen;
|
||||||
uint32_t encrypted_size = size + 4;
|
uint32_t encrypted_size = size + 4;
|
||||||
int total_len;
|
int total_len;
|
||||||
GWBUF *outbuf = gwbuf_alloc(encrypted_size);
|
GWBUF *outbuf;
|
||||||
uint8_t *out_ptr;
|
uint8_t *out_ptr;
|
||||||
|
|
||||||
if (outbuf == NULL)
|
if (key_len == 0)
|
||||||
|
{
|
||||||
|
MXS_ERROR("The encrytion key len is 0");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((outbuf = gwbuf_alloc(encrypted_size)) == NULL)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_ptr = GWBUF_DATA(outbuf);
|
out_ptr = GWBUF_DATA(outbuf);
|
||||||
|
|
||||||
if (router->encryption.key_len == 0)
|
EVP_CIPHER_CTX_init(&ctx);
|
||||||
|
|
||||||
|
/* Set the encryption algorithm accordingly to key_len and encryption mode */
|
||||||
|
if (!EVP_CipherInit_ex(&ctx,
|
||||||
|
ciphers[router->encryption.encryption_algorithm](router->encryption.key_len),
|
||||||
|
NULL,
|
||||||
|
key,
|
||||||
|
iv,
|
||||||
|
action))
|
||||||
{
|
{
|
||||||
MXS_ERROR("The encrytion key len is 0");
|
MXS_ERROR("Error in EVP_CipherInit_ex for algo %d", router->encryption.encryption_algorithm);
|
||||||
|
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||||
|
MXS_FREE(outbuf);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set no padding */
|
||||||
|
EVP_CIPHER_CTX_set_padding(&ctx, 0);
|
||||||
|
|
||||||
|
/* Encryt/Decrypt the input data */
|
||||||
|
if(!EVP_CipherUpdate(&ctx,
|
||||||
|
out_ptr + 4,
|
||||||
|
&outlen,
|
||||||
|
buffer,
|
||||||
|
size))
|
||||||
|
{
|
||||||
|
MXS_ERROR("Error in EVP_CipherUpdate");
|
||||||
|
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||||
|
MXS_FREE(outbuf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int finale_ret = 1;
|
||||||
|
|
||||||
|
/* Enc/dec finish is differently handled for AES_CBC */
|
||||||
|
if (router->encryption.encryption_algorithm != BLR_AES_CBC)
|
||||||
|
{
|
||||||
|
/* Call Final_ex */
|
||||||
|
if (!EVP_CipherFinal_ex(&ctx,
|
||||||
|
(out_ptr + 4 + outlen),
|
||||||
|
(int*)&flen))
|
||||||
|
{
|
||||||
|
MXS_ERROR("Error in EVP_CipherFinal_ex");
|
||||||
|
finale_ret = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memcpy(key, router->encryption.key_value, router->encryption.key_len);
|
/**
|
||||||
|
* If some bytes (ctx.buf_len) are still available in ctx.buf
|
||||||
|
* handle them with ECB and XOR
|
||||||
|
*/
|
||||||
|
if (ctx.buf_len)
|
||||||
|
{
|
||||||
|
if (!blr_aes_create_tail_for_cbc(out_ptr + 4 + outlen,
|
||||||
|
ctx.buf,
|
||||||
|
ctx.buf_len,
|
||||||
|
ctx.oiv,
|
||||||
|
router->encryption.key_value,
|
||||||
|
router->encryption.key_len))
|
||||||
|
{
|
||||||
|
MXS_ERROR("Error in blr_aes_create_tail_for_cbc");
|
||||||
|
finale_ret = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EVP_CIPHER_CTX_init(ctx);
|
if (!finale_ret)
|
||||||
|
|
||||||
/* Set the encryption algorithm accordingly to key_len and encryption mode */
|
|
||||||
EVP_CipherInit_ex(ctx,
|
|
||||||
ciphers[router->encryption.encryption_algorithm](router->encryption.key_len),
|
|
||||||
NULL, key, iv, action);
|
|
||||||
|
|
||||||
/* No padding */
|
|
||||||
EVP_CIPHER_CTX_set_padding(ctx, 0);
|
|
||||||
|
|
||||||
if(!EVP_CipherUpdate(ctx, out_ptr + 4, &outlen, buffer, size))
|
|
||||||
{
|
{
|
||||||
MXS_ERROR("Error in EVP_CipherUpdate");
|
MXS_FREE(outbuf);
|
||||||
EVP_CIPHER_CTX_free(ctx);
|
outbuf = NULL;
|
||||||
MXS_FREE(outbuf);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!EVP_CipherFinal_ex(ctx, (out_ptr + 4 + outlen), (int*)&flen))
|
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||||
{
|
|
||||||
MXS_ERROR("Error in EVP_CipherFinal_ex");
|
|
||||||
EVP_CIPHER_CTX_free(ctx);
|
|
||||||
MXS_FREE(outbuf);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
EVP_CIPHER_CTX_free(ctx);
|
|
||||||
|
|
||||||
return outbuf;
|
return outbuf;
|
||||||
}
|
}
|
||||||
@ -2944,3 +3010,74 @@ const char *blr_encryption_algorithm_list(void)
|
|||||||
return blr_encryption_algorithm_list_names;
|
return blr_encryption_algorithm_list_names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the final buffer for AES_CBC encryption
|
||||||
|
*
|
||||||
|
* As the encrypted/decrypted data must have same size of inpu data
|
||||||
|
* the remaining data from EVP_CipherUpdate with AES_CBC engine
|
||||||
|
* are handled this way:
|
||||||
|
*
|
||||||
|
* 1) The IV in the previous stage is encrypted with AES_ECB
|
||||||
|
* using the key and a NULL iv
|
||||||
|
* 2) the remaing data from previous stage are XORed with thant buffer
|
||||||
|
* and the the ouput buffer contains the result
|
||||||
|
*
|
||||||
|
* @param output The outut buffer to fill
|
||||||
|
* @param input The input buffere 8remaining bytes from previous stage)
|
||||||
|
* @param in_size The inout data size
|
||||||
|
* @param iv The IV used in previous stage
|
||||||
|
* @param key The encryption key
|
||||||
|
* @param key_len The lenght of encrytion key
|
||||||
|
* @return Return 1 on success, 0 otherwise
|
||||||
|
*/
|
||||||
|
int blr_aes_create_tail_for_cbc(uint8_t *output, uint8_t *input, uint32_t in_size, uint8_t *iv, uint8_t *key, unsigned int key_len)
|
||||||
|
{
|
||||||
|
EVP_CIPHER_CTX t_ctx;
|
||||||
|
uint8_t mask[AES_BLOCK_SIZE];
|
||||||
|
int mlen = 0;
|
||||||
|
|
||||||
|
EVP_CIPHER_CTX_init(&t_ctx);
|
||||||
|
|
||||||
|
/* Initialise with AES_ECB and NULL iv */
|
||||||
|
if (!EVP_CipherInit_ex(&t_ctx,
|
||||||
|
ciphers[BLR_AES_ECB](key_len),
|
||||||
|
NULL,
|
||||||
|
key,
|
||||||
|
NULL, /* NULL iv */
|
||||||
|
BINLOG_FLAG_ENCRYPT))
|
||||||
|
{
|
||||||
|
MXS_ERROR("Error in EVP_CipherInit_ex CBC for last block (ECB)");
|
||||||
|
EVP_CIPHER_CTX_cleanup(&t_ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set no padding */
|
||||||
|
EVP_CIPHER_CTX_set_padding(&t_ctx, 0);
|
||||||
|
|
||||||
|
/* Do the enc/dec of the IV (the one from previous stage) */
|
||||||
|
if (!EVP_CipherUpdate(&t_ctx,
|
||||||
|
mask,
|
||||||
|
&mlen,
|
||||||
|
iv,
|
||||||
|
sizeof(mask)))
|
||||||
|
{
|
||||||
|
MXS_ERROR("Error in EVP_CipherUpdate ECB");
|
||||||
|
EVP_CIPHER_CTX_cleanup(&t_ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Now the output buffer contains
|
||||||
|
* the XORed data of input data and the mask (encryption of IV)
|
||||||
|
*
|
||||||
|
* Note: this also works for decryption
|
||||||
|
*/
|
||||||
|
for (int i = 0; i < in_size; i++)
|
||||||
|
{
|
||||||
|
output[i] = input[i] ^ mask[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
EVP_CIPHER_CTX_cleanup(&t_ctx);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user