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

hmac.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: hmac.c,v 12.1 2005/06/16 20:22: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/db_page.h"      /* for hash.h only */
00022 #include "dbinc/hash.h"
00023 #include "dbinc/hmac.h"
00024 
00025 #define HMAC_OUTPUT_SIZE        20
00026 #define HMAC_BLOCK_SIZE 64
00027 
00028 static void __db_hmac __P((u_int8_t *, u_int8_t *, size_t, u_int8_t *));
00029 
00030 /*
00031  * !!!
00032  * All of these functions use a ctx structure on the stack.  The __db_SHA1Init
00033  * call does not initialize the 64-byte buffer portion of it.  The
00034  * underlying SHA1 functions will properly pad the buffer if the data length
00035  * is less than 64-bytes, so there isn't a chance of reading uninitialized
00036  * memory.  Although it would be cleaner to do a memset(ctx.buffer, 0, 64)
00037  * we do not want to incur that penalty if we don't have to for performance.
00038  */
00039 
00040 /*
00041  * __db_hmac --
00042  *      Do a hashed MAC.
00043  */
00044 static void
00045 __db_hmac(k, data, data_len, mac)
00046         u_int8_t *k, *data, *mac;
00047         size_t data_len;
00048 {
00049         SHA1_CTX ctx;
00050         u_int8_t key[HMAC_BLOCK_SIZE];
00051         u_int8_t ipad[HMAC_BLOCK_SIZE];
00052         u_int8_t opad[HMAC_BLOCK_SIZE];
00053         u_int8_t tmp[HMAC_OUTPUT_SIZE];
00054         int i;
00055 
00056         memset(key, 0x00, HMAC_BLOCK_SIZE);
00057         memset(ipad, 0x36, HMAC_BLOCK_SIZE);
00058         memset(opad, 0x5C, HMAC_BLOCK_SIZE);
00059 
00060         memcpy(key, k, HMAC_OUTPUT_SIZE);
00061 
00062         for (i = 0; i < HMAC_BLOCK_SIZE; i++) {
00063                 ipad[i] ^= key[i];
00064                 opad[i] ^= key[i];
00065         }
00066 
00067         __db_SHA1Init(&ctx);
00068         __db_SHA1Update(&ctx, ipad, HMAC_BLOCK_SIZE);
00069         __db_SHA1Update(&ctx, data, data_len);
00070         __db_SHA1Final(tmp, &ctx);
00071         __db_SHA1Init(&ctx);
00072         __db_SHA1Update(&ctx, opad, HMAC_BLOCK_SIZE);
00073         __db_SHA1Update(&ctx, tmp, HMAC_OUTPUT_SIZE);
00074         __db_SHA1Final(mac, &ctx);
00075         return;
00076 }
00077 
00078 /*
00079  * __db_chksum --
00080  *      Create a MAC/SHA1 checksum.
00081  *
00082  * PUBLIC: void __db_chksum __P((u_int8_t *, size_t, u_int8_t *, u_int8_t *));
00083  */
00084 void
00085 __db_chksum(data, data_len, mac_key, store)
00086         u_int8_t *data;
00087         size_t data_len;
00088         u_int8_t *mac_key;
00089         u_int8_t *store;
00090 {
00091         int sumlen;
00092         u_int32_t hash4;
00093         u_int8_t tmp[DB_MAC_KEY];
00094 
00095         /*
00096          * Since the checksum might be on a page of data we are checksumming
00097          * we might be overwriting after checksumming, we zero-out the
00098          * checksum value so that we can have a known value there when
00099          * we verify the checksum.
00100          */
00101         if (mac_key == NULL)
00102                 sumlen = sizeof(u_int32_t);
00103         else
00104                 sumlen = DB_MAC_KEY;
00105         memset(store, 0, sumlen);
00106         if (mac_key == NULL) {
00107                 /* Just a hash, no MAC */
00108                 hash4 = __ham_func4(NULL, data, (u_int32_t)data_len);
00109                 memcpy(store, &hash4, sumlen);
00110         } else {
00111                 memset(tmp, 0, DB_MAC_KEY);
00112                 __db_hmac(mac_key, data, data_len, tmp);
00113                 memcpy(store, tmp, sumlen);
00114         }
00115         return;
00116 }
00117 /*
00118  * __db_derive_mac --
00119  *      Create a MAC/SHA1 key.
00120  *
00121  * PUBLIC: void __db_derive_mac __P((u_int8_t *, size_t, u_int8_t *));
00122  */
00123 void
00124 __db_derive_mac(passwd, plen, mac_key)
00125         u_int8_t *passwd;
00126         size_t plen;
00127         u_int8_t *mac_key;
00128 {
00129         SHA1_CTX ctx;
00130 
00131         /* Compute the MAC key. mac_key must be 20 bytes. */
00132         __db_SHA1Init(&ctx);
00133         __db_SHA1Update(&ctx, passwd, plen);
00134         __db_SHA1Update(&ctx, (u_int8_t *)DB_MAC_MAGIC, strlen(DB_MAC_MAGIC));
00135         __db_SHA1Update(&ctx, passwd, plen);
00136         __db_SHA1Final(mac_key, &ctx);
00137 
00138         return;
00139 }
00140 
00141 /*
00142  * __db_check_chksum --
00143  *      Verify a checksum.
00144  *
00145  *      Return 0 on success, >0 (errno) on error, -1 on checksum mismatch.
00146  *
00147  * PUBLIC: int __db_check_chksum __P((DB_ENV *,
00148  * PUBLIC:     DB_CIPHER *, u_int8_t *, void *, size_t, int));
00149  */
00150 int
00151 __db_check_chksum(dbenv, db_cipher, chksum, data, data_len, is_hmac)
00152         DB_ENV *dbenv;
00153         DB_CIPHER *db_cipher;
00154         u_int8_t *chksum;
00155         void *data;
00156         size_t data_len;
00157         int is_hmac;
00158 {
00159         int ret;
00160         size_t sum_len;
00161         u_int32_t hash4;
00162         u_int8_t *mac_key, old[DB_MAC_KEY], new[DB_MAC_KEY];
00163 
00164         /*
00165          * If we are just doing checksumming and not encryption, then checksum
00166          * is 4 bytes.  Otherwise, it is DB_MAC_KEY size.  Check for illegal
00167          * combinations of crypto/non-crypto checksums.
00168          */
00169         if (is_hmac == 0) {
00170                 if (db_cipher != NULL) {
00171                         __db_err(dbenv,
00172     "Unencrypted checksum with a supplied encryption key");
00173                         return (EINVAL);
00174                 }
00175                 sum_len = sizeof(u_int32_t);
00176                 mac_key = NULL;
00177         } else {
00178                 if (db_cipher == NULL) {
00179                         __db_err(dbenv,
00180     "Encrypted checksum: no encryption key specified");
00181                         return (EINVAL);
00182                 }
00183                 sum_len = DB_MAC_KEY;
00184                 mac_key = db_cipher->mac_key;
00185         }
00186 
00187         /*
00188          * !!!
00189          * Since the checksum might be on the page, we need to have known data
00190          * there so that we can generate the same original checksum.  We zero
00191          * it out, just like we do in __db_chksum above.
00192          */
00193         memcpy(old, chksum, sum_len);
00194         memset(chksum, 0, sum_len);
00195         if (mac_key == NULL) {
00196                 /* Just a hash, no MAC */
00197                 hash4 = __ham_func4(NULL, data, (u_int32_t)data_len);
00198                 ret = memcmp((u_int32_t *)old, &hash4, sum_len) ? -1 : 0;
00199         } else {
00200                 __db_hmac(mac_key, data, data_len, new);
00201                 ret = memcmp(old, new, sum_len) ? -1 : 0;
00202         }
00203 
00204         return (ret);
00205 }

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