MySQL new features-mysql_config_editor encryption algorithm and Decryption Implementation
Mysql_config_editor adopts aes ecb encryption. The ECB encryption of AES is usually block encryption. to encrypt data that exceeds the block size, the padding and link encryption modes are required. The ECB mentioned in this Article refers to the link encryption mode. This article mainly introduces the use and implementation of the encryption technology in this tool, and does not detail the algorithm and implementation details of this secret technology.
In the previous article (SEE), the encryption process is as follows:
Encrypt_and_write_file-> encrypt_buffer-> my_aes_encrypt
The specific implementation of my_aes_encrypt is as follows:
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;
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 ))
Return AES_BAD_DATA;/* Error */
If (! EVP_EncryptUpdate (& ctx. ctx, (unsigned char *) dest, & u_len,
(Unsigned const char *) source, source_length ))
Return AES_BAD_DATA;/* Error */
If (! EVP_EncryptFinal (& ctx. ctx, (unsigned char *) dest + u_len, & f_len ))
Return AES_BAD_DATA;/* Error */
Return u_len + f_len;
# Endif
}
The above program is the confidential process for mysql to use AES. In encryption, if mysql defines the built-in AES encryption algorithm, it uses the built-in (# define HAVE_YASSL). Otherwise, it uses the openssl evp framework encryption algorithm.
Here we will introduce the steps of the openssl evp encryption algorithm:
Click (here) to fold or open
Int EVP_EncryptInit_ex (EVP_CIPHER_CTX * ctx, const EVP_CIPHER * cipher, ENGINE * impl, const unsigned char * key, const unsigned char * iv)
EVP_EncryptInit (initialization)
|
|
V
EVP_EncryptUpdate (& ctx, out + len, & outl, in, inl );
EVP_EncryptUpdate (the implementation of this EVP_EncryptUpdate is to encrypt the plaintext according to the length of 16 bytes, so that the block size of the cipher is obtained (16 bytes for aes_128) and encrypt the integer multiple of block-size. If the input is 50 bytes, only 48 bytes are encrypted, and outl is 48 bytes. The last two bytes in the input in are copied to ctx-> buf for caching.
If the value of inl is an integer multiple of block_size, and ctx-> buf does not have the data left behind, encryption and decryption are performed directly, saving a lot of subsequent work)
|
|
V
EVP_EncryptFinal_ex (& ctx, out + len, & outl );
As described in this example, the first time except for the remaining 48 bytes, the second time processing the remaining 2 bytes and 46 bytes for the first time, and the remaining 4 bytes in the input 100 bytes. Process it here. If pading is not supported and there is still data, an error occurs. Otherwise, set block_size-several bytes to the value of this number, for example, block_size = 16, and the data length is 4, set the next 12 bytes to 16-4 = 12 and add them to a group for encryption. If the input data is 16 bytes before the Final is called, the ciphertext is not needed if the input data is 16 bytes, it is also useless to call this Final.
As we know, in the encrypted file, the KEY is stored in the file header offset 4 bytes, and the subsequent 20 bytes stores the key information. Therefore, we only need to read the key, and then call the decryption program for a row of information after the key. The specific implementation is as follows:
Algo_aes_ecb.h
# Ifndef ALGO_AES_H
# Define ALGO_AES_H
Int encrypt (unsigned char * plaintext, int plaintext_len, unsigned char * key, unsigned char * ciphertext );
Int decrypt (unsigned char * ciphertext, int ciphertext_len, unsigned char * key, unsigned char * plaintext );
# Endif
Algo_aes_ecb.c
Click (here) to fold or open
# Include <stdlib. h>
# Include <stdio. h>
# Include <string. h>
# Include "algo_aes_ecb.h"
# Include <openssl/evp. h>
# Include <openssl/aes. h>
Typedef unsigned char uint8;
# Define AES_KEY_LENGTH 128
Uint8 rkey [AES_KEY_LENGTH/8];
Void handleErrors (void)
{
ERR_print_errors_fp (stderr );
Abort ();
}
Static int my_aes_create_key (const char * key, int key_length, uint8 * rkey)
{
Uint8 * rkey_end = rkey + AES_KEY_LENGTH/8;
Uint8 * ptr;
Const char * sptr;
Const char * key_end = key + key_length;
Memset (rkey, 0, AES_KEY_LENGTH/8 );
For (ptr = rkey, sptr = key; sptr <key_end; ptr ++, sptr ++)
{
If (ptr = rkey_end)
Ptr = rkey;
* Ptr ^ = (uint8) * sptr;
}
}
Int encrypt (unsigned char * plaintext, int plaintext_len, unsigned char * key, unsigned char * ciphertext)
{
EVP_CIPHER_CTX * ctx;
Int len;
Int ciphertext_len;
My_aes_create_key (key, 20, rkey );
/* Create and initialise the context */
If (! (Ctx = EVP_CIPHER_CTX_new () handleErrors ();
/* Initialise the encryption operation. IMPORTANT-ensure you use a key
* And IV size appropriate for your cipher
* In this example we are using 128 bit AES (I. e. a 128 bit key ).
*/
If (1! = EVP_EncryptInit (ctx, EVP_aes_128_ecb (), (const unsigned char *) rkey, NULL ))
HandleErrors ();
/* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*
*/
If (1! = EVP_EncryptUpdate (ctx, ciphertext, & len, (unsigned const char *) plaintext, plaintext_len ))
HandleErrors ();
Ciphertext_len = len;
/* Finalise the encryption. Further ciphertext bytes may be written
* ** This stage.
***/
If (1! = EVP_EncryptFinal (ctx, ciphertext + len, & len) handleErrors ();
Ciphertext_len + = len;
/* Clean up */
EVP_CIPHER_CTX_free (ctx );
Return ciphertext_len;
}
Int decrypt (unsigned char * ciphertext, int ciphertext_len, unsigned char * key, unsigned char * plaintext)
{
EVP_CIPHER_CTX * ctx;
Int len;
Int plaintext_len;
My_aes_create_key (key, 20, rkey );
/* Create and initialise the context */
If (! (Ctx = EVP_CIPHER_CTX_new () handleErrors ();
/* Initialise the decryption operation. IMPORTANT-ensure you use a key
* Size appropriate for your cipher
* In this example we are using 128 bit AES (I. e. a 128 bit key).
*/
If (1! = EVP_DecryptInit (ctx, EVP_aes_128_ecb (), rkey, NULL ))
HandleErrors ();
/* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*
*/
If (1! = EVP_DecryptUpdate (ctx, plaintext, & len, ciphertext, ciphertext_len ))
HandleErrors ();
Plaintext_len = len;
/* Finalise the decryption. Further plaintext bytes may be written
* ** This stage.
***/
If (1! = EVP_DecryptFinal (ctx, plaintext + len, & len) handleErrors ();
Plaintext_len + = len;
/* Clean up */
EVP_CIPHER_CTX_free (ctx );
Return plaintext_len;
}
For more details, please continue to read the highlights on the next page: