import from branch_1_1:
[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/libradius.h>
32 #include <freeradius-devel/md5.h>
33
34 /*
35 unsigned char*  text;                pointer to data stream
36 int             text_len;            length of data stream
37 unsigned char*  key;                 pointer to authentication key
38 int             key_len;             length of authentication key
39 unsigned char*  digest;              caller digest to be filled in
40 */
41
42 void
43 lrad_hmac_md5(const uint8_t *text, int text_len,
44               const uint8_t *key, int key_len,
45               uint8_t *digest)
46 {
47         lrad_MD5_CTX context;
48         uint8_t k_ipad[65];    /* inner padding -
49                                       * key XORd with ipad
50                                       */
51         uint8_t k_opad[65];    /* outer padding -
52                                       * key XORd with opad
53                                       */
54         uint8_t tk[16];
55         int i;
56         /* if key is longer than 64 bytes reset it to key=MD5(key) */
57         if (key_len > 64) {
58
59                 lrad_MD5_CTX      tctx;
60
61                 lrad_MD5Init(&tctx);
62                 lrad_MD5Update(&tctx, key, key_len);
63                 lrad_MD5Final(tk, &tctx);
64
65                 key = tk;
66                 key_len = 16;
67         }
68
69         /*
70          * the HMAC_MD5 transform looks like:
71          *
72          * MD5(K XOR opad, MD5(K XOR ipad, text))
73          *
74          * where K is an n byte key
75          * ipad is the byte 0x36 repeated 64 times
76
77          * opad is the byte 0x5c repeated 64 times
78          * and text is the data being protected
79          */
80
81         /* start out by storing key in pads */
82         memset( k_ipad, 0, sizeof(k_ipad));
83         memset( k_opad, 0, sizeof(k_opad));
84         memcpy( k_ipad, key, key_len);
85         memcpy( k_opad, key, key_len);
86
87         /* XOR key with ipad and opad values */
88         for (i = 0; i < 64; i++) {
89                 k_ipad[i] ^= 0x36;
90                 k_opad[i] ^= 0x5c;
91         }
92         /*
93          * perform inner MD5
94          */
95         lrad_MD5Init(&context);                   /* init context for 1st
96                                               * pass */
97         lrad_MD5Update(&context, k_ipad, 64);      /* start with inner pad */
98         lrad_MD5Update(&context, text, text_len); /* then text of datagram */
99         lrad_MD5Final(digest, &context);          /* finish up 1st pass */
100         /*
101          * perform outer MD5
102          */
103         lrad_MD5Init(&context);                   /* init context for 2nd
104                                               * pass */
105         lrad_MD5Update(&context, k_opad, 64);     /* start with outer pad */
106         lrad_MD5Update(&context, digest, 16);     /* then results of 1st
107                                               * hash */
108         lrad_MD5Final(digest, &context);          /* finish up 2nd pass */
109 }
110
111 /*
112 Test Vectors (Trailing '\0' of a character string not included in test):
113
114   key =         0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
115   key_len =     16 bytes
116   data =        "Hi There"
117   data_len =    8  bytes
118   digest =      0x9294727a3638bb1c13f48ef8158bfc9d
119
120   key =         "Jefe"
121   data =        "what do ya want for nothing?"
122   data_len =    28 bytes
123   digest =      0x750c783e6ab0b503eaa86e310a5db738
124
125   key =         0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
126
127   key_len       16 bytes
128   data =        0xDDDDDDDDDDDDDDDDDDDD...
129                 ..DDDDDDDDDDDDDDDDDDDD...
130                 ..DDDDDDDDDDDDDDDDDDDD...
131                 ..DDDDDDDDDDDDDDDDDDDD...
132                 ..DDDDDDDDDDDDDDDDDDDD
133   data_len =    50 bytes
134   digest =      0x56be34521d144c88dbb8c733f0e8b3f6
135 */
136
137 #ifdef TESTING
138 /*
139  *  cc -DTESTING -I ../include/ hmac.c md5.c -o hmac
140  *
141  *  ./hmac Jefe "what do ya want for nothing?"
142  */
143
144 #include <stdlib.h>
145
146 int main(int argc, char **argv)
147 {
148   uint8_t digest[16];
149   char *key;
150   int key_len;
151   char *text;
152   int text_len;
153   int i;
154
155   key = argv[1];
156   key_len = strlen(key);
157
158   text = argv[2];
159   text_len = strlen(text);
160
161   lrad_hmac_md5(text, text_len, key, key_len, digest);
162
163   for (i = 0; i < 16; i++) {
164     printf("%02x", digest[i]);
165   }
166   printf("\n");
167
168   exit(0);
169   return 0;
170 }
171
172 #endif