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(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 uint16 channel_name_len,
127 unsigned char *channel_id,
128 uint32 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 /* Frees 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 uint32 *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 uint32 *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 uint32 silc_channel_get_mode(SilcChannelPayload payload)
212 return payload->mode;
215 /******************************************************************************
217 Channel Message Payload
219 ******************************************************************************/
221 #define SILC_CHANNEL_MESSAGE_PAD(__payloadlen) (16 - (__payloadlen) % 16)
223 /* Channel Message Payload structure. Contents of this structure is parsed
224 from SILC packets. */
225 struct SilcChannelMessagePayloadStruct {
226 SilcMessageFlags flags;
233 /* Decrypts the channel message payload. */
235 int silc_channel_message_payload_decrypt(unsigned char *data,
240 uint32 iv_len, mac_len;
241 unsigned char *end, *mac, mac2[32];
243 /* Decrypt the channel message. First push the IV out of the packet.
244 The IV is used in the decryption process. Then decrypt the message.
245 After decyprtion, take the MAC from the decrypted packet, compute MAC
246 and compare the MACs. If they match, the decryption was successfull
247 and we have the channel message ready to be displayed. */
248 end = data + data_len;
250 /* Push the IV out of the packet */
251 iv_len = silc_cipher_get_block_len(cipher);
253 /* Decrypt the channel message */
254 silc_cipher_decrypt(cipher, data, data, data_len - iv_len, (end - iv_len));
258 mac_len = silc_hmac_len(hmac);
259 mac = (end - iv_len - mac_len);
261 /* Check the MAC of the message */
262 SILC_LOG_DEBUG(("Checking channel message MACs"));
263 silc_hmac_make(hmac, data, (data_len - iv_len - mac_len), mac2, &mac_len);
264 if (memcmp(mac, mac2, mac_len)) {
265 SILC_LOG_DEBUG(("Channel message MACs does not match"));
268 SILC_LOG_DEBUG(("MAC is Ok"));
274 /* Parses channel message payload returning new channel payload structure.
275 This also decrypts it and checks the MAC. */
277 SilcChannelMessagePayload
278 silc_channel_message_payload_parse(SilcBuffer buffer,
282 SilcChannelMessagePayload new;
284 uint32 iv_len, mac_len;
286 SILC_LOG_DEBUG(("Parsing channel message payload"));
288 /* Decrypt the payload */
289 ret = silc_channel_message_payload_decrypt(buffer->data, buffer->len,
294 iv_len = silc_cipher_get_block_len(cipher);
295 mac_len = silc_hmac_len(hmac);
297 new = silc_calloc(1, sizeof(*new));
299 /* Parse the Channel Message Payload. Ignore the padding. */
300 ret = silc_buffer_unformat(buffer,
301 SILC_STR_UI_SHORT(&new->flags),
302 SILC_STR_UI16_NSTRING_ALLOC(&new->data,
304 SILC_STR_UI16_NSTRING(NULL, NULL),
305 SILC_STR_UI_XNSTRING(&new->mac, mac_len),
306 SILC_STR_UI_XNSTRING(&new->iv, iv_len),
311 if (new->data_len < 1 || new->data_len > buffer->len) {
312 SILC_LOG_ERROR(("Incorrect channel message payload in packet, "
320 silc_channel_message_payload_free(new);
324 /* Encodes channel message payload into a buffer and returns it. This is used
325 to add channel message payload into a packet. As the channel payload is
326 encrypted separately from other parts of the packet padding must
327 be applied to the payload. */
329 SilcBuffer silc_channel_message_payload_encode(uint16 flags,
339 uint32 len, pad_len, mac_len;
340 unsigned char pad[16];
341 unsigned char mac[32];
343 SILC_LOG_DEBUG(("Encoding channel message payload"));
345 /* Calculate length of padding. IV is not included into the calculation
346 since it is not encrypted. */
347 mac_len = silc_hmac_len(hmac);
348 len = 6 + data_len + mac_len;
349 pad_len = SILC_CHANNEL_MESSAGE_PAD(len);
351 /* Allocate channel payload buffer */
352 len += pad_len + iv_len;
353 buffer = silc_buffer_alloc(len);
355 /* Generate padding */
356 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte();
358 /* Encode the Channel Message Payload */
359 silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
360 silc_buffer_format(buffer,
361 SILC_STR_UI_SHORT(flags),
362 SILC_STR_UI_SHORT(data_len),
363 SILC_STR_UI_XNSTRING(data, data_len),
364 SILC_STR_UI_SHORT(pad_len),
365 SILC_STR_UI_XNSTRING(pad, pad_len),
368 /* Compute the MAC of the channel message data */
369 silc_hmac_make(hmac, buffer->data, buffer->len, mac, &mac_len);
371 /* Put rest of the data to the payload */
372 silc_buffer_pull_tail(buffer, mac_len + iv_len);
373 silc_buffer_pull(buffer, 6 + data_len + pad_len);
374 silc_buffer_format(buffer,
375 SILC_STR_UI_XNSTRING(mac, mac_len),
376 SILC_STR_UI_XNSTRING(iv, iv_len),
378 silc_buffer_push(buffer, 6 + data_len + pad_len);
380 /* Encrypt payload of the packet. This is encrypted with the channel key. */
381 silc_cipher_encrypt(cipher, buffer->data, buffer->data,
382 buffer->len - iv_len, iv);
384 memset(pad, 0, sizeof(pad));
385 memset(mac, 0, sizeof(mac));
390 /* Free's Channel Message Payload */
392 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
395 memset(payload->data, 0, payload->data_len);
396 silc_free(payload->data);
404 silc_channel_message_get_flags(SilcChannelMessagePayload payload)
406 return payload->flags;
411 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
415 *data_len = payload->data_len;
417 return payload->data;
420 /* Return MAC. The caller knows the length of the MAC */
422 unsigned char *silc_channel_mesage_get_mac(SilcChannelMessagePayload payload)
427 /* Return IV. The caller knows the length of the IV */
429 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
434 /******************************************************************************
438 ******************************************************************************/
440 /* Channel Key Payload structrue. Channel keys are parsed from SILC
441 packets into this structure. */
442 struct SilcChannelKeyPayloadStruct {
446 unsigned char *cipher;
451 /* Parses channel key payload returning new channel key payload structure */
453 SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer)
455 SilcChannelKeyPayload new;
458 SILC_LOG_DEBUG(("Parsing channel key payload"));
460 new = silc_calloc(1, sizeof(*new));
462 /* Parse the Channel Key Payload */
464 silc_buffer_unformat(buffer,
465 SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len),
466 SILC_STR_UI16_NSTRING_ALLOC(&new->cipher,
468 SILC_STR_UI16_NSTRING_ALLOC(&new->key, &new->key_len),
473 if (new->id_len < 1 || new->key_len < 1 || new->cipher_len < 1) {
474 SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
484 silc_free(new->cipher);
491 /* Encodes channel key payload into a buffer and returns it. This is used
492 to add channel key payload into a packet. */
494 SilcBuffer silc_channel_key_payload_encode(uint16 id_len,
497 unsigned char *cipher,
504 SILC_LOG_DEBUG(("Encoding channel key payload"));
506 /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
508 len = 2 + id_len + 2 + key_len + 2 + cipher_len;
509 buffer = silc_buffer_alloc(len);
511 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
513 /* Encode the Channel Payload */
514 silc_buffer_format(buffer,
515 SILC_STR_UI_SHORT(id_len),
516 SILC_STR_UI_XNSTRING(id, id_len),
517 SILC_STR_UI_SHORT(cipher_len),
518 SILC_STR_UI_XNSTRING(cipher, cipher_len),
519 SILC_STR_UI_SHORT(key_len),
520 SILC_STR_UI_XNSTRING(key, key_len),
526 /* Frees Channel Key Payload */
528 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
531 silc_free(payload->id);
532 silc_free(payload->cipher);
534 memset(payload->key, 0, payload->key_len);
535 silc_free(payload->key);
543 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
547 *id_len = payload->id_len;
552 /* Return cipher name */
554 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
558 *cipher_len = payload->cipher_len;
560 return payload->cipher;
565 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
569 *key_len = payload->key_len;