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,
48 SilcBufferStruct buffer;
49 SilcChannelPayload new;
52 SILC_LOG_DEBUG(("Parsing channel payload"));
54 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
55 new = silc_calloc(1, sizeof(*new));
57 /* Parse the Channel Payload. Ignore the padding. */
58 ret = silc_buffer_unformat(&buffer,
59 SILC_STR_UI16_NSTRING_ALLOC(&new->channel_name,
61 SILC_STR_UI16_NSTRING_ALLOC(&new->channel_id,
63 SILC_STR_UI_INT(&new->mode),
68 if ((new->name_len < 1 || new->name_len > buffer.len) ||
69 (new->id_len < 1 || new->id_len > buffer.len)) {
70 SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
77 silc_channel_payload_free(new);
81 /* Parses list of channel payloads returning list of payloads. */
83 SilcDList silc_channel_payload_parse_list(const unsigned char *payload,
86 SilcBufferStruct buffer;
88 SilcChannelPayload new;
91 SILC_LOG_DEBUG(("Parsing channel payload list"));
93 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
94 list = silc_dlist_init();
97 new = silc_calloc(1, sizeof(*new));
98 ret = silc_buffer_unformat(&buffer,
99 SILC_STR_UI16_NSTRING_ALLOC(&new->channel_name,
101 SILC_STR_UI16_NSTRING_ALLOC(&new->channel_id,
103 SILC_STR_UI_INT(&new->mode),
108 if ((new->name_len < 1 || new->name_len > buffer.len) ||
109 (new->id_len < 1 || new->id_len > buffer.len)) {
110 SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
114 len = 2 + new->name_len + 2 + new->id_len + 4;
115 if (buffer.len < len)
117 silc_buffer_pull(&buffer, len);
119 silc_dlist_add(list, new);
125 silc_channel_payload_list_free(list);
129 /* Encode new channel payload and returns it as buffer. */
131 SilcBuffer silc_channel_payload_encode(const unsigned char *channel_name,
132 uint16 channel_name_len,
133 const unsigned char *channel_id,
134 uint32 channel_id_len,
139 SILC_LOG_DEBUG(("Encoding message payload"));
141 buffer = silc_buffer_alloc(2 + channel_name_len + 2 + channel_id_len + 4);
142 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
144 /* Encode the Channel Payload */
145 silc_buffer_format(buffer,
146 SILC_STR_UI_SHORT(channel_name_len),
147 SILC_STR_UI_XNSTRING(channel_name, channel_name_len),
148 SILC_STR_UI_SHORT(channel_id_len),
149 SILC_STR_UI_XNSTRING(channel_id, channel_id_len),
150 SILC_STR_UI_INT(mode),
156 /* Frees Channel Payload */
158 void silc_channel_payload_free(SilcChannelPayload payload)
160 silc_free(payload->channel_name);
161 silc_free(payload->channel_id);
165 /* Free's list of Channel Payloads */
167 void silc_channel_payload_list_free(SilcDList list)
169 SilcChannelPayload entry;
171 silc_dlist_start(list);
172 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
173 silc_free(entry->channel_name);
174 silc_free(entry->channel_id);
176 silc_dlist_del(list, entry);
179 silc_dlist_uninit(list);
182 /* Return the channel name */
184 unsigned char *silc_channel_get_name(SilcChannelPayload payload,
185 uint32 *channel_name_len)
187 if (channel_name_len)
188 *channel_name_len = payload->name_len;
190 return payload->channel_name;
193 /* Return the channel ID */
195 unsigned char *silc_channel_get_id(SilcChannelPayload payload,
196 uint32 *channel_id_len)
199 *channel_id_len = payload->id_len;
201 return payload->channel_id;
204 /* Return the channel ID as parsed ID. */
206 SilcChannelID *silc_channel_get_id_parse(SilcChannelPayload payload)
208 return silc_id_str2id(payload->channel_id, payload->id_len,
212 /* Return the mode. The mode is arbitrary. It can be the mode of the
213 channel or perhaps the mode of the client on the channel. The protocol
214 dictates what the usage of the mode is in different circumstances. */
216 uint32 silc_channel_get_mode(SilcChannelPayload payload)
218 return payload->mode;
221 /******************************************************************************
223 Channel Message Payload
225 ******************************************************************************/
227 #define SILC_CHANNEL_MESSAGE_PAD(__payloadlen) (16 - (__payloadlen) % 16)
229 /* Channel Message Payload structure. Contents of this structure is parsed
230 from SILC packets. */
231 struct SilcChannelMessagePayloadStruct {
232 SilcMessageFlags flags;
239 /* Decrypts the channel message payload. */
241 int silc_channel_message_payload_decrypt(unsigned char *data,
246 uint32 iv_len, mac_len;
247 unsigned char *end, *mac, mac2[32];
249 /* Decrypt the channel message. First push the IV out of the packet.
250 The IV is used in the decryption process. Then decrypt the message.
251 After decyprtion, take the MAC from the decrypted packet, compute MAC
252 and compare the MACs. If they match, the decryption was successfull
253 and we have the channel message ready to be displayed. */
254 end = data + data_len;
256 /* Push the IV out of the packet */
257 iv_len = silc_cipher_get_block_len(cipher);
259 /* Decrypt the channel message */
260 silc_cipher_decrypt(cipher, data, data, data_len - iv_len, (end - iv_len));
264 mac_len = silc_hmac_len(hmac);
265 mac = (end - iv_len - mac_len);
267 /* Check the MAC of the message */
268 SILC_LOG_DEBUG(("Checking channel message MACs"));
269 silc_hmac_make(hmac, data, (data_len - iv_len - mac_len), mac2, &mac_len);
270 if (memcmp(mac, mac2, mac_len)) {
271 SILC_LOG_DEBUG(("Channel message MACs does not match"));
274 SILC_LOG_DEBUG(("MAC is Ok"));
280 /* Parses channel message payload returning new channel payload structure.
281 This also decrypts it and checks the MAC. */
283 SilcChannelMessagePayload
284 silc_channel_message_payload_parse(unsigned char *payload,
289 SilcBufferStruct buffer;
290 SilcChannelMessagePayload new;
292 uint32 iv_len, mac_len;
294 SILC_LOG_DEBUG(("Parsing channel message payload"));
296 silc_buffer_set(&buffer, payload, payload_len);
298 /* Decrypt the payload */
299 ret = silc_channel_message_payload_decrypt(buffer.data, buffer.len,
304 iv_len = silc_cipher_get_block_len(cipher);
305 mac_len = silc_hmac_len(hmac);
307 new = silc_calloc(1, sizeof(*new));
309 /* Parse the Channel Message Payload. Ignore the padding. */
310 ret = silc_buffer_unformat(&buffer,
311 SILC_STR_UI_SHORT(&new->flags),
312 SILC_STR_UI16_NSTRING_ALLOC(&new->data,
314 SILC_STR_UI16_NSTRING(NULL, NULL),
315 SILC_STR_UI_XNSTRING(&new->mac, mac_len),
316 SILC_STR_UI_XNSTRING(&new->iv, iv_len),
321 if (new->data_len < 1 || new->data_len > buffer.len) {
322 SILC_LOG_ERROR(("Incorrect channel message payload in packet, "
330 silc_channel_message_payload_free(new);
334 /* Encodes channel message payload into a buffer and returns it. This is used
335 to add channel message payload into a packet. As the channel payload is
336 encrypted separately from other parts of the packet padding must
337 be applied to the payload. */
339 SilcBuffer silc_channel_message_payload_encode(uint16 flags,
341 const unsigned char *data,
349 uint32 len, pad_len, mac_len;
350 unsigned char pad[16];
351 unsigned char mac[32];
353 SILC_LOG_DEBUG(("Encoding channel message payload"));
355 /* Calculate length of padding. IV is not included into the calculation
356 since it is not encrypted. */
357 mac_len = silc_hmac_len(hmac);
358 len = 6 + data_len + mac_len;
359 pad_len = SILC_CHANNEL_MESSAGE_PAD(len);
361 /* Allocate channel payload buffer */
362 len += pad_len + iv_len;
363 buffer = silc_buffer_alloc(len);
365 /* Generate padding */
366 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte();
368 /* Encode the Channel Message Payload */
369 silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
370 silc_buffer_format(buffer,
371 SILC_STR_UI_SHORT(flags),
372 SILC_STR_UI_SHORT(data_len),
373 SILC_STR_UI_XNSTRING(data, data_len),
374 SILC_STR_UI_SHORT(pad_len),
375 SILC_STR_UI_XNSTRING(pad, pad_len),
378 /* Compute the MAC of the channel message data */
379 silc_hmac_make(hmac, buffer->data, buffer->len, mac, &mac_len);
381 /* Put rest of the data to the payload */
382 silc_buffer_pull_tail(buffer, mac_len + iv_len);
383 silc_buffer_pull(buffer, 6 + data_len + pad_len);
384 silc_buffer_format(buffer,
385 SILC_STR_UI_XNSTRING(mac, mac_len),
386 SILC_STR_UI_XNSTRING(iv, iv_len),
388 silc_buffer_push(buffer, 6 + data_len + pad_len);
390 /* Encrypt payload of the packet. This is encrypted with the channel key. */
391 silc_cipher_encrypt(cipher, buffer->data, buffer->data,
392 buffer->len - iv_len, iv);
394 memset(pad, 0, sizeof(pad));
395 memset(mac, 0, sizeof(mac));
400 /* Free's Channel Message Payload */
402 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
405 memset(payload->data, 0, payload->data_len);
406 silc_free(payload->data);
414 silc_channel_message_get_flags(SilcChannelMessagePayload payload)
416 return payload->flags;
421 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
425 *data_len = payload->data_len;
427 return payload->data;
430 /* Return MAC. The caller knows the length of the MAC */
432 unsigned char *silc_channel_mesage_get_mac(SilcChannelMessagePayload payload)
437 /* Return IV. The caller knows the length of the IV */
439 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
444 /******************************************************************************
448 ******************************************************************************/
450 /* Channel Key Payload structrue. Channel keys are parsed from SILC
451 packets into this structure. */
452 struct SilcChannelKeyPayloadStruct {
456 unsigned char *cipher;
461 /* Parses channel key payload returning new channel key payload structure */
463 SilcChannelKeyPayload
464 silc_channel_key_payload_parse(const unsigned char *payload,
467 SilcBufferStruct buffer;
468 SilcChannelKeyPayload new;
471 SILC_LOG_DEBUG(("Parsing channel key payload"));
473 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
474 new = silc_calloc(1, sizeof(*new));
476 /* Parse the Channel Key Payload */
478 silc_buffer_unformat(&buffer,
479 SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len),
480 SILC_STR_UI16_NSTRING_ALLOC(&new->cipher,
482 SILC_STR_UI16_NSTRING_ALLOC(&new->key, &new->key_len),
487 if (new->id_len < 1 || new->key_len < 1 || new->cipher_len < 1) {
488 SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
498 silc_free(new->cipher);
505 /* Encodes channel key payload into a buffer and returns it. This is used
506 to add channel key payload into a packet. */
508 SilcBuffer silc_channel_key_payload_encode(uint16 id_len,
509 const unsigned char *id,
511 const unsigned char *cipher,
513 const unsigned char *key)
518 SILC_LOG_DEBUG(("Encoding channel key payload"));
520 /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
522 len = 2 + id_len + 2 + key_len + 2 + cipher_len;
523 buffer = silc_buffer_alloc(len);
525 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
527 /* Encode the Channel Payload */
528 silc_buffer_format(buffer,
529 SILC_STR_UI_SHORT(id_len),
530 SILC_STR_UI_XNSTRING(id, id_len),
531 SILC_STR_UI_SHORT(cipher_len),
532 SILC_STR_UI_XNSTRING(cipher, cipher_len),
533 SILC_STR_UI_SHORT(key_len),
534 SILC_STR_UI_XNSTRING(key, key_len),
540 /* Frees Channel Key Payload */
542 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
545 silc_free(payload->id);
546 silc_free(payload->cipher);
548 memset(payload->key, 0, payload->key_len);
549 silc_free(payload->key);
557 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
561 *id_len = payload->id_len;
566 /* Return cipher name */
568 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
572 *cipher_len = payload->cipher_len;
574 return payload->cipher;
579 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
583 *key_len = payload->key_len;