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