# HG changeset patch # User Florian Zeitz # Date 1346280236 -7200 # Node ID e2f682fab829c2ef23a050f884191f57e2fb5d60 # Parent 9bc2e718392ceaa327f14b50163232b629cd54d1 lib: Generalize hmac to be hash independent 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-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,64 @@ +/* + * CRAM-MD5 (RFC 2195) compatibility code + * Copyright (c) 2003 Joshua Goodall + * + * This software is released under the MIT license. + */ + +#include "lib.h" +#include "md5.h" +#include "hmac.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 = hmac_ctx->ctx; + struct md5_context *ctxo = 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 = hmac_ctx->ctx; + struct md5_context *ctxo = 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,12 @@ +#ifndef HMAC_CRAM_MD5_H +#define HMAC_CRAM_MD5_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 - * - * CRAM-MD5 (RFC 2195) compatibility code - * Copyright (c) 2003 Joshua Goodall - * - * 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 - * Copyright (c) 2011 Florian Zeitz - * - * 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 unsigned char *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 unsigned char *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 + * Copyright (c) 2011-2012 Florian Zeitz + * + * 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]; + + ctx->hash = meth; + ctx->ctx = t_malloc(meth->context_size); + ctx->ctxo = t_malloc(meth->context_size); + + 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,23 @@ +#ifndef HMAC_H +#define HMAC_H + +#include "hash-method.h" +#include "sha1.h" + +struct hmac_context { + void *ctx, *ctxo; + 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