5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 /* Channel Payload, Channel Message Payload and Channel Key Payload
24 #include "silcincludes.h"
25 #include "silcchannel.h"
27 /******************************************************************************
31 ******************************************************************************/
33 /* Channel Message Payload structure. Contents of this structure is parsed
35 struct SilcChannelPayloadStruct {
37 unsigned char *channel_name;
39 unsigned char *channel_id;
43 /* Parses channel payload returning new channel payload structure. */
45 SilcChannelPayload silc_channel_payload_parse(const unsigned char *payload,
46 SilcUInt32 payload_len)
48 SilcBufferStruct buffer;
49 SilcChannelPayload newp;
52 SILC_LOG_DEBUG(("Parsing channel payload"));
54 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
55 newp = silc_calloc(1, sizeof(*newp));
59 /* Parse the Channel Payload. Ignore the padding. */
60 ret = silc_buffer_unformat(&buffer,
61 SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_name,
63 SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_id,
65 SILC_STR_UI_INT(&newp->mode),
70 if ((newp->name_len < 1 || newp->name_len > buffer.len) ||
71 (newp->id_len < 1 || newp->id_len > buffer.len)) {
72 SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
79 silc_channel_payload_free(newp);
83 /* Parses list of channel payloads returning list of payloads. */
85 SilcDList silc_channel_payload_parse_list(const unsigned char *payload,
86 SilcUInt32 payload_len)
88 SilcBufferStruct buffer;
90 SilcChannelPayload newp;
93 SILC_LOG_DEBUG(("Parsing channel payload list"));
95 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
96 list = silc_dlist_init();
99 newp = silc_calloc(1, sizeof(*newp));
102 ret = silc_buffer_unformat(&buffer,
103 SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_name,
105 SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_id,
107 SILC_STR_UI_INT(&newp->mode),
112 if ((newp->name_len < 1 || newp->name_len > buffer.len) ||
113 (newp->id_len < 1 || newp->id_len > buffer.len)) {
114 SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
118 len = 2 + newp->name_len + 2 + newp->id_len + 4;
119 if (buffer.len < len)
121 silc_buffer_pull(&buffer, len);
123 silc_dlist_add(list, newp);
129 silc_channel_payload_list_free(list);
133 /* Encode new channel payload and returns it as buffer. */
135 SilcBuffer silc_channel_payload_encode(const unsigned char *channel_name,
136 SilcUInt16 channel_name_len,
137 const unsigned char *channel_id,
138 SilcUInt32 channel_id_len,
143 SILC_LOG_DEBUG(("Encoding message payload"));
145 buffer = silc_buffer_alloc_size(2 + channel_name_len + 2 +
150 /* Encode the Channel Payload */
151 silc_buffer_format(buffer,
152 SILC_STR_UI_SHORT(channel_name_len),
153 SILC_STR_UI_XNSTRING(channel_name, channel_name_len),
154 SILC_STR_UI_SHORT(channel_id_len),
155 SILC_STR_UI_XNSTRING(channel_id, channel_id_len),
156 SILC_STR_UI_INT(mode),
162 /* Frees Channel Payload */
164 void silc_channel_payload_free(SilcChannelPayload payload)
166 silc_free(payload->channel_name);
167 silc_free(payload->channel_id);
171 /* Free's list of Channel Payloads */
173 void silc_channel_payload_list_free(SilcDList list)
175 SilcChannelPayload entry;
177 silc_dlist_start(list);
178 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
179 silc_free(entry->channel_name);
180 silc_free(entry->channel_id);
181 silc_dlist_del(list, entry);
185 silc_dlist_uninit(list);
188 /* Return the channel name */
190 unsigned char *silc_channel_get_name(SilcChannelPayload payload,
191 SilcUInt32 *channel_name_len)
193 if (channel_name_len)
194 *channel_name_len = payload->name_len;
196 return payload->channel_name;
199 /* Return the channel ID */
201 unsigned char *silc_channel_get_id(SilcChannelPayload payload,
202 SilcUInt32 *channel_id_len)
205 *channel_id_len = payload->id_len;
207 return payload->channel_id;
210 /* Return the channel ID as parsed ID. */
212 SilcChannelID *silc_channel_get_id_parse(SilcChannelPayload payload)
214 return silc_id_str2id(payload->channel_id, payload->id_len,
218 /* Return the mode. The mode is arbitrary. It can be the mode of the
219 channel or perhaps the mode of the client on the channel. The protocol
220 dictates what the usage of the mode is in different circumstances. */
222 SilcUInt32 silc_channel_get_mode(SilcChannelPayload payload)
224 return payload->mode;
227 /******************************************************************************
229 Channel Message Payload
231 ******************************************************************************/
233 /* Calculates padding length for message payload */
234 #define SILC_CHANNEL_MESSAGE_PAD(__payloadlen) (16 - (__payloadlen) % 16)
236 /* Header length plus maximum padding length */
237 #define SILC_CHANNEL_MESSAGE_HLEN 6 + 16
239 /* Returns the data length that fits to the packet. If data length is too
240 big it will be truncated to fit to the payload. */
241 #define SILC_CHANNEL_MESSAGE_DATALEN(data_len, header_len) \
242 ((data_len + SILC_CHANNEL_MESSAGE_HLEN + header_len) > \
243 SILC_PACKET_MAX_LEN ? \
244 data_len - ((data_len + SILC_CHANNEL_MESSAGE_HLEN + header_len) - \
245 SILC_PACKET_MAX_LEN) : data_len)
247 /* Channel Message Payload structure. Contents of this structure is parsed
248 from SILC packets. */
249 struct SilcChannelMessagePayloadStruct {
250 SilcMessageFlags flags;
259 /* Decrypts the channel message payload. First push the IV out of the
260 packet. The IV is used in the decryption process. Then decrypt the
261 message. After decyprtion, take the MAC from the decrypted packet,
262 compute MAC and compare the MACs. If they match, the decryption was
263 successful and we have the channel message ready to be displayed. */
265 bool silc_channel_message_payload_decrypt(unsigned char *data,
270 SilcUInt32 iv_len, mac_len;
271 unsigned char *end, *mac, mac2[32];
272 unsigned char *dst, iv[SILC_CIPHER_MAX_IV_SIZE];
274 /* Push the IV out of the packet, and copy the IV since we do not want
275 to modify the original data buffer. */
276 end = data + data_len;
277 iv_len = silc_cipher_get_block_len(cipher);
278 memcpy(iv, end - iv_len, iv_len);
280 /* Allocate destination decryption buffer since we do not want to modify
281 the original data buffer, since we might want to call this function
282 many times for same payload. */
284 dst = silc_calloc(data_len - iv_len, sizeof(*dst));
291 /* Decrypt the channel message */
292 silc_cipher_decrypt(cipher, data, dst, data_len - iv_len, iv);
296 end = dst + (data_len - iv_len);
297 mac_len = silc_hmac_len(hmac);
298 mac = (end - mac_len);
300 /* Check the MAC of the message */
301 SILC_LOG_DEBUG(("Checking channel message MACs"));
302 silc_hmac_init(hmac);
303 silc_hmac_update(hmac, dst, (data_len - iv_len - mac_len));
304 silc_hmac_update(hmac, data + (data_len - iv_len), iv_len);
305 silc_hmac_final(hmac, mac2, &mac_len);
306 if (memcmp(mac, mac2, mac_len)) {
307 SILC_LOG_DEBUG(("Channel message MACs does not match"));
311 SILC_LOG_DEBUG(("MAC is Ok"));
313 /* Now copy the decrypted data into the buffer since it is verified
314 it decrypted correctly. */
315 memcpy(data, dst, data_len - iv_len);
316 memset(dst, 0, data_len - iv_len);
323 /* Parses channel message payload returning new channel payload structure.
324 This also decrypts it and checks the MAC. */
326 SilcChannelMessagePayload
327 silc_channel_message_payload_parse(unsigned char *payload,
328 SilcUInt32 payload_len,
332 SilcBufferStruct buffer;
333 SilcChannelMessagePayload newp;
335 SilcUInt32 iv_len, mac_len;
337 SILC_LOG_DEBUG(("Parsing channel message payload"));
339 silc_buffer_set(&buffer, payload, payload_len);
341 /* Decrypt the payload */
342 ret = silc_channel_message_payload_decrypt(buffer.data, buffer.len,
347 iv_len = silc_cipher_get_block_len(cipher);
348 mac_len = silc_hmac_len(hmac);
350 newp = silc_calloc(1, sizeof(*newp));
354 /* Parse the Channel Message Payload. */
355 ret = silc_buffer_unformat(&buffer,
356 SILC_STR_UI_SHORT(&newp->flags),
357 SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
359 SILC_STR_UI16_NSTRING_ALLOC(&newp->pad,
361 SILC_STR_UI_XNSTRING(&newp->mac, mac_len),
362 SILC_STR_UI_XNSTRING(&newp->iv, iv_len),
367 if (newp->data_len > buffer.len) {
368 SILC_LOG_ERROR(("Incorrect channel message payload in packet, "
376 silc_channel_message_payload_free(newp);
380 /* This function is used to encrypt the Channel Messsage Payload which is
381 the `data' and `data_len'. This is used internally by the Channel Message
382 Payload encoding routines but application may call this too if needed.
383 The `data_len' is the data lenght which is used to create MAC out of.
384 The `true_len' is the true length of `data' message payload and is used
385 assemble rest of the packet after MAC creation. The `true_len' length
386 packet will then be encrypted. */
388 bool silc_channel_message_payload_encrypt(unsigned char *data,
396 unsigned char mac[32];
398 SilcBufferStruct buf;
400 /* Compute the MAC of the channel message data */
401 silc_hmac_init(hmac);
402 silc_hmac_update(hmac, data, data_len);
403 silc_hmac_update(hmac, iv, iv_len);
404 silc_hmac_final(hmac, mac, &mac_len);
406 /* Put rest of the data to the payload */
407 silc_buffer_set(&buf, data, true_len);
408 silc_buffer_pull(&buf, data_len);
409 silc_buffer_format(&buf,
410 SILC_STR_UI_XNSTRING(mac, mac_len),
411 SILC_STR_UI_XNSTRING(iv, iv_len),
414 /* Encrypt payload of the packet. This is encrypted with the channel key. */
415 silc_cipher_encrypt(cipher, data, data, true_len - iv_len, iv);
417 memset(mac, 0, sizeof(mac));
421 /* Encodes channel message payload into a buffer and returns it. This is used
422 to add channel message payload into a packet. As the channel payload is
423 encrypted separately from other parts of the packet padding must
424 be applied to the payload. */
426 SilcBuffer silc_channel_message_payload_encode(SilcUInt16 flags,
428 const unsigned char *data,
437 SilcUInt32 len, pad_len, mac_len;
438 unsigned char pad[16];
440 SILC_LOG_DEBUG(("Encoding channel message payload"));
442 /* Calculate length of padding. IV is not included into the calculation
443 since it is not encrypted. */
444 mac_len = silc_hmac_len(hmac);
445 data_len = SILC_CHANNEL_MESSAGE_DATALEN(data_len, mac_len + iv_len);
446 len = 6 + data_len + mac_len;
447 pad_len = SILC_CHANNEL_MESSAGE_PAD(len);
449 /* Allocate channel payload buffer */
450 len += pad_len + iv_len;
451 buffer = silc_buffer_alloc(len);
455 /* Generate padding */
457 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
459 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
462 /* Encode the Channel Message Payload */
463 silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
464 silc_buffer_format(buffer,
465 SILC_STR_UI_SHORT(flags),
466 SILC_STR_UI_SHORT(data_len),
467 SILC_STR_UI_XNSTRING(data, data_len),
468 SILC_STR_UI_SHORT(pad_len),
469 SILC_STR_UI_XNSTRING(pad, pad_len),
472 memset(pad, 0, sizeof(pad));
474 if (!silc_channel_message_payload_encrypt(buffer->data, buffer->len,
475 buffer->truelen, iv, iv_len,
477 silc_buffer_free(buffer);
481 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer) - buffer->len);
486 /* Free's Channel Message Payload */
488 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
491 memset(payload->data, 0, payload->data_len);
492 silc_free(payload->data);
500 silc_channel_message_get_flags(SilcChannelMessagePayload payload)
502 return payload->flags;
507 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
508 SilcUInt32 *data_len)
511 *data_len = payload->data_len;
513 return payload->data;
516 /* Return MAC. The caller knows the length of the MAC */
518 unsigned char *silc_channel_message_get_mac(SilcChannelMessagePayload payload)
523 /* Return IV. The caller knows the length of the IV */
525 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
530 /******************************************************************************
534 ******************************************************************************/
536 /* Channel Key Payload structrue. Channel keys are parsed from SILC
537 packets into this structure. */
538 struct SilcChannelKeyPayloadStruct {
541 SilcUInt16 cipher_len;
542 unsigned char *cipher;
547 /* Parses channel key payload returning new channel key payload structure */
549 SilcChannelKeyPayload
550 silc_channel_key_payload_parse(const unsigned char *payload,
551 SilcUInt32 payload_len)
553 SilcBufferStruct buffer;
554 SilcChannelKeyPayload newp;
557 SILC_LOG_DEBUG(("Parsing channel key payload"));
559 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
560 newp = silc_calloc(1, sizeof(*newp));
564 /* Parse the Channel Key Payload */
566 silc_buffer_unformat(&buffer,
567 SILC_STR_UI16_NSTRING_ALLOC(&newp->id, &newp->id_len),
568 SILC_STR_UI16_NSTRING_ALLOC(&newp->cipher,
570 SILC_STR_UI16_NSTRING_ALLOC(&newp->key,
576 if (newp->id_len < 1 || newp->key_len < 1 || newp->cipher_len < 1) {
577 SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
587 silc_free(newp->cipher);
589 silc_free(newp->key);
594 /* Encodes channel key payload into a buffer and returns it. This is used
595 to add channel key payload into a packet. */
597 SilcBuffer silc_channel_key_payload_encode(SilcUInt16 id_len,
598 const unsigned char *id,
599 SilcUInt16 cipher_len,
600 const unsigned char *cipher,
602 const unsigned char *key)
607 SILC_LOG_DEBUG(("Encoding channel key payload"));
609 /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
611 len = 2 + id_len + 2 + key_len + 2 + cipher_len;
612 buffer = silc_buffer_alloc_size(len);
616 /* Encode the Channel Payload */
617 silc_buffer_format(buffer,
618 SILC_STR_UI_SHORT(id_len),
619 SILC_STR_UI_XNSTRING(id, id_len),
620 SILC_STR_UI_SHORT(cipher_len),
621 SILC_STR_UI_XNSTRING(cipher, cipher_len),
622 SILC_STR_UI_SHORT(key_len),
623 SILC_STR_UI_XNSTRING(key, key_len),
629 /* Frees Channel Key Payload */
631 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
634 silc_free(payload->id);
635 silc_free(payload->cipher);
637 memset(payload->key, 0, payload->key_len);
638 silc_free(payload->key);
646 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
650 *id_len = payload->id_len;
655 /* Return cipher name */
657 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
658 SilcUInt32 *cipher_len)
661 *cipher_len = payload->cipher_len;
663 return payload->cipher;
668 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
672 *key_len = payload->key_len;