5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "silcincludes.h"
24 /* List of dynamically registered HMACs. */
25 SilcDList silc_hmac_list = NULL;
27 /* Default hmacs for silc_hmac_register_default(). */
28 SilcHmacObject silc_default_hmacs[] =
30 { "hmac-sha1-96", 12 },
31 { "hmac-md5-96", 12 },
38 /* Registers a new HMAC into the SILC. This function is used at the
39 initialization of the SILC. */
41 bool silc_hmac_register(SilcHmacObject *hmac)
45 SILC_LOG_DEBUG(("Registering new HMAC `%s'", hmac->name));
47 new = silc_calloc(1, sizeof(*new));
48 new->name = strdup(hmac->name);
52 if (silc_hmac_list == NULL)
53 silc_hmac_list = silc_dlist_init();
54 silc_dlist_add(silc_hmac_list, new);
59 /* Unregister a HMAC from the SILC. */
61 bool silc_hmac_unregister(SilcHmacObject *hmac)
63 SilcHmacObject *entry;
65 SILC_LOG_DEBUG(("Unregistering HMAC"));
70 silc_dlist_start(silc_hmac_list);
71 while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
72 if (hmac == SILC_ALL_HMACS || entry == hmac) {
73 silc_dlist_del(silc_hmac_list, entry);
75 if (silc_dlist_count(silc_hmac_list) == 0) {
76 silc_dlist_uninit(silc_hmac_list);
77 silc_hmac_list = NULL;
87 /* Function that registers all the default hmacs (all builtin ones).
88 The application may use this to register the default hmacs if
89 specific hmacs in any specific order is not wanted. */
91 bool silc_hmac_register_default(void)
95 for (i = 0; silc_default_hmacs[i].name; i++)
96 silc_hmac_register(&(silc_default_hmacs[i]));
101 /* Allocates a new SilcHmac object of name of `name'. The `hash' may
102 be provided as argument. If provided it is used as the hash function
103 of the HMAC. If it is NULL then the hash function is allocated and
104 the name of the hash algorithm is derived from the `name'. */
106 bool silc_hmac_alloc(char *name, SilcHash hash, SilcHmac *new_hmac)
108 SilcHmacObject *entry;
110 SILC_LOG_DEBUG(("Allocating new HMAC"));
112 /* Allocate the new object */
113 *new_hmac = silc_calloc(1, sizeof(**new_hmac));
116 char *tmp = strdup(name), *hname;
119 if (strchr(hname, '-'))
120 hname = strchr(hname, '-') + 1;
121 if (strchr(hname, '-'))
122 *strchr(hname, '-') = '\0';
124 if (!silc_hash_alloc(hname, &hash)) {
129 (*new_hmac)->allocated_hash = TRUE;
133 (*new_hmac)->hash = hash;
135 if (silc_hmac_list) {
136 silc_dlist_start(silc_hmac_list);
137 while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
138 if (!strcmp(entry->name, name)) {
139 (*new_hmac)->hmac = entry;
148 /* Free's the SilcHmac object. */
150 void silc_hmac_free(SilcHmac hmac)
153 if (hmac->allocated_hash)
154 silc_hash_free(hmac->hash);
159 /* Returns the length of the MAC that the HMAC will produce. */
161 uint32 silc_hmac_len(SilcHmac hmac)
163 return hmac->hmac->len;
166 /* Returns TRUE if HMAC `name' is supported. */
168 bool silc_hmac_is_supported(const char *name)
170 SilcHmacObject *entry;
175 if (silc_hmac_list) {
176 silc_dlist_start(silc_hmac_list);
177 while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
178 if (!strcmp(entry->name, name))
186 /* Returns comma separated list of supported HMACs. */
188 char *silc_hmac_get_supported()
190 SilcHmacObject *entry;
195 if (silc_hmac_list) {
196 silc_dlist_start(silc_hmac_list);
197 while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
198 len += strlen(entry->name);
199 list = silc_realloc(list, len + 1);
201 memcpy(list + (len - strlen(entry->name)),
202 entry->name, strlen(entry->name));
203 memcpy(list + len, ",", 1);
213 /* Sets the HMAC key used in the HMAC creation */
215 void silc_hmac_set_key(SilcHmac hmac, const unsigned char *key,
219 memset(hmac->key, 0, hmac->key_len);
220 silc_free(hmac->key);
222 hmac->key = silc_calloc(key_len, sizeof(unsigned char));
223 hmac->key_len = key_len;
224 memcpy(hmac->key, key, key_len);
227 /* Creates the HMAC. The created keyed hash value is returned to
228 return_hash argument. */
230 void silc_hmac_make_internal(SilcHmac hmac, unsigned char *data,
231 uint32 data_len, unsigned char *key,
232 uint32 key_len, unsigned char *return_hash)
234 SilcHash hash = hmac->hash;
235 unsigned char inner_pad[hash->hash->block_len + 1];
236 unsigned char outer_pad[hash->hash->block_len + 1];
237 unsigned char hvalue[hash->hash->hash_len];
238 unsigned char mac[128];
242 SILC_LOG_DEBUG(("Making HMAC for message"));
244 hash_context = silc_calloc(1, hash->hash->context_len());
246 memset(inner_pad, 0, sizeof(inner_pad));
247 memset(outer_pad, 0, sizeof(outer_pad));
249 /* If the key length is more than block size of the hash function, the
251 if (key_len > hash->hash->block_len) {
252 silc_hash_make(hash, key, key_len, hvalue);
254 key_len = hash->hash->hash_len;
257 /* Copy the key into the pads */
258 memcpy(inner_pad, key, key_len);
259 memcpy(outer_pad, key, key_len);
261 /* XOR the key with pads */
262 for (i = 0; i < hash->hash->block_len; i++) {
263 inner_pad[i] ^= 0x36;
264 outer_pad[i] ^= 0x5c;
267 /* Do the HMAC transform (too bad I can't do make_hash directly, sigh) */
268 hash->hash->init(hash_context);
269 hash->hash->update(hash_context, inner_pad, hash->hash->block_len);
270 hash->hash->update(hash_context, data, data_len);
271 hash->hash->final(hash_context, mac);
272 hash->hash->init(hash_context);
273 hash->hash->update(hash_context, outer_pad, hash->hash->block_len);
274 hash->hash->update(hash_context, mac, hash->hash->hash_len);
275 hash->hash->final(hash_context, mac);
276 memcpy(return_hash, mac, hmac->hmac->len);
277 memset(mac, 0, sizeof(mac));
278 silc_free(hash_context);
281 /* Create the HMAC. This is thee make_hmac function pointer. This
282 uses the internal key set with silc_hmac_set_key. */
284 void silc_hmac_make(SilcHmac hmac, unsigned char *data,
285 uint32 data_len, unsigned char *return_hash,
288 silc_hmac_make_internal(hmac, data, data_len, hmac->key,
289 hmac->key_len, return_hash);
291 *return_len = hmac->hmac->len;
294 /* Creates HMAC just as above except that this doesn't use the internal
295 key. The key is sent as argument to the function. */
297 void silc_hmac_make_with_key(SilcHmac hmac, unsigned char *data,
299 unsigned char *key, uint32 key_len,
300 unsigned char *return_hash,
303 silc_hmac_make_internal(hmac, data, data_len, key, key_len, return_hash);
305 *return_len = hmac->hmac->len;
308 /* Creates the HMAC just as above except that the hash value is truncated
309 to the truncated_len sent as argument. NOTE: One should not truncate to
310 less than half of the length of original hash value. However, this
311 routine allows these dangerous truncations. */
313 void silc_hmac_make_truncated(SilcHmac hmac, unsigned char *data,
315 uint32 truncated_len,
316 unsigned char *return_hash)
318 unsigned char hvalue[hmac->hash->hash->hash_len];
320 silc_hmac_make_internal(hmac, data, data_len,
321 hmac->key, hmac->key_len, hvalue);
322 memcpy(return_hash, hvalue, truncated_len);
323 memset(hvalue, 0, sizeof(hvalue));