X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilccore%2Fsilcprivate.c;h=b90d01096dcdb058380b017fd0d56598f309b503;hb=cdedc07c65bab8467f6f5b1ef4b38982c2c77571;hp=67cb967b078c039c477cb4af05f687d5083ed7e0;hpb=2878ba34b8d864f89cfb785448e95cdd42297ee0;p=silc.git diff --git a/lib/silccore/silcprivate.c b/lib/silccore/silcprivate.c index 67cb967b..b90d0109 100644 --- a/lib/silccore/silcprivate.c +++ b/lib/silccore/silcprivate.c @@ -22,6 +22,7 @@ #include "silcincludes.h" #include "silcprivate.h" +#include "silcprivate_i.h" /****************************************************************************** @@ -29,67 +30,97 @@ ******************************************************************************/ -/* Calculates padding length for message payload */ -#define SILC_PRIVATE_MESSAGE_PAD(__payloadlen) (16 - ((__payloadlen) % 16)) - -/* Header length plus maximum padding length */ -#define SILC_PRIVATE_MESSAGE_HLEN 4 + 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_PRIVATE_MESSAGE_DATALEN(data_len) \ - ((data_len + SILC_PRIVATE_MESSAGE_HLEN) > SILC_PACKET_MAX_LEN ? \ - data_len - ((data_len + SILC_PRIVATE_MESSAGE_HLEN) - \ - SILC_PACKET_MAX_LEN) : data_len) - -/* Private Message Payload structure. Contents of this structure is parsed - from SILC packets. */ -struct SilcPrivateMessagePayloadStruct { - SilcUInt16 flags; - SilcUInt16 message_len; - unsigned char *message; -}; - /* Parses private message payload returning new private mesage payload structure. This also decrypts the message if the `cipher' is provided. */ SilcPrivateMessagePayload silc_private_message_payload_parse(unsigned char *payload, SilcUInt32 payload_len, - SilcCipher cipher) + SilcCipher cipher, + SilcHmac hmac) { SilcBufferStruct buffer; SilcPrivateMessagePayload newp; - int ret; + SilcUInt32 mac_len = 0, block_len, pad_len = 0; + unsigned char data[16], mac[32]; + int len, totlen; SILC_LOG_DEBUG(("Parsing private message payload")); silc_buffer_set(&buffer, payload, payload_len); - /* Decrypt the payload */ - if (cipher) - silc_cipher_decrypt(cipher, buffer.data, buffer.data, - buffer.len, silc_cipher_get_iv(cipher)); - newp = silc_calloc(1, sizeof(*newp)); if (!newp) return NULL; - /* Parse the Private Message Payload. Ignore the padding. */ - ret = silc_buffer_unformat(&buffer, + /* Decrypt the payload */ + if (cipher) { + /* Decrypt first block. This is to get the true length of the data in + payload. It is possible there is additional data after the message + payload with private messages. */ + block_len = silc_cipher_get_block_len(cipher); + if (block_len > buffer.len) + goto err; + silc_cipher_decrypt(cipher, buffer.data, data, block_len, + silc_cipher_get_iv(cipher)); + + /* Length of encrypted area */ + SILC_GET16_MSB(newp->message_len, data + 2); + totlen = 4 + newp->message_len; + pad_len = SILC_PRIVATE_MESSAGE_PAD(4 + newp->message_len); + totlen += pad_len; + + /* Sanity checks */ + if (totlen > buffer.len || newp->message_len < 1 || + newp->message_len > buffer.len - 4) { + SILC_LOG_DEBUG(("Incorrect private message payload in packet")); + goto err; + } + + /* Compute MAC for integrity check from the cipher text */ + if (hmac) { + SILC_LOG_DEBUG(("Checking private message MAC")); + silc_hmac_init(hmac); + silc_hmac_update(hmac, buffer.data, totlen); + silc_hmac_final(hmac, mac, &mac_len); + if (memcmp(mac, buffer.data + totlen, mac_len)) { + SILC_LOG_DEBUG(("Private message MAC does not match")); + goto err; + } + SILC_LOG_DEBUG(("MAC is Ok")); + } + + /* Now decrypt rest of the data */ + memcpy(buffer.data, data, block_len); + if (totlen - block_len > 0) + silc_cipher_decrypt(cipher, buffer.data + block_len, + buffer.data + block_len, totlen - block_len, + silc_cipher_get_iv(cipher)); + memset(data, 0, sizeof(data)); + } + + /* Parse the Private Message Payload. */ + len = silc_buffer_unformat(&buffer, SILC_STR_UI_SHORT(&newp->flags), SILC_STR_UI16_NSTRING_ALLOC(&newp->message, &newp->message_len), SILC_STR_END); - if (ret == -1) { - SILC_LOG_DEBUG(("Incorrect private message payload")); + if (len == -1 || newp->message_len < 1 || + newp->message_len > buffer.len - 4) { + SILC_LOG_DEBUG(("Incorrect private message payload in packet")); goto err; } - if ((newp->message_len < 1 || newp->message_len > buffer.len - 4)) { - SILC_LOG_DEBUG(("Incorrect private message payload in packet, " - "packet dropped")); - goto err; + /* Parse also padding and MAC */ + if (cipher) { + silc_buffer_pull(&buffer, 4 + newp->message_len); + len = silc_buffer_unformat(&buffer, + SILC_STR_UI_XNSTRING_ALLOC(&newp->pad, + pad_len), + SILC_STR_UI_XNSTRING_ALLOC(&newp->mac, + mac_len), + SILC_STR_END); + silc_buffer_push(&buffer, 4 + newp->message_len); } return newp; @@ -107,12 +138,13 @@ SilcBuffer silc_private_message_payload_encode(SilcUInt16 flags, SilcUInt16 data_len, const unsigned char *data, SilcCipher cipher, + SilcHmac hmac, SilcRng rng) { int i; SilcBuffer buffer; - SilcUInt32 len, pad_len = 0; - unsigned char pad[16]; + SilcUInt32 len, pad_len = 0, mac_len = 0; + unsigned char pad[16], mac[32]; SILC_LOG_DEBUG(("Encoding private message payload")); @@ -123,9 +155,15 @@ SilcBuffer silc_private_message_payload_encode(SilcUInt16 flags, /* Calculate length of padding. */ pad_len = SILC_PRIVATE_MESSAGE_PAD(len); len += pad_len; + mac_len = hmac ? silc_hmac_len(hmac) : 0; + len += mac_len; /* Generate padding */ - for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte(); + if (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_fast(); + } } /* Allocate private message payload buffer */ @@ -144,8 +182,17 @@ SilcBuffer silc_private_message_payload_encode(SilcUInt16 flags, if (cipher) { /* Encrypt payload of the packet. */ silc_cipher_encrypt(cipher, buffer->data, buffer->data, - buffer->len, silc_cipher_get_iv(cipher)); + buffer->len - mac_len, silc_cipher_get_iv(cipher)); memset(pad, 0, sizeof(pad)); + + /* Compute MAC from the ciphertext */ + if (hmac) { + silc_hmac_init(hmac); + silc_hmac_update(hmac, buffer->data, buffer->len - mac_len); + silc_hmac_final(hmac, mac, &mac_len); + memcpy(buffer->data + (buffer->len - mac_len), mac, mac_len); + memset(mac, 0, sizeof(mac)); + } } return buffer; @@ -181,3 +228,11 @@ silc_private_message_get_message(SilcPrivateMessagePayload payload, return payload->message; } + +/* Return MAC. Caller knows its length */ + +unsigned char * +silc_private_message_get_mac(SilcPrivateMessagePayload payload) +{ + return payload->mac; +}