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 /* Decrypts the channel message payload. */
43 int silc_channel_payload_decrypt(unsigned char *data,
48 unsigned int iv_len, mac_len;
49 unsigned char *end, *mac, mac2[32];
51 /* Decrypt the channel message. First push the IV out of the packet.
52 The IV is used in the decryption process. Then decrypt the message.
53 After decyprtion, take the MAC from the decrypted packet, compute MAC
54 and compare the MACs. If they match, the decryption was successfull
55 and we have the channel message ready to be displayed. */
56 end = data + data_len;
58 /* Push the IV out of the packet */
59 iv_len = silc_cipher_get_block_len(cipher);
61 /* Decrypt the channel message */
62 silc_cipher_decrypt(cipher, data, data, data_len - iv_len, (end - iv_len));
66 mac_len = silc_hmac_len(hmac);
67 mac = (end - iv_len - mac_len);
69 /* Check the MAC of the message */
70 SILC_LOG_DEBUG(("Checking channel message MACs"));
71 silc_hmac_make(hmac, data, (data_len - iv_len - mac_len), mac2, &mac_len);
72 if (memcmp(mac, mac2, mac_len)) {
73 SILC_LOG_DEBUG(("Channel message MACs does not match"));
76 SILC_LOG_DEBUG(("MAC is Ok"));
82 /* Parses channel payload returning new channel payload structure. This
83 also decrypts it and checks the MAC. */
85 SilcChannelPayload silc_channel_payload_parse(SilcBuffer buffer,
89 SilcChannelPayload new;
91 unsigned int iv_len, mac_len;
93 SILC_LOG_DEBUG(("Parsing channel payload"));
95 /* Decrypt the payload */
96 ret = silc_channel_payload_decrypt(buffer->data, buffer->len,
101 iv_len = silc_cipher_get_block_len(cipher);
102 mac_len = silc_hmac_len(hmac);
104 new = silc_calloc(1, sizeof(*new));
106 /* Parse the Channel Payload. Ignore the padding. */
107 ret = silc_buffer_unformat(buffer,
108 SILC_STR_UI16_NSTRING_ALLOC(&new->data,
110 SILC_STR_UI16_NSTRING(NULL, NULL),
111 SILC_STR_UI_XNSTRING(&new->mac, mac_len),
112 SILC_STR_UI_XNSTRING(&new->iv, iv_len),
117 if (new->data_len < 1 || new->data_len > buffer->len) {
118 SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
125 silc_channel_payload_free(new);
129 /* Encodes channel payload into a buffer and returns it. This is used
130 to add channel payload into a packet. As the channel payload is
131 encrypted separately from other parts of the packet padding must
132 be applied to the payload. */
134 SilcBuffer silc_channel_payload_encode(unsigned short data_len,
136 unsigned short iv_len,
144 unsigned int len, pad_len, mac_len;
145 unsigned char pad[SILC_PACKET_MAX_PADLEN];
146 unsigned char mac[32];
148 SILC_LOG_DEBUG(("Encoding channel payload"));
150 /* Calculate length of padding. IV is not included into the calculation
151 since it is not encrypted. */
152 mac_len = silc_hmac_len(hmac);
153 len = 4 + data_len + mac_len;
154 pad_len = SILC_PACKET_PADLEN((len + 2));
156 /* Allocate channel payload buffer */
157 len += pad_len + iv_len;
158 buffer = silc_buffer_alloc(len);
160 /* Generate padding */
161 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte(rng);
163 /* Encode the Channel Payload */
164 silc_buffer_pull_tail(buffer, 4 + data_len + pad_len);
165 silc_buffer_format(buffer,
166 SILC_STR_UI_SHORT(data_len),
167 SILC_STR_UI_XNSTRING(data, data_len),
168 SILC_STR_UI_SHORT(pad_len),
169 SILC_STR_UI_XNSTRING(pad, pad_len),
172 /* Compute the MAC of the channel message data */
173 silc_hmac_make(hmac, buffer->data, buffer->len, mac, &mac_len);
175 /* Put rest of the data to the payload */
176 silc_buffer_pull_tail(buffer, mac_len + iv_len);
177 silc_buffer_pull(buffer, 4 + data_len + pad_len);
178 silc_buffer_format(buffer,
179 SILC_STR_UI_XNSTRING(mac, mac_len),
180 SILC_STR_UI_XNSTRING(iv, iv_len),
182 silc_buffer_push(buffer, 4 + data_len + pad_len);
184 /* Encrypt payload of the packet. This is encrypted with the channel key. */
185 silc_cipher_encrypt(cipher, buffer->data, buffer->data,
186 buffer->len - iv_len, iv);
188 memset(pad, 0, sizeof(pad));
189 memset(mac, 0, sizeof(mac));
194 /* Free's Channel Payload */
196 void silc_channel_payload_free(SilcChannelPayload payload)
200 memset(payload->data, 0, payload->data_len);
201 silc_free(payload->data);
209 unsigned char *silc_channel_get_data(SilcChannelPayload payload,
210 unsigned int *data_len)
213 *data_len = payload->data_len;
215 return payload->data;
218 /* Return MAC. The caller knows the length of the MAC */
220 unsigned char *silc_channel_get_mac(SilcChannelPayload payload)
225 /* Return IV. The caller knows the length of the IV */
227 unsigned char *silc_channel_get_iv(SilcChannelPayload payload)
232 /******************************************************************************
236 ******************************************************************************/
238 /* Channel Key Payload structrue. Channel keys are parsed from SILC
239 packets into this structure. */
240 struct SilcChannelKeyPayloadStruct {
241 unsigned short id_len;
243 unsigned short cipher_len;
244 unsigned char *cipher;
245 unsigned short key_len;
249 /* Parses channel key payload returning new channel key payload structure */
251 SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer)
253 SilcChannelKeyPayload new;
256 SILC_LOG_DEBUG(("Parsing channel key payload"));
258 new = silc_calloc(1, sizeof(*new));
260 /* Parse the Channel Key Payload */
262 silc_buffer_unformat(buffer,
263 SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len),
264 SILC_STR_UI16_NSTRING_ALLOC(&new->cipher,
266 SILC_STR_UI16_NSTRING_ALLOC(&new->key, &new->key_len),
271 if (new->id_len < 1 || new->key_len < 1 || new->cipher_len < 1) {
272 SILC_LOG_ERROR(("Incorrect channel key payload in packet"));
282 silc_free(new->cipher);
289 /* Encodes channel key payload into a buffer and returns it. This is used
290 to add channel key payload into a packet. */
292 SilcBuffer silc_channel_key_payload_encode(unsigned short id_len,
294 unsigned short cipher_len,
295 unsigned char *cipher,
296 unsigned short key_len,
302 SILC_LOG_DEBUG(("Encoding channel key payload"));
304 /* Allocate channel payload buffer. Length is 2 + id + 2 + key +
306 len = 2 + id_len + 2 + key_len + 2 + cipher_len;
307 buffer = silc_buffer_alloc(len);
309 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
311 /* Encode the Channel Payload */
312 silc_buffer_format(buffer,
313 SILC_STR_UI_SHORT(id_len),
314 SILC_STR_UI_XNSTRING(id, id_len),
315 SILC_STR_UI_SHORT(cipher_len),
316 SILC_STR_UI_XNSTRING(cipher, cipher_len),
317 SILC_STR_UI_SHORT(key_len),
318 SILC_STR_UI_XNSTRING(key, key_len),
324 /* Free's Channel Key Payload */
326 void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
330 silc_free(payload->id);
332 silc_free(payload->cipher);
334 memset(payload->key, 0, payload->key_len);
335 silc_free(payload->key);
343 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload,
344 unsigned int *id_len)
347 *id_len = payload->id_len;
352 /* Return cipher name */
354 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
355 unsigned int *cipher_len)
358 *cipher_len = payload->cipher_len;
360 return payload->cipher;
365 unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload,
366 unsigned int *key_len)
369 *key_len = payload->key_len;