include <string.h> if necessary, too
[freeradius.git] / src / lib / hmac.c
1 /*
2  * hmac.c       For the sake of illustration we provide the following
3  *              sample code for the implementation of HMAC-MD5 as well
4  *              as some corresponding test vectors (the code is based
5  *              on MD5 code as described in [MD5]).
6  *
7  *   This library is free software; you can redistribute it and/or
8  *   modify it under the terms of the GNU Lesser General Public
9  *   License as published by the Free Software Foundation; either
10  *   version 2.1 of the License, or (at your option) any later version.
11  *
12  *   This library is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  *   Lesser General Public License for more details.
16  *
17  *   You should have received a copy of the GNU Lesser General Public
18  *   License along with this library; if not, write to the Free Software
19  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * Copyright 2000,2006  The FreeRADIUS server project
22  */
23
24 /*
25 ** Function: hmac_md5
26 */
27
28 #include <freeradius-devel/ident.h>
29 RCSID("$Id$")
30
31 #include <freeradius-devel/autoconf.h>
32
33 #include <string.h>
34 #include <freeradius-devel/md5.h>
35 #include <freeradius-devel/missing.h>
36 #include <freeradius-devel/libradius.h>
37
38 /*
39 unsigned char*  text;                pointer to data stream
40 int             text_len;            length of data stream
41 unsigned char*  key;                 pointer to authentication key
42 int             key_len;             length of authentication key
43 unsigned char*  digest;              caller digest to be filled in
44 */
45
46 void
47 lrad_hmac_md5(const uint8_t *text, int text_len,
48               const uint8_t *key, int key_len,
49               uint8_t *digest)
50 {
51         lrad_MD5_CTX context;
52         uint8_t k_ipad[65];    /* inner padding -
53                                       * key XORd with ipad
54                                       */
55         uint8_t k_opad[65];    /* outer padding -
56                                       * key XORd with opad
57                                       */
58         uint8_t tk[16];
59         int i;
60         /* if key is longer than 64 bytes reset it to key=MD5(key) */
61         if (key_len > 64) {
62
63                 lrad_MD5_CTX      tctx;
64
65                 lrad_MD5Init(&tctx);
66                 lrad_MD5Update(&tctx, key, key_len);
67                 lrad_MD5Final(tk, &tctx);
68
69                 key = tk;
70                 key_len = 16;
71         }
72
73         /*
74          * the HMAC_MD5 transform looks like:
75          *
76          * MD5(K XOR opad, MD5(K XOR ipad, text))
77          *
78          * where K is an n byte key
79          * ipad is the byte 0x36 repeated 64 times
80
81          * opad is the byte 0x5c repeated 64 times
82          * and text is the data being protected
83          */
84
85         /* start out by storing key in pads */
86         memset( k_ipad, 0, sizeof(k_ipad));
87         memset( k_opad, 0, sizeof(k_opad));
88         memcpy( k_ipad, key, key_len);
89         memcpy( k_opad, key, key_len);
90
91         /* XOR key with ipad and opad values */
92         for (i = 0; i < 64; i++) {
93                 k_ipad[i] ^= 0x36;
94                 k_opad[i] ^= 0x5c;
95         }
96         /*
97          * perform inner MD5
98          */
99         lrad_MD5Init(&context);                   /* init context for 1st
100                                               * pass */
101         lrad_MD5Update(&context, k_ipad, 64);      /* start with inner pad */
102         lrad_MD5Update(&context, text, text_len); /* then text of datagram */
103         lrad_MD5Final(digest, &context);          /* finish up 1st pass */
104         /*
105          * perform outer MD5
106          */
107         lrad_MD5Init(&context);                   /* init context for 2nd
108                                               * pass */
109         lrad_MD5Update(&context, k_opad, 64);     /* start with outer pad */
110         lrad_MD5Update(&context, digest, 16);     /* then results of 1st
111                                               * hash */
112         lrad_MD5Final(digest, &context);          /* finish up 2nd pass */
113 }
114
115 /*
116 Test Vectors (Trailing '\0' of a character string not included in test):
117
118   key =         0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
119   key_len =     16 bytes
120   data =        "Hi There"
121   data_len =    8  bytes
122   digest =      0x9294727a3638bb1c13f48ef8158bfc9d
123
124   key =         "Jefe"
125   data =        "what do ya want for nothing?"
126   data_len =    28 bytes
127   digest =      0x750c783e6ab0b503eaa86e310a5db738
128
129   key =         0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
130
131   key_len       16 bytes
132   data =        0xDDDDDDDDDDDDDDDDDDDD...
133                 ..DDDDDDDDDDDDDDDDDDDD...
134                 ..DDDDDDDDDDDDDDDDDDDD...
135                 ..DDDDDDDDDDDDDDDDDDDD...
136                 ..DDDDDDDDDDDDDDDDDDDD
137   data_len =    50 bytes
138   digest =      0x56be34521d144c88dbb8c733f0e8b3f6
139 */
140
141 #ifdef TESTING
142 /*
143  *  cc -DTESTING -I ../include/ hmac.c md5.c -o hmac
144  *
145  *  ./hmac Jefe "what do ya want for nothing?"
146  */
147
148 #include <stdlib.h>
149
150 int main(int argc, char **argv)
151 {
152   uint8_t digest[16];
153   char *key;
154   int key_len;
155   char *text;
156   int text_len;
157   int i;
158
159   key = argv[1];
160   key_len = strlen(key);
161
162   text = argv[2];
163   text_len = strlen(text);
164
165   lrad_hmac_md5(text, text_len, key, key_len, digest);
166
167   for (i = 0; i < 16; i++) {
168     printf("%02x", digest[i]);
169   }
170   printf("\n");
171
172   exit(0);
173   return 0;
174 }
175
176 #endif