- removed key from constructor
[strongswan.git] / Source / charon / transforms / hmac.c
1 /**
2 * @file hmac.c
3 *
4 * @brief Implementation of message authentication
5 * using cryptographic hash functions (HMAC). See RFC2104.
6 *
7 */
8
9 /*
10 * Copyright (C) 2005 Jan Hutter, Martin Willi
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24
25 #include "hmac.h"
26
27 #include "../utils/allocator.h"
28
29 /**
30 * Private data of an hmac_t object.
31 *
32 */
33 typedef struct private_hmac_s private_hmac_t;
34
35 struct private_hmac_s {
36 /**
37 * public hmac_t interface
38 */
39 hmac_t public;
40
41 /**
42 * key, as in RFC
43 */
44 chunk_t k;
45
46 /**
47 * block size, as in RFC
48 */
49 u_int8_t b;
50
51 /**
52 * hash function
53 */
54 hasher_t *h;
55
56 /**
57 * previously xor'ed key using opad
58 */
59 chunk_t opaded_key;
60 /**
61 * previously xor'ed key using ipad
62 */
63 chunk_t ipaded_key;
64 };
65
66 /**
67 * implementation of hmac_t.get_mac
68 */
69 static status_t get_mac(private_hmac_t *this, chunk_t data, u_int8_t *out)
70 {
71 /* H(K XOR opad, H(K XOR ipad, text)) */
72 u_int8_t buffer[this->h->get_block_size(this->h)];
73 chunk_t inner;
74 inner.ptr = buffer;
75 inner.len = this->h->get_block_size(this->h);
76
77 /* inner */
78 this->h->get_hash(this->h, this->ipaded_key, NULL);
79 this->h->get_hash(this->h, data, buffer);
80
81 /* outer */
82 this->h->get_hash(this->h, this->opaded_key, NULL);
83 this->h->get_hash(this->h, inner, out);
84
85 return SUCCESS;
86 }
87
88 /**
89 * implementation of hmac_t.allocate_mac
90 */
91 static status_t allocate_mac(private_hmac_t *this, chunk_t data, chunk_t *out)
92 {
93 /* allocate space and use get_mac */
94 out->len = this->h->get_block_size(this->h);
95 out->ptr = allocator_alloc(out->len);
96 if (out->ptr == NULL)
97 {
98 return OUT_OF_RES;
99 }
100 this->public.get_mac(&(this->public), data, out->ptr);
101 return SUCCESS;
102 }
103
104 /**
105 * implementation of hmac_t.get_block_size
106 */
107 static size_t get_block_size(private_hmac_t *this)
108 {
109 return this->h->get_block_size(this->h);
110 }
111
112 /**
113 * implementation of hmac_t.set_key
114 */
115 static status_t set_key(private_hmac_t *this, chunk_t key)
116 {
117 int i;
118 u_int8_t buffer[this->b];
119
120 memset(buffer, 0, this->b);
121
122 if (key.len > this->b)
123 {
124 /* if key is too long, it will be hashed */
125 this->h->get_hash(this->h, key, buffer);
126 }
127 else
128 {
129 /* if not, just copy it in our pre-padded k */
130 memcpy(buffer, key.ptr, key.len);
131 }
132
133 /* apply ipad and opad to key */
134 for (i = 0; i < this->b; i++)
135 {
136 this->ipaded_key.ptr[i] = buffer[i] ^ 0x36;
137 this->opaded_key.ptr[i] = buffer[i] ^ 0x5C;
138 }
139
140 return SUCCESS;;
141 }
142
143 /**
144 * implementation of hmac_t.destroy
145 */
146 static status_t destroy(private_hmac_t *this)
147 {
148 this->h->destroy(this->h);
149 allocator_free(this->k.ptr);
150 allocator_free(this->opaded_key.ptr);
151 allocator_free(this->ipaded_key.ptr);
152 allocator_free(this);
153 return SUCCESS;
154 }
155
156 /*
157 * Described in header
158 */
159 hmac_t *hmac_create(hash_algorithm_t hash_algorithm)
160 {
161 private_hmac_t *this;
162
163 this = allocator_alloc_thing(private_hmac_t);
164 if (this == NULL)
165 {
166 return NULL;
167 }
168 /* set public methods */
169 this->public.get_mac = (size_t (*)(hmac_t *,chunk_t,u_int8_t*))get_mac;
170 this->public.allocate_mac = (size_t (*)(hmac_t *,chunk_t,chunk_t*))allocate_mac;
171 this->public.get_block_size = (size_t (*)(hmac_t *))get_block_size;
172 this->public.set_key = (status_t (*)(hmac_t *,chunk_t))set_key;
173 this->public.destroy = (status_t (*)(hmac_t *))destroy;
174
175 /* set b, according to hasher */
176 switch (hash_algorithm)
177 {
178 case HASH_SHA1:
179 this->b = 64;
180 break;
181 default:
182 allocator_free(this);
183 return NULL;
184 }
185
186 /* build the hasher */
187 this->h = hasher_create(hash_algorithm);
188 if (this->h == NULL)
189 {
190 allocator_free(this);
191 return NULL;
192 }
193
194
195
196 /* build ipad and opad */
197 this->opaded_key.ptr = allocator_alloc(this->b);
198 this->opaded_key.len = this->b;
199 if (this->opaded_key.ptr == NULL)
200 {
201 this->h->destroy(this->h);
202 allocator_free(this->k.ptr);
203 allocator_free(this);
204 return NULL;
205 }
206 this->ipaded_key.ptr = allocator_alloc(this->b);
207 this->ipaded_key.len = this->b;
208 if (this->ipaded_key.ptr == NULL)
209 {
210 this->h->destroy(this->h);
211 allocator_free(this->opaded_key.ptr);
212 allocator_free(this);
213 return NULL;
214 }
215
216
217 return &(this->public);
218 }