hmac.c revision 1.1 1 1.1 sjg /*
2 1.1 sjg * Copyright (c) 2004, Juniper Networks, Inc.
3 1.1 sjg * All rights reserved.
4 1.1 sjg *
5 1.1 sjg * Redistribution and use in source and binary forms, with or without
6 1.1 sjg * modification, are permitted provided that the following conditions
7 1.1 sjg * are met:
8 1.1 sjg * 1. Redistributions of source code must retain the above copyright
9 1.1 sjg * notice, this list of conditions and the following disclaimer.
10 1.1 sjg * 2. Redistributions in binary form must reproduce the above copyright
11 1.1 sjg * notice, this list of conditions and the following disclaimer in the
12 1.1 sjg * documentation and/or other materials provided with the distribution.
13 1.1 sjg * 3. Neither the name of the copyright holders nor the names of its
14 1.1 sjg * contributors may be used to endorse or promote products derived
15 1.1 sjg * from this software without specific prior written permission.
16 1.1 sjg *
17 1.1 sjg * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 1.1 sjg * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 1.1 sjg * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 1.1 sjg * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 1.1 sjg * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 1.1 sjg * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 1.1 sjg * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 1.1 sjg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 1.1 sjg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 1.1 sjg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 1.1 sjg * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 1.1 sjg */
29 1.1 sjg /*
30 1.1 sjg * Implement HMAC as described in RFC 2104
31 1.1 sjg *
32 1.1 sjg * You need to define the following before including this file.
33 1.1 sjg *
34 1.1 sjg * HMAC_FUNC the name of the function (hmac_sha1 or hmac_md5 etc)
35 1.1 sjg * HASH_LENGTH the size of the digest (20 for SHA1, 16 for MD5)
36 1.1 sjg * HASH_CTX the name of the HASH CTX
37 1.1 sjg * HASH_Init
38 1.1 sjg * HASH_Update
39 1.1 sjg * Hash_Final
40 1.1 sjg */
41 1.1 sjg #include <sys/cdefs.h>
42 1.1 sjg #if !defined(lint)
43 1.1 sjg __RCSID("$Id: hmac.c,v 1.1 2004/07/02 00:05:23 sjg Exp $");
44 1.1 sjg #endif /* not lint */
45 1.1 sjg
46 1.1 sjg #include <stdlib.h>
47 1.1 sjg #include <string.h>
48 1.1 sjg
49 1.1 sjg /* Don't change these */
50 1.1 sjg #define HMAC_IPAD 0x36
51 1.1 sjg #define HMAC_OPAD 0x5c
52 1.1 sjg
53 1.1 sjg /* Nor this */
54 1.1 sjg #ifndef HMAC_BLOCKSZ
55 1.1 sjg # define HMAC_BLOCKSZ 64
56 1.1 sjg #endif
57 1.1 sjg
58 1.1 sjg /* Keep gcc quiet */
59 1.1 sjg void
60 1.1 sjg HMAC_FUNC (unsigned char *text, size_t text_len,
61 1.1 sjg unsigned char *key, size_t key_len,
62 1.1 sjg unsigned char *digest);
63 1.1 sjg
64 1.1 sjg /*
65 1.1 sjg * The logic here is lifted straight from RFC 2104 except that
66 1.1 sjg * rather than filling the pads with 0, copying in the key and then
67 1.1 sjg * XOR with the pad byte, we just fill with the pad byte and
68 1.1 sjg * XOR with the key.
69 1.1 sjg */
70 1.1 sjg void
71 1.1 sjg HMAC_FUNC (unsigned char *text, size_t text_len,
72 1.1 sjg unsigned char *key, size_t key_len,
73 1.1 sjg unsigned char *digest)
74 1.1 sjg {
75 1.1 sjg HASH_CTX context;
76 1.1 sjg /* Inner padding key XOR'd with ipad */
77 1.1 sjg unsigned char k_ipad[HMAC_BLOCKSZ + 1];
78 1.1 sjg /* Outer padding key XOR'd with opad */
79 1.1 sjg unsigned char k_opad[HMAC_BLOCKSZ + 1];
80 1.1 sjg /* HASH(key) if needed */
81 1.1 sjg unsigned char tk[HASH_LENGTH];
82 1.1 sjg int i;
83 1.1 sjg
84 1.1 sjg /*
85 1.1 sjg * If key is longer than HMAC_BLOCKSZ bytes
86 1.1 sjg * reset it to key=HASH(key)
87 1.1 sjg */
88 1.1 sjg if (key_len > HMAC_BLOCKSZ) {
89 1.1 sjg HASH_CTX tctx;
90 1.1 sjg
91 1.1 sjg HASH_Init(&tctx);
92 1.1 sjg HASH_Update(&tctx, key, key_len);
93 1.1 sjg HASH_Final(tk, &tctx);
94 1.1 sjg
95 1.1 sjg key = tk;
96 1.1 sjg key_len = HASH_LENGTH;
97 1.1 sjg }
98 1.1 sjg
99 1.1 sjg /*
100 1.1 sjg * The HMAC_ transform looks like:
101 1.1 sjg *
102 1.1 sjg * HASH(K XOR opad, HASH(K XOR ipad, text))
103 1.1 sjg *
104 1.1 sjg * where K is an n byte key
105 1.1 sjg * ipad is the byte HMAC_IPAD repeated HMAC_BLOCKSZ times
106 1.1 sjg * opad is the byte HMAC_OPAD repeated HMAC_BLOCKSZ times
107 1.1 sjg * and text is the data being protected
108 1.1 sjg */
109 1.1 sjg
110 1.1 sjg /*
111 1.1 sjg * Fill the pads and XOR in the key
112 1.1 sjg */
113 1.1 sjg memset( k_ipad, HMAC_IPAD, sizeof k_ipad);
114 1.1 sjg memset( k_opad, HMAC_OPAD, sizeof k_opad);
115 1.1 sjg for (i = 0; i < key_len; i++) {
116 1.1 sjg k_ipad[i] ^= key[i];
117 1.1 sjg k_opad[i] ^= key[i];
118 1.1 sjg }
119 1.1 sjg
120 1.1 sjg /*
121 1.1 sjg * Perform inner HASH.
122 1.1 sjg * Start with inner pad,
123 1.1 sjg * then the text.
124 1.1 sjg */
125 1.1 sjg HASH_Init(&context);
126 1.1 sjg HASH_Update(&context, k_ipad, HMAC_BLOCKSZ);
127 1.1 sjg HASH_Update(&context, text, text_len);
128 1.1 sjg HASH_Final(digest, &context);
129 1.1 sjg
130 1.1 sjg /*
131 1.1 sjg * Perform outer HASH.
132 1.1 sjg * Start with the outer pad,
133 1.1 sjg * then the result of the inner hash.
134 1.1 sjg */
135 1.1 sjg HASH_Init(&context);
136 1.1 sjg HASH_Update(&context, k_opad, HMAC_BLOCKSZ);
137 1.1 sjg HASH_Update(&context, digest, HASH_LENGTH);
138 1.1 sjg HASH_Final(digest, &context);
139 1.1 sjg }
140 1.1 sjg
141 1.1 sjg #if defined(MAIN) || defined(UNIT_TEST)
142 1.1 sjg #include <stdio.h>
143 1.1 sjg
144 1.1 sjg
145 1.1 sjg static char *
146 1.1 sjg b2x(char *buf, int bufsz, unsigned char *data, int nbytes)
147 1.1 sjg {
148 1.1 sjg int i;
149 1.1 sjg
150 1.1 sjg if (bufsz <= (nbytes * 2))
151 1.1 sjg return NULL;
152 1.1 sjg buf[0] = '\0';
153 1.1 sjg for (i = 0; i < nbytes; i++) {
154 1.1 sjg (void) sprintf(&buf[i*2], "%02x", data[i]);
155 1.1 sjg }
156 1.1 sjg return buf;
157 1.1 sjg }
158 1.1 sjg
159 1.1 sjg #if defined(UNIT_TEST)
160 1.1 sjg
161 1.1 sjg static int
162 1.1 sjg x2b(unsigned char *buf, int bufsz, char *data, int nbytes)
163 1.1 sjg {
164 1.1 sjg int i;
165 1.1 sjg int c;
166 1.1 sjg
167 1.1 sjg if (nbytes < 0)
168 1.1 sjg nbytes = strlen(data);
169 1.1 sjg nbytes /= 2;
170 1.1 sjg if (bufsz <= nbytes)
171 1.1 sjg return 0;
172 1.1 sjg for (i = 0; i < nbytes; i++) {
173 1.1 sjg if (sscanf(&data[i*2], "%02x", &c) < 1)
174 1.1 sjg break;
175 1.1 sjg buf[i] = c;
176 1.1 sjg }
177 1.1 sjg buf[i] = 0;
178 1.1 sjg return i;
179 1.1 sjg }
180 1.1 sjg
181 1.1 sjg #ifndef HMAC_KAT
182 1.1 sjg # define HMAC_KAT hmac_kat
183 1.1 sjg #endif
184 1.1 sjg
185 1.1 sjg /*
186 1.1 sjg * If a test key or data starts with 0x we'll convert to binary.
187 1.1 sjg */
188 1.1 sjg #define X2B(v, b) do { \
189 1.1 sjg if (strncmp(v, "0x", 2) == 0) { \
190 1.1 sjg v += 2; \
191 1.1 sjg x2b(b, sizeof(b), v, strlen(v)); \
192 1.1 sjg v = b; \
193 1.1 sjg } \
194 1.1 sjg } while (0)
195 1.1 sjg
196 1.1 sjg /*
197 1.1 sjg * Run some of the known answer tests from RFC 2202
198 1.1 sjg * We assume that HASH_LENGTH==20 means SHA1 else MD5.
199 1.1 sjg */
200 1.1 sjg static int
201 1.1 sjg HMAC_KAT (FILE *fp)
202 1.1 sjg {
203 1.1 sjg struct test_s {
204 1.1 sjg unsigned char *key;
205 1.1 sjg unsigned char *data;
206 1.1 sjg unsigned char *expect;
207 1.1 sjg } tests[] = {
208 1.1 sjg {
209 1.1 sjg #if HASH_LENGTH == 20
210 1.1 sjg "0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
211 1.1 sjg "Hi There",
212 1.1 sjg "0xb617318655057264e28bc0b6fb378c8ef146be00",
213 1.1 sjg #else
214 1.1 sjg "0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
215 1.1 sjg "Hi There",
216 1.1 sjg "0x9294727a3638bb1c13f48ef8158bfc9d",
217 1.1 sjg #endif
218 1.1 sjg },
219 1.1 sjg {
220 1.1 sjg "Jefe",
221 1.1 sjg "what do ya want for nothing?",
222 1.1 sjg #if HASH_LENGTH == 20
223 1.1 sjg "0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79",
224 1.1 sjg #else
225 1.1 sjg "0x750c783e6ab0b503eaa86e310a5db738",
226 1.1 sjg #endif
227 1.1 sjg },
228 1.1 sjg {
229 1.1 sjg #if HASH_LENGTH == 20
230 1.1 sjg "0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
231 1.1 sjg "Test With Truncation",
232 1.1 sjg "0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04",
233 1.1 sjg #else
234 1.1 sjg "0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
235 1.1 sjg "Test With Truncation",
236 1.1 sjg "0x56461ef2342edc00f9bab995690efd4c",
237 1.1 sjg #endif
238 1.1 sjg },
239 1.1 sjg {
240 1.1 sjg "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
241 1.1 sjg "Test Using Larger Than Block-Size Key - Hash Key First",
242 1.1 sjg #if HASH_LENGTH == 20
243 1.1 sjg "0xaa4ae5e15272d00e95705637ce8a3b55ed402112",
244 1.1 sjg #else
245 1.1 sjg "0x6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd",
246 1.1 sjg #endif
247 1.1 sjg },
248 1.1 sjg {
249 1.1 sjg 0, 0, 0,
250 1.1 sjg },
251 1.1 sjg };
252 1.1 sjg struct test_s *test = tests;
253 1.1 sjg unsigned char digest[HASH_LENGTH];
254 1.1 sjg unsigned char kbuf[BUFSIZ];
255 1.1 sjg unsigned char dbuf[BUFSIZ];
256 1.1 sjg unsigned char *key;
257 1.1 sjg unsigned char *data;
258 1.1 sjg char *result;
259 1.1 sjg int n = 0;
260 1.1 sjg
261 1.1 sjg for (test = tests; test->key; test++) {
262 1.1 sjg key = test->key;
263 1.1 sjg X2B(key, kbuf);
264 1.1 sjg data = test->data;
265 1.1 sjg X2B(data, dbuf);
266 1.1 sjg HMAC_FUNC(data, strlen(data), key, strlen(key), digest);
267 1.1 sjg strcpy(dbuf, "0x");
268 1.1 sjg b2x(&dbuf[2], (sizeof dbuf) - 2, digest, HASH_LENGTH);
269 1.1 sjg
270 1.1 sjg if (strcmp(dbuf, test->expect) == 0)
271 1.1 sjg result = "Ok";
272 1.1 sjg else {
273 1.1 sjg n++;
274 1.1 sjg result = test->expect;
275 1.1 sjg }
276 1.1 sjg if (fp)
277 1.1 sjg fprintf(fp, "key=%s, data=%s, result=%s: %s\n",
278 1.1 sjg test->key, test->data, dbuf, result);
279 1.1 sjg }
280 1.1 sjg return n;
281 1.1 sjg }
282 1.1 sjg #endif
283 1.1 sjg
284 1.1 sjg
285 1.1 sjg int
286 1.1 sjg main (int argc, char *argv[])
287 1.1 sjg {
288 1.1 sjg char buf[BUFSIZ];
289 1.1 sjg unsigned char *key;
290 1.1 sjg unsigned char *data;
291 1.1 sjg int key_len;
292 1.1 sjg int data_len;
293 1.1 sjg int i;
294 1.1 sjg unsigned char digest[HASH_LENGTH];
295 1.1 sjg
296 1.1 sjg #ifdef UNIT_TEST
297 1.1 sjg if (argc == 1)
298 1.1 sjg exit(HMAC_KAT(stdout));
299 1.1 sjg #endif
300 1.1 sjg
301 1.1 sjg if (argc < 3) {
302 1.1 sjg fprintf(stderr, "Usage:\n\t%s key data\n", argv[0]);
303 1.1 sjg exit(1);
304 1.1 sjg }
305 1.1 sjg key = argv[1];
306 1.1 sjg data = argv[2];
307 1.1 sjg key_len = strlen(key);
308 1.1 sjg data_len = strlen(data);
309 1.1 sjg HMAC_FUNC(data, data_len, key, key_len, digest);
310 1.1 sjg printf("0x%s\n", b2x(buf, sizeof buf, digest, HASH_LENGTH));
311 1.1 sjg exit(0);
312 1.1 sjg }
313 1.1 sjg #endif
314 1.1 sjg
315 1.1 sjg
316