Example #1
0
SilcBool silc_client_del_private_message_key(SilcClient client,
					     SilcClientConnection conn,
					     SilcClientEntry client_entry)
{
  if (!client || !client_entry)
    return FALSE;

  if (!client_entry->internal.send_key && !client_entry->internal.receive_key)
    return FALSE;

  silc_cipher_free(client_entry->internal.send_key);
  silc_cipher_free(client_entry->internal.receive_key);

  if (client_entry->internal.key) {
    memset(client_entry->internal.key, 0, client_entry->internal.key_len);
    silc_free(client_entry->internal.key);
  }

  client_entry->internal.send_key = NULL;
  client_entry->internal.receive_key = NULL;
  client_entry->internal.key = NULL;
  client_entry->internal.prv_resp = FALSE;

  return TRUE;
}
Example #2
0
int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
{
  if (entry) {
    /* Remove from cache */
    if (!silc_idcache_del_by_context(id_list->channels, entry, NULL)) {
      SILC_LOG_DEBUG(("Unknown channel, did not delete"));
      return FALSE;
    }

    SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name));

    /* Free all client entrys from the users list. The silc_hash_table_free
       will free all the entries so they are not freed at the foreach
       callback. */
    silc_hash_table_foreach(entry->user_list, silc_idlist_del_channel_foreach,
			    NULL);
    silc_hash_table_free(entry->user_list);

    /* Free data */
    silc_free(entry->channel_name);
    silc_free(entry->id);
    silc_free(entry->topic);

    if (entry->invite_list)
      silc_hash_table_free(entry->invite_list);
    if (entry->ban_list)
      silc_hash_table_free(entry->ban_list);

    if (entry->send_key)
      silc_cipher_free(entry->send_key);
    if (entry->receive_key)
      silc_cipher_free(entry->receive_key);
    if (entry->key) {
      memset(entry->key, 0, entry->key_len / 8);
      silc_free(entry->key);
    }
    silc_free(entry->cipher);
    if (entry->hmac)
      silc_hmac_free(entry->hmac);
    silc_free(entry->hmac_name);
    silc_free(entry->rekey);
    if (entry->founder_key)
      silc_pkcs_public_key_free(entry->founder_key);
    if (entry->channel_pubkeys)
      silc_hash_table_free(entry->channel_pubkeys);

    memset(entry, 'F', sizeof(*entry));
    silc_free(entry);
    return TRUE;
  }

  return FALSE;
}
Example #3
0
int main(int argc, char **argv)
{
  SilcUInt64 sec;
  SilcUInt32 usec;
  double totsec;
  unsigned char *data;
  SilcUInt32 rounds;
  SilcUInt32 i, k;

  data = malloc(ENC_LEN * sizeof(*data));
  if (!data)
    exit(1);

  for (i = 0; i < ENC_LEN; i++)
    data[i] = i % 255;

  silc_timer_synchronize(&timer);

  for (i = 0; silc_default_ciphers[i].name; i++) {
    if (!silc_cipher_alloc(silc_default_ciphers[i].name, &cipher)) {
      fprintf(stderr, "Error allocating %s\n", silc_default_ciphers[i].name);
      exit(1);
    }

    silc_cipher_set_key(cipher, data, silc_cipher_get_key_len(cipher), TRUE);
    silc_cipher_set_iv(cipher, data);

    rounds = ENC_ROUND;

  retry:
    silc_timer_start(&timer);
    for (k = 0; k < rounds; k++)
      silc_cipher_encrypt(cipher, data, data, ENC_LEN, NULL);
    silc_timer_stop(&timer);

    silc_timer_value(&timer, &sec, &usec);
    totsec = (double)sec;
    totsec += ((double)usec / (double)(1000 * 1000));
    if (totsec < ENC_MIN_TIME) {
      rounds += rounds;
      goto retry;
    }

    printf("%s:\t%.2f KB (%.2f MB) / sec (total test time %.2f secs)\n",
	   silc_default_ciphers[i].name,
	   (((double)(ENC_LEN * rounds) / 1024.0) / totsec),
	   (((double)(ENC_LEN * rounds) / (1024.0 * 1024.0)) / totsec),
	   totsec);

    silc_cipher_free(cipher);
  }

  return 0;
}
Example #4
0
SilcBool silc_client_del_channel_private_key(SilcClient client,
					     SilcClientConnection conn,
					     SilcChannelEntry channel,
					     SilcChannelPrivateKey key)
{
  SilcChannelPrivateKey entry;

  if (!client || !conn || !channel)
    return FALSE;

  if (!channel->internal.private_keys)
    return FALSE;

  silc_dlist_start(channel->internal.private_keys);
  while ((entry = silc_dlist_get(channel->internal.private_keys))) {
    if (entry != key)
      continue;

    if (channel->internal.curr_key == entry) {
      channel->internal.curr_key = NULL;
      channel->cipher = silc_cipher_get_name(channel->internal.send_key);
      channel->hmac = silc_hmac_get_name(channel->internal.hmac);
    }

    silc_dlist_del(channel->internal.private_keys, entry);
    silc_free(entry->name);
    silc_cipher_free(entry->send_key);
    silc_cipher_free(entry->receive_key);
    silc_hmac_free(entry->hmac);
    silc_free(entry);

    if (silc_dlist_count(channel->internal.private_keys) == 0) {
      silc_dlist_uninit(channel->internal.private_keys);
      channel->internal.private_keys = NULL;
    }

    return TRUE;
  }

  return FALSE;
}
Example #5
0
static SILC_TASK_CALLBACK(silc_softacc_cipher_completion)
{
  SilcSoftaccCipher c = context;
  int i;

  /* Disconnect from key stream queue */
  if (silc_thread_queue_disconnect(c->queue))
    return;

  silc_cipher_free(c->c.ecb);
  for (i = 0; i < c->num_key_stream; i++)
    silc_free(c->key_stream[i]);
  silc_free(c->key_stream);
  memset(c, 0, sizeof(*c));
  silc_free(c);
}
int main(int argc, char **argv)
{
  SilcUInt64 sec;
  SilcUInt32 usec;
  double totsec;
  unsigned char *data;
  SilcUInt32 rounds;
  SilcUInt32 i, k;

  silc_runtime_init();
  silc_crypto_init(NULL);

#if 0
  silc_log_debug(TRUE);
  silc_log_quick(TRUE);
  silc_log_debug_hexdump(TRUE);
  silc_log_set_debug_string("*acc*,*thread*");
#endif

  if (!silc_acc_init(SILC_SOFTACC, (void *)0x01, "min_threads", 2,
		     "max_threads", 8, NULL))
    exit(1);

  data = malloc(ENC_LEN * sizeof(*data));
  if (!data)
    exit(1);

  for (i = 0; i < ENC_LEN; i++)
    data[i] = i % 255;

  silc_timer_synchronize(&timer);

  for (i = 0; silc_default_ciphers[i].name; i++) {
    if (!silc_cipher_alloc(silc_default_ciphers[i].name, &cipher)) {
      fprintf(stderr, "Error allocating %s\n", silc_default_ciphers[i].name);
      exit(1);
    }

    acc_cipher = silc_acc_cipher(SILC_SOFTACC, cipher);
    if (!acc_cipher)
      continue;

    silc_cipher_set_iv(acc_cipher, data);
    silc_cipher_set_key(acc_cipher, data, silc_cipher_get_key_len(cipher),
			TRUE);
    sleep(1);

    rounds = ENC_ROUND;

  retry:
    silc_timer_start(&timer);
    for (k = 0; k < rounds; k++)
      silc_cipher_encrypt(acc_cipher, data, data, ENC_LEN, NULL);
    silc_timer_stop(&timer);

    silc_timer_value(&timer, &sec, &usec);
    totsec = (double)sec;
    totsec += ((double)usec / (double)((double)1000 * (double)1000));
    if (totsec < ENC_MIN_TIME) {
      rounds += rounds;
      goto retry;
    }

    silc_cipher_free(acc_cipher);
    silc_cipher_free(cipher);

    sleep(1);
    printf("%s:\t%.2f KB (%.2f MB, %.2f Mbit) / sec (total %.3f secs)\n",
	   silc_default_ciphers[i].name,
	   (((double)((double)ENC_LEN * (double)rounds) / 1024.0) / totsec),
	   (((double)((double)ENC_LEN * (double)rounds) / (1024.0 *
							   1024.0)) / totsec),
	   ((((double)((double)ENC_LEN * (double)rounds) / 1024.0)
	     / 128.0) / totsec),
	   totsec);
  }

  silc_acc_uninit(SILC_SOFTACC);

  silc_crypto_uninit();
  silc_runtime_uninit();

  return 0;
}
Example #7
0
int main(int argc, char **argv)
{
  SilcBool success = FALSE;
  SilcMessagePayload message;
  SilcBuffer buf;
  const char *msg = "FOOBAR MESSAGE";
  unsigned char *data, tmp[1023], *tmp2;
  SilcUInt32 data_len;
  SilcUInt16 flags;
  int i, n;

  if (argc > 1 && !strcmp(argv[1], "-d")) {
    silc_log_debug(TRUE);
    silc_log_debug_hexdump(TRUE);
    silc_log_set_debug_string("*message*");
  }

  silc_cipher_register_default();
  silc_hash_register_default();
  silc_hmac_register_default();
  silc_pkcs_register_default();

  SILC_LOG_DEBUG(("Load keypair"));
  if (!silc_load_key_pair("pubkey.pub", "privkey.prv", "",
			  &public_key, &private_key)) {
    SILC_LOG_DEBUG(("Create keypair"));
    if (!silc_create_key_pair("rsa", 2048, "pubkey.pub", "privkey.prv",
			      NULL, "", &public_key, &private_key, FALSE))
      goto err;
  }

  SILC_LOG_DEBUG(("Alloc RNG"));
  rng = silc_rng_alloc();
  silc_rng_init(rng);

  SILC_LOG_DEBUG(("Alloc AES"));
  if (!silc_cipher_alloc("aes-128-cbc", &key))
    goto err;

  SILC_LOG_DEBUG(("Alloc SHA-256"));
  if (!silc_hash_alloc("sha256", &hash))
    goto err;

  SILC_LOG_DEBUG(("Alloc HMAC"));
  if (!silc_hmac_alloc("hmac-sha256-96", hash, &hmac))
    goto err;

  SILC_LOG_DEBUG(("Set static key: '1234567890123456'"));
  if (!silc_cipher_set_key(key, "1234567890123456", 16 * 8))
    goto err;
  SILC_LOG_DEBUG(("Set HMAC key: '1234567890123456'"));
  silc_hmac_set_key(hmac, "1234567890123456", 16);

  /* Simple private message */
  SILC_LOG_DEBUG(("Encoding private message len %d (static key)",
		  strlen(msg)));
  buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION |
				    SILC_MESSAGE_FLAG_UTF8 |
				    SILC_MESSAGE_FLAG_ACK,
				    msg, strlen(msg), TRUE, TRUE,
				    key, hmac, rng, NULL, NULL, NULL, NULL);
  if (!buf)
    goto err;
  SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf));
  SILC_LOG_DEBUG(("Parsing private messsage (static key)"));
  message = silc_message_payload_parse(silc_buffer_data(buf),
				       silc_buffer_len(buf), TRUE, TRUE,
				       key, hmac, NULL, FALSE, NULL);
  if (!message)
    goto err;
  flags = silc_message_get_flags(message);
  SILC_LOG_DEBUG(("Flags: %x", flags));
  if (!(flags & SILC_MESSAGE_FLAG_ACTION))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_UTF8))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_ACK))
    goto err;
  data = silc_message_get_data(message, &data_len);
  SILC_LOG_HEXDUMP(("Data"), data, data_len);
  if (data_len != strlen(msg) || memcmp(data, msg, strlen(msg)))
    goto err;
  SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message),
		   silc_hmac_len(hmac));
  silc_message_payload_free(message);

  /* Simple private message */
  n = 10;
  SILC_LOG_DEBUG(("Encoding private message len %d (static key)", n));
  buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION |
				    SILC_MESSAGE_FLAG_UTF8 |
				    SILC_MESSAGE_FLAG_ACK,
				    msg, n, TRUE, TRUE,
				    key, hmac, rng, NULL, NULL, NULL, buf);
  if (!buf)
    goto err;
  SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf));
  SILC_LOG_DEBUG(("Parsing private messsage (static key)"));
  message = silc_message_payload_parse(silc_buffer_data(buf),
				       silc_buffer_len(buf), TRUE, TRUE,
				       key, hmac, NULL, FALSE, NULL);
  if (!message)
    goto err;
  flags = silc_message_get_flags(message);
  SILC_LOG_DEBUG(("Flags: %x", flags));
  if (!(flags & SILC_MESSAGE_FLAG_ACTION))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_UTF8))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_ACK))
    goto err;
  data = silc_message_get_data(message, &data_len);
  SILC_LOG_HEXDUMP(("Data"), data, data_len);
  if (data_len != n || memcmp(data, msg, n))
    goto err;
  SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message),
		   silc_hmac_len(hmac));
  silc_message_payload_free(message);

  /* Simple private message */
  n = 1;
  SILC_LOG_DEBUG(("Encoding private message len %d (static key)", n));
  buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION |
				    SILC_MESSAGE_FLAG_UTF8 |
				    SILC_MESSAGE_FLAG_ACK,
				    msg, n, TRUE, TRUE,
				    key, hmac, rng, NULL, NULL, NULL, buf);
  if (!buf)
    goto err;
  SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf));
  SILC_LOG_DEBUG(("Parsing private messsage (static key)"));
  message = silc_message_payload_parse(silc_buffer_data(buf),
				       silc_buffer_len(buf), TRUE, TRUE,
				       key, hmac, NULL, FALSE, NULL);
  if (!message)
    goto err;
  flags = silc_message_get_flags(message);
  SILC_LOG_DEBUG(("Flags: %x", flags));
  if (!(flags & SILC_MESSAGE_FLAG_ACTION))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_UTF8))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_ACK))
    goto err;
  data = silc_message_get_data(message, &data_len);
  SILC_LOG_HEXDUMP(("Data"), data, data_len);
  if (data_len != n || memcmp(data, msg, n))
    goto err;
  SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message),
		   silc_hmac_len(hmac));
  silc_message_payload_free(message);

  /* Simple private message */
  for (i = 0; i < sizeof(tmp); i++)
    tmp[i] = (32 + i) & 127;
  SILC_LOG_DEBUG(("Encoding private message len %d (static key)",
		  sizeof(tmp)));
  buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION |
				    SILC_MESSAGE_FLAG_UTF8 |
				    SILC_MESSAGE_FLAG_ACK,
				    tmp, sizeof(tmp), TRUE, TRUE,
				    key, hmac, rng, NULL, NULL, NULL, buf);
  if (!buf)
    goto err;
  SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf));
  SILC_LOG_DEBUG(("Parsing private messsage (static key)"));
  message = silc_message_payload_parse(silc_buffer_data(buf),
				       silc_buffer_len(buf), TRUE, TRUE,
				       key, hmac, NULL, FALSE, NULL);
  if (!message)
    goto err;
  flags = silc_message_get_flags(message);
  SILC_LOG_DEBUG(("Flags: %x", flags));
  if (!(flags & SILC_MESSAGE_FLAG_ACTION))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_UTF8))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_ACK))
    goto err;
  data = silc_message_get_data(message, &data_len);
  SILC_LOG_HEXDUMP(("Data"), data, data_len);
  if (data_len != sizeof(tmp) || memcmp(data, tmp, sizeof(tmp)))
    goto err;
  SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message),
		   silc_hmac_len(hmac));
  silc_message_payload_free(message);

  /* Digitally signed private message */
  for (i = 0; i < sizeof(tmp); i++)
    tmp[i] = (32 + i) & 127;
  SILC_LOG_DEBUG(("Encoding private message len %d (static key) SIGNED",
		  sizeof(tmp)));
  buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION |
				    SILC_MESSAGE_FLAG_UTF8 |
				    SILC_MESSAGE_FLAG_ACK |
				    SILC_MESSAGE_FLAG_SIGNED,
				    tmp, sizeof(tmp), TRUE, TRUE,
				    key, hmac, rng,
				    public_key, private_key, hash, buf);
  if (!buf)
    goto err;
  SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf));
  SILC_LOG_DEBUG(("Parsing private messsage (static key)"));
  message = silc_message_payload_parse(silc_buffer_data(buf),
				       silc_buffer_len(buf), TRUE, TRUE,
				       key, hmac, NULL, FALSE, NULL);
  if (!message)
    goto err;
  flags = silc_message_get_flags(message);
  SILC_LOG_DEBUG(("Flags: %x", flags));
  if (!(flags & SILC_MESSAGE_FLAG_ACTION))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_UTF8))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_ACK))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_SIGNED))
    goto err;
  data = silc_message_get_data(message, &data_len);
  SILC_LOG_HEXDUMP(("Data"), data, data_len);
  if (data_len != sizeof(tmp) || memcmp(data, tmp, sizeof(tmp)))
    goto err;
  SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message),
		   silc_hmac_len(hmac));
  SILC_LOG_DEBUG(("Verifying signature"));
  if (silc_message_signed_verify(message, public_key, hash) !=
      SILC_AUTH_OK)
    goto err;
  SILC_LOG_DEBUG(("Signature Ok"));
  SILC_LOG_DEBUG(("Get public key"));
  pk2 = silc_message_signed_get_public_key(message, NULL, NULL);
  if (!pk2)
    goto err;
  SILC_LOG_DEBUG(("Verify public key"));
  if (!silc_pkcs_public_key_compare(public_key, pk2))
    goto err;
  SILC_LOG_DEBUG(("Public key Ok"));
  silc_pkcs_public_key_free(pk2);
  silc_message_payload_free(message);

  /* Digitally signed channel message */
  for (i = 0; i < sizeof(tmp) / 2; i++)
    tmp[i] = (32 + i) & 127;
  SILC_LOG_DEBUG(("Encoding channel message len %d (static key) SIGNED",
		  sizeof(tmp) / 2));
  buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION |
				    SILC_MESSAGE_FLAG_UTF8 |
				    SILC_MESSAGE_FLAG_ACK |
				    SILC_MESSAGE_FLAG_SIGNED,
				    tmp, sizeof(tmp) / 2, TRUE, FALSE,
				    key, hmac, rng,
				    public_key, private_key, hash, buf);
  if (!buf)
    goto err;
  SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf));
  SILC_LOG_DEBUG(("Parsing channel messsage (static key)"));
  message = silc_message_payload_parse(silc_buffer_data(buf),
				       silc_buffer_len(buf), FALSE, TRUE,
				       key, hmac, NULL, FALSE, NULL);
  if (!message)
    goto err;
  flags = silc_message_get_flags(message);
  SILC_LOG_DEBUG(("Flags: %x", flags));
  if (!(flags & SILC_MESSAGE_FLAG_ACTION))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_UTF8))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_ACK))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_SIGNED))
    goto err;
  data = silc_message_get_data(message, &data_len);
  SILC_LOG_HEXDUMP(("Data"), data, data_len);
  if (data_len != sizeof(tmp) / 2 || memcmp(data, tmp, sizeof(tmp) / 2))
    goto err;
  SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message),
		   silc_hmac_len(hmac));
  SILC_LOG_DEBUG(("Verifying signature"));
  if (silc_message_signed_verify(message, public_key, hash) !=
      SILC_AUTH_OK)
    goto err;
  SILC_LOG_DEBUG(("Signature Ok"));
  SILC_LOG_DEBUG(("Get public key"));
  pk2 = silc_message_signed_get_public_key(message, NULL, NULL);
  if (!pk2)
    goto err;
  SILC_LOG_DEBUG(("Verify public key"));
  if (!silc_pkcs_public_key_compare(public_key, pk2))
    goto err;
  SILC_LOG_DEBUG(("Public key Ok"));
  silc_pkcs_public_key_free(pk2);
  silc_message_payload_free(message);

  /* Digitally signed private message (no encryption) */
  for (i = 0; i < sizeof(tmp) / 2; i++)
    tmp[i] = (32 + i) & 127;
  SILC_LOG_DEBUG(("Encoding private message len %d SIGNED",
		  sizeof(tmp) / 2));
  buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION |
				    SILC_MESSAGE_FLAG_UTF8 |
				    SILC_MESSAGE_FLAG_ACK |
				    SILC_MESSAGE_FLAG_SIGNED,
				    tmp, sizeof(tmp) / 2, FALSE, TRUE,
				    NULL, NULL, rng,
				    public_key, private_key, hash, buf);
  if (!buf)
    goto err;
  SILC_LOG_HEXDUMP(("message"), buf->data, silc_buffer_len(buf));
  SILC_LOG_DEBUG(("Parsing private messsage (static key)"));
  message = silc_message_payload_parse(silc_buffer_data(buf),
				       silc_buffer_len(buf), TRUE, FALSE,
				       NULL, NULL, NULL, FALSE, NULL);
  if (!message)
    goto err;
  flags = silc_message_get_flags(message);
  SILC_LOG_DEBUG(("Flags: %x", flags));
  if (!(flags & SILC_MESSAGE_FLAG_ACTION))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_UTF8))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_ACK))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_SIGNED))
    goto err;
  data = silc_message_get_data(message, &data_len);
  SILC_LOG_HEXDUMP(("Data"), data, data_len);
  if (data_len != sizeof(tmp) / 2 || memcmp(data, tmp, sizeof(tmp) / 2))
    goto err;
  SILC_LOG_DEBUG(("Verifying signature"));
  if (silc_message_signed_verify(message, public_key, hash) !=
      SILC_AUTH_OK)
    goto err;
  SILC_LOG_DEBUG(("Signature Ok"));
  SILC_LOG_DEBUG(("Get public key"));
  pk2 = silc_message_signed_get_public_key(message, NULL, NULL);
  if (!pk2)
    goto err;
  SILC_LOG_DEBUG(("Verify public key"));
  if (!silc_pkcs_public_key_compare(public_key, pk2))
    goto err;
  SILC_LOG_DEBUG(("Public key Ok"));
  silc_pkcs_public_key_free(pk2);
  silc_message_payload_free(message);

  /* Digitally signed channel message (LARGE) */
  n = 65550;
  tmp2 = silc_malloc(n);
  if (!tmp2)
    goto err;
  SILC_LOG_DEBUG(("Encoding channel message len %d (static key) SIGNED LARGE",
		  n));
  buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION |
				    SILC_MESSAGE_FLAG_UTF8 |
				    SILC_MESSAGE_FLAG_ACK |
				    SILC_MESSAGE_FLAG_SIGNED,
				    tmp2, n, TRUE, FALSE,
				    key, hmac, rng,
				    public_key, private_key, hash, buf);
  if (!buf)
    goto err;
  SILC_LOG_DEBUG(("Message length: %d", silc_buffer_len(buf)));
  if (silc_buffer_len(buf) > SILC_PACKET_MAX_LEN)
    goto err;
  SILC_LOG_DEBUG(("Parsing channel messsage (static key)"));
  message = silc_message_payload_parse(silc_buffer_data(buf),
				       silc_buffer_len(buf), FALSE, TRUE,
				       key, hmac, NULL, FALSE, NULL);
  if (!message)
    goto err;
  flags = silc_message_get_flags(message);
  SILC_LOG_DEBUG(("Flags: %x", flags));
  if (!(flags & SILC_MESSAGE_FLAG_ACTION))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_UTF8))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_ACK))
    goto err;
  if (!(flags & SILC_MESSAGE_FLAG_SIGNED))
    goto err;
  data = silc_message_get_data(message, &data_len);
  SILC_LOG_DEBUG(("Data len: %d", data_len));
  if (silc_buffer_len(buf) > SILC_PACKET_MAX_LEN)
    goto err;
  SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message),
		   silc_hmac_len(hmac));
  SILC_LOG_DEBUG(("Verifying signature"));
  if (silc_message_signed_verify(message, public_key, hash) !=
      SILC_AUTH_OK)
    goto err;
  SILC_LOG_DEBUG(("Signature Ok"));
  SILC_LOG_DEBUG(("Get public key"));
  pk2 = silc_message_signed_get_public_key(message, NULL, NULL);
  if (!pk2)
    goto err;
  SILC_LOG_DEBUG(("Verify public key"));
  if (!silc_pkcs_public_key_compare(public_key, pk2))
    goto err;
  SILC_LOG_DEBUG(("Public key Ok"));
  silc_pkcs_public_key_free(pk2);
  silc_message_payload_free(message);
  silc_free(tmp2);


  success = TRUE;
  SILC_LOG_DEBUG(("Cleanup"));
  silc_pkcs_public_key_free(public_key);
  silc_pkcs_private_key_free(private_key);
  silc_cipher_free(key);
  silc_hash_free(hash);
  silc_rng_free(rng);

 err:
  silc_cipher_unregister_all();
  silc_hash_unregister_all();
  silc_hmac_unregister_all();
  silc_pkcs_unregister_all();

  SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
  fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");

  return success;
}
Example #8
0
int main(int argc, char **argv)
{
  SilcBool success = FALSE;
  SilcCipher cipher, cipher2;
  unsigned char dst[256], pdst[256];
  int i;

  if (argc > 1 && !strcmp(argv[1], "-d")) {
    silc_log_debug(TRUE);
    silc_log_debug_hexdump(TRUE);
    silc_log_set_debug_string("*crypt*,*cast*,*cipher*");
  }

  SILC_LOG_DEBUG(("Registering builtin hash functions"));
  silc_cipher_register_default();

  SILC_LOG_DEBUG(("Allocating cast5-CBC cipher"));
  if (!silc_cipher_alloc("cast5-128-cbc", &cipher)) {
    SILC_LOG_DEBUG(("Allocating cas5-CBC cipher failed"));
    goto err;
  }
  if (!silc_cipher_alloc("cast5-128-cbc", &cipher2)) {
    SILC_LOG_DEBUG(("Allocating cast5-CBC cipher failed"));
    goto err;
  }

  /* First test vector */
  SILC_LOG_DEBUG(("First test vector"));
  memset(dst, 0, sizeof(dst));
  memset(pdst, 0, sizeof(pdst));
  silc_cipher_set_iv(cipher, iv1);
  assert(silc_cipher_set_key(cipher, key1, key1_len, TRUE));
  assert(silc_cipher_set_key(cipher2, key1, key1_len, FALSE));
  assert(silc_cipher_encrypt(cipher, p1, dst, p1_len, NULL));
  SILC_LOG_DEBUG(("block len %d, key len %d, name %s",
		 silc_cipher_get_block_len(cipher),
		 silc_cipher_get_key_len(cipher),
		 silc_cipher_get_name(cipher)));
  SILC_LOG_HEXDUMP(("Plaintext"), (unsigned char *)p1, p1_len);
  SILC_LOG_HEXDUMP(("Ciphertext"), (unsigned char *)dst, p1_len);
  SILC_LOG_HEXDUMP(("Expected ciphertext"), (unsigned char *)c1, p1_len);
  if (memcmp(dst, c1, p1_len)) {
    SILC_LOG_DEBUG(("Encrypt failed"));
    goto err;
  }
  SILC_LOG_DEBUG(("Encrypt is successful"));
  silc_cipher_set_iv(cipher2, iv1);
  assert(silc_cipher_decrypt(cipher2, dst, pdst, p1_len, NULL));
  SILC_LOG_HEXDUMP(("Decrypted plaintext"), (unsigned char *)pdst, p1_len);
  SILC_LOG_HEXDUMP(("Expected plaintext"), (unsigned char *)p1, p1_len);
  if (memcmp(pdst, p1, p1_len)) {
    SILC_LOG_DEBUG(("Decrypt failed"));
    goto err;
  }
  SILC_LOG_DEBUG(("Decrypt is successful"));


  /* Second test vector */
  SILC_LOG_DEBUG(("Second test vector"));
  memset(dst, 0, sizeof(dst));
  memset(pdst, 0, sizeof(pdst));
  silc_cipher_set_iv(cipher, iv2);
  assert(silc_cipher_set_key(cipher, key2, key2_len, TRUE));
  assert(silc_cipher_set_key(cipher2, key2, key2_len, FALSE));
  assert(silc_cipher_encrypt(cipher, p2, dst, p2_len, NULL));
  SILC_LOG_DEBUG(("block len %d, key len %d, name %s",
		 silc_cipher_get_block_len(cipher),
		 silc_cipher_get_key_len(cipher),
		 silc_cipher_get_name(cipher)));
  SILC_LOG_HEXDUMP(("Plaintext"), (unsigned char *)p2, p2_len);
  SILC_LOG_HEXDUMP(("Ciphertext"), (unsigned char *)dst, p2_len);
  SILC_LOG_HEXDUMP(("Expected ciphertext"), (unsigned char *)c2, p2_len);
  if (memcmp(dst, c2, p2_len)) {
    SILC_LOG_DEBUG(("Encrypt failed"));
    goto err;
  }
  SILC_LOG_DEBUG(("Encrypt is successful"));
  silc_cipher_set_iv(cipher2, iv2);
  assert(silc_cipher_decrypt(cipher2, dst, pdst, p2_len, NULL));
  SILC_LOG_HEXDUMP(("Decrypted plaintext"), (unsigned char *)pdst, p2_len);
  SILC_LOG_HEXDUMP(("Expected plaintext"), (unsigned char *)p2, p2_len);
  if (memcmp(pdst, p2, p2_len)) {
    SILC_LOG_DEBUG(("Decrypt failed"));
    goto err;
  }
  SILC_LOG_DEBUG(("Decrypt is successful"));
  silc_cipher_free(cipher);
  silc_cipher_free(cipher2);

  SILC_LOG_DEBUG(("Allocating cast5-128-ctr cipher"));
  if (!silc_cipher_alloc("cast5-128-ctr", &cipher)) {
    SILC_LOG_DEBUG(("Allocating cast5-128-ctr cipher failed"));
    goto err;
  }

  /* Fourth test vector */
  SILC_LOG_DEBUG(("Fourth test vector"));
  memset(dst, 0, sizeof(dst));
  memset(pdst, 0, sizeof(pdst));
  silc_cipher_set_iv(cipher, iv4);
  assert(silc_cipher_set_key(cipher, key4, key4_len, TRUE));
  assert(silc_cipher_encrypt(cipher, p4, dst, p4_len, NULL));
  SILC_LOG_DEBUG(("block len %d, key len %d, name %s",
		 silc_cipher_get_block_len(cipher),
		 silc_cipher_get_key_len(cipher),
		 silc_cipher_get_name(cipher)));
  SILC_LOG_HEXDUMP(("Plaintext"), (unsigned char *)p4, p4_len);
  SILC_LOG_HEXDUMP(("Ciphertext"), (unsigned char *)dst, p4_len);
  SILC_LOG_HEXDUMP(("Expected ciphertext"), (unsigned char *)c4, p4_len);
  if (memcmp(dst, c4, p4_len)) {
    SILC_LOG_DEBUG(("Encrypt failed"));
    goto err;
  }
  SILC_LOG_DEBUG(("Encrypt is successful"));
  silc_cipher_set_iv(cipher, iv4);
  assert(silc_cipher_decrypt(cipher, dst, pdst, p4_len, NULL));
  SILC_LOG_HEXDUMP(("Decrypted plaintext"), (unsigned char *)pdst, p4_len);
  SILC_LOG_HEXDUMP(("Expected plaintext"), (unsigned char *)p4, p4_len);
  if (memcmp(pdst, p4, p4_len)) {
    SILC_LOG_DEBUG(("Decrypt failed"));
    goto err;
  }
  SILC_LOG_DEBUG(("Decrypt is successful"));
  silc_cipher_free(cipher);


  SILC_LOG_DEBUG(("Allocating cast5-128-cfb cipher"));
  if (!silc_cipher_alloc("cast5-128-cfb", &cipher)) {
    SILC_LOG_DEBUG(("Allocating cast5-128-cfb cipher failed"));
    goto err;
  }
  if (!silc_cipher_alloc("cast5-128-cfb", &cipher2)) {
    SILC_LOG_DEBUG(("Allocating cast5-128-cfb cipher failed"));
    goto err;
  }

  SILC_LOG_DEBUG(("CFB test vector"));
  memset(dst, 0, sizeof(dst));
  memset(pdst, 0, sizeof(pdst));
  silc_cipher_set_iv(cipher, iv6);
  assert(silc_cipher_set_key(cipher, key6, key6_len, TRUE));
  assert(silc_cipher_set_key(cipher2, key6, key6_len, FALSE));
  assert(silc_cipher_encrypt(cipher, p6, dst, p6_len, NULL));
  SILC_LOG_DEBUG(("block len %d, key len %d, name %s",
		 silc_cipher_get_block_len(cipher),
		 silc_cipher_get_key_len(cipher),
		 silc_cipher_get_name(cipher)));
  SILC_LOG_HEXDUMP(("Plaintext"), (unsigned char *)p6, p6_len);
  SILC_LOG_HEXDUMP(("Ciphertext"), (unsigned char *)dst, p6_len);
  SILC_LOG_HEXDUMP(("Expected ciphertext"), (unsigned char *)c6, p6_len);
  if (memcmp(dst, c6, p6_len)) {
    SILC_LOG_DEBUG(("Encrypt failed"));
    goto err;
  }
  SILC_LOG_DEBUG(("Encrypt is successful"));
  silc_cipher_set_iv(cipher2, iv6);
  assert(silc_cipher_decrypt(cipher2, dst, pdst, p6_len, NULL));
  SILC_LOG_HEXDUMP(("Decrypted plaintext"), (unsigned char *)pdst, p6_len);
  SILC_LOG_HEXDUMP(("Expected plaintext"), (unsigned char *)p6, p6_len);
  if (memcmp(pdst, p6, p6_len)) {
    SILC_LOG_DEBUG(("Decrypt failed"));
    goto err;
  }
  SILC_LOG_DEBUG(("Decrypt is successful"));
  silc_cipher_free(cipher2);

  success = TRUE;

 err:
  SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
  fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");

  silc_cipher_unregister_all();
  return success;
}
int main(int argc, char **argv)
{
  SilcBool success = FALSE;
  unsigned char *data, iv[SILC_CIPHER_MAX_IV_SIZE];
  SilcUInt32 i, k;

  silc_runtime_init();
  silc_crypto_init(NULL);

  if (argc > 1 && !strcmp(argv[1], "-d")) {
    silc_log_debug(TRUE);
    silc_log_debug_hexdump(TRUE);
    silc_log_set_debug_string("*acc*,*cipher*,*twofish*");
  }

  if (!silc_acc_init(SILC_SOFTACC, (void *)0x01, "min_threads", 2,
		     "max_threads", 8, NULL))
    exit(1);

  data = malloc(ENC_LEN * sizeof(*data));
  if (!data)
    exit(1);

  /* Plaintext */
  for (i = 0; i < ENC_LEN; i++)
    data[i] = i % 255;
  SILC_LOG_HEXDUMP(("data"), data, ENC_LEN);

  /* IV */
  for (i = 0; i < SILC_CIPHER_MAX_IV_SIZE; i++)
    iv[i] = i % 255;

  SILC_LOG_HEXDUMP(("IV"), iv, SILC_CIPHER_MAX_IV_SIZE);

  for (i = 0; silc_default_ciphers[i].name; i++) {
    if (!silc_cipher_alloc(silc_default_ciphers[i].name, &enc_cipher)) {
      fprintf(stderr, "Error allocating %s\n", silc_default_ciphers[i].name);
      exit(1);
    }
    if (!silc_cipher_alloc(silc_default_ciphers[i].name, &dec_cipher)) {
      fprintf(stderr, "Error allocating %s\n", silc_default_ciphers[i].name);
      exit(1);
    }

    enc_acc_cipher = silc_acc_cipher(SILC_SOFTACC, enc_cipher);
    if (!enc_acc_cipher)
      continue;
    dec_acc_cipher = silc_acc_cipher(SILC_SOFTACC, dec_cipher);
    if (!dec_acc_cipher)
      continue;

    SILC_LOG_DEBUG(("Allocated cipher %s", silc_default_ciphers[i].name));

    SILC_LOG_DEBUG(("Set key"));
    silc_cipher_set_key(enc_acc_cipher, data,
			silc_cipher_get_key_len(enc_cipher),
			TRUE);
    silc_cipher_set_key(dec_acc_cipher, data,
			silc_cipher_get_key_len(dec_cipher),
			FALSE);


    SILC_LOG_DEBUG(("Set IV"));
    silc_cipher_set_iv(enc_acc_cipher, iv);

    SILC_LOG_DEBUG(("Encrypt with accelerated cipher"));
    for (k = 0; k < ENC_ROUND; k++)
      silc_cipher_encrypt(enc_acc_cipher, data, data, ENC_LEN, NULL);
    SILC_LOG_HEXDUMP(("data"), data, ENC_LEN);

    SILC_LOG_DEBUG(("Set IV"));
    silc_cipher_set_iv(dec_cipher, iv);

    SILC_LOG_DEBUG(("Decrypt with associated cipher"));
    for (k = 0; k < ENC_ROUND; k++)
      silc_cipher_decrypt(dec_cipher, data, data, ENC_LEN, NULL);
    SILC_LOG_HEXDUMP(("data"), data, ENC_LEN);

    /* Verify */
    SILC_LOG_DEBUG(("Verify"));
    for (k = 0; k < ENC_LEN; k++)
      if (data[k] != k % 255)
	goto err;
    SILC_LOG_DEBUG(("Ok"));


    SILC_LOG_DEBUG(("Set IV"));
    silc_cipher_set_iv(enc_cipher, iv);

    SILC_LOG_DEBUG(("Encrypt with associated cipher"));
    for (k = 0; k < ENC_ROUND; k++)
      silc_cipher_encrypt(enc_cipher, data, data, ENC_LEN, NULL);
    SILC_LOG_HEXDUMP(("data"), data, ENC_LEN);

    SILC_LOG_DEBUG(("Set IV"));
    silc_cipher_set_iv(dec_acc_cipher, iv);

    SILC_LOG_DEBUG(("Decrypt with accelerated cipher"));
    for (k = 0; k < ENC_ROUND; k++)
      silc_cipher_decrypt(dec_acc_cipher, data, data, ENC_LEN, NULL);
    SILC_LOG_HEXDUMP(("data"), data, ENC_LEN);

    /* Verify */
    SILC_LOG_DEBUG(("Verify"));
    for (k = 0; k < ENC_LEN; k++)
      if (data[k] != k % 255)
	goto err;
    SILC_LOG_DEBUG(("Ok"));


    SILC_LOG_DEBUG(("Set IV"));
    silc_cipher_set_iv(enc_acc_cipher, iv);

    SILC_LOG_DEBUG(("Encrypt with accelerated cipher"));
    for (k = 0; k < ENC_ROUND; k++)
      silc_cipher_encrypt(enc_acc_cipher, data, data, ENC_LEN, NULL);
    SILC_LOG_HEXDUMP(("data"), data, ENC_LEN);

    SILC_LOG_DEBUG(("Set IV"));
    silc_cipher_set_iv(dec_acc_cipher, iv);

    SILC_LOG_DEBUG(("Decrypt with accelerated cipher"));
    for (k = 0; k < ENC_ROUND; k++)
      silc_cipher_decrypt(dec_acc_cipher, data, data, ENC_LEN, NULL);
    SILC_LOG_HEXDUMP(("data"), data, ENC_LEN);

    /* Verify */
    SILC_LOG_DEBUG(("Verify"));
    for (k = 0; k < ENC_LEN; k++)
      if (data[k] != k % 255)
	goto err;
    SILC_LOG_DEBUG(("Ok"));


    SILC_LOG_DEBUG(("Set IV"));
    silc_cipher_set_iv(enc_cipher, iv);

    SILC_LOG_DEBUG(("Encrypt with associated cipher"));
    for (k = 0; k < ENC_ROUND; k++)
      silc_cipher_encrypt(enc_cipher, data, data, ENC_LEN, NULL);
    SILC_LOG_HEXDUMP(("data"), data, ENC_LEN);

    SILC_LOG_DEBUG(("Set IV"));
    silc_cipher_set_iv(dec_cipher, iv);

    SILC_LOG_DEBUG(("Decrypt with associated cipher"));
    for (k = 0; k < ENC_ROUND; k++)
      silc_cipher_decrypt(dec_cipher, data, data, ENC_LEN, NULL);
    SILC_LOG_HEXDUMP(("data"), data, ENC_LEN);

    /* Verify */
    SILC_LOG_DEBUG(("Verify"));
    for (k = 0; k < ENC_LEN; k++)
      if (data[k] != k % 255)
	goto err;
    SILC_LOG_DEBUG(("Ok"));


    silc_cipher_free(enc_acc_cipher);
    silc_cipher_free(enc_cipher);
    silc_cipher_free(dec_acc_cipher);
    silc_cipher_free(dec_cipher);
  }

  silc_acc_uninit(SILC_SOFTACC);

  success = TRUE;

 err:
  SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
  fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");

  silc_crypto_uninit();
  silc_runtime_uninit();

  return !success;
}
Example #10
0
SilcCipher silc_acc_cipher(SilcAccelerator acc, SilcCipher cipher)
{
  SilcCipher c;
  SilcAcceleratorCipher acc_cipher;
  const SilcCipherObject *alg;
  int i;

  if (!acc || !cipher)
    return NULL;

  SILC_LOG_DEBUG(("Accelerate cipher %p with accelerator %s",
		  cipher, acc->name));

  if (!acc->cipher) {
    SILC_LOG_ERROR(("Accelerator '%s' does not support cipher acceleration ",
		    acc->name));
    return NULL;
  }

  if (silc_acc_get_cipher(NULL, cipher)) {
    SILC_LOG_DEBUG(("Cipher %p is already accelerated", cipher));
    return NULL;
  }

  /* Check that accelerator supports this cipher algorithm */
  alg = cipher->cipher;
  for (i = 0; acc->cipher[i].alg_name; i++) {
    if ((!strcmp(acc->cipher[i].alg_name, alg->alg_name) ||
	 !strcmp(acc->cipher[i].alg_name, "any")) &&
	(acc->cipher[i].mode == alg->mode ||
	 acc->cipher[i].mode == 0) &&
	(acc->cipher[i].key_len == alg->key_len ||
	 acc->cipher[i].key_len == 0)) {
      alg = NULL;
      break;
    }
  }
  if (alg) {
    SILC_LOG_DEBUG(("Accelerator %s does not support %s (mode %d) "
		    "acceleration", acc->name, alg->name, alg->mode));
    return NULL;
  }

  /* Allocate cipher context for the SILC Cipher API */
  c = silc_calloc(1, sizeof(*c));
  if (!c)
    return NULL;

  /* Allocate cipher operations */
  c->cipher = silc_calloc(1, sizeof(SilcCipherObject));
  if (!c->cipher) {
    silc_free(c);
    return NULL;
  }
  *c->cipher = silc_acc_ciph;

  /* Allocate cipher context */
  c->context = acc_cipher = silc_calloc(1, sizeof(*acc_cipher));
  if (!acc_cipher) {
    silc_free(c->cipher);
    silc_free(c);
    return NULL;
  }
  acc_cipher->cipher = cipher;

  /* Allocate the actual algorithm accelerator. */
  acc_cipher->acc_cipher = silc_calloc(1, sizeof(*acc_cipher->acc_cipher));
  if (!acc_cipher->acc_cipher) {
    silc_free(c->cipher);
    silc_free(c);
    silc_free(acc_cipher);
  }

  /* Initialize the algorithm accelerator */
  acc_cipher->acc_cipher->context =
    acc->cipher[i].init((struct SilcCipherObjectStruct *)&acc->cipher[i]);
  if (!acc_cipher->acc_cipher->context) {
    silc_free(c->cipher);
    silc_free(c);
    silc_free(acc_cipher->acc_cipher);
    silc_free(acc_cipher);
    return NULL;
  }

  /* Allocate algorithm accelerator operations */
  acc_cipher->acc_cipher->cipher = silc_calloc(1, sizeof(SilcCipherObject));
  if (!acc_cipher->acc_cipher->cipher) {
    silc_free(c->cipher);
    silc_free(c);
    silc_free(acc_cipher->acc_cipher->context);
    silc_free(acc_cipher->acc_cipher);
    silc_free(acc_cipher);
    return NULL;
  }

  /* Set algorithm accelerator operations.  They are copied from the
     accelerator, but algorithm specific things come from associated
     cipher.  This way accelerators get the associated cipher details. */
  *acc_cipher->acc_cipher->cipher = acc->cipher[i];
  acc_cipher->acc_cipher->cipher->alg_name =
    (char *)silc_cipher_get_alg_name(cipher);
  acc_cipher->acc_cipher->cipher->key_len = silc_cipher_get_key_len(cipher);
  acc_cipher->acc_cipher->cipher->block_len =
    silc_cipher_get_block_len(cipher);
  acc_cipher->acc_cipher->cipher->iv_len = silc_cipher_get_iv_len(cipher);

  /* Set for the accelerator cipher too */
  c->cipher->key_len = silc_cipher_get_key_len(cipher);
  c->cipher->block_len = silc_cipher_get_block_len(cipher);
  c->cipher->iv_len = silc_cipher_get_iv_len(cipher);

  /* Start the accelerator.  The accelerator is started by setting key
     with NULL key. */
  if (!silc_cipher_set_key(acc_cipher->acc_cipher, NULL, 0, FALSE)) {
    SilcCipherObject *ops = acc_cipher->acc_cipher->cipher;
    silc_cipher_free(acc_cipher->acc_cipher);
    silc_free(ops);
    silc_free(c->cipher);
    silc_free(c);
    return NULL;
  }

  SILC_LOG_DEBUG(("New accelerated cipher %p", c));

  return c;
}
Example #11
0
SilcBool silc_client_add_channel_private_key(SilcClient client,
					     SilcClientConnection conn,
					     SilcChannelEntry channel,
					     const char *name,
					     char *cipher,
					     char *hmac,
					     unsigned char *key,
					     SilcUInt32 key_len,
					     SilcChannelPrivateKey *ret_key)
{
  SilcChannelPrivateKey entry;
  unsigned char hash[SILC_HASH_MAXLEN];
  SilcSKEKeyMaterial keymat;

  if (!client || !conn || !channel)
    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;

  if (!channel->internal.private_keys) {
    channel->internal.private_keys = silc_dlist_init();
    if (!channel->internal.private_keys)
      return FALSE;
  }

  /* Produce the key material */
  keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
					      conn->internal->sha1hash);
  if (!keymat)
    return FALSE;

  /* Save the key */
  entry = silc_calloc(1, sizeof(*entry));
  if (!entry) {
    silc_ske_free_key_material(keymat);
    return FALSE;
  }
  entry->name = name ? strdup(name) : NULL;

  /* Allocate the cipher and set the key */
  if (!silc_cipher_alloc(cipher, &entry->send_key)) {
    silc_free(entry);
    silc_free(entry->name);
    silc_ske_free_key_material(keymat);
    return FALSE;
  }
  if (!silc_cipher_alloc(cipher, &entry->receive_key)) {
    silc_free(entry);
    silc_free(entry->name);
    silc_cipher_free(entry->send_key);
    silc_ske_free_key_material(keymat);
    return FALSE;
  }
  silc_cipher_set_key(entry->send_key, keymat->send_enc_key,
		      keymat->enc_key_len, TRUE);
  silc_cipher_set_key(entry->receive_key, keymat->send_enc_key,
		      keymat->enc_key_len, FALSE);

  /* Generate HMAC key from the channel key data and set it */
  if (!silc_hmac_alloc(hmac, NULL, &entry->hmac)) {
    silc_free(entry);
    silc_free(entry->name);
    silc_cipher_free(entry->send_key);
    silc_cipher_free(entry->receive_key);
    silc_ske_free_key_material(keymat);
    return FALSE;
  }
  silc_hash_make(silc_hmac_get_hash(entry->hmac), keymat->send_enc_key,
		 keymat->enc_key_len / 8, 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->internal.private_keys, entry);

  if (!channel->internal.curr_key) {
    channel->internal.curr_key = entry;
    channel->cipher = silc_cipher_get_name(entry->send_key);
    channel->hmac = silc_cipher_get_name(entry->send_key);
  }

  /* Free the key material */
  silc_ske_free_key_material(keymat);

  if (ret_key)
    *ret_key = entry;

  return TRUE;
}