+ SilcHash hash = hmac->hash;
+ SilcUInt32 block_len;
+ unsigned char hvalue[SILC_HASH_MAXLEN];
+ int i;
+
+ memset(hmac->inner_pad, 0, sizeof(hmac->inner_pad));
+ memset(hmac->outer_pad, 0, sizeof(hmac->outer_pad));
+
+ block_len = silc_hash_block_len(hash);
+
+ /* If the key length is more than block size of the hash function, the
+ key is hashed. */
+ if (key_len > block_len) {
+ silc_hash_make(hash, key, key_len, hvalue);
+ key = hvalue;
+ key_len = silc_hash_len(hash);
+ }
+
+ /* Copy the key into the pads */
+ memcpy(hmac->inner_pad, key, key_len);
+ memcpy(hmac->outer_pad, key, key_len);
+
+ /* XOR the key with pads */
+ for (i = 0; i < block_len; i++) {
+ hmac->inner_pad[i] ^= 0x36;
+ hmac->outer_pad[i] ^= 0x5c;
+ }
+}
+
+/* Registers a new HMAC */
+
+SilcBool silc_hmac_register(const SilcHmacObject *hmac)
+{
+#ifndef SILC_SYMBIAN
+ SilcHmacObject *new;
+
+ SILC_LOG_DEBUG(("Registering new HMAC `%s'", hmac->name));
+
+ /* Check for existing */
+ if (silc_hmac_list) {
+ SilcHmacObject *entry;
+ silc_dlist_start(silc_hmac_list);
+ while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
+ if (!strcmp(entry->name, hmac->name))
+ return FALSE;
+ }
+ }
+
+ new = silc_calloc(1, sizeof(*new));
+ if (!new)
+ return FALSE;
+ new->name = strdup(hmac->name);
+ new->len = hmac->len;
+
+ /* Add to list */
+ if (silc_hmac_list == NULL)
+ silc_hmac_list = silc_dlist_init();
+ silc_dlist_add(silc_hmac_list, new);
+
+#endif /* SILC_SYMBIAN */
+ return TRUE;
+}
+
+/* Unregister a HMAC */
+
+SilcBool silc_hmac_unregister(SilcHmacObject *hmac)
+{
+#ifndef SILC_SYMBIAN
+ SilcHmacObject *entry;
+
+ SILC_LOG_DEBUG(("Unregistering HMAC"));
+
+ if (!silc_hmac_list)
+ return FALSE;
+
+ silc_dlist_start(silc_hmac_list);
+ while ((entry = silc_dlist_get(silc_hmac_list)) != SILC_LIST_END) {
+ if (hmac == SILC_ALL_HMACS || entry == hmac) {
+ silc_dlist_del(silc_hmac_list, entry);
+ silc_free(entry->name);
+ silc_free(entry);