my_aes.c 5.72 KB
Newer Older
1 2 3 4 5 6
/* 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.
7

8 9 10 11
 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.
12

13 14 15
 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 */
16 17


18 19 20 21
/*
  Implementation of AES Encryption for MySQL
  Initial version by Peter Zaitsev  June 2002
*/
22 23


24 25
#include <my_global.h>
#include <m_string.h>
26 27
#include "my_aes.h"

28
enum encrypt_dir { AES_ENCRYPT, AES_DECRYPT };
29

30
#define AES_BLOCK_SIZE 16	/* Block size in bytes */
31

32 33 34 35
#define AES_BAD_DATA  -1	/* If bad data discovered during decoding */


/* The structure for key information */
36
typedef struct {
37 38
  int	nr;				/* Number of rounds */
  uint32   rk[4*(AES_MAXNR + 1)];	/* key schedule */
39 40 41
} KEYINSTANCE;


42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
/*
  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 */
64
  char *rkey_end=rkey+AES_KEY_LENGTH/8; /* Real key boundary */
65 66 67 68
  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*/

69
  bzero(rkey,AES_KEY_LENGTH/8);      /* Set initial key  */
70

71 72 73 74
  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 */
75
    *ptr^= *sptr;
76
  }
77
  if (direction == AES_DECRYPT)
78
     aes_key->nr = rijndaelKeySetupDec(aes_key->rk, rkey, AES_KEY_LENGTH);
79
  else
80
     aes_key->nr = rijndaelKeySetupEnc(aes_key->rk, rkey, AES_KEY_LENGTH);
81
  return 0;
82 83 84
}


85
/*
86 87 88 89 90 91 92 93 94 95 96 97 98
  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
99 100
*/

101 102
int my_aes_encrypt(const char* source, int source_length, char* dest,
		   const char* key, int key_length)
103 104
{
  KEYINSTANCE aes_key;
105 106 107 108
  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 */
109
  int i;
110 111

  if ((rc= my_aes_create_key(&aes_key,AES_ENCRYPT,key,key_length)))
112
    return rc;
113 114 115

  num_blocks = source_length/AES_BLOCK_SIZE;

116 117 118 119 120 121
  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;
  }
122

123
  /* Encode the rest. We always have incomplete block */
124 125
  pad_len = AES_BLOCK_SIZE - (source_length - AES_BLOCK_SIZE*num_blocks);
  memcpy(block, source, 16 - pad_len);
126 127
  bfill(block + AES_BLOCK_SIZE - pad_len, pad_len, pad_len);
  rijndaelEncrypt(aes_key.rk, aes_key.nr, block, dest);
128
  return AES_BLOCK_SIZE*(num_blocks + 1);
129
}
130 131 132


/*
133 134 135 136 137 138 139 140 141 142 143 144 145 146
  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
*/
147

148 149
int my_aes_decrypt(const char *source, int source_length, char *dest,
		   const char *key, int key_length)
150 151
{
  KEYINSTANCE aes_key;
152 153 154 155
  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 */
156
  int i;
157

158
  if ((rc=my_aes_create_key(&aes_key,AES_DECRYPT,key,key_length)))
159
    return rc;
160 161 162 163 164 165

  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 */

166 167 168 169 170 171
  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;
  }
172

173
  rijndaelDecrypt(aes_key.rk, aes_key.nr, source, block);
174
  pad_len = block[AES_BLOCK_SIZE-1]; /* Use last char in the block as size */
175

176
  if (pad_len > AES_BLOCK_SIZE)
177 178
    return AES_BAD_DATA;
  /* We could also check whole padding but we do not really need this */
179

180
  memcpy(dest, block, AES_BLOCK_SIZE - pad_len);
181
  return AES_BLOCK_SIZE*num_blocks - pad_len;
182
}
183 184 185


/*
186 187 188 189 190 191 192 193
  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
194
*/
195

196
int my_aes_get_size(int source_length)
197
{
198 199
  return AES_BLOCK_SIZE*(source_length/AES_BLOCK_SIZE)+AES_BLOCK_SIZE;
}