e5ae3069d8cedb2651042ca59af913c93bf7ad94
[silc.git] / lib / silccore / silcprivate.c
1 /*
2
3   silcprivate.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2001 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 /* Includes the Private Message Payload implementation */
21 /* $Id$ */
22
23 #include "silcincludes.h"
24 #include "silcprivate.h"
25
26 /******************************************************************************
27
28                            Private Message Payload
29
30 ******************************************************************************/
31
32 /* Calculates padding length for message payload */
33 #define SILC_PRIVATE_MESSAGE_PAD(__payloadlen) (16 - ((__payloadlen) % 16))
34
35 /* Header length plus maximum padding length */
36 #define SILC_PRIVATE_MESSAGE_HLEN 4 + 16
37
38 /* Returns the data length that fits to the packet.  If data length is too
39    big it will be truncated to fit to the payload. */
40 #define SILC_PRIVATE_MESSAGE_DATALEN(data_len)                          \
41   ((data_len + SILC_PRIVATE_MESSAGE_HLEN) > SILC_PACKET_MAX_LEN ?       \
42    data_len - ((data_len + SILC_PRIVATE_MESSAGE_HLEN) -                 \
43                SILC_PACKET_MAX_LEN) : data_len)
44
45 /* Private Message Payload structure. Contents of this structure is parsed
46    from SILC packets. */
47 struct SilcPrivateMessagePayloadStruct {
48   SilcUInt16 flags;
49   SilcUInt16 message_len;
50   unsigned char *message;
51 };
52
53 /* Parses private message payload returning new private mesage payload 
54    structure. This also decrypts the message if the `cipher' is provided. */
55
56 SilcPrivateMessagePayload 
57 silc_private_message_payload_parse(unsigned char *payload,
58                                    SilcUInt32 payload_len,
59                                    SilcCipher cipher)
60 {
61   SilcBufferStruct buffer;
62   SilcPrivateMessagePayload newp;
63   int ret;
64
65   SILC_LOG_DEBUG(("Parsing private message payload"));
66
67   silc_buffer_set(&buffer, payload, payload_len);
68
69   /* Decrypt the payload */
70   if (cipher)
71     silc_cipher_decrypt(cipher, buffer.data, buffer.data, 
72                         buffer.len, cipher->iv);
73
74   newp = silc_calloc(1, sizeof(*newp));
75   if (!newp)
76     return NULL;
77
78   /* Parse the Private Message Payload. Ignore the padding. */
79   ret = silc_buffer_unformat(&buffer,
80                              SILC_STR_UI_SHORT(&newp->flags),
81                              SILC_STR_UI16_NSTRING_ALLOC(&newp->message, 
82                                                          &newp->message_len),
83                              SILC_STR_END);
84   if (ret == -1) {
85     SILC_LOG_DEBUG(("Incorrect private message payload"));
86     goto err;
87   }
88
89   if ((newp->message_len < 1 || newp->message_len > buffer.len - 4)) {
90     SILC_LOG_DEBUG(("Incorrect private message payload in packet, "
91                     "packet dropped"));
92     goto err;
93   }
94
95   return newp;
96
97  err:
98   silc_private_message_payload_free(newp);
99   return NULL;
100 }
101
102 /* Encodes private message payload into a buffer and returns it.  If
103    the cipher is provided the packet is also encrypted here.  It is provided
104    if the private message private keys are used. */
105
106 SilcBuffer silc_private_message_payload_encode(SilcUInt16 flags,
107                                                SilcUInt16 data_len,
108                                                const unsigned char *data,
109                                                SilcCipher cipher,
110                                                SilcRng rng)
111 {
112   int i;
113   SilcBuffer buffer;
114   SilcUInt32 len, pad_len = 0;
115   unsigned char pad[16];
116
117   SILC_LOG_DEBUG(("Encoding private message payload"));
118
119   data_len = SILC_PRIVATE_MESSAGE_DATALEN(data_len);
120   len = 4 + data_len;
121
122   if (cipher) {
123     /* Calculate length of padding. */
124     pad_len = SILC_PRIVATE_MESSAGE_PAD(len);
125     len += pad_len;
126
127     /* Generate padding */
128     for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte();
129   }
130
131   /* Allocate private message payload buffer */
132   buffer = silc_buffer_alloc_size(len);
133   if (!buffer)
134     return NULL;
135
136   /* Encode the Channel Message Payload */
137   silc_buffer_format(buffer, 
138                      SILC_STR_UI_SHORT(flags),
139                      SILC_STR_UI_SHORT(data_len),
140                      SILC_STR_UI_XNSTRING(data, data_len),
141                      SILC_STR_UI_XNSTRING(pad, pad_len),
142                      SILC_STR_END);
143
144   if (cipher) {
145     /* Encrypt payload of the packet. */
146     silc_cipher_encrypt(cipher, buffer->data, buffer->data, 
147                         buffer->len, cipher->iv);
148     memset(pad, 0, sizeof(pad));
149   }
150
151   return buffer;
152 }
153
154 /* Frees Private Message Payload */
155
156 void silc_private_message_payload_free(SilcPrivateMessagePayload payload)
157 {
158   if (payload->message) {
159     memset(payload->message, 0, payload->message_len);
160     silc_free(payload->message);
161   }
162   silc_free(payload);
163 }
164
165 /* Return flags */
166
167 SilcUInt16 
168 silc_private_message_get_flags(SilcPrivateMessagePayload payload)
169 {
170   return payload->flags;
171 }
172
173 /* Return message */
174
175 unsigned char *
176 silc_private_message_get_message(SilcPrivateMessagePayload payload,
177                                  SilcUInt32 *message_len)
178 {
179   if (message_len)
180     *message_len = payload->message_len;
181
182   return payload->message;
183 }