blob: 212567fad20716a2c78e09c4ac383d6c53889c1e [file] [log] [blame]
/**
* @file openssl/hmac.c HMAC using OpenSSL
*
* Copyright (C) 2010 Creytiv.com
*/
#include <openssl/hmac.h>
#include <openssl/err.h>
#include <re_types.h>
#include <re_mem.h>
#include <re_hmac.h>
struct hmac {
HMAC_CTX *ctx;
};
static void destructor(void *arg)
{
struct hmac *hmac = arg;
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
!defined(LIBRESSL_VERSION_NUMBER)
if (hmac->ctx)
HMAC_CTX_free(hmac->ctx);
#else
if (hmac->ctx)
HMAC_CTX_cleanup(hmac->ctx);
mem_deref(hmac->ctx);
#endif
}
int hmac_create(struct hmac **hmacp, enum hmac_hash hash,
const uint8_t *key, size_t key_len)
{
struct hmac *hmac;
const EVP_MD *evp;
int err = 0;
if (!hmacp || !key || !key_len)
return EINVAL;
switch (hash) {
case HMAC_HASH_SHA1:
evp = EVP_sha1();
break;
case HMAC_HASH_SHA256:
evp = EVP_sha256();
break;
default:
return ENOTSUP;
}
hmac = mem_zalloc(sizeof(*hmac), destructor);
if (!hmac)
return ENOMEM;
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
!defined(LIBRESSL_VERSION_NUMBER)
hmac->ctx = HMAC_CTX_new();
if (!hmac->ctx) {
ERR_clear_error();
err = ENOMEM;
goto out;
}
#else
hmac->ctx = mem_zalloc(sizeof(*hmac->ctx), NULL);
if (!hmac->ctx) {
err = ENOMEM;
goto out;
}
HMAC_CTX_init(hmac->ctx);
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x00909000)
if (!HMAC_Init_ex(hmac->ctx, key, (int)key_len, evp, NULL)) {
ERR_clear_error();
err = EPROTO;
}
#else
HMAC_Init_ex(hmac->ctx, key, (int)key_len, evp, NULL);
#endif
out:
if (err)
mem_deref(hmac);
else
*hmacp = hmac;
return err;
}
int hmac_digest(struct hmac *hmac, uint8_t *md, size_t md_len,
const uint8_t *data, size_t data_len)
{
unsigned int len = (unsigned int)md_len;
if (!hmac || !md || !md_len || !data || !data_len)
return EINVAL;
#if (OPENSSL_VERSION_NUMBER >= 0x00909000)
/* the HMAC context must be reset here */
if (!HMAC_Init_ex(hmac->ctx, 0, 0, 0, NULL))
goto error;
if (!HMAC_Update(hmac->ctx, data, (int)data_len))
goto error;
if (!HMAC_Final(hmac->ctx, md, &len))
goto error;
return 0;
error:
ERR_clear_error();
return EPROTO;
#else
/* the HMAC context must be reset here */
HMAC_Init_ex(hmac->ctx, 0, 0, 0, NULL);
HMAC_Update(hmac->ctx, data, (int)data_len);
HMAC_Final(hmac->ctx, md, &len);
return 0;
#endif
}