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