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,
46 SilcUInt32 payload_len)
48 SilcBufferStruct buffer;
49 SilcChannelPayload newp;
52 SILC_LOG_DEBUG(("Parsing channel payload"));
54 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
55 newp = silc_calloc(1, sizeof(*newp));
59 /* Parse the Channel Payload. Ignore the padding. */
60 ret = silc_buffer_unformat(&buffer,
61 SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_name,
63 SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_id,
65 SILC_STR_UI_INT(&newp->mode),
70 if ((newp->name_len < 1 || newp->name_len > buffer.len) ||
71 (newp->id_len < 1 || newp->id_len > buffer.len)) {
72 SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
79 silc_channel_payload_free(newp);
83 /* Parses list of channel payloads returning list of payloads. */
85 SilcDList silc_channel_payload_parse_list(const unsigned char *payload,
86 SilcUInt32 payload_len)
88 SilcBufferStruct buffer;
90 SilcChannelPayload newp;
93 SILC_LOG_DEBUG(("Parsing channel payload list"));
95 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
96 list = silc_dlist_init();
99 newp = silc_calloc(1, sizeof(*newp));
102 ret = silc_buffer_unformat(&buffer,
103 SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_name,
105 SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_id,
107 SILC_STR_UI_INT(&newp->mode),
112 if ((newp->name_len < 1 || newp->name_len > buffer.len) ||
113 (newp->id_len < 1 || newp->id_len > buffer.len)) {
114 SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
118 len = 2 + newp->name_len + 2 + newp->id_len + 4;
119 if (buffer.len < len)
121 silc_buffer_pull(&buffer, len);
123 silc_dlist_add(list, newp);
129 silc_channel_payload_list_free(list);
133 /* Encode new channel payload and returns it as buffer. */
135 SilcBuffer silc_channel_payload_encode(const unsigned char *channel_name,
136 SilcUInt16 channel_name_len,
137 const unsigned char *channel_id,
138 SilcUInt32 channel_id_len,
143 SILC_LOG_DEBUG(("Encoding message payload"));
145 buffer = silc_buffer_alloc_size(2 + channel_name_len + 2 +
150 /* Encode the Channel Payload */
151 silc_buffer_format(buffer,
152 SILC_STR_UI_SHORT(channel_name_len),
153 SILC_STR_UI_XNSTRING(channel_name, channel_name_len),
154 SILC_STR_UI_SHORT(channel_id_len),
155 SILC_STR_UI_XNSTRING(channel_id, channel_id_len),
156 SILC_STR_UI_INT(mode),
162 /* Frees Channel Payload */
164 void silc_channel_payload_free(SilcChannelPayload payload)
166 silc_free(payload->channel_name);
167 silc_free(payload->channel_id);
171 /* Free's list of Channel Payloads */
173 void silc_channel_payload_list_free(SilcDList list)
175 SilcChannelPayload entry;
177 silc_dlist_start(list);
178 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
179 silc_free(entry->channel_name);
180 silc_free(entry->channel_id);
181 silc_dlist_del(list, entry);
185 silc_dlist_uninit(list);
188 /* Return the channel name */
190 unsigned char *silc_channel_get_name(SilcChannelPayload payload,
191 SilcUInt32 *channel_name_len)
193 if (channel_name_len)
194 *channel_name_len = payload->name_len;
196 return payload->channel_name;
199 /* Return the channel ID */
201 unsigned char *silc_channel_get_id(SilcChannelPayload payload,
202 SilcUInt32 *channel_id_len)
205 *channel_id_len = payload->id_len;
207 return payload->channel_id;
210 /* Return the channel ID as parsed ID. */
212 SilcChannelID *silc_channel_get_id_parse(SilcChannelPayload payload)
214 return silc_id_str2id(payload->channel_id, payload->id_len,
218 /* Return the mode. The mode is arbitrary. It can be the mode of the
219 channel or perhaps the mode of the client on the channel. The protocol
220 dictates what the usage of the mode is in different circumstances. */
222 SilcUInt32 silc_channel_get_mode(SilcChannelPayload payload)
224 return payload->mode;
227 /******************************************************************************
229 Channel Message Payload
231 ******************************************************************************/
233 #define SILC_CHANNEL_MESSAGE_PAD(__payloadlen) (16 - (__payloadlen) % 16)
235 /* Channel Message Payload structure. Contents of this structure is parsed
236 from SILC packets. */
237 struct SilcChannelMessagePayloadStruct {
238 SilcMessageFlags flags;
245 /* Decrypts the channel message payload. First push the IV out of the
246 packet. The IV is used in the decryption process. Then decrypt the
247 message. After decyprtion, take the MAC from the decrypted packet,
248 compute MAC and compare the MACs. If they match, the decryption was
249 successful and we have the channel message ready to be displayed. */
251 bool silc_channel_message_payload_decrypt(unsigned char *data,
256 SilcUInt32 iv_len, mac_len;
257 unsigned char *end, *mac, mac2[32];
258 unsigned char *dst, iv[SILC_CIPHER_MAX_IV_SIZE];
260 /* Push the IV out of the packet, and copy the IV since we do not want
261 to modify the original data buffer. */
262 end = data + data_len;
263 iv_len = silc_cipher_get_block_len(cipher);
264 memcpy(iv, end - iv_len, iv_len);
266 /* Allocate destination decryption buffer since we do not want to modify
267 the original data buffer, since we might want to call this function
268 many times for same payload. */
270 dst = silc_calloc(data_len - iv_len, sizeof(*dst));
277 /* Decrypt the channel message */
278 silc_cipher_decrypt(cipher, data, dst, data_len - iv_len, iv);
282 end = dst + (data_len - iv_len);
283 mac_len = silc_hmac_len(hmac);
284 mac = (end - mac_len);
286 /* Check the MAC of the message */
287 SILC_LOG_DEBUG(("Checking channel message MACs"));
288 silc_hmac_make(hmac, dst, (data_len - iv_len - mac_len), mac2, &mac_len);
289 if (memcmp(mac, mac2, mac_len)) {
290 SILC_LOG_DEBUG(("Channel message MACs does not match"));
294 SILC_LOG_DEBUG(("MAC is Ok"));
296 /* Now copy the decrypted data into the buffer since it is verified
297 it decrypted correctly. */
298 memcpy(data, dst, data_len - iv_len);
299 memset(dst, 0, data_len - iv_len);
306 /* Parses channel message payload returning new channel payload structure.
307 This also decrypts it and checks the MAC. */
309 SilcChannelMessagePayload
310 silc_channel_message_payload_parse(unsigned char *payload,
311 SilcUInt32 payload_len,
315 SilcBufferStruct buffer;
316 SilcChannelMessagePayload newp;
318 SilcUInt32 iv_len, mac_len;
320 SILC_LOG_DEBUG(("Parsing channel message payload"));
322 silc_buffer_set(&buffer, payload, payload_len);
324 /* Decrypt the payload */
325 ret = silc_channel_message_payload_decrypt(buffer.data, buffer.len,
330 iv_len = silc_cipher_get_block_len(cipher);
331 mac_len = silc_hmac_len(hmac);
333 newp = silc_calloc(1, sizeof(*newp));
337 /* Parse the Channel Message Payload. Ignore the padding. */
338 ret = silc_buffer_unformat(&buffer,
339 SILC_STR_UI_SHORT(&newp->flags),
340 SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
342 SILC_STR_UI16_NSTRING(NULL, NULL),
343 SILC_STR_UI_XNSTRING(&newp->mac, mac_len),
344 SILC_STR_UI_XNSTRING(&newp->iv, iv_len),
349 if (newp->data_len > buffer.len) {
350 SILC_LOG_ERROR(("Incorrect channel message payload in packet, "
358 silc_channel_message_payload_free(newp);
362 /* Encodes channel message payload into a buffer and returns it. This is used
363 to add channel message payload into a packet. As the channel payload is
364 encrypted separately from other parts of the packet padding must
365 be applied to the payload. */
367 SilcBuffer silc_channel_message_payload_encode(SilcUInt16 flags,
369 const unsigned char *data,
378 SilcUInt32 len, pad_len, mac_len;
379 unsigned char pad[16];
380 unsigned char mac[32];
382 SILC_LOG_DEBUG(("Encoding channel message payload"));
384 /* Calculate length of padding. IV is not included into the calculation
385 since it is not encrypted. */
386 mac_len = silc_hmac_len(hmac);
387 len = 6 + data_len + mac_len;
388 pad_len = SILC_CHANNEL_MESSAGE_PAD(len);
390 /* Allocate channel payload buffer */
391 len += pad_len + iv_len;
392 buffer = silc_buffer_alloc(len);
396 /* Generate padding */
398 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte(rng);
400 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte();
403 /* Encode the Channel Message Payload */
404 silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
405 silc_buffer_format(buffer,
406 SILC_STR_UI_SHORT(flags),
407 SILC_STR_UI_SHORT(data_len),
408 SILC_STR_UI_XNSTRING(data, data_len),
409 SILC_STR_UI_SHORT(pad_len),
410 SILC_STR_UI_XNSTRING(pad, pad_len),
413 /* Compute the MAC of the channel message data */
414 silc_hmac_make(hmac, buffer->data, buffer->len, mac, &mac_len);
416 /* Put rest of the data to the payload */
417 silc_buffer_pull_tail(buffer, mac_len + iv_len);
418 silc_buffer_pull(buffer, 6 + data_len + pad_len);
419 silc_buffer_format(buffer,
420 SILC_STR_UI_XNSTRING(mac, mac_len),
421 SILC_STR_UI_XNSTRING(iv, iv_len),
423 silc_buffer_push(buffer, 6 + data_len + pad_len);
425 /* Encrypt payload of the packet. This is encrypted with the channel key. */
426 silc_cipher_encrypt(cipher, buffer->data, buffer->data,
427 buffer->len - iv_len, iv);
429 memset(pad, 0, sizeof(pad));
430 memset(mac, 0, sizeof(mac));
435 /* Free's Channel Message Payload */
437 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
440 memset(payload->data, 0, payload->data_len);
441 silc_free(payload->data);
449 silc_channel_message_get_flags(SilcChannelMessagePayload payload)
451 return payload->flags;
456 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
457 SilcUInt32 *data_len)
460 *data_len = payload->data_len;
462 return payload->data;
465 /* Return MAC. The caller knows the length of the MAC */
467 unsigned char *silc_channel_message_get_mac(SilcChannelMessagePayload payload)
472 /* Return IV. The caller knows the length of the IV */
474 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
479 /******************************************************************************
483 ******************************************************************************/
485 /* Channel Key Payload structrue. Channel keys are parsed from SILC
486 packets into this structure. */
487 struct SilcChannelKeyPayloadStruct {
490 SilcUInt16 cipher_len;
491 unsigned char *cipher;
496 /* Parses channel key payload returning new channel key payload structure */
498 SilcChannelKeyPayload
499 silc_channel_key_payload_parse(const unsigned char *payload,
500 SilcUInt32 payload_len)
502 SilcBufferStruct buffer;
503 SilcChannelKeyPayload newp;
506 SILC_LOG_DEBUG(("Parsing channel key payload"));
508 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
509 newp = silc_calloc(1, sizeof(*newp));
513 /* Parse the Channel Key Payload */
515 silc_buffer_unformat(&buffer,
516 SILC_STR_UI16_NSTRING_ALLOC(&newp->id, &newp->id_len),
517 SILC_STR_UI16_NSTRING_ALLOC(&newp->cipher,
519 SILC_STR_UI16_NSTRING_ALLOC(&newp->key,
525 if (newp->id_len < 1 || newp->key_len < 1 || newp->cipher_len < 1) {
526 SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
536 silc_free(newp->cipher);
538 silc_free(newp->key);
543 /* Encodes channel key payload into a buffer and returns it. This is used
544 to add channel key payload into a packet. */
546 SilcBuffer silc_channel_key_payload_encode(SilcUInt16 id_len,
547 const unsigned char *id,
548 SilcUInt16 cipher_len,
549 const unsigned char *cipher,
551 const unsigned char *key)
556 SILC_LOG_DEBUG(("Encoding channel key payload"));
558 /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
560 len = 2 + id_len + 2 + key_len + 2 + cipher_len;
561 buffer = silc_buffer_alloc_size(len);
565 /* Encode the Channel Payload */
566 silc_buffer_format(buffer,
567 SILC_STR_UI_SHORT(id_len),
568 SILC_STR_UI_XNSTRING(id, id_len),
569 SILC_STR_UI_SHORT(cipher_len),
570 SILC_STR_UI_XNSTRING(cipher, cipher_len),
571 SILC_STR_UI_SHORT(key_len),
572 SILC_STR_UI_XNSTRING(key, key_len),
578 /* Frees Channel Key Payload */
580 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
583 silc_free(payload->id);
584 silc_free(payload->cipher);
586 memset(payload->key, 0, payload->key_len);
587 silc_free(payload->key);
595 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
599 *id_len = payload->id_len;
604 /* Return cipher name */
606 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
607 SilcUInt32 *cipher_len)
610 *cipher_len = payload->cipher_len;
612 return payload->cipher;
617 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
621 *key_len = payload->key_len;