1/* $OpenBSD: hash.c,v 1.24 2015/10/15 06:35:54 mmcc Exp $	 */
2/* $EOM: hash.c,v 1.10 1999/04/17 23:20:34 niklas Exp $	 */
3
4/*
5 * Copyright (c) 1998 Niels Provos.  All rights reserved.
6 * Copyright (c) 1999 Niklas Hallqvist.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * This code was written under funding by Ericsson Radio Systems.
31 */
32
33#include <sys/types.h>
34#include <string.h>
35#include <md5.h>
36#include <sha1.h>
37#include <sha2.h>
38
39#include "hash.h"
40#include "log.h"
41
42void	hmac_init(struct hash *, unsigned char *, unsigned int);
43void	hmac_final(unsigned char *, struct hash *);
44
45/* Temporary hash contexts.  */
46static union {
47	MD5_CTX		md5ctx;
48	SHA1_CTX        sha1ctx;
49	SHA2_CTX	sha2ctx;
50} Ctx, Ctx2;
51
52/* Temporary hash digest.  */
53static unsigned char digest[HASH_MAX];
54
55/* Encapsulation of hash functions.  */
56
57static struct hash hashes[] = {
58    {
59	HASH_MD5, 5, MD5_SIZE, (void *)&Ctx.md5ctx, digest,
60	sizeof(MD5_CTX), (void *)&Ctx2.md5ctx,
61	(void (*)(void *))MD5Init,
62	(void (*)(void *, unsigned char *, unsigned int))MD5Update,
63	(void (*)(unsigned char *, void *))MD5Final,
64	hmac_init,
65	hmac_final
66    }, {
67	HASH_SHA1, 6, SHA1_SIZE, (void *)&Ctx.sha1ctx, digest,
68	sizeof(SHA1_CTX), (void *)&Ctx2.sha1ctx,
69	(void (*)(void *))SHA1Init,
70	(void (*)(void *, unsigned char *, unsigned int))SHA1Update,
71	(void (*)(unsigned char *, void *))SHA1Final,
72	hmac_init,
73	hmac_final
74    }, {
75	HASH_SHA2_256, 7, SHA2_256_SIZE, (void *)&Ctx.sha2ctx, digest,
76	sizeof(SHA2_CTX), (void *)&Ctx2.sha2ctx,
77	(void (*)(void *))SHA256Init,
78	(void (*)(void *, unsigned char *, unsigned int))SHA256Update,
79	(void (*)(u_int8_t *, void *))SHA256Final,
80	hmac_init,
81	hmac_final
82    }, {
83	HASH_SHA2_384, 8, SHA2_384_SIZE, (void *)&Ctx.sha2ctx, digest,
84	sizeof(SHA2_CTX), (void *)&Ctx2.sha2ctx,
85	(void (*)(void *))SHA384Init,
86	(void (*)(void *, unsigned char *, unsigned int))SHA384Update,
87	(void (*)(u_int8_t *, void *))SHA384Final,
88	hmac_init,
89	hmac_final
90    }, {
91	HASH_SHA2_512, 9, SHA2_512_SIZE, (void *)&Ctx.sha2ctx, digest,
92	sizeof(SHA2_CTX), (void *)&Ctx2.sha2ctx,
93	(void (*)(void *))SHA512Init,
94	(void (*)(void *, unsigned char *, unsigned int))SHA512Update,
95	(void (*)(u_int8_t *, void *))SHA512Final,
96	hmac_init,
97	hmac_final
98    }
99};
100
101struct hash *
102hash_get(enum hashes hashtype)
103{
104	size_t	i;
105
106	LOG_DBG((LOG_CRYPTO, 60, "hash_get: requested algorithm %d",
107	    hashtype));
108
109	for (i = 0; i < sizeof hashes / sizeof hashes[0]; i++)
110		if (hashtype == hashes[i].type)
111			return &hashes[i];
112
113	return 0;
114}
115
116/*
117 * Initial a hash for HMAC usage this requires a special init function.
118 * ctx, ctx2 hold the contexts, if you want to use the hash object for
119 * something else in the meantime, be sure to store the contexts somewhere.
120 */
121
122void
123hmac_init(struct hash *hash, unsigned char *okey, unsigned int len)
124{
125	unsigned int    i, blocklen = HMAC_BLOCKLEN;
126	unsigned char   key[HMAC_BLOCKLEN];
127
128	bzero(key, blocklen);
129	if (len > blocklen) {
130		/* Truncate key down to blocklen */
131		hash->Init(hash->ctx);
132		hash->Update(hash->ctx, okey, len);
133		hash->Final(key, hash->ctx);
134	} else {
135		memcpy(key, okey, len);
136	}
137
138	/* HMAC I and O pad computation */
139	for (i = 0; i < blocklen; i++)
140		key[i] ^= HMAC_IPAD_VAL;
141
142	hash->Init(hash->ctx);
143	hash->Update(hash->ctx, key, blocklen);
144
145	for (i = 0; i < blocklen; i++)
146		key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
147
148	hash->Init(hash->ctx2);
149	hash->Update(hash->ctx2, key, blocklen);
150
151	explicit_bzero(key, blocklen);
152}
153
154/*
155 * HMAC Final function
156 */
157
158void
159hmac_final(unsigned char *dgst, struct hash *hash)
160{
161	hash->Final(dgst, hash->ctx);
162	hash->Update(hash->ctx2, dgst, hash->hashsize);
163	hash->Final(dgst, hash->ctx2);
164}
165