mariadb/mysys/my_aes.c
monty@hundin.mysql.fi 0d8e13979d Made keyread (key scanning) a key specific attribute.
This avoids using fulltext keys for table scanning.
This also reverts Sinisa's original fix for this problem.
2002-06-19 00:22:30 +03:00

199 lines
5.7 KiB
C

/* Copyright (C) 2002 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
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; either version 2 of the License, or
(at your option) any later version.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Implementation of AES Encryption for MySQL
Initial version by Peter Zaitsev June 2002
*/
#include <my_global.h>
#include <m_string.h>
#include "my_aes.h"
enum encrypt_dir { AES_ENCRYPT, AES_DECRYPT };
#define AES_BLOCK_SIZE 16 /* Block size in bytes */
#define AES_BAD_DATA -1 /* If bad data discovered during decoding */
/* The structure for key information */
typedef struct {
int nr; /* Number of rounds */
uint32 rk[4*(AES_MAXNR + 1)]; /* key schedule */
} KEYINSTANCE;
/*
This is internal function just keeps joint code of Key generation
SYNOPSIS
my_aes_create_key()
aes_key Address of Key Instance to be created
direction Direction (are we encoding or decoding)
key Key to use for real key creation
key_length Length of the key
DESCRIPTION
RESULT
0 ok
-1 Error Note: The current impementation never returns this
*/
static int my_aes_create_key(KEYINSTANCE *aes_key,
enum encrypt_dir direction, const char *key,
int key_length)
{
char rkey[AES_KEY_LENGTH/8]; /* The real key to be used for encryption */
char *rkey_end=rkey+AES_KEY_LENGTH/8; /* Real key boundary */
char *ptr; /* Start of the real key*/
const char *sptr; /* Start of the working key */
const char *key_end=key+key_length; /* Working key boundary*/
bzero(rkey,AES_KEY_LENGTH/8); /* Set initial key */
for (ptr= rkey, sptr= key; sptr < key_end; ptr++,sptr++)
{
if (ptr == rkey_end)
ptr= rkey; /* Just loop over tmp_key until we used all key */
*ptr^= *sptr;
}
if (direction == AES_DECRYPT)
aes_key->nr = rijndaelKeySetupDec(aes_key->rk, rkey, AES_KEY_LENGTH);
else
aes_key->nr = rijndaelKeySetupEnc(aes_key->rk, rkey, AES_KEY_LENGTH);
return 0;
}
/*
Crypt buffer with AES encryption algorithm.
SYNOPSIS
my_aes_encrypt()
source Pointer to data for encryption
source_length Size of encryption data
dest Buffer to place encrypted data (must be large enough)
key Key to be used for encryption
key_length Length of the key. Will handle keys of any length
RETURN
>= 0 Size of encrypted data
< 0 Error
*/
int my_aes_encrypt(const char* source, int source_length, char* dest,
const char* key, int key_length)
{
KEYINSTANCE aes_key;
char block[AES_BLOCK_SIZE]; /* 128 bit block used for padding */
int rc; /* result codes */
int num_blocks; /* number of complete blocks */
char pad_len; /* pad size for the last block */
int i;
if ((rc= my_aes_create_key(&aes_key,AES_ENCRYPT,key,key_length)))
return rc;
num_blocks = source_length/AES_BLOCK_SIZE;
for (i = num_blocks; i > 0; i--) /* Encode complete blocks */
{
rijndaelEncrypt(aes_key.rk, aes_key.nr, source, dest);
source+= AES_BLOCK_SIZE;
dest+= AES_BLOCK_SIZE;
}
/* Encode the rest. We always have incomplete block */
pad_len = AES_BLOCK_SIZE - (source_length - AES_BLOCK_SIZE*num_blocks);
memcpy(block, source, 16 - pad_len);
bfill(block + AES_BLOCK_SIZE - pad_len, pad_len, pad_len);
rijndaelEncrypt(aes_key.rk, aes_key.nr, block, dest);
return AES_BLOCK_SIZE*(num_blocks + 1);
}
/*
DeCrypt buffer with AES encryption algorithm.
SYNOPSIS
my_aes_decrypt()
source Pointer to data for decryption
source_length Size of encrypted data
dest Buffer to place decrypted data (must be large enough)
key Key to be used for decryption
key_length Length of the key. Will handle keys of any length
RETURN
>= 0 Size of encrypted data
< 0 Error
*/
int my_aes_decrypt(const char *source, int source_length, char *dest,
const char *key, int key_length)
{
KEYINSTANCE aes_key;
char block[AES_BLOCK_SIZE]; /* 128 bit block used for padding */
int rc; /* Result codes */
int num_blocks; /* Number of complete blocks */
char pad_len; /* Pad size for the last block */
int i;
if ((rc=my_aes_create_key(&aes_key,AES_DECRYPT,key,key_length)))
return rc;
num_blocks = source_length/AES_BLOCK_SIZE;
if ((source_length != num_blocks*AES_BLOCK_SIZE) || num_blocks ==0 )
return AES_BAD_DATA; /* Input size has to be even and at least one block */
for (i = num_blocks-1; i > 0; i--) /* Decode all but last blocks */
{
rijndaelDecrypt(aes_key.rk, aes_key.nr, source, dest);
source+= AES_BLOCK_SIZE;
dest+= AES_BLOCK_SIZE;
}
rijndaelDecrypt(aes_key.rk, aes_key.nr, source, block);
pad_len = block[AES_BLOCK_SIZE-1]; /* Use last char in the block as size */
if (pad_len > AES_BLOCK_SIZE)
return AES_BAD_DATA;
/* We could also check whole padding but we do not really need this */
memcpy(dest, block, AES_BLOCK_SIZE - pad_len);
return AES_BLOCK_SIZE*num_blocks - pad_len;
}
/*
Get size of buffer which will be large enough for encrypted data
SYNOPSIS
my_aes_get_size()
source_length Length of data to be encrypted
RETURN
Size of buffer required to store encrypted data
*/
int my_aes_get_size(int source_length)
{
return AES_BLOCK_SIZE*(source_length/AES_BLOCK_SIZE)+AES_BLOCK_SIZE;
}