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 - 8) ||
71 (newp->id_len < 1 || newp->id_len > buffer.len - 8) ||
72 (newp->id_len + newp->name_len > buffer.len - 8)) {
73 SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
80 silc_channel_payload_free(newp);
84 /* Parses list of channel payloads returning list of payloads. */
86 SilcDList silc_channel_payload_parse_list(const unsigned char *payload,
87 SilcUInt32 payload_len)
89 SilcBufferStruct buffer;
91 SilcChannelPayload newp;
94 SILC_LOG_DEBUG(("Parsing channel payload list"));
96 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
97 list = silc_dlist_init();
100 newp = silc_calloc(1, sizeof(*newp));
103 ret = silc_buffer_unformat(&buffer,
104 SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_name,
106 SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_id,
108 SILC_STR_UI_INT(&newp->mode),
113 if ((newp->name_len < 1 || newp->name_len > buffer.len) ||
114 (newp->id_len < 1 || newp->id_len > buffer.len)) {
115 SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
119 len = 2 + newp->name_len + 2 + newp->id_len + 4;
120 if (buffer.len < len)
122 silc_buffer_pull(&buffer, len);
124 silc_dlist_add(list, newp);
130 silc_channel_payload_list_free(list);
134 /* Encode new channel payload and returns it as buffer. */
136 SilcBuffer silc_channel_payload_encode(const unsigned char *channel_name,
137 SilcUInt16 channel_name_len,
138 const unsigned char *channel_id,
139 SilcUInt32 channel_id_len,
144 SILC_LOG_DEBUG(("Encoding message payload"));
146 buffer = silc_buffer_alloc_size(2 + channel_name_len + 2 +
151 /* Encode the Channel Payload */
152 silc_buffer_format(buffer,
153 SILC_STR_UI_SHORT(channel_name_len),
154 SILC_STR_UI_XNSTRING(channel_name, channel_name_len),
155 SILC_STR_UI_SHORT(channel_id_len),
156 SILC_STR_UI_XNSTRING(channel_id, channel_id_len),
157 SILC_STR_UI_INT(mode),
163 /* Frees Channel Payload */
165 void silc_channel_payload_free(SilcChannelPayload payload)
167 silc_free(payload->channel_name);
168 silc_free(payload->channel_id);
172 /* Free's list of Channel Payloads */
174 void silc_channel_payload_list_free(SilcDList list)
176 SilcChannelPayload entry;
178 silc_dlist_start(list);
179 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
180 silc_free(entry->channel_name);
181 silc_free(entry->channel_id);
182 silc_dlist_del(list, entry);
186 silc_dlist_uninit(list);
189 /* Return the channel name */
191 unsigned char *silc_channel_get_name(SilcChannelPayload payload,
192 SilcUInt32 *channel_name_len)
194 if (channel_name_len)
195 *channel_name_len = payload->name_len;
197 return payload->channel_name;
200 /* Return the channel ID */
202 unsigned char *silc_channel_get_id(SilcChannelPayload payload,
203 SilcUInt32 *channel_id_len)
206 *channel_id_len = payload->id_len;
208 return payload->channel_id;
211 /* Return the channel ID as parsed ID. */
213 SilcChannelID *silc_channel_get_id_parse(SilcChannelPayload payload)
215 return silc_id_str2id(payload->channel_id, payload->id_len,
219 /* Return the mode. The mode is arbitrary. It can be the mode of the
220 channel or perhaps the mode of the client on the channel. The protocol
221 dictates what the usage of the mode is in different circumstances. */
223 SilcUInt32 silc_channel_get_mode(SilcChannelPayload payload)
225 return payload->mode;
228 /******************************************************************************
230 Channel Message Payload
232 ******************************************************************************/
234 /* Calculates padding length for message payload */
235 #define SILC_CHANNEL_MESSAGE_PAD(__payloadlen) (16 - ((__payloadlen) % 16))
237 /* Header length plus maximum padding length */
238 #define SILC_CHANNEL_MESSAGE_HLEN 6 + 16
240 /* Returns the data length that fits to the packet. If data length is too
241 big it will be truncated to fit to the payload. */
242 #define SILC_CHANNEL_MESSAGE_DATALEN(data_len, header_len) \
243 ((data_len + SILC_CHANNEL_MESSAGE_HLEN + header_len) > \
244 SILC_PACKET_MAX_LEN ? \
245 data_len - ((data_len + SILC_CHANNEL_MESSAGE_HLEN + header_len) - \
246 SILC_PACKET_MAX_LEN) : data_len)
248 /* Channel Message Payload structure. Contents of this structure is parsed
249 from SILC packets. */
250 struct SilcChannelMessagePayloadStruct {
251 SilcMessageFlags flags;
260 /* Decrypts the channel message payload. First push the IV out of the
261 packet. The IV is used in the decryption process. Then decrypt the
262 message. After decyprtion, take the MAC from the decrypted packet,
263 compute MAC and compare the MACs. If they match, the decryption was
264 successful and we have the channel message ready to be displayed. */
266 bool silc_channel_message_payload_decrypt(unsigned char *data,
271 SilcUInt32 iv_len, mac_len;
272 unsigned char *end, *mac, mac2[32];
273 unsigned char *dst, iv[SILC_CIPHER_MAX_IV_SIZE];
275 /* Push the IV out of the packet, and copy the IV since we do not want
276 to modify the original data buffer. */
277 end = data + data_len;
278 iv_len = silc_cipher_get_block_len(cipher);
279 memcpy(iv, end - iv_len, iv_len);
281 /* Allocate destination decryption buffer since we do not want to modify
282 the original data buffer, since we might want to call this function
283 many times for same payload. */
285 dst = silc_calloc(data_len - iv_len, sizeof(*dst));
292 /* Decrypt the channel message */
293 silc_cipher_decrypt(cipher, data, dst, data_len - iv_len, iv);
297 end = dst + (data_len - iv_len);
298 mac_len = silc_hmac_len(hmac);
299 mac = (end - mac_len);
301 /* Check the MAC of the message */
302 SILC_LOG_DEBUG(("Checking channel message MACs"));
303 silc_hmac_init(hmac);
304 silc_hmac_update(hmac, dst, (data_len - iv_len - mac_len));
305 silc_hmac_update(hmac, data + (data_len - iv_len), iv_len);
306 silc_hmac_final(hmac, mac2, &mac_len);
307 if (memcmp(mac, mac2, mac_len)) {
309 /* Backwards support for old mac checking, remove in 1.0 */
310 silc_hmac_make(hmac, dst, (data_len - iv_len - mac_len), mac2, &mac_len);
311 if (memcmp(mac, mac2, mac_len)) {
314 SILC_LOG_DEBUG(("Channel message MACs does not match"));
321 SILC_LOG_DEBUG(("MAC is Ok"));
323 /* Now copy the decrypted data into the buffer since it is verified
324 it decrypted correctly. */
325 memcpy(data, dst, data_len - iv_len);
326 memset(dst, 0, data_len - iv_len);
333 /* Parses channel message payload returning new channel payload structure.
334 This also decrypts it and checks the MAC. */
336 SilcChannelMessagePayload
337 silc_channel_message_payload_parse(unsigned char *payload,
338 SilcUInt32 payload_len,
342 SilcBufferStruct buffer;
343 SilcChannelMessagePayload newp;
345 SilcUInt32 iv_len, mac_len;
347 SILC_LOG_DEBUG(("Parsing channel message payload"));
349 silc_buffer_set(&buffer, payload, payload_len);
351 /* Decrypt the payload */
352 ret = silc_channel_message_payload_decrypt(buffer.data, buffer.len,
357 iv_len = silc_cipher_get_block_len(cipher);
358 mac_len = silc_hmac_len(hmac);
360 newp = silc_calloc(1, sizeof(*newp));
364 /* Parse the Channel Message Payload. */
365 ret = silc_buffer_unformat(&buffer,
366 SILC_STR_UI_SHORT(&newp->flags),
367 SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
369 SILC_STR_UI16_NSTRING_ALLOC(&newp->pad,
371 SILC_STR_UI_XNSTRING(&newp->mac, mac_len),
372 SILC_STR_UI_XNSTRING(&newp->iv, iv_len),
377 if ((newp->data_len > buffer.len - 6 - mac_len - iv_len) ||
378 (newp->pad_len + newp->data_len > buffer.len - 6 - mac_len - iv_len)) {
379 SILC_LOG_ERROR(("Incorrect channel message payload in packet, "
387 silc_channel_message_payload_free(newp);
391 /* This function is used to encrypt the Channel Messsage Payload which is
392 the `data' and `data_len'. This is used internally by the Channel Message
393 Payload encoding routines but application may call this too if needed.
394 The `data_len' is the data lenght which is used to create MAC out of.
395 The `true_len' is the true length of `data' message payload and is used
396 assemble rest of the packet after MAC creation. The `true_len' length
397 packet will then be encrypted. */
399 bool silc_channel_message_payload_encrypt(unsigned char *data,
407 unsigned char mac[32];
409 SilcBufferStruct buf;
411 /* Compute the MAC of the channel message data */
412 silc_hmac_init(hmac);
413 silc_hmac_update(hmac, data, data_len);
414 silc_hmac_update(hmac, iv, iv_len);
415 silc_hmac_final(hmac, mac, &mac_len);
417 /* Put rest of the data to the payload */
418 silc_buffer_set(&buf, data, true_len);
419 silc_buffer_pull(&buf, data_len);
420 silc_buffer_format(&buf,
421 SILC_STR_UI_XNSTRING(mac, mac_len),
422 SILC_STR_UI_XNSTRING(iv, iv_len),
425 /* Encrypt payload of the packet. This is encrypted with the channel key. */
426 silc_cipher_encrypt(cipher, data, data, true_len - iv_len, iv);
428 memset(mac, 0, sizeof(mac));
432 /* Encodes channel message payload into a buffer and returns it. This is used
433 to add channel message payload into a packet. As the channel payload is
434 encrypted separately from other parts of the packet padding must
435 be applied to the payload. */
437 SilcBuffer silc_channel_message_payload_encode(SilcUInt16 flags,
439 const unsigned char *data,
448 SilcUInt32 len, pad_len, mac_len;
449 unsigned char pad[16];
451 SILC_LOG_DEBUG(("Encoding channel message payload"));
453 /* Calculate length of padding. IV is not included into the calculation
454 since it is not encrypted. */
455 mac_len = silc_hmac_len(hmac);
456 data_len = SILC_CHANNEL_MESSAGE_DATALEN(data_len, mac_len + iv_len);
457 len = 6 + data_len + mac_len;
458 pad_len = SILC_CHANNEL_MESSAGE_PAD(len);
460 /* Allocate channel payload buffer */
461 len += pad_len + iv_len;
462 buffer = silc_buffer_alloc(len);
466 /* Generate padding */
468 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
470 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
473 /* Encode the Channel Message Payload */
474 silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
475 silc_buffer_format(buffer,
476 SILC_STR_UI_SHORT(flags),
477 SILC_STR_UI_SHORT(data_len),
478 SILC_STR_UI_XNSTRING(data, data_len),
479 SILC_STR_UI_SHORT(pad_len),
480 SILC_STR_UI_XNSTRING(pad, pad_len),
483 memset(pad, 0, sizeof(pad));
485 if (!silc_channel_message_payload_encrypt(buffer->data, buffer->len,
486 buffer->truelen, iv, iv_len,
488 silc_buffer_free(buffer);
492 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer) - buffer->len);
497 /* Free's Channel Message Payload */
499 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
502 memset(payload->data, 0, payload->data_len);
503 silc_free(payload->data);
511 silc_channel_message_get_flags(SilcChannelMessagePayload payload)
513 return payload->flags;
518 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
519 SilcUInt32 *data_len)
522 *data_len = payload->data_len;
524 return payload->data;
527 /* Return MAC. The caller knows the length of the MAC */
529 unsigned char *silc_channel_message_get_mac(SilcChannelMessagePayload payload)
534 /* Return IV. The caller knows the length of the IV */
536 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
541 /******************************************************************************
545 ******************************************************************************/
547 /* Channel Key Payload structrue. Channel keys are parsed from SILC
548 packets into this structure. */
549 struct SilcChannelKeyPayloadStruct {
552 SilcUInt16 cipher_len;
553 unsigned char *cipher;
558 /* Parses channel key payload returning new channel key payload structure */
560 SilcChannelKeyPayload
561 silc_channel_key_payload_parse(const unsigned char *payload,
562 SilcUInt32 payload_len)
564 SilcBufferStruct buffer;
565 SilcChannelKeyPayload newp;
568 SILC_LOG_DEBUG(("Parsing channel key payload"));
570 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
571 newp = silc_calloc(1, sizeof(*newp));
575 /* Parse the Channel Key Payload */
577 silc_buffer_unformat(&buffer,
578 SILC_STR_UI16_NSTRING_ALLOC(&newp->id, &newp->id_len),
579 SILC_STR_UI16_NSTRING_ALLOC(&newp->cipher,
581 SILC_STR_UI16_NSTRING_ALLOC(&newp->key,
587 if (newp->id_len < 1 || newp->key_len < 1 || newp->cipher_len < 1 ||
588 newp->id_len + newp->cipher_len + newp->key_len > buffer.len - 6) {
589 SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
599 silc_free(newp->cipher);
601 silc_free(newp->key);
606 /* Encodes channel key payload into a buffer and returns it. This is used
607 to add channel key payload into a packet. */
609 SilcBuffer silc_channel_key_payload_encode(SilcUInt16 id_len,
610 const unsigned char *id,
611 SilcUInt16 cipher_len,
612 const unsigned char *cipher,
614 const unsigned char *key)
619 SILC_LOG_DEBUG(("Encoding channel key payload"));
621 /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
623 len = 2 + id_len + 2 + key_len + 2 + cipher_len;
624 buffer = silc_buffer_alloc_size(len);
628 /* Encode the Channel Payload */
629 silc_buffer_format(buffer,
630 SILC_STR_UI_SHORT(id_len),
631 SILC_STR_UI_XNSTRING(id, id_len),
632 SILC_STR_UI_SHORT(cipher_len),
633 SILC_STR_UI_XNSTRING(cipher, cipher_len),
634 SILC_STR_UI_SHORT(key_len),
635 SILC_STR_UI_XNSTRING(key, key_len),
641 /* Frees Channel Key Payload */
643 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
646 silc_free(payload->id);
647 silc_free(payload->cipher);
649 memset(payload->key, 0, payload->key_len);
650 silc_free(payload->key);
658 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
662 *id_len = payload->id_len;
667 /* Return cipher name */
669 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
670 SilcUInt32 *cipher_len)
673 *cipher_len = payload->cipher_len;
675 return payload->cipher;
680 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
684 *key_len = payload->key_len;