+#include "silc.h"
+
+/* HMAC context */
+struct SilcHmacStruct {
+ SilcHmacObject *hmac;
+ SilcHash hash;
+ unsigned char inner_pad[64];
+ unsigned char outer_pad[64];
+ unsigned char *key;
+ unsigned int key_len : 31;
+ unsigned int allocated_hash : 1; /* TRUE if the hash was allocated */
+};
+
+#ifndef SILC_SYMBIAN
+/* List of dynamically registered HMACs. */
+SilcDList silc_hmac_list = NULL;
+#endif /* SILC_SYMBIAN */
+
+/* Default hmacs for silc_hmac_register_default(). */
+const SilcHmacObject silc_default_hmacs[] =
+{
+ { "hmac-sha256-96", 12 },
+ { "hmac-sha512-96", 12 },
+ { "hmac-sha1-96", 12 },
+ { "hmac-md5-96", 12 },
+ { "hmac-sha256", 32 },
+ { "hmac-sha512", 64 },
+ { "hmac-sha1", 20 },
+ { "hmac-md5", 16 },
+
+ { NULL, 0 }
+};
+
+static void silc_hmac_init_internal(SilcHmac hmac, unsigned char *key,
+ SilcUInt32 key_len)
+{
+ 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;
+ }
+}