6136dc75349eb720bae50ac568731c558616adfc
[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 #define SILC_PRIVATE_MESSAGE_PAD(__payloadlen) (16 - (__payloadlen) % 16)
33
34 /* Private Message Payload structure. Contents of this structure is parsed
35    from SILC packets. */
36 struct SilcPrivateMessagePayloadStruct {
37   SilcUInt16 flags;
38   SilcUInt16 message_len;
39   unsigned char *message;
40 };
41
42 /* Parses private message payload returning new private mesage payload 
43    structure. This also decrypts the message if the `cipher' is provided. */
44
45 SilcPrivateMessagePayload 
46 silc_private_message_payload_parse(unsigned char *payload,
47                                    SilcUInt32 payload_len,
48                                    SilcCipher cipher)
49 {
50   SilcBufferStruct buffer;
51   SilcPrivateMessagePayload newp;
52   int ret;
53
54   SILC_LOG_DEBUG(("Parsing private message payload"));
55
56   silc_buffer_set(&buffer, payload, payload_len);
57
58   /* Decrypt the payload */
59   if (cipher)
60     silc_cipher_decrypt(cipher, buffer.data, buffer.data, 
61                         buffer.len, cipher->iv);
62
63   newp = silc_calloc(1, sizeof(*newp));
64   if (!newp)
65     return NULL;
66
67   /* Parse the Private Message Payload. Ignore the padding. */
68   ret = silc_buffer_unformat(&buffer,
69                              SILC_STR_UI_SHORT(&newp->flags),
70                              SILC_STR_UI16_NSTRING_ALLOC(&newp->message, 
71                                                          &newp->message_len),
72                              SILC_STR_END);
73   if (ret == -1) {
74     SILC_LOG_DEBUG(("Incorrect private message payload"));
75     goto err;
76   }
77
78   if ((newp->message_len < 1 || newp->message_len > buffer.len)) {
79     SILC_LOG_DEBUG(("Incorrect private message payload in packet, "
80                     "packet dropped"));
81     goto err;
82   }
83
84   return newp;
85
86  err:
87   silc_private_message_payload_free(newp);
88   return NULL;
89 }
90
91 /* Encodes private message payload into a buffer and returns it.  If
92    the cipher is provided the packet is also encrypted here.  It is provided
93    if the private message private keys are used. */
94
95 SilcBuffer silc_private_message_payload_encode(SilcUInt16 flags,
96                                                SilcUInt16 data_len,
97                                                const unsigned char *data,
98                                                SilcCipher cipher,
99                                                SilcRng rng)
100 {
101   int i;
102   SilcBuffer buffer;
103   SilcUInt32 len, pad_len = 0;
104   unsigned char pad[16];
105
106   SILC_LOG_DEBUG(("Encoding private message payload"));
107
108   len = 4 + data_len;
109
110   if (cipher) {
111     /* Calculate length of padding. */
112     pad_len = SILC_PRIVATE_MESSAGE_PAD(len);
113     len += pad_len;
114
115     /* Generate padding */
116     for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte();
117   }
118
119   /* Allocate private message payload buffer */
120   buffer = silc_buffer_alloc_size(len);
121   if (!buffer)
122     return NULL;
123
124   /* Encode the Channel Message Payload */
125   silc_buffer_format(buffer, 
126                      SILC_STR_UI_SHORT(flags),
127                      SILC_STR_UI_SHORT(data_len),
128                      SILC_STR_UI_XNSTRING(data, data_len),
129                      SILC_STR_UI_XNSTRING(pad, pad_len),
130                      SILC_STR_END);
131
132   if (cipher) {
133     /* Encrypt payload of the packet. */
134     silc_cipher_encrypt(cipher, buffer->data, buffer->data, 
135                         buffer->len, cipher->iv);
136     memset(pad, 0, sizeof(pad));
137   }
138
139   return buffer;
140 }
141
142 /* Frees Private Message Payload */
143
144 void silc_private_message_payload_free(SilcPrivateMessagePayload payload)
145 {
146   if (payload->message) {
147     memset(payload->message, 0, payload->message_len);
148     silc_free(payload->message);
149   }
150   silc_free(payload);
151 }
152
153 /* Return flags */
154
155 SilcUInt16 
156 silc_private_message_get_flags(SilcPrivateMessagePayload payload)
157 {
158   return payload->flags;
159 }
160
161 /* Return message */
162
163 unsigned char *
164 silc_private_message_get_message(SilcPrivateMessagePayload payload,
165                                  SilcUInt32 *message_len)
166 {
167   if (message_len)
168     *message_len = payload->message_len;
169
170   return payload->message;
171 }