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)) {
126 silc_free(*new_hmac);
131 (*new_hmac)->allocated_hash = TRUE;
135 (*new_hmac)->hash = hash;
137 if (silc_hmac_list) {
138 silc_dlist_start(silc_hmac_list);
139 while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
140 if (!strcmp(entry->name, name)) {
141 (*new_hmac)->hmac = entry;
147 silc_free(*new_hmac);
152 /* Free's the SilcHmac object. */
154 void silc_hmac_free(SilcHmac hmac)
157 if (hmac->allocated_hash)
158 silc_hash_free(hmac->hash);
163 /* Returns the length of the MAC that the HMAC will produce. */
165 uint32 silc_hmac_len(SilcHmac hmac)
167 return hmac->hmac->len;
170 /* Returns TRUE if HMAC `name' is supported. */
172 bool silc_hmac_is_supported(const char *name)
174 SilcHmacObject *entry;
179 if (silc_hmac_list) {
180 silc_dlist_start(silc_hmac_list);
181 while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
182 if (!strcmp(entry->name, name))
190 /* Returns comma separated list of supported HMACs. */
192 char *silc_hmac_get_supported()
194 SilcHmacObject *entry;
199 if (silc_hmac_list) {
200 silc_dlist_start(silc_hmac_list);
201 while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
202 len += strlen(entry->name);
203 list = silc_realloc(list, len + 1);
205 memcpy(list + (len - strlen(entry->name)),
206 entry->name, strlen(entry->name));
207 memcpy(list + len, ",", 1);
216 /* Sets the HMAC key used in the HMAC creation */
218 void silc_hmac_set_key(SilcHmac hmac, const unsigned char *key,
222 memset(hmac->key, 0, hmac->key_len);
223 silc_free(hmac->key);
225 hmac->key = silc_calloc(key_len, sizeof(unsigned char));
226 hmac->key_len = key_len;
227 memcpy(hmac->key, key, key_len);
230 /* Creates the HMAC. The created keyed hash value is returned to
231 return_hash argument. */
233 void silc_hmac_make_internal(SilcHmac hmac, unsigned char *data,
234 uint32 data_len, unsigned char *key,
235 uint32 key_len, unsigned char *return_hash)
237 SilcHash hash = hmac->hash;
238 unsigned char inner_pad[64];
239 unsigned char outer_pad[64];
240 unsigned char hvalue[20], mac[20];
244 SILC_LOG_DEBUG(("Making HMAC for message"));
246 hash_context = silc_calloc(1, hash->hash->context_len());
248 memset(inner_pad, 0, sizeof(inner_pad));
249 memset(outer_pad, 0, sizeof(outer_pad));
251 /* If the key length is more than block size of the hash function, the
253 if (key_len > hash->hash->block_len) {
254 silc_hash_make(hash, key, key_len, hvalue);
256 key_len = hash->hash->hash_len;
259 /* Copy the key into the pads */
260 memcpy(inner_pad, key, key_len);
261 memcpy(outer_pad, key, key_len);
263 /* XOR the key with pads */
264 for (i = 0; i < hash->hash->block_len; i++) {
265 inner_pad[i] ^= 0x36;
266 outer_pad[i] ^= 0x5c;
269 /* Do the HMAC transform (too bad I can't do make_hash directly, sigh) */
270 hash->hash->init(hash_context);
271 hash->hash->update(hash_context, inner_pad, hash->hash->block_len);
272 hash->hash->update(hash_context, data, data_len);
273 hash->hash->final(hash_context, mac);
274 hash->hash->init(hash_context);
275 hash->hash->update(hash_context, outer_pad, hash->hash->block_len);
276 hash->hash->update(hash_context, mac, hash->hash->hash_len);
277 hash->hash->final(hash_context, mac);
278 memcpy(return_hash, mac, hmac->hmac->len);
279 memset(mac, 0, sizeof(mac));
280 silc_free(hash_context);
283 /* Create the HMAC. This is thee make_hmac function pointer. This
284 uses the internal key set with silc_hmac_set_key. */
286 void silc_hmac_make(SilcHmac hmac, unsigned char *data,
287 uint32 data_len, unsigned char *return_hash,
290 silc_hmac_make_internal(hmac, data, data_len, hmac->key,
291 hmac->key_len, return_hash);
293 *return_len = hmac->hmac->len;
296 /* Creates HMAC just as above except that this doesn't use the internal
297 key. The key is sent as argument to the function. */
299 void silc_hmac_make_with_key(SilcHmac hmac, unsigned char *data,
301 unsigned char *key, uint32 key_len,
302 unsigned char *return_hash,
305 silc_hmac_make_internal(hmac, data, data_len, key, key_len, return_hash);
307 *return_len = hmac->hmac->len;
310 /* Creates the HMAC just as above except that the hash value is truncated
311 to the truncated_len sent as argument. NOTE: One should not truncate to
312 less than half of the length of original hash value. However, this
313 routine allows these dangerous truncations. */
315 void silc_hmac_make_truncated(SilcHmac hmac, unsigned char *data,
317 uint32 truncated_len,
318 unsigned char *return_hash)
320 unsigned char hvalue[20];
322 silc_hmac_make_internal(hmac, data, data_len,
323 hmac->key, hmac->key_len, hvalue);
324 memcpy(return_hash, hvalue, truncated_len);
325 memset(hvalue, 0, sizeof(hvalue));