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;
257 /* Decrypts the channel message payload. First push the IV out of the
258 packet. The IV is used in the decryption process. Then decrypt the
259 message. After decyprtion, take the MAC from the decrypted packet,
260 compute MAC and compare the MACs. If they match, the decryption was
261 successful and we have the channel message ready to be displayed. */
263 bool silc_channel_message_payload_decrypt(unsigned char *data,
268 SilcUInt32 iv_len, mac_len;
269 unsigned char *end, *mac, mac2[32];
270 unsigned char *dst, iv[SILC_CIPHER_MAX_IV_SIZE];
272 /* Push the IV out of the packet, and copy the IV since we do not want
273 to modify the original data buffer. */
274 end = data + data_len;
275 iv_len = silc_cipher_get_block_len(cipher);
276 memcpy(iv, end - iv_len, iv_len);
278 /* Allocate destination decryption buffer since we do not want to modify
279 the original data buffer, since we might want to call this function
280 many times for same payload. */
282 dst = silc_calloc(data_len - iv_len, sizeof(*dst));
289 /* Decrypt the channel message */
290 silc_cipher_decrypt(cipher, data, dst, data_len - iv_len, iv);
294 end = dst + (data_len - iv_len);
295 mac_len = silc_hmac_len(hmac);
296 mac = (end - mac_len);
298 /* Check the MAC of the message */
299 SILC_LOG_DEBUG(("Checking channel message MACs"));
300 silc_hmac_make(hmac, dst, (data_len - iv_len - mac_len), mac2, &mac_len);
301 if (memcmp(mac, mac2, mac_len)) {
302 SILC_LOG_DEBUG(("Channel message MACs does not match"));
306 SILC_LOG_DEBUG(("MAC is Ok"));
308 /* Now copy the decrypted data into the buffer since it is verified
309 it decrypted correctly. */
310 memcpy(data, dst, data_len - iv_len);
311 memset(dst, 0, data_len - iv_len);
318 /* Parses channel message payload returning new channel payload structure.
319 This also decrypts it and checks the MAC. */
321 SilcChannelMessagePayload
322 silc_channel_message_payload_parse(unsigned char *payload,
323 SilcUInt32 payload_len,
327 SilcBufferStruct buffer;
328 SilcChannelMessagePayload newp;
330 SilcUInt32 iv_len, mac_len;
332 SILC_LOG_DEBUG(("Parsing channel message payload"));
334 silc_buffer_set(&buffer, payload, payload_len);
336 /* Decrypt the payload */
337 ret = silc_channel_message_payload_decrypt(buffer.data, buffer.len,
342 iv_len = silc_cipher_get_block_len(cipher);
343 mac_len = silc_hmac_len(hmac);
345 newp = silc_calloc(1, sizeof(*newp));
349 /* Parse the Channel Message Payload. Ignore the padding. */
350 ret = silc_buffer_unformat(&buffer,
351 SILC_STR_UI_SHORT(&newp->flags),
352 SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
354 SILC_STR_UI16_NSTRING(NULL, NULL),
355 SILC_STR_UI_XNSTRING(&newp->mac, mac_len),
356 SILC_STR_UI_XNSTRING(&newp->iv, iv_len),
361 if (newp->data_len > buffer.len) {
362 SILC_LOG_ERROR(("Incorrect channel message payload in packet, "
370 silc_channel_message_payload_free(newp);
374 /* Encodes channel message payload into a buffer and returns it. This is used
375 to add channel message payload into a packet. As the channel payload is
376 encrypted separately from other parts of the packet padding must
377 be applied to the payload. */
379 SilcBuffer silc_channel_message_payload_encode(SilcUInt16 flags,
381 const unsigned char *data,
390 SilcUInt32 len, pad_len, mac_len;
391 unsigned char pad[16];
392 unsigned char mac[32];
394 SILC_LOG_DEBUG(("Encoding channel message payload"));
396 /* Calculate length of padding. IV is not included into the calculation
397 since it is not encrypted. */
398 mac_len = silc_hmac_len(hmac);
399 data_len = SILC_CHANNEL_MESSAGE_DATALEN(data_len, mac_len + iv_len);
400 len = 6 + data_len + mac_len;
401 pad_len = SILC_CHANNEL_MESSAGE_PAD(len);
403 /* Allocate channel payload buffer */
404 len += pad_len + iv_len;
405 buffer = silc_buffer_alloc(len);
409 /* Generate padding */
411 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte(rng);
413 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte();
416 /* Encode the Channel Message Payload */
417 silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
418 silc_buffer_format(buffer,
419 SILC_STR_UI_SHORT(flags),
420 SILC_STR_UI_SHORT(data_len),
421 SILC_STR_UI_XNSTRING(data, data_len),
422 SILC_STR_UI_SHORT(pad_len),
423 SILC_STR_UI_XNSTRING(pad, pad_len),
426 /* Compute the MAC of the channel message data */
427 silc_hmac_make(hmac, buffer->data, buffer->len, mac, &mac_len);
429 /* Put rest of the data to the payload */
430 silc_buffer_pull_tail(buffer, mac_len + iv_len);
431 silc_buffer_pull(buffer, 6 + data_len + pad_len);
432 silc_buffer_format(buffer,
433 SILC_STR_UI_XNSTRING(mac, mac_len),
434 SILC_STR_UI_XNSTRING(iv, iv_len),
436 silc_buffer_push(buffer, 6 + data_len + pad_len);
438 /* Encrypt payload of the packet. This is encrypted with the channel key. */
439 silc_cipher_encrypt(cipher, buffer->data, buffer->data,
440 buffer->len - iv_len, iv);
442 memset(pad, 0, sizeof(pad));
443 memset(mac, 0, sizeof(mac));
448 /* Free's Channel Message Payload */
450 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
453 memset(payload->data, 0, payload->data_len);
454 silc_free(payload->data);
462 silc_channel_message_get_flags(SilcChannelMessagePayload payload)
464 return payload->flags;
469 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
470 SilcUInt32 *data_len)
473 *data_len = payload->data_len;
475 return payload->data;
478 /* Return MAC. The caller knows the length of the MAC */
480 unsigned char *silc_channel_message_get_mac(SilcChannelMessagePayload payload)
485 /* Return IV. The caller knows the length of the IV */
487 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
492 /******************************************************************************
496 ******************************************************************************/
498 /* Channel Key Payload structrue. Channel keys are parsed from SILC
499 packets into this structure. */
500 struct SilcChannelKeyPayloadStruct {
503 SilcUInt16 cipher_len;
504 unsigned char *cipher;
509 /* Parses channel key payload returning new channel key payload structure */
511 SilcChannelKeyPayload
512 silc_channel_key_payload_parse(const unsigned char *payload,
513 SilcUInt32 payload_len)
515 SilcBufferStruct buffer;
516 SilcChannelKeyPayload newp;
519 SILC_LOG_DEBUG(("Parsing channel key payload"));
521 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
522 newp = silc_calloc(1, sizeof(*newp));
526 /* Parse the Channel Key Payload */
528 silc_buffer_unformat(&buffer,
529 SILC_STR_UI16_NSTRING_ALLOC(&newp->id, &newp->id_len),
530 SILC_STR_UI16_NSTRING_ALLOC(&newp->cipher,
532 SILC_STR_UI16_NSTRING_ALLOC(&newp->key,
538 if (newp->id_len < 1 || newp->key_len < 1 || newp->cipher_len < 1) {
539 SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
549 silc_free(newp->cipher);
551 silc_free(newp->key);
556 /* Encodes channel key payload into a buffer and returns it. This is used
557 to add channel key payload into a packet. */
559 SilcBuffer silc_channel_key_payload_encode(SilcUInt16 id_len,
560 const unsigned char *id,
561 SilcUInt16 cipher_len,
562 const unsigned char *cipher,
564 const unsigned char *key)
569 SILC_LOG_DEBUG(("Encoding channel key payload"));
571 /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
573 len = 2 + id_len + 2 + key_len + 2 + cipher_len;
574 buffer = silc_buffer_alloc_size(len);
578 /* Encode the Channel Payload */
579 silc_buffer_format(buffer,
580 SILC_STR_UI_SHORT(id_len),
581 SILC_STR_UI_XNSTRING(id, id_len),
582 SILC_STR_UI_SHORT(cipher_len),
583 SILC_STR_UI_XNSTRING(cipher, cipher_len),
584 SILC_STR_UI_SHORT(key_len),
585 SILC_STR_UI_XNSTRING(key, key_len),
591 /* Frees Channel Key Payload */
593 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
596 silc_free(payload->id);
597 silc_free(payload->cipher);
599 memset(payload->key, 0, payload->key_len);
600 silc_free(payload->key);
608 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
612 *id_len = payload->id_len;
617 /* Return cipher name */
619 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
620 SilcUInt32 *cipher_len)
623 *cipher_len = payload->cipher_len;
625 return payload->cipher;
630 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
634 *key_len = payload->key_len;