+ SilcChannelPrivateKey entry;
+ unsigned char hash[32];
+ SilcSKEKeyMaterial *keymat;
+
+ if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
+ return FALSE;
+
+ if (!cipher)
+ cipher = SILC_DEFAULT_CIPHER;
+ if (!hmac)
+ hmac = SILC_DEFAULT_HMAC;
+
+ if (!silc_cipher_is_supported(cipher))
+ 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->internal->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);
+ memset(channel->key, 0, channel->key_len / 8);
+ silc_free(channel->key);
+ channel->channel_key = NULL;
+ channel->key = NULL;
+ channel->key_len = 0;
+ }
+ 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_memdup(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, 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(silc_hmac_get_hash(entry->hmac), entry->key,
+ entry->key_len, hash);
+ silc_hmac_set_key(entry->hmac, hash,
+ silc_hash_len(silc_hmac_get_hash(entry->hmac)));
+ memset(hash, 0, sizeof(hash));
+
+ /* Add to the private keys list */
+ silc_dlist_add(channel->private_keys, entry);
+
+ if (!channel->curr_key)
+ channel->curr_key = entry;
+
+ /* Free the key material */
+ silc_ske_free_key_material(keymat);