port fix from branch_1_1
[freeradius.git] / src / lib / hmacsha1.c
1 /*
2  * Adapted from hmac.c (HMAC-MD5) for use by SHA1.
3  * by <mcr@sandelman.ottawa.on.ca>. Test cases from RFC2202.
4  *
5  */
6
7 /*
8 ** Function: hmac_sha1
9 */
10
11 #include <freeradius-devel/ident.h>
12 RCSID("$Id$")
13
14 #include <freeradius-devel/autoconf.h>
15
16 #include <string.h>
17 #include <sys/types.h>
18
19 #ifdef HAVE_STDINT_H
20 #include <stdint.h>
21 #endif
22
23 #include <freeradius-devel/sha1.h>
24
25 #include <freeradius-devel/missing.h>
26 #include <freeradius-devel/libradius.h>
27
28 /*
29 uint8_t*  text;                pointer to data stream
30 int             text_len;            length of data stream
31 uint8_t*  key;                 pointer to authentication key
32 int             key_len;             length of authentication key
33 uint8_t*  digest;              caller digest to be filled in
34 */
35
36 #ifdef HMAC_SHA1_DATA_PROBLEMS
37 unsigned int sha1_data_problems = 0;
38 #endif
39
40 void
41 lrad_hmac_sha1(const uint8_t *text, int text_len,
42                const uint8_t *key, int key_len,
43                uint8_t *digest)
44 {
45         SHA1_CTX context;
46         uint8_t k_ipad[65];    /* inner padding -
47                                       * key XORd with ipad
48                                       */
49         uint8_t k_opad[65];    /* outer padding -
50                                       * key XORd with opad
51                                       */
52         uint8_t tk[20];
53         int i;
54         /* if key is longer than 64 bytes reset it to key=SHA1(key) */
55         if (key_len > 64) {
56
57                 SHA1_CTX      tctx;
58
59                 SHA1Init(&tctx);
60                 SHA1Update(&tctx, key, key_len);
61                 SHA1Final(tk, &tctx);
62
63                 key = tk;
64                 key_len = 20;
65         }
66
67 #ifdef HMAC_SHA1_DATA_PROBLEMS
68         if(sha1_data_problems)
69         {
70                 int j,k;
71
72                 printf("\nhmac-sha1 key(%d): ", key_len);
73                 j=0; k=0;
74                 for (i = 0; i < key_len; i++) {
75                         if(j==4) {
76                                 printf("_");
77                                 j=0;
78                         }
79                         j++;
80
81                         printf("%02x", key[i]);
82                 }
83                 printf("\nDATA: (%d)    ",text_len);
84
85                 j=0; k=0;
86                 for (i = 0; i < text_len; i++) {
87                   if(k==20) {
88                     printf("\n            ");
89                     k=0;
90                     j=0;
91                   }
92                   if(j==4) {
93                     printf("_");
94                     j=0;
95                   }
96                   k++;
97                   j++;
98
99                   printf("%02x", text[i]);
100                 }
101                 printf("\n");
102         }
103 #endif
104
105
106         /*
107          * the HMAC_SHA1 transform looks like:
108          *
109          * SHA1(K XOR opad, SHA1(K XOR ipad, text))
110          *
111          * where K is an n byte key
112          * ipad is the byte 0x36 repeated 64 times
113
114          * opad is the byte 0x5c repeated 64 times
115          * and text is the data being protected
116          */
117
118         /* start out by storing key in pads */
119         memset( k_ipad, 0, sizeof(k_ipad));
120         memset( k_opad, 0, sizeof(k_opad));
121         memcpy( k_ipad, key, key_len);
122         memcpy( k_opad, key, key_len);
123
124         /* XOR key with ipad and opad values */
125         for (i = 0; i < 64; i++) {
126                 k_ipad[i] ^= 0x36;
127                 k_opad[i] ^= 0x5c;
128         }
129         /*
130          * perform inner SHA1
131          */
132         SHA1Init(&context);                   /* init context for 1st
133                                               * pass */
134         SHA1Update(&context, k_ipad, 64);      /* start with inner pad */
135         SHA1Update(&context, text, text_len); /* then text of datagram */
136         SHA1Final(digest, &context);          /* finish up 1st pass */
137         /*
138          * perform outer MD5
139          */
140         SHA1Init(&context);                   /* init context for 2nd
141                                               * pass */
142         SHA1Update(&context, k_opad, 64);     /* start with outer pad */
143         SHA1Update(&context, digest, 20);     /* then results of 1st
144                                               * hash */
145         SHA1Final(digest, &context);          /* finish up 2nd pass */
146
147 #ifdef HMAC_SHA1_DATA_PROBLEMS
148         if(sha1_data_problems)
149         {
150           int j;
151
152                 printf("\nhmac-sha1 mac(20): ");
153                 j=0;
154                 for (i = 0; i < 20; i++) {
155                         if(j==4) {
156                                 printf("_");
157                                 j=0;
158                         }
159                         j++;
160
161                         printf("%02x", digest[i]);
162                 }
163                 printf("\n");
164         }
165 #endif
166 }
167
168 /*
169 Test Vectors (Trailing '\0' of a character string not included in test):
170
171   key =         "Jefe"
172   data =        "what do ya want for nothing?"
173   data_len =    28 bytes
174   digest =      effcdf6ae5eb2fa2d27416d5f184df9c259a7c79
175
176   key =         0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
177
178   key_len       16 bytes
179   data =        0xDDDDDDDDDDDDDDDDDDDD...
180                 ..DDDDDDDDDDDDDDDDDDDD...
181                 ..DDDDDDDDDDDDDDDDDDDD...
182                 ..DDDDDDDDDDDDDDDDDDDD...
183                 ..DDDDDDDDDDDDDDDDDDDD
184   data_len =    50 bytes
185   digest =      0x56be34521d144c88dbb8c733f0e8b3f6
186 */
187
188 #ifdef TESTING
189 /*
190  *  cc -DTESTING -I ../include/ hmac.c sha1.c -o hmac
191  *
192  *  ./hmac Jefe "what do ya want for nothing?"
193  */
194
195 #include <stdlib.h>
196
197 int main(int argc, char **argv)
198 {
199   uint8_t digest[20];
200   char *key;
201   int key_len;
202   char *text;
203   int text_len;
204   int i;
205
206   key = argv[1];
207   key_len = strlen(key);
208
209   text = argv[2];
210   text_len = strlen(text);
211
212   lrad_hmac_sha1(text, text_len, key, key_len, digest);
213
214   for (i = 0; i < 20; i++) {
215     printf("%02x", digest[i]);
216   }
217   printf("\n");
218
219   exit(0);
220   return 0;
221 }
222
223 #endif