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(&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"));
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)
184 unsigned char *silc_channel_get_data(SilcChannelPayload payload,
185 unsigned int *data_len)
188 *data_len = payload->data_len;
190 return payload->data;
193 /* Return MAC. The caller knows the length of the MAC */
195 unsigned char *silc_channel_get_mac(SilcChannelPayload payload)
200 /* Return IV. The caller knows the length of the IV */
202 unsigned char *silc_channel_get_iv(SilcChannelPayload payload)
207 /******************************************************************************
211 ******************************************************************************/
213 /* Channel Key Payload structrue. Channel keys are parsed from SILC
214 packets into this structure. */
215 struct SilcChannelKeyPayloadStruct {
216 unsigned short id_len;
218 unsigned short cipher_len;
219 unsigned char *cipher;
220 unsigned short key_len;
224 /* Parses channel key payload returning new channel key payload structure */
226 SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer)
228 SilcChannelKeyPayload new;
231 SILC_LOG_DEBUG(("Parsing channel key payload"));
233 new = silc_calloc(1, sizeof(*new));
235 /* Parse the Channel Key Payload */
237 silc_buffer_unformat(buffer,
238 SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len),
239 SILC_STR_UI16_NSTRING_ALLOC(&new->cipher,
241 SILC_STR_UI16_NSTRING_ALLOC(&new->key, &new->key_len),
246 if (new->id_len < 1 || new->key_len < 1 || new->cipher_len < 1) {
247 SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
257 silc_free(new->cipher);
264 /* Encodes channel key payload into a buffer and returns it. This is used
265 to add channel key payload into a packet. */
267 SilcBuffer silc_channel_key_payload_encode(unsigned short id_len,
269 unsigned short cipher_len,
270 unsigned char *cipher,
271 unsigned short key_len,
277 SILC_LOG_DEBUG(("Encoding channel key payload"));
279 /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
281 len = 2 + id_len + 2 + key_len + 2 + cipher_len;
282 buffer = silc_buffer_alloc(len);
284 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
286 /* Encode the Channel Payload */
287 silc_buffer_format(buffer,
288 SILC_STR_UI_SHORT(id_len),
289 SILC_STR_UI_XNSTRING(id, id_len),
290 SILC_STR_UI_SHORT(cipher_len),
291 SILC_STR_UI_XNSTRING(cipher, cipher_len),
292 SILC_STR_UI_SHORT(key_len),
293 SILC_STR_UI_XNSTRING(key, key_len),
299 /* Free's Channel Key Payload */
301 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
305 silc_free(payload->id);
307 silc_free(payload->cipher);
309 memset(payload->key, 0, payload->key_len);
310 silc_free(payload->key);
318 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
319 unsigned int *id_len)
322 *id_len = payload->id_len;
327 /* Return cipher name */
329 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
330 unsigned int *cipher_len)
333 *cipher_len = payload->cipher_len;
335 return payload->cipher;
340 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
341 unsigned int *key_len)
344 *key_len = payload->key_len;