1 /* $OpenBSD: prf.c,v 1.15 2005/04/08 22:32:10 cloder Exp $	 */
2 /* $EOM: prf.c,v 1.7 1999/05/02 12:50:29 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/param.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 #include "hash.h"
38 #include "log.h"
39 #include "prf.h"
40 
41 void	prf_hash_init(struct prf_hash_ctx *);
42 void	prf_hash_update(struct prf_hash_ctx *, unsigned char *, unsigned int);
43 void	prf_hash_final(unsigned char *, struct prf_hash_ctx *);
44 
45 /* PRF behaves likes a hash */
46 
47 void
prf_hash_init(struct prf_hash_ctx * ctx)48 prf_hash_init(struct prf_hash_ctx *ctx)
49 {
50 	memcpy(ctx->hash->ctx, ctx->ctx, ctx->hash->ctxsize);
51 	memcpy(ctx->hash->ctx2, ctx->ctx2, ctx->hash->ctxsize);
52 }
53 
54 void
prf_hash_update(struct prf_hash_ctx * ctx,unsigned char * data,unsigned int len)55 prf_hash_update(struct prf_hash_ctx *ctx, unsigned char *data,
56     unsigned int len)
57 {
58 	ctx->hash->Update(ctx->hash->ctx, data, len);
59 }
60 
61 void
prf_hash_final(unsigned char * digest,struct prf_hash_ctx * ctx)62 prf_hash_final(unsigned char *digest, struct prf_hash_ctx *ctx)
63 {
64 	ctx->hash->HMACFinal(digest, ctx->hash);
65 }
66 
67 /*
68  * Obtain a Pseudo-Random Function for us. At the moment this is
69  * the HMAC version of a hash. See RFC-2104 for reference.
70  */
71 struct prf *
prf_alloc(enum prfs type,int subtype,unsigned char * shared,unsigned int sharedsize)72 prf_alloc(enum prfs type, int subtype, unsigned char *shared,
73     unsigned int sharedsize)
74 {
75 	struct hash    *hash;
76 	struct prf     *prf;
77 	struct prf_hash_ctx *prfctx;
78 
79 	switch (type) {
80 	case PRF_HMAC:
81 		hash = hash_get(subtype);
82 		if (!hash) {
83 			log_print("prf_alloc: unknown hash type %d", subtype);
84 			return 0;
85 		}
86 		break;
87 	default:
88 		log_print("prf_alloc: unknown PRF type %d", type);
89 		return 0;
90 	}
91 
92 	prf = malloc(sizeof *prf);
93 	if (!prf) {
94 		log_error("prf_alloc: malloc (%lu) failed",
95 		    (unsigned long)sizeof *prf);
96 		return 0;
97 	}
98 	if (type == PRF_HMAC) {
99 		/* Obtain needed memory.  */
100 		prfctx = malloc(sizeof *prfctx);
101 		if (!prfctx) {
102 			log_error("prf_alloc: malloc (%lu) failed",
103 			    (unsigned long)sizeof *prfctx);
104 			goto cleanprf;
105 		}
106 		prf->prfctx = prfctx;
107 
108 		prfctx->ctx = malloc(hash->ctxsize);
109 		if (!prfctx->ctx) {
110 			log_error("prf_alloc: malloc (%d) failed",
111 			    hash->ctxsize);
112 			goto cleanprfctx;
113 		}
114 		prfctx->ctx2 = malloc(hash->ctxsize);
115 		if (!prfctx->ctx2) {
116 			log_error("prf_alloc: malloc (%d) failed",
117 			    hash->ctxsize);
118 			free(prfctx->ctx);
119 			goto cleanprfctx;
120 		}
121 		prf->type = PRF_HMAC;
122 		prf->blocksize = hash->hashsize;
123 		prfctx->hash = hash;
124 
125 		/* Use the correct function pointers.  */
126 		prf->Init = (void(*)(void *))prf_hash_init;
127 		prf->Update = (void(*)(void *, unsigned char *,
128 		    unsigned int))prf_hash_update;
129 		prf->Final = (void(*)(unsigned char *, void *))prf_hash_final;
130 
131 		/* Init HMAC contexts.  */
132 		hash->HMACInit(hash, shared, sharedsize);
133 
134 		/* Save contexts.  */
135 		memcpy(prfctx->ctx, hash->ctx, hash->ctxsize);
136 		memcpy(prfctx->ctx2, hash->ctx2, hash->ctxsize);
137 	}
138 	return prf;
139 
140 cleanprfctx:
141 	free(prf->prfctx);
142 cleanprf:
143 	free(prf);
144 	return 0;
145 }
146 
147 /* Deallocate the PRF pointed to by PRF.  */
148 void
prf_free(struct prf * prf)149 prf_free(struct prf *prf)
150 {
151 	struct prf_hash_ctx *prfctx = prf->prfctx;
152 
153 	if (prf->type == PRF_HMAC) {
154 		free(prfctx->ctx2);
155 		free(prfctx->ctx);
156 	}
157 	free(prf->prfctx);
158 	free(prf);
159 }
160