[Dovecot] [PATCH] Generalize HMAC implementation

Florian Zeitz florob at babelmonkeys.de
Wed Sep 19 20:43:09 EEST 2012


Am 11.09.2012 20:21, schrieb Timo Sirainen:
> On 11.9.2012, at 21.07, Florian Zeitz wrote:
> 
>>> I think we could simply #define the largest allowed context_size, use it for these buffers' sizes and then add i_assert(meth->context_size <= HMAC_MAX_CONTEXT_SIZE)
>>>
>> Well, either that, or we could use a union of all known context structs
>> there.
> 
> That annoyingly requires #including in hmac.h all the different .h files that contain hash contexts. When new hashes are added I doubt anyone remembers to update that. And since the hmac_context is rather rarely used I don't think it matters if we just use a somewhat large context size.
> 
>> Or we could use i_malloc() and i_free() under the assumption hmac_init()
>> + hmac_final() calls are always matched.
> 
> Yeah, that's not too bad either I guess. Although it is different from other hash_init()+final calls which don't require it, and it's also wasting CPU a bit.
> 
Here is an updated version of the patch.
It uses the variant defining the largest allowed content size.
I choose 1024 bit (128 Byte), since that is what most of the SHA-3
candidates use, so it's hopefully somewhat future proof.

It's also rebased to the current head and switches the hmac uses added
since the last version over to the changed API. It also fixes an
"interesting" compiler warning I got with clang, which complained about
the fact that struct hmac_context* was (re)declared in the prototype of
hmac_md5_get_cram_context() and therefore separate from the one declared
in hmac.h.

Regards,
Florian
-------------- next part --------------
# HG changeset patch
# User Florian Zeitz <florob at babelmonkeys.de>
# Date 1346280236 -7200
# Node ID 0aa0a656176c9ca1c3f187999cd4725bf52665e5
# Parent  488c7dde19ad8baaa1d6bb48ee092c24eb9d44fb
lib: Generalize hmac to be hash independent

diff --git a/src/auth/auth-token.c b/src/auth/auth-token.c
--- a/src/auth/auth-token.c
+++ b/src/auth/auth-token.c
@@ -11,7 +11,8 @@
 
 #include "auth-common.h"
 #include "hex-binary.h"
-#include "hmac-sha1.h"
+#include "hmac.h"
+#include "sha1.h"
 #include "randgen.h"
 #include "read-full.h"
 #include "write-full.h"
@@ -168,16 +169,17 @@
 const char *auth_token_get(const char *service, const char *session_pid,
 			   const char *username, const char *session_id)
 {
-	struct hmac_sha1_context ctx;
+	struct hmac_context ctx;
 	unsigned char result[SHA1_RESULTLEN];
 
-	hmac_sha1_init(&ctx, username, strlen(username));
-	hmac_sha1_update(&ctx, session_pid, strlen(session_pid));
+	hmac_init(&ctx, (const unsigned char*)username, strlen(username),
+		  &hash_method_sha1);
+	hmac_update(&ctx, session_pid, strlen(session_pid));
 	if (session_id != NULL && *session_id != '\0')
-		hmac_sha1_update(&ctx, session_id, strlen(session_id));
-	hmac_sha1_update(&ctx, service, strlen(service));
-	hmac_sha1_update(&ctx, auth_token_secret, sizeof(auth_token_secret));
-	hmac_sha1_final(&ctx, result);
+		hmac_update(&ctx, session_id, strlen(session_id));
+	hmac_update(&ctx, service, strlen(service));
+	hmac_update(&ctx, auth_token_secret, sizeof(auth_token_secret));
+	hmac_final(&ctx, result);
 
 	return binary_to_hex(result, sizeof(result));
 }
diff --git a/src/auth/mech-cram-md5.c b/src/auth/mech-cram-md5.c
--- a/src/auth/mech-cram-md5.c
+++ b/src/auth/mech-cram-md5.c
@@ -7,7 +7,9 @@
 #include "ioloop.h"
 #include "buffer.h"
 #include "hex-binary.h"
-#include "hmac-md5.h"
+#include "hmac-cram-md5.h"
+#include "hmac.h"
+#include "md5.h"
 #include "randgen.h"
 #include "mech.h"
 #include "passdb.h"
@@ -50,7 +52,7 @@
 {
 	
 	unsigned char digest[MD5_RESULTLEN];
-        struct hmac_md5_context ctx;
+        struct hmac_context ctx;
 	const char *response_hex;
 
 	if (size != CRAM_MD5_CONTEXTLEN) {
@@ -59,9 +61,10 @@
 		return FALSE;
 	}
 
+	hmac_init(&ctx, NULL, 0, &hash_method_md5);
 	hmac_md5_set_cram_context(&ctx, credentials);
-	hmac_md5_update(&ctx, request->challenge, strlen(request->challenge));
-	hmac_md5_final(&ctx, digest);
+	hmac_update(&ctx, request->challenge, strlen(request->challenge));
+	hmac_final(&ctx, digest);
 
 	response_hex = binary_to_hex(digest, sizeof(digest));
 
diff --git a/src/auth/mech-scram-sha1.c b/src/auth/mech-scram-sha1.c
--- a/src/auth/mech-scram-sha1.c
+++ b/src/auth/mech-scram-sha1.c
@@ -9,7 +9,8 @@
 #include "auth-common.h"
 #include "base64.h"
 #include "buffer.h"
-#include "hmac-sha1.h"
+#include "hmac.h"
+#include "sha1.h"
 #include "randgen.h"
 #include "safe-memset.h"
 #include "str.h"
@@ -44,23 +45,23 @@
 	       const unsigned char *salt, size_t salt_size, unsigned int i,
 	       unsigned char result[SHA1_RESULTLEN])
 {
-	struct hmac_sha1_context ctx;
+	struct hmac_context ctx;
 	unsigned char U[SHA1_RESULTLEN];
 	unsigned int j, k;
 
 	/* Calculate U1 */
-	hmac_sha1_init(&ctx, str, str_size);
-	hmac_sha1_update(&ctx, salt, salt_size);
-	hmac_sha1_update(&ctx, "\0\0\0\1", 4);
-	hmac_sha1_final(&ctx, U);
+	hmac_init(&ctx, str, str_size, &hash_method_sha1);
+	hmac_update(&ctx, salt, salt_size);
+	hmac_update(&ctx, "\0\0\0\1", 4);
+	hmac_final(&ctx, U);
 
 	memcpy(result, U, SHA1_RESULTLEN);
 
 	/* Calculate U2 to Ui and Hi */
 	for (j = 2; j <= i; j++) {
-		hmac_sha1_init(&ctx, str, str_size);
-		hmac_sha1_update(&ctx, U, sizeof(U));
-		hmac_sha1_final(&ctx, U);
+		hmac_init(&ctx, str, str_size, &hash_method_sha1);
+		hmac_update(&ctx, U, sizeof(U));
+		hmac_final(&ctx, U);
 		for (k = 0; k < SHA1_RESULTLEN; k++)
 			result[k] ^= U[k];
 	}
@@ -94,7 +95,7 @@
 
 static const char *get_scram_server_final(struct scram_auth_request *request)
 {
-	struct hmac_sha1_context ctx;
+	struct hmac_context ctx;
 	const char *auth_message;
 	unsigned char server_key[SHA1_RESULTLEN];
 	unsigned char server_signature[SHA1_RESULTLEN];
@@ -104,17 +105,17 @@
 			request->server_first_message, ",",
 			request->client_final_message_without_proof, NULL);
 
-	hmac_sha1_init(&ctx, request->salted_password,
-		       sizeof(request->salted_password));
-	hmac_sha1_update(&ctx, "Server Key", 10);
-	hmac_sha1_final(&ctx, server_key);
+	hmac_init(&ctx, request->salted_password,
+		  sizeof(request->salted_password), &hash_method_sha1);
+	hmac_update(&ctx, "Server Key", 10);
+	hmac_final(&ctx, server_key);
 
 	safe_memset(request->salted_password, 0,
 		    sizeof(request->salted_password));
 
-	hmac_sha1_init(&ctx, server_key, sizeof(server_key));
-	hmac_sha1_update(&ctx, auth_message, strlen(auth_message));
-	hmac_sha1_final(&ctx, server_signature);
+	hmac_init(&ctx, server_key, sizeof(server_key), &hash_method_sha1);
+	hmac_update(&ctx, auth_message, strlen(auth_message));
+	hmac_final(&ctx, server_signature);
 
 	str = t_str_new(MAX_BASE64_ENCODED_SIZE(sizeof(server_signature)));
 	str_append(str, "v=");
@@ -213,7 +214,7 @@
 static bool verify_credentials(struct scram_auth_request *request,
 			       const unsigned char *credentials, size_t size)
 {
-	struct hmac_sha1_context ctx;
+	struct hmac_context ctx;
 	const char *auth_message;
 	unsigned char client_key[SHA1_RESULTLEN];
 	unsigned char client_signature[SHA1_RESULTLEN];
@@ -224,10 +225,10 @@
 	Hi(credentials, size, request->salt, sizeof(request->salt),
 	   SCRAM_ITERATE_COUNT, request->salted_password);
 
-	hmac_sha1_init(&ctx, request->salted_password,
-			sizeof(request->salted_password));
-	hmac_sha1_update(&ctx, "Client Key", 10);
-	hmac_sha1_final(&ctx, client_key);
+	hmac_init(&ctx, request->salted_password,
+		  sizeof(request->salted_password), &hash_method_sha1);
+	hmac_update(&ctx, "Client Key", 10);
+	hmac_final(&ctx, client_key);
 
 	sha1_get_digest(client_key, sizeof(client_key), stored_key);
 
@@ -235,9 +236,9 @@
 			request->server_first_message, ",",
 			request->client_final_message_without_proof, NULL);
 
-	hmac_sha1_init(&ctx, stored_key, sizeof(stored_key));
-	hmac_sha1_update(&ctx, auth_message, strlen(auth_message));
-	hmac_sha1_final(&ctx, client_signature);
+	hmac_init(&ctx, stored_key, sizeof(stored_key), &hash_method_sha1);
+	hmac_update(&ctx, auth_message, strlen(auth_message));
+	hmac_final(&ctx, client_signature);
 
 	for (i = 0; i < sizeof(client_signature); i++)
 		client_signature[i] ^= client_key[i];
diff --git a/src/auth/password-scheme.c b/src/auth/password-scheme.c
--- a/src/auth/password-scheme.c
+++ b/src/auth/password-scheme.c
@@ -6,7 +6,8 @@
 #include "hex-binary.h"
 #include "md4.h"
 #include "md5.h"
-#include "hmac-md5.h"
+#include "hmac.h"
+#include "hmac-cram-md5.h"
 #include "ntlm.h"
 #include "mycrypt.h"
 #include "randgen.h"
@@ -655,12 +656,12 @@
 cram_md5_generate(const char *plaintext, const char *user ATTR_UNUSED,
 		  const unsigned char **raw_password_r, size_t *size_r)
 {
-	struct hmac_md5_context ctx;
+	struct hmac_context ctx;
 	unsigned char *context_digest;
 
 	context_digest = t_malloc(CRAM_MD5_CONTEXTLEN);
-	hmac_md5_init(&ctx, (const unsigned char *)plaintext,
-		      strlen(plaintext));
+	hmac_init(&ctx, (const unsigned char *)plaintext,
+		  strlen(plaintext), &hash_method_md5);
 	hmac_md5_get_cram_context(&ctx, context_digest);
 
 	*raw_password_r = context_digest;
diff --git a/src/lib-imap-urlauth/imap-urlauth.c b/src/lib-imap-urlauth/imap-urlauth.c
--- a/src/lib-imap-urlauth/imap-urlauth.c
+++ b/src/lib-imap-urlauth/imap-urlauth.c
@@ -3,7 +3,8 @@
 #include "lib.h"
 #include "hostpid.h"
 #include "var-expand.h"
-#include "hmac-sha1.h"
+#include "hmac.h"
+#include "sha1.h"
 #include "randgen.h"
 #include "safe-memset.h"
 #include "mail-storage.h"
@@ -88,15 +89,15 @@
 			       const unsigned char mailbox_key[IMAP_URLAUTH_KEY_LEN],
 			       size_t *token_len_r)
 {
-	struct hmac_sha1_context hmac;
+	struct hmac_context hmac;
 	unsigned char *token;
 
 	token = t_new(unsigned char, SHA1_RESULTLEN + 1);
 	token[0] = IMAP_URLAUTH_MECH_INTERNAL_VERSION;
 
-	hmac_sha1_init(&hmac, mailbox_key, IMAP_URLAUTH_KEY_LEN);
-	hmac_sha1_update(&hmac, rumpurl, strlen(rumpurl));
-	hmac_sha1_final(&hmac, token+1);
+	hmac_init(&hmac, mailbox_key, IMAP_URLAUTH_KEY_LEN, &hash_method_sha1);
+	hmac_update(&hmac, rumpurl, strlen(rumpurl));
+	hmac_final(&hmac, token+1);
 
 	*token_len_r = SHA1_RESULTLEN + 1;
 	return token;
diff --git a/src/lib-ntlm/ntlm-encrypt.c b/src/lib-ntlm/ntlm-encrypt.c
--- a/src/lib-ntlm/ntlm-encrypt.c
+++ b/src/lib-ntlm/ntlm-encrypt.c
@@ -11,7 +11,8 @@
 #include "compat.h"
 #include "safe-memset.h"
 #include "md4.h"
-#include "hmac-md5.h"
+#include "md5.h"
+#include "hmac.h"
 #include "ntlm.h"
 #include "ntlm-des.h"
 
@@ -60,12 +61,12 @@
 }
 
 static void
-hmac_md5_ucs2le_string_ucase(struct hmac_md5_context *ctx, const char *str)
+hmac_md5_ucs2le_string_ucase(struct hmac_context *ctx, const char *str)
 {
 	size_t len;
 	unsigned char *wstr = t_unicode_str(str, 1, &len);
 
-	hmac_md5_update(ctx, wstr, len);
+	hmac_update(ctx, wstr, len);
 }
 
 static void ATTR_NULL(2)
@@ -73,13 +74,13 @@
 	     const unsigned char *hash_v1,
 	     unsigned char hash[NTLMSSP_V2_HASH_SIZE])
 {
-	struct hmac_md5_context ctx;
+	struct hmac_context ctx;
 
-	hmac_md5_init(&ctx, hash_v1, NTLMSSP_HASH_SIZE);
+	hmac_init(&ctx, hash_v1, NTLMSSP_HASH_SIZE, &hash_method_md5);
 	hmac_md5_ucs2le_string_ucase(&ctx, user);
 	if (target != NULL)
 		hmac_md5_ucs2le_string_ucase(&ctx, target);
-	hmac_md5_final(&ctx, hash);
+	hmac_final(&ctx, hash);
 }
 
 void
@@ -124,15 +125,15 @@
 		    const unsigned char *blob, size_t blob_size,
 		    unsigned char response[NTLMSSP_V2_RESPONSE_SIZE])
 {
-	struct hmac_md5_context ctx;
+	struct hmac_context ctx;
 	unsigned char hash[NTLMSSP_V2_HASH_SIZE];
 
 	ntlm_v2_hash(user, target, hash_v1, hash);
 
-	hmac_md5_init(&ctx, hash, NTLMSSP_V2_HASH_SIZE);
-	hmac_md5_update(&ctx, challenge, NTLMSSP_CHALLENGE_SIZE);
-	hmac_md5_update(&ctx, blob, blob_size);
-	hmac_md5_final(&ctx, response);
+	hmac_init(&ctx, hash, NTLMSSP_V2_HASH_SIZE, &hash_method_md5);
+	hmac_update(&ctx, challenge, NTLMSSP_CHALLENGE_SIZE);
+	hmac_update(&ctx, blob, blob_size);
+	hmac_final(&ctx, response);
 
 	safe_memset(hash, 0, sizeof(hash));
 }
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -44,8 +44,8 @@
 	hash2.c \
 	hex-binary.c \
 	hex-dec.c \
-	hmac-md5.c \
-	hmac-sha1.c \
+	hmac.c \
+	hmac-cram-md5.c \
 	home-expand.c \
 	hostpid.c \
 	imem.c \
@@ -170,8 +170,8 @@
 	hash2.h \
 	hex-binary.h \
 	hex-dec.h \
-	hmac-md5.h \
-	hmac-sha1.h \
+	hmac.h \
+	hmac-cram-md5.h \
 	home-expand.h \
 	hostpid.h \
 	imem.h \
diff --git a/src/lib/hmac-cram-md5.c b/src/lib/hmac-cram-md5.c
new file mode 100644
--- /dev/null
+++ b/src/lib/hmac-cram-md5.c
@@ -0,0 +1,63 @@
+/*
+ * CRAM-MD5 (RFC 2195) compatibility code
+ * Copyright (c) 2003 Joshua Goodall <joshua at roughtrade.net>
+ *
+ * This software is released under the MIT license.
+ */
+
+#include "lib.h"
+#include "md5.h"
+#include "hmac-cram-md5.h"
+
+void hmac_md5_get_cram_context(struct hmac_context *hmac_ctx,
+			unsigned char context_digest[CRAM_MD5_CONTEXTLEN])
+{
+	unsigned char *cdp;
+
+	struct md5_context *ctx = (void*)hmac_ctx->ctx;
+	struct md5_context *ctxo = (void*)hmac_ctx->ctxo;
+
+#define CDPUT(p, c) STMT_START {   \
+	*(p)++ = (c) & 0xff;       \
+	*(p)++ = (c) >> 8 & 0xff;  \
+	*(p)++ = (c) >> 16 & 0xff; \
+	*(p)++ = (c) >> 24 & 0xff; \
+} STMT_END
+	cdp = context_digest;
+	CDPUT(cdp, ctxo->a);
+	CDPUT(cdp, ctxo->b);
+	CDPUT(cdp, ctxo->c);
+	CDPUT(cdp, ctxo->d);
+	CDPUT(cdp, ctx->a);
+	CDPUT(cdp, ctx->b);
+	CDPUT(cdp, ctx->c);
+	CDPUT(cdp, ctx->d);
+}
+
+void hmac_md5_set_cram_context(struct hmac_context *hmac_ctx,
+			const unsigned char context_digest[CRAM_MD5_CONTEXTLEN])
+{
+	const unsigned char *cdp;
+
+	struct md5_context *ctx = (void*)hmac_ctx->ctx;
+	struct md5_context *ctxo = (void*)hmac_ctx->ctxo;
+
+#define CDGET(p, c) STMT_START { \
+	(c)  = (*p++);           \
+	(c) += (*p++ << 8);      \
+	(c) += (*p++ << 16);     \
+	(c) += (*p++ << 24);     \
+} STMT_END
+	cdp = context_digest;
+	CDGET(cdp, ctxo->a);
+	CDGET(cdp, ctxo->b);
+	CDGET(cdp, ctxo->c);
+	CDGET(cdp, ctxo->d);
+	CDGET(cdp, ctx->a);
+	CDGET(cdp, ctx->b);
+	CDGET(cdp, ctx->c);
+	CDGET(cdp, ctx->d);
+
+	ctxo->lo = ctx->lo = 64;
+	ctxo->hi = ctx->hi = 0;
+}
diff --git a/src/lib/hmac-cram-md5.h b/src/lib/hmac-cram-md5.h
new file mode 100644
--- /dev/null
+++ b/src/lib/hmac-cram-md5.h
@@ -0,0 +1,14 @@
+#ifndef HMAC_CRAM_MD5_H
+#define HMAC_CRAM_MD5_H
+
+#include "hmac.h"
+
+#define CRAM_MD5_CONTEXTLEN 32
+
+void hmac_md5_get_cram_context(struct hmac_context *ctx,
+		unsigned char context_digest[CRAM_MD5_CONTEXTLEN]);
+void hmac_md5_set_cram_context(struct hmac_context *ctx,
+		const unsigned char context_digest[CRAM_MD5_CONTEXTLEN]);
+
+
+#endif
diff --git a/src/lib/hmac-md5.c b/src/lib/hmac-md5.c
deleted file mode 100644
--- a/src/lib/hmac-md5.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * HMAC-MD5 (RFC-2104) implementation.
- *
- * Copyright (c) 2004 Andrey Panin <pazke at donpac.ru>
- *
- * CRAM-MD5 (RFC 2195) compatibility code
- * Copyright (c) 2003 Joshua Goodall <joshua at roughtrade.net>
- *
- * This software is released under the MIT license.
- */
-
-#include "lib.h"
-#include "hmac-md5.h"
-#include "safe-memset.h"
-
-void hmac_md5_init(struct hmac_md5_context *ctx,
-		   const unsigned char *key, size_t key_len)
-{
-	int i;
-	unsigned char md5key[16];
-	unsigned char k_ipad[64];
-	unsigned char k_opad[64];
-
-	if (key_len > 64) {
-		md5_get_digest(key, key_len, md5key);
-		key = md5key;
-		key_len = 16;
-	}
-
-	memcpy(k_ipad, key, key_len);
-	memset(k_ipad + key_len, 0, 64 - key_len);
-	memcpy(k_opad, k_ipad, 64);
-
-	for (i = 0; i < 64; i++) {
-		k_ipad[i] ^= 0x36;
-		k_opad[i] ^= 0x5c;
-	}
-
-	md5_init(&ctx->ctx);
-	md5_update(&ctx->ctx, k_ipad, 64);  
-	md5_init(&ctx->ctxo);
-	md5_update(&ctx->ctxo, k_opad, 64);   
-
-	safe_memset(k_ipad, 0, 64);
-	safe_memset(k_opad, 0, 64);
-}
-
-void hmac_md5_final(struct hmac_md5_context *ctx, unsigned char *digest)
-{
-	md5_final(&ctx->ctx, digest);
-
-	md5_update(&ctx->ctxo, digest, 16); 
-	md5_final(&ctx->ctxo, digest);
-}
-
-void hmac_md5_get_cram_context(struct hmac_md5_context *ctx,
-			unsigned char context_digest[CRAM_MD5_CONTEXTLEN])
-{
-	unsigned char *cdp;
-
-#define CDPUT(p, c) STMT_START {   \
-	*(p)++ = (c) & 0xff;       \
-	*(p)++ = (c) >> 8 & 0xff;  \
-	*(p)++ = (c) >> 16 & 0xff; \
-	*(p)++ = (c) >> 24 & 0xff; \
-} STMT_END
-	cdp = context_digest;
-	CDPUT(cdp, ctx->ctxo.a);
-	CDPUT(cdp, ctx->ctxo.b);
-	CDPUT(cdp, ctx->ctxo.c);
-	CDPUT(cdp, ctx->ctxo.d);
-	CDPUT(cdp, ctx->ctx.a);
-	CDPUT(cdp, ctx->ctx.b);
-	CDPUT(cdp, ctx->ctx.c);
-	CDPUT(cdp, ctx->ctx.d);
-}
-
-void hmac_md5_set_cram_context(struct hmac_md5_context *ctx,
-			const unsigned char context_digest[CRAM_MD5_CONTEXTLEN])
-{
-	const unsigned char *cdp;
-
-#define CDGET(p, c) STMT_START { \
-	(c)  = (*p++);           \
-	(c) += (*p++ << 8);      \
-	(c) += (*p++ << 16);     \
-	(c) += (*p++ << 24);     \
-} STMT_END
-	cdp = context_digest;
-	CDGET(cdp, ctx->ctxo.a);
-	CDGET(cdp, ctx->ctxo.b);
-	CDGET(cdp, ctx->ctxo.c);
-	CDGET(cdp, ctx->ctxo.d);
-	CDGET(cdp, ctx->ctx.a);
-	CDGET(cdp, ctx->ctx.b);
-	CDGET(cdp, ctx->ctx.c);
-	CDGET(cdp, ctx->ctx.d);
-
-	ctx->ctxo.lo = ctx->ctx.lo = 64;
-	ctx->ctxo.hi = ctx->ctx.hi = 0;
-}
diff --git a/src/lib/hmac-md5.h b/src/lib/hmac-md5.h
deleted file mode 100644
--- a/src/lib/hmac-md5.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef HMAC_MD5_H
-#define HMAC_MD5_H
-
-#include "md5.h"
-
-#define CRAM_MD5_CONTEXTLEN 32
-
-struct hmac_md5_context {
-	struct md5_context ctx, ctxo;
-};
-
-void hmac_md5_init(struct hmac_md5_context *ctx,
-		   const unsigned char *key, size_t key_len);
-void hmac_md5_final(struct hmac_md5_context *ctx,
-		    unsigned char digest[MD5_RESULTLEN]);
-
-void hmac_md5_get_cram_context(struct hmac_md5_context *ctx,
-		unsigned char context_digest[CRAM_MD5_CONTEXTLEN]);
-void hmac_md5_set_cram_context(struct hmac_md5_context *ctx,
-		const unsigned char context_digest[CRAM_MD5_CONTEXTLEN]);
-
-
-static inline void
-hmac_md5_update(struct hmac_md5_context *ctx, const void *data, size_t size)
-{
-	md5_update(&ctx->ctx, data, size);
-}
-
-#endif
diff --git a/src/lib/hmac-sha1.c b/src/lib/hmac-sha1.c
deleted file mode 100644
--- a/src/lib/hmac-sha1.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * HMAC-SHA1 (RFC-2104) implementation.
- *
- * Copyright (c) 2004 Andrey Panin <pazke at donpac.ru>
- * Copyright (c) 2011 Florian Zeitz <florob at babelmonkeys.de>
- *
- * This software is released under the MIT license.
- */
-
-#include "lib.h"
-#include "hmac-sha1.h"
-#include "safe-memset.h"
-
-void hmac_sha1_init(struct hmac_sha1_context *ctx,
-		    const void *key, size_t key_len)
-{
-	int i;
-	unsigned char sha1key[20];
-	unsigned char k_ipad[64];
-	unsigned char k_opad[64];
-
-	if (key_len > 64) {
-		sha1_get_digest(key, key_len, sha1key);
-		key = sha1key;
-		key_len = 20;
-	}
-
-	memcpy(k_ipad, key, key_len);
-	memset(k_ipad + key_len, 0, 64 - key_len);
-	memcpy(k_opad, k_ipad, 64);
-
-	for (i = 0; i < 64; i++) {
-		k_ipad[i] ^= 0x36;
-		k_opad[i] ^= 0x5c;
-	}
-
-	sha1_init(&ctx->ctx);
-	sha1_loop(&ctx->ctx, k_ipad, 64);
-	sha1_init(&ctx->ctxo);
-	sha1_loop(&ctx->ctxo, k_opad, 64);
-
-	safe_memset(k_ipad, 0, 64);
-	safe_memset(k_opad, 0, 64);
-}
-
-void hmac_sha1_final(struct hmac_sha1_context *ctx, unsigned char *digest)
-{
-	sha1_result(&ctx->ctx, digest);
-
-	sha1_loop(&ctx->ctxo, digest, 20);
-	sha1_result(&ctx->ctxo, digest);
-}
diff --git a/src/lib/hmac-sha1.h b/src/lib/hmac-sha1.h
deleted file mode 100644
--- a/src/lib/hmac-sha1.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef HMAC_SHA1_H
-#define HMAC_SHA1_H
-
-#include "sha1.h"
-
-struct hmac_sha1_context {
-	struct sha1_ctxt ctx, ctxo;
-};
-
-void hmac_sha1_init(struct hmac_sha1_context *ctx,
-		    const void *key, size_t key_len);
-void hmac_sha1_final(struct hmac_sha1_context *ctx,
-		     unsigned char digest[SHA1_RESULTLEN]);
-
-
-static inline void
-hmac_sha1_update(struct hmac_sha1_context *ctx, const void *data, size_t size)
-{
-	sha1_loop(&ctx->ctx, data, size);
-}
-
-#endif
diff --git a/src/lib/hmac.c b/src/lib/hmac.c
new file mode 100644
--- /dev/null
+++ b/src/lib/hmac.c
@@ -0,0 +1,58 @@
+/*
+ * HMAC (RFC-2104) implementation.
+ *
+ * Copyright (c) 2004 Andrey Panin <pazke at donpac.ru>
+ * Copyright (c) 2011-2012 Florian Zeitz <florob at babelmonkeys.de>
+ *
+ * This software is released under the MIT license.
+ */
+
+#include "lib.h"
+#include "hmac.h"
+#include "safe-memset.h"
+
+void hmac_init(struct hmac_context *ctx, const unsigned char *key,
+		size_t key_len, const struct hash_method *meth)
+{
+	int i;
+	unsigned char k_ipad[64];
+	unsigned char k_opad[64];
+	unsigned char hashedkey[meth->digest_size];
+
+	i_assert(meth->context_size <= HMAC_MAX_CONTEXT_SIZE);
+
+	ctx->hash = meth;
+
+	if (key_len > 64) {
+		meth->init(ctx->ctx);
+		meth->loop(ctx->ctx, key, key_len);
+		meth->result(ctx->ctx, hashedkey);
+		key = hashedkey;
+		key_len = meth->digest_size;
+	}
+
+	memcpy(k_ipad, key, key_len);
+	memset(k_ipad + key_len, 0, 64 - key_len);
+	memcpy(k_opad, k_ipad, 64);
+
+	for (i = 0; i < 64; i++) {
+		k_ipad[i] ^= 0x36;
+		k_opad[i] ^= 0x5c;
+	}
+
+	meth->init(ctx->ctx);
+	meth->loop(ctx->ctx, k_ipad, 64);
+	meth->init(ctx->ctxo);
+	meth->loop(ctx->ctxo, k_opad, 64);
+
+	safe_memset(k_ipad, 0, 64);
+	safe_memset(k_opad, 0, 64);
+}
+
+void hmac_final(struct hmac_context *ctx, unsigned char *digest)
+{
+	ctx->hash->result(ctx->ctx, digest);
+
+	ctx->hash->loop(ctx->ctxo, digest, ctx->hash->digest_size);
+	ctx->hash->result(ctx->ctxo, digest);
+}
diff --git a/src/lib/hmac.h b/src/lib/hmac.h
new file mode 100644
--- /dev/null
+++ b/src/lib/hmac.h
@@ -0,0 +1,26 @@
+#ifndef HMAC_H
+#define HMAC_H
+
+#include "hash-method.h"
+#include "sha1.h"
+
+#define HMAC_MAX_CONTEXT_SIZE (1024 / 8)
+
+struct hmac_context {
+	char ctx[HMAC_MAX_CONTEXT_SIZE];
+	char ctxo[HMAC_MAX_CONTEXT_SIZE];
+	const struct hash_method *hash;
+};
+
+void hmac_init(struct hmac_context *ctx, const unsigned char *key,
+		size_t key_len, const struct hash_method *meth);
+void hmac_final(struct hmac_context *ctx, unsigned char *digest);
+
+
+static inline void
+hmac_update(struct hmac_context *ctx, const void *data, size_t size)
+{
+	ctx->hash->loop(ctx->ctx, data, size);
+}
+
+#endif


More information about the dovecot mailing list