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