static gboolean perform_encrypt (GcrSecretExchange *self, GKeyFile *output, const gchar *secret, gsize n_secret) { GcrSecretExchangeClass *klass; guchar *result, *iv; gsize n_result, n_iv; klass = GCR_SECRET_EXCHANGE_GET_CLASS (self); g_return_val_if_fail (klass->encrypt_transport_data, FALSE); if (!(klass->encrypt_transport_data) (self, g_realloc, (const guchar *)secret, n_secret, &iv, &n_iv, &result, &n_result)) return FALSE; key_file_set_base64 (output, GCR_SECRET_EXCHANGE_PROTOCOL_1, "secret", result, n_result); key_file_set_base64 (output, GCR_SECRET_EXCHANGE_PROTOCOL_1, "iv", iv, n_iv); g_free (result); g_free (iv); return TRUE; }
static gboolean derive_key (GcrSecretExchange *self, GKeyFile *input) { GcrSecretExchangeClass *klass; gboolean ret; guchar *peer; gsize n_peer; klass = GCR_SECRET_EXCHANGE_GET_CLASS (self); g_return_val_if_fail (klass->derive_transport_key, FALSE); g_debug ("deriving shared transport key"); peer = key_file_get_base64 (input, GCR_SECRET_EXCHANGE_PROTOCOL_1, "public", &n_peer); if (peer == NULL) { g_message ("secret-exchange: invalid or missing 'public' argument"); return FALSE; } ret = (klass->derive_transport_key) (self, peer, n_peer); self->pv->derived = ret; g_free (peer); return ret; }
/** * gcr_secret_exchange_receive: * @self: a #GcrSecretExchange object * @exchange: the string received * * Receive a string from the other side of secret exchange. This string will * have been created by gcr_secret_exchange_begin() or gcr_secret_exchange_send(). * * After this call completes successfully the value returned from * gcr_secret_exchange_get_secret() will have changed. * * Returns: whether the string was successfully parsed and received */ gboolean gcr_secret_exchange_receive (GcrSecretExchange *self, const gchar *exchange) { GcrSecretExchangeClass *klass; gchar *secret = NULL; gsize n_secret = 0; GKeyFile *input; gboolean ret; g_return_val_if_fail (GCR_IS_SECRET_EXCHANGE (self), FALSE); g_return_val_if_fail (exchange != NULL, FALSE); klass = GCR_SECRET_EXCHANGE_GET_CLASS (self); g_return_val_if_fail (klass->generate_exchange_key, FALSE); g_return_val_if_fail (klass->derive_transport_key, FALSE); gchar *string = g_strescape (exchange, ""); g_debug ("receiving secret exchange: %s", string); g_free (string); /* Parse the input */ input = g_key_file_new (); if (!g_key_file_load_from_data (input, exchange, strlen (exchange), G_KEY_FILE_NONE, NULL)) { g_key_file_free (input); g_message ("couldn't parse secret exchange data"); return FALSE; } if (!self->pv->generated) { if (!(klass->generate_exchange_key) (self, GCR_SECRET_EXCHANGE_PROTOCOL_1, &self->pv->publi, &self->pv->n_publi)) g_return_val_if_reached (FALSE); self->pv->generated = TRUE; } ret = TRUE; if (!self->pv->derived) { if (!derive_key (self, input)) ret = FALSE; } if (ret && g_key_file_has_key (input, GCR_SECRET_EXCHANGE_PROTOCOL_1, "secret", NULL)) ret = perform_decrypt (self, input, (guchar **)&secret, &n_secret); if (ret) { egg_secure_free (self->pv->secret); self->pv->secret = secret; self->pv->n_secret = n_secret; } g_key_file_free (input); return ret; }
static gboolean perform_decrypt (GcrSecretExchange *self, GKeyFile *input, guchar **secret, gsize *n_secret) { GcrSecretExchangeClass *klass; gpointer iv, value; guchar *result; gsize n_result, n_iv, n_value; gboolean ret; klass = GCR_SECRET_EXCHANGE_GET_CLASS (self); g_return_val_if_fail (klass->decrypt_transport_data, FALSE); iv = key_file_get_base64 (input, GCR_SECRET_EXCHANGE_PROTOCOL_1, "iv", &n_iv); value = key_file_get_base64 (input, GCR_SECRET_EXCHANGE_PROTOCOL_1, "secret", &n_value); if (value == NULL) { g_message ("secret-exchange: invalid or missing value"); g_free (iv); return FALSE; } ret = (klass->decrypt_transport_data) (self, egg_secure_realloc, value, n_value, iv, n_iv, &result, &n_result); g_free (value); g_free (iv); if (!ret) return FALSE; /* Reallocate a null terminator */ if (result) { result = egg_secure_realloc (result, n_result + 1); result[n_result] = 0; } *secret = result; *n_secret = n_result; return TRUE; }
/** * gcr_secret_exchange_begin: * @self: a #GcrSecretExchange object * * Begin the secret exchange. The resulting string should be sent to the other * side of the exchange. The other side should use gcr_secret_exchange_receive() * to process the string. * * Returns: (transfer full): A newly allocated string to be sent to the other * side of the secret exchange */ gchar * gcr_secret_exchange_begin (GcrSecretExchange *self) { GcrSecretExchangeClass *klass; GKeyFile *output; gchar *result; g_return_val_if_fail (GCR_IS_SECRET_EXCHANGE (self), NULL); klass = GCR_SECRET_EXCHANGE_GET_CLASS (self); g_return_val_if_fail (klass->generate_exchange_key, NULL); clear_secret_exchange (self); output = g_key_file_new (); if (!(klass->generate_exchange_key) (self, GCR_SECRET_EXCHANGE_PROTOCOL_1, &self->pv->publi, &self->pv->n_publi)) g_return_val_if_reached (NULL); self->pv->generated = TRUE; key_file_set_base64 (output, GCR_SECRET_EXCHANGE_PROTOCOL_1, "public", self->pv->publi, self->pv->n_publi); result = g_key_file_to_data (output, NULL, NULL); g_return_val_if_fail (result != NULL, NULL); g_strchug (result); gchar *string = g_strescape (result, ""); g_debug ("beginning the secret exchange: %s", string); g_free (string); if (!g_str_has_prefix (result, SECRET_EXCHANGE_PROTOCOL_1_PREFIX)) g_warning ("the prepared data does not have the correct protocol prefix"); g_key_file_free (output); return result; }