1 /* algo_hmac - hash-based message authentication code (HMAC) wrapper
2  *
3  * Copyright(c) 2021 Glenn Strauss gstrauss()gluelogic.com  All rights reserved
4  * License: BSD 3-clause (same as lighttpd)
5  */
6 #include "first.h"
7 
8 #include "algo_hmac.h"
9 
10 #include "sys-crypto-md.h"
11 #ifdef USE_LIB_CRYPTO
12 #if defined(USE_NETTLE_CRYPTO)
13 #include <nettle/hmac.h>
14 #elif defined(USE_MBEDTLS_CRYPTO)
15 #include <mbedtls/md.h>
16 #elif defined(USE_WOLFSSL_CRYPTO)
17 #include <wolfssl/wolfcrypt/hmac.h>
18 #elif defined(USE_OPENSSL_CRYPTO)
19 #include <openssl/evp.h>
20 #include <openssl/hmac.h>
21 #elif defined(USE_GNUTLS_CRYPTO)
22 #include <gnutls/crypto.h>
23 #elif defined(USE_NSS_CRYPTO)
24 #if 0 /*(nss/alghmac.h might not be present)*/
25 #ifdef NSS_VER_INCLUDE
26 #include <nss3/alghmac.h>
27 #else
28 #include <nss/alghmac.h>
29 #endif
30 #endif
31 #endif
32 #endif
33 
34 #ifndef USE_NETTLE_CRYPTO
35 #if defined(USE_OPENSSL_CRYPTO) && OPENSSL_VERSION_NUMBER >= 0x30000000L
36 #define HMAC EVP_HMAC
37 static unsigned char *
EVP_HMAC(const EVP_MD * evp_md,const void * key,int key_len,const unsigned char * d,int n,unsigned char * md,size_t * md_len)38 EVP_HMAC (const EVP_MD *evp_md, const void *key,
39           int key_len, const unsigned char *d, int n,
40           unsigned char *md, size_t *md_len)
41 {
42     EVP_PKEY * const pkey =
43       EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, key_len);
44     if (NULL == pkey) return NULL;
45 
46     EVP_MD_CTX * const ctx = EVP_MD_CTX_new();
47     if (NULL == ctx) {
48         EVP_PKEY_free(pkey);
49         return NULL;
50     }
51 
52     int rc = (1 == EVP_DigestSignInit(ctx, NULL, evp_md, NULL, pkey))
53           && (1 == EVP_DigestSignUpdate(ctx, d, n))
54           && (1 == EVP_DigestSignFinal(ctx, md, md_len));
55     EVP_MD_CTX_free(ctx);
56     EVP_PKEY_free(pkey);
57     return (1 == rc) ? md : NULL;
58 }
59 #endif
60 #endif
61 
62 
63 int
li_hmac_md5(unsigned char digest[MD5_DIGEST_LENGTH],const void * const secret,const uint32_t slen,const unsigned char * const msg,const uint32_t mlen)64 li_hmac_md5 (unsigned char digest[MD5_DIGEST_LENGTH],
65              const void * const secret, const uint32_t slen,
66              const unsigned char * const msg, const uint32_t mlen)
67 {
68     struct const_iovec iov[] = { { secret, slen }, { msg, mlen } };
69     MD5_iov(digest, iov, sizeof(iov)/sizeof(*iov));
70     return 1;
71 }
72 
73 
74 #ifdef USE_LIB_CRYPTO_SHA1
75 int
li_hmac_sha1(unsigned char digest[SHA_DIGEST_LENGTH],const void * const secret,const uint32_t slen,const unsigned char * const msg,const uint32_t mlen)76 li_hmac_sha1 (unsigned char digest[SHA_DIGEST_LENGTH],
77               const void * const secret, const uint32_t slen,
78               const unsigned char * const msg, const uint32_t mlen)
79 {
80   #ifdef USE_LIB_CRYPTO
81    #if defined(USE_NETTLE_CRYPTO)
82     struct hmac_sha1_ctx ctx;
83     hmac_sha1_set_key(&ctx, slen, (const uint8_t *)secret);
84     hmac_sha1_update(&ctx, mlen, (const uint8_t *)msg);
85     hmac_sha1_digest(&ctx, SHA_DIGEST_LENGTH, (uint8_t *)digest);
86     return 1;
87    #elif defined(USE_MBEDTLS_CRYPTO) \
88       && defined(MBEDTLS_MD_C) && defined(MBEDTLS_SHA1_C)
89     return 0 ==
90       mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1),
91                       (const unsigned char *)secret, slen,
92                       (const unsigned char *)msg, mlen, digest);
93    #elif defined(USE_WOLFSSL_CRYPTO)
94     Hmac hmac;
95     if (0 != wc_HmacInit(&hmac, NULL, INVALID_DEVID)
96         || wc_HmacSetKey(&hmac, WC_SHA, (const byte *)secret, (word32)slen) < 0
97         || wc_HmacUpdate(&hmac, (const byte *)msg, (word32)mlen) < 0
98         || wc_HmacFinal(&hmac, (byte *)digest) < 0)
99         return 0;
100     return 1;
101    #elif defined(USE_OPENSSL_CRYPTO)
102     return (NULL != HMAC(EVP_sha1(),
103                          (const unsigned char *)secret, (int)slen,
104                          (const unsigned char *)msg, mlen,
105                          digest, NULL));
106    #elif defined(USE_GNUTLS_CRYPTO)
107     return 0 ==
108       gnutls_hmac_fast(GNUTLS_MAC_SHA1,
109                        (const unsigned char *)secret, slen,
110                        (const unsigned char *)msg, mlen, digest);
111    #elif defined(USE_NSS_CRYPTO)
112     /*(HMAC* funcs not public export of libfreebl3.so,
113      * even though nss3/alghmac.h is public (WTH?!))*/
114     #if 0
115     HMACContext *hmac =
116       HMAC_Create(HASH_GetHashObject(HASH_AlgSHA1),
117                   (const unsigned char *)secret, slen, PR_FALSE);
118     if (NULL == hmac)
119         return 0;
120     HMAC_Begin(hmac);
121     HMAC_Update(hmac, (const unsigned char *)msg, mlen);
122     unsigned int dlen;
123     int rc = HMAC_Finish(hmac, digest, &dlen, SHA_DIGEST_LENGTH);
124     HMAC_Destroy(hmac, PR_TRUE);
125     return (SECSuccess == rc);
126     #else
127     UNUSED(digest);
128     UNUSED(secret);
129     UNUSED(slen);
130     UNUSED(msg);
131     UNUSED(mlen);
132     return 0;
133     #endif
134    #else
135    #error "unexpected; crypto lib not configured for HMAC SHA1"
136    #endif
137   #else
138     UNUSED(digest);
139     UNUSED(secret);
140     UNUSED(slen);
141     UNUSED(msg);
142     UNUSED(mlen);
143     return 0;
144   #endif
145 }
146 #endif
147 
148 
149 #ifdef USE_LIB_CRYPTO_SHA256
150 int
li_hmac_sha256(unsigned char digest[SHA256_DIGEST_LENGTH],const void * const secret,const uint32_t slen,const unsigned char * const msg,const uint32_t mlen)151 li_hmac_sha256 (unsigned char digest[SHA256_DIGEST_LENGTH],
152                 const void * const secret, const uint32_t slen,
153                 const unsigned char * const msg, const uint32_t mlen)
154 {
155   #ifdef USE_LIB_CRYPTO
156    #if defined(USE_NETTLE_CRYPTO)
157     struct hmac_sha256_ctx ctx;
158     hmac_sha256_set_key(&ctx, slen, (const uint8_t *)secret);
159     hmac_sha256_update(&ctx, mlen, (const uint8_t *)msg);
160     hmac_sha256_digest(&ctx, SHA256_DIGEST_LENGTH, (uint8_t *)digest);
161     return 1;
162    #elif defined(USE_MBEDTLS_CRYPTO) \
163       && defined(MBEDTLS_MD_C) && defined(MBEDTLS_SHA256_C)
164     return 0 ==
165       mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
166                       (const unsigned char *)secret, slen,
167                       (const unsigned char *)msg, mlen, digest);
168    #elif defined(USE_WOLFSSL_CRYPTO)
169     Hmac hmac;
170     if (0 != wc_HmacInit(&hmac, NULL, INVALID_DEVID)
171         || wc_HmacSetKey(&hmac, WC_SHA256,(const byte *)secret,(word32)slen) < 0
172         || wc_HmacUpdate(&hmac, (const byte *)msg, (word32)mlen) < 0
173         || wc_HmacFinal(&hmac, (byte *)digest) < 0)
174         return 0;
175     return 1;
176    #elif defined(USE_OPENSSL_CRYPTO)
177     return (NULL != HMAC(EVP_sha256(),
178                          (const unsigned char *)secret, (int)slen,
179                          (const unsigned char *)msg, mlen,
180                          digest, NULL));
181    #elif defined(USE_GNUTLS_CRYPTO)
182     return 0 ==
183       gnutls_hmac_fast(GNUTLS_MAC_SHA256,
184                        (const unsigned char *)secret, slen,
185                        (const unsigned char *)msg, mlen, digest);
186    #elif defined(USE_NSS_CRYPTO)
187     /*(HMAC* funcs not public export of libfreebl3.so,
188      * even though nss3/alghmac.h is public (WTH?!))*/
189     #if 0
190     HMACContext *hmac =
191       HMAC_Create(HASH_GetHashObject(HASH_AlgSHA256),
192                   (const unsigned char *)secret, slen, PR_FALSE);
193     if (NULL == hmac)
194         return 0;
195     HMAC_Begin(hmac);
196     HMAC_Update(hmac, (const unsigned char *)msg, mlen);
197     unsigned int dlen;
198     int rc = HMAC_Finish(hmac, digest, &dlen, SHA256_DIGEST_LENGTH);
199     HMAC_Destroy(hmac, PR_TRUE);
200     return (SECSuccess == rc);
201     #else
202     UNUSED(digest);
203     UNUSED(secret);
204     UNUSED(slen);
205     UNUSED(msg);
206     UNUSED(mlen);
207     return 0;
208     #endif
209    #else
210    #error "unexpected; crypto lib not configured for HMAC SHA256"
211    #endif
212   #else
213     UNUSED(digest);
214     UNUSED(secret);
215     UNUSED(slen);
216     UNUSED(msg);
217     UNUSED(mlen);
218     return 0;
219   #endif
220 }
221 #endif
222 
223 
224 #ifdef USE_LIB_CRYPTO_SHA512
225 int
li_hmac_sha512(unsigned char digest[SHA512_DIGEST_LENGTH],const void * const secret,const uint32_t slen,const unsigned char * const msg,const uint32_t mlen)226 li_hmac_sha512 (unsigned char digest[SHA512_DIGEST_LENGTH],
227                 const void * const secret, const uint32_t slen,
228                 const unsigned char * const msg, const uint32_t mlen)
229 {
230   #ifdef USE_LIB_CRYPTO
231    #if defined(USE_NETTLE_CRYPTO)
232     struct hmac_sha512_ctx ctx;
233     hmac_sha512_set_key(&ctx, slen, (const uint8_t *)secret);
234     hmac_sha512_update(&ctx, mlen, (const uint8_t *)msg);
235     hmac_sha512_digest(&ctx, SHA512_DIGEST_LENGTH, (uint8_t *)digest);
236     return 1;
237    #elif defined(USE_MBEDTLS_CRYPTO) \
238       && defined(MBEDTLS_MD_C) && defined(MBEDTLS_SHA512_C)
239     return 0 ==
240       mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA512),
241                       (const unsigned char *)secret, slen,
242                       (const unsigned char *)msg, mlen, digest);
243    #elif defined(USE_WOLFSSL_CRYPTO)
244     Hmac hmac;
245     if (0 != wc_HmacInit(&hmac, NULL, INVALID_DEVID)
246         || wc_HmacSetKey(&hmac, WC_SHA512,(const byte *)secret,(word32)slen) < 0
247         || wc_HmacUpdate(&hmac, (const byte *)msg, (word32)mlen) < 0
248         || wc_HmacFinal(&hmac, (byte *)digest) < 0)
249         return 0;
250     return 1;
251    #elif defined(USE_OPENSSL_CRYPTO)
252     return (NULL != HMAC(EVP_sha512(),
253                          (const unsigned char *)secret, (int)slen,
254                          (const unsigned char *)msg, mlen,
255                          digest, NULL));
256    #elif defined(USE_GNUTLS_CRYPTO)
257     return 0 ==
258       gnutls_hmac_fast(GNUTLS_MAC_SHA512,
259                        (const unsigned char *)secret, slen,
260                        (const unsigned char *)msg, mlen, digest);
261    #elif defined(USE_NSS_CRYPTO)
262     /*(HMAC* funcs not public export of libfreebl3.so,
263      * even though nss3/alghmac.h is public (WTH?!))*/
264     #if 0
265     HMACContext *hmac =
266       HMAC_Create(HASH_GetHashObject(HASH_AlgSHA512),
267                   (const unsigned char *)secret, slen, PR_FALSE);
268     if (NULL == hmac)
269         return 0;
270     HMAC_Begin(hmac);
271     HMAC_Update(hmac, (const unsigned char *)msg, mlen);
272     unsigned int dlen;
273     int rc = HMAC_Finish(hmac, digest, &dlen, SHA512_DIGEST_LENGTH);
274     HMAC_Destroy(hmac, PR_TRUE);
275     return (SECSuccess == rc);
276     #else
277     UNUSED(digest);
278     UNUSED(secret);
279     UNUSED(slen);
280     UNUSED(msg);
281     UNUSED(mlen);
282     return 0;
283     #endif
284    #else
285    #error "unexpected; crypto lib not configured for HMAC SHA512"
286    #endif
287   #else
288     UNUSED(digest);
289     UNUSED(secret);
290     UNUSED(slen);
291     UNUSED(msg);
292     UNUSED(mlen);
293     return 0;
294   #endif
295 }
296 #endif
297