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