SilcClientConnection conn,
SilcChannelEntry channel,
SilcChannelPrivateKey key,
+ SilcMessageFlags flags,
unsigned char *data,
- unsigned int data_len,
+ uint32 data_len,
int force_send)
{
int i;
SilcCipher cipher;
SilcHmac hmac;
unsigned char *id_string;
- unsigned int iv_len;
+ uint32 iv_len;
SILC_LOG_DEBUG(("Sending packet to channel"));
- if (!channel || !channel->hmac ||
- (!channel->channel_key && !key && !channel->private_keys)) {
- client->ops->say(client, conn,
- "Cannot talk to channel: key does not exist");
- return;
- }
-
/* Take the key to be used */
- if (key) {
- /* Use key application specified */
- cipher = key->cipher;
- hmac = key->hmac;
- } else if (channel->curr_key) {
- /* Use current private key */
- cipher = channel->curr_key->cipher;
- hmac = channel->curr_key->hmac;
- } else if (!channel->curr_key && channel->private_keys) {
- /* Use just some private key since we don't know what to use
- and private keys are set. */
- silc_dlist_start(channel->private_keys);
- key = silc_dlist_get(channel->private_keys);
- cipher = key->cipher;
- hmac = key->hmac;
-
- /* Use this key as current private key */
- channel->curr_key = key;
+ if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
+ if (key) {
+ /* Use key application specified */
+ cipher = key->cipher;
+ hmac = key->hmac;
+ } else if (channel->curr_key) {
+ /* Use current private key */
+ cipher = channel->curr_key->cipher;
+ hmac = channel->curr_key->hmac;
+ } else if (!channel->curr_key && channel->private_keys) {
+ /* Use just some private key since we don't know what to use
+ and private keys are set. */
+ silc_dlist_start(channel->private_keys);
+ key = silc_dlist_get(channel->private_keys);
+ cipher = key->cipher;
+ hmac = key->hmac;
+
+ /* Use this key as current private key */
+ channel->curr_key = key;
+ } else {
+ /* Use normal channel key generated by the server */
+ cipher = channel->channel_key;
+ hmac = channel->hmac;
+ }
} else {
/* Use normal channel key generated by the server */
cipher = channel->channel_key;
hmac = channel->hmac;
}
+ if (!cipher || !hmac)
+ return;
+
/* Generate IV */
iv_len = silc_cipher_get_block_len(cipher);
if (channel->iv[0] == '\0')
silc_hash_make(client->md5hash, channel->iv, iv_len, channel->iv);
/* Encode the channel payload. This also encrypts the message payload. */
- payload = silc_channel_payload_encode(data_len, data, iv_len,
- channel->iv, cipher, hmac,
- client->rng);
+ payload = silc_channel_message_payload_encode(flags, data_len, data, iv_len,
+ channel->iv, cipher, hmac);
/* Get data used in packet header encryption, keys and stuff. */
cipher = conn->send_key;
{
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
SilcBuffer buffer = packet->buffer;
- SilcChannelPayload payload = NULL;
+ SilcChannelMessagePayload payload = NULL;
SilcChannelID *id = NULL;
SilcChannelEntry channel;
SilcChannelUser chu;
/* If there is no channel private key then just decrypt the message
with the channel key. If private keys are set then just go through
all private keys and check what decrypts correctly. */
- if (!channel->private_keys) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
/* Parse the channel message payload. This also decrypts the payload */
- payload = silc_channel_payload_parse(buffer, channel->channel_key,
- channel->hmac);
+ payload = silc_channel_message_payload_parse(buffer, channel->channel_key,
+ channel->hmac);
if (!payload)
goto out;
- } else {
+ } else if (channel->private_keys) {
SilcChannelPrivateKey entry;
silc_dlist_start(channel->private_keys);
while ((entry = silc_dlist_get(channel->private_keys)) != SILC_LIST_END) {
/* Parse the channel message payload. This also decrypts the payload */
- payload = silc_channel_payload_parse(buffer, entry->cipher,
- entry->hmac);
+ payload = silc_channel_message_payload_parse(buffer, entry->cipher,
+ entry->hmac);
if (payload)
break;
}
if (entry == SILC_LIST_END)
goto out;
+ } else {
+ goto out;
}
- message = silc_channel_get_data(payload, NULL);
+ message = silc_channel_message_get_data(payload, NULL);
/* Find client entry */
silc_list_start(channel->clients);
/* Pass the message to application */
client->ops->channel_message(client, conn, found ? chu->client : NULL,
- channel, message);
+ channel,
+ silc_channel_message_get_flags(payload),
+ message);
out:
if (id)
if (client_id)
silc_free(client_id);
if (payload)
- silc_channel_payload_free(payload);
+ silc_channel_message_payload_free(payload);
}
/* Saves channel key from encoded `key_payload'. This is used when we
SilcChannelEntry channel)
{
unsigned char *id_string, *key, *cipher, hash[32];
- unsigned int tmp_len;
+ uint32 tmp_len;
SilcChannelID *id;
SilcIDCacheEntry id_cache = NULL;
SilcChannelKeyPayload payload;
silc_hmac_set_key(channel->hmac, hash, silc_hash_len(channel->hmac->hash));
memset(hash, 0, sizeof(hash));
- /* Client is now joined to the channel */
- channel->on_channel = TRUE;
-
out:
silc_free(id);
silc_channel_key_payload_free(payload);
several private keys per one channel. In this case only some of the
clients on the channel may know the one key and only some the other key.
- if `cipher' and/or `hmac' is NULL then default values will be used
+ If `cipher' and/or `hmac' is NULL then default values will be used
(aes-256-cbc for cipher and hmac-sha1-96 for hmac).
The private key for channel is optional. If it is not set then the
char *cipher,
char *hmac,
unsigned char *key,
- unsigned int key_len)
+ uint32 key_len)
{
SilcChannelPrivateKey entry;
unsigned char hash[32];
+ SilcSKEKeyMaterial *keymat;
if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
return FALSE;
if (!silc_hmac_is_supported(hmac))
return FALSE;
+ /* Produce the key material */
+ keymat = silc_calloc(1, sizeof(*keymat));
+ if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
+ client->md5hash, keymat)
+ != SILC_SKE_STATUS_OK)
+ return FALSE;
+
/* Remove the current key, if it exists. */
if (channel->channel_key) {
silc_cipher_free(channel->channel_key);
channel->key = NULL;
channel->key_len = 0;
}
- if (channel->hmac)
+ if (channel->hmac) {
silc_hmac_free(channel->hmac);
+ channel->hmac = NULL;
+ }
if (!channel->private_keys)
channel->private_keys = silc_dlist_init();
/* Save the key */
entry = silc_calloc(1, sizeof(*entry));
- entry->key = silc_calloc(key_len, sizeof(*entry->key));
- memcpy(entry->key, key, key_len);
- entry->key_len = key_len;
+ entry->key = silc_calloc(keymat->enc_key_len / 8, sizeof(*entry->key));
+ memcpy(entry->key, keymat->send_enc_key, keymat->enc_key_len / 8);
+ entry->key_len = keymat->enc_key_len / 8;
/* Allocate the cipher and set the key*/
silc_cipher_alloc(cipher, &entry->cipher);
- silc_cipher_set_key(entry->cipher, key, key_len * 8);
+ silc_cipher_set_key(entry->cipher, entry->key, keymat->enc_key_len);
/* Generate HMAC key from the channel key data and set it */
silc_hmac_alloc(hmac, NULL, &entry->hmac);
- silc_hash_make(entry->hmac->hash, key, key_len, hash);
+ silc_hash_make(entry->hmac->hash, entry->key, entry->key_len, hash);
silc_hmac_set_key(entry->hmac, hash, silc_hash_len(entry->hmac->hash));
memset(hash, 0, sizeof(hash));
if (!channel->curr_key)
channel->curr_key = entry;
+ /* Free the key material */
+ silc_ske_free_key_material(keymat);
+
return TRUE;
}
silc_client_list_channel_private_keys(SilcClient client,
SilcClientConnection conn,
SilcChannelEntry channel,
- unsigned int *key_count)
+ uint32 *key_count)
{
SilcChannelPrivateKey *keys = NULL, entry;
- unsigned int count = 0;
+ uint32 count = 0;
if (!channel->private_keys)
return NULL;
/* Frees the SilcChannelPrivateKey array. */
void silc_client_free_channel_private_keys(SilcChannelPrivateKey *keys,
- unsigned int key_count)
+ uint32 key_count)
{
silc_free(keys);
}