hmac.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:5k
- /*-
- * See the file LICENSE for redistribution information.
- *
- * Copyright (c) 2001-2002
- * Sleepycat Software. All rights reserved.
- *
- * Some parts of this code originally written by Adam Stubblefield,
- * astubble@rice.edu.
- */
- #include "db_config.h"
- #ifndef lint
- static const char revid[] = "$Id: hmac.c,v 1.25 2002/09/10 02:40:40 bostic Exp $";
- #endif /* not lint */
- #ifndef NO_SYSTEM_INCLUDES
- #include <string.h>
- #endif
- #include "db_int.h"
- #include "dbinc/crypto.h"
- #include "dbinc/db_page.h" /* for hash.h only */
- #include "dbinc/hash.h"
- #include "dbinc/hmac.h"
- #define HMAC_OUTPUT_SIZE 20
- #define HMAC_BLOCK_SIZE 64
- static void __db_hmac __P((u_int8_t *, u_int8_t *, size_t, u_int8_t *));
- /*
- * !!!
- * All of these functions use a ctx structure on the stack. The __db_SHA1Init
- * call does not initialize the 64-byte buffer portion of it. The
- * underlying SHA1 functions will properly pad the buffer if the data length
- * is less than 64-bytes, so there isn't a chance of reading uninitialized
- * memory. Although it would be cleaner to do a memset(ctx.buffer, 0, 64)
- * we do not want to incur that penalty if we don't have to for performance.
- */
- /*
- * __db_hmac --
- * Do a hashed MAC.
- */
- static void
- __db_hmac(k, data, data_len, mac)
- u_int8_t *k, *data, *mac;
- size_t data_len;
- {
- SHA1_CTX ctx;
- u_int8_t key[HMAC_BLOCK_SIZE];
- u_int8_t ipad[HMAC_BLOCK_SIZE];
- u_int8_t opad[HMAC_BLOCK_SIZE];
- u_int8_t tmp[HMAC_OUTPUT_SIZE];
- int i;
- memset(key, 0x00, HMAC_BLOCK_SIZE);
- memset(ipad, 0x36, HMAC_BLOCK_SIZE);
- memset(opad, 0x5C, HMAC_BLOCK_SIZE);
- memcpy(key, k, HMAC_OUTPUT_SIZE);
- for (i = 0; i < HMAC_BLOCK_SIZE; i++) {
- ipad[i] ^= key[i];
- opad[i] ^= key[i];
- }
- __db_SHA1Init(&ctx);
- __db_SHA1Update(&ctx, ipad, HMAC_BLOCK_SIZE);
- __db_SHA1Update(&ctx, data, data_len);
- __db_SHA1Final(tmp, &ctx);
- __db_SHA1Init(&ctx);
- __db_SHA1Update(&ctx, opad, HMAC_BLOCK_SIZE);
- __db_SHA1Update(&ctx, tmp, HMAC_OUTPUT_SIZE);
- __db_SHA1Final(mac, &ctx);
- return;
- }
- /*
- * __db_chksum --
- * Create a MAC/SHA1 checksum.
- *
- * PUBLIC: void __db_chksum __P((u_int8_t *, size_t, u_int8_t *, u_int8_t *));
- */
- void
- __db_chksum(data, data_len, mac_key, store)
- u_int8_t *data;
- size_t data_len;
- u_int8_t *mac_key;
- u_int8_t *store;
- {
- int sumlen;
- u_int32_t hash4;
- u_int8_t tmp[DB_MAC_KEY];
- /*
- * Since the checksum might be on a page of data we are checksumming
- * we might be overwriting after checksumming, we zero-out the
- * checksum value so that we can have a known value there when
- * we verify the checksum.
- */
- if (mac_key == NULL)
- sumlen = sizeof(u_int32_t);
- else
- sumlen = DB_MAC_KEY;
- memset(store, 0, sumlen);
- if (mac_key == NULL) {
- /* Just a hash, no MAC */
- hash4 = __ham_func4(NULL, data, (u_int32_t)data_len);
- memcpy(store, &hash4, sumlen);
- } else {
- memset(tmp, 0, DB_MAC_KEY);
- __db_hmac(mac_key, data, data_len, tmp);
- memcpy(store, tmp, sumlen);
- }
- return;
- }
- /*
- * __db_derive_mac --
- * Create a MAC/SHA1 key.
- *
- * PUBLIC: void __db_derive_mac __P((u_int8_t *, size_t, u_int8_t *));
- */
- void
- __db_derive_mac(passwd, plen, mac_key)
- u_int8_t *passwd;
- size_t plen;
- u_int8_t *mac_key;
- {
- SHA1_CTX ctx;
- /* Compute the MAC key. mac_key must be 20 bytes. */
- __db_SHA1Init(&ctx);
- __db_SHA1Update(&ctx, passwd, plen);
- __db_SHA1Update(&ctx, (u_int8_t *)DB_MAC_MAGIC, strlen(DB_MAC_MAGIC));
- __db_SHA1Update(&ctx, passwd, plen);
- __db_SHA1Final(mac_key, &ctx);
- return;
- }
- /*
- * __db_check_chksum --
- * Verify a checksum.
- *
- * Return 0 on success, >0 (errno) on error, -1 on checksum mismatch.
- *
- * PUBLIC: int __db_check_chksum __P((DB_ENV *,
- * PUBLIC: DB_CIPHER *, u_int8_t *, void *, size_t, int));
- */
- int
- __db_check_chksum(dbenv, db_cipher, chksum, data, data_len, is_hmac)
- DB_ENV *dbenv;
- DB_CIPHER *db_cipher;
- u_int8_t *chksum;
- void *data;
- size_t data_len;
- int is_hmac;
- {
- int ret;
- size_t sum_len;
- u_int32_t hash4;
- u_int8_t *mac_key, old[DB_MAC_KEY], new[DB_MAC_KEY];
- /*
- * If we are just doing checksumming and not encryption, then checksum
- * is 4 bytes. Otherwise, it is DB_MAC_KEY size. Check for illegal
- * combinations of crypto/non-crypto checksums.
- */
- if (is_hmac == 0) {
- if (db_cipher != NULL) {
- __db_err(dbenv,
- "Unencrypted checksum with a supplied encryption key");
- return (EINVAL);
- }
- sum_len = sizeof(u_int32_t);
- mac_key = NULL;
- } else {
- if (db_cipher == NULL) {
- __db_err(dbenv,
- "Encrypted checksum: no encryption key specified");
- return (EINVAL);
- }
- sum_len = DB_MAC_KEY;
- mac_key = db_cipher->mac_key;
- }
- /*
- * !!!
- * Since the checksum might be on the page, we need to have known data
- * there so that we can generate the same original checksum. We zero
- * it out, just like we do in __db_chksum above.
- */
- memcpy(old, chksum, sum_len);
- memset(chksum, 0, sum_len);
- if (mac_key == NULL) {
- /* Just a hash, no MAC */
- hash4 = __ham_func4(NULL, data, (u_int32_t)data_len);
- ret = memcmp((u_int32_t *)old, &hash4, sum_len) ? -1 : 0;
- } else {
- __db_hmac(mac_key, data, data_len, new);
- ret = memcmp(old, new, sum_len) ? -1 : 0;
- }
- return (ret);
- }