All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
hmacmd5.c
Go to the documentation of this file.
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: fr_hmac_md5
26 */
27 
28 RCSID("$Id: 2c662ff368e46556edd2cfdf408bd0fca0ab5f18 $")
29 
30 #include <freeradius-devel/libradius.h>
31 #include <freeradius-devel/md5.h>
32 
33 /** Calculate HMAC using MD5
34  *
35  * @param digest Caller digest to be filled in.
36  * @param text Pointer to data stream.
37  * @param text_len length of data stream.
38  * @param key Pointer to authentication key.
39  * @param key_len Length of authentication key.
40  *
41  */
42 void fr_hmac_md5(uint8_t digest[MD5_DIGEST_LENGTH], uint8_t const *text, size_t text_len,
43  uint8_t const *key, size_t key_len)
44 {
45  FR_MD5_CTX context;
46  uint8_t k_ipad[65]; /* inner padding - key XORd with ipad */
47  uint8_t k_opad[65]; /* outer padding - key XORd with opad */
48  uint8_t tk[16];
49  int i;
50 
51  /* if key is longer than 64 bytes reset it to key=MD5(key) */
52  if (key_len > 64) {
53  FR_MD5_CTX tctx;
54 
55  fr_md5_init(&tctx);
56  fr_md5_update(&tctx, key, key_len);
57  fr_md5_final(tk, &tctx);
58 
59  key = tk;
60  key_len = 16;
61  }
62 
63  /*
64  * the HMAC_MD5 transform looks like:
65  *
66  * MD5(K XOR opad, MD5(K XOR ipad, text))
67  *
68  * where K is an n byte key
69  * ipad is the byte 0x36 repeated 64 times
70 
71  * opad is the byte 0x5c repeated 64 times
72  * and text is the data being protected
73  */
74 
75  /* start out by storing key in pads */
76  memset( k_ipad, 0, sizeof(k_ipad));
77  memset( k_opad, 0, sizeof(k_opad));
78  memcpy( k_ipad, key, key_len);
79  memcpy( k_opad, key, key_len);
80 
81  /* XOR key with ipad and opad values */
82  for (i = 0; i < 64; i++) {
83  k_ipad[i] ^= 0x36;
84  k_opad[i] ^= 0x5c;
85  }
86  /*
87  * perform inner MD5
88  */
89  fr_md5_init(&context); /* init context for 1st
90  * pass */
91  fr_md5_update(&context, k_ipad, 64); /* start with inner pad */
92  fr_md5_update(&context, text, text_len); /* then text of datagram */
93  fr_md5_final(digest, &context); /* finish up 1st pass */
94  /*
95  * perform outer MD5
96  */
97  fr_md5_init(&context); /* init context for 2nd
98  * pass */
99  fr_md5_update(&context, k_opad, 64); /* start with outer pad */
100  fr_md5_update(&context, digest, 16); /* then results of 1st
101  * hash */
102  fr_md5_final(digest, &context); /* finish up 2nd pass */
103 }
104 
105 /*
106 Test Vectors (Trailing '\0' of a character string not included in test):
107 
108  key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
109  key_len = 16 bytes
110  data = "Hi There"
111  data_len = 8 bytes
112  digest = 0x9294727a3638bb1c13f48ef8158bfc9d
113 
114  key = "Jefe"
115  data = "what do ya want for nothing?"
116  data_len = 28 bytes
117  digest = 0x750c783e6ab0b503eaa86e310a5db738
118 
119  key = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
120 
121  key_len 16 bytes
122  data = 0xDDDDDDDDDDDDDDDDDDDD...
123  ..DDDDDDDDDDDDDDDDDDDD...
124  ..DDDDDDDDDDDDDDDDDDDD...
125  ..DDDDDDDDDDDDDDDDDDDD...
126  ..DDDDDDDDDDDDDDDDDDDD
127  data_len = 50 bytes
128  digest = 0x56be34521d144c88dbb8c733f0e8b3f6
129 */
130 
131 #ifdef TESTING
132 /*
133  * cc -DTESTING -I ../include/ hmac.c md5.c -o hmac
134  *
135  * ./hmac Jefe "what do ya want for nothing?"
136  */
137 int main(int argc, char **argv)
138 {
139  uint8_t digest[16];
140  char *key;
141  int key_len;
142  char *text;
143  int text_len;
144  int i;
145 
146  key = argv[1];
147  key_len = strlen(key);
148 
149  text = argv[2];
150  text_len = strlen(text);
151 
152  fr_hmac_md5(digest, text, text_len, key, key_len);
153 
154  for (i = 0; i < 16; i++) {
155  printf("%02x", digest[i]);
156  }
157  printf("\n");
158 
159  exit(0);
160  return 0;
161 }
162 
163 #endif
void fr_md5_init(FR_MD5_CTX *ctx)
Initialise a new MD5 context.
Definition: md5.c:84
void fr_md5_update(FR_MD5_CTX *ctx, uint8_t const *in, size_t inlen) CC_BOUNDED(__string__
void fr_hmac_md5(uint8_t digest[MD5_DIGEST_LENGTH], uint8_t const *text, size_t text_len, uint8_t const *key, size_t key_len)
Calculate HMAC using MD5.
Definition: hmacmd5.c:42
int main(int argc, char *argv[])
Definition: radattr.c:959
void void fr_md5_final(uint8_t out[MD5_DIGEST_LENGTH], FR_MD5_CTX *ctx) CC_BOUNDED(__minbytes__
void void MD5_DIGEST_LENGTH
Definition: md5.h:65
#define RCSID(id)
Definition: build.h:135