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"
26 #include "silcchannel_i.h"
28 /* Parses channel payload returning new channel payload structure. */
30 SilcChannelPayload silc_channel_payload_parse(const unsigned char *payload,
31 SilcUInt32 payload_len)
33 SilcBufferStruct buffer;
34 SilcChannelPayload newp;
37 SILC_LOG_DEBUG(("Parsing channel payload"));
39 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
40 newp = silc_calloc(1, sizeof(*newp));
44 /* Parse the Channel Payload. Ignore the padding. */
45 ret = silc_buffer_unformat(&buffer,
46 SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_name,
48 SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_id,
50 SILC_STR_UI_INT(&newp->mode),
55 if ((newp->name_len < 1 || newp->name_len > buffer.len - 8) ||
56 (newp->id_len < 1 || newp->id_len > buffer.len - 8) ||
57 (newp->id_len + newp->name_len > buffer.len - 8)) {
58 SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
65 silc_channel_payload_free(newp);
69 /* Parses list of channel payloads returning list of payloads. */
71 SilcDList silc_channel_payload_parse_list(const unsigned char *payload,
72 SilcUInt32 payload_len)
74 SilcBufferStruct buffer;
76 SilcChannelPayload newp;
79 SILC_LOG_DEBUG(("Parsing channel payload list"));
81 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
82 list = silc_dlist_init();
85 newp = silc_calloc(1, sizeof(*newp));
88 ret = silc_buffer_unformat(&buffer,
89 SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_name,
91 SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_id,
93 SILC_STR_UI_INT(&newp->mode),
98 if ((newp->name_len < 1 || newp->name_len > buffer.len) ||
99 (newp->id_len < 1 || newp->id_len > buffer.len)) {
100 SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
104 len = 2 + newp->name_len + 2 + newp->id_len + 4;
105 if (buffer.len < len)
107 silc_buffer_pull(&buffer, len);
109 silc_dlist_add(list, newp);
115 silc_channel_payload_list_free(list);
119 /* Encode new channel payload and returns it as buffer. */
121 SilcBuffer silc_channel_payload_encode(const unsigned char *channel_name,
122 SilcUInt16 channel_name_len,
123 const unsigned char *channel_id,
124 SilcUInt32 channel_id_len,
129 SILC_LOG_DEBUG(("Encoding message payload"));
131 buffer = silc_buffer_alloc_size(2 + channel_name_len + 2 +
136 /* Encode the Channel Payload */
137 silc_buffer_format(buffer,
138 SILC_STR_UI_SHORT(channel_name_len),
139 SILC_STR_UI_XNSTRING(channel_name, channel_name_len),
140 SILC_STR_UI_SHORT(channel_id_len),
141 SILC_STR_UI_XNSTRING(channel_id, channel_id_len),
142 SILC_STR_UI_INT(mode),
148 /* Frees Channel Payload */
150 void silc_channel_payload_free(SilcChannelPayload payload)
152 silc_free(payload->channel_name);
153 silc_free(payload->channel_id);
157 /* Free's list of Channel Payloads */
159 void silc_channel_payload_list_free(SilcDList list)
161 SilcChannelPayload entry;
163 silc_dlist_start(list);
164 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
165 silc_free(entry->channel_name);
166 silc_free(entry->channel_id);
167 silc_dlist_del(list, entry);
171 silc_dlist_uninit(list);
174 /* Return the channel name */
176 unsigned char *silc_channel_get_name(SilcChannelPayload payload,
177 SilcUInt32 *channel_name_len)
179 if (channel_name_len)
180 *channel_name_len = payload->name_len;
182 return payload->channel_name;
185 /* Return the channel ID */
187 unsigned char *silc_channel_get_id(SilcChannelPayload payload,
188 SilcUInt32 *channel_id_len)
191 *channel_id_len = payload->id_len;
193 return payload->channel_id;
196 /* Return the channel ID as parsed ID. */
198 SilcChannelID *silc_channel_get_id_parse(SilcChannelPayload payload)
200 return silc_id_str2id(payload->channel_id, payload->id_len,
204 /* Return the mode. The mode is arbitrary. It can be the mode of the
205 channel or perhaps the mode of the client on the channel. The protocol
206 dictates what the usage of the mode is in different circumstances. */
208 SilcUInt32 silc_channel_get_mode(SilcChannelPayload payload)
210 return payload->mode;
213 /******************************************************************************
215 Channel Message Payload
217 ******************************************************************************/
219 /* Decrypts the channel message payload. First push the IV out of the
220 packet. The IV is used in the decryption process. Then decrypt the
221 message. After decyprtion, take the MAC from the decrypted packet,
222 compute MAC and compare the MACs. If they match, the decryption was
223 successful and we have the channel message ready to be displayed. */
225 bool silc_channel_message_payload_decrypt(unsigned char *data,
231 SilcUInt32 iv_len, mac_len;
232 unsigned char *mac, mac2[32];
234 mac_len = silc_hmac_len(hmac);
235 iv_len = silc_cipher_get_block_len(cipher);
237 if (data_len < mac_len)
242 mac = data + (data_len - mac_len);
244 /* Check the MAC of the message */
245 SILC_LOG_DEBUG(("Checking channel message MAC"));
246 silc_hmac_init(hmac);
247 silc_hmac_update(hmac, data, data_len - mac_len);
248 silc_hmac_final(hmac, mac2, &mac_len);
249 if (memcmp(mac, mac2, mac_len)) {
250 SILC_LOG_DEBUG(("Channel message MAC does not match"));
253 SILC_LOG_DEBUG(("MAC is Ok"));
256 /* Decrypt the channel message */
257 silc_cipher_decrypt(cipher, data, data,
258 data_len - iv_len - mac_len,
259 data + (data_len - iv_len - mac_len));
263 /* Parses channel message payload returning new channel payload structure.
264 This also decrypts it and checks the MAC. */
266 SilcChannelMessagePayload
267 silc_channel_message_payload_parse(unsigned char *payload,
268 SilcUInt32 payload_len,
272 SilcBufferStruct buffer;
273 SilcChannelMessagePayload newp;
275 SilcUInt32 iv_len, mac_len;
277 SILC_LOG_DEBUG(("Parsing channel message payload"));
279 silc_buffer_set(&buffer, payload, payload_len);
281 /* Decrypt the payload */
282 ret = silc_channel_message_payload_decrypt(buffer.data, buffer.len,
287 iv_len = silc_cipher_get_block_len(cipher);
288 mac_len = silc_hmac_len(hmac);
290 newp = silc_calloc(1, sizeof(*newp));
294 /* Parse the Channel Message Payload. */
295 ret = silc_buffer_unformat(&buffer,
296 SILC_STR_UI_SHORT(&newp->flags),
297 SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
299 SILC_STR_UI16_NSTRING_ALLOC(&newp->pad,
301 SILC_STR_UI_XNSTRING(&newp->iv, iv_len),
302 SILC_STR_UI_XNSTRING(&newp->mac, mac_len),
307 if ((newp->data_len > buffer.len - 6 - mac_len - iv_len) ||
308 (newp->pad_len + newp->data_len > buffer.len - 6 - mac_len - iv_len)) {
309 SILC_LOG_ERROR(("Incorrect channel message payload in packet, "
314 newp->iv_len = iv_len;
319 silc_channel_message_payload_free(newp);
323 /* This function is used to encrypt the Channel Messsage Payload which is
324 the `data' and `data_len'. This is used internally by the Channel Message
325 Payload encoding routines but application may call this too if needed.
326 The `data_len' is the data lenght which is used to create MAC out of.
327 The `true_len' is the true length of `data' message payload and is used
328 assemble rest of the packet after MAC creation. The `true_len' length
329 packet will then be encrypted. */
331 bool silc_channel_message_payload_encrypt(unsigned char *data,
338 unsigned char mac[32];
340 SilcBufferStruct buf;
342 /* Encrypt payload of the packet. This is encrypted with the channel key. */
343 silc_cipher_encrypt(cipher, data, data, data_len - iv_len, iv);
345 /* Compute the MAC of the encrypted channel message data */
346 silc_hmac_init(hmac);
347 silc_hmac_update(hmac, data, data_len);
348 silc_hmac_final(hmac, mac, &mac_len);
350 /* Put rest of the data to the payload */
351 silc_buffer_set(&buf, data, data_len + mac_len);
352 silc_buffer_pull(&buf, data_len);
353 silc_buffer_put(&buf, mac, mac_len);
358 /* Encodes channel message payload into a buffer and returns it. This is used
359 to add channel message payload into a packet. As the channel payload is
360 encrypted separately from other parts of the packet padding must
361 be applied to the payload. */
363 SilcBuffer silc_channel_message_payload_encode(SilcMessageFlags flags,
365 const unsigned char *data,
374 SilcUInt32 len, pad_len, mac_len;
375 unsigned char pad[16];
377 SILC_LOG_DEBUG(("Encoding channel message payload"));
379 /* Calculate length of padding. IV is not included into the calculation
380 since it is not encrypted. */
381 mac_len = silc_hmac_len(hmac);
382 data_len = SILC_CHANNEL_MESSAGE_DATALEN(data_len, mac_len + iv_len);
384 pad_len = SILC_CHANNEL_MESSAGE_PAD(len);
386 /* Allocate channel payload buffer */
387 len += pad_len + iv_len + mac_len;
388 buffer = silc_buffer_alloc(len);
392 /* Generate padding */
394 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
396 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
399 /* Encode the Channel Message Payload */
400 silc_buffer_pull_tail(buffer, 6 + data_len + pad_len + iv_len);
401 silc_buffer_format(buffer,
402 SILC_STR_UI_SHORT(flags),
403 SILC_STR_UI_SHORT(data_len),
404 SILC_STR_UI_XNSTRING(data, data_len),
405 SILC_STR_UI_SHORT(pad_len),
406 SILC_STR_UI_XNSTRING(pad, pad_len),
407 SILC_STR_UI_XNSTRING(iv, iv_len),
410 memset(pad, 0, sizeof(pad));
412 if (!silc_channel_message_payload_encrypt(buffer->data, buffer->len,
413 iv, iv_len, cipher, hmac)) {
414 silc_buffer_free(buffer);
418 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer) - buffer->len);
423 /* Free's Channel Message Payload */
425 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
428 memset(payload->data, 0, payload->data_len);
429 silc_free(payload->data);
437 silc_channel_message_get_flags(SilcChannelMessagePayload payload)
439 return payload->flags;
444 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
445 SilcUInt32 *data_len)
448 *data_len = payload->data_len;
450 return payload->data;
453 /* Return MAC. The caller knows the length of the MAC */
455 unsigned char *silc_channel_message_get_mac(SilcChannelMessagePayload payload)
460 /* Return IV. The caller knows the length of the IV */
462 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
467 /******************************************************************************
471 ******************************************************************************/
473 /* Parses channel key payload returning new channel key payload structure */
475 SilcChannelKeyPayload
476 silc_channel_key_payload_parse(const unsigned char *payload,
477 SilcUInt32 payload_len)
479 SilcBufferStruct buffer;
480 SilcChannelKeyPayload newp;
483 SILC_LOG_DEBUG(("Parsing channel key payload"));
485 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
486 newp = silc_calloc(1, sizeof(*newp));
490 /* Parse the Channel Key Payload */
492 silc_buffer_unformat(&buffer,
493 SILC_STR_UI16_NSTRING_ALLOC(&newp->id, &newp->id_len),
494 SILC_STR_UI16_NSTRING_ALLOC(&newp->cipher,
496 SILC_STR_UI16_NSTRING_ALLOC(&newp->key,
502 if (newp->id_len < 1 || newp->key_len < 1 || newp->cipher_len < 1 ||
503 newp->id_len + newp->cipher_len + newp->key_len > buffer.len - 6) {
504 SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
514 silc_free(newp->cipher);
516 silc_free(newp->key);
521 /* Encodes channel key payload into a buffer and returns it. This is used
522 to add channel key payload into a packet. */
524 SilcBuffer silc_channel_key_payload_encode(SilcUInt16 id_len,
525 const unsigned char *id,
526 SilcUInt16 cipher_len,
527 const unsigned char *cipher,
529 const unsigned char *key)
534 SILC_LOG_DEBUG(("Encoding channel key payload"));
536 /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
538 len = 2 + id_len + 2 + key_len + 2 + cipher_len;
539 buffer = silc_buffer_alloc_size(len);
543 /* Encode the Channel Payload */
544 silc_buffer_format(buffer,
545 SILC_STR_UI_SHORT(id_len),
546 SILC_STR_UI_XNSTRING(id, id_len),
547 SILC_STR_UI_SHORT(cipher_len),
548 SILC_STR_UI_XNSTRING(cipher, cipher_len),
549 SILC_STR_UI_SHORT(key_len),
550 SILC_STR_UI_XNSTRING(key, key_len),
556 /* Frees Channel Key Payload */
558 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
561 silc_free(payload->id);
562 silc_free(payload->cipher);
564 memset(payload->key, 0, payload->key_len);
565 silc_free(payload->key);
573 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
577 *id_len = payload->id_len;
582 /* Return cipher name */
584 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
585 SilcUInt32 *cipher_len)
588 *cipher_len = payload->cipher_len;
590 return payload->cipher;
595 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
599 *key_len = payload->key_len;