5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 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 and Channel Key Payload implementations. */
23 #include "silcincludes.h"
24 #include "silcchannel.h"
26 /******************************************************************************
28 Channel Message Payload
30 ******************************************************************************/
32 /* Channel Message Payload structure. Contents of this structure is parsed
34 struct SilcChannelPayloadStruct {
35 unsigned short data_len;
41 /* Parses channel payload returning new channel payload structure. This
42 also decrypts it and checks the MAC. */
44 SilcChannelPayload silc_channel_payload_parse(SilcBuffer buffer,
48 SilcChannelPayload new;
50 unsigned int iv_len, mac_len;
51 unsigned char *mac, mac2[32];
53 SILC_LOG_DEBUG(("Parsing channel payload"));
55 /* Decrypt the channel message. First push the IV out of the packet.
56 The IV is used in the decryption process. Then decrypt the message.
57 After decyprtion, take the MAC from the decrypted packet, compute MAC
58 and compare the MACs. If they match, the decryption was successfull
59 and we have the channel message ready to be displayed. */
61 /* Push the IV out of the packet (it will be in buffer->tail) */
62 iv_len = silc_cipher_get_block_len(cipher);
63 silc_buffer_push_tail(buffer, iv_len);
65 /* Decrypt the channel message */
66 silc_cipher_decrypt(cipher, buffer->data, buffer->data,
67 buffer->len, buffer->tail);
70 mac_len = silc_hmac_len(hmac);
71 silc_buffer_push_tail(buffer, mac_len);
74 /* Check the MAC of the message */
75 SILC_LOG_DEBUG(("Checking channel message MACs"));
76 silc_hmac_make(hmac, buffer->data, buffer->len, mac2, &mac_len);
77 if (memcmp(mac, mac2, mac_len)) {
78 SILC_LOG_DEBUG(("Channel message MACs does not match"));
81 SILC_LOG_DEBUG(("MAC is Ok"));
82 silc_buffer_pull_tail(buffer, iv_len + mac_len);
84 new = silc_calloc(1, sizeof(*new));
86 /* Parse the Channel Payload. Ignore the padding. */
87 ret = silc_buffer_unformat(buffer,
88 SILC_STR_UI16_NSTRING_ALLOC(&new->data,
90 SILC_STR_UI16_NSTRING(NULL, NULL),
91 SILC_STR_UI_XNSTRING(&new->mac, mac_len),
92 SILC_STR_UI_XNSTRING(&new->iv, iv_len),
97 if (new->data_len < 1 || new->data_len > buffer->len) {
98 SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
105 silc_channel_payload_free(new);
109 /* Encodes channel payload into a buffer and returns it. This is used
110 to add channel payload into a packet. As the channel payload is
111 encrypted separately from other parts of the packet padding must
112 be applied to the payload. */
114 SilcBuffer silc_channel_payload_encode(unsigned short data_len,
116 unsigned short iv_len,
124 unsigned int len, pad_len, mac_len;
125 unsigned char pad[SILC_PACKET_MAX_PADLEN];
126 unsigned char mac[32];
128 SILC_LOG_DEBUG(("Encoding channel payload"));
130 /* Calculate length of padding. IV is not included into the calculation
131 since it is not encrypted. */
132 mac_len = silc_hmac_len(hmac);
133 len = 4 + data_len + mac_len;
134 pad_len = SILC_PACKET_PADLEN((len + 2));
136 /* Allocate channel payload buffer */
137 len += pad_len + iv_len;
138 buffer = silc_buffer_alloc(len);
140 /* Generate padding */
141 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte(rng);
143 /* Encode the Channel Payload */
144 silc_buffer_pull_tail(buffer, 4 + data_len + pad_len);
145 silc_buffer_format(buffer,
146 SILC_STR_UI_SHORT(data_len),
147 SILC_STR_UI_XNSTRING(data, data_len),
148 SILC_STR_UI_SHORT(pad_len),
149 SILC_STR_UI_XNSTRING(pad, pad_len),
152 /* Compute the MAC of the channel message data */
153 silc_hmac_make(hmac, buffer->data, buffer->len, mac, &mac_len);
155 /* Put rest of the data to the payload */
156 silc_buffer_pull_tail(buffer, mac_len + iv_len);
157 silc_buffer_pull(buffer, 4 + data_len + pad_len);
158 silc_buffer_format(buffer,
159 SILC_STR_UI_XNSTRING(mac, mac_len),
160 SILC_STR_UI_XNSTRING(iv, iv_len),
162 silc_buffer_push(buffer, 4 + data_len + pad_len);
164 /* Encrypt payload of the packet. This is encrypted with the channel key. */
165 silc_cipher_encrypt(cipher, buffer->data, buffer->data,
166 buffer->len - iv_len, iv);
168 memset(pad, 0, sizeof(pad));
169 memset(mac, 0, sizeof(mac));
174 /* Free's Channel Payload */
176 void silc_channel_payload_free(SilcChannelPayload payload)
180 silc_free(payload->data);
187 unsigned char *silc_channel_get_data(SilcChannelPayload payload,
188 unsigned int *data_len)
191 *data_len = payload->data_len;
193 return payload->data;
196 /* Return MAC. The caller knows the length of the MAC */
198 unsigned char *silc_channel_get_mac(SilcChannelPayload payload)
203 /* Return IV. The caller knows the length of the IV */
205 unsigned char *silc_channel_get_iv(SilcChannelPayload payload)
210 /******************************************************************************
214 ******************************************************************************/
216 /* Channel Key Payload structrue. Channel keys are parsed from SILC
217 packets into this structure. */
218 struct SilcChannelKeyPayloadStruct {
219 unsigned short id_len;
221 unsigned short cipher_len;
222 unsigned char *cipher;
223 unsigned short key_len;
227 /* Parses channel key payload returning new channel key payload structure */
229 SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer)
231 SilcChannelKeyPayload new;
234 SILC_LOG_DEBUG(("Parsing channel key payload"));
236 new = silc_calloc(1, sizeof(*new));
238 /* Parse the Channel Key Payload */
240 silc_buffer_unformat(buffer,
241 SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len),
242 SILC_STR_UI16_NSTRING_ALLOC(&new->cipher,
244 SILC_STR_UI16_NSTRING_ALLOC(&new->key, &new->key_len),
249 if (new->id_len < 1 || new->key_len < 1 || new->cipher_len < 1) {
250 SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
260 silc_free(new->cipher);
267 /* Encodes channel key payload into a buffer and returns it. This is used
268 to add channel key payload into a packet. */
270 SilcBuffer silc_channel_key_payload_encode(unsigned short id_len,
272 unsigned short cipher_len,
273 unsigned char *cipher,
274 unsigned short key_len,
280 SILC_LOG_DEBUG(("Encoding channel key payload"));
282 /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
284 len = 2 + id_len + 2 + key_len + 2 + cipher_len;
285 buffer = silc_buffer_alloc(len);
287 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
289 /* Encode the Channel Payload */
290 silc_buffer_format(buffer,
291 SILC_STR_UI_SHORT(id_len),
292 SILC_STR_UI_XNSTRING(id, id_len),
293 SILC_STR_UI_SHORT(cipher_len),
294 SILC_STR_UI_XNSTRING(cipher, cipher_len),
295 SILC_STR_UI_SHORT(key_len),
296 SILC_STR_UI_XNSTRING(key, key_len),
302 /* Free's Channel Key Payload */
304 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
308 silc_free(payload->id);
310 silc_free(payload->cipher);
312 memset(payload->key, 0, payload->key_len);
313 silc_free(payload->key);
321 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
322 unsigned int *id_len)
325 *id_len = payload->id_len;
330 /* Return cipher name */
332 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
333 unsigned int *cipher_len)
336 *cipher_len = payload->cipher_len;
338 return payload->cipher;
343 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
344 unsigned int *key_len)
347 *key_len = payload->key_len;