-/* Sends packet to a channel. Packet to channel is always encrypted
- differently from "normal" packets. SILC header of the packet is
- encrypted with the next receiver's key and the rest of the packet is
- encrypted with the channel specific key. Padding and HMAC is computed
- with the next receiver's key. */
-
-void silc_client_packet_send_to_channel(SilcClient client,
- SilcSocketConnection sock,
- SilcChannelEntry channel,
- unsigned char *data,
- unsigned int data_len,
- int force_send)
-{
- int i;
- SilcClientConnection conn = (SilcClientConnection)sock->user_data;
- SilcBuffer payload;
- SilcPacketContext packetdata;
- SilcCipher cipher;
- SilcHmac hmac;
- unsigned char *id_string;
-
- SILC_LOG_DEBUG(("Sending packet to channel"));
-
- if (!channel || !channel->key) {
- client->ops->say(client, conn,
- "Cannot talk to channel: key does not exist");
- return;
- }
-
- /* Generate IV */
- if (!channel->iv)
- for (i = 0; i < 16; i++)
- channel->iv[i] = silc_rng_get_byte(client->rng);
- else
- silc_hash_make(client->md5hash, channel->iv, 16, channel->iv);
-
- /* Encode the channel payload */
- payload = silc_channel_encode_payload(strlen(conn->nickname), conn->nickname,
- data_len, data, 16, channel->iv,
- client->rng);
- if (!payload) {
- client->ops->say(client, conn,
- "Error: Could not create packet to be sent to channel");
- return;
- }
-
- /* Get data used in packet header encryption, keys and stuff. Rest
- of the packet (the payload) is, however, encrypted with the
- specified channel key. */
- cipher = conn->send_key;
- hmac = conn->hmac;
- id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-
- /* Set the packet context pointers. The destination ID is always
- the Channel ID of the channel. Server and router will handle the
- distribution of the packet. */
- packetdata.flags = 0;
- packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
- packetdata.src_id = conn->local_id_data;
- packetdata.src_id_len = SILC_ID_CLIENT_LEN;
- packetdata.src_id_type = SILC_ID_CLIENT;
- packetdata.dst_id = id_string;
- packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
- packetdata.dst_id_type = SILC_ID_CHANNEL;
- packetdata.rng = client->rng;
- packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len + packetdata.dst_id_len;
- packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len +
- packetdata.dst_id_len));
-
- /* Prepare outgoing data buffer for packet sending */
- silc_packet_send_prepare(sock,
- SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len +
- packetdata.dst_id_len,
- packetdata.padlen,
- payload->len);
-
- packetdata.buffer = sock->outbuf;
-
- /* Encrypt payload of the packet. This is encrypted with the channel key. */
- channel->channel_key->cipher->encrypt(channel->channel_key->context,
- payload->data, payload->data,
- payload->len - 16, /* -IV_LEN */
- channel->iv);
-
- /* Put the actual encrypted payload data into the buffer. */
- silc_buffer_put(sock->outbuf, payload->data, payload->len);
-
- /* Create the outgoing packet */
- silc_packet_assemble(&packetdata);
-
- /* Encrypt the header and padding of the packet. This is encrypted
- with normal session key shared with our server. */
- silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len + packetdata.dst_id_len +
- packetdata.padlen);
-
- SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
- sock->outbuf->data, sock->outbuf->len);
-
- /* Now actually send the packet */
- silc_client_packet_send_real(client, sock, force_send);
- silc_buffer_free(payload);
- silc_free(id_string);
-}
-
-/* Sends private message to remote client. If private message key has
- not been set with this client then the message will be encrypted using
- normal session keys. Private messages are special packets in SILC
- network hence we need this own function for them. This is similiar
- to silc_client_packet_send_to_channel except that we send private
- message. */
-
-void silc_client_packet_send_private_message(SilcClient client,
- SilcSocketConnection sock,
- SilcClientEntry client_entry,
- unsigned char *data,
- unsigned int data_len,
- int force_send)
-{
- SilcClientConnection conn = (SilcClientConnection)sock->user_data;
- SilcBuffer buffer;
- SilcPacketContext packetdata;
- unsigned int nick_len;
- SilcCipher cipher;
- SilcHmac hmac;
-
- SILC_LOG_DEBUG(("Sending private message"));
-
- /* Create private message payload */
- nick_len = strlen(conn->nickname);
- buffer = silc_buffer_alloc(2 + nick_len + data_len);
- silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
- silc_buffer_format(buffer,
- SILC_STR_UI_SHORT(nick_len),
- SILC_STR_UI_XNSTRING(conn->nickname,
- nick_len),
- SILC_STR_UI_XNSTRING(data, data_len),
- SILC_STR_END);
-
- /* If we don't have private message specific key then private messages
- are just as any normal packet thus call normal packet sending. If
- the key exist then the encryption process is a bit different and
- will be done in the rest of this function. */
- if (!client_entry->send_key) {
- silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
- client_entry->id, SILC_ID_CLIENT, NULL, NULL,
- buffer->data, buffer->len, force_send);
- goto out;
- }
-
- /* We have private message specific key */
-
- /* Get data used in the encryption */
- cipher = client_entry->send_key;
- hmac = conn->hmac;
-
- /* Set the packet context pointers. */
- packetdata.flags = 0;
- packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
- packetdata.src_id = conn->local_id_data;
- packetdata.src_id_len = SILC_ID_CLIENT_LEN;
- packetdata.src_id_type = SILC_ID_CLIENT;
- if (client_entry)
- packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
- else
- packetdata.dst_id = conn->local_id_data;
- packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
- packetdata.dst_id_type = SILC_ID_CLIENT;
- packetdata.rng = client->rng;
- packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len + packetdata.dst_id_len;
- packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len +
- packetdata.dst_id_len));
-
- /* Prepare outgoing data buffer for packet sending */
- silc_packet_send_prepare(sock,
- SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len +
- packetdata.dst_id_len,
- packetdata.padlen,
- buffer->len);
-
- packetdata.buffer = sock->outbuf;
-
- /* Encrypt payload of the packet. Encrypt with private message specific
- key if it exist, otherwise with session key. */
- cipher->cipher->encrypt(cipher->context, buffer->data, buffer->data,
- buffer->len, cipher->iv);
-
- /* Put the actual encrypted payload data into the buffer. */
- silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
-
- /* Create the outgoing packet */
- silc_packet_assemble(&packetdata);
-
- /* Encrypt the header and padding of the packet. */
- silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
- packetdata.src_id_len + packetdata.dst_id_len +
- packetdata.padlen);
-
- SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
- sock->outbuf->data, sock->outbuf->len);
-
- /* Now actually send the packet */
- silc_client_packet_send_real(client, sock, force_send);
- silc_free(packetdata.dst_id);
-
- out:
- silc_free(buffer);
-}
-