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