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_make(hmac, dst, (data_len - iv_len - mac_len), mac2, &mac_len);
303 if (memcmp(mac, mac2, mac_len)) {
304 SILC_LOG_DEBUG(("Channel message MACs does not match"));
308 SILC_LOG_DEBUG(("MAC is Ok"));
310 /* Now copy the decrypted data into the buffer since it is verified
311 it decrypted correctly. */
312 memcpy(data, dst, data_len - iv_len);
313 memset(dst, 0, data_len - iv_len);
320 /* Parses channel message payload returning new channel payload structure.
321 This also decrypts it and checks the MAC. */
323 SilcChannelMessagePayload
324 silc_channel_message_payload_parse(unsigned char *payload,
325 SilcUInt32 payload_len,
329 SilcBufferStruct buffer;
330 SilcChannelMessagePayload newp;
332 SilcUInt32 iv_len, mac_len;
334 SILC_LOG_DEBUG(("Parsing channel message payload"));
336 silc_buffer_set(&buffer, payload, payload_len);
338 /* Decrypt the payload */
339 ret = silc_channel_message_payload_decrypt(buffer.data, buffer.len,
344 iv_len = silc_cipher_get_block_len(cipher);
345 mac_len = silc_hmac_len(hmac);
347 newp = silc_calloc(1, sizeof(*newp));
351 /* Parse the Channel Message Payload. */
352 ret = silc_buffer_unformat(&buffer,
353 SILC_STR_UI_SHORT(&newp->flags),
354 SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
356 SILC_STR_UI16_NSTRING_ALLOC(&newp->pad,
358 SILC_STR_UI_XNSTRING(&newp->mac, mac_len),
359 SILC_STR_UI_XNSTRING(&newp->iv, iv_len),
364 if (newp->data_len > buffer.len) {
365 SILC_LOG_ERROR(("Incorrect channel message payload in packet, "
373 silc_channel_message_payload_free(newp);
377 /* This function is used to encrypt the Channel Messsage Payload which is
378 the `data' and `data_len'. This is used internally by the Channel Message
379 Payload encoding routines but application may call this too if needed.
380 The `data_len' is the data lenght which is used to create MAC out of.
381 The `true_len' is the true length of `data' message payload and is used
382 assemble rest of the packet after MAC creation. The `true_len' length
383 packet will then be encrypted. */
385 bool silc_channel_message_payload_encrypt(unsigned char *data,
393 unsigned char mac[32];
395 SilcBufferStruct buf;
397 /* Compute the MAC of the channel message data */
398 silc_hmac_make(hmac, data, data_len, mac, &mac_len);
400 /* Put rest of the data to the payload */
401 silc_buffer_set(&buf, data, true_len);
402 silc_buffer_pull(&buf, data_len);
403 silc_buffer_format(&buf,
404 SILC_STR_UI_XNSTRING(mac, mac_len),
405 SILC_STR_UI_XNSTRING(iv, iv_len),
408 /* Encrypt payload of the packet. This is encrypted with the channel key. */
409 silc_cipher_encrypt(cipher, data, data, true_len - iv_len, iv);
411 memset(mac, 0, sizeof(mac));
415 /* Encodes channel message payload into a buffer and returns it. This is used
416 to add channel message payload into a packet. As the channel payload is
417 encrypted separately from other parts of the packet padding must
418 be applied to the payload. */
420 SilcBuffer silc_channel_message_payload_encode(SilcUInt16 flags,
422 const unsigned char *data,
431 SilcUInt32 len, pad_len, mac_len;
432 unsigned char pad[16];
434 SILC_LOG_DEBUG(("Encoding channel message payload"));
436 /* Calculate length of padding. IV is not included into the calculation
437 since it is not encrypted. */
438 mac_len = silc_hmac_len(hmac);
439 data_len = SILC_CHANNEL_MESSAGE_DATALEN(data_len, mac_len + iv_len);
440 len = 6 + data_len + mac_len;
441 pad_len = SILC_CHANNEL_MESSAGE_PAD(len);
443 /* Allocate channel payload buffer */
444 len += pad_len + iv_len;
445 buffer = silc_buffer_alloc(len);
449 /* Generate padding */
451 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
453 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
456 /* Encode the Channel Message Payload */
457 silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
458 silc_buffer_format(buffer,
459 SILC_STR_UI_SHORT(flags),
460 SILC_STR_UI_SHORT(data_len),
461 SILC_STR_UI_XNSTRING(data, data_len),
462 SILC_STR_UI_SHORT(pad_len),
463 SILC_STR_UI_XNSTRING(pad, pad_len),
466 memset(pad, 0, sizeof(pad));
468 if (!silc_channel_message_payload_encrypt(buffer->data, buffer->len,
469 buffer->truelen, iv, iv_len,
471 silc_buffer_free(buffer);
475 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer) - buffer->len);
480 /* Free's Channel Message Payload */
482 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
485 memset(payload->data, 0, payload->data_len);
486 silc_free(payload->data);
494 silc_channel_message_get_flags(SilcChannelMessagePayload payload)
496 return payload->flags;
501 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
502 SilcUInt32 *data_len)
505 *data_len = payload->data_len;
507 return payload->data;
510 /* Return MAC. The caller knows the length of the MAC */
512 unsigned char *silc_channel_message_get_mac(SilcChannelMessagePayload payload)
517 /* Return IV. The caller knows the length of the IV */
519 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
524 /******************************************************************************
528 ******************************************************************************/
530 /* Channel Key Payload structrue. Channel keys are parsed from SILC
531 packets into this structure. */
532 struct SilcChannelKeyPayloadStruct {
535 SilcUInt16 cipher_len;
536 unsigned char *cipher;
541 /* Parses channel key payload returning new channel key payload structure */
543 SilcChannelKeyPayload
544 silc_channel_key_payload_parse(const unsigned char *payload,
545 SilcUInt32 payload_len)
547 SilcBufferStruct buffer;
548 SilcChannelKeyPayload newp;
551 SILC_LOG_DEBUG(("Parsing channel key payload"));
553 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
554 newp = silc_calloc(1, sizeof(*newp));
558 /* Parse the Channel Key Payload */
560 silc_buffer_unformat(&buffer,
561 SILC_STR_UI16_NSTRING_ALLOC(&newp->id, &newp->id_len),
562 SILC_STR_UI16_NSTRING_ALLOC(&newp->cipher,
564 SILC_STR_UI16_NSTRING_ALLOC(&newp->key,
570 if (newp->id_len < 1 || newp->key_len < 1 || newp->cipher_len < 1) {
571 SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
581 silc_free(newp->cipher);
583 silc_free(newp->key);
588 /* Encodes channel key payload into a buffer and returns it. This is used
589 to add channel key payload into a packet. */
591 SilcBuffer silc_channel_key_payload_encode(SilcUInt16 id_len,
592 const unsigned char *id,
593 SilcUInt16 cipher_len,
594 const unsigned char *cipher,
596 const unsigned char *key)
601 SILC_LOG_DEBUG(("Encoding channel key payload"));
603 /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
605 len = 2 + id_len + 2 + key_len + 2 + cipher_len;
606 buffer = silc_buffer_alloc_size(len);
610 /* Encode the Channel Payload */
611 silc_buffer_format(buffer,
612 SILC_STR_UI_SHORT(id_len),
613 SILC_STR_UI_XNSTRING(id, id_len),
614 SILC_STR_UI_SHORT(cipher_len),
615 SILC_STR_UI_XNSTRING(cipher, cipher_len),
616 SILC_STR_UI_SHORT(key_len),
617 SILC_STR_UI_XNSTRING(key, key_len),
623 /* Frees Channel Key Payload */
625 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
628 silc_free(payload->id);
629 silc_free(payload->cipher);
631 memset(payload->key, 0, payload->key_len);
632 silc_free(payload->key);
640 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
644 *id_len = payload->id_len;
649 /* Return cipher name */
651 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
652 SilcUInt32 *cipher_len)
655 *cipher_len = payload->cipher_len;
657 return payload->cipher;
662 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
666 *key_len = payload->key_len;