Created silcpayload.[ch] for generic payloads.
[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++)
103     pad[i] = silc_rng_get_byte(rng);
104
105   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
106
107   /* Encode the Channel Payload */
108   silc_buffer_format(buffer, 
109                      SILC_STR_UI_SHORT(data_len),
110                      SILC_STR_UI_XNSTRING(data, data_len),
111                      SILC_STR_UI_SHORT(pad_len),
112                      SILC_STR_UI_XNSTRING(pad, pad_len),
113                      SILC_STR_UI_XNSTRING(iv, iv_len),
114                      SILC_STR_END);
115
116   memset(pad, 0, pad_len);
117   return buffer;
118 }
119
120 /* Free's Channel Payload */
121
122 void silc_channel_payload_free(SilcChannelPayload payload)
123 {
124   if (payload) {
125     if (payload->data)
126       silc_free(payload->data);
127     if (payload->iv)
128       silc_free(payload->iv);
129     silc_free(payload);
130   }
131 }
132
133 /* Return data */
134
135 unsigned char *silc_channel_get_data(SilcChannelPayload payload,
136                                      unsigned int *data_len)
137 {
138   if (data_len)
139     *data_len = payload->data_len;
140
141   return payload->data;
142 }
143
144 /* Return initial vector */
145
146 unsigned char *silc_channel_get_iv(SilcChannelPayload payload,
147                                    unsigned int *iv_len)
148 {
149   if (iv_len)
150     *iv_len = payload->iv_len;
151
152   return payload->iv;
153 }
154
155 /******************************************************************************
156
157                              Channel Key Payload
158
159 ******************************************************************************/
160
161 /* Channel Key Payload structrue. Channel keys are parsed from SILC
162    packets into this structure. */
163 struct SilcChannelKeyPayloadStruct {
164   unsigned short id_len;
165   unsigned char *id;
166   unsigned short cipher_len;
167   unsigned char *cipher;
168   unsigned short key_len;
169   unsigned char *key;
170 };
171
172 /* Parses channel key payload returning new channel key payload structure */
173
174 SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer)
175 {
176   SilcChannelKeyPayload new;
177
178   SILC_LOG_DEBUG(("Parsing channel key payload"));
179
180   new = silc_calloc(1, sizeof(*new));
181
182   /* Parse the Channel Key Payload */
183   silc_buffer_unformat(buffer,
184                        SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len),
185                        SILC_STR_UI16_NSTRING_ALLOC(&new->cipher, 
186                                                    &new->cipher_len),
187                        SILC_STR_UI16_NSTRING_ALLOC(&new->key, &new->key_len),
188                        SILC_STR_END);
189
190   if (new->id_len < 1 || new->key_len < 1 || new->cipher_len < 1) {
191     SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
192     goto err;
193   }
194
195   return new;
196
197  err:
198   if (new->id)
199     silc_free(new->id);
200   if (new->cipher)
201     silc_free(new->cipher);
202   if (new->key)
203     silc_free(new->key);
204   silc_free(new);
205   return NULL;
206 }
207
208 /* Encodes channel key payload into a buffer and returns it. This is used 
209    to add channel key payload into a packet. */
210
211 SilcBuffer silc_channel_key_payload_encode(unsigned short id_len,
212                                            unsigned char *id,
213                                            unsigned short cipher_len,
214                                            unsigned char *cipher,
215                                            unsigned short key_len,
216                                            unsigned char *key)
217 {
218   SilcBuffer buffer;
219   unsigned int len;
220
221   SILC_LOG_DEBUG(("Encoding channel key payload"));
222
223   /* Sanity checks */
224   if (!id_len || !key_len || !id || !key || !cipher_len || !cipher)
225     return NULL;
226
227   /* Allocate channel payload buffer. Length is 2 + id + 2 + key + 
228      2 + cipher */
229   len = 2 + id_len + 2 + key_len + 2 + cipher_len;
230   buffer = silc_buffer_alloc(len);
231
232   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
233
234   /* Encode the Channel Payload */
235   silc_buffer_format(buffer, 
236                      SILC_STR_UI_SHORT(id_len),
237                      SILC_STR_UI_XNSTRING(id, id_len),
238                      SILC_STR_UI_SHORT(cipher_len),
239                      SILC_STR_UI_XNSTRING(cipher, cipher_len),
240                      SILC_STR_UI_SHORT(key_len),
241                      SILC_STR_UI_XNSTRING(key, key_len),
242                      SILC_STR_END);
243
244   return buffer;
245 }
246
247 /* Free's Channel Key Payload */
248
249 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
250 {
251   if (payload) {
252     if (payload->id)
253       silc_free(payload->id);
254     if (payload->cipher)
255       silc_free(payload->cipher);
256     if (payload->key) {
257       memset(payload->key, 0, payload->key_len);
258       silc_free(payload->key);
259     }
260     silc_free(payload);
261   }
262 }
263
264 /* Return ID */
265
266 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, 
267                                        unsigned int *id_len)
268 {
269   if (id_len)
270     *id_len = payload->id_len;
271
272   return payload->id;
273 }
274
275 /* Return cipher name */
276
277 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
278                                            unsigned int *cipher_len)
279 {
280   if (cipher_len)
281     *cipher_len = payload->cipher_len;
282
283   return payload->cipher;
284 }
285
286 /* Return key */
287
288 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
289                                         unsigned int *key_len)
290 {
291   if (key_len)
292     *key_len = payload->key_len;
293
294   return payload->key;
295 }