1290001Sglebius/*
2290001Sglebius * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
3290001Sglebius * Copyright (C) 2000, 2001  Internet Software Consortium.
4290001Sglebius *
5290001Sglebius * Permission to use, copy, modify, and/or distribute this software for any
6290001Sglebius * purpose with or without fee is hereby granted, provided that the above
7290001Sglebius * copyright notice and this permission notice appear in all copies.
8290001Sglebius *
9290001Sglebius * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10290001Sglebius * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11290001Sglebius * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12290001Sglebius * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13290001Sglebius * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14290001Sglebius * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15290001Sglebius * PERFORMANCE OF THIS SOFTWARE.
16290001Sglebius */
17290001Sglebius
18290001Sglebius/* $Id: hmacmd5.c,v 1.16 2009/02/06 23:47:42 tbox Exp $ */
19290001Sglebius
20290001Sglebius/*! \file
21290001Sglebius * This code implements the HMAC-MD5 keyed hash algorithm
22290001Sglebius * described in RFC2104.
23290001Sglebius */
24290001Sglebius
25290001Sglebius#include "config.h"
26290001Sglebius
27290001Sglebius#include <isc/assertions.h>
28290001Sglebius#include <isc/hmacmd5.h>
29290001Sglebius#include <isc/md5.h>
30290001Sglebius#include <isc/platform.h>
31290001Sglebius#include <isc/string.h>
32290001Sglebius#include <isc/types.h>
33290001Sglebius#include <isc/util.h>
34290001Sglebius
35290001Sglebius#ifdef ISC_PLATFORM_OPENSSLHASH
36290001Sglebius
37290001Sglebiusvoid
38290001Sglebiusisc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
39290001Sglebius		 unsigned int len)
40290001Sglebius{
41290001Sglebius	HMAC_Init(ctx, (const void *) key, (int) len, EVP_md5());
42290001Sglebius}
43290001Sglebius
44290001Sglebiusvoid
45290001Sglebiusisc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
46290001Sglebius	HMAC_CTX_cleanup(ctx);
47290001Sglebius}
48290001Sglebius
49290001Sglebiusvoid
50290001Sglebiusisc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
51290001Sglebius		   unsigned int len)
52290001Sglebius{
53290001Sglebius	HMAC_Update(ctx, buf, (int) len);
54290001Sglebius}
55290001Sglebius
56290001Sglebiusvoid
57290001Sglebiusisc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
58290001Sglebius	HMAC_Final(ctx, digest, NULL);
59290001Sglebius	HMAC_CTX_cleanup(ctx);
60290001Sglebius}
61290001Sglebius
62290001Sglebius#else
63290001Sglebius
64290001Sglebius#define PADLEN 64
65290001Sglebius#define IPAD 0x36
66290001Sglebius#define OPAD 0x5C
67290001Sglebius
68290001Sglebius/*!
69290001Sglebius * Start HMAC-MD5 process.  Initialize an md5 context and digest the key.
70290001Sglebius */
71290001Sglebiusvoid
72290001Sglebiusisc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
73290001Sglebius		 unsigned int len)
74290001Sglebius{
75290001Sglebius	unsigned char ipad[PADLEN];
76290001Sglebius	int i;
77290001Sglebius
78290001Sglebius	memset(ctx->key, 0, sizeof(ctx->key));
79290001Sglebius	if (len > sizeof(ctx->key)) {
80290001Sglebius		isc_md5_t md5ctx;
81290001Sglebius		isc_md5_init(&md5ctx);
82290001Sglebius		isc_md5_update(&md5ctx, key, len);
83290001Sglebius		isc_md5_final(&md5ctx, ctx->key);
84290001Sglebius	} else
85290001Sglebius		memcpy(ctx->key, key, len);
86290001Sglebius
87290001Sglebius	isc_md5_init(&ctx->md5ctx);
88290001Sglebius	memset(ipad, IPAD, sizeof(ipad));
89290001Sglebius	for (i = 0; i < PADLEN; i++)
90290001Sglebius		ipad[i] ^= ctx->key[i];
91290001Sglebius	isc_md5_update(&ctx->md5ctx, ipad, sizeof(ipad));
92290001Sglebius}
93290001Sglebius
94290001Sglebiusvoid
95290001Sglebiusisc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
96290001Sglebius	isc_md5_invalidate(&ctx->md5ctx);
97290001Sglebius	memset(ctx->key, 0, sizeof(ctx->key));
98290001Sglebius}
99290001Sglebius
100290001Sglebius/*!
101290001Sglebius * Update context to reflect the concatenation of another buffer full
102290001Sglebius * of bytes.
103290001Sglebius */
104290001Sglebiusvoid
105290001Sglebiusisc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
106290001Sglebius		   unsigned int len)
107290001Sglebius{
108290001Sglebius	isc_md5_update(&ctx->md5ctx, buf, len);
109290001Sglebius}
110290001Sglebius
111290001Sglebius/*!
112290001Sglebius * Compute signature - finalize MD5 operation and reapply MD5.
113290001Sglebius */
114290001Sglebiusvoid
115290001Sglebiusisc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
116290001Sglebius	unsigned char opad[PADLEN];
117290001Sglebius	int i;
118290001Sglebius
119290001Sglebius	isc_md5_final(&ctx->md5ctx, digest);
120290001Sglebius
121290001Sglebius	memset(opad, OPAD, sizeof(opad));
122290001Sglebius	for (i = 0; i < PADLEN; i++)
123290001Sglebius		opad[i] ^= ctx->key[i];
124290001Sglebius
125290001Sglebius	isc_md5_init(&ctx->md5ctx);
126290001Sglebius	isc_md5_update(&ctx->md5ctx, opad, sizeof(opad));
127290001Sglebius	isc_md5_update(&ctx->md5ctx, digest, ISC_MD5_DIGESTLENGTH);
128290001Sglebius	isc_md5_final(&ctx->md5ctx, digest);
129290001Sglebius	isc_hmacmd5_invalidate(ctx);
130290001Sglebius}
131290001Sglebius#endif /* !ISC_PLATFORM_OPENSSLHASH */
132290001Sglebius
133290001Sglebius/*!
134290001Sglebius * Verify signature - finalize MD5 operation and reapply MD5, then
135290001Sglebius * compare to the supplied digest.
136290001Sglebius */
137290001Sglebiusisc_boolean_t
138290001Sglebiusisc_hmacmd5_verify(isc_hmacmd5_t *ctx, unsigned char *digest) {
139290001Sglebius	return (isc_hmacmd5_verify2(ctx, digest, ISC_MD5_DIGESTLENGTH));
140290001Sglebius}
141290001Sglebius
142290001Sglebiusisc_boolean_t
143290001Sglebiusisc_hmacmd5_verify2(isc_hmacmd5_t *ctx, unsigned char *digest, size_t len) {
144290001Sglebius	unsigned char newdigest[ISC_MD5_DIGESTLENGTH];
145290001Sglebius
146290001Sglebius	REQUIRE(len <= ISC_MD5_DIGESTLENGTH);
147290001Sglebius	isc_hmacmd5_sign(ctx, newdigest);
148298770Sdelphij	return (ISC_TF(isc_tsmemcmp(digest, newdigest, len) == 0));
149290001Sglebius}
150