log_certificates() now shows keyid and availability of matching private key
[strongswan.git] / src / libstrongswan / crypto / 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 #include <string.h>
23
24 #include "hmac.h"
25
26
27 typedef struct private_hmac_t private_hmac_t;
28
29 /**
30 * Private data of a hmac_t object.
31 *
32 * The variable names are the same as in the RFC.
33 */
34 struct private_hmac_t {
35 /**
36 * Public hmac_t interface.
37 */
38 hmac_t hmac;
39
40 /**
41 * Block size, as in RFC.
42 */
43 u_int8_t b;
44
45 /**
46 * Hash function.
47 */
48 hasher_t *h;
49
50 /**
51 * Previously xor'ed key using opad.
52 */
53 chunk_t opaded_key;
54
55 /**
56 * Previously xor'ed key using ipad.
57 */
58 chunk_t ipaded_key;
59 };
60
61 /**
62 * Implementation of hmac_t.get_mac.
63 */
64 static void get_mac(private_hmac_t *this, chunk_t data, u_int8_t *out)
65 {
66 /* H(K XOR opad, H(K XOR ipad, text))
67 *
68 * if out is NULL, we append text to the inner hash.
69 * else, we complete the inner and do the outer.
70 *
71 */
72
73 u_int8_t buffer[this->h->get_hash_size(this->h)];
74 chunk_t inner;
75
76 if (out == NULL)
77 {
78 /* append data to inner */
79 this->h->get_hash(this->h, data, NULL);
80 }
81 else
82 {
83 /* append and do outer hash */
84 inner.ptr = buffer;
85 inner.len = this->h->get_hash_size(this->h);
86
87 /* complete inner */
88 this->h->get_hash(this->h, data, buffer);
89
90 /* do outer */
91 this->h->get_hash(this->h, this->opaded_key, NULL);
92 this->h->get_hash(this->h, inner, out);
93
94 /* reinit for next call */
95 this->h->get_hash(this->h, this->ipaded_key, NULL);
96 }
97 }
98
99 /**
100 * Implementation of hmac_t.allocate_mac.
101 */
102 static void allocate_mac(private_hmac_t *this, chunk_t data, chunk_t *out)
103 {
104 /* allocate space and use get_mac */
105 if (out == NULL)
106 {
107 /* append mode */
108 this->hmac.get_mac(&(this->hmac), data, NULL);
109 }
110 else
111 {
112 out->len = this->h->get_hash_size(this->h);
113 out->ptr = malloc(out->len);
114 this->hmac.get_mac(&(this->hmac), data, out->ptr);
115 }
116 }
117
118 /**
119 * Implementation of hmac_t.get_block_size.
120 */
121 static size_t get_block_size(private_hmac_t *this)
122 {
123 return this->h->get_hash_size(this->h);
124 }
125
126 /**
127 * Implementation of hmac_t.set_key.
128 */
129 static void set_key(private_hmac_t *this, chunk_t key)
130 {
131 int i;
132 u_int8_t buffer[this->b];
133
134 memset(buffer, 0, this->b);
135
136 if (key.len > this->b)
137 {
138 /* if key is too long, it will be hashed */
139 this->h->get_hash(this->h, key, buffer);
140 }
141 else
142 {
143 /* if not, just copy it in our pre-padded k */
144 memcpy(buffer, key.ptr, key.len);
145 }
146
147 /* apply ipad and opad to key */
148 for (i = 0; i < this->b; i++)
149 {
150 this->ipaded_key.ptr[i] = buffer[i] ^ 0x36;
151 this->opaded_key.ptr[i] = buffer[i] ^ 0x5C;
152 }
153
154 /* begin hashing of inner pad */
155 this->h->reset(this->h);
156 this->h->get_hash(this->h, this->ipaded_key, NULL);
157 }
158
159 /**
160 * Implementation of hmac_t.destroy.
161 */
162 static void destroy(private_hmac_t *this)
163 {
164 this->h->destroy(this->h);
165 free(this->opaded_key.ptr);
166 free(this->ipaded_key.ptr);
167 free(this);
168 }
169
170 /*
171 * Described in header
172 */
173 hmac_t *hmac_create(hash_algorithm_t hash_algorithm)
174 {
175 private_hmac_t *this;
176
177 this = malloc_thing(private_hmac_t);
178
179 /* set hmac_t methods */
180 this->hmac.get_mac = (void (*)(hmac_t *,chunk_t,u_int8_t*))get_mac;
181 this->hmac.allocate_mac = (void (*)(hmac_t *,chunk_t,chunk_t*))allocate_mac;
182 this->hmac.get_block_size = (size_t (*)(hmac_t *))get_block_size;
183 this->hmac.set_key = (void (*)(hmac_t *,chunk_t))set_key;
184 this->hmac.destroy = (void (*)(hmac_t *))destroy;
185
186 /* set b, according to hasher */
187 switch (hash_algorithm)
188 {
189 case HASH_SHA1:
190 case HASH_MD5:
191 this->b = 64;
192 break;
193 default:
194 free(this);
195 return NULL;
196 }
197
198 /* build the hasher */
199 this->h = hasher_create(hash_algorithm);
200
201 /* build ipad and opad */
202 this->opaded_key.ptr = malloc(this->b);
203 this->opaded_key.len = this->b;
204
205 this->ipaded_key.ptr = malloc(this->b);
206 this->ipaded_key.len = this->b;
207
208 return &(this->hmac);
209 }