editor 加密算法与解密实现

MySQL_config_editor采用的AES ECB加密。关于AES 的ECB加密通常都是块加密,如果要加密超过块大小的数据,就需要涉及填充和链加密模式,文中提到的ECB就是指链加密模式。这篇文章主要介绍在该工具中该加密技术的使用与实现,并未详细介绍该机密技术的算法与实现细节。

editor 加密算法与解密实现

在前一篇文章中(见 ),加密的过程如下:
encrypt_and_write_file->encrypt_buffer->my_aes_encrypt
 
my_aes_encrypt的具体实现如下:

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 ctx;
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
}

上述程序就是mysql的使用AES的机密过程。在加密中,如果mysql定义了自带的AES加密算法,就使用自带的(#define HAVE_YASSL).否则就是用OPENSSL EVP框架的加密算法。
 
这里介绍OPENSSL EVP加密算法的步骤:
点击(此处)折叠或打开

int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv)

EVP_EncryptInit (初始化)
              |
              |
              V
 EVP_EncryptUpdate(&ctx,out+len,&outl,in,inl);
 EVP_EncryptUpdate(这个EVP_EncryptUpdate的实现实际就是将明文按照16 bytes的长度去加密,实现会取得该cipher的块大小(对aes_128来说是16字节)并将block-size的整数倍去加密。如果输入为50字节,则此处仅加密48字节,outl也为48字节。输入in中的最后两字节拷贝到ctx->buf缓存起来。
对于inl为block_size整数倍的情形,且ctx->buf并没有以前遗留的数据时则直接加解密操作,省去很多后续工作)
              |
              |
              V
  EVP_EncryptFinal_ex(&ctx,out+len,&outl);
  对于如本例所述,第一次除了了48字节余两字节,第二次处理了第一次余下的2字节及46字节,余下了输入100字节中的最后4字节。此处进行处理。如果不支持pading,且还有数据的话就出错,否则,将block_size-待处理字节数个数个字节设置为此个数的值,如block_size=16,数据长度为4,则将后面的12字节设置为16-4=12,补齐为一个分组后加密。对于前面为整分组时,如输入数据为16字节,最后再调用此Final时,不过是对16个0进行加密,此密文不用即可,也根本用不着调一下这Final。
由于我们知道了,在加密后的文件中,KEY是存放在文件头部 offset 4bytes的地方,之后的20bytes 存放的都是key的信息 。所以我们只要读取该key,然后对该key之后的信息一行一行的用该key 调用解密程序就好了。具体的实现如下:
 
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


点击(此处)折叠或打开

#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();
}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/af38511fbd3861c7b2949f0696b68e1e.html