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)) {
308 /* Backwards support for old mac checking, remove in 1.0 */
309 silc_hmac_make(hmac, dst, (data_len - iv_len - mac_len), mac2, &mac_len);
310 if (memcmp(mac, mac2, mac_len)) {
313 SILC_LOG_DEBUG(("Channel message MACs does not match"));
320 SILC_LOG_DEBUG(("MAC is Ok"));
322 /* Now copy the decrypted data into the buffer since it is verified
323 it decrypted correctly. */
324 memcpy(data, dst, data_len - iv_len);
325 memset(dst, 0, data_len - iv_len);
332 /* Parses channel message payload returning new channel payload structure.
333 This also decrypts it and checks the MAC. */
335 SilcChannelMessagePayload
336 silc_channel_message_payload_parse(unsigned char *payload,
337 SilcUInt32 payload_len,
341 SilcBufferStruct buffer;
342 SilcChannelMessagePayload newp;
344 SilcUInt32 iv_len, mac_len;
346 SILC_LOG_DEBUG(("Parsing channel message payload"));
348 silc_buffer_set(&buffer, payload, payload_len);
350 /* Decrypt the payload */
351 ret = silc_channel_message_payload_decrypt(buffer.data, buffer.len,
356 iv_len = silc_cipher_get_block_len(cipher);
357 mac_len = silc_hmac_len(hmac);
359 newp = silc_calloc(1, sizeof(*newp));
363 /* Parse the Channel Message Payload. */
364 ret = silc_buffer_unformat(&buffer,
365 SILC_STR_UI_SHORT(&newp->flags),
366 SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
368 SILC_STR_UI16_NSTRING_ALLOC(&newp->pad,
370 SILC_STR_UI_XNSTRING(&newp->mac, mac_len),
371 SILC_STR_UI_XNSTRING(&newp->iv, iv_len),
376 if (newp->data_len > buffer.len) {
377 SILC_LOG_ERROR(("Incorrect channel message payload in packet, "
385 silc_channel_message_payload_free(newp);
389 /* This function is used to encrypt the Channel Messsage Payload which is
390 the `data' and `data_len'. This is used internally by the Channel Message
391 Payload encoding routines but application may call this too if needed.
392 The `data_len' is the data lenght which is used to create MAC out of.
393 The `true_len' is the true length of `data' message payload and is used
394 assemble rest of the packet after MAC creation. The `true_len' length
395 packet will then be encrypted. */
397 bool silc_channel_message_payload_encrypt(unsigned char *data,
405 unsigned char mac[32];
407 SilcBufferStruct buf;
409 /* Compute the MAC of the channel message data */
410 silc_hmac_init(hmac);
411 silc_hmac_update(hmac, data, data_len);
412 silc_hmac_update(hmac, iv, iv_len);
413 silc_hmac_final(hmac, mac, &mac_len);
415 /* Put rest of the data to the payload */
416 silc_buffer_set(&buf, data, true_len);
417 silc_buffer_pull(&buf, data_len);
418 silc_buffer_format(&buf,
419 SILC_STR_UI_XNSTRING(mac, mac_len),
420 SILC_STR_UI_XNSTRING(iv, iv_len),
423 /* Encrypt payload of the packet. This is encrypted with the channel key. */
424 silc_cipher_encrypt(cipher, data, data, true_len - iv_len, iv);
426 memset(mac, 0, sizeof(mac));
430 /* Encodes channel message payload into a buffer and returns it. This is used
431 to add channel message payload into a packet. As the channel payload is
432 encrypted separately from other parts of the packet padding must
433 be applied to the payload. */
435 SilcBuffer silc_channel_message_payload_encode(SilcUInt16 flags,
437 const unsigned char *data,
446 SilcUInt32 len, pad_len, mac_len;
447 unsigned char pad[16];
449 SILC_LOG_DEBUG(("Encoding channel message payload"));
451 /* Calculate length of padding. IV is not included into the calculation
452 since it is not encrypted. */
453 mac_len = silc_hmac_len(hmac);
454 data_len = SILC_CHANNEL_MESSAGE_DATALEN(data_len, mac_len + iv_len);
455 len = 6 + data_len + mac_len;
456 pad_len = SILC_CHANNEL_MESSAGE_PAD(len);
458 /* Allocate channel payload buffer */
459 len += pad_len + iv_len;
460 buffer = silc_buffer_alloc(len);
464 /* Generate padding */
466 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
468 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
471 /* Encode the Channel Message Payload */
472 silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
473 silc_buffer_format(buffer,
474 SILC_STR_UI_SHORT(flags),
475 SILC_STR_UI_SHORT(data_len),
476 SILC_STR_UI_XNSTRING(data, data_len),
477 SILC_STR_UI_SHORT(pad_len),
478 SILC_STR_UI_XNSTRING(pad, pad_len),
481 memset(pad, 0, sizeof(pad));
483 if (!silc_channel_message_payload_encrypt(buffer->data, buffer->len,
484 buffer->truelen, iv, iv_len,
486 silc_buffer_free(buffer);
490 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer) - buffer->len);
495 /* Free's Channel Message Payload */
497 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
500 memset(payload->data, 0, payload->data_len);
501 silc_free(payload->data);
509 silc_channel_message_get_flags(SilcChannelMessagePayload payload)
511 return payload->flags;
516 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
517 SilcUInt32 *data_len)
520 *data_len = payload->data_len;
522 return payload->data;
525 /* Return MAC. The caller knows the length of the MAC */
527 unsigned char *silc_channel_message_get_mac(SilcChannelMessagePayload payload)
532 /* Return IV. The caller knows the length of the IV */
534 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
539 /******************************************************************************
543 ******************************************************************************/
545 /* Channel Key Payload structrue. Channel keys are parsed from SILC
546 packets into this structure. */
547 struct SilcChannelKeyPayloadStruct {
550 SilcUInt16 cipher_len;
551 unsigned char *cipher;
556 /* Parses channel key payload returning new channel key payload structure */
558 SilcChannelKeyPayload
559 silc_channel_key_payload_parse(const unsigned char *payload,
560 SilcUInt32 payload_len)
562 SilcBufferStruct buffer;
563 SilcChannelKeyPayload newp;
566 SILC_LOG_DEBUG(("Parsing channel key payload"));
568 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
569 newp = silc_calloc(1, sizeof(*newp));
573 /* Parse the Channel Key Payload */
575 silc_buffer_unformat(&buffer,
576 SILC_STR_UI16_NSTRING_ALLOC(&newp->id, &newp->id_len),
577 SILC_STR_UI16_NSTRING_ALLOC(&newp->cipher,
579 SILC_STR_UI16_NSTRING_ALLOC(&newp->key,
585 if (newp->id_len < 1 || newp->key_len < 1 || newp->cipher_len < 1) {
586 SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
596 silc_free(newp->cipher);
598 silc_free(newp->key);
603 /* Encodes channel key payload into a buffer and returns it. This is used
604 to add channel key payload into a packet. */
606 SilcBuffer silc_channel_key_payload_encode(SilcUInt16 id_len,
607 const unsigned char *id,
608 SilcUInt16 cipher_len,
609 const unsigned char *cipher,
611 const unsigned char *key)
616 SILC_LOG_DEBUG(("Encoding channel key payload"));
618 /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
620 len = 2 + id_len + 2 + key_len + 2 + cipher_len;
621 buffer = silc_buffer_alloc_size(len);
625 /* Encode the Channel Payload */
626 silc_buffer_format(buffer,
627 SILC_STR_UI_SHORT(id_len),
628 SILC_STR_UI_XNSTRING(id, id_len),
629 SILC_STR_UI_SHORT(cipher_len),
630 SILC_STR_UI_XNSTRING(cipher, cipher_len),
631 SILC_STR_UI_SHORT(key_len),
632 SILC_STR_UI_XNSTRING(key, key_len),
638 /* Frees Channel Key Payload */
640 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
643 silc_free(payload->id);
644 silc_free(payload->cipher);
646 memset(payload->key, 0, payload->key_len);
647 silc_free(payload->key);
655 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
659 *id_len = payload->id_len;
664 /* Return cipher name */
666 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
667 SilcUInt32 *cipher_len)
670 *cipher_len = payload->cipher_len;
672 return payload->cipher;
677 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
681 *key_len = payload->key_len;