The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
hmac_sha1.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** SHA1 HMAC not dependent on OpenSSL
18 *
19 * @note New code that needs fast or incremental HMACs should use the OpenSSL EVP_* HMAC
20 * interface instead, as that can take advantage of acceleration instructions provided
21 * by various CPUs (and provides an incremental hashing interface).
22 *
23 * Adapted from hmacmd5.c (HMAC-MD5). Test cases from RFC2202.
24 *
25 * @file src/lib/util/hmac_sha1.c
26 *
27 * @author Michael Richardson (mcr@sandelman.ottawa.on.ca)
28 *
29 * @copyright 2003 Michael Richardson (mcr@sandelman.ottawa.on.ca)
30 * @copyright 2000,2003,2006 The FreeRADIUS server project
31 */
32RCSID("$Id: 4a3248a5337b73485d00af6dd21370e3dd0fe5f7 $")
33
34#include <freeradius-devel/util/sha1.h>
35#include <freeradius-devel/util/atexit.h>
36#include <freeradius-devel/util/strerror.h>
37
38#ifdef HMAC_SHA1_DATA_PROBLEMS
39unsigned int sha1_data_problems = 0;
40#endif
41
42#ifdef HAVE_OPENSSL_EVP_H
43# include <freeradius-devel/tls/openssl_user_macros.h>
44# include <openssl/hmac.h>
45
46static _Thread_local EVP_MD_CTX *sha1_hmac_ctx;
47
48static int _hmac_sha1_ctx_free_on_exit(void *arg)
49{
50 EVP_MD_CTX_free(arg);
51 return 0;
52}
53
54/** Calculate HMAC using OpenSSL's SHA1 implementation
55 *
56 * @param digest Caller digest to be filled in.
57 * @param in Pointer to data stream.
58 * @param inlen length of data stream.
59 * @param key Pointer to authentication key.
60 * @param key_len Length of authentication key.
61 * @return
62 * - 0 on success.
63 * - -1 on error.
64 */
65int fr_hmac_sha1(uint8_t digest[SHA1_DIGEST_LENGTH], uint8_t const *in, size_t inlen,
66 uint8_t const *key, size_t key_len)
67{
68 EVP_MD_CTX *ctx;
69 EVP_PKEY *pkey;
70
71 if (unlikely(!sha1_hmac_ctx)) {
72 ctx = EVP_MD_CTX_new();
73 if (unlikely(!ctx)) {
74 fr_strerror_const("Failed allocating EVP_MD_CTX for HMAC-SHA1");
75 return -1;
76 }
77 EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT);
78 fr_atexit_thread_local(sha1_hmac_ctx, _hmac_sha1_ctx_free_on_exit, ctx);
79 } else {
80 ctx = sha1_hmac_ctx;
81 }
82
83 pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, key_len);
84 if (unlikely(pkey == NULL)) {
85 fr_strerror_const("Failed allocating pkey for HMAC-SHA1");
86 return -1;
87 }
88
89 if (unlikely(EVP_DigestSignInit(ctx, NULL, EVP_sha1(), NULL, pkey) != 1)) {
90 fr_strerror_const("Failed initialising EVP_MD_CTX for HMAC-SHA1");
91 error:
92 EVP_PKEY_free(pkey);
93 return -1;
94 }
95 if (unlikely(EVP_DigestSignUpdate(ctx, in, inlen) != 1)) {
96 fr_strerror_const("Failed ingesting data for HMAC-SHA1");
97 goto error;
98 }
99 /*
100 * OpenSSL <= 1.1.1 requires a non-null pointer for len
101 */
102 if (unlikely(EVP_DigestSignFinal(ctx, digest, &(size_t){ SHA1_DIGEST_LENGTH }) != 1)) {
103 fr_strerror_const("Failed finalising HMAC-SHA1");
104 goto error;
105 }
106
107 EVP_PKEY_free(pkey);
108 EVP_MD_CTX_reset(ctx);
109
110 return 0;
111}
112#else
113/** Calculate HMAC using internal SHA1 implementation
114 *
115 * @param digest Caller digest to be filled in.
116 * @param in Pointer to data stream.
117 * @param inlen length of data stream.
118 * @param key Pointer to authentication key.
119 * @param key_len Length of authentication key.
120 * @return
121 * - 0 on success.
122 * - -1 on error.
123 */
124int fr_hmac_sha1(uint8_t digest[static SHA1_DIGEST_LENGTH], uint8_t const *in, size_t inlen,
125 uint8_t const *key, size_t key_len)
126{
127 fr_sha1_ctx ctx;
128 uint8_t k_ipad[65]; /* inner padding - key XORd with ipad */
129 uint8_t k_opad[65]; /* outer padding - key XORd with opad */
130 uint8_t tk[20];
131 int i;
132 /* if key is longer than 64 bytes reset it to key=SHA1(key) */
133 if (key_len > 64) {
134
135 fr_sha1_ctx tctx;
136
137 fr_sha1_init(&tctx);
138 fr_sha1_update(&tctx, key, key_len);
139 fr_sha1_final(tk, &tctx);
140
141 key = tk;
142 key_len = 20;
143 }
144
145#ifdef HMAC_SHA1_DATA_PROBLEMS
146 if(sha1_data_problems)
147 {
148 int j,k;
149
150 printf("\nhmac-sha1 key(%d): ", key_len);
151 j=0; k=0;
152 for (i = 0; i < key_len; i++) {
153 if(j==4) {
154 printf("_");
155 j=0;
156 }
157 j++;
158
159 printf("%02x", key[i]);
160 }
161 printf("\nDATA: (%d) ",inlen);
162
163 j=0; k=0;
164 for (i = 0; i < inlen; i++) {
165 if(k==20) {
166 printf("\n ");
167 k=0;
168 j=0;
169 }
170 if(j==4) {
171 printf("_");
172 j=0;
173 }
174 k++;
175 j++;
176
177 printf("%02x", in[i]);
178 }
179 printf("\n");
180 }
181#endif
182
183
184 /*
185 * the HMAC_SHA1 transform looks like:
186 *
187 * SHA1(K XOR opad, SHA1(K XOR ipad, in))
188 *
189 * where K is an n byte key
190 * ipad is the byte 0x36 repeated 64 times
191
192 * opad is the byte 0x5c repeated 64 times
193 * and in is the data being protected
194 */
195
196 /* start out by storing key in pads */
197 memset(k_ipad, 0, sizeof(k_ipad));
198 memset(k_opad, 0, sizeof(k_opad));
199 memcpy(k_ipad, key, key_len);
200 memcpy(k_opad, key, key_len);
201
202 /* XOR key with ipad and opad values */
203 for (i = 0; i < 64; i++) {
204 k_ipad[i] ^= 0x36;
205 k_opad[i] ^= 0x5c;
206 }
207 /*
208 * perform inner SHA1
209 */
210 fr_sha1_init(&ctx); /* init ctx for 1st pass */
211 fr_sha1_update(&ctx, k_ipad, 64); /* start with inner pad */
212 fr_sha1_update(&ctx, in, inlen); /* then in of datagram */
213 fr_sha1_final(digest, &ctx); /* finish up 1st pass */
214 /*
215 * perform outer SHA1
216 */
217 fr_sha1_init(&ctx); /* init ctx for 2nd pass */
218 fr_sha1_update(&ctx, k_opad, 64); /* start with outer pad */
219 fr_sha1_update(&ctx, digest, 20); /* then results of 1st hash */
220 fr_sha1_final(digest, &ctx); /* finish up 2nd pass */
221
222#ifdef HMAC_SHA1_DATA_PROBLEMS
223 if (sha1_data_problems) {
224 int j;
225
226 printf("\nhmac-sha1 mac(20): ");
227 j=0;
228 for (i = 0; i < 20; i++) {
229 if(j==4) {
230 printf("_");
231 j=0;
232 }
233 j++;
234
235 printf("%02x", digest[i]);
236 }
237 printf("\n");
238 }
239#endif
240 return 0;
241}
242#endif /* HAVE_OPENSSL_EVP_H */
#define fr_atexit_thread_local(_name, _free, _uctx)
Definition atexit.h:221
#define RCSID(id)
Definition build.h:483
#define unlikely(_x)
Definition build.h:381
static fr_slen_t in
Definition dict.h:824
int fr_hmac_sha1(uint8_t digest[static SHA1_DIGEST_LENGTH], uint8_t const *in, size_t inlen, uint8_t const *key, size_t key_len)
Calculate HMAC using internal SHA1 implementation.
Definition hmac_sha1.c:124
unsigned char uint8_t
void fr_sha1_init(fr_sha1_ctx *context)
Definition sha1.c:93
void fr_sha1_final(uint8_t digest[static SHA1_DIGEST_LENGTH], fr_sha1_ctx *context)
Definition sha1.c:141
void fr_sha1_update(fr_sha1_ctx *context, uint8_t const *in, size_t len)
Definition sha1.c:105
#define SHA1_DIGEST_LENGTH
Definition sha1.h:29
#define fr_strerror_const(_msg)
Definition strerror.h:223
static size_t char fr_sbuff_t size_t inlen
Definition value.h:997