void silc_client_current_channel_private_key(SilcClient client, SilcClientConnection conn, SilcChannelEntry channel, SilcChannelPrivateKey key) { if (!channel) return; channel->internal.curr_key = key; channel->cipher = silc_cipher_get_name(key->send_key); channel->hmac = silc_hmac_get_name(key->hmac); }
SilcPrivateMessageKeys silc_client_list_private_message_keys(SilcClient client, SilcClientConnection conn, SilcUInt32 *key_count) { SilcPrivateMessageKeys keys; SilcUInt32 count = 0; SilcList list; SilcIDCacheEntry id_cache; SilcClientEntry entry; if (!client || !conn) return NULL; silc_mutex_lock(conn->internal->lock); if (!silc_idcache_get_all(conn->internal->client_cache, &list)) { silc_mutex_unlock(conn->internal->lock); return NULL; } keys = silc_calloc(silc_list_count(list), sizeof(*keys)); if (!keys) { silc_mutex_unlock(conn->internal->lock); return NULL; } silc_list_start(list); while ((id_cache = silc_list_get(list))) { entry = id_cache->context; if (entry->internal.send_key) { keys[count].client_entry = entry; keys[count].cipher = (char *)silc_cipher_get_name(entry->internal. send_key); keys[count].key = (entry->internal.generated == FALSE ? entry->internal.key : NULL); keys[count].key_len = (entry->internal.generated == FALSE ? entry->internal.key_len : 0); count++; } } silc_mutex_unlock(conn->internal->lock); if (key_count) *key_count = count; return keys; }
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; }
static SilcBool silc_client_send_private_message_key_request(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry) { const char *cipher, *hmac; SILC_LOG_DEBUG(("Sending private message key request")); cipher = silc_cipher_get_name(client_entry->internal.send_key); hmac = silc_hmac_get_name(client_entry->internal.hmac_send); /* Send the packet */ return silc_packet_send_va_ext(conn->stream, SILC_PACKET_PRIVATE_MESSAGE_KEY, 0, 0, NULL, SILC_ID_CLIENT, &client_entry->id, NULL, NULL, SILC_STR_UI_SHORT(strlen(cipher)), SILC_STR_DATA(cipher, strlen(cipher)), SILC_STR_UI_SHORT(strlen(hmac)), SILC_STR_DATA(hmac, strlen(hmac)), SILC_STR_END); }
static void silcpurple_chat_getinfo(PurpleConnection *gc, GHashTable *components) { SilcPurple sg = gc->proto_data; const char *chname; char *buf, tmp[256], *tmp2; GString *s; SilcChannelEntry channel; SilcHashTableList htl; SilcChannelUser chu; if (!components) return; chname = g_hash_table_lookup(components, "channel"); if (!chname) return; channel = silc_client_get_channel(sg->client, sg->conn, (char *)chname); if (!channel) { silc_client_get_channel_resolve(sg->client, sg->conn, (char *)chname, silcpurple_chat_getinfo_res, components); return; } s = g_string_new(""); tmp2 = g_markup_escape_text(channel->channel_name, -1); g_string_append_printf(s, _("<b>Channel Name:</b> %s"), tmp2); g_free(tmp2); if (channel->user_list && silc_hash_table_count(channel->user_list)) g_string_append_printf(s, _("<br><b>User Count:</b> %d"), (int)silc_hash_table_count(channel->user_list)); silc_hash_table_list(channel->user_list, &htl); while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) { tmp2 = g_markup_escape_text(chu->client->nickname, -1); g_string_append_printf(s, _("<br><b>Channel Founder:</b> %s"), tmp2); g_free(tmp2); break; } } silc_hash_table_list_reset(&htl); if (channel->channel_key) g_string_append_printf(s, _("<br><b>Channel Cipher:</b> %s"), silc_cipher_get_name(channel->channel_key)); if (channel->hmac) /* Definition of HMAC: http://en.wikipedia.org/wiki/HMAC */ g_string_append_printf(s, _("<br><b>Channel HMAC:</b> %s"), silc_hmac_get_name(channel->hmac)); if (channel->topic) { tmp2 = g_markup_escape_text(channel->topic, -1); g_string_append_printf(s, _("<br><b>Channel Topic:</b><br>%s"), tmp2); g_free(tmp2); } if (channel->mode) { g_string_append_printf(s, _("<br><b>Channel Modes:</b> ")); silcpurple_get_chmode_string(channel->mode, tmp, sizeof(tmp)); g_string_append(s, tmp); } if (channel->founder_key) { char *fingerprint, *babbleprint; unsigned char *pk; SilcUInt32 pk_len; pk = silc_pkcs_public_key_encode(channel->founder_key, &pk_len); fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); babbleprint = silc_hash_babbleprint(NULL, pk, pk_len); g_string_append_printf(s, _("<br><b>Founder Key Fingerprint:</b><br>%s"), fingerprint); g_string_append_printf(s, _("<br><b>Founder Key Babbleprint:</b><br>%s"), babbleprint); silc_free(fingerprint); silc_free(babbleprint); silc_free(pk); } buf = g_string_free(s, FALSE); purple_notify_formatted(gc, NULL, _("Channel Information"), NULL, buf, NULL, NULL); g_free(buf); }
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; }
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; }
SilcBool silc_client_save_channel_key(SilcClient client, SilcClientConnection conn, SilcBuffer key_payload, SilcChannelEntry channel) { unsigned char *id_string, *key, *cipher, *hmac, hash[SILC_HASH_MAXLEN]; SilcUInt32 tmp_len; SilcChannelID id; SilcChannelKeyPayload payload; SILC_LOG_DEBUG(("New channel key")); payload = silc_channel_key_payload_parse(silc_buffer_data(key_payload), silc_buffer_len(key_payload)); if (!payload) return FALSE; id_string = silc_channel_key_get_id(payload, &tmp_len); if (!id_string) { silc_channel_key_payload_free(payload); return FALSE; } if (!silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL, &id, sizeof(id))) { silc_channel_key_payload_free(payload); return FALSE; } /* Find channel. */ if (!channel) { channel = silc_client_get_channel_by_id(client, conn, &id); if (!channel) { SILC_LOG_DEBUG(("Key for unknown channel")); silc_channel_key_payload_free(payload); return FALSE; } } else { silc_client_ref_channel(client, conn, channel); } /* Save the old key for a short period of time so that we can decrypt channel message even after the rekey if some client would be sending messages with the old key after the rekey. */ if (!channel->internal.old_channel_keys) channel->internal.old_channel_keys = silc_dlist_init(); if (!channel->internal.old_hmacs) channel->internal.old_hmacs = silc_dlist_init(); if (channel->internal.old_channel_keys && channel->internal.old_hmacs) { silc_dlist_add(channel->internal.old_channel_keys, channel->internal.receive_key); silc_dlist_add(channel->internal.old_hmacs, channel->internal.hmac); silc_schedule_task_add_timeout(client->schedule, silc_client_save_channel_key_rekey, channel, 15, 0); } /* Get channel cipher */ cipher = silc_channel_key_get_cipher(payload, NULL); if (!silc_cipher_alloc(cipher, &channel->internal.send_key)) { client->internal->ops->say( conn->client, conn, SILC_CLIENT_MESSAGE_AUDIT, "Cannot talk to channel: unsupported cipher %s", cipher); silc_client_unref_channel(client, conn, channel); silc_channel_key_payload_free(payload); return FALSE; } if (!silc_cipher_alloc(cipher, &channel->internal.receive_key)) { client->internal->ops->say( conn->client, conn, SILC_CLIENT_MESSAGE_AUDIT, "Cannot talk to channel: unsupported cipher %s", cipher); silc_client_unref_channel(client, conn, channel); silc_channel_key_payload_free(payload); return FALSE; } /* Set the cipher key. Both sending and receiving keys are same */ key = silc_channel_key_get_key(payload, &tmp_len); silc_cipher_set_key(channel->internal.send_key, key, tmp_len * 8, TRUE); silc_cipher_set_key(channel->internal.receive_key, key, tmp_len * 8, FALSE); /* Get channel HMAC */ hmac = (channel->internal.hmac ? (char *)silc_hmac_get_name(channel->internal.hmac) : SILC_DEFAULT_HMAC); if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) { client->internal->ops->say( conn->client, conn, SILC_CLIENT_MESSAGE_AUDIT, "Cannot talk to channel: unsupported HMAC %s", hmac); silc_client_unref_channel(client, conn, channel); silc_channel_key_payload_free(payload); return FALSE; } channel->cipher = silc_cipher_get_name(channel->internal.send_key); channel->hmac = silc_hmac_get_name(channel->internal.hmac); /* Set HMAC key */ silc_hash_make(silc_hmac_get_hash(channel->internal.hmac), key, tmp_len, hash); silc_hmac_set_key(channel->internal.hmac, hash, silc_hash_len(silc_hmac_get_hash(channel->internal.hmac))); memset(hash, 0, sizeof(hash)); silc_channel_key_payload_free(payload); silc_client_unref_channel(client, conn, channel); return TRUE; }