93bbffade45411d57d8d3b438bad031793b66a01
[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.destroy
114 */
115 static status_t destroy(private_hmac_t *this)
116 {
117 this->h->destroy(this->h);
118 allocator_free(this->k.ptr);
119 allocator_free(this->opaded_key.ptr);
120 allocator_free(this->ipaded_key.ptr);
121 allocator_free(this);
122 return SUCCESS;
123 }
124
125 /*
126 * Described in header
127 */
128 hmac_t *hmac_create(hash_algorithm_t hash_algorithm, chunk_t key)
129 {
130 private_hmac_t *this;
131 u_int8_t i;
132
133 this = allocator_alloc_thing(private_hmac_t);
134 if (this == NULL)
135 {
136 return NULL;
137 }
138 /* set public methods */
139 this->public.get_mac = (size_t (*)(hmac_t *,chunk_t,u_int8_t*))get_mac;
140 this->public.allocate_mac = (size_t (*)(hmac_t *,chunk_t,chunk_t*))allocate_mac;
141 this->public.get_block_size = (size_t (*)(hmac_t *))get_block_size;
142 this->public.destroy = (status_t (*)(hmac_t *))destroy;
143
144 /* set b, according to hasher */
145 switch (hash_algorithm)
146 {
147 case HASH_SHA1:
148 this->b = 64;
149 break;
150 default:
151 allocator_free(this);
152 return NULL;
153 }
154
155 /* build the hasher */
156 this->h = hasher_create(hash_algorithm);
157 if (this->h == NULL)
158 {
159 allocator_free(this);
160 return NULL;
161 }
162
163 /* k must be b long, padded with 0x00 */
164 this->k.ptr = allocator_alloc(this->b);
165 this->k.len = this->b;
166 if (this->k.ptr == NULL)
167 {
168 this->h->destroy(this->h);
169 allocator_free(this);
170 }
171 memset(this->k.ptr, 0, this->k.len);
172
173 if (key.len > this->h->get_block_size(this->h))
174 {
175 /* if key is too long, it will be hashed */
176 this->h->get_hash(this->h, key, this->k.ptr);
177 }
178 else
179 {
180 /* if not, just copy it in our pre-padded k */
181 memcpy(this->k.ptr, key.ptr, key.len);
182 }
183
184 /* build ipad and opad */
185 this->opaded_key.ptr = allocator_alloc(this->b);
186 this->opaded_key.len = this->b;
187 if (this->opaded_key.ptr == NULL)
188 {
189 this->h->destroy(this->h);
190 allocator_free(this->k.ptr);
191 allocator_free(this);
192 return NULL;
193 }
194 this->ipaded_key.ptr = allocator_alloc(this->b);
195 this->ipaded_key.len = this->b;
196 if (this->ipaded_key.ptr == NULL)
197 {
198 this->h->destroy(this->h);
199 allocator_free(this->k.ptr);
200 allocator_free(this->opaded_key.ptr);
201 allocator_free(this);
202 return NULL;
203 }
204
205 for (i = 0; i < this->b; i++)
206 {
207 this->ipaded_key.ptr[i] = this->k.ptr[i] ^ 0x36;
208 this->opaded_key.ptr[i] = this->k.ptr[i] ^ 0x5C;
209 }
210
211 return &(this->public);
212 }