5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1999 - 2006 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.
24 struct SilcHmacStruct {
27 unsigned char inner_pad[64];
28 unsigned char outer_pad[64];
30 unsigned int key_len : 31;
31 unsigned int allocated_hash : 1; /* TRUE if the hash was allocated */
35 /* List of dynamically registered HMACs. */
36 SilcDList silc_hmac_list = NULL;
37 #endif /* SILC_SYMBIAN */
39 /* Default hmacs for silc_hmac_register_default(). */
40 const SilcHmacObject silc_default_hmacs[] =
42 { "hmac-sha256-96", 12 },
43 { "hmac-sha1-96", 12 },
44 { "hmac-md5-96", 12 },
45 { "hmac-sha256", 32 },
52 static void silc_hmac_init_internal(SilcHmac hmac, unsigned char *key,
55 SilcHash hash = hmac->hash;
57 unsigned char hvalue[SILC_HASH_MAXLEN];
60 memset(hmac->inner_pad, 0, sizeof(hmac->inner_pad));
61 memset(hmac->outer_pad, 0, sizeof(hmac->outer_pad));
63 block_len = silc_hash_block_len(hash);
65 /* If the key length is more than block size of the hash function, the
67 if (key_len > block_len) {
68 silc_hash_make(hash, key, key_len, hvalue);
70 key_len = silc_hash_len(hash);
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 < 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 SilcBool silc_hmac_register(const SilcHmacObject *hmac)
92 SILC_LOG_DEBUG(("Registering new HMAC `%s'", hmac->name));
94 /* Check for existing */
96 SilcHmacObject *entry;
97 silc_dlist_start(silc_hmac_list);
98 while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
99 if (!strcmp(entry->name, hmac->name))
104 new = silc_calloc(1, sizeof(*new));
107 new->name = strdup(hmac->name);
108 new->len = hmac->len;
111 if (silc_hmac_list == NULL)
112 silc_hmac_list = silc_dlist_init();
113 silc_dlist_add(silc_hmac_list, new);
115 #endif /* SILC_SYMBIAN */
119 /* Unregister a HMAC from the SILC. */
121 SilcBool silc_hmac_unregister(SilcHmacObject *hmac)
124 SilcHmacObject *entry;
126 SILC_LOG_DEBUG(("Unregistering HMAC"));
131 silc_dlist_start(silc_hmac_list);
132 while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
133 if (hmac == SILC_ALL_HMACS || entry == hmac) {
134 silc_dlist_del(silc_hmac_list, entry);
135 silc_free(entry->name);
138 if (silc_dlist_count(silc_hmac_list) == 0) {
139 silc_dlist_uninit(silc_hmac_list);
140 silc_hmac_list = NULL;
147 #endif /* SILC_SYMBIAN */
151 /* Function that registers all the default hmacs (all builtin ones).
152 The application may use this to register the default hmacs if
153 specific hmacs in any specific order is not wanted. */
155 SilcBool silc_hmac_register_default(void)
160 for (i = 0; silc_default_hmacs[i].name; i++)
161 silc_hmac_register(&(silc_default_hmacs[i]));
163 #endif /* SILC_SYMBIAN */
167 SilcBool silc_hmac_unregister_all(void)
170 SilcHmacObject *entry;
175 silc_dlist_start(silc_hmac_list);
176 while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
177 silc_hmac_unregister(entry);
181 #endif /* SILC_SYMBIAN */
185 /* Allocates a new SilcHmac object of name of `name'. The `hash' may
186 be provided as argument. If provided it is used as the hash function
187 of the HMAC. If it is NULL then the hash function is allocated and
188 the name of the hash algorithm is derived from the `name'. */
190 SilcBool silc_hmac_alloc(const char *name, SilcHash hash, SilcHmac *new_hmac)
192 SILC_LOG_DEBUG(("Allocating new HMAC"));
194 /* Allocate the new object */
195 *new_hmac = silc_calloc(1, sizeof(**new_hmac));
200 char *tmp = strdup(name), *hname;
203 if (strchr(hname, '-'))
204 hname = strchr(hname, '-') + 1;
205 if (strchr(hname, '-'))
206 *strchr(hname, '-') = '\0';
208 if (!silc_hash_alloc(hname, &hash)) {
210 silc_free(*new_hmac);
215 (*new_hmac)->allocated_hash = TRUE;
219 (*new_hmac)->hash = hash;
222 if (silc_hmac_list) {
223 SilcHmacObject *entry;
224 silc_dlist_start(silc_hmac_list);
225 while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
226 if (!strcmp(entry->name, name)) {
227 (*new_hmac)->hmac = entry;
234 /* On EPOC which don't have globals we check our constant hash list. */
236 for (i = 0; silc_default_hmacs[i].name; i++) {
237 if (!strcmp(silc_default_hmacs[i].name, name)) {
238 (*new_hmac)->hmac = (SilcHmacObject *)&(silc_default_hmacs[i]);
243 #endif /* SILC_SYMBIAN */
245 silc_free(*new_hmac);
250 /* Free's the SilcHmac object. */
252 void silc_hmac_free(SilcHmac hmac)
255 if (hmac->allocated_hash)
256 silc_hash_free(hmac->hash);
259 memset(hmac->key, 0, hmac->key_len);
260 silc_free(hmac->key);
267 /* Returns the length of the MAC that the HMAC will produce. */
269 SilcUInt32 silc_hmac_len(SilcHmac hmac)
271 return hmac->hmac->len;
274 /* Get hash context */
276 SilcHash silc_hmac_get_hash(SilcHmac hmac)
281 /* Return name of hmac */
283 const char *silc_hmac_get_name(SilcHmac hmac)
285 return hmac->hmac->name;
288 /* Returns TRUE if HMAC `name' is supported. */
290 SilcBool silc_hmac_is_supported(const char *name)
293 SilcHmacObject *entry;
298 if (silc_hmac_list) {
299 silc_dlist_start(silc_hmac_list);
300 while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
301 if (!strcmp(entry->name, name))
308 for (i = 0; silc_default_hmacs[i].name; i++)
309 if (!strcmp(silc_default_hmacs[i].name, name))
312 #endif /* SILC_SYMBIAN */
316 /* Returns comma separated list of supported HMACs. */
318 char *silc_hmac_get_supported()
320 SilcHmacObject *entry;
325 if (silc_hmac_list) {
326 silc_dlist_start(silc_hmac_list);
327 while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
328 len += strlen(entry->name);
329 list = silc_realloc(list, len + 1);
331 memcpy(list + (len - strlen(entry->name)),
332 entry->name, strlen(entry->name));
333 memcpy(list + len, ",", 1);
340 for (i = 0; silc_default_hmacs[i].name; i++) {
341 entry = (SilcHmacObject *)&(silc_default_hmacs[i]);
342 len += strlen(entry->name);
343 list = silc_realloc(list, len + 1);
345 memcpy(list + (len - strlen(entry->name)),
346 entry->name, strlen(entry->name));
347 memcpy(list + len, ",", 1);
351 #endif /* SILC_SYMBIAN */
359 /* Sets the HMAC key used in the HMAC creation */
361 void silc_hmac_set_key(SilcHmac hmac, const unsigned char *key,
365 memset(hmac->key, 0, hmac->key_len);
366 silc_free(hmac->key);
368 hmac->key = silc_malloc(key_len);
371 hmac->key_len = key_len;
372 memcpy(hmac->key, key, key_len);
375 /* Return HMAC key */
377 const unsigned char *silc_hmac_get_key(SilcHmac hmac, SilcUInt32 *key_len)
380 *key_len = hmac->key_len;
381 return (const unsigned char *)hmac->key;
384 /* Create the HMAC. This is thee make_hmac function pointer. This
385 uses the internal key set with silc_hmac_set_key. */
387 void silc_hmac_make(SilcHmac hmac, unsigned char *data,
388 SilcUInt32 data_len, unsigned char *return_hash,
389 SilcUInt32 *return_len)
391 SILC_LOG_DEBUG(("Making HMAC for message"));
393 silc_hmac_init(hmac);
394 silc_hmac_update(hmac, data, data_len);
395 silc_hmac_final(hmac, return_hash, return_len);
398 /* Creates HMAC just as above except that this doesn't use the internal
399 key. The key is sent as argument to the function. */
401 void silc_hmac_make_with_key(SilcHmac hmac, unsigned char *data,
403 unsigned char *key, SilcUInt32 key_len,
404 unsigned char *return_hash,
405 SilcUInt32 *return_len)
407 SILC_LOG_DEBUG(("Making HMAC for message"));
409 silc_hmac_init_with_key(hmac, key, key_len);
410 silc_hmac_update(hmac, data, data_len);
411 silc_hmac_final(hmac, return_hash, return_len);
414 /* Creates the HMAC just as above except that the hash value is truncated
415 to the truncated_len sent as argument. NOTE: One should not truncate to
416 less than half of the length of original hash value. However, this
417 routine allows these dangerous truncations. */
419 void silc_hmac_make_truncated(SilcHmac hmac, unsigned char *data,
421 SilcUInt32 truncated_len,
422 unsigned char *return_hash)
424 unsigned char hvalue[SILC_HASH_MAXLEN];
426 SILC_LOG_DEBUG(("Making HMAC for message"));
428 silc_hmac_init(hmac);
429 silc_hmac_update(hmac, data, data_len);
430 silc_hmac_final(hmac, return_hash, NULL);
431 memcpy(return_hash, hvalue, truncated_len);
432 memset(hvalue, 0, sizeof(hvalue));
435 /* Init HMAC for silc_hmac_update and silc_hmac_final. */
437 void silc_hmac_init(SilcHmac hmac)
439 silc_hmac_init_with_key(hmac, hmac->key, hmac->key_len);
442 /* Same as above but with specific key */
444 void silc_hmac_init_with_key(SilcHmac hmac, const unsigned char *key,
447 SilcHash hash = hmac->hash;
448 silc_hmac_init_internal(hmac, (unsigned char *)key, key_len);
449 silc_hash_init(hash);
450 silc_hash_update(hash, hmac->inner_pad, silc_hash_block_len(hash));
453 /* Add data to be used in the MAC computation. */
455 void silc_hmac_update(SilcHmac hmac, const unsigned char *data,
458 SilcHash hash = hmac->hash;
459 silc_hash_update(hash, data, data_len);
462 /* Compute the final MAC. */
464 void silc_hmac_final(SilcHmac hmac, unsigned char *return_hash,
465 SilcUInt32 *return_len)
467 SilcHash hash = hmac->hash;
468 unsigned char mac[SILC_HASH_MAXLEN];
470 silc_hash_final(hash, mac);
471 silc_hash_init(hash);
472 silc_hash_update(hash, hmac->outer_pad, silc_hash_block_len(hash));
473 silc_hash_update(hash, mac, silc_hash_len(hash));
474 silc_hash_final(hash, mac);
475 memcpy(return_hash, mac, hmac->hmac->len);
476 memset(mac, 0, sizeof(mac));
479 *return_len = hmac->hmac->len;