| /** |
| * @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 |
| } |