#include <stdlib.h>
#include <string.h>
#include "hash.h"
#include "log.h"
#include "prf.h"
void prf_hash_init(struct prf_hash_ctx *);
void prf_hash_update(struct prf_hash_ctx *, unsigned char *, unsigned int);
void prf_hash_final(unsigned char *, struct prf_hash_ctx *);
void
prf_hash_init(struct prf_hash_ctx *ctx)
{
memcpy(ctx->hash->ctx, ctx->ctx, ctx->hash->ctxsize);
memcpy(ctx->hash->ctx2, ctx->ctx2, ctx->hash->ctxsize);
}
void
prf_hash_update(struct prf_hash_ctx *ctx, unsigned char *data,
unsigned int len)
{
ctx->hash->Update(ctx->hash->ctx, data, len);
}
void
prf_hash_final(unsigned char *digest, struct prf_hash_ctx *ctx)
{
ctx->hash->HMACFinal(digest, ctx->hash);
}
struct prf *
prf_alloc(enum prfs type, int subtype, unsigned char *shared,
unsigned int sharedsize)
{
struct hash *hash;
struct prf *prf;
struct prf_hash_ctx *prfctx;
switch (type) {
case PRF_HMAC:
hash = hash_get(subtype);
if (!hash) {
log_print("prf_alloc: unknown hash type %d", subtype);
return 0;
}
break;
default:
log_print("prf_alloc: unknown PRF type %d", type);
return 0;
}
prf = malloc(sizeof *prf);
if (!prf) {
log_error("prf_alloc: malloc (%lu) failed",
(unsigned long)sizeof *prf);
return 0;
}
if (type == PRF_HMAC) {
prfctx = malloc(sizeof *prfctx);
if (!prfctx) {
log_error("prf_alloc: malloc (%lu) failed",
(unsigned long)sizeof *prfctx);
goto cleanprf;
}
prf->prfctx = prfctx;
prfctx->ctx = malloc(hash->ctxsize);
if (!prfctx->ctx) {
log_error("prf_alloc: malloc (%d) failed",
hash->ctxsize);
goto cleanprfctx;
}
prfctx->ctx2 = malloc(hash->ctxsize);
if (!prfctx->ctx2) {
log_error("prf_alloc: malloc (%d) failed",
hash->ctxsize);
free(prfctx->ctx);
goto cleanprfctx;
}
prf->type = PRF_HMAC;
prf->blocksize = hash->hashsize;
prfctx->hash = hash;
prf->Init = (void(*)(void *))prf_hash_init;
prf->Update = (void(*)(void *, unsigned char *,
unsigned int))prf_hash_update;
prf->Final = (void(*)(unsigned char *, void *))prf_hash_final;
hash->HMACInit(hash, shared, sharedsize);
memcpy(prfctx->ctx, hash->ctx, hash->ctxsize);
memcpy(prfctx->ctx2, hash->ctx2, hash->ctxsize);
}
return prf;
cleanprfctx:
free(prf->prfctx);
cleanprf:
free(prf);
return 0;
}
void
prf_free(struct prf *prf)
{
struct prf_hash_ctx *prfctx = prf->prfctx;
if (prf->type == PRF_HMAC) {
freezero(prfctx->ctx2, prfctx->hash->ctxsize);
freezero(prfctx->ctx, prfctx->hash->ctxsize);
}
free(prf->prfctx);
free(prf);
}