5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 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 {
36 unsigned short name_len;
37 unsigned char *channel_name;
38 unsigned short id_len;
39 unsigned char *channel_id;
43 /* Parses channel payload returning new channel payload structure. */
45 SilcChannelPayload silc_channel_payload_parse(SilcBuffer buffer)
47 SilcChannelPayload new;
50 SILC_LOG_DEBUG(("Parsing channel payload"));
52 new = silc_calloc(1, sizeof(*new));
54 /* Parse the Channel Payload. Ignore the padding. */
55 ret = silc_buffer_unformat(buffer,
56 SILC_STR_UI16_NSTRING_ALLOC(&new->channel_name,
58 SILC_STR_UI16_NSTRING_ALLOC(&new->channel_id,
60 SILC_STR_UI_INT(&new->mode),
65 if ((new->name_len < 1 || new->name_len > buffer->len) ||
66 (new->id_len < 1 || new->id_len > buffer->len)) {
67 SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
74 silc_channel_payload_free(new);
78 /* Parses list of channel payloads returning list of payloads. */
80 SilcDList silc_channel_payload_parse_list(SilcBuffer buffer)
83 SilcChannelPayload new;
86 SILC_LOG_DEBUG(("Parsing channel payload list"));
88 list = silc_dlist_init();
91 new = silc_calloc(1, sizeof(*new));
92 ret = silc_buffer_unformat(buffer,
93 SILC_STR_UI16_NSTRING_ALLOC(&new->channel_name,
95 SILC_STR_UI16_NSTRING_ALLOC(&new->channel_id,
97 SILC_STR_UI_INT(&new->mode),
102 if ((new->name_len < 1 || new->name_len > buffer->len) ||
103 (new->id_len < 1 || new->id_len > buffer->len)) {
104 SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
108 len = 2 + new->name_len + 2 + new->id_len + 4;
109 if (buffer->len < len)
111 silc_buffer_pull(buffer, len);
113 silc_dlist_add(list, new);
119 silc_channel_payload_list_free(list);
123 /* Encode new channel payload and returns it as buffer. */
125 SilcBuffer silc_channel_payload_encode(unsigned char *channel_name,
126 unsigned short channel_name_len,
127 unsigned char *channel_id,
128 unsigned int channel_id_len,
133 SILC_LOG_DEBUG(("Encoding message payload"));
135 buffer = silc_buffer_alloc(2 + channel_name_len + 2 + channel_id_len + 4);
136 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
138 /* Encode the Channel Payload */
139 silc_buffer_format(buffer,
140 SILC_STR_UI_SHORT(channel_name_len),
141 SILC_STR_UI_XNSTRING(channel_name, channel_name_len),
142 SILC_STR_UI_SHORT(channel_id_len),
143 SILC_STR_UI_XNSTRING(channel_id, channel_id_len),
144 SILC_STR_UI_INT(mode),
150 /* Free's Channel Payload */
152 void silc_channel_payload_free(SilcChannelPayload payload)
154 silc_free(payload->channel_name);
155 silc_free(payload->channel_id);
159 /* Free's list of Channel Payloads */
161 void silc_channel_payload_list_free(SilcDList list)
163 SilcChannelPayload entry;
165 silc_dlist_start(list);
166 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
167 silc_free(entry->channel_name);
168 silc_free(entry->channel_id);
170 silc_dlist_del(list, entry);
173 silc_dlist_uninit(list);
176 /* Return the channel name */
178 unsigned char *silc_channel_get_name(SilcChannelPayload payload,
179 unsigned int *channel_name_len)
181 if (channel_name_len)
182 *channel_name_len = payload->name_len;
184 return payload->channel_name;
187 /* Return the channel ID */
189 unsigned char *silc_channel_get_id(SilcChannelPayload payload,
190 unsigned int *channel_id_len)
193 *channel_id_len = payload->id_len;
195 return payload->channel_id;
198 /* Return the channel ID as parsed ID. */
200 SilcChannelID *silc_channel_get_id_parse(SilcChannelPayload payload)
202 return silc_id_str2id(payload->channel_id, payload->id_len,
206 /* Return the mode. The mode is arbitrary. It can be the mode of the
207 channel or perhaps the mode of the client on the channel. The protocol
208 dictates what the usage of the mode is in different circumstances. */
210 unsigned int silc_channel_get_mode(SilcChannelPayload payload)
212 return payload->mode;
215 /******************************************************************************
217 Channel Message Payload
219 ******************************************************************************/
221 /* Channel Message Payload structure. Contents of this structure is parsed
222 from SILC packets. */
223 struct SilcChannelMessagePayloadStruct {
224 unsigned short data_len;
230 /* Decrypts the channel message payload. */
232 int silc_channel_message_payload_decrypt(unsigned char *data,
237 unsigned int iv_len, mac_len;
238 unsigned char *end, *mac, mac2[32];
240 /* Decrypt the channel message. First push the IV out of the packet.
241 The IV is used in the decryption process. Then decrypt the message.
242 After decyprtion, take the MAC from the decrypted packet, compute MAC
243 and compare the MACs. If they match, the decryption was successfull
244 and we have the channel message ready to be displayed. */
245 end = data + data_len;
247 /* Push the IV out of the packet */
248 iv_len = silc_cipher_get_block_len(cipher);
250 /* Decrypt the channel message */
251 silc_cipher_decrypt(cipher, data, data, data_len - iv_len, (end - iv_len));
255 mac_len = silc_hmac_len(hmac);
256 mac = (end - iv_len - mac_len);
258 /* Check the MAC of the message */
259 SILC_LOG_DEBUG(("Checking channel message MACs"));
260 silc_hmac_make(hmac, data, (data_len - iv_len - mac_len), mac2, &mac_len);
261 if (memcmp(mac, mac2, mac_len)) {
262 SILC_LOG_DEBUG(("Channel message MACs does not match"));
265 SILC_LOG_DEBUG(("MAC is Ok"));
271 /* Parses channel message payload returning new channel payload structure.
272 This also decrypts it and checks the MAC. */
274 SilcChannelMessagePayload
275 silc_channel_message_payload_parse(SilcBuffer buffer,
279 SilcChannelMessagePayload new;
281 unsigned int iv_len, mac_len;
283 SILC_LOG_DEBUG(("Parsing channel message payload"));
285 /* Decrypt the payload */
286 ret = silc_channel_message_payload_decrypt(buffer->data, buffer->len,
291 iv_len = silc_cipher_get_block_len(cipher);
292 mac_len = silc_hmac_len(hmac);
294 new = silc_calloc(1, sizeof(*new));
296 /* Parse the Channel Message Payload. Ignore the padding. */
297 ret = silc_buffer_unformat(buffer,
298 SILC_STR_UI16_NSTRING_ALLOC(&new->data,
300 SILC_STR_UI16_NSTRING(NULL, NULL),
301 SILC_STR_UI_XNSTRING(&new->mac, mac_len),
302 SILC_STR_UI_XNSTRING(&new->iv, iv_len),
307 if (new->data_len < 1 || new->data_len > buffer->len) {
308 SILC_LOG_ERROR(("Incorrect channel messaeg payload in packet, "
316 silc_channel_message_payload_free(new);
320 /* Encodes channel message payload into a buffer and returns it. This is used
321 to add channel message payload into a packet. As the channel payload is
322 encrypted separately from other parts of the packet padding must
323 be applied to the payload. */
325 SilcBuffer silc_channel_message_payload_encode(unsigned short data_len,
327 unsigned short iv_len,
335 unsigned int len, pad_len, mac_len;
336 unsigned char pad[SILC_PACKET_MAX_PADLEN];
337 unsigned char mac[32];
339 SILC_LOG_DEBUG(("Encoding channel message payload"));
341 /* Calculate length of padding. IV is not included into the calculation
342 since it is not encrypted. */
343 mac_len = silc_hmac_len(hmac);
344 len = 4 + data_len + mac_len;
345 pad_len = SILC_PACKET_PADLEN((len + 2));
347 /* Allocate channel payload buffer */
348 len += pad_len + iv_len;
349 buffer = silc_buffer_alloc(len);
351 /* Generate padding */
352 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte(rng);
354 /* Encode the Channel Message Payload */
355 silc_buffer_pull_tail(buffer, 4 + data_len + pad_len);
356 silc_buffer_format(buffer,
357 SILC_STR_UI_SHORT(data_len),
358 SILC_STR_UI_XNSTRING(data, data_len),
359 SILC_STR_UI_SHORT(pad_len),
360 SILC_STR_UI_XNSTRING(pad, pad_len),
363 /* Compute the MAC of the channel message data */
364 silc_hmac_make(hmac, buffer->data, buffer->len, mac, &mac_len);
366 /* Put rest of the data to the payload */
367 silc_buffer_pull_tail(buffer, mac_len + iv_len);
368 silc_buffer_pull(buffer, 4 + data_len + pad_len);
369 silc_buffer_format(buffer,
370 SILC_STR_UI_XNSTRING(mac, mac_len),
371 SILC_STR_UI_XNSTRING(iv, iv_len),
373 silc_buffer_push(buffer, 4 + data_len + pad_len);
375 /* Encrypt payload of the packet. This is encrypted with the channel key. */
376 silc_cipher_encrypt(cipher, buffer->data, buffer->data,
377 buffer->len - iv_len, iv);
379 memset(pad, 0, sizeof(pad));
380 memset(mac, 0, sizeof(mac));
385 /* Free's Channel Message Payload */
387 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
390 memset(payload->data, 0, payload->data_len);
391 silc_free(payload->data);
398 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
399 unsigned int *data_len)
402 *data_len = payload->data_len;
404 return payload->data;
407 /* Return MAC. The caller knows the length of the MAC */
409 unsigned char *silc_channel_mesage_get_mac(SilcChannelMessagePayload payload)
414 /* Return IV. The caller knows the length of the IV */
416 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
421 /******************************************************************************
425 ******************************************************************************/
427 /* Channel Key Payload structrue. Channel keys are parsed from SILC
428 packets into this structure. */
429 struct SilcChannelKeyPayloadStruct {
430 unsigned short id_len;
432 unsigned short cipher_len;
433 unsigned char *cipher;
434 unsigned short key_len;
438 /* Parses channel key payload returning new channel key payload structure */
440 SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer)
442 SilcChannelKeyPayload new;
445 SILC_LOG_DEBUG(("Parsing channel key payload"));
447 new = silc_calloc(1, sizeof(*new));
449 /* Parse the Channel Key Payload */
451 silc_buffer_unformat(buffer,
452 SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len),
453 SILC_STR_UI16_NSTRING_ALLOC(&new->cipher,
455 SILC_STR_UI16_NSTRING_ALLOC(&new->key, &new->key_len),
460 if (new->id_len < 1 || new->key_len < 1 || new->cipher_len < 1) {
461 SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
471 silc_free(new->cipher);
478 /* Encodes channel key payload into a buffer and returns it. This is used
479 to add channel key payload into a packet. */
481 SilcBuffer silc_channel_key_payload_encode(unsigned short id_len,
483 unsigned short cipher_len,
484 unsigned char *cipher,
485 unsigned short key_len,
491 SILC_LOG_DEBUG(("Encoding channel key payload"));
493 /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
495 len = 2 + id_len + 2 + key_len + 2 + cipher_len;
496 buffer = silc_buffer_alloc(len);
498 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
500 /* Encode the Channel Payload */
501 silc_buffer_format(buffer,
502 SILC_STR_UI_SHORT(id_len),
503 SILC_STR_UI_XNSTRING(id, id_len),
504 SILC_STR_UI_SHORT(cipher_len),
505 SILC_STR_UI_XNSTRING(cipher, cipher_len),
506 SILC_STR_UI_SHORT(key_len),
507 SILC_STR_UI_XNSTRING(key, key_len),
513 /* Free's Channel Key Payload */
515 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
519 silc_free(payload->id);
521 silc_free(payload->cipher);
523 memset(payload->key, 0, payload->key_len);
524 silc_free(payload->key);
532 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
533 unsigned int *id_len)
536 *id_len = payload->id_len;
541 /* Return cipher name */
543 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
544 unsigned int *cipher_len)
547 *cipher_len = payload->cipher_len;
549 return payload->cipher;
554 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
555 unsigned int *key_len)
558 *key_len = payload->key_len;