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);
175 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. First push the IV out of the
240 packet. The IV is used in the decryption process. Then decrypt the
241 message. After decyprtion, take the MAC from the decrypted packet,
242 compute MAC and compare the MACs. If they match, the decryption was
243 successful and we have the channel message ready to be displayed. */
245 bool silc_channel_message_payload_decrypt(unsigned char *data,
250 uint32 iv_len, mac_len;
251 unsigned char *end, *mac, mac2[32];
252 unsigned char *dst, iv[SILC_CIPHER_MAX_IV_SIZE];
254 /* Push the IV out of the packet, and copy the IV since we do not want
255 to modify the original data buffer. */
256 end = data + data_len;
257 iv_len = silc_cipher_get_block_len(cipher);
258 memcpy(iv, end - iv_len, iv_len);
260 /* Allocate destination decryption buffer since we do not want to modify
261 the original data buffer, since we might want to call this function
262 many times for same payload. */
264 dst = silc_calloc(data_len - iv_len, sizeof(*dst));
268 /* Decrypt the channel message */
269 silc_cipher_decrypt(cipher, data, dst, data_len - iv_len, iv);
273 end = dst + (data_len - iv_len);
274 mac_len = silc_hmac_len(hmac);
275 mac = (end - mac_len);
277 /* Check the MAC of the message */
278 SILC_LOG_DEBUG(("Checking channel message MACs"));
279 silc_hmac_make(hmac, dst, (data_len - iv_len - mac_len), mac2, &mac_len);
280 if (memcmp(mac, mac2, mac_len)) {
281 SILC_LOG_DEBUG(("Channel message MACs does not match"));
285 SILC_LOG_DEBUG(("MAC is Ok"));
287 /* Now copy the decrypted data into the buffer since it is verified
288 it decrypted correctly. */
289 memcpy(data, dst, data_len - iv_len);
290 memset(dst, 0, data_len - iv_len);
297 /* Parses channel message payload returning new channel payload structure.
298 This also decrypts it and checks the MAC. */
300 SilcChannelMessagePayload
301 silc_channel_message_payload_parse(unsigned char *payload,
306 SilcBufferStruct buffer;
307 SilcChannelMessagePayload new;
309 uint32 iv_len, mac_len;
311 SILC_LOG_DEBUG(("Parsing channel message payload"));
313 silc_buffer_set(&buffer, payload, payload_len);
315 /* Decrypt the payload */
316 ret = silc_channel_message_payload_decrypt(buffer.data, buffer.len,
321 iv_len = silc_cipher_get_block_len(cipher);
322 mac_len = silc_hmac_len(hmac);
324 new = silc_calloc(1, sizeof(*new));
326 /* Parse the Channel Message Payload. Ignore the padding. */
327 ret = silc_buffer_unformat(&buffer,
328 SILC_STR_UI_SHORT(&new->flags),
329 SILC_STR_UI16_NSTRING_ALLOC(&new->data,
331 SILC_STR_UI16_NSTRING(NULL, NULL),
332 SILC_STR_UI_XNSTRING(&new->mac, mac_len),
333 SILC_STR_UI_XNSTRING(&new->iv, iv_len),
338 if (new->data_len > buffer.len) {
339 SILC_LOG_ERROR(("Incorrect channel message payload in packet, "
347 silc_channel_message_payload_free(new);
351 /* Encodes channel message payload into a buffer and returns it. This is used
352 to add channel message payload into a packet. As the channel payload is
353 encrypted separately from other parts of the packet padding must
354 be applied to the payload. */
356 SilcBuffer silc_channel_message_payload_encode(uint16 flags,
358 const unsigned char *data,
366 uint32 len, pad_len, mac_len;
367 unsigned char pad[16];
368 unsigned char mac[32];
370 SILC_LOG_DEBUG(("Encoding channel message payload"));
372 /* Calculate length of padding. IV is not included into the calculation
373 since it is not encrypted. */
374 mac_len = silc_hmac_len(hmac);
375 len = 6 + data_len + mac_len;
376 pad_len = SILC_CHANNEL_MESSAGE_PAD(len);
378 /* Allocate channel payload buffer */
379 len += pad_len + iv_len;
380 buffer = silc_buffer_alloc(len);
382 /* Generate padding */
383 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte();
385 /* Encode the Channel Message Payload */
386 silc_buffer_pull_tail(buffer, 6 + data_len + pad_len);
387 silc_buffer_format(buffer,
388 SILC_STR_UI_SHORT(flags),
389 SILC_STR_UI_SHORT(data_len),
390 SILC_STR_UI_XNSTRING(data, data_len),
391 SILC_STR_UI_SHORT(pad_len),
392 SILC_STR_UI_XNSTRING(pad, pad_len),
395 /* Compute the MAC of the channel message data */
396 silc_hmac_make(hmac, buffer->data, buffer->len, mac, &mac_len);
398 /* Put rest of the data to the payload */
399 silc_buffer_pull_tail(buffer, mac_len + iv_len);
400 silc_buffer_pull(buffer, 6 + data_len + pad_len);
401 silc_buffer_format(buffer,
402 SILC_STR_UI_XNSTRING(mac, mac_len),
403 SILC_STR_UI_XNSTRING(iv, iv_len),
405 silc_buffer_push(buffer, 6 + data_len + pad_len);
407 /* Encrypt payload of the packet. This is encrypted with the channel key. */
408 silc_cipher_encrypt(cipher, buffer->data, buffer->data,
409 buffer->len - iv_len, iv);
411 memset(pad, 0, sizeof(pad));
412 memset(mac, 0, sizeof(mac));
417 /* Free's Channel Message Payload */
419 void silc_channel_message_payload_free(SilcChannelMessagePayload payload)
422 memset(payload->data, 0, payload->data_len);
423 silc_free(payload->data);
431 silc_channel_message_get_flags(SilcChannelMessagePayload payload)
433 return payload->flags;
438 unsigned char *silc_channel_message_get_data(SilcChannelMessagePayload payload,
442 *data_len = payload->data_len;
444 return payload->data;
447 /* Return MAC. The caller knows the length of the MAC */
449 unsigned char *silc_channel_message_get_mac(SilcChannelMessagePayload payload)
454 /* Return IV. The caller knows the length of the IV */
456 unsigned char *silc_channel_message_get_iv(SilcChannelMessagePayload payload)
461 /******************************************************************************
465 ******************************************************************************/
467 /* Channel Key Payload structrue. Channel keys are parsed from SILC
468 packets into this structure. */
469 struct SilcChannelKeyPayloadStruct {
473 unsigned char *cipher;
478 /* Parses channel key payload returning new channel key payload structure */
480 SilcChannelKeyPayload
481 silc_channel_key_payload_parse(const unsigned char *payload,
484 SilcBufferStruct buffer;
485 SilcChannelKeyPayload new;
488 SILC_LOG_DEBUG(("Parsing channel key payload"));
490 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
491 new = silc_calloc(1, sizeof(*new));
493 /* Parse the Channel Key Payload */
495 silc_buffer_unformat(&buffer,
496 SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len),
497 SILC_STR_UI16_NSTRING_ALLOC(&new->cipher,
499 SILC_STR_UI16_NSTRING_ALLOC(&new->key, &new->key_len),
504 if (new->id_len < 1 || new->key_len < 1 || new->cipher_len < 1) {
505 SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
515 silc_free(new->cipher);
522 /* Encodes channel key payload into a buffer and returns it. This is used
523 to add channel key payload into a packet. */
525 SilcBuffer silc_channel_key_payload_encode(uint16 id_len,
526 const unsigned char *id,
528 const unsigned char *cipher,
530 const unsigned char *key)
535 SILC_LOG_DEBUG(("Encoding channel key payload"));
537 /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
539 len = 2 + id_len + 2 + key_len + 2 + cipher_len;
540 buffer = silc_buffer_alloc(len);
542 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
544 /* Encode the Channel Payload */
545 silc_buffer_format(buffer,
546 SILC_STR_UI_SHORT(id_len),
547 SILC_STR_UI_XNSTRING(id, id_len),
548 SILC_STR_UI_SHORT(cipher_len),
549 SILC_STR_UI_XNSTRING(cipher, cipher_len),
550 SILC_STR_UI_SHORT(key_len),
551 SILC_STR_UI_XNSTRING(key, key_len),
557 /* Frees Channel Key Payload */
559 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
562 silc_free(payload->id);
563 silc_free(payload->cipher);
565 memset(payload->key, 0, payload->key_len);
566 silc_free(payload->key);
574 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
578 *id_len = payload->id_len;
583 /* Return cipher name */
585 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
589 *cipher_len = payload->cipher_len;
591 return payload->cipher;
596 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
600 *key_len = payload->key_len;