mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
228 lines
6.8 KiB
C
228 lines
6.8 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)
|
|
{
|
|
uint8 rkey[AES_KEY_LENGTH/8]; /* The real key to be used for encryption */
|
|
uint8 *rkey_end=rkey+AES_KEY_LENGTH/8; /* Real key boundary */
|
|
uint8 *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((char*) 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^= (uint8) *sptr;
|
|
}
|
|
#ifdef AES_USE_KEY_BITS
|
|
/*
|
|
This block is intended to allow more weak encryption if application
|
|
build with libmysqld needs to correspond to export regulations
|
|
It should be never used in normal distribution as does not give
|
|
any speed improvement.
|
|
To get worse security define AES_USE_KEY_BITS to number of bits
|
|
you want key to be. It should be divisible by 8
|
|
|
|
WARNING: Changing this value results in changing of enryption for
|
|
all key lengths so altering this value will result in impossibility
|
|
to decrypt data encrypted with previous value
|
|
*/
|
|
#define AES_USE_KEY_BYTES (AES_USE_KEY_BITS/8)
|
|
/*
|
|
To get weaker key we use first AES_USE_KEY_BYTES bytes of created key
|
|
and cyclically copy them until we created all required key length
|
|
*/
|
|
for (ptr= rkey+AES_USE_KEY_BYTES, sptr=rkey ; ptr < rkey_end;
|
|
ptr++,sptr++)
|
|
{
|
|
if (sptr == rkey+AES_USE_KEY_BYTES)
|
|
sptr=rkey;
|
|
*ptr=*sptr;
|
|
}
|
|
#endif
|
|
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;
|
|
uint8 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, (const uint8*) source,
|
|
(uint8*) 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, (uint8*) 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;
|
|
uint8 block[AES_BLOCK_SIZE]; /* 128 bit block used for padding */
|
|
int rc; /* Result codes */
|
|
int num_blocks; /* Number of complete blocks */
|
|
uint 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, (const uint8*) source,
|
|
(uint8*) dest);
|
|
source+= AES_BLOCK_SIZE;
|
|
dest+= AES_BLOCK_SIZE;
|
|
}
|
|
|
|
rijndaelDecrypt(aes_key.rk, aes_key.nr, (const uint8*) source, block);
|
|
/* Use last char in the block as size */
|
|
pad_len = (uint) (uchar) block[AES_BLOCK_SIZE-1];
|
|
|
|
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;
|
|
}
|