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