******************************************************************************/
+/* Calculates padding length for message payload */
#define SILC_CHANNEL_MESSAGE_PAD(__payloadlen) (16 - (__payloadlen) % 16)
+/* Header length plus maximum padding length */
+#define SILC_CHANNEL_MESSAGE_HLEN 6 + 16
+
+/* Returns the data length that fits to the packet. If data length is too
+ big it will be truncated to fit to the payload. */
+#define SILC_CHANNEL_MESSAGE_DATALEN(data_len, header_len) \
+ ((data_len + SILC_CHANNEL_MESSAGE_HLEN + header_len) > \
+ SILC_PACKET_MAX_LEN ? \
+ data_len - ((data_len + SILC_CHANNEL_MESSAGE_HLEN + header_len) - \
+ SILC_PACKET_MAX_LEN) : data_len)
+
/* Channel Message Payload structure. Contents of this structure is parsed
from SILC packets. */
struct SilcChannelMessagePayloadStruct {
SilcMessageFlags flags;
SilcUInt16 data_len;
unsigned char *data;
+ SilcUInt16 pad_len;
+ unsigned char *pad;
unsigned char *mac;
unsigned char *iv;
};
/* Check the MAC of the message */
SILC_LOG_DEBUG(("Checking channel message MACs"));
- silc_hmac_make(hmac, dst, (data_len - iv_len - mac_len), mac2, &mac_len);
+ silc_hmac_init(hmac);
+ silc_hmac_update(hmac, dst, (data_len - iv_len - mac_len));
+ silc_hmac_update(hmac, data + (data_len - iv_len), iv_len);
+ silc_hmac_final(hmac, mac2, &mac_len);
if (memcmp(mac, mac2, mac_len)) {
SILC_LOG_DEBUG(("Channel message MACs does not match"));
silc_free(dst);
if (!newp)
return NULL;
- /* Parse the Channel Message Payload. Ignore the padding. */
+ /* Parse the Channel Message Payload. */
ret = silc_buffer_unformat(&buffer,
SILC_STR_UI_SHORT(&newp->flags),
SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
&newp->data_len),
- SILC_STR_UI16_NSTRING(NULL, NULL),
+ SILC_STR_UI16_NSTRING_ALLOC(&newp->pad,
+ &newp->pad_len),
SILC_STR_UI_XNSTRING(&newp->mac, mac_len),
SILC_STR_UI_XNSTRING(&newp->iv, iv_len),
SILC_STR_END);
return NULL;
}
+/* This function is used to encrypt the Channel Messsage Payload which is
+ the `data' and `data_len'. This is used internally by the Channel Message
+ Payload encoding routines but application may call this too if needed.
+ The `data_len' is the data lenght which is used to create MAC out of.
+ The `true_len' is the true length of `data' message payload and is used
+ assemble rest of the packet after MAC creation. The `true_len' length
+ packet will then be encrypted. */
+
+bool silc_channel_message_payload_encrypt(unsigned char *data,
+ SilcUInt32 data_len,
+ SilcUInt32 true_len,
+ unsigned char *iv,
+ SilcUInt32 iv_len,
+ SilcCipher cipher,
+ SilcHmac hmac)
+{
+ unsigned char mac[32];
+ SilcUInt32 mac_len;
+ SilcBufferStruct buf;
+
+ /* Compute the MAC of the channel message data */
+ silc_hmac_init(hmac);
+ silc_hmac_update(hmac, data, data_len);
+ silc_hmac_update(hmac, iv, iv_len);
+ silc_hmac_final(hmac, mac, &mac_len);
+
+ /* Put rest of the data to the payload */
+ silc_buffer_set(&buf, data, true_len);
+ silc_buffer_pull(&buf, data_len);
+ silc_buffer_format(&buf,
+ SILC_STR_UI_XNSTRING(mac, mac_len),
+ SILC_STR_UI_XNSTRING(iv, iv_len),
+ SILC_STR_END);
+
+ /* Encrypt payload of the packet. This is encrypted with the channel key. */
+ silc_cipher_encrypt(cipher, data, data, true_len - iv_len, iv);
+
+ memset(mac, 0, sizeof(mac));
+ return TRUE;
+}
+
/* Encodes channel message payload into a buffer and returns it. This is used
to add channel message payload into a packet. As the channel payload is
encrypted separately from other parts of the packet padding must
SilcBuffer buffer;
SilcUInt32 len, pad_len, mac_len;
unsigned char pad[16];
- unsigned char mac[32];
SILC_LOG_DEBUG(("Encoding channel message payload"));
/* Calculate length of padding. IV is not included into the calculation
since it is not encrypted. */
mac_len = silc_hmac_len(hmac);
+ data_len = SILC_CHANNEL_MESSAGE_DATALEN(data_len, mac_len + iv_len);
len = 6 + data_len + mac_len;
pad_len = SILC_CHANNEL_MESSAGE_PAD(len);
/* Generate padding */
if (rng) {
- for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte(rng);
+ for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
} else {
- for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte();
+ for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
}
/* Encode the Channel Message Payload */
SILC_STR_UI_XNSTRING(pad, pad_len),
SILC_STR_END);
- /* Compute the MAC of the channel message data */
- silc_hmac_make(hmac, buffer->data, buffer->len, mac, &mac_len);
-
- /* Put rest of the data to the payload */
- silc_buffer_pull_tail(buffer, mac_len + iv_len);
- silc_buffer_pull(buffer, 6 + data_len + pad_len);
- silc_buffer_format(buffer,
- SILC_STR_UI_XNSTRING(mac, mac_len),
- SILC_STR_UI_XNSTRING(iv, iv_len),
- SILC_STR_END);
- silc_buffer_push(buffer, 6 + data_len + pad_len);
+ memset(pad, 0, sizeof(pad));
- /* Encrypt payload of the packet. This is encrypted with the channel key. */
- silc_cipher_encrypt(cipher, buffer->data, buffer->data,
- buffer->len - iv_len, iv);
+ if (!silc_channel_message_payload_encrypt(buffer->data, buffer->len,
+ buffer->truelen, iv, iv_len,
+ cipher, hmac)) {
+ silc_buffer_free(buffer);
+ return NULL;
+ }
- memset(pad, 0, sizeof(pad));
- memset(mac, 0, sizeof(mac));
+ silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer) - buffer->len);
return buffer;
}