Created SILC Client Libary by moving stuff from silc/ directory.
[silc.git] / lib / silccore / silcchannel.c
1 /*
2
3   silcchannel.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 Pekka Riikonen
8
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.
13   
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.
18
19 */
20 /*
21  * $Id$
22  * $Log$
23  * Revision 1.2  2000/07/05 06:06:35  priikone
24  *      Global cosmetic change.
25  *
26  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
27  *      Imported from internal CVS/Added Log headers.
28  *
29  *
30  */
31
32 #include "silcincludes.h"
33 #include "silcchannel.h"
34
35 /* Channel Payload structure. Contents of this structure is parsed
36    from SILC packets. */
37 struct SilcChannelPayloadStruct {
38   unsigned short nick_len;
39   unsigned char *nick;
40   unsigned short data_len;
41   unsigned char *data;
42   unsigned short iv_len;
43   unsigned char *iv;
44 };
45
46 /* Channel Key Payload structrue. Channel keys are parsed from SILC
47    packets into this structure. */
48 struct SilcChannelKeyPayloadStruct {
49   unsigned short id_len;
50   unsigned char *id;
51   unsigned short cipher_len;
52   unsigned char *cipher;
53   unsigned short key_len;
54   unsigned char *key;
55 };
56
57 /* Parses channel payload returning new channel payload structure */
58
59 SilcChannelPayload silc_channel_parse_payload(SilcBuffer buffer)
60 {
61   SilcChannelPayload new;
62
63   SILC_LOG_DEBUG(("Parsing channel payload"));
64
65   new = silc_calloc(1, sizeof(*new));
66
67   /* Parse the Channel Payload. Ignore padding and IV, we don't need
68      them. */
69   silc_buffer_unformat(buffer,
70                        SILC_STR_UI16_NSTRING_ALLOC(&new->nick, &new->nick_len),
71                        SILC_STR_UI16_NSTRING_ALLOC(&new->data, &new->data_len),
72                        SILC_STR_UI16_NSTRING_ALLOC(NULL, NULL),
73                        SILC_STR_END);
74
75   if (new->data_len < 1) {
76     SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
77     goto err;
78   }
79
80   return new;
81
82  err:
83   if (new->nick)
84     silc_free(new->nick);
85   if (new->data)
86     silc_free(new->data);
87   if (new->iv)
88     silc_free(new->iv);
89   silc_free(new);
90   return NULL;
91 }
92
93 /* Encodes channel payload into a buffer and returns it. This is used 
94    to add channel payload into a packet. As the channel payload is
95    encrypted separately from other parts of the packet padding must
96    be applied to the payload. */
97
98 SilcBuffer silc_channel_encode_payload(unsigned short nick_len,
99                                        unsigned char *nick,
100                                        unsigned short data_len,
101                                        unsigned char *data,
102                                        unsigned short iv_len,
103                                        unsigned char *iv,
104                                        SilcRng rng)
105 {
106   int i;
107   SilcBuffer buffer;
108   unsigned int len, pad_len;
109   unsigned char pad[SILC_PACKET_MAX_PADLEN];
110
111   SILC_LOG_DEBUG(("Encoding channel payload"));
112
113   /* Calculate length of padding. IV is not included into the calculation
114      since it is not encrypted. */
115   len = 2 + nick_len + 2 + data_len + 2;
116   pad_len = SILC_PACKET_PADLEN((len + 2));
117
118   /* Allocate channel payload buffer */
119   len += pad_len;
120   buffer = silc_buffer_alloc(len + iv_len);
121
122   /* Generate padding */
123   for (i = 0; i < pad_len; i++)
124     pad[i] = silc_rng_get_byte(rng);
125
126   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
127
128   /* Encode the Channel Payload */
129   silc_buffer_format(buffer, 
130                      SILC_STR_UI_SHORT(nick_len),
131                      SILC_STR_UI_XNSTRING(nick, nick_len),
132                      SILC_STR_UI_SHORT(data_len),
133                      SILC_STR_UI_XNSTRING(data, data_len),
134                      SILC_STR_UI_SHORT(pad_len),
135                      SILC_STR_UI_XNSTRING(pad, pad_len),
136                      SILC_STR_UI_XNSTRING(iv, iv_len),
137                      SILC_STR_END);
138
139   memset(pad, 0, pad_len);
140   return buffer;
141 }
142
143 /* Free's Channel Payload */
144
145 void silc_channel_free_payload(SilcChannelPayload payload)
146 {
147   if (payload) {
148     if (payload->data)
149       silc_free(payload->data);
150     if (payload->iv)
151       silc_free(payload->iv);
152     silc_free(payload);
153   }
154 }
155
156 /* Return nickname */
157
158 unsigned char *silc_channel_get_nickname(SilcChannelPayload payload,
159                                          unsigned int *nick_len)
160 {
161   if (nick_len)
162     *nick_len = payload->nick_len;
163
164   return payload->nick;
165 }
166
167 /* Return data */
168
169 unsigned char *silc_channel_get_data(SilcChannelPayload payload,
170                                      unsigned int *data_len)
171 {
172   if (data_len)
173     *data_len = payload->data_len;
174
175   return payload->data;
176 }
177
178 /* Return initial vector */
179
180 unsigned char *silc_channel_get_iv(SilcChannelPayload payload,
181                                    unsigned int *iv_len)
182 {
183   if (iv_len)
184     *iv_len = payload->iv_len;
185
186   return payload->iv;
187 }
188
189 /* Parses channel key payload returning new channel key payload structure */
190
191 SilcChannelKeyPayload silc_channel_key_parse_payload(SilcBuffer buffer)
192 {
193   SilcChannelKeyPayload new;
194
195   SILC_LOG_DEBUG(("Parsing channel key payload"));
196
197   new = silc_calloc(1, sizeof(*new));
198
199   /* Parse the Channel Key Payload */
200   silc_buffer_unformat(buffer,
201                        SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len),
202                        SILC_STR_UI16_NSTRING_ALLOC(&new->cipher, 
203                                                    &new->cipher_len),
204                        SILC_STR_UI16_NSTRING_ALLOC(&new->key, &new->key_len),
205                        SILC_STR_END);
206
207   if (new->id_len < 1 || new->key_len < 1 || new->cipher_len < 1) {
208     SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
209     goto err;
210   }
211
212   return new;
213
214  err:
215   if (new->id)
216     silc_free(new->id);
217   if (new->cipher)
218     silc_free(new->cipher);
219   if (new->key)
220     silc_free(new->key);
221   silc_free(new);
222   return NULL;
223 }
224
225 /* Encodes channel key payload into a buffer and returns it. This is used 
226    to add channel key payload into a packet. */
227
228 SilcBuffer silc_channel_key_encode_payload(unsigned short id_len,
229                                            unsigned char *id,
230                                            unsigned short cipher_len,
231                                            unsigned char *cipher,
232                                            unsigned short key_len,
233                                            unsigned char *key)
234 {
235   SilcBuffer buffer;
236   unsigned int len;
237
238   SILC_LOG_DEBUG(("Encoding channel key payload"));
239
240   /* Sanity checks */
241   if (!id_len || !key_len || !id || !key || !cipher_len || !cipher)
242     return NULL;
243
244   /* Allocate channel payload buffer. Length is 2 + id + 2 + key + 
245      2 + cipher */
246   len = 2 + id_len + 2 + key_len + 2 + cipher_len;
247   buffer = silc_buffer_alloc(len);
248
249   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
250
251   /* Encode the Channel Payload */
252   silc_buffer_format(buffer, 
253                      SILC_STR_UI_SHORT(id_len),
254                      SILC_STR_UI_XNSTRING(id, id_len),
255                      SILC_STR_UI_SHORT(cipher_len),
256                      SILC_STR_UI_XNSTRING(cipher, cipher_len),
257                      SILC_STR_UI_SHORT(key_len),
258                      SILC_STR_UI_XNSTRING(key, key_len),
259                      SILC_STR_END);
260
261   return buffer;
262 }
263
264 /* Free's Channel Key Payload */
265
266 void silc_channel_key_free_payload(SilcChannelKeyPayload payload)
267 {
268   if (payload) {
269     if (payload->id)
270       silc_free(payload->id);
271     if (payload->cipher)
272       silc_free(payload->cipher);
273     if (payload->key) {
274       memset(payload->key, 0, payload->key_len);
275       silc_free(payload->key);
276     }
277     silc_free(payload);
278   }
279 }
280
281 /* Return ID */
282
283 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, 
284                                        unsigned int *id_len)
285 {
286   if (id_len)
287     *id_len = payload->id_len;
288
289   return payload->id;
290 }
291
292 /* Return cipher name */
293
294 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
295                                            unsigned int *cipher_len)
296 {
297   if (cipher_len)
298     *cipher_len = payload->cipher_len;
299
300   return payload->cipher;
301 }
302
303 /* Return key */
304
305 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
306                                         unsigned int *key_len)
307 {
308   if (key_len)
309     *key_len = payload->key_len;
310
311   return payload->key;
312 }