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,
230 SilcUInt32 iv_len, mac_len;
231 unsigned char *end, *mac, mac2[32];
232 unsigned char *dst, iv[SILC_CIPHER_MAX_IV_SIZE];
234 /* Push the IV out of the packet, and copy the IV since we do not want
235 to modify the original data buffer. */
236 end = data + data_len;
237 iv_len = silc_cipher_get_block_len(cipher);
238 memcpy(iv, end - iv_len, iv_len);
240 /* Allocate destination decryption buffer since we do not want to modify
241 the original data buffer, since we might want to call this function
242 many times for same payload. */
244 dst = silc_calloc(data_len - iv_len, sizeof(*dst));
251 /* Decrypt the channel message */
252 silc_cipher_decrypt(cipher, data, dst, data_len - iv_len, iv);
256 end = dst + (data_len - iv_len);
257 mac_len = silc_hmac_len(hmac);
258 mac = (end - mac_len);
260 /* Check the MAC of the message */
261 SILC_LOG_DEBUG(("Checking channel message MACs"));
262 silc_hmac_init(hmac);
263 silc_hmac_update(hmac, dst, (data_len - iv_len - mac_len));
264 silc_hmac_update(hmac, data + (data_len - iv_len), iv_len);
265 silc_hmac_final(hmac, mac2, &mac_len);
266 if (memcmp(mac, mac2, mac_len)) {
267 SILC_LOG_DEBUG(("Channel message MACs does not match"));
271 SILC_LOG_DEBUG(("MAC is Ok"));
273 /* Now copy the decrypted data into the buffer since it is verified
274 it decrypted correctly. */
275 memcpy(data, dst, data_len - iv_len);
276 memset(dst, 0, data_len - iv_len);
283 /* Parses channel message payload returning new channel payload structure.
284 This also decrypts it and checks the MAC. */
286 SilcChannelMessagePayload
287 silc_channel_message_payload_parse(unsigned char *payload,
288 SilcUInt32 payload_len,
292 SilcBufferStruct buffer;
293 SilcChannelMessagePayload newp;
295 SilcUInt32 iv_len, mac_len;
297 SILC_LOG_DEBUG(("Parsing channel message payload"));
299 silc_buffer_set(&buffer, payload, payload_len);
301 /* Decrypt the payload */
302 ret = silc_channel_message_payload_decrypt(buffer.data, buffer.len,
307 iv_len = silc_cipher_get_block_len(cipher);
308 mac_len = silc_hmac_len(hmac);
310 newp = silc_calloc(1, sizeof(*newp));
314 /* Parse the Channel Message Payload. */
315 ret = silc_buffer_unformat(&buffer,
316 SILC_STR_UI_SHORT(&newp->flags),
317 SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
319 SILC_STR_UI16_NSTRING_ALLOC(&newp->pad,
321 SILC_STR_UI_XNSTRING(&newp->mac, mac_len),
322 SILC_STR_UI_XNSTRING(&newp->iv, iv_len),
327 if ((newp->data_len > buffer.len - 6 - mac_len - iv_len) ||
328 (newp->pad_len + newp->data_len > buffer.len - 6 - mac_len - iv_len)) {
329 SILC_LOG_ERROR(("Incorrect channel message payload in packet, "
334 newp->iv_len = iv_len;
339 silc_channel_message_payload_free(newp);
343 /* This function is used to encrypt the Channel Messsage Payload which is
344 the `data' and `data_len'. This is used internally by the Channel Message
345 Payload encoding routines but application may call this too if needed.
346 The `data_len' is the data lenght which is used to create MAC out of.
347 The `true_len' is the true length of `data' message payload and is used
348 assemble rest of the packet after MAC creation. The `true_len' length
349 packet will then be encrypted. */
351 bool silc_channel_message_payload_encrypt(unsigned char *data,
359 unsigned char mac[32];
361 SilcBufferStruct buf;
363 /* Compute the MAC of the channel message data */
364 silc_hmac_init(hmac);
365 silc_hmac_update(hmac, data, data_len);
366 silc_hmac_update(hmac, iv, iv_len);
367 silc_hmac_final(hmac, mac, &mac_len);
369 /* Put rest of the data to the payload */
370 silc_buffer_set(&buf, data, true_len);
371 silc_buffer_pull(&buf, data_len);
372 silc_buffer_format(&buf,
373 SILC_STR_UI_XNSTRING(mac, mac_len),
374 SILC_STR_UI_XNSTRING(iv, iv_len),
377 /* Encrypt payload of the packet. This is encrypted with the channel key. */
378 silc_cipher_encrypt(cipher, data, data, true_len - iv_len, iv);
380 memset(mac, 0, sizeof(mac));
384 /* Encodes channel message payload into a buffer and returns it. This is used
385 to add channel message payload into a packet. As the channel payload is
386 encrypted separately from other parts of the packet padding must
387 be applied to the payload. */
389 SilcBuffer silc_channel_message_payload_encode(SilcMessageFlags flags,
391 const unsigned char *data,
400 SilcUInt32 len, pad_len, mac_len;
401 unsigned char pad[16];
403 SILC_LOG_DEBUG(("Encoding channel message payload"));
405 /* Calculate length of padding. IV is not included into the calculation
406 since it is not encrypted. */
407 mac_len = silc_hmac_len(hmac);
408 data_len = SILC_CHANNEL_MESSAGE_DATALEN(data_len, mac_len + iv_len);
409 len = 6 + data_len + mac_len;
410 pad_len = SILC_CHANNEL_MESSAGE_PAD(len);
412 /* Allocate channel payload buffer */
413 len += pad_len + iv_len;
414 buffer = silc_buffer_alloc(len);
418 /* Generate padding */
420 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
422 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
425 /* Encode the Channel Message Payload */
426 silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
427 silc_buffer_format(buffer,
428 SILC_STR_UI_SHORT(flags),
429 SILC_STR_UI_SHORT(data_len),
430 SILC_STR_UI_XNSTRING(data, data_len),
431 SILC_STR_UI_SHORT(pad_len),
432 SILC_STR_UI_XNSTRING(pad, pad_len),
435 memset(pad, 0, sizeof(pad));
437 if (!silc_channel_message_payload_encrypt(buffer->data, buffer->len,
438 buffer->truelen, iv, iv_len,
440 silc_buffer_free(buffer);
444 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer) - buffer->len);
449 /* Free's Channel Message Payload */
451 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
454 memset(payload->data, 0, payload->data_len);
455 silc_free(payload->data);
463 silc_channel_message_get_flags(SilcChannelMessagePayload payload)
465 return payload->flags;
470 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
471 SilcUInt32 *data_len)
474 *data_len = payload->data_len;
476 return payload->data;
479 /* Return MAC. The caller knows the length of the MAC */
481 unsigned char *silc_channel_message_get_mac(SilcChannelMessagePayload payload)
486 /* Return IV. The caller knows the length of the IV */
488 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
493 /******************************************************************************
497 ******************************************************************************/
499 /* Parses channel key payload returning new channel key payload structure */
501 SilcChannelKeyPayload
502 silc_channel_key_payload_parse(const unsigned char *payload,
503 SilcUInt32 payload_len)
505 SilcBufferStruct buffer;
506 SilcChannelKeyPayload newp;
509 SILC_LOG_DEBUG(("Parsing channel key payload"));
511 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
512 newp = silc_calloc(1, sizeof(*newp));
516 /* Parse the Channel Key Payload */
518 silc_buffer_unformat(&buffer,
519 SILC_STR_UI16_NSTRING_ALLOC(&newp->id, &newp->id_len),
520 SILC_STR_UI16_NSTRING_ALLOC(&newp->cipher,
522 SILC_STR_UI16_NSTRING_ALLOC(&newp->key,
528 if (newp->id_len < 1 || newp->key_len < 1 || newp->cipher_len < 1 ||
529 newp->id_len + newp->cipher_len + newp->key_len > buffer.len - 6) {
530 SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
540 silc_free(newp->cipher);
542 silc_free(newp->key);
547 /* Encodes channel key payload into a buffer and returns it. This is used
548 to add channel key payload into a packet. */
550 SilcBuffer silc_channel_key_payload_encode(SilcUInt16 id_len,
551 const unsigned char *id,
552 SilcUInt16 cipher_len,
553 const unsigned char *cipher,
555 const unsigned char *key)
560 SILC_LOG_DEBUG(("Encoding channel key payload"));
562 /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
564 len = 2 + id_len + 2 + key_len + 2 + cipher_len;
565 buffer = silc_buffer_alloc_size(len);
569 /* Encode the Channel Payload */
570 silc_buffer_format(buffer,
571 SILC_STR_UI_SHORT(id_len),
572 SILC_STR_UI_XNSTRING(id, id_len),
573 SILC_STR_UI_SHORT(cipher_len),
574 SILC_STR_UI_XNSTRING(cipher, cipher_len),
575 SILC_STR_UI_SHORT(key_len),
576 SILC_STR_UI_XNSTRING(key, key_len),
582 /* Frees Channel Key Payload */
584 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
587 silc_free(payload->id);
588 silc_free(payload->cipher);
590 memset(payload->key, 0, payload->key_len);
591 silc_free(payload->key);
599 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
603 *id_len = payload->id_len;
608 /* Return cipher name */
610 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
611 SilcUInt32 *cipher_len)
614 *cipher_len = payload->cipher_len;
616 return payload->cipher;
621 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
625 *key_len = payload->key_len;