5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 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 /* Includes the Private Message Payload implementation */
23 #include "silcincludes.h"
24 #include "silcprivate.h"
25 #include "silcprivate_i.h"
27 /******************************************************************************
29 Private Message Payload
31 ******************************************************************************/
33 /* Parses private message payload returning new private mesage payload
34 structure. This also decrypts the message if the `cipher' is provided. */
36 SilcPrivateMessagePayload
37 silc_private_message_payload_parse(unsigned char *payload,
38 SilcUInt32 payload_len,
42 SilcBufferStruct buffer;
43 SilcPrivateMessagePayload newp;
44 SilcUInt32 mac_len = 0, block_len, pad_len = 0;
45 unsigned char data[16], mac[32];
48 SILC_LOG_DEBUG(("Parsing private message payload"));
50 silc_buffer_set(&buffer, payload, payload_len);
52 newp = silc_calloc(1, sizeof(*newp));
56 /* Decrypt the payload */
58 /* Decrypt first block. This is to get the true length of the data in
59 payload. It is possible there is additional data after the message
60 payload with private messages. */
61 block_len = silc_cipher_get_block_len(cipher);
62 if (block_len > buffer.len)
64 silc_cipher_decrypt(cipher, buffer.data, data, block_len,
65 silc_cipher_get_iv(cipher));
67 /* Length of encrypted area */
68 SILC_GET16_MSB(newp->message_len, data + 2);
69 totlen = 4 + newp->message_len;
70 pad_len = SILC_PRIVATE_MESSAGE_PAD(4 + newp->message_len);
74 if (totlen > buffer.len || newp->message_len < 1 ||
75 newp->message_len > buffer.len - 4) {
76 SILC_LOG_DEBUG(("Incorrect private message payload in packet"));
80 /* Compute MAC for integrity check from the cipher text */
82 SILC_LOG_DEBUG(("Checking private message MAC"));
84 silc_hmac_update(hmac, buffer.data, totlen);
85 silc_hmac_final(hmac, mac, &mac_len);
86 if (memcmp(mac, buffer.data + totlen, mac_len)) {
87 SILC_LOG_DEBUG(("Private message MAC does not match"));
90 SILC_LOG_DEBUG(("MAC is Ok"));
93 /* Now decrypt rest of the data */
94 memcpy(buffer.data, data, block_len);
95 if (totlen - block_len > 0)
96 silc_cipher_decrypt(cipher, buffer.data + block_len,
97 buffer.data + block_len, totlen - block_len,
98 silc_cipher_get_iv(cipher));
99 memset(data, 0, sizeof(data));
102 /* Parse the Private Message Payload. */
103 len = silc_buffer_unformat(&buffer,
104 SILC_STR_UI_SHORT(&newp->flags),
105 SILC_STR_UI16_NSTRING_ALLOC(&newp->message,
108 if (len == -1 || newp->message_len < 1 ||
109 newp->message_len > buffer.len - 4) {
110 SILC_LOG_DEBUG(("Incorrect private message payload in packet"));
114 /* Parse also padding and MAC */
116 silc_buffer_pull(&buffer, 4 + newp->message_len);
117 len = silc_buffer_unformat(&buffer,
118 SILC_STR_UI_XNSTRING_ALLOC(&newp->pad,
120 SILC_STR_UI_XNSTRING_ALLOC(&newp->mac,
123 silc_buffer_push(&buffer, 4 + newp->message_len);
129 silc_private_message_payload_free(newp);
133 /* Encodes private message payload into a buffer and returns it. If
134 the cipher is provided the packet is also encrypted here. It is provided
135 if the private message private keys are used. */
137 SilcBuffer silc_private_message_payload_encode(SilcUInt16 flags,
139 const unsigned char *data,
146 SilcUInt32 len, pad_len = 0, mac_len = 0;
147 unsigned char pad[16], mac[32];
149 SILC_LOG_DEBUG(("Encoding private message payload"));
151 data_len = SILC_PRIVATE_MESSAGE_DATALEN(data_len);
155 /* Calculate length of padding. */
156 pad_len = SILC_PRIVATE_MESSAGE_PAD(len);
158 mac_len = hmac ? silc_hmac_len(hmac) : 0;
161 /* Generate padding */
163 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
165 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
169 /* Allocate private message payload buffer */
170 buffer = silc_buffer_alloc_size(len);
174 /* Encode the Channel Message Payload */
175 silc_buffer_format(buffer,
176 SILC_STR_UI_SHORT(flags),
177 SILC_STR_UI_SHORT(data_len),
178 SILC_STR_UI_XNSTRING(data, data_len),
179 SILC_STR_UI_XNSTRING(pad, pad_len),
183 /* Encrypt payload of the packet. */
184 silc_cipher_encrypt(cipher, buffer->data, buffer->data,
185 buffer->len - mac_len, silc_cipher_get_iv(cipher));
186 memset(pad, 0, sizeof(pad));
188 /* Compute MAC from the ciphertext */
190 silc_hmac_init(hmac);
191 silc_hmac_update(hmac, buffer->data, buffer->len - mac_len);
192 silc_hmac_final(hmac, mac, &mac_len);
193 memcpy(buffer->data + (buffer->len - mac_len), mac, mac_len);
194 memset(mac, 0, sizeof(mac));
201 /* Frees Private Message Payload */
203 void silc_private_message_payload_free(SilcPrivateMessagePayload payload)
205 if (payload->message) {
206 memset(payload->message, 0, payload->message_len);
207 silc_free(payload->message);
215 silc_private_message_get_flags(SilcPrivateMessagePayload payload)
217 return payload->flags;
223 silc_private_message_get_message(SilcPrivateMessagePayload payload,
224 SilcUInt32 *message_len)
227 *message_len = payload->message_len;
229 return payload->message;
232 /* Return MAC. Caller knows its length */
235 silc_private_message_get_mac(SilcPrivateMessagePayload payload)