unify my_{en|de}crypt_{cbc|ecb|ctr}. no yassl support yet.
This commit is contained in:
parent
27cc252bb7
commit
2f8d101f9e
@ -1,3 +1,20 @@
|
||||
/*
|
||||
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 */
|
||||
|
||||
// TODO: Add Windows support
|
||||
|
||||
#ifndef MYSYS_MY_CRYPT_H_
|
||||
@ -12,25 +29,39 @@ 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);
|
||||
uint no_padding);
|
||||
|
||||
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);
|
||||
uint no_padding);
|
||||
|
||||
Crypt_result my_aes_encrypt_cbc(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 no_padding);
|
||||
|
||||
Crypt_result my_aes_decrypt_cbc(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 no_padding);
|
||||
|
||||
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 no_padding);
|
||||
|
||||
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 no_padding);
|
||||
C_MODE_END
|
||||
|
||||
Crypt_result EncryptAes128Ctr(const uchar* key,
|
||||
const uchar* iv, int iv_size,
|
||||
const uchar* plaintext, int plaintext_size,
|
||||
uchar* ciphertext, int* ciphertext_used);
|
||||
|
||||
Crypt_result DecryptAes128Ctr(const uchar* key,
|
||||
const uchar* iv, int iv_size,
|
||||
const uchar* ciphertext, int ciphertext_size,
|
||||
uchar* plaintext, int* plaintext_used);
|
||||
|
||||
#endif /* !defined(HAVE_YASSL) && defined(HAVE_OPENSSL) */
|
||||
|
||||
C_MODE_START
|
||||
|
@ -100,536 +100,6 @@ static int my_aes_create_key(const char *key, int key_length, uint8 *rkey)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Crypt buffer with AES CBC encryption algorithm.
|
||||
|
||||
SYNOPSIS
|
||||
my_aes_encrypt_cbc()
|
||||
@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 dest_length [out] Pointer to size of encrypted data
|
||||
@param key [in] Key to be used for encryption
|
||||
@param key_length [in] Length of the key. 16, 24 or 32
|
||||
@param iv [in] Iv to be used for encryption
|
||||
@param iv_length [in] Length of the iv. should be 16.
|
||||
@param noPadding [in] if set to true, no padding is used. if the input length is not a
|
||||
multiple of the AES block size, trailing bytes are only copied to destination buffer.
|
||||
This allows currently the same interface for CBC, ECB and CTR encryption.
|
||||
@return
|
||||
!= 0 error
|
||||
0 no error
|
||||
*/
|
||||
|
||||
static int my_aes_encrypt_cbc(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)
|
||||
{
|
||||
uint8 remaining_bytes = (noPadding == 0) ? 0 : source_length % MY_AES_BLOCK_SIZE;
|
||||
source_length = source_length - remaining_bytes;
|
||||
|
||||
#ifdef HAVE_YASSL
|
||||
TaoCrypt::AES_CBC_Encryption enc;
|
||||
/* 128 bit block used for padding */
|
||||
uint8 block[MY_AES_BLOCK_SIZE];
|
||||
int num_blocks; /* number of complete blocks */
|
||||
int i;
|
||||
switch(key_length) {
|
||||
case 16:
|
||||
break;
|
||||
case 24:
|
||||
break;
|
||||
case 32:
|
||||
break;
|
||||
default:
|
||||
return AES_BAD_KEYSIZE;
|
||||
}
|
||||
|
||||
enc.SetKey((const TaoCrypt::byte *) key, key_length, (const TaoCrypt::byte *) iv);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (noPadding) {
|
||||
if (remaining_bytes!=0) {
|
||||
/* Note that we moved the original pointers above */
|
||||
memcpy(dest, source, remaining_bytes);
|
||||
}
|
||||
*dest_length = MY_AES_BLOCK_SIZE * (num_blocks) + remaining_bytes;
|
||||
return AES_OK;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
*dest_length = MY_AES_BLOCK_SIZE * (num_blocks + 1);
|
||||
return AES_OK;
|
||||
#elif defined(HAVE_OPENSSL)
|
||||
MyCipherCtx ctx;
|
||||
int u_len, f_len;
|
||||
/* The real key to be used for encryption */
|
||||
const EVP_CIPHER* cipher;
|
||||
switch(key_length) {
|
||||
case 16:
|
||||
cipher = EVP_aes_128_cbc();
|
||||
break;
|
||||
case 24:
|
||||
cipher = EVP_aes_192_cbc();
|
||||
break;
|
||||
case 32:
|
||||
cipher = EVP_aes_256_cbc();
|
||||
break;
|
||||
default:
|
||||
return AES_BAD_KEYSIZE;
|
||||
}
|
||||
//Initialize Encryption Engine here, default software Engine is default
|
||||
ENGINE *engine = NULL;
|
||||
|
||||
if (! EVP_EncryptInit_ex(&ctx.ctx, cipher, engine, key, iv))
|
||||
return AES_BAD_DATA; /* Error */
|
||||
if (noPadding) {
|
||||
EVP_CIPHER_CTX_set_padding(&ctx.ctx, 0);
|
||||
}
|
||||
EVP_CIPHER_CTX_key_length(&ctx.ctx);
|
||||
OPENSSL_assert(EVP_CIPHER_CTX_key_length(&ctx.ctx) == key_length);
|
||||
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(&ctx.ctx) == iv_length);
|
||||
OPENSSL_assert(EVP_CIPHER_CTX_block_size(&ctx.ctx) == 16);
|
||||
if (! EVP_EncryptUpdate(&ctx.ctx, (unsigned char *) dest, &u_len,
|
||||
(unsigned const char *) source, source_length))
|
||||
return AES_BAD_DATA; /* Error */
|
||||
if (! EVP_EncryptFinal_ex(&ctx.ctx, (unsigned char *) dest + u_len, &f_len))
|
||||
return AES_BAD_DATA; /* Error */
|
||||
|
||||
if (remaining_bytes!=0) {
|
||||
memcpy(dest + source_length, source + source_length, remaining_bytes);
|
||||
}
|
||||
*dest_length = (unsigned long int) (u_len + f_len + remaining_bytes);
|
||||
|
||||
return AES_OK;
|
||||
#else
|
||||
/* currently Open SSL is required */
|
||||
return AES_BAD_DATA;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Crypt buffer with AES ECB encryption algorithm.
|
||||
|
||||
SYNOPSIS
|
||||
my_aes_encrypt_ecb()
|
||||
@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 dest_length [out] Pointer to size of encrypted data
|
||||
@param key [in] Key to be used for encryption
|
||||
@param key_length [in] Length of the key. 16, 24 or 32
|
||||
@param iv [in] Iv to be used for encryption
|
||||
@param iv_length [in] Length of the iv. should be 16.
|
||||
@param noPadding [in] if set to true, no padding is used. if the input length is not a
|
||||
multiple of the AES block size, trailing bytes are only copied to destination buffer.
|
||||
This allows currently the same interface for CBC, ECB and CTR encryption.
|
||||
@return
|
||||
!= 0 error
|
||||
0 no error
|
||||
*/
|
||||
|
||||
static int 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)
|
||||
{
|
||||
uint8 remaining_bytes = (noPadding == 0) ? 0 : source_length % MY_AES_BLOCK_SIZE;
|
||||
source_length = source_length - remaining_bytes;
|
||||
|
||||
#ifdef 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;
|
||||
switch(key_length) {
|
||||
case 16:
|
||||
break;
|
||||
case 24:
|
||||
break;
|
||||
case 32:
|
||||
break;
|
||||
default:
|
||||
return AES_BAD_KEYSIZE;
|
||||
}
|
||||
|
||||
enc.SetKey((const TaoCrypt::byte *) key, key_length, (const TaoCrypt::byte *) iv);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (noPadding) {
|
||||
if (remaining_bytes!=0) {
|
||||
/* Note that we moved the original pointers above */
|
||||
memcpy(dest, source, remaining_bytes);
|
||||
}
|
||||
*dest_length = MY_AES_BLOCK_SIZE * (num_blocks) + remaining_bytes;
|
||||
return AES_OK;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
*dest_length = MY_AES_BLOCK_SIZE * (num_blocks + 1);
|
||||
return AES_OK;
|
||||
#elif defined(HAVE_OPENSSL)
|
||||
MyCipherCtx ctx;
|
||||
int u_len, f_len;
|
||||
/* The real key to be used for encryption */
|
||||
const EVP_CIPHER* cipher;
|
||||
switch(key_length) {
|
||||
case 16:
|
||||
cipher = EVP_aes_128_ecb();
|
||||
break;
|
||||
case 24:
|
||||
cipher = EVP_aes_192_ecb();
|
||||
break;
|
||||
case 32:
|
||||
cipher = EVP_aes_256_ecb();
|
||||
break;
|
||||
default:
|
||||
return AES_BAD_KEYSIZE;
|
||||
}
|
||||
//Initialize Encryption Engine here, default software Engine is default
|
||||
ENGINE *engine = NULL;
|
||||
|
||||
if (! EVP_EncryptInit_ex(&ctx.ctx, cipher, engine, key, iv))
|
||||
return AES_BAD_DATA; /* Error */
|
||||
if (noPadding) {
|
||||
EVP_CIPHER_CTX_set_padding(&ctx.ctx, 0);
|
||||
}
|
||||
EVP_CIPHER_CTX_key_length(&ctx.ctx);
|
||||
OPENSSL_assert(EVP_CIPHER_CTX_key_length(&ctx.ctx) == key_length);
|
||||
// ECB does not use IV
|
||||
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(&ctx.ctx) == 0);
|
||||
OPENSSL_assert(EVP_CIPHER_CTX_block_size(&ctx.ctx) == 16);
|
||||
if (! EVP_EncryptUpdate(&ctx.ctx, (unsigned char *) dest, &u_len,
|
||||
(unsigned const char *) source, source_length))
|
||||
return AES_BAD_DATA; /* Error */
|
||||
if (! EVP_EncryptFinal_ex(&ctx.ctx, (unsigned char *) dest + u_len, &f_len))
|
||||
return AES_BAD_DATA; /* Error */
|
||||
|
||||
if (remaining_bytes!=0)
|
||||
memcpy(dest + source_length, source + source_length, remaining_bytes);
|
||||
|
||||
*dest_length = (unsigned long int) (u_len + f_len + remaining_bytes);
|
||||
|
||||
return AES_OK;
|
||||
#else
|
||||
/* currently Open SSL is required */
|
||||
return AES_BAD_DATA;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
AES decryption - CBC mode
|
||||
|
||||
SYNOPSIS
|
||||
my_aes_decrypt_cbc()
|
||||
@param source [in] Pointer to data to decrypt
|
||||
@param source_length [in] Size of data
|
||||
@param dest [out] Buffer to place decrypted data (must be large enough)
|
||||
@param dest_length [out] Pointer to size of decrypted data
|
||||
@param key [in] Key to be used for decryption
|
||||
@param key_length [in] Length of the key. 16, 24 or 32
|
||||
@param iv [in] Iv to be used for encryption
|
||||
@param iv_length [in] Length of the iv. should be 16.
|
||||
@param noPadding [in] if set to true, no padding is used. if the input length is not a
|
||||
multiple of the AES block size, trailing bytes are only copied to destination buffer.
|
||||
This allows currently the same interface for CBC, ECB and CTR encryption.
|
||||
|
||||
@return
|
||||
!= 0 error
|
||||
0 no error
|
||||
*/
|
||||
|
||||
static int my_aes_decrypt_cbc(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)
|
||||
{
|
||||
uint8 remaining_bytes = (noPadding == 0) ? 0 : source_length % MY_AES_BLOCK_SIZE;
|
||||
source_length = source_length - remaining_bytes;
|
||||
|
||||
|
||||
#ifdef HAVE_YASSL
|
||||
TaoCrypt::AES_CBC_Decryption dec;
|
||||
/* 128 bit block used for padding */
|
||||
uint8 block[MY_AES_BLOCK_SIZE];
|
||||
uint num_blocks; /* Number of complete blocks */
|
||||
int i;
|
||||
switch(key_length) {
|
||||
case 16:
|
||||
break;
|
||||
case 24:
|
||||
break;
|
||||
case 32:
|
||||
break;
|
||||
default:
|
||||
return AES_BAD_KEYSIZE;
|
||||
}
|
||||
|
||||
dec.SetKey((const TaoCrypt::byte *) key, key_length, iv);
|
||||
|
||||
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);
|
||||
|
||||
if (noPadding) {
|
||||
memcpy(dest, block, MY_AES_BLOCK_SIZE);
|
||||
if (remaining_bytes!=0) {
|
||||
/* Note that we have moved dest and source */
|
||||
memcpy(dest + MY_AES_BLOCK_SIZE, source + MY_AES_BLOCK_SIZE, remaining_bytes);
|
||||
}
|
||||
*dest_length = MY_AES_BLOCK_SIZE * num_blocks + remaining_bytes;
|
||||
return AES_OK;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
*dest_length = MY_AES_BLOCK_SIZE * num_blocks - pad_len;
|
||||
return AES_OK;
|
||||
#elif defined(HAVE_OPENSSL)
|
||||
MyCipherCtx ctx;
|
||||
int u_len, f_len;
|
||||
|
||||
const EVP_CIPHER* cipher;
|
||||
switch(key_length) {
|
||||
case 16:
|
||||
cipher = EVP_aes_128_cbc();
|
||||
break;
|
||||
case 24:
|
||||
cipher = EVP_aes_192_cbc();
|
||||
break;
|
||||
case 32:
|
||||
cipher = EVP_aes_256_cbc();
|
||||
break;
|
||||
default:
|
||||
return AES_BAD_KEYSIZE;
|
||||
}
|
||||
//Initialize Encryption Engine here, default software Engine is default
|
||||
ENGINE *engine = NULL;
|
||||
|
||||
if (! EVP_DecryptInit_ex(&ctx.ctx, cipher, engine, key, iv))
|
||||
return AES_BAD_DATA; /* Error */
|
||||
if (noPadding) {
|
||||
EVP_CIPHER_CTX_set_padding(&ctx.ctx, 0);
|
||||
}
|
||||
OPENSSL_assert(EVP_CIPHER_CTX_key_length(&ctx.ctx) == key_length);
|
||||
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(&ctx.ctx) == iv_length);
|
||||
OPENSSL_assert(EVP_CIPHER_CTX_block_size(&ctx.ctx) == 16);
|
||||
if (! EVP_DecryptUpdate(&ctx.ctx, (unsigned char *) dest, &u_len,
|
||||
(unsigned char *)source, source_length))
|
||||
return AES_BAD_DATA; /* Error */
|
||||
if (! EVP_DecryptFinal_ex(&ctx.ctx, (unsigned char *) dest + u_len, &f_len)) {
|
||||
*dest_length = (unsigned long int) u_len;
|
||||
return AES_BAD_DATA;
|
||||
}
|
||||
if (remaining_bytes!=0) {
|
||||
memcpy(dest + source_length, source + source_length, remaining_bytes);
|
||||
}
|
||||
*dest_length = (unsigned long int) (u_len + f_len) + remaining_bytes;
|
||||
#endif
|
||||
return AES_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
AES decryption - ECB mode
|
||||
|
||||
SYNOPSIS
|
||||
my_aes_decrypt_ecb()
|
||||
@param source [in] Pointer to data to decrypt
|
||||
@param source_length [in] Size of data
|
||||
@param dest [out] Buffer to place decrypted data (must be large enough)
|
||||
@param dest_length [out] Pointer to size of decrypted data
|
||||
@param key [in] Key to be used for decryption
|
||||
@param key_length [in] Length of the key. 16, 24 or 32
|
||||
@param iv [in] Iv to be used for encryption
|
||||
@param iv_length [in] Length of the iv. should be 16.
|
||||
@param noPadding [in] if set to true, no padding is used. if the input length is not a
|
||||
multiple of the AES block size, trailing bytes are only copied to destination buffer.
|
||||
This allows currently the same interface for CBC, ECB and CTR encryption.
|
||||
|
||||
@return
|
||||
!= 0 error
|
||||
0 no error
|
||||
*/
|
||||
|
||||
static int 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)
|
||||
{
|
||||
uint8 remaining_bytes = (noPadding == 0) ? 0 : source_length % MY_AES_BLOCK_SIZE;
|
||||
source_length = source_length - remaining_bytes;
|
||||
|
||||
|
||||
#ifdef HAVE_YASSL
|
||||
TaoCrypt::AES_ECB_Decryption dec;
|
||||
/* 128 bit block used for padding */
|
||||
uint8 block[MY_AES_BLOCK_SIZE];
|
||||
uint num_blocks; /* Number of complete blocks */
|
||||
int i;
|
||||
switch(key_length) {
|
||||
case 16:
|
||||
break;
|
||||
case 24:
|
||||
break;
|
||||
case 32:
|
||||
break;
|
||||
default:
|
||||
return AES_BAD_KEYSIZE;
|
||||
}
|
||||
|
||||
dec.SetKey((const TaoCrypt::byte *) key, key_length, iv);
|
||||
|
||||
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);
|
||||
|
||||
if (noPadding) {
|
||||
memcpy(dest, block, MY_AES_BLOCK_SIZE);
|
||||
if (remaining_bytes!=0) {
|
||||
/* Note that we have moved dest and source */
|
||||
memcpy(dest + MY_AES_BLOCK_SIZE, source + MY_AES_BLOCK_SIZE, remaining_bytes);
|
||||
}
|
||||
*dest_length = MY_AES_BLOCK_SIZE * num_blocks + remaining_bytes;
|
||||
return AES_OK;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
*dest_length = MY_AES_BLOCK_SIZE * num_blocks - pad_len;
|
||||
return AES_OK;
|
||||
#elif defined(HAVE_OPENSSL)
|
||||
MyCipherCtx ctx;
|
||||
int u_len, f_len;
|
||||
|
||||
const EVP_CIPHER* cipher;
|
||||
switch(key_length) {
|
||||
case 16:
|
||||
cipher = EVP_aes_128_ecb();
|
||||
break;
|
||||
case 24:
|
||||
cipher = EVP_aes_192_ecb();
|
||||
break;
|
||||
case 32:
|
||||
cipher = EVP_aes_256_ecb();
|
||||
break;
|
||||
default:
|
||||
return AES_BAD_KEYSIZE;
|
||||
}
|
||||
//Initialize Encryption Engine here, default software Engine is default
|
||||
ENGINE *engine = NULL;
|
||||
|
||||
if (! EVP_DecryptInit_ex(&ctx.ctx, cipher, engine, key, iv))
|
||||
return AES_BAD_DATA; /* Error */
|
||||
if (noPadding) {
|
||||
EVP_CIPHER_CTX_set_padding(&ctx.ctx, 0);
|
||||
}
|
||||
OPENSSL_assert(EVP_CIPHER_CTX_key_length(&ctx.ctx) == key_length);
|
||||
// ECB does not use IV
|
||||
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(&ctx.ctx) == 0);
|
||||
OPENSSL_assert(EVP_CIPHER_CTX_block_size(&ctx.ctx) == 16);
|
||||
if (! EVP_DecryptUpdate(&ctx.ctx, (unsigned char *) dest, &u_len,
|
||||
(unsigned char *)source, source_length))
|
||||
return AES_BAD_DATA; /* Error */
|
||||
if (! EVP_DecryptFinal_ex(&ctx.ctx, (unsigned char *) dest + u_len, &f_len)) {
|
||||
*dest_length = (unsigned long int) u_len;
|
||||
return AES_BAD_DATA;
|
||||
}
|
||||
if (remaining_bytes!=0) {
|
||||
memcpy(dest + source_length, source + source_length, remaining_bytes);
|
||||
}
|
||||
*dest_length = (unsigned long int) (u_len + f_len) + remaining_bytes;
|
||||
|
||||
#endif
|
||||
return AES_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Encryption interface that doesn't do anything (for testing)
|
||||
|
||||
|
@ -1,3 +1,20 @@
|
||||
/*
|
||||
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 */
|
||||
|
||||
/*
|
||||
TODO: add support for YASSL
|
||||
*/
|
||||
@ -5,10 +22,8 @@
|
||||
#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>
|
||||
|
||||
@ -17,67 +32,119 @@ static const int CRYPT_DECRYPT = 0;
|
||||
|
||||
C_MODE_START
|
||||
|
||||
static int do_crypt(const EVP_CIPHER *cipher, int mode,
|
||||
static int do_crypt(const EVP_CIPHER *cipher, int encrypt,
|
||||
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)
|
||||
const uchar* key, uint8 key_length,
|
||||
const uchar* iv, uint8 iv_length, int no_padding)
|
||||
{
|
||||
int res= AES_OPENSSL_ERROR;
|
||||
int res= AES_OPENSSL_ERROR, fin;
|
||||
int tail= no_padding ? source_length % MY_AES_BLOCK_SIZE : 0;
|
||||
|
||||
EVP_CIPHER_CTX ctx;
|
||||
EVP_CIPHER_CTX_init(&ctx);
|
||||
if (!EVP_CipherInit_ex(&ctx, cipher, NULL, key, iv, mode))
|
||||
if (!EVP_CipherInit_ex(&ctx, cipher, NULL, key, iv, encrypt))
|
||||
goto err;
|
||||
if (!EVP_CipherUpdate(&ctx, dest, (int*)dest_length, source, source_length))
|
||||
|
||||
EVP_CIPHER_CTX_set_padding(&ctx, !no_padding);
|
||||
|
||||
DBUG_ASSERT(EVP_CIPHER_CTX_key_length(&ctx) == key_length);
|
||||
DBUG_ASSERT(EVP_CIPHER_CTX_iv_length(&ctx) == iv_length || !EVP_CIPHER_CTX_iv_length(&ctx));
|
||||
DBUG_ASSERT(EVP_CIPHER_CTX_block_size(&ctx) == MY_AES_BLOCK_SIZE || !no_padding);
|
||||
|
||||
if (!EVP_CipherUpdate(&ctx, dest, (int*)dest_length, source, source_length - tail))
|
||||
goto err;
|
||||
if (!EVP_CipherFinal_ex(&ctx, dest + *dest_length, &fin))
|
||||
goto err;
|
||||
*dest_length += fin;
|
||||
|
||||
if (tail)
|
||||
{
|
||||
/*
|
||||
Not much we can do here, block cyphers cannot encrypt data that aren't
|
||||
a multiple of the block length. At least not without padding.
|
||||
What we do here, we XOR the tail with the previous encrypted block.
|
||||
*/
|
||||
|
||||
DBUG_ASSERT(source_length - tail == *dest_length);
|
||||
DBUG_ASSERT(source_length - tail > MY_AES_BLOCK_SIZE);
|
||||
const uchar *s= source + source_length - tail;
|
||||
const uchar *e= source + source_length;
|
||||
uchar *d= dest + source_length - tail;
|
||||
const uchar *m= (encrypt ? d : s) - MY_AES_BLOCK_SIZE;
|
||||
while (s < e)
|
||||
*d++ = *s++ ^ *m++;
|
||||
*dest_length= source_length;
|
||||
}
|
||||
|
||||
res= AES_OK;
|
||||
err:
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* CTR is a stream cypher mode, it needs no special padding code */
|
||||
|
||||
int 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)
|
||||
uchar* dest, uint32* dest_length,
|
||||
const uchar* key, uint8 key_length,
|
||||
const uchar* iv, uint8 iv_length,
|
||||
uint no_padding)
|
||||
{
|
||||
return do_crypt(EVP_aes_128_ctr(), CRYPT_ENCRYPT, source, source_length,
|
||||
dest, dest_length, key, key_length, iv, iv_length, noPadding);
|
||||
dest, dest_length, key, key_length, iv, iv_length, 0);
|
||||
}
|
||||
|
||||
|
||||
int 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)
|
||||
uchar* dest, uint32* dest_length,
|
||||
const uchar* key, uint8 key_length,
|
||||
const uchar* iv, uint8 iv_length,
|
||||
uint no_padding)
|
||||
{
|
||||
return do_crypt(EVP_aes_128_ctr(), CRYPT_DECRYPT, source, source_length,
|
||||
dest, dest_length, key, key_length, iv, iv_length, noPadding);
|
||||
dest, dest_length, key, key_length, iv, iv_length, 0);
|
||||
}
|
||||
|
||||
|
||||
int 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)
|
||||
uchar* dest, uint32* dest_length,
|
||||
const uchar* key, uint8 key_length,
|
||||
const uchar* iv, uint8 iv_length,
|
||||
uint no_padding)
|
||||
{
|
||||
return do_crypt(EVP_aes_128_ecb(), CRYPT_ENCRYPT, source, source_length,
|
||||
dest, dest_length, key, key_length, iv, iv_length, noPadding);
|
||||
dest, dest_length, key, key_length, iv, iv_length, no_padding);
|
||||
}
|
||||
|
||||
int 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)
|
||||
uchar* dest, uint32* dest_length,
|
||||
const uchar* key, uint8 key_length,
|
||||
const uchar* iv, uint8 iv_length,
|
||||
uint no_padding)
|
||||
{
|
||||
return do_crypt(EVP_aes_128_ecb(), CRYPT_DECRYPT, source, source_length,
|
||||
dest, dest_length, key, key_length, iv, iv_length, noPadding);
|
||||
dest, dest_length, key, key_length, iv, iv_length, no_padding);
|
||||
}
|
||||
|
||||
int my_aes_encrypt_cbc(const uchar* source, uint32 source_length,
|
||||
uchar* dest, uint32* dest_length,
|
||||
const uchar* key, uint8 key_length,
|
||||
const uchar* iv, uint8 iv_length,
|
||||
uint no_padding)
|
||||
{
|
||||
return do_crypt(EVP_aes_128_cbc(), CRYPT_ENCRYPT, source, source_length,
|
||||
dest, dest_length, key, key_length, iv, iv_length, no_padding);
|
||||
}
|
||||
|
||||
int my_aes_decrypt_cbc(const uchar* source, uint32 source_length,
|
||||
uchar* dest, uint32* dest_length,
|
||||
const uchar* key, uint8 key_length,
|
||||
const uchar* iv, uint8 iv_length,
|
||||
uint no_padding)
|
||||
{
|
||||
return do_crypt(EVP_aes_128_cbc(), CRYPT_DECRYPT, source, source_length,
|
||||
dest, dest_length, key, key_length, iv, iv_length, no_padding);
|
||||
}
|
||||
|
||||
C_MODE_END
|
||||
|
@ -212,6 +212,7 @@ fil_crypt_get_key(byte *dst, uint* key_length,
|
||||
mutex_enter(&crypt_data->mutex);
|
||||
|
||||
if (!page_encrypted) {
|
||||
*key_length = get_encryption_key_size(version);
|
||||
// Check if we already have key
|
||||
for (uint i = 0; i < crypt_data->key_count; i++) {
|
||||
if (crypt_data->keys[i].key_version == version) {
|
||||
|
@ -212,6 +212,7 @@ fil_crypt_get_key(byte *dst, uint* key_length,
|
||||
mutex_enter(&crypt_data->mutex);
|
||||
|
||||
if (!page_encrypted) {
|
||||
*key_length = get_encryption_key_size(version);
|
||||
// Check if we already have key
|
||||
for (uint i = 0; i < crypt_data->key_count; i++) {
|
||||
if (crypt_data->keys[i].key_version == version) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user