1*82bad92dSderaadt /* $OpenBSD: prf.c,v 1.16 2013/03/21 04:30:14 deraadt Exp $ */
206f41d32Sniklas /* $EOM: prf.c,v 1.7 1999/05/02 12:50:29 niklas Exp $ */
32040585eSniklas
42040585eSniklas /*
5eb840acdSniklas * Copyright (c) 1998 Niels Provos. All rights reserved.
6eb840acdSniklas * Copyright (c) 1999 Niklas Hallqvist. All rights reserved.
72040585eSniklas *
82040585eSniklas * Redistribution and use in source and binary forms, with or without
92040585eSniklas * modification, are permitted provided that the following conditions
102040585eSniklas * are met:
112040585eSniklas * 1. Redistributions of source code must retain the above copyright
122040585eSniklas * notice, this list of conditions and the following disclaimer.
132040585eSniklas * 2. Redistributions in binary form must reproduce the above copyright
142040585eSniklas * notice, this list of conditions and the following disclaimer in the
152040585eSniklas * documentation and/or other materials provided with the distribution.
162040585eSniklas *
172040585eSniklas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
182040585eSniklas * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
192040585eSniklas * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
202040585eSniklas * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
212040585eSniklas * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
222040585eSniklas * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232040585eSniklas * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242040585eSniklas * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252040585eSniklas * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
262040585eSniklas * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272040585eSniklas */
282040585eSniklas
292040585eSniklas /*
302040585eSniklas * This code was written under funding by Ericsson Radio Systems.
312040585eSniklas */
322040585eSniklas
332040585eSniklas #include <stdlib.h>
342040585eSniklas #include <string.h>
352040585eSniklas
362040585eSniklas #include "hash.h"
372040585eSniklas #include "log.h"
382040585eSniklas #include "prf.h"
392040585eSniklas
402040585eSniklas void prf_hash_init(struct prf_hash_ctx *);
412040585eSniklas void prf_hash_update(struct prf_hash_ctx *, unsigned char *, unsigned int);
422040585eSniklas void prf_hash_final(unsigned char *, struct prf_hash_ctx *);
432040585eSniklas
442040585eSniklas /* PRF behaves likes a hash */
452040585eSniklas
462040585eSniklas void
prf_hash_init(struct prf_hash_ctx * ctx)472040585eSniklas prf_hash_init(struct prf_hash_ctx *ctx)
482040585eSniklas {
492040585eSniklas memcpy(ctx->hash->ctx, ctx->ctx, ctx->hash->ctxsize);
502040585eSniklas memcpy(ctx->hash->ctx2, ctx->ctx2, ctx->hash->ctxsize);
512040585eSniklas }
522040585eSniklas
532040585eSniklas void
prf_hash_update(struct prf_hash_ctx * ctx,unsigned char * data,unsigned int len)542040585eSniklas prf_hash_update(struct prf_hash_ctx *ctx, unsigned char *data,
552040585eSniklas unsigned int len)
562040585eSniklas {
572040585eSniklas ctx->hash->Update(ctx->hash->ctx, data, len);
582040585eSniklas }
592040585eSniklas
602040585eSniklas void
prf_hash_final(unsigned char * digest,struct prf_hash_ctx * ctx)612040585eSniklas prf_hash_final(unsigned char *digest, struct prf_hash_ctx *ctx)
622040585eSniklas {
632040585eSniklas ctx->hash->HMACFinal(digest, ctx->hash);
642040585eSniklas }
652040585eSniklas
662040585eSniklas /*
672040585eSniklas * Obtain a Pseudo-Random Function for us. At the moment this is
682040585eSniklas * the HMAC version of a hash. See RFC-2104 for reference.
692040585eSniklas */
702040585eSniklas struct prf *
prf_alloc(enum prfs type,int subtype,unsigned char * shared,unsigned int sharedsize)71f1d529f7Sho prf_alloc(enum prfs type, int subtype, unsigned char *shared,
72f1d529f7Sho unsigned int sharedsize)
732040585eSniklas {
742040585eSniklas struct hash *hash;
752040585eSniklas struct prf *prf;
760568d6daSniklas struct prf_hash_ctx *prfctx;
772040585eSniklas
78fb9475d6Sderaadt switch (type) {
792040585eSniklas case PRF_HMAC:
802040585eSniklas hash = hash_get(subtype);
81fb9475d6Sderaadt if (!hash) {
8206f41d32Sniklas log_print("prf_alloc: unknown hash type %d", subtype);
830568d6daSniklas return 0;
8406f41d32Sniklas }
852040585eSniklas break;
862040585eSniklas default:
870568d6daSniklas log_print("prf_alloc: unknown PRF type %d", type);
880568d6daSniklas return 0;
892040585eSniklas }
902040585eSniklas
910568d6daSniklas prf = malloc(sizeof *prf);
92fb9475d6Sderaadt if (!prf) {
93fb9475d6Sderaadt log_error("prf_alloc: malloc (%lu) failed",
94fb9475d6Sderaadt (unsigned long)sizeof *prf);
950568d6daSniklas return 0;
962040585eSniklas }
97fb9475d6Sderaadt if (type == PRF_HMAC) {
980568d6daSniklas /* Obtain needed memory. */
990568d6daSniklas prfctx = malloc(sizeof *prfctx);
100fb9475d6Sderaadt if (!prfctx) {
1010cd3ca40Sho log_error("prf_alloc: malloc (%lu) failed",
1020cd3ca40Sho (unsigned long)sizeof *prfctx);
1032040585eSniklas goto cleanprf;
1042040585eSniklas }
1052040585eSniklas prf->prfctx = prfctx;
1062040585eSniklas
1072040585eSniklas prfctx->ctx = malloc(hash->ctxsize);
108fb9475d6Sderaadt if (!prfctx->ctx) {
10912f43dabShshoexer log_error("prf_alloc: malloc (%d) failed",
11012f43dabShshoexer hash->ctxsize);
1112040585eSniklas goto cleanprfctx;
1122040585eSniklas }
1132040585eSniklas prfctx->ctx2 = malloc(hash->ctxsize);
114fb9475d6Sderaadt if (!prfctx->ctx2) {
11512f43dabShshoexer log_error("prf_alloc: malloc (%d) failed",
11612f43dabShshoexer hash->ctxsize);
1172040585eSniklas free(prfctx->ctx);
1182040585eSniklas goto cleanprfctx;
1192040585eSniklas }
1202040585eSniklas prf->type = PRF_HMAC;
1212040585eSniklas prf->blocksize = hash->hashsize;
1222040585eSniklas prfctx->hash = hash;
1232040585eSniklas
1240568d6daSniklas /* Use the correct function pointers. */
1252040585eSniklas prf->Init = (void(*)(void *))prf_hash_init;
126fb9475d6Sderaadt prf->Update = (void(*)(void *, unsigned char *,
127fb9475d6Sderaadt unsigned int))prf_hash_update;
1282040585eSniklas prf->Final = (void(*)(unsigned char *, void *))prf_hash_final;
1292040585eSniklas
1300568d6daSniklas /* Init HMAC contexts. */
1312040585eSniklas hash->HMACInit(hash, shared, sharedsize);
1322040585eSniklas
1330568d6daSniklas /* Save contexts. */
1342040585eSniklas memcpy(prfctx->ctx, hash->ctx, hash->ctxsize);
1352040585eSniklas memcpy(prfctx->ctx2, hash->ctx2, hash->ctxsize);
1362040585eSniklas }
1372040585eSniklas return prf;
1382040585eSniklas
1392040585eSniklas cleanprfctx:
1402040585eSniklas free(prf->prfctx);
1412040585eSniklas cleanprf:
1422040585eSniklas free(prf);
1430568d6daSniklas return 0;
1442040585eSniklas }
1452040585eSniklas
1460568d6daSniklas /* Deallocate the PRF pointed to by PRF. */
1472040585eSniklas void
prf_free(struct prf * prf)1482040585eSniklas prf_free(struct prf *prf)
1492040585eSniklas {
1500568d6daSniklas struct prf_hash_ctx *prfctx = prf->prfctx;
1510568d6daSniklas
152fb9475d6Sderaadt if (prf->type == PRF_HMAC) {
1532040585eSniklas free(prfctx->ctx2);
1542040585eSniklas free(prfctx->ctx);
1552040585eSniklas }
1562040585eSniklas free(prf->prfctx);
1572040585eSniklas free(prf);
1582040585eSniklas }
159