blob: 212567fad20716a2c78e09c4ac383d6c53889c1e [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file openssl/hmac.c HMAC using OpenSSL
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6
7#include <openssl/hmac.h>
8#include <openssl/err.h>
9#include <re_types.h>
10#include <re_mem.h>
11#include <re_hmac.h>
12
13
14struct hmac {
15 HMAC_CTX *ctx;
16};
17
18
19static void destructor(void *arg)
20{
21 struct hmac *hmac = arg;
22
23#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
24 !defined(LIBRESSL_VERSION_NUMBER)
25
26 if (hmac->ctx)
27 HMAC_CTX_free(hmac->ctx);
28#else
29 if (hmac->ctx)
30 HMAC_CTX_cleanup(hmac->ctx);
31 mem_deref(hmac->ctx);
32#endif
33}
34
35
36int hmac_create(struct hmac **hmacp, enum hmac_hash hash,
37 const uint8_t *key, size_t key_len)
38{
39 struct hmac *hmac;
40 const EVP_MD *evp;
41 int err = 0;
42
43 if (!hmacp || !key || !key_len)
44 return EINVAL;
45
46 switch (hash) {
47
48 case HMAC_HASH_SHA1:
49 evp = EVP_sha1();
50 break;
51
52 case HMAC_HASH_SHA256:
53 evp = EVP_sha256();
54 break;
55
56 default:
57 return ENOTSUP;
58 }
59
60 hmac = mem_zalloc(sizeof(*hmac), destructor);
61 if (!hmac)
62 return ENOMEM;
63
64#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
65 !defined(LIBRESSL_VERSION_NUMBER)
66
67 hmac->ctx = HMAC_CTX_new();
68 if (!hmac->ctx) {
69 ERR_clear_error();
70 err = ENOMEM;
71 goto out;
72 }
73#else
74 hmac->ctx = mem_zalloc(sizeof(*hmac->ctx), NULL);
75 if (!hmac->ctx) {
76 err = ENOMEM;
77 goto out;
78 }
79
80 HMAC_CTX_init(hmac->ctx);
81#endif
82
83#if (OPENSSL_VERSION_NUMBER >= 0x00909000)
84 if (!HMAC_Init_ex(hmac->ctx, key, (int)key_len, evp, NULL)) {
85 ERR_clear_error();
86 err = EPROTO;
87 }
88#else
89 HMAC_Init_ex(hmac->ctx, key, (int)key_len, evp, NULL);
90#endif
91
92 out:
93 if (err)
94 mem_deref(hmac);
95 else
96 *hmacp = hmac;
97
98 return err;
99}
100
101
102int hmac_digest(struct hmac *hmac, uint8_t *md, size_t md_len,
103 const uint8_t *data, size_t data_len)
104{
105 unsigned int len = (unsigned int)md_len;
106
107 if (!hmac || !md || !md_len || !data || !data_len)
108 return EINVAL;
109
110#if (OPENSSL_VERSION_NUMBER >= 0x00909000)
111 /* the HMAC context must be reset here */
112 if (!HMAC_Init_ex(hmac->ctx, 0, 0, 0, NULL))
113 goto error;
114
115 if (!HMAC_Update(hmac->ctx, data, (int)data_len))
116 goto error;
117 if (!HMAC_Final(hmac->ctx, md, &len))
118 goto error;
119
120 return 0;
121
122 error:
123 ERR_clear_error();
124 return EPROTO;
125
126#else
127 /* the HMAC context must be reset here */
128 HMAC_Init_ex(hmac->ctx, 0, 0, 0, NULL);
129
130 HMAC_Update(hmac->ctx, data, (int)data_len);
131 HMAC_Final(hmac->ctx, md, &len);
132
133 return 0;
134#endif
135}