Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

aes_method.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 2001-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * Some parts of this code originally written by Adam Stubblefield,
00008  * -- [email protected].
00009  *
00010  * $Id: aes_method.c,v 12.1 2005/06/16 20:20:55 bostic Exp $
00011  */
00012 
00013 #include "db_config.h"
00014 
00015 #ifndef NO_SYSTEM_INCLUDES
00016 #include <string.h>
00017 #endif
00018 
00019 #include "db_int.h"
00020 #include "dbinc/crypto.h"
00021 #include "dbinc/hmac.h"
00022 
00023 static void __aes_err __P((DB_ENV *, int));
00024 static int __aes_derivekeys __P((DB_ENV *, DB_CIPHER *, u_int8_t *, size_t));
00025 
00026 /*
00027  * __aes_setup --
00028  *      Setup AES functions.
00029  *
00030  * PUBLIC: int __aes_setup __P((DB_ENV *, DB_CIPHER *));
00031  */
00032 int
00033 __aes_setup(dbenv, db_cipher)
00034         DB_ENV *dbenv;
00035         DB_CIPHER *db_cipher;
00036 {
00037         AES_CIPHER *aes_cipher;
00038         int ret;
00039 
00040         db_cipher->adj_size = __aes_adj_size;
00041         db_cipher->close = __aes_close;
00042         db_cipher->decrypt = __aes_decrypt;
00043         db_cipher->encrypt = __aes_encrypt;
00044         db_cipher->init = __aes_init;
00045         if ((ret = __os_calloc(dbenv, 1, sizeof(AES_CIPHER), &aes_cipher)) != 0)
00046                 return (ret);
00047         db_cipher->data = aes_cipher;
00048         return (0);
00049 }
00050 
00051 /*
00052  * __aes_adj_size --
00053  *      Given a size, return an addition amount needed to meet the
00054  *      "chunk" needs of the algorithm.
00055  *
00056  * PUBLIC: u_int __aes_adj_size __P((size_t));
00057  */
00058 u_int
00059 __aes_adj_size(len)
00060         size_t len;
00061 {
00062         if (len % DB_AES_CHUNK == 0)
00063                 return (0);
00064         return (DB_AES_CHUNK - (u_int)(len % DB_AES_CHUNK));
00065 }
00066 
00067 /*
00068  * __aes_close --
00069  *      Destroy the AES encryption instantiation.
00070  *
00071  * PUBLIC: int __aes_close __P((DB_ENV *, void *));
00072  */
00073 int
00074 __aes_close(dbenv, data)
00075         DB_ENV *dbenv;
00076         void *data;
00077 {
00078         __os_free(dbenv, data);
00079         return (0);
00080 }
00081 
00082 /*
00083  * __aes_decrypt --
00084  *      Decrypt data with AES.
00085  *
00086  * PUBLIC: int __aes_decrypt __P((DB_ENV *, void *, void *,
00087  * PUBLIC:     u_int8_t *, size_t));
00088  */
00089 int
00090 __aes_decrypt(dbenv, aes_data, iv, cipher, cipher_len)
00091         DB_ENV *dbenv;
00092         void *aes_data;
00093         void *iv;
00094         u_int8_t *cipher;
00095         size_t cipher_len;
00096 {
00097         AES_CIPHER *aes;
00098         cipherInstance c;
00099         int ret;
00100 
00101         aes = (AES_CIPHER *)aes_data;
00102         if (iv == NULL || cipher == NULL)
00103                 return (EINVAL);
00104         if ((cipher_len % DB_AES_CHUNK) != 0)
00105                 return (EINVAL);
00106         /*
00107          * Initialize the cipher
00108          */
00109         if ((ret = __db_cipherInit(&c, MODE_CBC, iv)) < 0) {
00110                 __aes_err(dbenv, ret);
00111                 return (EAGAIN);
00112         }
00113 
00114         /* Do the decryption */
00115         if ((ret = __db_blockDecrypt(&c, &aes->decrypt_ki, cipher,
00116             cipher_len * 8, cipher)) < 0) {
00117                 __aes_err(dbenv, ret);
00118                 return (EAGAIN);
00119         }
00120         return (0);
00121 }
00122 
00123 /*
00124  * __aes_encrypt --
00125  *      Encrypt data with AES.
00126  *
00127  * PUBLIC: int __aes_encrypt __P((DB_ENV *, void *, void *,
00128  * PUBLIC:     u_int8_t *, size_t));
00129  */
00130 int
00131 __aes_encrypt(dbenv, aes_data, iv, data, data_len)
00132         DB_ENV *dbenv;
00133         void *aes_data;
00134         void *iv;
00135         u_int8_t *data;
00136         size_t data_len;
00137 {
00138         AES_CIPHER *aes;
00139         cipherInstance c;
00140         u_int32_t tmp_iv[DB_IV_BYTES/4];
00141         int ret;
00142 
00143         aes = (AES_CIPHER *)aes_data;
00144         if (aes == NULL || data == NULL)
00145                 return (EINVAL);
00146         if ((data_len % DB_AES_CHUNK) != 0)
00147                 return (EINVAL);
00148         /*
00149          * Generate the IV here.  We store it in a tmp IV because
00150          * the IV might be stored within the data we are encrypting
00151          * and so we will copy it over to the given location after
00152          * encryption is done.
00153          * We don't do this outside of there because some encryption
00154          * algorithms someone might add may not use IV's and we always
00155          * want on here.
00156          */
00157         if ((ret = __db_generate_iv(dbenv, tmp_iv)) != 0)
00158                 return (ret);
00159 
00160         /*
00161          * Initialize the cipher
00162          */
00163         if ((ret = __db_cipherInit(&c, MODE_CBC, (char *)tmp_iv)) < 0) {
00164                 __aes_err(dbenv, ret);
00165                 return (EAGAIN);
00166         }
00167 
00168         /* Do the encryption */
00169         if ((ret = __db_blockEncrypt(&c, &aes->encrypt_ki, data, data_len * 8,
00170             data)) < 0) {
00171                 __aes_err(dbenv, ret);
00172                 return (EAGAIN);
00173         }
00174         memcpy(iv, tmp_iv, DB_IV_BYTES);
00175         return (0);
00176 }
00177 
00178 /*
00179  * __aes_init --
00180  *      Initialize the AES encryption instantiation.
00181  *
00182  * PUBLIC: int __aes_init __P((DB_ENV *, DB_CIPHER *));
00183  */
00184 int
00185 __aes_init(dbenv, db_cipher)
00186         DB_ENV *dbenv;
00187         DB_CIPHER *db_cipher;
00188 {
00189         return (__aes_derivekeys(dbenv, db_cipher, (u_int8_t *)dbenv->passwd,
00190             dbenv->passwd_len));
00191 }
00192 
00193 static int
00194 __aes_derivekeys(dbenv, db_cipher, passwd, plen)
00195         DB_ENV *dbenv;
00196         DB_CIPHER *db_cipher;
00197         u_int8_t *passwd;
00198         size_t plen;
00199 {
00200         SHA1_CTX ctx;
00201         AES_CIPHER *aes;
00202         int ret;
00203         u_int32_t temp[DB_MAC_KEY/4];
00204 
00205         if (passwd == NULL)
00206                 return (EINVAL);
00207 
00208         aes = (AES_CIPHER *)db_cipher->data;
00209 
00210         /* Derive the crypto keys */
00211         __db_SHA1Init(&ctx);
00212         __db_SHA1Update(&ctx, passwd, plen);
00213         __db_SHA1Update(&ctx, (u_int8_t *)DB_ENC_MAGIC, strlen(DB_ENC_MAGIC));
00214         __db_SHA1Update(&ctx, passwd, plen);
00215         __db_SHA1Final((u_int8_t *)temp, &ctx);
00216 
00217         if ((ret = __db_makeKey(&aes->encrypt_ki, DIR_ENCRYPT,
00218             DB_AES_KEYLEN, (char *)temp)) != TRUE) {
00219                 __aes_err(dbenv, ret);
00220                 return (EAGAIN);
00221         }
00222         if ((ret = __db_makeKey(&aes->decrypt_ki, DIR_DECRYPT,
00223             DB_AES_KEYLEN, (char *)temp)) != TRUE) {
00224                 __aes_err(dbenv, ret);
00225                 return (EAGAIN);
00226         }
00227         return (0);
00228 }
00229 
00230 /*
00231  * __aes_err --
00232  *      Handle AES-specific errors.  Codes and messages derived from
00233  *      rijndael/rijndael-api-fst.h.
00234  */
00235 static void
00236 __aes_err(dbenv, err)
00237         DB_ENV *dbenv;
00238         int err;
00239 {
00240         char *errstr;
00241 
00242         switch (err) {
00243         case BAD_KEY_DIR:
00244                 errstr = "AES key direction is invalid";
00245                 break;
00246         case BAD_KEY_MAT:
00247                 errstr = "AES key material not of correct length";
00248                 break;
00249         case BAD_KEY_INSTANCE:
00250                 errstr = "AES key passwd not valid";
00251                 break;
00252         case BAD_CIPHER_MODE:
00253                 errstr = "AES cipher in wrong state (not initialized)";
00254                 break;
00255         case BAD_BLOCK_LENGTH:
00256                 errstr = "AES bad block length";
00257                 break;
00258         case BAD_CIPHER_INSTANCE:
00259                 errstr = "AES cipher instance is invalid";
00260                 break;
00261         case BAD_DATA:
00262                 errstr = "AES data contents are invalid";
00263                 break;
00264         case BAD_OTHER:
00265                 errstr = "AES unknown error";
00266                 break;
00267         default:
00268                 errstr = "AES error unrecognized";
00269                 break;
00270         }
00271         __db_err(dbenv, errstr);
00272         return;
00273 }

Generated on Sun Dec 25 12:14:17 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2