summaryrefslogtreecommitdiff
path: root/src/hmac
diff options
context:
space:
mode:
authorLorry <lorry@roadtrain.codethink.co.uk>2012-07-20 20:00:05 +0100
committerLorry <lorry@roadtrain.codethink.co.uk>2012-07-20 20:00:05 +0100
commit3ef782d3745ea8f25a3151561a3cfb882190210e (patch)
tree86b9c2f5fde051dd0bced99b3fc9f5a3ba08db69 /src/hmac
downloadberkeleydb-3ef782d3745ea8f25a3151561a3cfb882190210e.tar.gz
Tarball conversion
Diffstat (limited to 'src/hmac')
-rw-r--r--src/hmac/hmac.c223
-rw-r--r--src/hmac/sha1.c289
2 files changed, 512 insertions, 0 deletions
diff --git a/src/hmac/hmac.c b/src/hmac/hmac.c
new file mode 100644
index 00000000..4febfc60
--- /dev/null
+++ b/src/hmac/hmac.c
@@ -0,0 +1,223 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2001, 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Some parts of this code originally written by Adam Stubblefield,
+ * -- astubble@rice.edu.
+ *
+ * $Id$
+ */
+
+#include "db_config.h"
+
+#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"
+#include "dbinc/log.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((void *,
+ * PUBLIC: u_int8_t *, size_t, u_int8_t *, u_int8_t *));
+ */
+void
+__db_chksum(hdr, data, data_len, mac_key, store)
+ void *hdr;
+ u_int8_t *data;
+ size_t data_len;
+ u_int8_t *mac_key;
+ u_int8_t *store;
+{
+ int sumlen;
+ u_int32_t hash4;
+
+ /*
+ * 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 we are passed a log header XOR in prev and len so we have
+ * some redundancy on these fields. Mostly we need to be sure that
+ * we detect a race when doing hot backups and reading a live log
+ * file.
+ */
+ if (mac_key == NULL)
+ sumlen = sizeof(u_int32_t);
+ else
+ sumlen = DB_MAC_KEY;
+ if (hdr == NULL)
+ memset(store, 0, sumlen);
+ else
+ store = ((HDR*)hdr)->chksum;
+ if (mac_key == NULL) {
+ /* Just a hash, no MAC */
+ hash4 = __ham_func4(NULL, data, (u_int32_t)data_len);
+ if (hdr != NULL)
+ hash4 ^= ((HDR *)hdr)->prev ^ ((HDR *)hdr)->len;
+ memcpy(store, &hash4, sumlen);
+ } else {
+ __db_hmac(mac_key, data, data_len, store);
+ if (hdr != 0) {
+ ((int *)store)[0] ^= ((HDR *)hdr)->prev;
+ ((int *)store)[1] ^= ((HDR *)hdr)->len;
+ }
+ }
+ 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((ENV *,
+ * PUBLIC: void *, DB_CIPHER *, u_int8_t *, void *, size_t, int));
+ */
+int
+__db_check_chksum(env, hdr, db_cipher, chksum, data, data_len, is_hmac)
+ ENV *env;
+ void *hdr;
+ 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_errx(env, DB_STR("0195",
+ "Unencrypted checksum with a supplied encryption key"));
+ return (EINVAL);
+ }
+ sum_len = sizeof(u_int32_t);
+ mac_key = NULL;
+ } else {
+ if (db_cipher == NULL) {
+ __db_errx(env, DB_STR("0196",
+ "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.
+ * If there is a log header, XOR the prev and len fields.
+ */
+ if (hdr == NULL) {
+ memcpy(old, chksum, sum_len);
+ memset(chksum, 0, sum_len);
+ chksum = old;
+ }
+
+ if (mac_key == NULL) {
+ /* Just a hash, no MAC */
+ hash4 = __ham_func4(NULL, data, (u_int32_t)data_len);
+ if (hdr != NULL)
+ LOG_HDR_SUM(0, hdr, &hash4);
+ ret = memcmp((u_int32_t *)chksum, &hash4, sum_len) ? -1 : 0;
+ } else {
+ __db_hmac(mac_key, data, data_len, new);
+ if (hdr != NULL)
+ LOG_HDR_SUM(1, hdr, new);
+ ret = memcmp(chksum, new, sum_len) ? -1 : 0;
+ }
+
+ return (ret);
+}
diff --git a/src/hmac/sha1.c b/src/hmac/sha1.c
new file mode 100644
index 00000000..76069694
--- /dev/null
+++ b/src/hmac/sha1.c
@@ -0,0 +1,289 @@
+/*
+ * $Id$
+ */
+
+#include "db_config.h"
+
+#include "db_int.h"
+#include "dbinc/hmac.h"
+
+/*
+SHA-1 in C
+By Steve Reid <sreid@sea-to-sky.net>
+100% Public Domain
+
+-----------------
+Modified 7/98
+By James H. Brown <jbrown@burgoyne.com>
+Still 100% Public Domain
+
+Corrected a problem which generated improper hash values on 16 bit machines
+Routine SHA1Update changed from
+ void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
+len)
+to
+ void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
+long len)
+
+The 'len' parameter was declared an int which works fine on 32 bit machines.
+However, on 16 bit machines an int is too small for the shifts being done
+against
+it. This caused the hash function to generate incorrect values if len was
+greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
+
+Since the file IO in main() reads 16K at a time, any file 8K or larger would
+be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
+"a"s).
+
+I also changed the declaration of variables i & j in SHA1Update to
+unsigned long from unsigned int for the same reason.
+
+These changes should make no difference to any 32 bit implementations since
+an
+int and a long are the same size in those environments.
+
+--
+I also corrected a few compiler warnings generated by Borland C.
+1. Added #include <process.h> for exit() prototype
+2. Removed unused variable 'j' in SHA1Final
+3. Changed exit(0) to return (0) at end of main.
+
+ALL changes I made can be located by searching for comments containing 'JHB'
+-----------------
+Modified 8/98
+By Steve Reid <sreid@sea-to-sky.net>
+Still 100% public domain
+
+1- Removed #include <process.h> and used return () instead of exit()
+2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
+3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
+
+-----------------
+Modified 4/01
+By Saul Kravitz <Saul.Kravitz@celera.com>
+Still 100% PD
+Modified to run on Compaq Alpha hardware.
+
+*/
+
+/*
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+#define SHA1HANDSOFF
+
+/* #include <process.h> */ /* prototype for exit() - JHB */
+/* Using return () instead of exit() - SWR */
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#define blk0(i) is_bigendian ? block->l[i] : \
+ (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5); \
+ w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5); \
+ w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5); \
+ w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+#ifdef VERBOSE /* SAK */
+static void __db_SHAPrintContext __P((SHA1_CTX *, char *));
+static void
+__db_SHAPrintContext(context, msg)
+ SHA1_CTX *context;
+ char *msg;
+{
+ printf("%s (%d,%d) %x %x %x %x %x\n",
+ msg,
+ context->count[0], context->count[1],
+ context->state[0],
+ context->state[1],
+ context->state[2],
+ context->state[3],
+ context->state[4]);
+}
+#endif
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+/*
+ * __db_SHA1Transform --
+ *
+ * PUBLIC: void __db_SHA1Transform __P((u_int32_t *, unsigned char *));
+ */
+void
+__db_SHA1Transform(state, buffer)
+ u_int32_t *state;
+ unsigned char *buffer;
+{
+u_int32_t a, b, c, d, e;
+typedef union {
+ unsigned char c[64];
+ u_int32_t l[16];
+} CHAR64LONG16;
+CHAR64LONG16* block;
+ int is_bigendian;
+#ifdef SHA1HANDSOFF
+ unsigned char workspace[64];
+
+ block = (CHAR64LONG16*)workspace;
+ memcpy(block, buffer, 64);
+#else
+ block = (CHAR64LONG16*)buffer;
+#endif
+ is_bigendian = __db_isbigendian();
+
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+/* SHA1Init - Initialize new context */
+
+/*
+ * __db_SHA1Init --
+ * Initialize new context
+ *
+ * PUBLIC: void __db_SHA1Init __P((SHA1_CTX *));
+ */
+void
+__db_SHA1Init(context)
+ SHA1_CTX *context;
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+/* Run your data through this. */
+
+/*
+ * __db_SHA1Update --
+ * Run your data through this.
+ *
+ * PUBLIC: void __db_SHA1Update __P((SHA1_CTX *, unsigned char *,
+ * PUBLIC: size_t));
+ */
+void
+__db_SHA1Update(context, data, len)
+ SHA1_CTX *context;
+ unsigned char *data;
+ size_t len;
+{
+u_int32_t i, j; /* JHB */
+
+#ifdef VERBOSE
+ __db_SHAPrintContext(context, DB_STR_P("before"));
+#endif
+ j = (context->count[0] >> 3) & 63;
+ if ((context->count[0] += (u_int32_t)len << 3) < (len << 3))
+ context->count[1]++;
+ context->count[1] += (u_int32_t)(len >> 29);
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ __db_SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ __db_SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+#ifdef VERBOSE
+ __db_SHAPrintContext(context, DB_STR_P("after "));
+#endif
+}
+
+/* Add padding and return the message digest. */
+
+/*
+ * __db_SHA1Final --
+ * Add padding and return the message digest.
+ *
+ * PUBLIC: void __db_SHA1Final __P((unsigned char *, SHA1_CTX *));
+ */
+void
+__db_SHA1Final(digest, context)
+ unsigned char *digest;
+ SHA1_CTX *context;
+{
+u_int32_t i; /* JHB */
+unsigned char finalcount[8];
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ __db_SHA1Update(context, (unsigned char *)"\200", 1);
+ while ((context->count[0] & 504) != 448) {
+ __db_SHA1Update(context, (unsigned char *)"\0", 1);
+ }
+ __db_SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform()
+*/
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ /* Wipe variables */
+ i = 0; /* JHB */
+ memset(context->buffer, 0, 64);
+ memset(context->state, 0, 20);
+ memset(context->count, 0, 8);
+ memset(finalcount, 0, 8); /* SWR */
+#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */
+ __db_SHA1Transform(context->state, context->buffer);
+#endif
+}
+
+/*************************************************************/