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