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