xref: /curl/lib/hmac.c (revision ad1c49bc)
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * SPDX-License-Identifier: curl
22  *
23  * RFC2104 Keyed-Hashing for Message Authentication
24  *
25  ***************************************************************************/
26 
27 #include "curl_setup.h"
28 
29 #if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI))         \
30   || !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH)
31 
32 #include <curl/curl.h>
33 
34 #include "curl_hmac.h"
35 #include "curl_memory.h"
36 #include "warnless.h"
37 
38 /* The last #include file should be: */
39 #include "memdebug.h"
40 
41 /*
42  * Generic HMAC algorithm.
43  *
44  *   This module computes HMAC digests based on any hash function. Parameters
45  * and computing procedures are setup dynamically at HMAC computation context
46  * initialization.
47  */
48 
49 static const unsigned char hmac_ipad = 0x36;
50 static const unsigned char hmac_opad = 0x5C;
51 
52 struct HMAC_context *
Curl_HMAC_init(const struct HMAC_params * hashparams,const unsigned char * key,unsigned int keylen)53 Curl_HMAC_init(const struct HMAC_params *hashparams,
54                const unsigned char *key,
55                unsigned int keylen)
56 {
57   size_t i;
58   struct HMAC_context *ctxt;
59   unsigned char *hkey;
60   unsigned char b;
61 
62   /* Create HMAC context. */
63   i = sizeof(*ctxt) + 2 * hashparams->ctxtsize + hashparams->resultlen;
64   ctxt = malloc(i);
65 
66   if(!ctxt)
67     return ctxt;
68 
69   ctxt->hash = hashparams;
70   ctxt->hashctxt1 = (void *) (ctxt + 1);
71   ctxt->hashctxt2 = (void *) ((char *) ctxt->hashctxt1 + hashparams->ctxtsize);
72 
73   /* If the key is too long, replace it by its hash digest. */
74   if(keylen > hashparams->maxkeylen) {
75     hashparams->hinit(ctxt->hashctxt1);
76     hashparams->hupdate(ctxt->hashctxt1, key, keylen);
77     hkey = (unsigned char *) ctxt->hashctxt2 + hashparams->ctxtsize;
78     hashparams->hfinal(hkey, ctxt->hashctxt1);
79     key = hkey;
80     keylen = hashparams->resultlen;
81   }
82 
83   /* Prime the two hash contexts with the modified key. */
84   hashparams->hinit(ctxt->hashctxt1);
85   hashparams->hinit(ctxt->hashctxt2);
86 
87   for(i = 0; i < keylen; i++) {
88     b = (unsigned char)(*key ^ hmac_ipad);
89     hashparams->hupdate(ctxt->hashctxt1, &b, 1);
90     b = (unsigned char)(*key++ ^ hmac_opad);
91     hashparams->hupdate(ctxt->hashctxt2, &b, 1);
92   }
93 
94   for(; i < hashparams->maxkeylen; i++) {
95     hashparams->hupdate(ctxt->hashctxt1, &hmac_ipad, 1);
96     hashparams->hupdate(ctxt->hashctxt2, &hmac_opad, 1);
97   }
98 
99   /* Done, return pointer to HMAC context. */
100   return ctxt;
101 }
102 
Curl_HMAC_update(struct HMAC_context * ctxt,const unsigned char * ptr,unsigned int len)103 int Curl_HMAC_update(struct HMAC_context *ctxt,
104                      const unsigned char *ptr,
105                      unsigned int len)
106 {
107   /* Update first hash calculation. */
108   ctxt->hash->hupdate(ctxt->hashctxt1, ptr, len);
109   return 0;
110 }
111 
112 
Curl_HMAC_final(struct HMAC_context * ctxt,unsigned char * output)113 int Curl_HMAC_final(struct HMAC_context *ctxt, unsigned char *output)
114 {
115   const struct HMAC_params *hashparams = ctxt->hash;
116 
117   /* Do not get output if called with a null parameter: only release
118      storage. */
119 
120   if(!output)
121     output = (unsigned char *) ctxt->hashctxt2 + ctxt->hash->ctxtsize;
122 
123   hashparams->hfinal(output, ctxt->hashctxt1);
124   hashparams->hupdate(ctxt->hashctxt2, output, hashparams->resultlen);
125   hashparams->hfinal(output, ctxt->hashctxt2);
126   free(ctxt);
127   return 0;
128 }
129 
130 /*
131  * Curl_hmacit()
132  *
133  * This is used to generate a HMAC hash, for the specified input data, given
134  * the specified hash function and key.
135  *
136  * Parameters:
137  *
138  * hashparams [in]     - The hash function (Curl_HMAC_MD5).
139  * key        [in]     - The key to use.
140  * keylen     [in]     - The length of the key.
141  * buf        [in]     - The data to encrypt.
142  * buflen     [in]     - The length of the data.
143  * output     [in/out] - The output buffer.
144  *
145  * Returns CURLE_OK on success.
146  */
Curl_hmacit(const struct HMAC_params * hashparams,const unsigned char * key,const size_t keylen,const unsigned char * buf,const size_t buflen,unsigned char * output)147 CURLcode Curl_hmacit(const struct HMAC_params *hashparams,
148                      const unsigned char *key, const size_t keylen,
149                      const unsigned char *buf, const size_t buflen,
150                      unsigned char *output)
151 {
152   struct HMAC_context *ctxt =
153     Curl_HMAC_init(hashparams, key, curlx_uztoui(keylen));
154 
155   if(!ctxt)
156     return CURLE_OUT_OF_MEMORY;
157 
158   /* Update the digest with the given challenge */
159   Curl_HMAC_update(ctxt, buf, curlx_uztoui(buflen));
160 
161   /* Finalise the digest */
162   Curl_HMAC_final(ctxt, output);
163 
164   return CURLE_OK;
165 }
166 
167 #endif /* Using NTLM (without SSPI) or AWS */
168