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