SilcBool silc_client_add_private_message_key(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry, const char *cipher, const char *hmac, unsigned char *key, SilcUInt32 key_len) { SilcSKEKeyMaterial keymat; SilcBool ret; if (!client || !client_entry) return FALSE; /* Return FALSE if key already set */ if (client_entry->internal.send_key && client_entry->internal.receive_key) return FALSE; if (!cipher) cipher = SILC_DEFAULT_CIPHER; if (!hmac) hmac = SILC_DEFAULT_HMAC; /* Check the requested cipher and HMAC */ if (!silc_cipher_is_supported(cipher)) return FALSE; if (!silc_hmac_is_supported(hmac)) return FALSE; /* Save the key */ client_entry->internal.key = silc_memdup(key, key_len); client_entry->internal.key_len = key_len; /* Produce the key material as the protocol defines */ keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16, conn->internal->sha1hash); if (!keymat) return FALSE; /* Set the key into use */ ret = silc_client_add_private_message_key_ske(client, conn, client_entry, cipher, hmac, keymat); client_entry->internal.generated = FALSE; /* Free the key material */ silc_ske_free_key_material(keymat); /* If we are setting the key without a request from the remote client, we will send request to remote. */ if (!client_entry->internal.prv_resp) silc_client_send_private_message_key_request(client, conn, client_entry); return ret; }
static void silcpurple_buddy_keyagr_cb(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry, SilcKeyAgreementStatus status, SilcSKEKeyMaterial *key, void *context) { PurpleConnection *gc = client->application; SilcPurple sg = gc->proto_data; SilcPurpleKeyAgr a = context; if (!sg->conn) return; switch (status) { case SILC_KEY_AGREEMENT_OK: { PurpleConversation *convo; char tmp[128]; /* Set the private key for this client */ silc_client_del_private_message_key(client, conn, client_entry); silc_client_add_private_message_key_ske(client, conn, client_entry, NULL, NULL, key, a->responder); silc_ske_free_key_material(key); /* Open IM window */ convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, client_entry->nickname, sg->account); if (convo) { /* we don't have windows in the core anymore...but we may want to * provide some method for asking the UI to show the window purple_conv_window_show(purple_conversation_get_window(convo)); */ } else { convo = purple_conversation_new(PURPLE_CONV_TYPE_IM, sg->account, client_entry->nickname); } g_snprintf(tmp, sizeof(tmp), "%s [private key]", client_entry->nickname); purple_conversation_set_title(convo, tmp); } break; case SILC_KEY_AGREEMENT_ERROR: purple_notify_error(gc, _("Key Agreement"), _("Error occurred during key agreement"), NULL); break; case SILC_KEY_AGREEMENT_FAILURE: purple_notify_error(gc, _("Key Agreement"), _("Key Agreement failed"), NULL); break; case SILC_KEY_AGREEMENT_TIMEOUT: purple_notify_error(gc, _("Key Agreement"), _("Timeout during key agreement"), NULL); break; case SILC_KEY_AGREEMENT_ABORTED: purple_notify_error(gc, _("Key Agreement"), _("Key agreement was aborted"), NULL); break; case SILC_KEY_AGREEMENT_ALREADY_STARTED: purple_notify_error(gc, _("Key Agreement"), _("Key agreement is already started"), NULL); break; case SILC_KEY_AGREEMENT_SELF_DENIED: purple_notify_error(gc, _("Key Agreement"), _("Key agreement cannot be started with yourself"), NULL); break; default: break; } silc_free(a); }