5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1999 - 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "silcincludes.h"
24 struct SilcHmacStruct {
27 bool allocated_hash; /* TRUE if the hash was allocated */
32 unsigned char inner_pad[64];
33 unsigned char outer_pad[64];
36 /* XXX backwards thingy for 0.5.x MAC computation.
37 XXX Remove in 0.7.x */
38 bool backwards_support;
41 /* List of dynamically registered HMACs. */
42 SilcDList silc_hmac_list = NULL;
44 /* Default hmacs for silc_hmac_register_default(). */
45 SilcHmacObject silc_default_hmacs[] =
47 { "hmac-sha1-96", 12 },
48 { "hmac-md5-96", 12 },
55 static void silc_hmac_init_internal(SilcHmac hmac, unsigned char *key,
58 SilcHash hash = hmac->hash;
59 unsigned char hvalue[20];
62 memset(hmac->inner_pad, 0, sizeof(hmac->inner_pad));
63 memset(hmac->outer_pad, 0, sizeof(hmac->outer_pad));
65 /* If the key length is more than block size of the hash function, the
67 if (key_len > hash->hash->block_len) {
68 silc_hash_make(hash, key, key_len, hvalue);
70 key_len = hash->hash->hash_len;
73 /* Copy the key into the pads */
74 memcpy(hmac->inner_pad, key, key_len);
75 memcpy(hmac->outer_pad, key, key_len);
77 /* XOR the key with pads */
78 for (i = 0; i < hash->hash->block_len; i++) {
79 hmac->inner_pad[i] ^= 0x36;
80 hmac->outer_pad[i] ^= 0x5c;
84 /* Registers a new HMAC into the SILC. This function is used at the
85 initialization of the SILC. */
87 bool silc_hmac_register(SilcHmacObject *hmac)
91 SILC_LOG_DEBUG(("Registering new HMAC `%s'", hmac->name));
93 new = silc_calloc(1, sizeof(*new));
94 new->name = strdup(hmac->name);
98 if (silc_hmac_list == NULL)
99 silc_hmac_list = silc_dlist_init();
100 silc_dlist_add(silc_hmac_list, new);
105 /* Unregister a HMAC from the SILC. */
107 bool silc_hmac_unregister(SilcHmacObject *hmac)
109 SilcHmacObject *entry;
111 SILC_LOG_DEBUG(("Unregistering HMAC"));
116 silc_dlist_start(silc_hmac_list);
117 while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
118 if (hmac == SILC_ALL_HMACS || entry == hmac) {
119 silc_dlist_del(silc_hmac_list, entry);
121 if (silc_dlist_count(silc_hmac_list) == 0) {
122 silc_dlist_uninit(silc_hmac_list);
123 silc_hmac_list = NULL;
133 /* Function that registers all the default hmacs (all builtin ones).
134 The application may use this to register the default hmacs if
135 specific hmacs in any specific order is not wanted. */
137 bool silc_hmac_register_default(void)
141 for (i = 0; silc_default_hmacs[i].name; i++)
142 silc_hmac_register(&(silc_default_hmacs[i]));
147 /* Allocates a new SilcHmac object of name of `name'. The `hash' may
148 be provided as argument. If provided it is used as the hash function
149 of the HMAC. If it is NULL then the hash function is allocated and
150 the name of the hash algorithm is derived from the `name'. */
152 bool silc_hmac_alloc(char *name, SilcHash hash, SilcHmac *new_hmac)
154 SilcHmacObject *entry;
156 SILC_LOG_DEBUG(("Allocating new HMAC"));
158 /* Allocate the new object */
159 *new_hmac = silc_calloc(1, sizeof(**new_hmac));
162 char *tmp = strdup(name), *hname;
165 if (strchr(hname, '-'))
166 hname = strchr(hname, '-') + 1;
167 if (strchr(hname, '-'))
168 *strchr(hname, '-') = '\0';
170 if (!silc_hash_alloc(hname, &hash)) {
172 silc_free(*new_hmac);
177 (*new_hmac)->allocated_hash = TRUE;
181 (*new_hmac)->hash = hash;
183 if (silc_hmac_list) {
184 silc_dlist_start(silc_hmac_list);
185 while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
186 if (!strcmp(entry->name, name)) {
187 (*new_hmac)->hmac = entry;
193 silc_free(*new_hmac);
198 /* Free's the SilcHmac object. */
200 void silc_hmac_free(SilcHmac hmac)
203 if (hmac->allocated_hash)
204 silc_hash_free(hmac->hash);
207 memset(hmac->key, 0, hmac->key_len);
208 silc_free(hmac->key);
211 silc_free(hmac->hash_context);
216 /* Returns the length of the MAC that the HMAC will produce. */
218 uint32 silc_hmac_len(SilcHmac hmac)
220 return hmac->hmac->len;
223 /* Get hash context */
225 SilcHash silc_hmac_get_hash(SilcHmac hmac)
230 /* Return name of hmac */
232 const char *silc_hmac_get_name(SilcHmac hmac)
234 return hmac->hmac->name;
237 /* Returns TRUE if HMAC `name' is supported. */
239 bool silc_hmac_is_supported(const char *name)
241 SilcHmacObject *entry;
246 if (silc_hmac_list) {
247 silc_dlist_start(silc_hmac_list);
248 while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
249 if (!strcmp(entry->name, name))
257 /* Returns comma separated list of supported HMACs. */
259 char *silc_hmac_get_supported()
261 SilcHmacObject *entry;
266 if (silc_hmac_list) {
267 silc_dlist_start(silc_hmac_list);
268 while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
269 len += strlen(entry->name);
270 list = silc_realloc(list, len + 1);
272 memcpy(list + (len - strlen(entry->name)),
273 entry->name, strlen(entry->name));
274 memcpy(list + len, ",", 1);
283 /* Sets the HMAC key used in the HMAC creation */
285 void silc_hmac_set_key(SilcHmac hmac, const unsigned char *key,
289 memset(hmac->key, 0, hmac->key_len);
290 silc_free(hmac->key);
292 hmac->key = silc_calloc(key_len, sizeof(unsigned char));
293 hmac->key_len = key_len;
294 memcpy(hmac->key, key, key_len);
297 /* Create the HMAC. This is thee make_hmac function pointer. This
298 uses the internal key set with silc_hmac_set_key. */
300 void silc_hmac_make(SilcHmac hmac, unsigned char *data,
301 uint32 data_len, unsigned char *return_hash,
304 SILC_LOG_DEBUG(("Making HMAC for message"));
306 silc_hmac_init(hmac);
307 silc_hmac_update(hmac, data, data_len);
308 silc_hmac_final(hmac, return_hash, return_len);
311 /* Creates HMAC just as above except that this doesn't use the internal
312 key. The key is sent as argument to the function. */
314 void silc_hmac_make_with_key(SilcHmac hmac, unsigned char *data,
316 unsigned char *key, uint32 key_len,
317 unsigned char *return_hash,
320 SILC_LOG_DEBUG(("Making HMAC for message"));
322 silc_hmac_init_with_key(hmac, key, key_len);
323 silc_hmac_update(hmac, data, data_len);
324 silc_hmac_final(hmac, return_hash, return_len);
327 /* Creates the HMAC just as above except that the hash value is truncated
328 to the truncated_len sent as argument. NOTE: One should not truncate to
329 less than half of the length of original hash value. However, this
330 routine allows these dangerous truncations. */
332 void silc_hmac_make_truncated(SilcHmac hmac, unsigned char *data,
334 uint32 truncated_len,
335 unsigned char *return_hash)
337 unsigned char hvalue[20];
339 SILC_LOG_DEBUG(("Making HMAC for message"));
341 silc_hmac_init(hmac);
342 silc_hmac_update(hmac, data, data_len);
343 silc_hmac_final(hmac, return_hash, NULL);
344 memcpy(return_hash, hvalue, truncated_len);
345 memset(hvalue, 0, sizeof(hvalue));
348 /* Init HMAC for silc_hmac_update and silc_hmac_final. */
350 void silc_hmac_init(SilcHmac hmac)
352 silc_hmac_init_with_key(hmac, hmac->key, hmac->key_len);
355 /* Same as above but with specific key */
357 void silc_hmac_init_with_key(SilcHmac hmac, const unsigned char *key,
360 SilcHash hash = hmac->hash;
362 silc_hmac_init_internal(hmac, hmac->key, hmac->key_len);
364 if (!hmac->hash_context)
365 hmac->hash_context = silc_calloc(1, hash->hash->context_len());
367 hash->hash->init(hmac->hash_context);
368 hash->hash->update(hmac->hash_context, hmac->inner_pad,
369 hash->hash->block_len);
372 /* Add data to be used in the MAC computation. */
374 void silc_hmac_update(SilcHmac hmac, const unsigned char *data,
377 SilcHash hash = hmac->hash;
378 hash->hash->update(hmac->hash_context, (unsigned char *)data, data_len);
381 /* Compute the final MAC. */
383 void silc_hmac_final(SilcHmac hmac, unsigned char *return_hash,
386 SilcHash hash = hmac->hash;
387 unsigned char mac[20];
389 hash->hash->final(hmac->hash_context, mac);
390 hash->hash->init(hmac->hash_context);
391 hash->hash->update(hmac->hash_context, hmac->outer_pad,
392 hash->hash->block_len);
393 hash->hash->update(hmac->hash_context, mac, hash->hash->hash_len);
394 hash->hash->final(hmac->hash_context, mac);
395 memcpy(return_hash, mac, hmac->hmac->len);
396 memset(mac, 0, sizeof(mac));
399 *return_len = hmac->hmac->len;
402 void silc_hmac_set_b(SilcHmac hmac)
404 hmac->backwards_support = TRUE;
407 bool silc_hmac_get_b(SilcHmac hmac)
409 return hmac->backwards_support;