updates.
authorPekka Riikonen <priikone@silcnet.org>
Mon, 15 Oct 2001 21:22:01 +0000 (21:22 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Mon, 15 Oct 2001 21:22:01 +0000 (21:22 +0000)
18 files changed:
CHANGES
apps/irssi/src/silc/core/client_ops.c
apps/irssi/src/silc/core/silc-channels.c
apps/silcd/command.c
apps/silcd/command_reply.c
apps/silcd/idlist.c
apps/silcd/idlist.h
apps/silcd/packet_receive.c
apps/silcd/packet_send.c
apps/silcd/protocol.c
apps/silcd/server.c
lib/silcclient/client_channel.c
lib/silcclient/client_notify.c
lib/silcclient/protocol.c
lib/silccore/silcpacket.c
lib/silccore/silcpacket.h
lib/silccrypt/silchmac.c
lib/silccrypt/silchmac.h

diff --git a/CHANGES b/CHANGES
index 385fc821514d9197b1d88db68be4e4f84c117a51..25649f7f9b2675796da0b9b71e753bc28b00472c 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -23,6 +23,11 @@ Mon Oct 15 17:42:55 EDT 2001  Pekka Riikonen <priikone@silcnet.org>
          Affected files silcd/server_util.[ch], silcd/server.c. and
          silcd/backup_router.c.
 
+       * ROBODoc documented the lib/silccrypt/silchmac.h.  Added new
+         function silc_hmac_init, silc_hmac_update, silc_hmac_final,
+         silc_hmac_get_hash and silc_hmac_get_name.  Affected file
+         lib/silccrypt/silchmac.c.
+
 Sun Oct 14 18:28:22 EDT 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Assure that router cannot reroute the same channel message
index f3507b7e167151eed57d5cc08555b3eab31c7361..b140aa8ed106cdd84f4283c12cdf941ba569ec0a 100644 (file)
@@ -561,7 +561,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
                                channel_entry->channel_key ? 
                                channel_entry->channel_key->cipher->name : "",
                                channel_entry->hmac ? 
-                               channel_entry->hmac->hmac->name : "");
+                               silc_hmac_get_name(channel_entry->hmac) : "");
       g_free_not_null(chanrec->mode);
       chanrec->mode = g_strdup(mode == NULL ? "" : mode);
       signal_emit("channel mode changed", 1, chanrec);
index 1292aa82ae2174bd0fdf548062a1bd8061f5dafc..81696eeecbd0b160cd02b0358c29d669c0208e89 100644 (file)
@@ -332,7 +332,7 @@ static void event_cmode(SILC_SERVER_REC *server, va_list va)
 
   mode = silc_client_chmode(modei, 
                            channel->channel_key->cipher->name,
-                           channel->hmac->hmac->name);
+                           silc_hmac_get_name(channel->hmac));
   
   chanrec = silc_channel_find_entry(server, channel);
   if (chanrec != NULL) {
@@ -1125,8 +1125,8 @@ static void command_key(const char *data, SILC_SERVER_REC *server,
            strcat(buf, " ");
        strcat(buf, " ");
        
-       len = strlen(keys[k]->hmac->hmac->name);
-       strncat(buf, keys[k]->hmac->hmac->name, len > 16 ? 16 : len);
+       len = strlen(silc_hmac_get_name(keys[k]->hmac));
+       strncat(buf, silc_hmac_get_name(keys[k]->hmac), len > 16 ? 16 : len);
        if (len < 16)
          for (i = 0; i < 16 - len; i++)
            strcat(buf, " ");
index 0eae9abce4fd25791aa2d68e70a65db1a40523a3..d77a7cdd3f75a5147d352b3f066c5db755a63818 100644 (file)
@@ -3146,8 +3146,9 @@ static void silc_server_command_join_channel(SilcServer server,
                                         10, channel->topic,
                                         channel->topic ?
                                         strlen(channel->topic) : 0,
-                                        11, channel->hmac->hmac->name,
-                                        strlen(channel->hmac->hmac->name),
+                                        11, silc_hmac_get_name(channel->hmac),
+                                        strlen(silc_hmac_get_name(channel->
+                                                                  hmac)),
                                         12, tmp3, 4,
                                         13, user_list->data, user_list->len,
                                         14, mode_list->data, 
@@ -3780,7 +3781,7 @@ SILC_SERVER_CMD_FUNC(cmode)
                                   FALSE : !server->standalone);
 
       cipher = channel->channel_key->cipher->name;
-      hmac = channel->hmac->hmac->name;
+      hmac = (char *)silc_hmac_get_name(channel->hmac);
     }
   }
   
@@ -3911,10 +3912,11 @@ SILC_SERVER_CMD_FUNC(cmode)
 
       /* Set the HMAC key out of current channel key. The client must do
         this locally. */
-      silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8, 
+      silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, 
+                    channel->key_len / 8, 
                     hash);
       silc_hmac_set_key(channel->hmac, hash, 
-                       silc_hash_len(channel->hmac->hash));
+                       silc_hash_len(silc_hmac_get_hash(channel->hmac)));
       memset(hash, 0, sizeof(hash));
     }
   } else {
@@ -3935,10 +3937,11 @@ SILC_SERVER_CMD_FUNC(cmode)
 
       /* Set the HMAC key out of current channel key. The client must do
         this locally. */
-      silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8, 
+      silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, 
+                    channel->key_len / 8, 
                     hash);
       silc_hmac_set_key(channel->hmac, hash, 
-                       silc_hash_len(channel->hmac->hash));
+                       silc_hash_len(silc_hmac_get_hash(channel->hmac)));
       memset(hash, 0, sizeof(hash));
     }
   }
index 9b18d11afb11e7eccc6b295c8d8384b705a91319..88a91d64854449b079c7b3e7b15695739c95cd60 100644 (file)
@@ -833,7 +833,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
 
   if (entry->hmac_name && hmac) {
     silc_free(entry->hmac_name);
-    entry->hmac_name = strdup(hmac->hmac->name);
+    entry->hmac_name = strdup(silc_hmac_get_name(hmac));
   }
 
   /* Get the ban list */
index f762787fe80af56f9e921192b0bb14947bafccce..527b49ea6a8fa535dae296544ef26b69ee7a1d90 100644 (file)
@@ -36,11 +36,13 @@ void silc_idlist_add_data(void *entry, SilcIDListData idata)
   SilcIDListData data = (SilcIDListData)entry;
   data->send_key = idata->send_key;
   data->receive_key = idata->receive_key;
-  data->rekey = idata->rekey;
-  data->hash = idata->hash;
   data->hmac_send = idata->hmac_send;
   data->hmac_receive = idata->hmac_receive;
+  data->psn_send = idata->psn_send;
+  data->psn_receive = idata->psn_receive;
+  data->hash = idata->hash;
   data->public_key = idata->public_key;
+  data->rekey = idata->rekey;
   data->last_receive = idata->last_receive;
   data->last_sent = idata->last_sent;
   data->status = idata->status;
index bd526b9368ba5732f09953162312f6e7ad15724a..6e8e2c946cd05e026cd0881efff381c865f8797b 100644 (file)
@@ -80,19 +80,23 @@ typedef struct {
   SilcCipher send_key;
   SilcCipher receive_key;
 
-  /* Re-key context */
-  SilcServerRekey rekey;
-
-  /* Hash selected in the SKE protocol, NULL if not needed at all */
-  SilcHash hash;
-
   /* HMAC */
   SilcHmac hmac_send;
   SilcHmac hmac_receive;
 
+  /* Packet sequence numbers */
+  uint32 psn_send;
+  uint32 psn_receive;
+
+  /* Hash selected in the SKE protocol, NULL if not needed at all */
+  SilcHash hash;
+
   /* Public key */
   SilcPublicKey public_key;
 
+  /* Re-key context */
+  SilcServerRekey rekey;
+
   long last_receive;           /* Time last received data */
   long last_sent;              /* Time last sent data */
 
index cef910174d70058077bdb206a7eed7e4719626fd..983d44f3015253cb313353c4c1ce61d1cb70547f 100644 (file)
@@ -510,10 +510,11 @@ void silc_server_notify(SilcServer server,
 
       /* Set the HMAC key out of current channel key. The client must do
         this locally. */
-      silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8, 
+      silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, 
+                    channel->key_len / 8, 
                     hash);
       silc_hmac_set_key(channel->hmac, hash, 
-                       silc_hash_len(channel->hmac->hash));
+                       silc_hash_len(silc_hmac_get_hash(channel->hmac)));
       memset(hash, 0, sizeof(hash));
     }
 
index 160209085866f8f5e452582535fa7f140fc8dc34..a73493608c4acd0a77abecc4c4a7d09b3bf2a8b8 100644 (file)
@@ -903,10 +903,10 @@ void silc_server_send_private_message(SilcServer server,
                     + packet->dst_id_len + packet->padlen);
     silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
     silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
-    
+
     /* Re-encrypt packet */
     silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, buffer->len);
-    
+
     /* Send the packet */
     silc_server_packet_send_real(server, dst_sock, FALSE);
 
index 170120f696c98007627aa1a7394628185b8ecf59..c3cad75bc336c1769fdf3805ad4dc6f24e0f9613 100644 (file)
@@ -268,7 +268,8 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske,
   }
 
   /* Save HMAC key to be used in the communication. */
-  if (!silc_hmac_alloc(hmac->hmac->name, NULL, &idata->hmac_send)) {
+  if (!silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, 
+                      &idata->hmac_send)) {
     silc_cipher_free(idata->send_key);
     silc_cipher_free(idata->receive_key);
     silc_hash_free(idata->hash);
@@ -283,7 +284,7 @@ int silc_server_protocol_ke_set_keys(SilcSKE ske,
   SILC_LOG_INFO(("%s (%s) security properties: %s %s %s", 
                 sock->hostname, sock->ip,
                 idata->send_key->cipher->name,
-                idata->hmac_send->hmac->name,
+                (char *)silc_hmac_get_name(idata->hmac_send),
                 idata->hash->hash->name));
 
   return TRUE;
@@ -1228,7 +1229,8 @@ silc_server_protocol_rekey_validate(SilcServer server,
   }
 
   if (send) {
-    silc_hmac_alloc(idata->hmac_send->hmac->name, NULL, &idata->hmac_send);
+    silc_hmac_alloc((char *)silc_hmac_get_name(idata->hmac_send), NULL, 
+                   &idata->hmac_send);
     silc_hmac_set_key(idata->hmac_send, keymat->hmac_key, 
                      keymat->hmac_key_len);
   } else {
index 0822bec5ebff480bb5a517c070ff59ab3b5f1236..5c95ce98b03b0275d11b5552f7bd23e1705de022 100644 (file)
@@ -2916,8 +2916,9 @@ bool silc_server_create_channel_key(SilcServer server,
   /* Generate HMAC key from the channel key data and set it */
   if (!channel->hmac)
     silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac);
-  silc_hash_make(channel->hmac->hash, channel->key, len, hash);
-  silc_hmac_set_key(channel->hmac, hash, silc_hash_len(channel->hmac->hash));
+  silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, len, hash);
+  silc_hmac_set_key(channel->hmac, hash, 
+                   silc_hash_len(silc_hmac_get_hash(channel->hmac)));
   memset(hash, 0, sizeof(hash));
 
   if (server->server_type == SILC_ROUTER) {
@@ -3023,8 +3024,9 @@ SilcChannelEntry silc_server_save_channel_key(SilcServer server,
   /* Generate HMAC key from the channel key data and set it */
   if (!channel->hmac)
     silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac);
-  silc_hash_make(channel->hmac->hash, tmp, tmp_len, hash);
-  silc_hmac_set_key(channel->hmac, hash, silc_hash_len(channel->hmac->hash));
+  silc_hash_make(silc_hmac_get_hash(channel->hmac), tmp, tmp_len, hash);
+  silc_hmac_set_key(channel->hmac, hash, 
+                   silc_hash_len(silc_hmac_get_hash(channel->hmac)));
 
   memset(hash, 0, sizeof(hash));
   memset(tmp, 0, tmp_len);
index 88ccd4534aea5e2a6d50512ba67669c9672eb4b9..d08b3da00e8ed81986dd0003228302ca98ee66b7 100644 (file)
@@ -331,7 +331,8 @@ void silc_client_save_channel_key(SilcClientConnection conn,
     channel = (SilcChannelEntry)id_cache->context;
   }
 
-  hmac = channel->hmac ? channel->hmac->hmac->name : SILC_DEFAULT_HMAC;
+  hmac = (channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) : 
+         SILC_DEFAULT_HMAC);
 
   /* Save the old key for a short period of time so that we can decrypt
      channel message even after the rekey if some client would be sending
@@ -371,8 +372,9 @@ void silc_client_save_channel_key(SilcClientConnection conn,
 
   /* Generate HMAC key from the channel key data and set it */
   silc_hmac_alloc(hmac, NULL, &channel->hmac);
-  silc_hash_make(channel->hmac->hash, key, tmp_len, hash);
-  silc_hmac_set_key(channel->hmac, hash, silc_hash_len(channel->hmac->hash));
+  silc_hash_make(silc_hmac_get_hash(channel->hmac), key, tmp_len, hash);
+  silc_hmac_set_key(channel->hmac, hash, 
+                   silc_hash_len(silc_hmac_get_hash(channel->hmac)));
   memset(hash, 0, sizeof(hash));
 
  out:
@@ -487,8 +489,10 @@ int silc_client_add_channel_private_key(SilcClient client,
 
   /* Generate HMAC key from the channel key data and set it */
   silc_hmac_alloc(hmac, NULL, &entry->hmac);
-  silc_hash_make(entry->hmac->hash, entry->key, entry->key_len, hash);
-  silc_hmac_set_key(entry->hmac, hash, silc_hash_len(entry->hmac->hash));
+  silc_hash_make(silc_hmac_get_hash(entry->hmac), entry->key, 
+                entry->key_len, hash);
+  silc_hmac_set_key(entry->hmac, hash, 
+                   silc_hash_len(silc_hmac_get_hash(entry->hmac)));
   memset(hash, 0, sizeof(hash));
 
   /* Add to the private keys list */
index 82a0654fa9158a125f53a06b4ad0de17a673a8a1..a5af48869e665fe52815b8c81e9d2ff7ec46f2f3 100644 (file)
@@ -478,10 +478,11 @@ void silc_client_notify_by_server(SilcClient client,
       if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
        goto out;
 
-      silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8,
+      silc_hash_make(silc_hmac_get_hash(channel->hmac), 
+                    channel->key, channel->key_len / 8,
                     hash);
       silc_hmac_set_key(channel->hmac, hash, 
-                       silc_hash_len(channel->hmac->hash));
+                       silc_hash_len(silc_hmac_get_hash(channel->hmac)));
       memset(hash, 0, sizeof(hash));
     }
 
index 8460ad8fccd0df61fb4f5c315c8086d459cc7eda..51ee452cc555f6b331d7478ee3aef8e8bd00793a 100644 (file)
@@ -145,7 +145,7 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske,
   conn->rekey->ske_group = silc_ske_group_get_number(group);
 
   /* Save HMAC key to be used in the communication. */
-  silc_hmac_alloc(hmac->hmac->name, NULL, &conn->hmac_send);
+  silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, &conn->hmac_send);
   silc_hmac_set_key(conn->hmac_send, keymat->hmac_key, keymat->hmac_key_len);
   conn->hmac_receive = conn->hmac_send;
 
@@ -768,7 +768,8 @@ silc_client_protocol_rekey_validate(SilcClient client,
   }
 
   if (send) {
-    silc_hmac_alloc(conn->hmac_receive->hmac->name, NULL, &conn->hmac_send);
+    silc_hmac_alloc((char *)silc_hmac_get_name(conn->hmac_receive), NULL, 
+                   &conn->hmac_send);
     silc_hmac_set_key(conn->hmac_send, keymat->hmac_key, 
                      keymat->hmac_key_len);
   } else {
index ec26ab1dd8cd60f64a0c7dfc529a2b6e61e9bb25..28349d51783dacb2e9c19e16d618ab327a1bac10 100644 (file)
@@ -1,16 +1,15 @@
 /*
 
-  silcpacket.c
+  silcpacket.c 
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
   Copyright (C) 1997 - 2001 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-  
+  the Free Software Foundation; version 2 of the License.
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -38,7 +37,7 @@
    later time. If `force_send' is TRUE this attempts to write the data
    directly to the network, if FALSE, this returns -2. */
 
-int silc_packet_send(SilcSocketConnection sock, int force_send)
+int silc_packet_send(SilcSocketConnection sock, bool force_send)
 {
   SILC_LOG_DEBUG(("Sending packet to %s:%d [%s]", sock->hostname,
                  sock->port,  
@@ -87,7 +86,9 @@ void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac,
      data area thus this uses the length found in buffer, not the length
      sent as argument. */
   if (hmac) {
-    silc_hmac_make(hmac, buffer->data, buffer->len, mac, &mac_len);
+    silc_hmac_init(hmac);
+    silc_hmac_update(hmac, buffer->data, buffer->len);
+    silc_hmac_final(hmac, mac, &mac_len);
     silc_buffer_put_tail(buffer, mac, mac_len);
     memset(mac, 0, sizeof(mac));
   }
@@ -225,7 +226,10 @@ void silc_packet_send_prepare(SilcSocketConnection sock,
     /* Allocate new buffer. This is done only once per connection. */
     SILC_LOG_DEBUG(("Allocating outgoing data buffer"));
     
-    sock->outbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
+    if (totlen > SILC_PACKET_DEFAULT_SIZE)
+      sock->outbuf = silc_buffer_alloc(totlen);
+    else
+      sock->outbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
     silc_buffer_pull_tail(sock->outbuf, totlen);
     silc_buffer_pull(sock->outbuf, header_len + padlen);
   } else {
@@ -289,7 +293,7 @@ void silc_packet_receive_process(SilcSocketConnection sock,
     return;
 
   if (hmac)
-    mac_len = hmac->hmac->len;
+    mac_len = silc_hmac_len(hmac);
 
   /* Parse the packets from the data */
   count = 0;
@@ -378,7 +382,9 @@ static int silc_packet_check_mac(SilcHmac hmac, SilcBuffer buffer)
 
     /* Compute HMAC of packet */
     memset(mac, 0, sizeof(mac));
-    silc_hmac_make(hmac, buffer->data, buffer->len, mac, &mac_len);
+    silc_hmac_init(hmac);
+    silc_hmac_update(hmac, buffer->data, buffer->len);
+    silc_hmac_final(hmac, mac, &mac_len);
 
     /* Compare the HMAC's (buffer->tail has the packet's HMAC) */
     if (memcmp(mac, buffer->tail, mac_len)) {
@@ -405,8 +411,8 @@ static int silc_packet_decrypt_rest(SilcCipher cipher, SilcHmac hmac,
 
     /* Pull MAC from packet before decryption */
     if (hmac) {
-      if ((buffer->len - hmac->hmac->len) > SILC_PACKET_MIN_LEN) {
-       silc_buffer_push_tail(buffer, hmac->hmac->len);
+      if ((buffer->len - silc_hmac_len(hmac)) > SILC_PACKET_MIN_LEN) {
+       silc_buffer_push_tail(buffer, silc_hmac_len(hmac));
       } else {
        SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
        return FALSE;
@@ -445,8 +451,8 @@ static int silc_packet_decrypt_rest_special(SilcCipher cipher,
 
     /* Pull MAC from packet before decryption */
     if (hmac) {
-      if ((buffer->len - hmac->hmac->len) > SILC_PACKET_MIN_LEN) {
-       silc_buffer_push_tail(buffer, hmac->hmac->len);
+      if ((buffer->len - silc_hmac_len(hmac)) > SILC_PACKET_MIN_LEN) {
+       silc_buffer_push_tail(buffer, silc_hmac_len(hmac));
       } else {
        SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
        return FALSE;
index a7d5c3ecaab39eee5280f71d3c984281c2c6668d..c8490b0b8bfb6e5ab20c719333302041c5703071 100644 (file)
@@ -1,16 +1,15 @@
 /*
 
-  silcpacket.h
+  silcpacket.h 
+
   Author: Pekka Riikonen <priikone@silcnet.org>
+
   Copyright (C) 1997 - 2001 Pekka Riikonen
+
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
+  the Free Software Foundation; version 2 of the License.
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -370,7 +369,7 @@ do {                                                                             \
  *
  * SYNOPSIS
  *
- *    int silc_packet_send(SilcSocketConnection sock, int force_send);
+ *    int silc_packet_send(SilcSocketConnection sock, bool force_send);
  *
  * DESCRIPTION
  *
@@ -383,7 +382,7 @@ do {                                                                             \
  *    directly to the network, if FALSE, this returns -2.
  *
  ***/
-int silc_packet_send(SilcSocketConnection sock, int force_send);
+int silc_packet_send(SilcSocketConnection sock, bool force_send);
 
 /****f* silccore/SilcPacketAPI/silc_packet_encrypt
  *
index 00fd15ecb4d252aafd8ba7fbe1d9923f74ea9117..77dce315b4693961ee662c34300b4eb7dac9f15b 100644 (file)
@@ -1,16 +1,15 @@
 /*
 
-  silchmac.c
+  silchmac.c 
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+  Copyright (C) 1999 - 2001 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-  
+  the Free Software Foundation; version 2 of the License.
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 #include "silcincludes.h"
 
+/* HMAC context */
+struct SilcHmacStruct {
+  SilcHmacObject *hmac;
+  SilcHash hash;
+  bool allocated_hash;         /* TRUE if the hash was allocated */
+
+  unsigned char *key;
+  uint32 key_len;
+
+  unsigned char inner_pad[64];
+  unsigned char outer_pad[64];
+  void *hash_context;
+};
+
 /* List of dynamically registered HMACs. */
 SilcDList silc_hmac_list = NULL;
 
@@ -35,6 +48,35 @@ SilcHmacObject silc_default_hmacs[] =
   { NULL, 0 }
 };
 
+static void silc_hmac_init_internal(SilcHmac hmac, unsigned char *key,
+                                   uint32 key_len)
+{
+  SilcHash hash = hmac->hash;
+  unsigned char hvalue[20];
+  int i;
+
+  memset(hmac->inner_pad, 0, sizeof(hmac->inner_pad));
+  memset(hmac->outer_pad, 0, sizeof(hmac->outer_pad));
+
+  /* If the key length is more than block size of the hash function, the
+     key is hashed. */
+  if (key_len > hash->hash->block_len) {
+    silc_hash_make(hash, key, key_len, hvalue);
+    key = hvalue;
+    key_len = hash->hash->hash_len;
+  }
+
+  /* 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 < hash->hash->block_len; i++) {
+    hmac->inner_pad[i] ^= 0x36;
+    hmac->outer_pad[i] ^= 0x5c;
+  }
+}
+
 /* Registers a new HMAC into the SILC. This function is used at the
    initialization of the SILC. */
 
@@ -156,6 +198,13 @@ void silc_hmac_free(SilcHmac hmac)
   if (hmac) {
     if (hmac->allocated_hash)
       silc_hash_free(hmac->hash);
+
+    if (hmac->key) {
+      memset(hmac->key, 0, hmac->key_len);
+      silc_free(hmac->key);
+    }
+
+    silc_free(hmac->hash_context);
     silc_free(hmac);
   }
 }
@@ -167,6 +216,20 @@ uint32 silc_hmac_len(SilcHmac hmac)
   return hmac->hmac->len;
 }
 
+/* Get hash context */
+
+SilcHash silc_hmac_get_hash(SilcHmac hmac)
+{
+  return hmac->hash;
+}
+
+/* Return name of hmac */
+
+const char *silc_hmac_get_name(SilcHmac hmac)
+{
+  return hmac->hmac->name;
+}
+
 /* Returns TRUE if HMAC `name' is supported. */
 
 bool silc_hmac_is_supported(const char *name)
@@ -227,59 +290,6 @@ void silc_hmac_set_key(SilcHmac hmac, const unsigned char *key,
   memcpy(hmac->key, key, key_len);
 }
 
-/* Creates the HMAC. The created keyed hash value is returned to 
-   return_hash argument. */
-
-void silc_hmac_make_internal(SilcHmac hmac, unsigned char *data,
-                            uint32 data_len, unsigned char *key,
-                            uint32 key_len, unsigned char *return_hash)
-{
-  SilcHash hash = hmac->hash;
-  unsigned char inner_pad[64];
-  unsigned char outer_pad[64];
-  unsigned char hvalue[20], mac[20];
-  void *hash_context;
-  int i;
-
-  SILC_LOG_DEBUG(("Making HMAC for message"));
-
-  hash_context = silc_calloc(1, hash->hash->context_len());
-
-  memset(inner_pad, 0, sizeof(inner_pad));
-  memset(outer_pad, 0, sizeof(outer_pad));
-
-  /* If the key length is more than block size of the hash function, the
-     key is hashed. */
-  if (key_len > hash->hash->block_len) {
-    silc_hash_make(hash, key, key_len, hvalue);
-    key = hvalue;
-    key_len = hash->hash->hash_len;
-  }
-
-  /* Copy the key into the pads */
-  memcpy(inner_pad, key, key_len);
-  memcpy(outer_pad, key, key_len);
-
-  /* XOR the key with pads */
-  for (i = 0; i < hash->hash->block_len; i++) {
-    inner_pad[i] ^= 0x36;
-    outer_pad[i] ^= 0x5c;
-  }
-
-  /* Do the HMAC transform (too bad I can't do make_hash directly, sigh) */
-  hash->hash->init(hash_context);
-  hash->hash->update(hash_context, inner_pad, hash->hash->block_len);
-  hash->hash->update(hash_context, data, data_len);
-  hash->hash->final(hash_context, mac);
-  hash->hash->init(hash_context);
-  hash->hash->update(hash_context, outer_pad, hash->hash->block_len);
-  hash->hash->update(hash_context, mac, hash->hash->hash_len);
-  hash->hash->final(hash_context, mac);
-  memcpy(return_hash, mac, hmac->hmac->len);
-  memset(mac, 0, sizeof(mac));
-  silc_free(hash_context);
-}
-
 /* Create the HMAC. This is thee make_hmac function pointer.  This
    uses the internal key set with silc_hmac_set_key. */
 
@@ -287,10 +297,11 @@ void silc_hmac_make(SilcHmac hmac, unsigned char *data,
                    uint32 data_len, unsigned char *return_hash,
                    uint32 *return_len)
 {
-  silc_hmac_make_internal(hmac, data, data_len, hmac->key, 
-                         hmac->key_len, return_hash);
-  if (return_len)
-    *return_len = hmac->hmac->len;
+  SILC_LOG_DEBUG(("Making HMAC for message"));
+
+  silc_hmac_init(hmac);
+  silc_hmac_update(hmac, data, data_len);
+  silc_hmac_final(hmac, return_hash, return_len);
 }
 
 /* Creates HMAC just as above except that this doesn't use the internal
@@ -302,9 +313,11 @@ void silc_hmac_make_with_key(SilcHmac hmac, unsigned char *data,
                             unsigned char *return_hash,
                             uint32 *return_len)
 {
-  silc_hmac_make_internal(hmac, data, data_len, key, key_len, return_hash);
-  if (return_len)
-    *return_len = hmac->hmac->len;
+  SILC_LOG_DEBUG(("Making HMAC for message"));
+
+  silc_hmac_init_with_key(hmac, key, key_len);
+  silc_hmac_update(hmac, data, data_len);
+  silc_hmac_final(hmac, return_hash, return_len);
 }
 
 /* Creates the HMAC just as above except that the hash value is truncated
@@ -319,8 +332,65 @@ void silc_hmac_make_truncated(SilcHmac hmac, unsigned char *data,
 {
   unsigned char hvalue[20];
 
-  silc_hmac_make_internal(hmac, data, data_len, 
-                         hmac->key, hmac->key_len, hvalue);
+  SILC_LOG_DEBUG(("Making HMAC for message"));
+
+  silc_hmac_init(hmac);
+  silc_hmac_update(hmac, data, data_len);
+  silc_hmac_final(hmac, return_hash, NULL);
   memcpy(return_hash, hvalue, truncated_len);
   memset(hvalue, 0, sizeof(hvalue));
 }
+
+/* Init HMAC for silc_hmac_update and silc_hmac_final. */
+
+void silc_hmac_init(SilcHmac hmac)
+{
+  silc_hmac_init_with_key(hmac, hmac->key, hmac->key_len);
+}
+
+/* Same as above but with specific key */
+
+void silc_hmac_init_with_key(SilcHmac hmac, const unsigned char *key,
+                            uint32 key_len)
+{
+  SilcHash hash = hmac->hash;
+
+  silc_hmac_init_internal(hmac, hmac->key, hmac->key_len);
+
+  if (!hmac->hash_context)
+    hmac->hash_context = silc_calloc(1, hash->hash->context_len());
+
+  hash->hash->init(hmac->hash_context);
+  hash->hash->update(hmac->hash_context, hmac->inner_pad, 
+                    hash->hash->block_len);
+}
+
+/* Add data to be used in the MAC computation. */
+
+void silc_hmac_update(SilcHmac hmac, const unsigned char *data,
+                     uint32 data_len)
+{
+  SilcHash hash = hmac->hash;
+  hash->hash->update(hmac->hash_context, (unsigned char *)data, data_len);
+}
+
+/* Compute the final MAC. */
+
+void silc_hmac_final(SilcHmac hmac, unsigned char *return_hash,
+                    uint32 *return_len)
+{
+  SilcHash hash = hmac->hash;
+  unsigned char mac[20];
+
+  hash->hash->final(hmac->hash_context, mac);
+  hash->hash->init(hmac->hash_context);
+  hash->hash->update(hmac->hash_context, hmac->outer_pad, 
+                    hash->hash->block_len);
+  hash->hash->update(hmac->hash_context, mac, hash->hash->hash_len);
+  hash->hash->final(hmac->hash_context, mac);
+  memcpy(return_hash, mac, hmac->hmac->len);
+  memset(mac, 0, sizeof(mac));
+
+  if (return_len)
+    *return_len = hmac->hmac->len;
+}
index 7394390ab99d0883253656ac8346657474f9b7c7..286ccdf8a7873298cfd196841eab26aa7f621909 100644 (file)
@@ -1,16 +1,15 @@
 /*
 
-  silchmac.h
+  silchmac.h 
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+  Copyright (C) 1999 - 2001 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-  
+  the Free Software Foundation; version 2 of the License.
+
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 #ifndef SILCHMAC_H
 #define SILCHMAC_H
 
-/* 
-   SILC HMAC object. 
-   
-   This is the HMAC object to create keyed hash values for message
-   authentication. These routines uses already implemented hash functions.
-   HMAC's can be created using any hash function implemented in SILC. These
-   routines were created according to RFC2104. Following short description 
-   of the fields:
-
-   SilcHmacObject:
-
-   char *name
-
-       Name of the HMAC.
-
-   uint32 len
-
-       Length of the MAC the HMAC is to produce (bytes).
-
-
-   SilcHmac:
-
-   SilcHash hash
+/****h* silccrypt/SilcHMACAPI
+ *
+ * DESCRIPTION
+ *
+ *    This is the interface for HMAC, or the keyed hash values, that are
+ *    used for packet and message authentication.  These routines uses
+ *    already implemented hash functions from the SilcHashAPI. These 
+ *    routines were created according to RFC 2104.
+ *
+ ***/
 
-       The hash object to tell what hash function to use with this HMAC.
-
-   char allocated_hash
-
-       TRUE if the `hash' was allocated and FALSE if it is static and
-       must not be freed.
-
-   unsigned char *key
-   uint32 len
-
-       The key and its length used to make the HMAC. This is set
      with silc_hmac_set_key function.
-
-*/
+/****s* silccrypt/SilcHMACAPI/SilcHmac
+ *
+ * NAME
+ * 
+ *    typedef struct SilcHmacStruct *SilcHmac;
+ *
+ * DESCRIPTION
+ *
+ *    This context is the actual HMAC context and is allocated
+ *    by silc_hmac_alloc and given as argument usually to all
+ *    silc_hmac_* functions.  It is freed by the silc_hmac_free
*    function.
+ *
+ ***/
 typedef struct SilcHmacStruct *SilcHmac;
 
+/****s* silccrypt/SilcHMACAPI/SilcHmacObject
+ *
+ * NAME
+ * 
+ *    typedef struct { ... } SilcHmacObject;
+ *
+ * DESCRIPTION
+ *
+ *    This structure represents one HMAC.  The HMAC's name and the
+ *    MAC length is defined in the structure.  This structure is
+ *    then given as argument to the silc_hmac_register.  That function
+ *    is used to register all HMACs into SILC.  They can be then
+ *    allocated by the name found in this structure by calling the
+ *    silc_hmac_alloc.
+ *
+ ***/
 typedef struct {
   char *name;
   uint32 len;
 } SilcHmacObject;
 
-struct SilcHmacStruct {
-  SilcHmacObject *hmac;
-  SilcHash hash;
-  char allocated_hash;
-  unsigned char *key;
-  uint32 key_len;
-};
-
 /* Marks for all hmacs. This can be used in silc_hmac_unregister
    to unregister all hmacs at once. */
 #define SILC_ALL_HMACS ((SilcHmacObject *)1)
@@ -85,28 +79,340 @@ extern SilcHmacObject silc_default_hmacs[];
 #define SILC_DEFAULT_HMAC "hmac-sha1-96"
 
 /* Prototypes */
+
+/****f* silccrypt/SilcHMACAPI/silc_hmac_register
+ *
+ * SYNOPSIS
+ *
+ *    bool silc_hmac_register(SilcHmacObject *hmac);
+ *
+ * DESCRIPTION
+ *
+ *    Registers a new HMAC into the SILC. This function is used at the
+ *    initialization of the SILC.  All registered HMACs should be
+ *    unregistered with silc_hmac_unregister.  The `hmac' includes the
+ *    name of the HMAC and the length of the MAC.  Usually this
+ *    function is not called directly.  Instead, application can call
+ *    the silc_hmac_register_default to register all default HMACs
+ *    that are builtin the sources.  Returns FALSE on error.
+ *
+ ***/
 bool silc_hmac_register(SilcHmacObject *hmac);
+
+/****f* silccrypt/SilcHMACAPI/silc_hmac_unregister
+ *
+ * SYNOPSIS
+ *
+ *    bool silc_hmac_unregister(SilcHmacObject *hmac);
+ *
+ * DESCRIPTION
+ *
+ *    Unregister a HMAC from SILC by the HMAC structure `hmac'.  This
+ *    should be called for all registered HMAC's.  Returns FALSE on
+ *    error.
+ *
+ ***/
 bool silc_hmac_unregister(SilcHmacObject *hmac);
+
+/****f* silccrypt/SilcHMACAPI/silc_hmac_register_default
+ *
+ * SYNOPSIS
+ *
+ *    bool silc_hmac_register_default(void);
+ *
+ * DESCRIPTION
+ *
+ *    Registers all default HMACs into the SILC.  These are the HMACs
+ *    that are builtin in the sources.  See the list of default HMACs
+ *    in the silchmac.c source file.  The application may use this
+ *    to register default HMACs if specific HMAC in any specific order
+ *    is not wanted (application's configuration usually may decide
+ *    the order of the registration, in which case this should not be
+ *    used).
+ *
+ ***/
 bool silc_hmac_register_default(void);
+
+/****f* silccrypt/SilcHMACAPI/silc_hmac_alloc
+ *
+ * SYNOPSIS
+ *
+ *    bool silc_hmac_alloc(char *name, SilcHash hash, SilcHmac *new_hmac);
+ *
+ * DESCRIPTION
+ *
+ *    Allocates a new SilcHmac object of name of `name'.  The `hash' may
+ *    be provided as argument.  If provided it is used as the hash function
+ *    of the HMAC.  If it is NULL then the hash function is allocated and
+ *    the name of the hash algorithm is derived from the `name'.  Returns
+ *    FALSE if such HMAC does not exist.
+ *
+ ***/
 bool silc_hmac_alloc(char *name, SilcHash hash, SilcHmac *new_hmac);
+
+/****f* silccrypt/SilcHMACAPI/silc_hmac_free
+ *
+ * SYNOPSIS
+ *
+ *    void silc_hmac_free(SilcHmac hmac);
+ *
+ * DESCRIPTION
+ *
+ *    Frees the allocated HMAC context.  The key that may have been set
+ *    with the silc_hmac_set_key is also destroyed.
+ *
+ ***/
 void silc_hmac_free(SilcHmac hmac);
+
+/****f* silccrypt/SilcHMACAPI/silc_hmac_is_supported
+ *
+ * SYNOPSIS
+ *
+ *    bool silc_hmac_is_supported(const char *name);
+ *
+ * DESCRIPTION
+ *
+ *    Returns TRUE if the HMAC indicated by the `name' exists.
+ *
+ ***/
 bool silc_hmac_is_supported(const char *name);
+
+/****f* silccrypt/SilcHMACAPI/silc_hmac_get_supported
+ *
+ * SYNOPSIS
+ *
+ *    char *silc_hmac_get_supported(void);
+ *
+ * DESCRIPTION
+ *
+ *    Returns comma (`,') separated list of registered HMACs.  This is
+ *    used for example when sending supported HMAC list during the SILC
+ *    Key Exchange protocol (SKE).  The caller must free the returned
+ *    pointer.
+ *
+ ***/
 char *silc_hmac_get_supported(void);
+
+/****f* silccrypt/SilcHMACAPI/silc_hmac_len
+ *
+ * SYNOPSIS
+ *
+ *    uint32 silc_hmac_len(SilcHmac hmac);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the length of the MAC that the HMAC will produce.
+ *
+ ***/
 uint32 silc_hmac_len(SilcHmac hmac);
+
+/****f* silccrypt/SilcHMACAPI/silc_hmac_get_hash
+ *
+ * SYNOPSIS
+ *
+ *    SilcHash silc_hmac_get_hash(SilcHmac hmac);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the SilcHash context that has been associated with the
+ *    HMAC context.  The caller must not free the returned context.
+ *
+ ***/
+SilcHash silc_hmac_get_hash(SilcHmac hmac);
+
+/****f* silccrypt/SilcHMACAPI/silc_hmac_get_name
+ *
+ * SYNOPSIS
+ *
+ *    const char *silc_hmac_get_name(SilcHmac hmac);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the name of the HMAC context.
+ *
+ ***/
+const char *silc_hmac_get_name(SilcHmac hmac);
+
+/****f* silccrypt/SilcHMACAPI/silc_hmac_set_key
+ *
+ * SYNOPSIS
+ *
+ *    void silc_hmac_set_key(SilcHmac hmac, const unsigned char *key,
+ *                           uint32 key_len);
+ *
+ * DESCRIPTION
+ *
+ *    Sets the key to be used in the HMAC operation.  This must be set
+ *    before calling silc_hmac_make or silc_hmac_final functions.  If
+ *    you do not want to set the key you can still produce a MAC by
+ *    calling the silc_hmac_make_with_key where you give the key as
+ *    argument.  Usually application still wants to set the key.
+ *
+ ***/
 void silc_hmac_set_key(SilcHmac hmac, const unsigned char *key,
                       uint32 key_len);
+
+/****f* silccrypt/SilcHMACAPI/silc_hmac_make
+ *
+ * SYNOPSIS
+ *
+ *    void silc_hmac_make(SilcHmac hmac, unsigned char *data,
+ *                        uint32 data_len, unsigned char *return_hash,
+ *                        uint32 *return_len);
+ *
+ * DESCRIPTION
+ *
+ *    Computes a MAC from a data buffer indicated by the `data' of the
+ *    length of `data_len'.  The returned MAC is copied into the 
+ *    `return_hash' pointer which must be at least the size of the
+ *    value silc_hmac_len returns.  The returned length is still
+ *    returned to `return_len'.
+ *
+ ***/
 void silc_hmac_make(SilcHmac hmac, unsigned char *data,
                    uint32 data_len, unsigned char *return_hash,
                    uint32 *return_len);
+
+/****f* silccrypt/SilcHMACAPI/silc_hmac_make_with_key
+ *
+ * SYNOPSIS
+ *
+ *    void silc_hmac_make_with_key(SilcHmac hmac, unsigned char *data,
+ *                                 uint32 data_len, 
+ *                                 unsigned char *key, uint32 key_len,
+ *                                 unsigned char *return_hash,
+ *                                 uint32 *return_len);
+ *
+ * DESCRIPTION
+ *
+ *    Same as the silc_hmac_make but takes the key for the HMAC as
+ *    argument.  If this is used the key that may have been set by calling
+ *    silc_hmac_set_key is ignored.
+ *
+ ***/
 void silc_hmac_make_with_key(SilcHmac hmac, unsigned char *data,
                             uint32 data_len, 
                             unsigned char *key, uint32 key_len,
                             unsigned char *return_hash,
                             uint32 *return_len);
+
+/****f* silccrypt/SilcHMACAPI/silc_hmac_make_truncated
+ *
+ * SYNOPSIS
+ *
+ *    void silc_hmac_make_truncated(SilcHmac hmac, 
+ *                                  unsigned char *data, 
+ *                                  uint32 data_len,
+ *                                  uint32 truncated_len,
+ *                                  unsigned char *return_hash);
+ *
+ * DESCRIPTION
+ *
+ *    Same as the silc_hmac_make except that the returned MAC is
+ *    truncated to the length indicated by the `truncated_len'.  Some
+ *    special applications may need this function.  The `return_hash'
+ *    must be at least the size of `truncated_len'.
+ *
+ * NOTES
+ *
+ *    For security reasons, one should not truncate to less than half
+ *    of the length of the true MAC lenght.  However, since this routine
+ *    may be used to non-critical applications this allows these dangerous
+ *    truncations.
+ *
+ ***/
 void silc_hmac_make_truncated(SilcHmac hmac, 
                              unsigned char *data, 
                              uint32 data_len,
                              uint32 truncated_len,
                              unsigned char *return_hash);
 
+/****f* silccrypt/SilcHMACAPI/silc_hmac_init
+ *
+ * SYNOPSIS
+ *
+ *    void silc_hmac_init(SilcHmac hmac);
+ *
+ * DESCRIPTION
+ *
+ *    Sometimes calling the silc_hmac_make might not be the most
+ *    optimal case of doing MACs.  If you have a lot of different data
+ *    that you need to put together for computing a MAC you may either
+ *    put them into a buffer and compute the MAC from the buffer by
+ *    calling the silc_hmac_make, or you can use the silc_hmac_init,
+ *    silc_hmac_update and silc_hmac_final to do the MAC.  This function
+ *    prepares the allocated HMAC context for this kind of MAC 
+ *    computation.  The caller must have been called the function
+ *    silc_hmac_set_key before calling this function.  To add the
+ *    data to be used in the MAC computation call the silc_hmac_update
+ *    function.
+ *
+ ***/
+void silc_hmac_init(SilcHmac hmac);
+
+/****f* silccrypt/SilcHMACAPI/silc_hmac_init_with_key
+ *
+ * SYNOPSIS
+ *
+ *    void silc_hmac_init_with_key(SilcHmac hmac, const unsigned char *key,
+ *                                 uint32 key_len);
+ *
+ * DESCRIPTION
+ *
+ *    Same as silc_hmac_init but initializes with specific key.  The
+ *    key that may have been set with silc_hmac_set_key is ignored.
+ *
+ ***/
+void silc_hmac_init_with_key(SilcHmac hmac, const unsigned char *key,
+                            uint32 key_len);
+
+/****f* silccrypt/SilcHMACAPI/silc_hmac_update
+ *
+ * SYNOPSIS
+ *
+ *    void silc_hmac_update(SilcHmac hmac, const unsigned char *data,
+ *                          uint32 data_len);
+ *
+ * DESCRIPTION
+ *
+ *    This function may be called to add data to be used in the MAC
+ *    computation.  This can be called multiple times to add data from
+ *    many sources before actually performing the HMAC.  Once you've
+ *    added all the data you need you can call the silc_hmac_final to
+ *    actually produce the MAC.
+ *
+ * EXAMPLE
+ *
+ *    unsigned char mac[20];
+ *    uint32 mac_len;
+ *
+ *    silc_hmac_init(hmac);
+ *    silc_hmac_update(hmac, data, data_len);
+ *    silc_hmac_update(hmac, more_data, more_data_len);
+ *    silc_hmac_final(hmac, mac, &mac_len);
+ *
+ ***/
+void silc_hmac_update(SilcHmac hmac, const unsigned char *data,
+                     uint32 data_len);
+
+/****f* silccrypt/SilcHMACAPI/silc_hmac_init
+ *
+ * SYNOPSIS
+ *
+ *    void silc_hmac_final(SilcHmac hmac, unsigned char *return_hash,
+ *                         uint32 *return_len);
+ *
+ * DESCRIPTION
+ *
+ *    This function is used to produce the final MAC from the data
+ *    that has been added to the HMAC context by calling the 
+ *    silc_hmac_update function.  The MAC is copied in to the
+ *    `return_hash' pointer which must be at least the size that
+ *    the silc_hmac_len returns.  The length of the MAC is still
+ *    returned into `return_len'.
+ *
+ ***/
+void silc_hmac_final(SilcHmac hmac, unsigned char *return_hash,
+                    uint32 *return_len);
+
 #endif