From 9c4f7f18c31afa9dbaf4540c30cafd980b29c318 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Mon, 15 Oct 2001 21:22:01 +0000 Subject: [PATCH] updates. --- CHANGES | 5 + apps/irssi/src/silc/core/client_ops.c | 2 +- apps/irssi/src/silc/core/silc-channels.c | 6 +- apps/silcd/command.c | 17 +- apps/silcd/command_reply.c | 2 +- apps/silcd/idlist.c | 6 +- apps/silcd/idlist.h | 16 +- apps/silcd/packet_receive.c | 5 +- apps/silcd/packet_send.c | 4 +- apps/silcd/protocol.c | 8 +- apps/silcd/server.c | 10 +- lib/silcclient/client_channel.c | 14 +- lib/silcclient/client_notify.c | 5 +- lib/silcclient/protocol.c | 5 +- lib/silccore/silcpacket.c | 34 +- lib/silccore/silcpacket.h | 17 +- lib/silccrypt/silchmac.c | 206 ++++++++---- lib/silccrypt/silchmac.h | 408 ++++++++++++++++++++--- 18 files changed, 588 insertions(+), 182 deletions(-) diff --git a/CHANGES b/CHANGES index 385fc821..25649f7f 100644 --- a/CHANGES +++ b/CHANGES @@ -23,6 +23,11 @@ Mon Oct 15 17:42:55 EDT 2001 Pekka Riikonen 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 * Assure that router cannot reroute the same channel message diff --git a/apps/irssi/src/silc/core/client_ops.c b/apps/irssi/src/silc/core/client_ops.c index f3507b7e..b140aa8e 100644 --- a/apps/irssi/src/silc/core/client_ops.c +++ b/apps/irssi/src/silc/core/client_ops.c @@ -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); diff --git a/apps/irssi/src/silc/core/silc-channels.c b/apps/irssi/src/silc/core/silc-channels.c index 1292aa82..81696eee 100644 --- a/apps/irssi/src/silc/core/silc-channels.c +++ b/apps/irssi/src/silc/core/silc-channels.c @@ -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, " "); diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 0eae9abc..d77a7cdd 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -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)); } } diff --git a/apps/silcd/command_reply.c b/apps/silcd/command_reply.c index 9b18d11a..88a91d64 100644 --- a/apps/silcd/command_reply.c +++ b/apps/silcd/command_reply.c @@ -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 */ diff --git a/apps/silcd/idlist.c b/apps/silcd/idlist.c index f762787f..527b49ea 100644 --- a/apps/silcd/idlist.c +++ b/apps/silcd/idlist.c @@ -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; diff --git a/apps/silcd/idlist.h b/apps/silcd/idlist.h index bd526b93..6e8e2c94 100644 --- a/apps/silcd/idlist.h +++ b/apps/silcd/idlist.h @@ -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 */ diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index cef91017..983d44f3 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -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)); } diff --git a/apps/silcd/packet_send.c b/apps/silcd/packet_send.c index 16020908..a7349360 100644 --- a/apps/silcd/packet_send.c +++ b/apps/silcd/packet_send.c @@ -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); diff --git a/apps/silcd/protocol.c b/apps/silcd/protocol.c index 170120f6..c3cad75b 100644 --- a/apps/silcd/protocol.c +++ b/apps/silcd/protocol.c @@ -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 { diff --git a/apps/silcd/server.c b/apps/silcd/server.c index 0822bec5..5c95ce98 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -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); diff --git a/lib/silcclient/client_channel.c b/lib/silcclient/client_channel.c index 88ccd453..d08b3da0 100644 --- a/lib/silcclient/client_channel.c +++ b/lib/silcclient/client_channel.c @@ -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 */ diff --git a/lib/silcclient/client_notify.c b/lib/silcclient/client_notify.c index 82a0654f..a5af4886 100644 --- a/lib/silcclient/client_notify.c +++ b/lib/silcclient/client_notify.c @@ -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)); } diff --git a/lib/silcclient/protocol.c b/lib/silcclient/protocol.c index 8460ad8f..51ee452c 100644 --- a/lib/silcclient/protocol.c +++ b/lib/silcclient/protocol.c @@ -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 { diff --git a/lib/silccore/silcpacket.c b/lib/silccore/silcpacket.c index ec26ab1d..28349d51 100644 --- a/lib/silccore/silcpacket.c +++ b/lib/silccore/silcpacket.c @@ -1,16 +1,15 @@ /* - silcpacket.c + silcpacket.c - Author: Pekka Riikonen + Author: Pekka Riikonen 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; diff --git a/lib/silccore/silcpacket.h b/lib/silccore/silcpacket.h index a7d5c3ec..c8490b0b 100644 --- a/lib/silccore/silcpacket.h +++ b/lib/silccore/silcpacket.h @@ -1,16 +1,15 @@ /* - silcpacket.h - + silcpacket.h + Author: Pekka Riikonen - + 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 * diff --git a/lib/silccrypt/silchmac.c b/lib/silccrypt/silchmac.c index 00fd15ec..77dce315 100644 --- a/lib/silccrypt/silchmac.c +++ b/lib/silccrypt/silchmac.c @@ -1,16 +1,15 @@ /* - silchmac.c + silchmac.c - Author: Pekka Riikonen + Author: Pekka Riikonen - 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 @@ -21,6 +20,20 @@ #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; +} diff --git a/lib/silccrypt/silchmac.h b/lib/silccrypt/silchmac.h index 7394390a..286ccdf8 100644 --- a/lib/silccrypt/silchmac.h +++ b/lib/silccrypt/silchmac.h @@ -1,16 +1,15 @@ /* - silchmac.h + silchmac.h - Author: Pekka Riikonen + Author: Pekka Riikonen - 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 @@ -21,59 +20,54 @@ #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 -- 2.24.0