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);
212 /* Sets the HMAC key used in the HMAC creation */
214 void silc_hmac_set_key(SilcHmac hmac, const unsigned char *key,
218 memset(hmac->key, 0, hmac->key_len);
219 silc_free(hmac->key);
221 hmac->key = silc_calloc(key_len, sizeof(unsigned char));
222 hmac->key_len = key_len;
223 memcpy(hmac->key, key, key_len);
226 /* Creates the HMAC. The created keyed hash value is returned to
227 return_hash argument. */
229 void silc_hmac_make_internal(SilcHmac hmac, unsigned char *data,
230 uint32 data_len, unsigned char *key,
231 uint32 key_len, unsigned char *return_hash)
233 SilcHash hash = hmac->hash;
234 unsigned char inner_pad[hash->hash->block_len + 1];
235 unsigned char outer_pad[hash->hash->block_len + 1];
236 unsigned char hvalue[hash->hash->hash_len];
237 unsigned char mac[128];
241 SILC_LOG_DEBUG(("Making HMAC for message"));
243 hash_context = silc_calloc(1, hash->hash->context_len());
245 memset(inner_pad, 0, sizeof(inner_pad));
246 memset(outer_pad, 0, sizeof(outer_pad));
248 /* If the key length is more than block size of the hash function, the
250 if (key_len > hash->hash->block_len) {
251 silc_hash_make(hash, key, key_len, hvalue);
253 key_len = hash->hash->hash_len;
256 /* Copy the key into the pads */
257 memcpy(inner_pad, key, key_len);
258 memcpy(outer_pad, key, key_len);
260 /* XOR the key with pads */
261 for (i = 0; i < hash->hash->block_len; i++) {
262 inner_pad[i] ^= 0x36;
263 outer_pad[i] ^= 0x5c;
266 /* Do the HMAC transform (too bad I can't do make_hash directly, sigh) */
267 hash->hash->init(hash_context);
268 hash->hash->update(hash_context, inner_pad, hash->hash->block_len);
269 hash->hash->update(hash_context, data, data_len);
270 hash->hash->final(hash_context, mac);
271 hash->hash->init(hash_context);
272 hash->hash->update(hash_context, outer_pad, hash->hash->block_len);
273 hash->hash->update(hash_context, mac, hash->hash->hash_len);
274 hash->hash->final(hash_context, mac);
275 memcpy(return_hash, mac, hmac->hmac->len);
276 memset(mac, 0, sizeof(mac));
277 silc_free(hash_context);
280 /* Create the HMAC. This is thee make_hmac function pointer. This
281 uses the internal key set with silc_hmac_set_key. */
283 void silc_hmac_make(SilcHmac hmac, unsigned char *data,
284 uint32 data_len, unsigned char *return_hash,
287 silc_hmac_make_internal(hmac, data, data_len, hmac->key,
288 hmac->key_len, return_hash);
290 *return_len = hmac->hmac->len;
293 /* Creates HMAC just as above except that this doesn't use the internal
294 key. The key is sent as argument to the function. */
296 void silc_hmac_make_with_key(SilcHmac hmac, unsigned char *data,
298 unsigned char *key, uint32 key_len,
299 unsigned char *return_hash,
302 silc_hmac_make_internal(hmac, data, data_len, key, key_len, return_hash);
304 *return_len = hmac->hmac->len;
307 /* Creates the HMAC just as above except that the hash value is truncated
308 to the truncated_len sent as argument. NOTE: One should not truncate to
309 less than half of the length of original hash value. However, this
310 routine allows these dangerous truncations. */
312 void silc_hmac_make_truncated(SilcHmac hmac, unsigned char *data,
314 uint32 truncated_len,
315 unsigned char *return_hash)
317 unsigned char hvalue[hmac->hash->hash->hash_len];
319 silc_hmac_make_internal(hmac, data, data_len,
320 hmac->key, hmac->key_len, hvalue);
321 memcpy(return_hash, hvalue, truncated_len);
322 memset(hvalue, 0, sizeof(hvalue));