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